hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1565641 - in /httpcomponents/httpcore/trunk: ./ 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/java/...
Date Fri, 07 Feb 2014 13:28:03 GMT
Author: olegk
Date: Fri Feb  7 13:28:02 2014
New Revision: 1565641

URL: http://svn.apache.org/r1565641
Log:
HTTPCORE-372: Chunk decoders to throw an I/O exception if data stream is terminated without
a closing chunk
Contributed by Dmitry Potapov <potapov.d at gmail.com>

Modified:
    httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java
    httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java
    httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java
    httpcomponents/httpcore/trunk/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java

Modified: httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt?rev=1565641&r1=1565640&r2=1565641&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpcore/trunk/RELEASE_NOTES.txt Fri Feb  7 13:28:02 2014
@@ -1,6 +1,10 @@
-Changes since release 4.3.1
+Changes for release 4.4-alpha1
 -------------------
 
+* [HTTPCORE-372] Blocking and non-blocking chunk decoders to throw an I/O exception if data
stream
+  is terminated without a closing chunk.
+  Contributed by Dmitry Potapov <potapov.d at gmail.com>
+
 * [HTTPCORE-368] Customizable buffer management strategies for SSLIOSession.
   Contributed by offbynull <offbynull at gmail.com>
 

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java?rev=1565641&r1=1565640&r2=1565641&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java
(original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/ChunkDecoder.java
Fri Feb  7 13:28:02 2014
@@ -33,6 +33,7 @@ import java.nio.channels.ReadableByteCha
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.Header;
 import org.apache.http.MalformedChunkCodingException;
 import org.apache.http.ParseException;
@@ -94,7 +95,7 @@ public class ChunkDecoder extends Abstra
                     throw new MalformedChunkCodingException("CRLF expected at end of chunk");
                 }
             } else {
-                if (this.buffer.length() > 2) {
+                if (this.buffer.length() > 2 || this.endOfStream) {
                     throw new MalformedChunkCodingException("CRLF expected at end of chunk");
                 }
                 return;
@@ -113,6 +114,9 @@ public class ChunkDecoder extends Abstra
                 throw new MalformedChunkCodingException("Bad chunk header");
             }
             this.pos = 0;
+        } else if (this.endOfStream) {
+            throw new ConnectionClosedException("Premature end of chunk coded message body:
" +
+                    "closing chunk expected");
         }
     }
 
@@ -177,10 +181,6 @@ public class ChunkDecoder extends Abstra
                     readChunkHead();
                     if (this.chunkSize == -1) {
                         // Unable to read a chunk head
-                        if (this.endOfStream) {
-                            this.state = COMPLETED;
-                            this.completed = true;
-                        }
                         return totalRead;
                     }
                     if (this.chunkSize == 0) {

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java?rev=1565641&r1=1565640&r2=1565641&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java
(original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestChunkDecoder.java
Fri Feb  7 13:28:02 2014
@@ -31,10 +31,12 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.MalformedChunkCodingException;
 import org.apache.http.ReadableByteChannelMock;
+import org.apache.http.TruncatedChunkException;
 import org.apache.http.impl.io.HttpTransportMetricsImpl;
 import org.apache.http.impl.nio.reactor.SessionInputBufferImpl;
 import org.apache.http.nio.reactor.SessionInputBuffer;
@@ -211,7 +213,7 @@ public class TestChunkDecoder {
         Assert.assertTrue(decoder.isCompleted());
     }
 
-    @Test
+    @Test(expected=MalformedChunkCodingException.class)
     public void testMalformedChunkSizeDecoding() throws Exception {
         final String s = "5\r\n01234\r\n5zz\r\n56789\r\n6\r\nabcdef\r\n0\r\n\r\n";
         final ReadableByteChannel channel = new ReadableByteChannelMock(
@@ -222,16 +224,10 @@ public class TestChunkDecoder {
         final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
 
         final ByteBuffer dst = ByteBuffer.allocate(1024);
-
-        try {
-            decoder.read(dst);
-            Assert.fail("MalformedChunkCodingException should have been thrown");
-        } catch (final MalformedChunkCodingException ex) {
-            // expected
-        }
+        decoder.read(dst);
     }
 
-    @Test
+    @Test(expected=MalformedChunkCodingException.class)
     public void testMalformedChunkEndingDecoding() throws Exception {
         final String s = "5\r\n01234\r\n5\r\n56789\r\r6\r\nabcdef\r\n0\r\n\r\n";
         final ReadableByteChannel channel = new ReadableByteChannelMock(
@@ -242,16 +238,10 @@ public class TestChunkDecoder {
         final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
 
         final ByteBuffer dst = ByteBuffer.allocate(1024);
-
-        try {
-            decoder.read(dst);
-            Assert.fail("MalformedChunkCodingException should have been thrown");
-        } catch (final MalformedChunkCodingException ex) {
-            // expected
-        }
+        decoder.read(dst);
     }
 
-    @Test
+    @Test(expected=TruncatedChunkException.class)
     public void testMalformedChunkTruncatedChunk() throws Exception {
         final String s = "3\r\n12";
         final ReadableByteChannel channel = new ReadableByteChannelMock(
@@ -263,12 +253,7 @@ public class TestChunkDecoder {
 
         final ByteBuffer dst = ByteBuffer.allocate(1024);
         Assert.assertEquals(2, decoder.read(dst));
-        try {
-            decoder.read(dst);
-            Assert.fail("MalformedChunkCodingException should have been thrown");
-        } catch (final MalformedChunkCodingException ex) {
-            // expected
-        }
+        decoder.read(dst);
     }
 
     @Test
@@ -294,7 +279,7 @@ public class TestChunkDecoder {
         Assert.assertEquals("abcde  fghij", footers[0].getValue());
     }
 
-    @Test
+    @Test(expected=IOException.class)
     public void testMalformedFooters() throws Exception {
         final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
                 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1 abcde\r\n\r\n";
@@ -306,19 +291,31 @@ public class TestChunkDecoder {
         final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
 
         final ByteBuffer dst = ByteBuffer.allocate(1024);
+        decoder.read(dst);
+    }
 
-        try {
+    @Test(expected=MalformedChunkCodingException.class)
+    public void testMissingLastCRLF() throws Exception {
+        final String s = "10\r\n1234567890123456\r\n" +
+                "5\r\n12345\r\n5\r\n12345";
+        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(1024);
+
+        while (dst.hasRemaining() && !decoder.isCompleted()) {
             decoder.read(dst);
-            Assert.fail("MalformedChunkCodingException should have been thrown");
-        } catch (final IOException ex) {
-            // expected
         }
     }
 
-    @Test
-    public void testEndOfStreamConditionReadingLastChunk() throws Exception {
+    @Test(expected=ConnectionClosedException.class)
+    public void testMissingClosingChunk() throws Exception {
         final String s = "10\r\n1234567890123456\r\n" +
-                "5\r\n12345\r\n5\r\n12345";
+                "5\r\n12345\r\n5\r\n12345\r\n";
         final ReadableByteChannel channel = new ReadableByteChannelMock(
                 new String[] {s}, Consts.ASCII);
 
@@ -328,17 +325,20 @@ public class TestChunkDecoder {
 
         final ByteBuffer dst = ByteBuffer.allocate(1024);
 
-        int bytesRead = 0;
-        while (dst.hasRemaining() && !decoder.isCompleted()) {
-            final int i = decoder.read(dst);
-            if (i > 0) {
-                bytesRead += i;
+        long bytesRead = 0;
+        try {
+            while (dst.hasRemaining() && !decoder.isCompleted()) {
+                final int i = decoder.read(dst);
+                if (i > 0) {
+                    bytesRead += i;
+                }
             }
+        } catch (final MalformedChunkCodingException ex) {
+            Assert.assertEquals(26L, bytesRead);
+            Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
+            Assert.assertTrue(decoder.isCompleted());
+            throw ex;
         }
-
-        Assert.assertEquals(26, bytesRead);
-        Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
-        Assert.assertTrue(decoder.isCompleted());
     }
 
     @Test
@@ -426,7 +426,7 @@ public class TestChunkDecoder {
         }
     }
 
-    @Test
+    @Test(expected=IllegalArgumentException.class)
     public void testInvalidInput() throws Exception {
         final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
                 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1 abcde\r\n\r\n";
@@ -436,13 +436,7 @@ public class TestChunkDecoder {
         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
         final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
-
-        try {
-            decoder.read(null);
-            Assert.fail("IllegalArgumentException should have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
+        decoder.read(null);
     }
 
 }

Modified: httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java?rev=1565641&r1=1565640&r2=1565641&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java
(original)
+++ httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java
Fri Feb  7 13:28:02 2014
@@ -30,6 +30,7 @@ package org.apache.http.impl.io;
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.Header;
 import org.apache.http.HttpException;
 import org.apache.http.MalformedChunkCodingException;
@@ -227,7 +228,8 @@ public class ChunkedInputStream extends 
             this.buffer.clear();
             final int bytesRead1 = this.in.readLine(this.buffer);
             if (bytesRead1 == -1) {
-                return 0;
+                throw new MalformedChunkCodingException(
+                    "CRLF expected at end of chunk");
             }
             if (!this.buffer.isEmpty()) {
                 throw new MalformedChunkCodingException(
@@ -239,7 +241,8 @@ public class ChunkedInputStream extends 
             this.buffer.clear();
             final int bytesRead2 = this.in.readLine(this.buffer);
             if (bytesRead2 == -1) {
-                return 0;
+                throw new ConnectionClosedException("Premature end of chunk coded message
body: " +
+                        "closing chunk expected");
             }
             int separator = this.buffer.indexOf(';');
             if (separator < 0) {

Modified: httpcomponents/httpcore/trunk/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java?rev=1565641&r1=1565640&r2=1565641&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java
(original)
+++ httpcomponents/httpcore/trunk/httpcore/src/test/java/org/apache/http/impl/io/TestChunkCoding.java
Fri Feb  7 13:28:02 2014
@@ -33,6 +33,7 @@ import java.io.InputStream;
 import java.io.InterruptedIOException;
 import java.io.OutputStream;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.MalformedChunkCodingException;
@@ -195,19 +196,29 @@ public class TestChunkCoding {
     }
 
     // Missing closing chunk
-    @Test
+    @Test(expected=ConnectionClosedException.class)
     public void testChunkedInputStreamNoClosingChunk() throws IOException {
         final String s = "5\r\n01234\r\n";
         final ChunkedInputStream in = new ChunkedInputStream(
                 new SessionInputBufferMock(s, Consts.ISO_8859_1));
         final byte[] tmp = new byte[5];
         Assert.assertEquals(5, in.read(tmp));
-        Assert.assertEquals(-1, in.read());
-        in.close();
-}
+        in.read();
+    }
+
+    // Truncated stream (missing closing CRLF)
+    @Test(expected=MalformedChunkCodingException.class)
+    public void testCorruptChunkedInputStreamTruncatedCRLF() throws IOException {
+        final String s = "5\r\n01234";
+        final ChunkedInputStream in = new ChunkedInputStream(
+                new SessionInputBufferMock(s, Consts.ISO_8859_1));
+        final byte[] tmp = new byte[5];
+        Assert.assertEquals(5, in.read(tmp));
+        in.read();
+    }
 
     // Missing \r\n at the end of the first chunk
-    @Test
+    @Test(expected=MalformedChunkCodingException.class)
     public void testCorruptChunkedInputStreamMissingCRLF() throws IOException {
         final String s = "5\r\n012345\r\n56789\r\n0\r\n";
         final InputStream in = new ChunkedInputStream(
@@ -215,29 +226,18 @@ public class TestChunkCoding {
         final byte[] buffer = new byte[300];
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         int len;
-        try {
-            while ((len = in.read(buffer)) > 0) {
-                out.write(buffer, 0, len);
-            }
-            Assert.fail("MalformedChunkCodingException should have been thrown");
-        } catch(final MalformedChunkCodingException e) {
-            /* expected exception */
+        while ((len = in.read(buffer)) > 0) {
+            out.write(buffer, 0, len);
         }
     }
 
     // Missing LF
-    @Test
+    @Test(expected=MalformedChunkCodingException.class)
     public void testCorruptChunkedInputStreamMissingLF() throws IOException {
         final String s = "5\r01234\r\n5\r\n56789\r\n0\r\n";
         final InputStream in = new ChunkedInputStream(
                 new SessionInputBufferMock(s, Consts.ISO_8859_1));
-        try {
-            in.read();
-            Assert.fail("MalformedChunkCodingException should have been thrown");
-        } catch(final MalformedChunkCodingException e) {
-            /* expected exception */
-        }
-        in.close();
+        in.read();
 }
 
     // Invalid chunk size



Mime
View raw message