Merge branch 'feature/SLING-8424-request-parameter-handling'
diff --git a/src/main/java/org/apache/sling/servlethelpers/MockRequestParameter.java b/src/main/java/org/apache/sling/servlethelpers/MockRequestParameter.java
index 2951e6a..1515dd8 100644
--- a/src/main/java/org/apache/sling/servlethelpers/MockRequestParameter.java
+++ b/src/main/java/org/apache/sling/servlethelpers/MockRequestParameter.java
@@ -32,6 +32,9 @@
private String name;
private String encoding = "UTF-8";
private String value;
+ private String contentType;
+ private boolean isFormField;
+ private String filename;
private byte[] content;
@@ -39,7 +42,29 @@
this.name = name;
this.value = value;
this.content = null;
+ this.contentType = "text/plain";
+ this.isFormField = true;
+ this.filename = null;
}
+
+ public MockRequestParameter(String name, byte[] content, String contentType) {
+ this.name = name;
+ this.value = null;
+ this.content = content;
+ this.contentType = contentType;
+ this.isFormField = false;
+ this.filename = null;
+ }
+
+ public MockRequestParameter(String name, byte[] content, String contentType, String filename) {
+ this.name = name;
+ this.value = null;
+ this.content = content;
+ this.contentType = contentType;
+ this.isFormField = false;
+ this.filename = filename;
+ }
+
void setName(String name) {
this.name = name;
}
@@ -57,20 +82,20 @@
}
public byte[] get() {
- if (content == null) {
+ if (this.content == null && this.value != null) {
try {
- content = getString().getBytes(getEncoding());
+ this.content = getString().getBytes(getEncoding());
} catch (Exception e) {
// UnsupportedEncodingException, IllegalArgumentException
- content = getString().getBytes();
+ this.content = getString().getBytes();
}
}
- return content;
+ return this.content;
}
public String getContentType() {
- // none known for www-form-encoded parameters
- return null;
+ // text/plain for www-form-encoded parameters
+ return this.contentType;
}
public InputStream getInputStream() {
@@ -78,8 +103,7 @@
}
public String getFileName() {
- // no original file name
- return null;
+ return this.filename;
}
public long getSize() {
@@ -87,7 +111,7 @@
}
public String getString() {
- return value;
+ return this.value == null && this.content != null? new String(this.content) : this.value;
}
public String getString(String encoding) throws UnsupportedEncodingException {
@@ -95,8 +119,7 @@
}
public boolean isFormField() {
- // www-form-encoded are always form fields
- return true;
+ return this.isFormField;
}
public String toString() {
diff --git a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java
index dfb318c..f1d92ab 100644
--- a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java
+++ b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java
@@ -41,6 +41,7 @@
import java.util.ListResourceBundle;
import java.util.Locale;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.ResourceBundle;
import javax.servlet.AsyncContext;
@@ -82,7 +83,7 @@
private final ResourceResolver resourceResolver;
private final RequestPathInfo requestPathInfo;
private Map<String, Object> attributeMap = new HashMap<String, Object>();
- private Map<String, String[]> parameterMap = new LinkedHashMap<String, String[]>();
+ private Map<String, MockRequestParameter[]> parameterMap = new LinkedHashMap<>();
private HttpSession session;
private Resource resource;
private String authType;
@@ -108,8 +109,8 @@
private boolean getReaderCalled;
private MockRequestDispatcherFactory requestDispatcherFactory;
- private String responseContentType;
-
+ private String responseContentType;
+
protected static final ResourceBundle EMPTY_RESOURCE_BUNDLE = new ListResourceBundle() {
@Override
protected Object[][] getContents() {
@@ -150,7 +151,7 @@
}
return this.session;
}
-
+
@Override
public RequestPathInfo getRequestPathInfo() {
return this.requestPathInfo;
@@ -188,21 +189,26 @@
@Override
public String getParameter(String name) {
- Object object = this.parameterMap.get(name);
- if (object instanceof String) {
- return (String) object;
- } else if (object instanceof String[]) {
- String[] values = (String[]) object;
- if (values.length > 0) {
- return values[0];
- }
+ MockRequestParameter[] params = this.parameterMap.get(name);
+ if (params != null && params.length > 0) {
+ return params[0].getString();
}
return null;
}
@Override
public Map<String, String[]> getParameterMap() {
- return this.parameterMap;
+ LinkedHashMap<String, String[]> result = new LinkedHashMap<>();
+ for (Entry<String, MockRequestParameter[]> entry : this.parameterMap.entrySet()) {
+ MockRequestParameter[] values = entry.getValue();
+ String[] resultValues = new String[values.length];
+ for (int i = 0; i < values.length; i++) {
+ resultValues[i] = values[i].getString();
+ }
+ result.put(entry.getKey(), resultValues);
+ }
+
+ return result;
}
@SuppressWarnings("unchecked")
@@ -213,11 +219,13 @@
@Override
public String[] getParameterValues(String name) { // NOPMD
- Object object = this.parameterMap.get(name);
- if (object instanceof String) {
- return new String[] { (String) object };
- } else if (object instanceof String[]) {
- return (String[]) object;
+ MockRequestParameter[] param = this.parameterMap.get(name);
+ if (param != null) {
+ String[] values = new String[param.length];
+ for (int i = 0; i < param.length; i++) {
+ values[i] = param[i].getString();
+ }
+ return values;
}
return null; // NOPMD
}
@@ -231,9 +239,16 @@
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof String[]) {
- this.parameterMap.put(key, (String[]) value);
+ String[] array = (String[]) value;
+ MockRequestParameter[] values = new MockRequestParameter[array.length];
+ for (int i = 0; i < array.length; i++) {
+ values[i] = new MockRequestParameter(key, array[i]);
+ }
+ this.parameterMap.put(key, values);
+ } else if (value instanceof MockRequestParameter[]) {
+ this.parameterMap.put(key, (MockRequestParameter[]) value);
} else if (value != null) {
- this.parameterMap.put(key, new String[] { value.toString() });
+ this.addRequestParameter(key, value.toString());
} else {
this.parameterMap.put(key, null);
}
@@ -245,26 +260,26 @@
}
}
- private String formatQueryString(Map<String, String[]> map) throws UnsupportedEncodingException {
+ private static String formatQueryString(Map<String, MockRequestParameter[]> map) throws UnsupportedEncodingException {
StringBuilder querystring = new StringBuilder();
- for (Map.Entry<String, String[]> entry : this.parameterMap.entrySet()) {
+ for (Map.Entry<String, MockRequestParameter[]> entry : map.entrySet()) {
if (entry.getValue() != null) {
- for (String value : entry.getValue()) {
- if (querystring.length() != 0) {
- querystring.append('&');
- }
- querystring.append(URLEncoder.encode(entry.getKey(), CharEncoding.UTF_8));
- querystring.append('=');
- if (value != null) {
- querystring.append(URLEncoder.encode(value, CharEncoding.UTF_8));
- }
- }
+ formatQueryStringParameter(querystring, entry);
}
}
- if (querystring.length() > 0) {
- return querystring.toString();
- } else {
- return null;
+ return querystring.length() > 0 ? querystring.toString() : null;
+ }
+
+ private static void formatQueryStringParameter(StringBuilder querystring, Map.Entry<String, MockRequestParameter[]> entry) throws UnsupportedEncodingException {
+ for (MockRequestParameter value : entry.getValue()) {
+ if (querystring.length() != 0) {
+ querystring.append('&');
+ }
+ querystring.append(URLEncoder.encode(entry.getKey(), CharEncoding.UTF_8));
+ querystring.append('=');
+ if (value.getString() != null) {
+ querystring.append(URLEncoder.encode(value.getString(), CharEncoding.UTF_8));
+ }
}
}
@@ -272,13 +287,13 @@
public Locale getLocale() {
return locale;
}
-
+
/**
* @param loc Request locale
*/
public void setLocale(Locale loc) {
this.locale = loc;
- }
+ }
@Override
public String getContextPath() {
@@ -304,7 +319,7 @@
}
}
- private void parseQueryString(Map<String, String[]> map, String query) throws UnsupportedEncodingException {
+ private void parseQueryString(Map<String, MockRequestParameter[]> map, String query) throws UnsupportedEncodingException {
Map<String, List<String>> queryPairs = new LinkedHashMap<String, List<String>>();
String[] pairs = query.split("&");
for (String pair : pairs) {
@@ -313,13 +328,18 @@
if (!queryPairs.containsKey(key)) {
queryPairs.put(key, new ArrayList<String>());
}
- String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1),
- CharEncoding.UTF_8) : null;
+ String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), CharEncoding.UTF_8) : null;
queryPairs.get(key).add(value);
}
map.clear();
for (Map.Entry<String, List<String>> entry : queryPairs.entrySet()) {
- map.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
+ List<String> valueList = entry.getValue();
+ int numEntries = valueList.size();
+ MockRequestParameter[] values = new MockRequestParameter[numEntries];
+ for (int i = 0; i < numEntries; i++) {
+ values[i] = new MockRequestParameter(entry.getKey(), valueList.get(i));
+ }
+ map.put(entry.getKey(), values);
}
}
@@ -396,7 +416,8 @@
/**
* Add header, keep existing ones with same name.
- * @param name Header name
+ *
+ * @param name Header name
* @param value Header value
*/
public void addHeader(String name, String value) {
@@ -405,7 +426,8 @@
/**
* Add header, keep existing ones with same name.
- * @param name Header name
+ *
+ * @param name Header name
* @param value Header value
*/
public void addIntHeader(String name, int value) {
@@ -414,6 +436,7 @@
/**
* Add header, keep existing ones with same name.
+ *
* @param name Header name
* @param date Header value
*/
@@ -423,7 +446,8 @@
/**
* Set header, overwrite existing ones with same name.
- * @param name Header name
+ *
+ * @param name Header name
* @param value Header value
*/
public void setHeader(String name, String value) {
@@ -432,7 +456,8 @@
/**
* Set header, overwrite existing ones with same name.
- * @param name Header name
+ *
+ * @param name Header name
* @param value Header value
*/
public void setIntHeader(String name, int value) {
@@ -441,6 +466,7 @@
/**
* Set header, overwrite existing ones with same name.
+ *
* @param name Header name
* @param date Header value
*/
@@ -460,6 +486,7 @@
/**
* Set cookie
+ *
* @param cookie Cookie
*/
public void addCookie(Cookie cookie) {
@@ -478,9 +505,9 @@
@Override
public RequestParameter getRequestParameter(String name) {
- String value = getParameter(name);
- if (value != null) {
- return new MockRequestParameter(name, value);
+ MockRequestParameter[] params = this.parameterMap.get(name);
+ if (params != null && params.length > 0) {
+ return params[0];
}
return null;
}
@@ -488,7 +515,7 @@
@Override
public RequestParameterMap getRequestParameterMap() {
MockRequestParameterMap map = new MockRequestParameterMap();
- for (Map.Entry<String,String[]> entry : getParameterMap().entrySet()) {
+ for (Map.Entry<String, String[]> entry : getParameterMap().entrySet()) {
map.put(entry.getKey(), getRequestParameters(entry.getKey()));
}
return map;
@@ -496,15 +523,7 @@
@Override
public RequestParameter[] getRequestParameters(String name) {
- String[] values = getParameterValues(name);
- if (values == null) {
- return null;
- }
- RequestParameter[] requestParameters = new RequestParameter[values.length];
- for (int i = 0; i < values.length; i++) {
- requestParameters[i] = new MockRequestParameter(name, values[i]);
- }
- return requestParameters;
+ return this.parameterMap.get(name);
}
// part of Sling API 2.7
@@ -516,6 +535,54 @@
return params;
}
+ /**
+ * Add a request parameter that consists of a simple name/value pair. This
+ * emulates a simple form field.
+ *
+ * @param name field name
+ * @param value field value
+ */
+ public void addRequestParameter(String name, String value) {
+ MockRequestParameter mockRequestParameter = new MockRequestParameter(name, value);
+ addMockRequestParameter(name, mockRequestParameter);
+ }
+
+ /**
+ * Add a request parameter that emulates a file upload field.
+ *
+ * @param name field name
+ * @param content file content
+ * @param contentType mime type of content in the field
+ */
+ public void addRequestParameter(String name, byte[] content, String contentType) {
+ MockRequestParameter mockRequestParameter = new MockRequestParameter(name, content, contentType);
+ addMockRequestParameter(name, mockRequestParameter);
+ }
+
+ /**
+ * Add a request parameter that emulates a file upload field with a filename
+ * associated with it.
+ *
+ * @param name field name
+ * @param content file content
+ * @param contentType mime type of content in the field
+ * @param filename filename associated with content
+ */
+ public void addRequestParameter(String name, byte[] content, String contentType, String filename) {
+ MockRequestParameter mockRequestParameter = new MockRequestParameter(name, content, contentType, filename);
+ addMockRequestParameter(name, mockRequestParameter);
+ }
+
+ private void addMockRequestParameter(String name, MockRequestParameter mockRequestParameter) {
+ if (this.parameterMap.containsKey(name)) {
+ List<MockRequestParameter> list = new ArrayList<>(Arrays.asList(this.parameterMap.get(name)));
+ list.add(mockRequestParameter);
+ this.parameterMap.put(name, list.toArray(new MockRequestParameter[0]));
+ } else {
+ this.parameterMap.put(name, new MockRequestParameter[] { mockRequestParameter });
+ }
+ }
+
@Override
public String getCharacterEncoding() {
return this.characterEncoding;
@@ -531,11 +598,10 @@
if (this.contentType == null) {
return null;
} else {
- return this.contentType
- + (StringUtils.isNotBlank(characterEncoding) ? CHARSET_SEPARATOR + characterEncoding : "");
+ return this.contentType + (StringUtils.isNotBlank(characterEncoding) ? CHARSET_SEPARATOR + characterEncoding : "");
}
}
-
+
public void setContentType(String type) {
this.contentType = type;
if (StringUtils.contains(this.contentType, CHARSET_SEPARATOR)) {
@@ -552,23 +618,27 @@
getInputStreamCalled = true;
return new ServletInputStream() {
private final InputStream is = content == null ? new ByteArrayInputStream(new byte[0]) : new ByteArrayInputStream(content);
+
@Override
public int read() throws IOException {
return is.read();
}
+
@Override
public boolean isReady() {
return true;
}
+
@Override
public boolean isFinished() {
throw new UnsupportedOperationException();
}
+
@Override
public void setReadListener(ReadListener readListener) {
throw new UnsupportedOperationException();
}
- };
+ };
}
@Override
@@ -578,7 +648,7 @@
}
return content.length;
}
-
+
public void setContent(byte[] content) {
this.content = content;
}
@@ -588,7 +658,7 @@
if (requestDispatcherFactory == null) {
throw new IllegalStateException("Please provdide a MockRequestDispatcherFactory (setRequestDispatcherFactory).");
}
- return requestDispatcherFactory.getRequestDispatcher(path, null);
+ return requestDispatcherFactory.getRequestDispatcher(path, null);
}
@Override
@@ -596,7 +666,7 @@
if (requestDispatcherFactory == null) {
throw new IllegalStateException("Please provdide a MockRequestDispatcherFactory (setRequestDispatcherFactory).");
}
- return requestDispatcherFactory.getRequestDispatcher(path, options);
+ return requestDispatcherFactory.getRequestDispatcher(path, options);
}
@Override
@@ -614,7 +684,7 @@
}
return requestDispatcherFactory.getRequestDispatcher(resource, options);
}
-
+
public void setRequestDispatcherFactory(MockRequestDispatcherFactory requestDispatcherFactory) {
this.requestDispatcherFactory = requestDispatcherFactory;
}
@@ -667,9 +737,9 @@
@Override
public String getPathInfo() {
if (this.pathInfo != null) {
- return this.pathInfo;
+ return this.pathInfo;
}
-
+
RequestPathInfo requestPathInfo = this.getRequestPathInfo();
if (StringUtils.isEmpty(requestPathInfo.getResourcePath())) {
@@ -696,7 +766,7 @@
return pathInfo.toString();
}
-
+
public void setPathInfo(String pathInfo) {
this.pathInfo = pathInfo;
}
@@ -727,8 +797,7 @@
requestUrl.append(this.getScheme());
requestUrl.append("://");
requestUrl.append(getServerName());
- if ((StringUtils.equals(this.getScheme(), "http") && this.getServerPort() != 80) ||
- (StringUtils.equals(this.getScheme(), "https") && this.getServerPort() != 443)) {
+ if ((StringUtils.equals(this.getScheme(), "http") && this.getServerPort() != 80) || (StringUtils.equals(this.getScheme(), "https") && this.getServerPort() != 443)) {
requestUrl.append(':');
requestUrl.append(getServerPort());
}
@@ -757,12 +826,11 @@
public String getResponseContentType() {
return responseContentType;
}
-
+
public void setResponseContentType(String responseContentType) {
this.responseContentType = responseContentType;
}
-
@Override
public Enumeration<String> getResponseContentTypes() {
return Collections.enumeration(Collections.singleton(responseContentType));
diff --git a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java
index 3f74230..dcba6b4 100644
--- a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java
+++ b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java
@@ -47,6 +47,7 @@
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.sling.api.request.RequestDispatcherOptions;
+import org.apache.sling.api.request.RequestParameter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
@@ -317,6 +318,47 @@
}
@Test
+ public void testFormRequestParameters() throws Exception {
+ request.addRequestParameter("param1", "value1");
+ request.addRequestParameter("param2", "value2".getBytes("UTF-8"), "application/xml");
+ request.addRequestParameter("param3", "value3".getBytes("UTF-8"), "application/json", "param3.json");
+ request.addRequestParameter("param4", "value4a".getBytes("UTF-8"), "application/xml");
+ request.addRequestParameter("param4", "value4b".getBytes("UTF-8"), "application/json");
+
+ RequestParameter param1 = request.getRequestParameter("param1");
+ assertEquals("value1", param1.getString());
+ assertArrayEquals("value1".getBytes(), param1.get());
+ assertEquals("text/plain", param1.getContentType());
+ assertArrayEquals("value1".getBytes(), param1.get());
+
+ RequestParameter param2 = request.getRequestParameter("param2");
+ assertEquals("value2", param2.getString());
+ assertEquals("application/xml", param2.getContentType());
+ assertArrayEquals("value2".getBytes(), param2.get());
+
+ RequestParameter param3 = request.getRequestParameter("param3");
+ assertEquals("value3", param3.getString());
+ assertEquals("application/json", param3.getContentType());
+ assertArrayEquals("value3".getBytes(), param3.get());
+ assertEquals("param3.json", param3.getFileName());
+
+ RequestParameter param4 = request.getRequestParameter("param4");
+ assertEquals("value4a", param4.getString());
+ assertEquals("application/xml", param4.getContentType());
+ assertArrayEquals("value4a".getBytes(), param4.get());
+
+ RequestParameter[] param4array = request.getRequestParameters("param4");
+ assertEquals(2, param4array.length);
+ assertEquals("value4a", param4array[0].getString());
+ assertEquals("value4b", param4array[1].getString());
+ assertEquals("application/xml", param4array[0].getContentType());
+ assertEquals("application/json", param4array[1].getContentType());
+ assertArrayEquals("value4a".getBytes(), param4array[0].get());
+ assertArrayEquals("value4b".getBytes(), param4array[1].get());
+
+ }
+
+ @Test
public void testContentTypeCharset() throws Exception {
assertNull(request.getContentType());
assertNull(request.getCharacterEncoding());
@@ -462,4 +504,5 @@
assertSame(resource, request.getRequestPathInfo().getSuffixResource());
}
+
}