You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2016/04/06 09:20:23 UTC

svn commit: r1737928 - in /httpcomponents/httpcore/branches/4.4.x: httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/ httpcore/src/main/java/org/apache/http/impl/io/ httpcore/src/test...

Author: olegk
Date: Wed Apr  6 07:20:23 2016
New Revision: 1737928

URL: http://svn.apache.org/viewvc?rev=1737928&view=rev
Log:
Support 64-bit chunk headers

Modified:
    httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java
    httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java
    httpcomponents/httpcore/branches/4.4.x/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java
    httpcomponents/httpcore/branches/4.4.x/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java

Modified: httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java?rev=1737928&r1=1737927&r2=1737928&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java (original)
+++ httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java Wed Apr  6 07:20:23 2016
@@ -65,8 +65,8 @@ public class ChunkDecoder extends Abstra
     private boolean endOfStream;
 
     private CharArrayBuffer lineBuf;
-    private int chunkSize;
-    private int pos;
+    private long chunkSize;
+    private long pos;
 
     private final MessageConstraints constraints;
     private final List<CharArrayBuffer> trailerBufs;
@@ -83,8 +83,8 @@ public class ChunkDecoder extends Abstra
             final HttpTransportMetricsImpl metrics) {
         super(channel, buffer, metrics);
         this.state = READ_CONTENT;
-        this.chunkSize = -1;
-        this.pos = 0;
+        this.chunkSize = -1L;
+        this.pos = 0L;
         this.endOfChunk = false;
         this.endOfStream = false;
         this.constraints = constraints != null ? constraints : MessageConstraints.DEFAULT;
@@ -129,13 +129,13 @@ public class ChunkDecoder extends Abstra
             if (separator < 0) {
                 separator = this.lineBuf.length();
             }
+            final String s = this.lineBuf.substringTrimmed(0, separator);
             try {
-                final String s = this.lineBuf.substringTrimmed(0, separator);
-                this.chunkSize = Integer.parseInt(s, 16);
+                this.chunkSize = Long.parseLong(s, 16);
             } catch (final NumberFormatException e) {
-                throw new MalformedChunkCodingException("Bad chunk header");
+                throw new MalformedChunkCodingException("Bad chunk header: " + s);
             }
-            this.pos = 0;
+            this.pos = 0L;
         } else if (this.endOfStream) {
             throw new ConnectionClosedException("Premature end of chunk coded message body: " +
                     "closing chunk expected");
@@ -193,7 +193,7 @@ public class ChunkDecoder extends Abstra
         int totalRead = 0;
         while (this.state != COMPLETED) {
 
-            if (!this.buffer.hasData() || this.chunkSize == -1) {
+            if (!this.buffer.hasData() || this.chunkSize == -1L) {
                 final int bytesRead = fillBufferFromChannel();
                 if (bytesRead == -1) {
                     this.endOfStream = true;
@@ -203,21 +203,21 @@ public class ChunkDecoder extends Abstra
             switch (this.state) {
             case READ_CONTENT:
 
-                if (this.chunkSize == -1) {
+                if (this.chunkSize == -1L) {
                     readChunkHead();
-                    if (this.chunkSize == -1) {
+                    if (this.chunkSize == -1L) {
                         // Unable to read a chunk head
                         return totalRead;
                     }
-                    if (this.chunkSize == 0) {
+                    if (this.chunkSize == 0L) {
                         // Last chunk. Read footers
-                        this.chunkSize = -1;
+                        this.chunkSize = -1L;
                         this.state = READ_FOOTERS;
                         break;
                     }
                 }
-                final int maxLen = this.chunkSize - this.pos;
-                final int len = this.buffer.read(dst, maxLen);
+                final long maxLen = this.chunkSize - this.pos;
+                final int len = this.buffer.read(dst, (int) Math.min(maxLen, Integer.MAX_VALUE));
                 if (len > 0) {
                     this.pos += len;
                     totalRead += len;
@@ -233,8 +233,8 @@ public class ChunkDecoder extends Abstra
 
                 if (this.pos == this.chunkSize) {
                     // At the end of the chunk
-                    this.chunkSize = -1;
-                    this.pos = 0;
+                    this.chunkSize = -1L;
+                    this.pos = 0L;
                     this.endOfChunk = true;
                     break;
                 }

Modified: httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java?rev=1737928&r1=1737927&r2=1737928&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java (original)
+++ httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java Wed Apr  6 07:20:23 2016
@@ -586,4 +586,24 @@ public class TestChunkDecoder {
         decoder.read(null);
     }
 
+    @Test
+    public void testHugeChunk() throws Exception {
+        final String s = "1234567890abcdef\r\n0123456789abcdef";
+        final ReadableByteChannel channel = new ReadableByteChannelMock(
+                new String[] {s}, Consts.ASCII);
+        final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
+        final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
+        final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
+
+        final ByteBuffer dst = ByteBuffer.allocate(4);
+
+        int bytesRead = decoder.read(dst);
+        Assert.assertEquals(4, bytesRead);
+        Assert.assertEquals("0123", CodecTestUtils.convert(dst));
+        dst.clear();
+        bytesRead = decoder.read(dst);
+        Assert.assertEquals(4, bytesRead);
+        Assert.assertEquals("4567", CodecTestUtils.convert(dst));
+    }
+
 }

Modified: httpcomponents/httpcore/branches/4.4.x/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java?rev=1737928&r1=1737927&r2=1737928&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java (original)
+++ httpcomponents/httpcore/branches/4.4.x/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java Wed Apr  6 07:20:23 2016
@@ -76,10 +76,10 @@ public class ChunkedInputStream extends
     private int state;
 
     /** The chunk size */
-    private int chunkSize;
+    private long chunkSize;
 
     /** The current position within the current chunk */
-    private int pos;
+    private long pos;
 
     /** True if we've reached the end of stream */
     private boolean eof = false;
@@ -101,7 +101,7 @@ public class ChunkedInputStream extends
     public ChunkedInputStream(final SessionInputBuffer in, final MessageConstraints constraints) {
         super();
         this.in = Args.notNull(in, "Session input buffer");
-        this.pos = 0;
+        this.pos = 0L;
         this.buffer = new CharArrayBuffer(16);
         this.constraints = constraints != null ? constraints : MessageConstraints.DEFAULT;
         this.state = CHUNK_LEN;
@@ -120,7 +120,7 @@ public class ChunkedInputStream extends
     public int available() throws IOException {
         if (this.in instanceof BufferInfo) {
             final int len = ((BufferInfo) this.in).length();
-            return Math.min(len, this.chunkSize - this.pos);
+            return (int) Math.min(len, this.chunkSize - this.pos);
         } else {
             return 0;
         }
@@ -188,7 +188,7 @@ public class ChunkedInputStream extends
                 return -1;
             }
         }
-        final int bytesRead = in.read(b, off, Math.min(len, chunkSize - pos));
+        final int bytesRead = in.read(b, off, (int) Math.min(len, chunkSize - pos));
         if (bytesRead != -1) {
             pos += bytesRead;
             if (pos >= chunkSize) {
@@ -225,12 +225,12 @@ public class ChunkedInputStream extends
         }
         try {
             chunkSize = getChunkSize();
-            if (chunkSize < 0) {
+            if (chunkSize < 0L) {
                 throw new MalformedChunkCodingException("Negative chunk size");
             }
             state = CHUNK_DATA;
-            pos = 0;
-            if (chunkSize == 0) {
+            pos = 0L;
+            if (chunkSize == 0L) {
                 eof = true;
                 parseTrailerHeaders();
             }
@@ -245,7 +245,7 @@ public class ChunkedInputStream extends
      * comments after a semicolon. The line must end with a CRLF: "a3; some
      * comment\r\n" Positions the stream at the start of the next line.
      */
-    private int getChunkSize() throws IOException {
+    private long getChunkSize() throws IOException {
         final int st = this.state;
         switch (st) {
         case CHUNK_CRLF:
@@ -272,10 +272,11 @@ public class ChunkedInputStream extends
             if (separator < 0) {
                 separator = this.buffer.length();
             }
+            final String s = this.buffer.substringTrimmed(0, separator);
             try {
-                return Integer.parseInt(this.buffer.substringTrimmed(0, separator), 16);
+                return Long.parseLong(s, 16);
             } catch (final NumberFormatException e) {
-                throw new MalformedChunkCodingException("Bad chunk header");
+                throw new MalformedChunkCodingException("Bad chunk header: " + s);
             }
         default:
             throw new IllegalStateException("Inconsistent codec state");

Modified: httpcomponents/httpcore/branches/4.4.x/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java?rev=1737928&r1=1737927&r2=1737928&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java (original)
+++ httpcomponents/httpcore/branches/4.4.x/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java Wed Apr  6 07:20:23 2016
@@ -506,5 +506,19 @@ public class TestChunkCoding {
         in.close();
 }
 
+    // Test for when buffer is larger than chunk size
+    @Test
+    public void testHugeChunk() throws IOException {
+        final ChunkedInputStream in = new ChunkedInputStream(
+                new SessionInputBufferMock("1234567890abcdef\r\n01234567", Consts.ISO_8859_1));
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        for (int i = 0; i < 8; ++i) {
+            out.write(in.read());
+        }
+
+        final String result = new String(out.toByteArray(), Consts.ISO_8859_1);
+        Assert.assertEquals("01234567", result);
+    }
+
 }