hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject [05/35] httpcomponents-core git commit: In case of an unexpected end of stream condition (the peer closed connection prematurely) truncated Content-Length delimited message bodies to cause an I/O (merged from trunk)
Date Tue, 09 May 2017 20:03:34 GMT
In case of an unexpected end of stream condition (the peer closed connection
prematurely) truncated Content-Length delimited message bodies to cause an I/O (merged from
trunk)

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpcore/branches/4.1.x@1102665
13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/commit/ef786ef0
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/tree/ef786ef0
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/diff/ef786ef0

Branch: refs/heads/4.1.x
Commit: ef786ef03d47670290d85f4453ae3a00b320ab9c
Parents: 26632ee
Author: Oleg Kalnichevski <olegk@apache.org>
Authored: Fri May 13 11:04:18 2011 +0000
Committer: Oleg Kalnichevski <olegk@apache.org>
Committed: Fri May 13 11:04:18 2011 +0000

----------------------------------------------------------------------
 RELEASE_NOTES.txt                               |  7 +++
 .../impl/nio/codecs/LengthDelimitedDecoder.java | 13 +++++-
 .../nio/codecs/TestLengthDelimitedDecoder.java  | 47 ++++++++++++++++++++
 .../http/impl/io/ContentLengthInputStream.java  | 29 +++++++++---
 .../impl/io/TestContentLengthInputStream.java   | 34 +++++++++++---
 5 files changed, 116 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/ef786ef0/RELEASE_NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index e3a999e..7934625 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -1,4 +1,5 @@
 Release 4.1.1
+-------------------
 
 This is a patch release that fixes a number of non-critical issues found since release 4.1.
 
@@ -11,6 +12,12 @@ Please note that several classes and methods deprecated between versions
4.0-bet
 Users of 4.0.x versions are advised to upgrade and replace deprecated API calls following
 recommendations in javadocs.  
 
+* In case of an unexpected end of stream condition (the peer closed connection prematurely)

+  truncated Content-Length delimited message bodies will cause an I/O exception. Application
+  can still choose to catch and ignore ConnectionClosedException in order to accept partial

+  message content.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
 * [HTTPCORE-255]: Fixed resource management in InputStreamEntity#writeTo()
   Contributed by Oleg Kalnichevski <olegk at apache.org>
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/ef786ef0/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java
----------------------------------------------------------------------
diff --git a/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java
b/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java
index 8097f95..1f12d8b 100644
--- a/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java
+++ b/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java
@@ -32,6 +32,7 @@ import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.ReadableByteChannel;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.impl.io.HttpTransportMetricsImpl;
 import org.apache.http.nio.FileContentDecoder;
 import org.apache.http.nio.reactor.SessionInputBuffer;
@@ -97,7 +98,11 @@ public class LengthDelimitedDecoder extends AbstractContentDecoder
         }
         if (bytesRead == -1) {
             this.completed = true;
-            return -1;
+            if (this.len < this.contentLength) {
+                throw new ConnectionClosedException(
+                        "Premature end of Content-Length delimited message body (expected:
"
+                        + this.contentLength + "; received: " + this.len);
+            }
         }
         this.len += bytesRead;
         if (this.len >= this.contentLength) {
@@ -149,7 +154,11 @@ public class LengthDelimitedDecoder extends AbstractContentDecoder
         }
         if (bytesRead == -1) {
             this.completed = true;
-            return -1;
+            if (this.len < this.contentLength) {
+                throw new ConnectionClosedException(
+                        "Premature end of Content-Length delimited message body (expected:
"
+                        + this.contentLength + "; received: " + this.len);
+            }
         }
         this.len += bytesRead;
         if (this.len >= this.contentLength) {

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/ef786ef0/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java
----------------------------------------------------------------------
diff --git a/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java
b/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java
index 2ab516e..1c005b2 100644
--- a/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java
+++ b/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java
@@ -38,6 +38,7 @@ import java.nio.channels.ReadableByteChannel;
 
 import junit.framework.TestCase;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.impl.io.HttpTransportMetricsImpl;
 import org.apache.http.impl.nio.reactor.SessionInputBufferImpl;
 import org.apache.http.mockup.ReadableByteChannelMockup;
@@ -516,4 +517,50 @@ public class TestLengthDelimitedDecoder extends TestCase {
         assertEquals(0, metrics.getBytesTransferred());
     }
 
+    public void testTruncatedContent() throws Exception {
+        ReadableByteChannel channel = new ReadableByteChannelMockup(
+                new String[] {"1234567890"}, "US-ASCII");
+        HttpParams params = new BasicHttpParams();
+
+        SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, params);
+        HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
+        LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
+                channel, inbuf, metrics, 20);
+
+        ByteBuffer dst = ByteBuffer.allocate(1024);
+
+        int bytesRead = decoder.read(dst);
+        assertEquals(10, bytesRead);
+        try {
+            decoder.read(dst);
+            fail("ClosedChannelException should have been thrown");
+        } catch (ConnectionClosedException ex) {
+        }
+    }
+
+    public void testTruncatedContentWithFile() throws Exception {
+        ReadableByteChannel channel = new ReadableByteChannelMockup(
+                new String[] {"1234567890"}, "US-ASCII");
+        HttpParams params = new BasicHttpParams();
+
+        SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, params);
+        HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
+        LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
+                channel, inbuf, metrics, 20);
+
+        File fileHandle = File.createTempFile("testFile", ".txt");
+        RandomAccessFile testfile  = new RandomAccessFile(fileHandle, "rw");
+        FileChannel fchannel = testfile.getChannel();
+        long bytesRead = decoder.transfer(fchannel, 0, Integer.MAX_VALUE);
+        assertEquals(10, bytesRead);
+        try {
+            decoder.transfer(fchannel, 10, Integer.MAX_VALUE);
+            fail("ClosedChannelException should have been thrown");
+        } catch (ConnectionClosedException ex) {
+        } finally {
+            testfile.close();
+            deleteWithCheck(fileHandle);
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/ef786ef0/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java
----------------------------------------------------------------------
diff --git a/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java
b/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java
index b53b9d5..e606b0e 100644
--- a/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java
+++ b/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java
@@ -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.io.BufferInfo;
 import org.apache.http.io.SessionInputBuffer;
 
@@ -99,8 +100,10 @@ public class ContentLengthInputStream extends InputStream {
     public void close() throws IOException {
         if (!closed) {
             try {
-                byte buffer[] = new byte[BUFFER_SIZE];
-                while (read(buffer) >= 0) {
+                if (pos < contentLength) {
+                    byte buffer[] = new byte[BUFFER_SIZE];
+                    while (read(buffer) >= 0) {
+                    }
                 }
             } finally {
                 // close after above so that we don't throw an exception trying
@@ -133,8 +136,17 @@ public class ContentLengthInputStream extends InputStream {
         if (pos >= contentLength) {
             return -1;
         }
-        pos++;
-        return this.in.read();
+        int b = this.in.read();
+        if (b == -1) {
+            if (pos < contentLength) {
+                throw new ConnectionClosedException(
+                        "Premature end of Content-Length delimited message body (expected:
"
+                        + contentLength + "; received: " + pos);
+            }
+        } else {
+            pos++;
+        }
+        return b;
     }
 
     /**
@@ -162,7 +174,14 @@ public class ContentLengthInputStream extends InputStream {
             len = (int) (contentLength - pos);
         }
         int count = this.in.read(b, off, len);
-        pos += count;
+        if (count == -1 && pos < contentLength) {
+            throw new ConnectionClosedException(
+                    "Premature end of Content-Length delimited message body (expected: "
+                    + contentLength + "; received: " + pos);
+        }
+        if (count > 0) {
+            pos += count;
+        }
         return count;
     }
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/ef786ef0/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java
----------------------------------------------------------------------
diff --git a/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java
b/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java
index 83b73f2..ea6d5ac 100644
--- a/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java
+++ b/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java
@@ -33,7 +33,9 @@ import java.io.InputStream;
 
 import junit.framework.TestCase;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.mockup.SessionInputBufferMockup;
+import org.apache.http.io.SessionInputBuffer;
 import org.apache.http.util.EncodingUtils;
 
 public class TestContentLengthInputStream extends TestCase {
@@ -93,10 +95,6 @@ public class TestContentLengthInputStream extends TestCase {
         assertTrue(in.skip(-1) == 0);
         assertTrue(in.read() == -1);
 
-        in = new ContentLengthInputStream(new SessionInputBufferMockup(new byte[2]), 4L);
-        in.read();
-        assertTrue(in.skip(2) == 1);
-
         in = new ContentLengthInputStream(new SessionInputBufferMockup(new byte[20]), 10L);
         assertEquals(5,in.skip(5));
         assertEquals(5, in.read(new byte[20]));
@@ -111,9 +109,10 @@ public class TestContentLengthInputStream extends TestCase {
     }
 
     public void testClose() throws IOException {
-        String correct = "1234567890123456";
-        InputStream in = new ContentLengthInputStream(new SessionInputBufferMockup(
-            EncodingUtils.getBytes(correct, CONTENT_CHARSET)), 10L);
+        String correct = "1234567890123456-";
+        SessionInputBuffer inbuffer = new SessionInputBufferMockup(
+                EncodingUtils.getBytes(correct, CONTENT_CHARSET));
+        InputStream in = new ContentLengthInputStream(inbuffer, 16L);
         in.close();
         in.close();
         try {
@@ -135,6 +134,27 @@ public class TestContentLengthInputStream extends TestCase {
         } catch (IOException ex) {
             // expected
         }
+        assertEquals('-', inbuffer.read());
+    }
+
+    public void testTruncatedContent() throws IOException {
+        String correct = "1234567890123456";
+        SessionInputBuffer inbuffer = new SessionInputBufferMockup(EncodingUtils.getBytes(
+                correct, CONTENT_CHARSET));
+        InputStream in = new ContentLengthInputStream(inbuffer, 32L);
+        byte[] tmp = new byte[32];
+        int byteRead = in.read(tmp);
+        assertEquals(16, byteRead);
+        try {
+            in.read(tmp);
+            fail("ConnectionClosedException should have been closed");
+        } catch (ConnectionClosedException ex) {
+        }
+        try {
+            in.read();
+            fail("ConnectionClosedException should have been closed");
+        } catch (ConnectionClosedException ex) {
+        }
     }
 
 }


Mime
View raw message