Author: fmui
Date: Wed Oct 1 14:14:13 2014
New Revision: 1628709
URL: http://svn.apache.org/r1628709
Log:
simple reimplementation of the form data parser including _charset_ field
support
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/POSTHttpServletRequestWrapper.java
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/QueryStringHttpServletRequestWrapper.java
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/CheckServletInputStreamTest.java
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/HttpRequestMockHelper.java
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/MultipartParserTest.java
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/POSTHttpServletRequestWrapper.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/POSTHttpServletRequestWrapper.java?rev=1628709&r1=1628708&r2=1628709&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/POSTHttpServletRequestWrapper.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/impl/browser/POSTHttpServletRequestWrapper.java
Wed Oct 1 14:14:13 2014
@@ -20,12 +20,16 @@ package org.apache.chemistry.opencmis.se
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.math.BigInteger;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
+import
org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import org.apache.chemistry.opencmis.commons.impl.IOUtils;
import org.apache.chemistry.opencmis.server.shared.HttpUtils;
@@ -33,19 +37,24 @@ import org.apache.chemistry.opencmis.ser
import
org.apache.chemistry.opencmis.server.shared.ThresholdOutputStreamFactory;
public final class POSTHttpServletRequestWrapper extends
QueryStringHttpServletRequestWrapper {
+
+ public static final String FORM_URLENCODED =
"application/x-www-form-urlencoded";
+ private static final int MAX_CONTENT_BYTES = 10 * 1024 * 1024;
+ private static final int BUFFER_SIZE = 64 * 1024;
+ private static final String CHARSET_FIELD = "_charset_";
+
private String filename;
private String contentType;
private BigInteger size;
private InputStream stream;
+ @SuppressWarnings("unchecked")
public POSTHttpServletRequestWrapper(HttpServletRequest request,
ThresholdOutputStreamFactory streamFactory)
throws IOException {
super(request);
- // check multipart
- boolean isMultipart = MultipartParser.isMultipartContent(request);
-
- if (isMultipart) {
+ if (MultipartParser.isMultipartContent(request)) {
+ // multipart processing
MultipartParser parser = new MultipartParser(request,
streamFactory);
parser.parse();
@@ -69,18 +78,14 @@ public final class POSTHttpServletReques
if ((contentTypeControl != null) &&
(contentTypeControl.trim().length() > 0)) {
contentType = contentTypeControl;
}
- } else {
+ } else if (isFormUrlencodedContent(request)) {
// form data processing
- StringBuilder sb = new StringBuilder();
-
- InputStreamReader sr = new
InputStreamReader(request.getInputStream(), IOUtils.UTF8);
- char[] buffer = new char[4096];
- int c = 0;
- while ((c = sr.read(buffer)) > -1) {
- sb.append(buffer, 0, c);
+ if (!parseFormUrlEncodedData(request)) {
+ parameters.putAll(request.getParameterMap());
}
-
- parseFormData(sb.toString());
+ } else {
+ // spec incompliant form encoding
+ throw new CmisInvalidArgumentException("Invalid form encoding!");
}
}
@@ -99,4 +104,167 @@ public final class POSTHttpServletReques
public InputStream getStream() {
return stream;
}
+
+ /**
+ * Parses a form data request
+ *
+ * @param request
+ * the request
+ * @return {@code true} if the body contained data, {@code false} otherwise
+ */
+ protected boolean parseFormUrlEncodedData(HttpServletRequest request)
throws IOException {
+ byte data[] = new byte[BUFFER_SIZE];
+ int dataPos = 0;
+
+ InputStream stream = request.getInputStream();
+ int b;
+ byte buffer[] = new byte[BUFFER_SIZE];
+
+ // read stream
+ while ((b = stream.read(buffer)) != -1) {
+ if (dataPos + b > MAX_CONTENT_BYTES) {
+ throw new CmisInvalidArgumentException("Limit exceeded!");
+ }
+
+ if (data.length - dataPos < b) {
+ // expand buffer
+ int newSize = ((data.length + b) * 2 < MAX_CONTENT_BYTES ?
(data.length + b * 2) : MAX_CONTENT_BYTES);
+ byte[] newbuf = new byte[newSize];
+ System.arraycopy(data, 0, newbuf, 0, dataPos);
+ data = newbuf;
+ }
+
+ System.arraycopy(buffer, 0, data, dataPos, b);
+ dataPos += b;
+ }
+
+ if (dataPos == 0) {
+ // empty stream
+ return false;
+ }
+
+ // parse parameters
+ boolean parseName = true;
+ boolean parseCharset = false;
+ int startPos = 0;
+
+ List<String[]> rawParameters = new ArrayList<String[]>();
+ String rawName = null;
+ String rawValue = null;
+
+ String charset = null;
+
+ for (int i = 0; i < dataPos; i++) {
+ switch (data[i]) {
+ case '=':
+ if (startPos < i) {
+ rawName = new String(data, startPos, i - startPos,
IOUtils.ISO_8859_1);
+ if (CHARSET_FIELD.equalsIgnoreCase(rawName)) {
+ parseCharset = true;
+ }
+ }
+
+ parseName = false;
+ startPos = i + 1;
+ break;
+
+ case '&':
+ if (parseName) {
+ if (startPos < i) {
+ rawName = new String(data, startPos, i - startPos,
IOUtils.ISO_8859_1);
+ rawParameters.add(new String[] { rawName, null });
+ }
+ } else {
+ if (rawName != null) {
+ rawValue = new String(data, startPos, i - startPos,
IOUtils.ISO_8859_1);
+ rawParameters.add(new String[] { rawName, rawValue });
+ if (parseCharset) {
+ charset = rawValue;
+ }
+ }
+ }
+
+ rawName = null;
+ rawValue = null;
+
+ parseName = true;
+ parseCharset = false;
+ startPos = i + 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (startPos < dataPos) {
+ // there is a final parameter after the last '&'
+ if (parseName) {
+ rawName = new String(data, startPos, dataPos - startPos,
IOUtils.ISO_8859_1);
+ rawParameters.add(new String[] { rawName, null });
+ } else {
+ if (rawName != null) {
+ rawValue = new String(data, startPos, dataPos - startPos,
IOUtils.ISO_8859_1);
+ rawParameters.add(new String[] { rawName, rawValue });
+ if (parseCharset) {
+ charset = rawValue;
+ }
+ }
+ }
+ } else if (!parseName) {
+ // the stream ended with '='
+ rawParameters.add(new String[] { rawName, "" });
+ }
+
+ data = null;
+
+ // find charset
+ if (charset == null) {
+ // check charset in content type
+ String contentType = request.getContentType();
+ if (contentType != null) {
+ String[] parts = contentType.split(";");
+ for (int i = 1; i < parts.length; i++) {
+ String part = parts[i].trim().toLowerCase(Locale.ENGLISH);
+ if (part.startsWith("charset")) {
+ int x = part.indexOf('=');
+ charset = part.substring(x + 1).trim();
+ break;
+ }
+ }
+ }
+ }
+
+ if (charset == null) {
+ // set default charset
+ charset = IOUtils.UTF8;
+ }
+
+ // decode parameters
+ for (String[] rawParameter : rawParameters) {
+ String name = URLDecoder.decode(rawParameter[0], charset);
+
+ String value = null;
+ if (rawParameter[1] != null) {
+ value = URLDecoder.decode(rawParameter[1], charset);
+ }
+
+ addParameter(name, value);
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns if the request is a form-urlencoded request.
+ */
+ public static final boolean isFormUrlencodedContent(HttpServletRequest
request) {
+ String contentType = request.getContentType();
+
+ if (contentType != null &&
contentType.toLowerCase(Locale.ENGLISH).startsWith(FORM_URLENCODED)) {
+ return true;
+ }
+
+ return false;
+ }
}
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/QueryStringHttpServletRequestWrapper.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/QueryStringHttpServletRequestWrapper.java?rev=1628709&r1=1628708&r2=1628709&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/QueryStringHttpServletRequestWrapper.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/main/java/org/apache/chemistry/opencmis/server/shared/QueryStringHttpServletRequestWrapper.java
Wed Oct 1 14:14:13 2014
@@ -35,7 +35,7 @@ import org.apache.chemistry.opencmis.com
*/
public class QueryStringHttpServletRequestWrapper extends
HttpServletRequestWrapper {
- private Map<String, String[]> parameters;
+ protected Map<String, String[]> parameters;
public QueryStringHttpServletRequestWrapper(HttpServletRequest request)
throws IOException {
super(request);
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/CheckServletInputStreamTest.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/CheckServletInputStreamTest.java?rev=1628709&r1=1628708&r2=1628709&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/CheckServletInputStreamTest.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/CheckServletInputStreamTest.java
Wed Oct 1 14:14:13 2014
@@ -106,8 +106,8 @@ public class CheckServletInputStreamTest
ByteArrayInputStream originStream = new
ByteArrayInputStream(byteBuffer);
try {
- ProtectionRequestWrapper prw = new
ProtectionRequestWrapper(HttpRequestMockHelper.createRequest(BOUNDARY,
- originStream), max);
+ ProtectionRequestWrapper prw = new
ProtectionRequestWrapper(HttpRequestMockHelper.createMultipartRequest(
+ BOUNDARY, originStream), max);
InputStream stream = prw.getInputStream();
int countS = 0;
@@ -143,8 +143,8 @@ public class CheckServletInputStreamTest
originStream = new ByteArrayInputStream(byteBuffer);
try {
- ProtectionRequestWrapper prw = new
ProtectionRequestWrapper(HttpRequestMockHelper.createRequest(BOUNDARY,
- originStream), max);
+ ProtectionRequestWrapper prw = new
ProtectionRequestWrapper(HttpRequestMockHelper.createMultipartRequest(
+ BOUNDARY, originStream), max);
InputStream stream = prw.getInputStream();
int countS = 0;
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/HttpRequestMockHelper.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/HttpRequestMockHelper.java?rev=1628709&r1=1628708&r2=1628709&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/HttpRequestMockHelper.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/HttpRequestMockHelper.java
Wed Oct 1 14:14:13 2014
@@ -29,7 +29,7 @@ import org.mockito.Mockito;
public class HttpRequestMockHelper {
- public static HttpServletRequest createRequest(String boundary, byte[]
content) throws IOException {
+ public static HttpServletRequest createMultipartRequest(String boundary,
byte[] content) throws IOException {
FakeServletInputStream stream = new FakeServletInputStream(content);
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
@@ -39,7 +39,8 @@ public class HttpRequestMockHelper {
return request;
}
- public static HttpServletRequest createRequest(String boundary,
InputStream inputStream) throws IOException {
+ public static HttpServletRequest createMultipartRequest(String boundary,
InputStream inputStream)
+ throws IOException {
FakeServletInputStream stream = new
FakeServletInputStream(inputStream);
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
@@ -49,6 +50,17 @@ public class HttpRequestMockHelper {
return request;
}
+ public static HttpServletRequest createFormRequest(String encoding, byte[]
content) throws IOException {
+ FakeServletInputStream stream = new FakeServletInputStream(content);
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ Mockito.when(request.getContentType()).thenReturn(
+ "application/x-www-form-urlencoded" + (encoding == null ? "" :
";charset=" + encoding));
+ Mockito.when(request.getInputStream()).thenReturn(stream);
+
+ return request;
+ }
+
private static class FakeServletInputStream extends ServletInputStream {
private InputStream stream;
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/MultipartParserTest.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/MultipartParserTest.java?rev=1628709&r1=1628708&r2=1628709&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/MultipartParserTest.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-bindings/src/test/java/org/apache/chemistry/opencmis/server/impl/MultipartParserTest.java
Wed Oct 1 14:14:13 2014
@@ -408,7 +408,7 @@ public class MultipartParserTest {
// ---- helpers ----
private MultipartParser prepareParser(String boundary, byte[] content)
throws Exception {
- HttpServletRequest request =
HttpRequestMockHelper.createRequest(boundary, content);
+ HttpServletRequest request =
HttpRequestMockHelper.createMultipartRequest(boundary, content);
ThresholdOutputStreamFactory streamFactory =
ThresholdOutputStreamFactory.newInstance(null, THRESHOLD,
MAX_SIZE, false);