You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by as...@apache.org on 2010/10/14 21:01:48 UTC

svn commit: r1022657 - in /httpcomponents/httpcore/trunk: RELEASE_NOTES.txt httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkEncoder.java httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkEncoder.java

Author: asankha
Date: Thu Oct 14 19:01:45 2010
New Revision: 1022657

URL: http://svn.apache.org/viewvc?rev=1022657&view=rev
Log:
fix HTTPCORE-239 - The ChunkEncoder could request for a negative buffer limit causing an IllegalArgumentException


Modified:
    httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkEncoder.java
    httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkEncoder.java

Modified: httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt?rev=1022657&r1=1022656&r2=1022657&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpcore/trunk/RELEASE_NOTES.txt Thu Oct 14 19:01:45 2010
@@ -1,5 +1,9 @@
 Changes since 4.1-BETA2
 
+* [HTTPCORE-239]: The ChunkEncoder could request for a negative buffer limit causing an 
+  IllegalArgumentException.
+  Contributed by Asankha Perera <asankha at apache.org>
+
 * [HTTPCORE-236]: SSLIOSession#isAppInputReady() does not check the status of the session input
   buffer.
   Contributed by Dmitry Lukyanov <dlukyanov at ukr.net>

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkEncoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkEncoder.java?rev=1022657&r1=1022656&r2=1022657&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkEncoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkEncoder.java Thu Oct 14 19:01:45 2010
@@ -81,15 +81,14 @@ public class ChunkEncoder extends Abstra
         } else {
             avail = 4096;
         }
-        if (avail == 0) {
-            return 0;
-        }
 
         // subtract the length of the longest chunk header
         // 12345678\r\n
-        avail -= 10;
-
-        if (avail < chunk) {
+        // <chunk-data>\r\n
+        avail -= 12;
+        if (avail <= 0) {
+            return 0;
+        } else if (avail < chunk) {
             // write no more than 'avail' bytes
             chunk = avail;
             this.lineBuffer.clear();

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkEncoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkEncoder.java?rev=1022657&r1=1022656&r2=1022657&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkEncoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkEncoder.java Thu Oct 14 19:01:45 2010
@@ -28,6 +28,8 @@
 package org.apache.http.impl.nio.codecs;
 
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.nio.channels.Channels;
 import java.nio.channels.WritableByteChannel;
@@ -103,6 +105,42 @@ public class TestChunkEncoder extends Te
         assertEquals("4\r\n1234\r\n0\r\n\r\n", s);
     }
 
+    public void testHttpCore239() throws Exception {
+        FixedByteChannel channel = new FixedByteChannel(16);
+        HttpParams params = new BasicHttpParams();
+        SessionOutputBuffer outbuf = new SessionOutputBufferImpl(16, 16, params);
+        HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
+        ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics);
+
+        // fill up the channel
+        channel.write(wrap("0123456789ABCDEF"));
+        // fill up the out buffer
+        outbuf.write(wrap("0123456789ABCDEF"));
+
+        ByteBuffer src = wrap("0123456789ABCDEF");
+        assertEquals(0, encoder.write(src));
+        assertEquals(0, encoder.write(src));
+        assertEquals(0, encoder.write(src));
+
+        // should not be able to copy any bytes, until we flush the channel and buffer
+        channel.reset();
+        outbuf.flush(channel);
+        channel.reset();
+
+        assertEquals(4, encoder.write(src));
+        channel.flush();
+        assertEquals(4, encoder.write(src));
+        channel.flush();
+        assertEquals(4, encoder.write(src));
+        channel.flush();
+        assertEquals(4, encoder.write(src));
+        channel.flush();
+        assertEquals(0, encoder.write(src));
+        
+        outbuf.flush(channel);
+        String s = channel.toString("US-ASCII");
+        assertEquals("4\r\n0123\r\n4\r\n4567\r\n4\r\n89AB\r\n4\r\nCDEF\r\n", s);
+    }
 
     public void testChunkExceed() throws Exception {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -114,20 +152,21 @@ public class TestChunkEncoder extends Te
 
         ByteBuffer src = wrap("0123456789ABCDEF");
 
-        assertEquals(6, encoder.write(src));
+        assertEquals(4, encoder.write(src));
         assertTrue(src.hasRemaining());
-        assertEquals(10, src.remaining());
+        assertEquals(12, src.remaining());
 
-        assertEquals(6, encoder.write(src));
+        assertEquals(4, encoder.write(src));
         assertTrue(src.hasRemaining());
-        assertEquals(4, src.remaining());
+        assertEquals(8, src.remaining());
 
         assertEquals(4, encoder.write(src));
+        assertEquals(4, encoder.write(src));
         assertFalse(src.hasRemaining());
 
         outbuf.flush(channel);
         String s = baos.toString("US-ASCII");
-        assertEquals("6\r\n012345\r\n6\r\n6789AB\r\n4\r\nCDEF\r\n", s);
+        assertEquals("4\r\n0123\r\n4\r\n4567\r\n4\r\n89AB\r\n4\r\nCDEF\r\n", s);
 
     }
 
@@ -211,4 +250,50 @@ public class TestChunkEncoder extends Te
         }
     }
 
+    public class FixedByteChannel implements WritableByteChannel {
+
+        // collect bytes written for unit test result evaluation
+        private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        private final ByteBuffer buffer;
+
+        public FixedByteChannel(int size) {
+            this.buffer = ByteBuffer.allocate(size);
+        }
+
+        public int write(ByteBuffer src) throws IOException {
+            // copy bytes into baos for result evaluation
+            final int start = src.position();
+            int count = 0;
+            for (int i=start; i<src.limit() && buffer.remaining() > 0; i++) {
+                final byte b = src.get(i);
+                baos.write(b);
+                buffer.put(b);
+                count++;
+            }
+            // update processed position on src buffer
+            src.position(src.position() + count);
+            return count;
+        }
+
+        public boolean isOpen() {
+            return false;
+        }
+
+        public void close() throws IOException {
+        }
+
+        public void flush() {
+            buffer.clear();
+        }
+
+        public void reset() {
+            baos.reset();
+            buffer.clear();
+        }
+
+        public String toString(String encoding) throws UnsupportedEncodingException {
+            return baos.toString(encoding);
+        }
+    }
+
 }