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 2011/05/13 13:04:19 UTC
svn commit: r1102665 - in /httpcomponents/httpcore/branches/4.1.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/t...
Author: olegk
Date: Fri May 13 11:04:18 2011
New Revision: 1102665
URL: http://svn.apache.org/viewvc?rev=1102665&view=rev
Log:
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)
Modified:
httpcomponents/httpcore/branches/4.1.x/ (props changed)
httpcomponents/httpcore/branches/4.1.x/RELEASE_NOTES.txt
httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java
httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java
httpcomponents/httpcore/branches/4.1.x/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java
httpcomponents/httpcore/branches/4.1.x/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java
Propchange: httpcomponents/httpcore/branches/4.1.x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri May 13 11:04:18 2011
@@ -1 +1,2 @@
/httpcomponents/httpcore/branches/ibm_compat_branch:755687-758898
+/httpcomponents/httpcore/trunk:1102241-1102657
Modified: httpcomponents/httpcore/branches/4.1.x/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.1.x/RELEASE_NOTES.txt?rev=1102665&r1=1102664&r2=1102665&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.1.x/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpcore/branches/4.1.x/RELEASE_NOTES.txt Fri May 13 11:04:18 2011
@@ -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 met
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>
Modified: httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java?rev=1102665&r1=1102664&r2=1102665&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java (original)
+++ httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/codecs/LengthDelimitedDecoder.java Fri May 13 11:04:18 2011
@@ -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 exte
}
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 exte
}
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) {
Modified: httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java?rev=1102665&r1=1102664&r2=1102665&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java (original)
+++ httpcomponents/httpcore/branches/4.1.x/httpcore-nio/src/test/java/org/apache/http/impl/nio/codecs/TestLengthDelimitedDecoder.java Fri May 13 11:04:18 2011
@@ -38,6 +38,7 @@ import java.nio.channels.ReadableByteCha
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
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);
+ }
+ }
+
}
Modified: httpcomponents/httpcore/branches/4.1.x/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.1.x/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java?rev=1102665&r1=1102664&r2=1102665&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.1.x/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java (original)
+++ httpcomponents/httpcore/branches/4.1.x/httpcore/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java Fri May 13 11:04:18 2011
@@ -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 ex
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 ex
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 ex
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;
}
Modified: httpcomponents/httpcore/branches/4.1.x/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.1.x/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java?rev=1102665&r1=1102664&r2=1102665&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.1.x/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java (original)
+++ httpcomponents/httpcore/branches/4.1.x/httpcore/src/test/java/org/apache/http/impl/io/TestContentLengthInputStream.java Fri May 13 11:04:18 2011
@@ -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 TestContentLengthInputStrea
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 TestContentLengthInputStrea
}
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 TestContentLengthInputStrea
} 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) {
+ }
}
}