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/08/28 15:22:14 UTC
svn commit: r1518199 - in /tomcat/tc7.0.x/trunk: ./
java/org/apache/coyote/ajp/AbstractAjpProcessor.java
test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java
webapps/docs/changelog.xml
Author: markt
Date: Wed Aug 28 13:22:13 2013
New Revision: 1518199
URL: http://svn.apache.org/r1518199
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=55453
Do not return a response body for those status codes and request methods that do not permit one.
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/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java
tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1518189
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=1518199&r1=1518198&r2=1518199&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 Aug 28 13:22:13 2013
@@ -215,6 +215,12 @@ public abstract class AbstractAjpProcess
/**
+ * Should any response body be swallowed and not sent to the client.
+ */
+ private boolean swallowResponse = false;
+
+
+ /**
* Finished response.
*/
protected boolean finished = false;
@@ -582,6 +588,7 @@ public abstract class AbstractAjpProcess
request.recycle();
response.recycle();
certificates.recycle();
+ swallowResponse = false;
bytesWritten = 0;
}
@@ -959,8 +966,25 @@ public abstract class AbstractAjpProcess
responseMessage.reset();
responseMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
+ // Responses with certain status codes are not permitted to include a
+ // response body.
+ int statusCode = response.getStatus();
+ if (statusCode < 200 || statusCode == 204 || statusCode == 205 ||
+ statusCode == 304) {
+ // No entity body
+ swallowResponse = true;
+ }
+
+ // Responses to HEAD requests are not permitted to incude a response
+ // body.
+ MessageBytes methodMB = request.method();
+ if (methodMB.equals("HEAD")) {
+ // No entity body
+ swallowResponse = true;
+ }
+
// HTTP header contents
- responseMessage.appendInt(response.getStatus());
+ responseMessage.appendInt(statusCode);
String message = null;
if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER &&
HttpMessages.isSafeInHttpHeader(response.getMessage())) {
@@ -1125,27 +1149,29 @@ public abstract class AbstractAjpProcess
}
}
- int len = chunk.getLength();
- // 4 - hardcoded, byte[] marshaling overhead
- // Adjust allowed size if packetSize != default (Constants.MAX_PACKET_SIZE)
- int chunkSize = Constants.MAX_SEND_SIZE + packetSize - Constants.MAX_PACKET_SIZE;
- int off = 0;
- while (len > 0) {
- int thisTime = len;
- if (thisTime > chunkSize) {
- thisTime = chunkSize;
- }
- len -= thisTime;
- responseMessage.reset();
- responseMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
- responseMessage.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime);
- responseMessage.end();
- output(responseMessage.getBuffer(), 0, responseMessage.getLen());
+ if (!swallowResponse) {
+ int len = chunk.getLength();
+ // 4 - hardcoded, byte[] marshaling overhead
+ // Adjust allowed size if packetSize != default (Constants.MAX_PACKET_SIZE)
+ int chunkSize = Constants.MAX_SEND_SIZE + packetSize - Constants.MAX_PACKET_SIZE;
+ int off = 0;
+ while (len > 0) {
+ int thisTime = len;
+ if (thisTime > chunkSize) {
+ thisTime = chunkSize;
+ }
+ len -= thisTime;
+ responseMessage.reset();
+ responseMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
+ responseMessage.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime);
+ responseMessage.end();
+ output(responseMessage.getBuffer(), 0, responseMessage.getLen());
+
+ off += thisTime;
+ }
- off += thisTime;
+ bytesWritten += chunk.getLength();
}
-
- bytesWritten += chunk.getLength();
return chunk.getLength();
}
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=1518199&r1=1518198&r2=1518199&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 Aug 28 13:22:13 2013
@@ -17,6 +17,12 @@
package org.apache.coyote.ajp;
import java.io.File;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import org.junit.Assert;
import org.junit.Test;
@@ -93,7 +99,6 @@ public class TestAbstractAjpProcessor ex
}
-
@Test
public void testSimplePost() throws Exception {
@@ -137,6 +142,44 @@ public class TestAbstractAjpProcessor ex
}
+ /*
+ * Bug 55453
+ */
+ @Test
+ public void test304WithBody() throws Exception {
+
+ Tomcat tomcat = getTomcatInstance();
+
+ // Must have a real docBase - just use temp
+ Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+ Tomcat.addServlet(ctx, "bug55453", new Tester304WithBodyServlet());
+ ctx.addServletMapping("/", "bug55453");
+
+ tomcat.start();
+
+ SimpleAjpClient ajpClient = new SimpleAjpClient();
+ ajpClient.setPort(getPort());
+ ajpClient.connect();
+
+ validateCpong(ajpClient.cping());
+
+ TesterAjpMessage forwardMessage = ajpClient.createForwardMessage("/");
+ forwardMessage.end();
+
+ TesterAjpMessage responseHeaders =
+ ajpClient.sendMessage(forwardMessage, null);
+
+ // Expect 2 messages: headers, end
+ validateResponseHeaders(responseHeaders, 304);
+ validateResponseEnd(ajpClient.readMessage(), true);
+
+ // Double check the connection is still open
+ validateCpong(ajpClient.cping());
+
+ ajpClient.disconnect();
+ }
+
+
/**
* Process response header packet and checks the status. Any other data is
* ignored.
@@ -227,4 +270,18 @@ public class TestAbstractAjpProcessor ex
// Data should be the value 9
Assert.assertEquals(9, message.buf[4]);
}
+
+
+ private static class Tester304WithBodyServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ resp.setStatus(304);
+ resp.getWriter().print("Body not permitted for 304 response");
+ }
+ }
}
Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1518199&r1=1518198&r2=1518199&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Wed Aug 28 13:22:13 2013
@@ -181,6 +181,11 @@
places in the AJP connector where this was restricted to an
<code>int</code>. (markt)
</fix>
+ <fix>
+ <bug>55453</bug>: Ensure that the AJP connector does not permit response
+ bodies to be included for responses with status codes and/or request
+ methods that are not permitted to have a response body. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org