Author: markt Date: Sun Mar 8 17:41:41 2015 New Revision: 1665061 URL: http://svn.apache.org/r1665061 Log: Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=57674 Avoid a BufferOverflowException when an AJP response body chunk larger than the socket write buffer is being written. This typically requires a larger than default AJP packetSize.
Modified: tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNio2Processor.java tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java tomcat/tc8.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml Modified: tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNio2Processor.java URL: http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNio2Processor.java?rev=1665061&r1=1665060&r2=1665061&view=diff ============================================================================== --- tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNio2Processor.java (original) +++ tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNio2Processor.java Sun Mar 8 17:41:41 2015 @@ -142,11 +142,12 @@ public class AjpNio2Processor extends Ab ByteBuffer writeBuffer = socketWrapper.getSocket().getBufHandler().getWriteBuffer(); + int toWrite = Math.min(length, writeBuffer.remaining()); int result = 0; if (block) { writeBuffer.clear(); - writeBuffer.put(src, offset, length); + writeBuffer.put(src, offset, toWrite); writeBuffer.flip(); try { result = socketWrapper.getSocket().write(writeBuffer) @@ -159,14 +160,14 @@ public class AjpNio2Processor extends Ab synchronized (writeCompletionHandler) { if (!writePending) { writeBuffer.clear(); - writeBuffer.put(src, offset, length); + writeBuffer.put(src, offset, toWrite); writeBuffer.flip(); writePending = true; Nio2Endpoint.startInline(); socketWrapper.getSocket().write(writeBuffer, socketWrapper.getTimeout(), TimeUnit.MILLISECONDS, socketWrapper, writeCompletionHandler); Nio2Endpoint.endInline(); - result = length; + result = toWrite; } } } Modified: tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java?rev=1665061&r1=1665060&r2=1665061&view=diff ============================================================================== --- tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java (original) +++ tomcat/tc8.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java Sun Mar 8 17:41:41 2015 @@ -124,7 +124,8 @@ public class AjpNioProcessor extends Abs ByteBuffer writeBuffer = socketWrapper.getSocket().getBufHandler().getWriteBuffer(); - writeBuffer.put(src, offset, length); + int toWrite = Math.min(length, writeBuffer.remaining()); + writeBuffer.put(src, offset, toWrite); writeBuffer.flip(); Modified: tomcat/tc8.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java?rev=1665061&r1=1665060&r2=1665061&view=diff ============================================================================== --- tomcat/tc8.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java (original) +++ tomcat/tc8.0.x/trunk/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java Sun Mar 8 17:41:41 2015 @@ -765,6 +765,48 @@ public class TestAbstractAjpProcessor ex } + @Test + public void testLargeResponse() throws Exception { + + int ajpPacketSize = 16000; + + Tomcat tomcat = getTomcatInstance(); + tomcat.getConnector().setProperty("packetSize", Integer.toString(ajpPacketSize)); + + // No file system docBase required + Context ctx = tomcat.addContext("", null); + + FixedResponseSizeServlet servlet = new FixedResponseSizeServlet(15000, 16000); + Tomcat.addServlet(ctx, "FixedResponseSizeServlet", servlet); + ctx.addServletMapping("/", "FixedResponseSizeServlet"); + + tomcat.start(); + + SimpleAjpClient ajpClient = new SimpleAjpClient(ajpPacketSize); + ajpClient.setPort(getPort()); + ajpClient.connect(); + + validateCpong(ajpClient.cping()); + + ajpClient.setUri("/"); + TesterAjpMessage forwardMessage = ajpClient.createForwardMessage(); + forwardMessage.end(); + + TesterAjpMessage responseHeaders = ajpClient.sendMessage(forwardMessage); + + // Expect 3 messages: headers, body, end for a valid request + validateResponseHeaders(responseHeaders, 200, "OK"); + TesterAjpMessage responseBody = ajpClient.readMessage(); + Assert.assertTrue(responseBody.len > 15000); + 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. @@ -945,4 +987,33 @@ public class TestAbstractAjpProcessor ex } } } + + + private static class FixedResponseSizeServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private final int responseSize; + private final int bufferSize; + + public FixedResponseSizeServlet(int responseSize, int bufferSize) { + this.responseSize = responseSize; + this.bufferSize = bufferSize; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setBufferSize(bufferSize); + + resp.setContentType("text/plain"); + resp.setCharacterEncoding("UTF-8"); + resp.setContentLength(responseSize); + + PrintWriter pw = resp.getWriter(); + for (int i = 0; i < responseSize; i++) { + pw.append('X'); + } + } + } } Modified: tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml?rev=1665061&r1=1665060&r2=1665061&view=diff ============================================================================== --- tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml Sun Mar 8 17:41:41 2015 @@ -139,6 +139,11 @@ body chunk larger than the socket read buffer is being read. This typically requires a larger than default AJP packetSize. (markt) </fix> + <fix> + <bug>57674</bug>: Avoid a BufferOverflowException when an AJP response + body chunk larger than the socket write buffer is being written. This + typically requires a larger than default AJP packetSize. (markt) + </fix> </changelog> </subsection> <subsection name="Jasper"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org