When I hit RpcServlet(gadgets-metadata) with a POST that has
Transfer-Encoding chunked the server returns a 411 Length Required.
Problem is the http 1.1 spec says that Content-Length should not be
there, and more importantly Content-Length must be ignored if the
Transfer-Encoding is present and has a value other than identity.

I've done a basic search of the mailing list and I can't see why the
length checks are present, but I suspect they are some basic DOS
protection.   Just to give additional information all of my posted
content to /gadgets/metadata have had Content-Length settings in the
range of 210-220.  The check if the content length is too long is
1024*128.   Seems to be a check to avoid malformed or maliciously
formed POSTS.  I suspect there are issues around transfer-encoding
where someone could choke a server with extremely large POST entity
requests.  So RpcServlet may have avoided that issue, but did so by
breaking the http 1.1 spec.

Attached are a unit test (JUnit 3, requires httpclient 3.1) and a
patch file that causes the test to pass.  I don't believe that this is
necessarily the right fix, but to know that I would have to know why
the checks are there.

Can anyone shed any light on this issue?
-- 
David S Boyer (IBM Jazz Web UI Foundation)
[email protected]
703.499.8728(h)
703.408.5395(m)
### Jazz Patch 1.0
#comment: "shindig /gadgets/metadata fails on a post with transfer-encoding \"chunked\""
#changeset: "_7oCOIqOkEd6nWIGVCz8vZg"
#date: "2009-09-17 12:37:29.000000099 -0400"
#work_item: "_T3zS4KOnEd6aXrImTl-GCA" "WorkItem" "com.ibm.team.workitem"
#itemid: "org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet/RpcServlet.java" "_1PdA4KLzEd67a_hGj--Rpw" "_9lwKIF9rEd6yqpSYkR3zcw"
#itemid: "org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet" "_1Nl_sKLzEd67a_hGj--Rpw" "_9lwKIF9rEd6yqpSYkR3zcw"
#itemid: "org.apache.shindig" "_p261AIEKEd6WONUw66A2xQ" "_9lwKIF9rEd6yqpSYkR3zcw"
#itemid: "org.apache.shindig/src-tests" "_H0gE4KL-Ed67a_hGj--Rpw" "_9lwKIF9rEd6yqpSYkR3zcw"
#before_state: "org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet/RpcServlet.java" "_1PdA4KLzEd67a_hGj--Rpw" "_PkyfNKOfEd6nWIGVCz8vZg"
#after_state: "org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet/RpcServlet.java" "_1PdA4KLzEd67a_hGj--Rpw" "_7tIJhKOkEd6nWIGVCz8vZg"
#after_state: "org.apache.shindig/src-tests" "_H0gE4KL-Ed67a_hGj--Rpw" "_F43kwKOlEd6nWIGVCz8vZg"
#create_folder: "org.apache.shindig/src-tests"
#
diff -u -N org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet/RpcServlet.java org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet/RpcServlet.java
--- org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet/RpcServlet.java	2009-09-17 11:31:40.000000000 -0400
+++ org.apache.shindig/src-shindig/org/apache/shindig/gadgets/servlet/RpcServlet.java	2009-09-17 12:06:27.000000000 -0400
@@ -84,29 +84,33 @@
   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
       throws IOException {
-
-    int length = request.getContentLength();
-    if (length <= 0) {
-      logger.info("No Content-Length specified.");
-      response.setStatus(HttpServletResponse.SC_LENGTH_REQUIRED);
-      return;
-    }
-    if (length > POST_REQUEST_MAX_SIZE) {
-      logger.info("Request size too large: " + length);
-      response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
-      return;
-    }
-
-    ServletInputStream is = request.getInputStream();
-    byte[] body = IOUtils.toByteArray(is);
-    if (body.length != length) {
-      logger.info("Wrong size. Length: " + length + " real: " + body.length);
-      response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
-      return;
-    }
-
-    Result result = process(request, response, body);
-    response.getWriter().write(result.getOutput());
+		byte[] body = null;
+		if ( request.getHeader("Transfer-Encoding").equals("chunked") ) {
+			ServletInputStream is = request.getInputStream();
+			body = IOUtils.toByteArray(is);
+		} else {
+			int length = request.getContentLength();
+			if (length <= 0) {
+				logger.info("No Content-Length specified.");
+				response.setStatus(HttpServletResponse.SC_LENGTH_REQUIRED);
+				return;
+			}
+			if (length > POST_REQUEST_MAX_SIZE) {
+				logger.info("Request size too large: " + length);
+				response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
+				return;
+			}
+			ServletInputStream is = request.getInputStream();
+			body = IOUtils.toByteArray(is);
+			if (body.length != length) {
+				logger.info("Wrong size. Length: " + length + " real: "
+						+ body.length);
+				response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+				return;
+			}
+		}
+		Result result = process(request, response, body);
+		response.getWriter().write(result.getOutput());
   }
 
   private String validateParameterValue(HttpServletRequest request, String parameter)
package org.apache.shindig;

import java.io.IOException;

import junit.framework.TestCase;

import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;

import sun.net.www.protocol.http.HttpURLConnection;

public class RpcServletTest extends TestCase {
	
	private final static String HOST = "localhost";
	private final static String PORT = "9081";
	private final static String URL = "http://"+HOST+":"+PORT+"/gadgets/metadata";;
	private final static String REQUEST = "blah blah blah";
	
	public void testTransferEncodingChunked() throws IOException {
		HttpClient client = new HttpClient();
		HttpState state = null;
		HostConfiguration config = new HostConfiguration();
		PostMethod post = new PostMethod(URL);
		post.setContentChunked(true);
		post.setRequestEntity(new StringRequestEntity(REQUEST,null,null));
		int x = client.executeMethod(post);
		if ( x == HttpURLConnection.HTTP_LENGTH_REQUIRED ) {
			fail("HTTP Length Required not a valid error when using Transfer-Encoding chunked");
		}
	}

}

Reply via email to