Index: trunk/http-core/src/test/org/apache/http/impl/TestDefaultEntityGenerator.java
===================================================================
--- trunk/http-core/src/test/org/apache/http/impl/TestDefaultEntityGenerator.java (revision 375039)
+++ trunk/http-core/src/test/org/apache/http/impl/TestDefaultEntityGenerator.java (working copy)
@@ -28,6 +28,8 @@
package org.apache.http.impl;
+import java.io.InputStream;
+
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpMutableMessage;
@@ -205,8 +207,9 @@
assertNotNull(entity);
assertEquals(1, entity.getContentLength());
assertFalse(entity.isChunked());
- assertNotNull(entity.getContent());
- assertTrue(entity.getContent() instanceof ContentLengthInputStream);
+ InputStream instream = entity.getContent();
+ assertNotNull(instream);
+ assertTrue(instream instanceof ContentLengthInputStream);
// strict mode
message.getParams().setBooleanParameter(HttpProtocolParams.STRICT_TRANSFER_ENCODING, true);
@@ -233,8 +236,9 @@
assertNotNull(entity);
assertEquals(1, entity.getContentLength());
assertFalse(entity.isChunked());
- assertNotNull(entity.getContent());
- assertTrue(entity.getContent() instanceof ContentLengthInputStream);
+ InputStream instream = entity.getContent();
+ assertNotNull(instream);
+ assertTrue(instream instanceof ContentLengthInputStream);
// strict mode
message.getParams().setBooleanParameter(HttpProtocolParams.STRICT_TRANSFER_ENCODING, true);
@@ -260,9 +264,10 @@
assertNotNull(entity);
assertEquals(-1, entity.getContentLength());
assertFalse(entity.isChunked());
- assertNotNull(entity.getContent());
- assertFalse(entity.getContent() instanceof ContentLengthInputStream);
- assertTrue(entity.getContent() instanceof HttpDataInputStream);
+ InputStream instream = entity.getContent();
+ assertNotNull(instream);
+ assertFalse(instream instanceof ContentLengthInputStream);
+ assertTrue(instream instanceof HttpDataInputStream);
// strict mode
message.getParams().setBooleanParameter(HttpProtocolParams.STRICT_TRANSFER_ENCODING, true);
@@ -287,9 +292,10 @@
assertNotNull(entity);
assertEquals(-1, entity.getContentLength());
assertFalse(entity.isChunked());
- assertNotNull(entity.getContent());
- assertFalse(entity.getContent() instanceof ContentLengthInputStream);
- assertTrue(entity.getContent() instanceof HttpDataInputStream);
+ InputStream instream = entity.getContent();
+ assertNotNull(instream);
+ assertFalse(instream instanceof ContentLengthInputStream);
+ assertTrue(instream instanceof HttpDataInputStream);
// strict mode
message.getParams().setBooleanParameter(HttpProtocolParams.STRICT_TRANSFER_ENCODING, true);
@@ -312,10 +318,11 @@
assertNotNull(entity);
assertEquals(-1, entity.getContentLength());
assertFalse(entity.isChunked());
- assertNotNull(entity.getContent());
- assertFalse(entity.getContent() instanceof ContentLengthInputStream);
- assertFalse(entity.getContent() instanceof ChunkedInputStream);
- assertTrue(entity.getContent() instanceof HttpDataInputStream);
+ InputStream instream = entity.getContent();
+ assertNotNull(instream);
+ assertFalse(instream instanceof ContentLengthInputStream);
+ assertFalse(instream instanceof ChunkedInputStream);
+ assertTrue(instream instanceof HttpDataInputStream);
}
}
Index: trunk/http-core/src/test/org/apache/http/util/TestEncodingUtils.java
===================================================================
--- trunk/http-core/src/test/org/apache/http/util/TestEncodingUtils.java (revision 375039)
+++ trunk/http-core/src/test/org/apache/http/util/TestEncodingUtils.java (working copy)
@@ -191,4 +191,17 @@
assertEquals(s1, s2);
}
-}
\ No newline at end of file
+ public void testIllegalEncoding() {
+ String s = constructString(SWISS_GERMAN_HELLO);
+ byte[] b1 = s.getBytes();
+ byte[] b2 = EncodingUtils.getBytes(s, "some chars,illegal/are!");
+ assertEquals(b1.length, b2.length);
+ for (int i = 0; i < b1.length; i++) {
+ assertEquals(b1[i], b2[i]);
+ }
+ String s1 = new String(b1);
+ String s2 = EncodingUtils.getString(b1, "some chars,illegal/are!");
+ assertEquals(s1, s2);
+ }
+
+}
Index: trunk/http-core/src/test/org/apache/http/util/TestEntityUtils.java
===================================================================
--- trunk/http-core/src/test/org/apache/http/util/TestEntityUtils.java (revision 375039)
+++ trunk/http-core/src/test/org/apache/http/util/TestEntityUtils.java (working copy)
@@ -29,6 +29,7 @@
package org.apache.http.util;
+import java.io.InputStream;
import java.io.ByteArrayInputStream;
import org.apache.http.Header;
@@ -68,8 +69,11 @@
}
public void testEmptyContentToByteArray() throws Exception {
- BasicHttpEntity httpentity = new BasicHttpEntity();
- httpentity.setContent(null);
+ NullHttpEntity httpentity = new NullHttpEntity();
+ //BasicHttpEntity httpentity = new BasicHttpEntity();
+ //httpentity.setContent(null);
+ //byte[] content = new byte[0];
+ //httpentity.setContent(new ByteArrayInputStream(content));
byte[] bytes = EntityUtils.toByteArray(httpentity);
assertNotNull(bytes);
assertEquals(0, bytes.length);
@@ -125,7 +129,7 @@
public void testNullContentTypeGetContentCharset() throws Exception {
BasicHttpEntity httpentity = new BasicHttpEntity();
- httpentity.setContentType(null);
+ httpentity.setContentType((Header)null);
assertNull(EntityUtils.getContentCharSet(httpentity));
}
@@ -151,8 +155,11 @@
}
public void testEmptyContentToString() throws Exception {
- BasicHttpEntity httpentity = new BasicHttpEntity();
- httpentity.setContent(null);
+ NullHttpEntity httpentity = new NullHttpEntity();
+ //BasicHttpEntity httpentity = new BasicHttpEntity();
+ //httpentity.setContent(null);
+ //byte[] content = new byte[0];
+ //httpentity.setContent(new ByteArrayInputStream(content));
String s = EntityUtils.toString(httpentity);
assertNotNull(s);
assertEquals("", s);
@@ -237,5 +244,22 @@
String s = EntityUtils.toString(httpentity, "ISO-8859-1");
assertEquals(content, s);
}
-
-}
+
+ /**
+ * Helper class that returns null as the content.
+ */
+ public static class NullHttpEntity extends BasicHttpEntity {
+
+ // default constructor
+ /**
+ * Obtains no content.
+ * This method disables the state checks in the base class.
+ *
+ * @return null
+ */
+ public InputStream getContent() {
+ return null;
+ }
+ } // class NullEntity
+
+} // class TestEntityUtils
Index: trunk/http-core/src/contrib/org/apache/http/contrib/compress/GzipDecompressingEntity.java
===================================================================
--- trunk/http-core/src/contrib/org/apache/http/contrib/compress/GzipDecompressingEntity.java (revision 375039)
+++ trunk/http-core/src/contrib/org/apache/http/contrib/compress/GzipDecompressingEntity.java (working copy)
@@ -47,26 +47,22 @@
*/
public class GzipDecompressingEntity extends HttpEntityWrapper {
- private InputStream instream = null;
-
public GzipDecompressingEntity(final HttpEntity entity) {
super(entity);
}
- public InputStream getContent() throws IOException {
- if (this.instream == null) {
- this.instream = new GZIPInputStream(wrappedEntity.getContent());
- }
- return this.instream;
+ public InputStream getContent()
+ throws IOException, IllegalStateException {
+
+ // the wrapped entity's getContent() decides about repeatability
+ InputStream wrappedin = wrappedEntity.getContent();
+
+ return new GZIPInputStream(wrappedin);
}
-
+
public long getContentLength() {
+ // length of ungzipped content not known in advance
return -1;
}
-
- public boolean isRepeatable() {
- // not repeatable, GZIPInputStream is created only once
- return false;
- }
-
-} // class GzipDecompressingEntity
\ No newline at end of file
+
+} // class GzipDecompressingEntity
Index: trunk/http-core/src/java/org/apache/http/HttpEntity.java
===================================================================
--- trunk/http-core/src/java/org/apache/http/HttpEntity.java (revision 375039)
+++ trunk/http-core/src/java/org/apache/http/HttpEntity.java (working copy)
@@ -130,10 +130,17 @@
* Creates a new InputStream object of the entity.
* It is a programming error
* to return the same InputStream object more than once.
+ * Entities that are not {@link #isRepeatable repeatable}
+ * will throw an exception if this method is called multiple times.
+ *
* @return a new input stream that returns the entity data.
+ *
* @throws IOException if the stream could not be created
+ * @throws IllegalStateException
+ * if this entity is not repeatable and the stream
+ * has already been obtained previously
*/
- InputStream getContent() throws IOException;
+ InputStream getContent() throws IOException, IllegalStateException;
/**
* Writes the entity content to the output stream.
Index: trunk/http-core/src/java/org/apache/http/entity/BasicHttpEntity.java
===================================================================
--- trunk/http-core/src/java/org/apache/http/entity/BasicHttpEntity.java (revision 375039)
+++ trunk/http-core/src/java/org/apache/http/entity/BasicHttpEntity.java (working copy)
@@ -45,62 +45,90 @@
*
* @since 4.0
*/
-public class BasicHttpEntity implements HttpEntity {
-
- private Header contentType = null;
- private Header contentEncoding = null;
- private InputStream content = null;
- private long length = -1;
- private boolean chunked = false;
-
+public class BasicHttpEntity extends AbstractHttpEntity
+ implements HttpEntity {
+
+ private InputStream content;
+ private boolean contentObtained;
+ private long length;
+
+
+ /**
+ * Creates a new basic entity.
+ * The content is initially missing, the content length
+ * is set to a negative number.
+ */
public BasicHttpEntity() {
super();
+ length = -1;
}
+
+ // non-javadoc, see interface HttpEntity
public long getContentLength() {
return this.length;
}
- public Header getContentType() {
- return this.contentType;
- }
-
- public Header getContentEncoding() {
- return this.contentEncoding;
- }
-
- public InputStream getContent() {
+
+ /**
+ * Obtains the content, once only.
+ *
+ * @return the content, if this is the first call to this method
+ * since {@link #setContent setContent} has been called
+ *
+ * @throws IllegalStateException
+ * if the content has been obtained before, or
+ * has not yet been provided
+ */
+ public InputStream getContent()
+ throws IllegalStateException {
+
+ if (this.content == null)
+ throw new IllegalStateException("content has not been provided");
+ if (contentObtained)
+ throw new IllegalStateException("content is not repeatable");
+
+ contentObtained = true;
return this.content;
- }
-
- public boolean isChunked() {
- return this.chunked;
- }
-
+
+ } // getContent
+
+
+ /**
+ * Tells that this entity is not repeatable.
+ *
+ * @return false
+ */
public boolean isRepeatable() {
return false;
}
-
- public void setChunked(boolean b) {
- this.chunked = b;
- }
-
+
+
+ /**
+ * Specifies the length of the content.
+ *
+ * @param len the number of bytes in the content, or
+ * a negative number to indicate an unknown length
+ */
public void setContentLength(long len) {
this.length = len;
}
-
- public void setContentType(final Header contentType) {
- this.contentType = contentType;
- }
-
- public void setContentEncoding(final Header contentEncoding) {
- this.contentEncoding = contentEncoding;
- }
-
+
+
+ /**
+ * Specifies the content.
+ *
+ * @param instream the stream to return with the next call to
+ * {@link #getContent getContent}
+ */
public void setContent(final InputStream instream) {
- this.content = instream;
+ this.content = instream;
+ if (instream != null)
+ contentObtained = false;
}
-
+
+
+ // non-javadoc, see interface HttpEntity
public void writeTo(final OutputStream outstream) throws IOException {
if (outstream == null) {
throw new IllegalArgumentException("Output stream may not be null");
Index: trunk/http-core/src/java/org/apache/http/util/EncodingUtils.java
===================================================================
--- trunk/http-core/src/java/org/apache/http/util/EncodingUtils.java (revision 375039)
+++ trunk/http-core/src/java/org/apache/http/util/EncodingUtils.java (working copy)
@@ -29,6 +29,7 @@
package org.apache.http.util;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.IllegalCharsetNameException;
import org.apache.http.protocol.HTTP;
@@ -70,14 +71,26 @@
throw new IllegalArgumentException("charset may not be null or empty");
}
+ String result = null;
try {
- return new String(data, offset, length, charset);
+ result = new String(data, offset, length, charset);
+
} catch (UnsupportedEncodingException e) {
- return new String(data, offset, length);
+ // ignore, result remains null to trigger fallback
+ } catch (IllegalCharsetNameException e) {
+ // ignore, result remains null to trigger fallback
}
- }
+ if (result == null) {
+ // fallback: use default platform encoding
+ result = new String(data, offset, length);
+ }
+ return result;
+
+ } // getString
+
+
/**
* Converts the byte array of HTTP content characters to a string. If
* the specified charset is not supported, default system encoding
Index: trunk/http-core/src/java/org/apache/http/util/EntityUtils.java
===================================================================
--- trunk/http-core/src/java/org/apache/http/util/EntityUtils.java (revision 375039)
+++ trunk/http-core/src/java/org/apache/http/util/EntityUtils.java (working copy)
@@ -101,7 +101,8 @@
if (entity == null) {
throw new IllegalArgumentException("HTTP entity may not be null");
}
- if (entity.getContent() == null) {
+ InputStream instream = entity.getContent();
+ if (instream == null) {
return "";
}
if (entity.getContentLength() > Integer.MAX_VALUE) {
@@ -118,7 +119,7 @@
if (charset == null) {
charset = HTTP.DEFAULT_CONTENT_CHARSET;
}
- Reader reader = new InputStreamReader(entity.getContent(), charset);
+ Reader reader = new InputStreamReader(instream, charset);
CharArrayBuffer buffer = new CharArrayBuffer(i);
char[] tmp = new char[1024];
int l;