You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2013/09/11 16:07:31 UTC
svn commit: r1521854 - in /tomcat/tc7.0.x/trunk: ./
java/org/apache/coyote/ajp/ java/org/apache/coyote/http11/
test/org/apache/coyote/ajp/ test/org/apache/coyote/http11/
Author: markt
Date: Wed Sep 11 14:07:31 2013
New Revision: 1521854
URL: http://svn.apache.org/r1521854
Log:
Better adherence to RFC2616 for content-length headers
Modified:
tomcat/tc7.0.x/trunk/ (props changed)
tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
tomcat/tc7.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java
tomcat/tc7.0.x/trunk/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1521829
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java?rev=1521854&r1=1521853&r2=1521854&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java Wed Sep 11 14:07:31 2013
@@ -25,6 +25,8 @@ import java.security.cert.CertificateFac
import java.security.cert.X509Certificate;
import java.util.concurrent.atomic.AtomicBoolean;
+import javax.servlet.http.HttpServletResponse;
+
import org.apache.coyote.AbstractProcessor;
import org.apache.coyote.ActionCode;
import org.apache.coyote.AsyncContextCallback;
@@ -691,6 +693,7 @@ public abstract class AbstractAjpProcess
// Set this every time in case limit has been changed via JMX
headers.setLimit(endpoint.getMaxHeaderCount());
+ boolean contentLengthSet = false;
int hCount = requestHeaderMessage.getInt();
for(int i = 0 ; i < hCount ; i++) {
String hName = null;
@@ -725,8 +728,15 @@ public abstract class AbstractAjpProcess
if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
(hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
- // just read the content-length header, so set it
- request.setContentLength(vMB.getLong());
+ long cl = vMB.getLong();
+ if (contentLengthSet) {
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ error = true;
+ } else {
+ contentLengthSet = true;
+ // Set the content-length header for the request
+ request.setContentLength(cl);
+ }
} else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
(hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
// just read the content-type header, so set it
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java?rev=1521854&r1=1521853&r2=1521854&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java Wed Sep 11 14:07:31 2013
@@ -1296,10 +1296,20 @@ public abstract class AbstractHttp11Proc
// Parse content-length header
long contentLength = request.getContentLengthLong();
- if (contentLength >= 0 && !contentDelimitation) {
- getInputBuffer().addActiveFilter
- (inputFilters[Constants.IDENTITY_FILTER]);
- contentDelimitation = true;
+ if (contentLength >= 0) {
+ if (contentDelimitation) {
+ // contentDelimitation being true at this point indicates that
+ // chunked encoding is being used but chunked encoding should
+ // not be used with a content length. RFC 2616, section 4.4,
+ // bullet 3 states Content-Length must be ignored in this case -
+ // so remove it.
+ headers.removeHeader("content-length");
+ request.setContentLength(-1);
+ } else {
+ getInputBuffer().addActiveFilter
+ (inputFilters[Constants.IDENTITY_FILTER]);
+ contentDelimitation = true;
+ }
}
MessageBytes valueMB = headers.getValue("host");
Modified: tomcat/tc7.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java?rev=1521854&r1=1521853&r2=1521854&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java Wed Sep 11 14:07:31 2013
@@ -98,9 +98,20 @@ public class TestAbstractAjpProcessor ex
ajpClient.disconnect();
}
+ @Test
+ public void testPost() throws Exception {
+ doTestPost(false, HttpServletResponse.SC_OK);
+ }
+
@Test
- public void testSimplePost() throws Exception {
+ public void testPostMultipleContentLength() throws Exception {
+ // Multiple content lengths
+ doTestPost(true, HttpServletResponse.SC_BAD_REQUEST);
+ }
+
+
+ public void doTestPost(boolean multipleCL, int expectedStatus) throws Exception {
Tomcat tomcat = getTomcatInstance();
@@ -119,6 +130,9 @@ public class TestAbstractAjpProcessor ex
TesterAjpMessage forwardMessage =
ajpClient.createForwardMessage("/echo-params.jsp", 4);
forwardMessage.addHeader(0xA008, "9");
+ if (multipleCL) {
+ forwardMessage.addHeader(0xA008, "99");
+ }
forwardMessage.addHeader(0xA007, "application/x-www-form-urlencoded");
forwardMessage.end();
@@ -128,15 +142,20 @@ public class TestAbstractAjpProcessor ex
TesterAjpMessage responseHeaders =
ajpClient.sendMessage(forwardMessage, bodyMessage);
- // Expect 3 messages: headers, body, end
- validateResponseHeaders(responseHeaders, 200);
- // Skip the body
- TesterAjpMessage responseBody = ajpClient.readMessage();
- validateResponseBody(responseBody, "test - data");
- validateResponseEnd(ajpClient.readMessage(), true);
+ validateResponseHeaders(responseHeaders, expectedStatus);
+ if (expectedStatus == HttpServletResponse.SC_OK) {
+ // Expect 3 messages: headers, body, end for a valid request
+ TesterAjpMessage responseBody = ajpClient.readMessage();
+ validateResponseBody(responseBody, "test - data");
+ validateResponseEnd(ajpClient.readMessage(), true);
+
+ // Double check the connection is still open
+ validateCpong(ajpClient.cping());
+ } else {
+ // Expect 2 messages: headers, end for an invalid request
+ validateResponseEnd(ajpClient.readMessage(), false);
+ }
- // Double check the connection is still open
- validateCpong(ajpClient.cping());
ajpClient.disconnect();
}
Modified: tomcat/tc7.0.x/trunk/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java?rev=1521854&r1=1521853&r2=1521854&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java (original)
+++ tomcat/tc7.0.x/trunk/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java Wed Sep 11 14:07:31 2013
@@ -101,6 +101,54 @@ public class TestAbstractHttp11Processor
@Test
+ public void testWithTEChunked() throws Exception {
+ doTestWithTEChunked(false);
+ }
+
+
+ @Test
+ public void testWithTEChunkedWithCL() throws Exception {
+ // Should be ignored
+ doTestWithTEChunked(true);
+ }
+
+
+ private void doTestWithTEChunked(boolean withCL)
+ throws Exception {
+
+ Tomcat tomcat = getTomcatInstance();
+
+ // Use the normal Tomcat ROOT context
+ File root = new File("test/webapp-3.0");
+ tomcat.addWebapp("", root.getAbsolutePath());
+
+ tomcat.start();
+
+ String request =
+ "POST /echo-params.jsp HTTP/1.1" + SimpleHttpClient.CRLF +
+ "Host: any" + SimpleHttpClient.CRLF +
+ (withCL ? "Content-length: 1" + SimpleHttpClient.CRLF : "") +
+ "Transfer-encoding: chunked" + SimpleHttpClient.CRLF +
+ "Content-Type: application/x-www-form-urlencoded" +
+ SimpleHttpClient.CRLF +
+ "Connection: close" + SimpleHttpClient.CRLF +
+ SimpleHttpClient.CRLF +
+ "9" + SimpleHttpClient.CRLF +
+ "test=data" + SimpleHttpClient.CRLF +
+ "0" + SimpleHttpClient.CRLF +
+ SimpleHttpClient.CRLF;
+
+ Client client = new Client(tomcat.getConnector().getLocalPort());
+ client.setRequest(new String[] {request});
+
+ client.connect();
+ client.processRequest();
+ assertTrue(client.isResponse200());
+ assertTrue(client.getResponseBody().contains("test - data"));
+ }
+
+
+ @Test
public void testWithTEIdentity() throws Exception {
Tomcat tomcat = getTomcatInstance();
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org