Index: /home/oleg/src/apache.org/jakarta-commons/httpclient-trunk/src/test/org/apache/commons/httpclient/TestNoncompliant.java =================================================================== --- /home/oleg/src/apache.org/jakarta-commons/httpclient-trunk/src/test/org/apache/commons/httpclient/TestNoncompliant.java (revision 160095) +++ /home/oleg/src/apache.org/jakarta-commons/httpclient-trunk/src/test/org/apache/commons/httpclient/TestNoncompliant.java (working copy) @@ -54,12 +54,12 @@ } /** - * Tests if client is able able to recover gracefully when HTTP server or + * Tests if client is able to recover gracefully when HTTP server or * proxy fails to send 100 status code when expected. The client should * resume sending the request body after a defined timeout without having * received "continue" code. */ - public void testNoncompliantPostMethodString() { + public void testNoncompliantPostMethodString() throws Exception { this.server.setRequestHandler(new HttpRequestHandler() { public boolean processRequest(SimpleHttpServerConnection conn, SimpleRequest request) throws IOException { @@ -78,12 +78,7 @@ HttpMethodParams.USE_EXPECT_CONTINUE, true); method.setRequestEntity(new StringRequestEntity( "This is data to be sent in the body of an HTTP POST.")); - try { - client.executeMethod(method); - } catch (Exception e) { - e.printStackTrace(); - fail("Unexpected exception: " + e.toString()); - } + client.executeMethod(method); assertEquals(200, method.getStatusCode()); } @@ -175,4 +170,54 @@ method.releaseConnection(); } + /** + * Tests if client is able to handle gracefully malformed responses + * that may not include response body. + */ + public void testMalformed304Response() throws Exception { + this.server.setRequestHandler(new HttpRequestHandler() { + public boolean processRequest(SimpleHttpServerConnection conn, + SimpleRequest request) throws IOException { + ResponseWriter out = conn.getWriter(); + out.println("HTTP/1.1 304 OK"); + out.println("Connection: keep-alive"); + out.println("Content-Length: 100"); + out.println(); + out.flush(); + conn.setKeepAlive(true); + conn.setSocketTimeout(20000); + return true; + } + }); + + GetMethod method = new GetMethod("/"); + method.getParams().setSoTimeout(1000); + client.executeMethod(method); + assertEquals(HttpStatus.SC_NOT_MODIFIED, method.getStatusCode()); + method.getResponseBody(); + } + + public void testMalformed204Response() throws Exception { + this.server.setRequestHandler(new HttpRequestHandler() { + public boolean processRequest(SimpleHttpServerConnection conn, + SimpleRequest request) throws IOException { + ResponseWriter out = conn.getWriter(); + out.println("HTTP/1.1 204 OK"); + out.println("Connection: close"); + out.println("Content-Length: 100"); + out.println(); + out.flush(); + conn.setKeepAlive(true); + conn.setSocketTimeout(20000); + return true; + } + }); + + GetMethod method = new GetMethod("/"); + method.getParams().setSoTimeout(1000); + client.executeMethod(method); + assertEquals(HttpStatus.SC_NO_CONTENT, method.getStatusCode()); + method.getResponseBody(); + } + } \ No newline at end of file Index: /home/oleg/src/apache.org/jakarta-commons/httpclient-trunk/src/java/org/apache/commons/httpclient/HttpMethodBase.java =================================================================== --- /home/oleg/src/apache.org/jakarta-commons/httpclient-trunk/src/java/org/apache/commons/httpclient/HttpMethodBase.java (revision 160095) +++ /home/oleg/src/apache.org/jakarta-commons/httpclient-trunk/src/java/org/apache/commons/httpclient/HttpMethodBase.java (working copy) @@ -1716,23 +1716,26 @@ } else { long expectedLength = getResponseContentLength(); if (expectedLength == -1) { - if (canResponseHaveBody(statusLine.getStatusCode())) { - Header connectionHeader = responseHeaders.getFirstHeader("Connection"); - String connectionDirective = null; - if (connectionHeader != null) { - connectionDirective = connectionHeader.getValue(); - } - if (this.effectiveVersion.greaterEquals(HttpVersion.HTTP_1_1) && - !"close".equalsIgnoreCase(connectionDirective)) { - LOG.info("Response content length is not known"); - setConnectionCloseForced(true); - } - result = is; + Header connectionHeader = responseHeaders.getFirstHeader("Connection"); + String connectionDirective = null; + if (connectionHeader != null) { + connectionDirective = connectionHeader.getValue(); } + if (this.effectiveVersion.greaterEquals(HttpVersion.HTTP_1_1) && + !"close".equalsIgnoreCase(connectionDirective)) { + LOG.info("Response content length is not known"); + setConnectionCloseForced(true); + } + result = is; } else { result = new ContentLengthInputStream(is, expectedLength); } } + + // See if the response is supposed to have a response body + if (!canResponseHaveBody(statusLine.getStatusCode())) { + result = null; + } // if there is a result - ALWAYS wrap it in an observer which will // close the underlying stream as soon as it is consumed, and notify // the watcher that the stream has been consumed.