Author: markt Date: Wed Aug 28 13:01:03 2013 New Revision: 1518189 URL: http://svn.apache.org/r1518189 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/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java tomcat/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java Modified: tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java?rev=1518189&r1=1518188&r2=1518189&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java (original) +++ tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java Wed Aug 28 13:01:03 2013 @@ -216,6 +216,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; @@ -563,6 +569,7 @@ public abstract class AbstractAjpProcess request.recycle(); response.recycle(); certificates.recycle(); + swallowResponse = false; bytesWritten = 0; } @@ -937,8 +944,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())) { @@ -1103,27 +1127,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/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java?rev=1518189&r1=1518188&r2=1518189&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java (original) +++ tomcat/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java Wed Aug 28 13:01:03 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"); + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org