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