You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by Oleg Kalnichevski <o....@dplanet.ch> on 2003/02/13 21:20:53 UTC
[PATCH]: 100-continue support in MultipartPost, non-compliant
emptry chunk-enconded content fix
Bug fixes
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16892
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14036
- Chunk-encoding problem related to non-compliant empty content streams
generated by IIS has been fixed
- MultipartPost method now supports "expect: 100-continue" handshake
All changes are incremental. I'll commit the patch before midnight (+1
GMT) if nobody loudly objects
Cheers
Oleg
Re: [PATCH]: 100-continue support in MultipartPost, non-compliant
emptry chunk-enconded content fix
Posted by Oleg Kalnichevski <o....@dplanet.ch>.
On Thu, 2003-02-13 at 21:30, Jeffrey Dever wrote:
> + public boolean responseAvaliable()
> Might be a little more standard by using:
>
> + public boolean isResponseAvaliable()
>
>
Agreed.
> + LOG.trace("enter recycle()");
>
> should be:
>
> + LOG.trace("enter MultiPartPostMethod.recycle()");
>
> But I kinda dispise those statements anyway. I'm looking into aspectJ
> for handling stuff like that, but not till 2.1
>
So do I. I find trace verbosity next to being useless. I'll correct the
messages
Oleg
Re: [PATCH]: 100-continue support in MultipartPost, non-compliant
emptry chunk-enconded content fix
Posted by Jeffrey Dever <js...@sympatico.ca>.
+ public boolean responseAvaliable()
Might be a little more standard by using:
+ public boolean isResponseAvaliable()
+ LOG.trace("enter recycle()");
should be:
+ LOG.trace("enter MultiPartPostMethod.recycle()");
But I kinda dispise those statements anyway. I'm looking into aspectJ
for handling stuff like that, but not till 2.1
Jandalf.
Oleg Kalnichevski wrote:
>Bug fixes
>
>http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16892
>http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14036
>
>- Chunk-encoding problem related to non-compliant empty content streams
>generated by IIS has been fixed
>- MultipartPost method now supports "expect: 100-continue" handshake
>
>All changes are incremental. I'll commit the patch before midnight (+1
>GMT) if nobody loudly objects
>
>Cheers
>
>Oleg
>
>
>------------------------------------------------------------------------
>
>Index: java/org/apache/commons/httpclient/ChunkedInputStream.java
>===================================================================
>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java,v
>retrieving revision 1.13
>diff -u -r1.13 ChunkedInputStream.java
>--- java/org/apache/commons/httpclient/ChunkedInputStream.java 11 Feb 2003 03:23:05 -0000 1.13
>+++ java/org/apache/commons/httpclient/ChunkedInputStream.java 13 Feb 2003 20:08:35 -0000
>@@ -87,6 +87,7 @@
> * @author Eric Johnson
> * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
> * @author Michael Becke
>+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
> *
> * @since 2.0
> *
>@@ -130,7 +131,7 @@
> }
> this.in = in;
> this.method = method;
>- this.chunkSize = getChunkSizeFromInputStream(in);
>+ this.chunkSize = getChunkSizeFromInputStream(in, false);
> if (chunkSize == 0) {
> eof = true;
> parseTrailerHeaders();
>@@ -239,11 +240,16 @@
> * comment\r\n" Positions the stream at the start of the next line.
> *
> * @param in The new input stream.
>+ * @param required <tt>true<tt/> if a valid chunk must be present,
>+ * <tt>false<tt/> otherwise.
>+ *
> * @return the chunk size as integer
>+ *
> * @throws IOException when the chunk size could not be parsed
> */
> private static int getChunkSizeFromInputStream(
>- final InputStream in) throws IOException {
>+ final InputStream in, boolean required)
>+ throws IOException {
>
> ByteArrayOutputStream baos = new ByteArrayOutputStream();
> // States: 0=normal, 1=\r was scanned, 2=inside quoted string, -1=end
>@@ -251,7 +257,11 @@
> while (state != -1) {
> int b = in.read();
> if (b == -1) {
>- throw new IOException("chunked stream ended unexpectedly");
>+ if (required) {
>+ throw new IOException("chunked stream ended unexpectedly");
>+ } else {
>+ return 0;
>+ }
> }
> switch (state) {
> case 0:
>@@ -310,6 +320,21 @@
> return result;
> }
>
>+ /**
>+ * Expects the stream to start with a chunksize in hex with optional
>+ * 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.
>+ *
>+ * @param in The new input stream.
>+ *
>+ * @return the chunk size as integer
>+ *
>+ * @throws IOException when the chunk size could not be parsed
>+ */
>+ private static int getChunkSizeFromInputStream(final InputStream in)
>+ throws IOException {
>+ return getChunkSizeFromInputStream(in, true);
>+ }
> /**
> * Reads and stores the Trailer headers.
> * @throws IOException If an IO problem occurs
>Index: java/org/apache/commons/httpclient/HttpConnection.java
>===================================================================
>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v
>retrieving revision 1.43
>diff -u -r1.43 HttpConnection.java
>--- java/org/apache/commons/httpclient/HttpConnection.java 11 Feb 2003 03:23:05 -0000 1.43
>+++ java/org/apache/commons/httpclient/HttpConnection.java 13 Feb 2003 20:08:33 -0000
>@@ -692,11 +692,29 @@
> }
>
> /**
>+ * Tests if input data avaialble.
>+ *
>+ * @return boolean <tt>true</tt> if input data is availble,
>+ * <tt>false</tt> otherwise.
>+ *
>+ * @throws IOException If an IO problem occurs
>+ * @throws IllegalStateException If the connection isn't open.
>+ */
>+ public boolean responseAvaliable()
>+ throws IOException {
>+ LOG.trace("enter HttpConnection.responseAvaliable()");
>+ assertOpen();
>+ return this.inputStream.available() > 0;
>+ }
>+
>+
>+ /**
> * Waits for the specified number of milliseconds for input data to become available
> *
> * @param timeout_ms Number of milliseconds to wait for input data.
> *
>- * @return boolean <tt>true</tt> if input data is availble, <tt>false</tt> otherwise.
>+ * @return boolean <tt>true</tt> if input data is availble,
>+ * <tt>false</tt> otherwise.
> *
> * @throws IOException If an IO problem occurs
> * @throws IllegalStateException If the connection isn't open.
>@@ -704,13 +722,12 @@
> public boolean waitForResponse(long timeout_ms)
> throws IOException, IllegalStateException {
> LOG.trace("enter HttpConnection.waitForResponse(int)");
>- assertOpen();
> if (timeout_ms < 0) {
> throw new IllegalArgumentException("Timeout value may not be negative");
> }
> long overtime = System.currentTimeMillis() + timeout_ms;
> while (System.currentTimeMillis() < overtime) {
>- if (inputStream.available() > 0) {
>+ if (responseAvaliable()) {
> return true;
> }
> }
>Index: java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java
>===================================================================
>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java,v
>retrieving revision 1.8
>diff -u -r1.8 EntityEnclosingMethod.java
>--- java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java 8 Feb 2003 19:22:49 -0000 1.8
>+++ java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java 13 Feb 2003 20:08:38 -0000
>@@ -126,7 +126,8 @@
> */
> private int requestContentLength = CONTENT_LENGTH_AUTO;
>
>-
>+ /** This flag specifies whether "expect: 100-continue" handshake is
>+ * to be used prior to sending the requesst body */
> private boolean useExpectHeader = true;
>
> // ----------------------------------------------------------- Constructors
>Index: java/org/apache/commons/httpclient/methods/MultipartPostMethod.java
>===================================================================
>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/MultipartPostMethod.java,v
>retrieving revision 1.9
>diff -u -r1.9 MultipartPostMethod.java
>--- java/org/apache/commons/httpclient/methods/MultipartPostMethod.java 12 Feb 2003 12:30:44 -0000 1.9
>+++ java/org/apache/commons/httpclient/methods/MultipartPostMethod.java 13 Feb 2003 20:08:40 -0000
>@@ -73,6 +73,7 @@
> import org.apache.commons.httpclient.HttpConnection;
> import org.apache.commons.httpclient.HttpException;
> import org.apache.commons.httpclient.HttpState;
>+import org.apache.commons.httpclient.HttpStatus;
> import org.apache.commons.httpclient.methods.multipart.FilePart;
> import org.apache.commons.httpclient.methods.multipart.Part;
> import org.apache.commons.httpclient.methods.multipart.StringPart;
>@@ -104,6 +105,10 @@
> /** The parameters for this method */
> private final List parameters = new ArrayList();
>
>+ /** This flag specifies whether "expect: 100-continue" handshake is
>+ * to be used prior to sending the request body */
>+ private boolean useExpectHeader = true;
>+
> /**
> * No-arg constructor.
> */
>@@ -141,7 +146,6 @@
> super(uri, tempDir, tempFile);
> }
>
>-
> /**
> * Returns <tt>"POST"</tt>.
> * @return <tt>"POST"</tt>
>@@ -151,12 +155,19 @@
> }
>
> /**
>- * Clear my request body.
>+ * Returns the useExpectHeader.
>+ * @return boolean
> */
>- public void recycle() {
>- LOG.trace("enter recycle()");
>- super.recycle();
>- parameters.clear();
>+ public boolean getUseExpectHeader() {
>+ return this.useExpectHeader;
>+ }
>+
>+ /**
>+ * Sets the useExpectHeader.
>+ * @param value The useExpectHeader to set
>+ */
>+ public void setUseExpectHeader(boolean value) {
>+ this.useExpectHeader = value;
> }
>
> /**
>@@ -216,11 +227,14 @@
> return (Part[])parameters.toArray(new Part[parameters.size()]);
> }
> /**
>- * Add a request header.
>+ * Add content type header and set the <tt>Expect</tt> header
>+ * if it has not already been set, in addition to the "standard"
>+ * set of headers
> *
> * @param state the client state
> * @param conn the {@link HttpConnection} the headers will eventually be
> * written to
>+ *
> * @throws IOException when an error occurs writing the request
> * @throws HttpException when a HTTP protocol error occurs
> */
>@@ -237,6 +251,16 @@
> }
> setRequestHeader("Content-Type", buffer.toString());
> }
>+ boolean headerPresent = (getRequestHeader("Expect") != null);
>+ if (getUseExpectHeader() && isHttp11()) {
>+ if (!headerPresent) {
>+ setRequestHeader("Expect", "100-continue");
>+ }
>+ } else {
>+ if (headerPresent) {
>+ removeRequestHeader("Expect");
>+ }
>+ }
> }
>
> /**
>@@ -252,6 +276,16 @@
> protected boolean writeRequestBody(HttpState state, HttpConnection conn)
> throws IOException, HttpException {
> LOG.trace("enter writeRequestBody(HttpState state, HttpConnection conn)");
>+ if (getRequestHeader("Expect") != null) {
>+ if (getStatusLine() == null) {
>+ LOG.debug("Expecting response");
>+ return false;
>+ }
>+ if (getStatusLine().getStatusCode() != HttpStatus.SC_CONTINUE) {
>+ LOG.debug("Expecting 100-continue");
>+ return false;
>+ }
>+ }
> OutputStream out = conn.getRequestOutputStream();
> Part.sendParts(out, getParts());
> return true;
>@@ -280,4 +314,15 @@
> throw new RuntimeException(e.toString());
> }
> }
>+
>+
>+ /**
>+ * Clear my request body.
>+ */
>+ public void recycle() {
>+ LOG.trace("enter recycle()");
>+ super.recycle();
>+ parameters.clear();
>+ }
>+
> }
>Index: test/org/apache/commons/httpclient/TestStreams.java
>===================================================================
>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestStreams.java,v
>retrieving revision 1.9
>diff -u -r1.9 TestStreams.java
>--- test/org/apache/commons/httpclient/TestStreams.java 11 Feb 2003 03:23:05 -0000 1.9
>+++ test/org/apache/commons/httpclient/TestStreams.java 13 Feb 2003 20:08:27 -0000
>@@ -152,6 +152,19 @@
> assertEquals(0, out.size());
> }
>
>+ public void testNoncompliantEmptyChunkedInputStream() throws IOException {
>+ HttpMethod method = new SimpleHttpMethod();
>+
>+ InputStream in = new ChunkedInputStream(new ByteArrayInputStream(new byte[] {}), method);
>+ byte[] buffer = new byte[300];
>+ ByteArrayOutputStream out = new ByteArrayOutputStream();
>+ int len;
>+ while ((len = in.read(buffer)) > 0) {
>+ out.write(buffer, 0, len);
>+ }
>+ assertEquals(0, out.size());
>+ }
>+
> public void testContentLengthInputStream() throws IOException {
> String correct = "1234567890123456";
> InputStream in = new ContentLengthInputStream(new ByteArrayInputStream(HttpConstants.getBytes(correct)), 10);
>
>
>
>------------------------------------------------------------------------
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org
>