Return-Path: X-Original-To: apmail-tomcat-dev-archive@www.apache.org Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5EE15102C4 for ; Sun, 8 Mar 2015 17:41:43 +0000 (UTC) Received: (qmail 27903 invoked by uid 500); 8 Mar 2015 17:41:42 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 27827 invoked by uid 500); 8 Mar 2015 17:41:42 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 27817 invoked by uid 99); 8 Mar 2015 17:41:42 -0000 Received: from eris.apache.org (HELO hades.apache.org) (140.211.11.105) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 08 Mar 2015 17:41:42 +0000 Received: from hades.apache.org (localhost [127.0.0.1]) by hades.apache.org (ASF Mail Server at hades.apache.org) with ESMTP id 5BB7BAC006E for ; Sun, 8 Mar 2015 17:41:42 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1665061 - in /tomcat/tc8.0.x/trunk: java/org/apache/coyote/ajp/AjpNio2Processor.java java/org/apache/coyote/ajp/AjpNioProcessor.java test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java webapps/docs/changelog.xml Date: Sun, 08 Mar 2015 17:41:42 -0000 To: dev@tomcat.apache.org From: markt@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20150308174142.5BB7BAC006E@hades.apache.org> 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) + + 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. (markt) + --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org