|
|
1af9a1 |
--- java/org/apache/coyote/ajp/AbstractAjpProcessor.java.orig 2014-03-14 17:13:46.228345000 -0400
|
|
|
1af9a1 |
+++ java/org/apache/coyote/ajp/AbstractAjpProcessor.java 2014-03-18 13:54:13.570758000 -0400
|
|
|
1af9a1 |
@@ -25,6 +25,8 @@
|
|
|
1af9a1 |
import java.security.cert.X509Certificate;
|
|
|
1af9a1 |
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
1af9a1 |
|
|
|
1af9a1 |
+import javax.servlet.http.HttpServletResponse;
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
import org.apache.coyote.AbstractProcessor;
|
|
|
1af9a1 |
import org.apache.coyote.ActionCode;
|
|
|
1af9a1 |
import org.apache.coyote.AsyncContextCallback;
|
|
|
1af9a1 |
@@ -651,7 +653,7 @@
|
|
|
1af9a1 |
|
|
|
1af9a1 |
// Set this every time in case limit has been changed via JMX
|
|
|
1af9a1 |
headers.setLimit(endpoint.getMaxHeaderCount());
|
|
|
1af9a1 |
-
|
|
|
1af9a1 |
+ boolean contentLengthSet = false;
|
|
|
1af9a1 |
int hCount = requestHeaderMessage.getInt();
|
|
|
1af9a1 |
for(int i = 0 ; i < hCount ; i++) {
|
|
|
1af9a1 |
String hName = null;
|
|
|
1af9a1 |
@@ -686,10 +688,15 @@
|
|
|
1af9a1 |
|
|
|
1af9a1 |
if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
|
|
|
1af9a1 |
(hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
|
|
|
1af9a1 |
- // just read the content-length header, so set it
|
|
|
1af9a1 |
long cl = vMB.getLong();
|
|
|
1af9a1 |
- if(cl < Integer.MAX_VALUE)
|
|
|
1af9a1 |
- request.setContentLength( (int)cl );
|
|
|
1af9a1 |
+ if (contentLengthSet) {
|
|
|
1af9a1 |
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
|
|
1af9a1 |
+ error = true;
|
|
|
1af9a1 |
+ } else {
|
|
|
1af9a1 |
+ contentLengthSet = true;
|
|
|
1af9a1 |
+ // Set the content-length header for the request
|
|
|
1af9a1 |
+ request.setContentLength((int)cl);
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
} else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
|
|
|
1af9a1 |
(hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
|
|
|
1af9a1 |
// just read the content-type header, so set it
|
|
|
1af9a1 |
--- java/org/apache/coyote/http11/AbstractHttp11Processor.java.orig 2014-03-14 17:13:46.514347000 -0400
|
|
|
1af9a1 |
+++ java/org/apache/coyote/http11/AbstractHttp11Processor.java 2014-03-14 17:13:46.353345000 -0400
|
|
|
1af9a1 |
@@ -1277,10 +1277,20 @@
|
|
|
1af9a1 |
|
|
|
1af9a1 |
// Parse content-length header
|
|
|
1af9a1 |
long contentLength = request.getContentLengthLong();
|
|
|
1af9a1 |
- if (contentLength >= 0 && !contentDelimitation) {
|
|
|
1af9a1 |
- getInputBuffer().addActiveFilter
|
|
|
1af9a1 |
- (inputFilters[Constants.IDENTITY_FILTER]);
|
|
|
1af9a1 |
- contentDelimitation = true;
|
|
|
1af9a1 |
+ if (contentLength >= 0) {
|
|
|
1af9a1 |
+ if (contentDelimitation) {
|
|
|
1af9a1 |
+ // contentDelimitation being true at this point indicates that
|
|
|
1af9a1 |
+ // chunked encoding is being used but chunked encoding should
|
|
|
1af9a1 |
+ // not be used with a content length. RFC 2616, section 4.4,
|
|
|
1af9a1 |
+ // bullet 3 states Content-Length must be ignored in this case -
|
|
|
1af9a1 |
+ // so remove it.
|
|
|
1af9a1 |
+ headers.removeHeader("content-length");
|
|
|
1af9a1 |
+ request.setContentLength(-1);
|
|
|
1af9a1 |
+ } else {
|
|
|
1af9a1 |
+ getInputBuffer().addActiveFilter
|
|
|
1af9a1 |
+ (inputFilters[Constants.IDENTITY_FILTER]);
|
|
|
1af9a1 |
+ contentDelimitation = true;
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
}
|
|
|
1af9a1 |
|
|
|
1af9a1 |
MessageBytes valueMB = headers.getValue("host");
|
|
|
1af9a1 |
--- test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java.orig 2014-03-14 17:13:52.878367000 -0400
|
|
|
1af9a1 |
+++ test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java 2014-03-14 17:21:43.278956000 -0400
|
|
|
1af9a1 |
@@ -90,6 +90,61 @@
|
|
|
1af9a1 |
ajpClient.disconnect();
|
|
|
1af9a1 |
}
|
|
|
1af9a1 |
|
|
|
1af9a1 |
+ @Test
|
|
|
1af9a1 |
+ public void testPost() throws Exception {
|
|
|
1af9a1 |
+ doTestPost(false, HttpServletResponse.SC_OK);
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ public void testPostMultipleContentLength() throws Exception {
|
|
|
1af9a1 |
+ // Multiple content lengths
|
|
|
1af9a1 |
+ doTestPost(true, HttpServletResponse.SC_BAD_REQUEST);
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ public void doTestPost(boolean multipleCL, int expectedStatus)
|
|
|
1af9a1 |
+ throws Exception {
|
|
|
1af9a1 |
+ Tomcat tomcat = getTomcatInstance();
|
|
|
1af9a1 |
+ // Use the normal Tomcat ROOT context
|
|
|
1af9a1 |
+ File root = new File("test/webapp-3.0");
|
|
|
1af9a1 |
+ tomcat.addWebapp("", root.getAbsolutePath());
|
|
|
1af9a1 |
+ tomcat.start();
|
|
|
1af9a1 |
+ SimpleAjpClient ajpClient = new SimpleAjpClient();
|
|
|
1af9a1 |
+ ajpClient.setPort(getPort());
|
|
|
1af9a1 |
+ ajpClient.connect();
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ validateCpong(ajpClient.cping());
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ TesterAjpMessage forwardMessage =
|
|
|
1af9a1 |
+ ajpClient.createForwardMessage("/echo-params.jsp", 4);
|
|
|
1af9a1 |
+ forwardMessage.addHeader(0xA008, "9");
|
|
|
1af9a1 |
+ if (multipleCL) {
|
|
|
1af9a1 |
+ forwardMessage.addHeader(0xA008, "99");
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+ forwardMessage.addHeader(0xA007, "application/x-www-form-urlencoded");
|
|
|
1af9a1 |
+ forwardMessage.end();
|
|
|
1af9a1 |
+ TesterAjpMessage bodyMessage =
|
|
|
1af9a1 |
+ ajpClient.createBodyMessage("test=data".getBytes());
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ TesterAjpMessage responseHeaders =
|
|
|
1af9a1 |
+ ajpClient.sendMessage(forwardMessage, bodyMessage);
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ validateResponseHeaders(responseHeaders, expectedStatus);
|
|
|
1af9a1 |
+ if (expectedStatus == HttpServletResponse.SC_OK) {
|
|
|
1af9a1 |
+ // Expect 3 messages: headers, body, end for a valid request
|
|
|
1af9a1 |
+ TesterAjpMessage responseBody = ajpClient.readMessage();
|
|
|
1af9a1 |
+ validateResponseBody(responseBody, "test - data");
|
|
|
1af9a1 |
+ validateResponseEnd(ajpClient.readMessage(), true);
|
|
|
1af9a1 |
+ // Double check the connection is still open
|
|
|
1af9a1 |
+ validateCpong(ajpClient.cping());
|
|
|
1af9a1 |
+ } else {
|
|
|
1af9a1 |
+ // Expect 2 messages: headers, end for an invalid request
|
|
|
1af9a1 |
+ validateResponseEnd(ajpClient.readMessage(), false);
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ ajpClient.disconnect();
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
/**
|
|
|
1af9a1 |
* Process response header packet and checks the status. Any other data is
|
|
|
1af9a1 |
* ignored.
|
|
|
1af9a1 |
--- test/org/apache/coyote/http11/TestAbstractHttp11Processor.java.orig 2014-03-14 17:13:52.946367000 -0400
|
|
|
1af9a1 |
+++ test/org/apache/coyote/http11/TestAbstractHttp11Processor.java 2014-03-14 17:13:52.925368000 -0400
|
|
|
1af9a1 |
@@ -87,7 +87,7 @@
|
|
|
1af9a1 |
"Transfer-encoding: buffered" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
"Content-Length: 9" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
"Content-Type: application/x-www-form-urlencoded" +
|
|
|
1af9a1 |
- SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
"test=data";
|
|
|
1af9a1 |
|
|
|
1af9a1 |
@@ -99,6 +99,54 @@
|
|
|
1af9a1 |
assertTrue(client.isResponse501());
|
|
|
1af9a1 |
}
|
|
|
1af9a1 |
|
|
|
1af9a1 |
+ @Test
|
|
|
1af9a1 |
+ public void testWithTEChunked() throws Exception {
|
|
|
1af9a1 |
+ doTestWithTEChunked(false);
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ @Test
|
|
|
1af9a1 |
+ public void testWithTEChunkedWithCL() throws Exception {
|
|
|
1af9a1 |
+ // Should be ignored
|
|
|
1af9a1 |
+ doTestWithTEChunked(true);
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ private void doTestWithTEChunked(boolean withCL)
|
|
|
1af9a1 |
+ throws Exception {
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ Tomcat tomcat = getTomcatInstance();
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ // Use the normal Tomcat ROOT context
|
|
|
1af9a1 |
+ File root = new File("test/webapp-3.0");
|
|
|
1af9a1 |
+ tomcat.addWebapp("", root.getAbsolutePath());
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ tomcat.start();
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ String request =
|
|
|
1af9a1 |
+ "POST /echo-params.jsp HTTP/1.1" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ "Host: any" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ (withCL ? "Content-length: 1" + SimpleHttpClient.CRLF : "") +
|
|
|
1af9a1 |
+ "Transfer-encoding: chunked" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ "Content-Type: application/x-www-form-urlencoded" +
|
|
|
1af9a1 |
+ SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ "Connection: close" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ "9" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ "test=data" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ "0" + SimpleHttpClient.CRLF +
|
|
|
1af9a1 |
+ SimpleHttpClient.CRLF;
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ Client client = new Client(tomcat.getConnector().getLocalPort());
|
|
|
1af9a1 |
+ client.setRequest(new String[] {request});
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+ client.connect();
|
|
|
1af9a1 |
+ client.processRequest();
|
|
|
1af9a1 |
+ assertTrue(client.isResponse200());
|
|
|
1af9a1 |
+ assertTrue(client.getResponseBody().contains("test - data"));
|
|
|
1af9a1 |
+ }
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
+
|
|
|
1af9a1 |
|
|
|
1af9a1 |
@Test
|
|
|
1af9a1 |
public void testWithTEIdentity() throws Exception {
|