Index: java/org/apache/commons/httpclient/HttpMethodBase.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v retrieving revision 1.190 diff -u -r1.190 HttpMethodBase.java --- java/org/apache/commons/httpclient/HttpMethodBase.java 13 Nov 2003 22:24:46 -0000 1.190 +++ java/org/apache/commons/httpclient/HttpMethodBase.java 13 Nov 2003 22:31:16 -0000 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v 1.190 2003/11/13 22:24:46 olegk Exp $ + * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v 1.190 2003/11/13 22:24:46 olegk Exp $ * $Revision: 1.190 $ * $Date: 2003/11/13 22:24:46 $ * @@ -122,6 +122,7 @@ * @author Oleg Kalnichevski * @author Mike Bowler * @author Gary Gregory + * @author Christian Kohlschuetter * * @version $Revision: 1.190 $ $Date: 2003/11/13 22:24:46 $ */ @@ -886,7 +887,6 @@ LOG.debug("Should force-close connection."); return true; } - Header connectionHeader = null; // In case being connected via a proxy server if (!conn.isTransparent()) { @@ -1838,13 +1838,37 @@ throws IOException, HttpRecoverableException, HttpException { LOG.trace("enter HttpMethodBase.readStatusLine(HttpState, HttpConnection)"); - //read out the HTTP status string - String s = conn.readLine(); - while ((s != null) && !StatusLine.startsWithHTTP(s)) { + final int maxGarbageLines = getParams(). + getIntParameter(HttpMethodParams.STATUS_LINE_GARBAGE_LIMIT, -1); + + // Skip all blank lines first + String s = null; + while ((s = conn.readLine()) != null) { if (Wire.enabled()) { Wire.input(s + "\r\n"); } + if (s.trim().length() > 0) { + break; + } + } + + //read out the HTTP status string + int count = 0; + while (s != null) { + if (StatusLine.startsWithHTTP(s)) { + // Got one + break; + } + if ((maxGarbageLines >= 0) && (count >= maxGarbageLines)) { + // Giving up + s = null; + break; + } s = conn.readLine(); + if (Wire.enabled()) { + Wire.input(s + "\r\n"); + } + count++; } if (s == null) { // A null statusString means the connection was lost before we got a @@ -1853,9 +1877,7 @@ + " line from the response: unable to find line starting with" + " \"HTTP\""); } - if (Wire.enabled()) { - Wire.input(s + "\r\n"); - } + //create the status line from the status string statusLine = new StatusLine(s); @@ -2250,6 +2272,23 @@ if (responseConnection != null) { responseConnection.setLastResponseInputStream(null); + // At this point, no response data should be available. + // If there is data available, assume a protocol violation and + // close the connection + boolean testExtraInput = getParams(). + isParameterTrue(HttpMethodParams.TEST_EXTRA_INPUT); + if (testExtraInput) { + try { + if (responseConnection.isResponseAvailable()) { + LOG.warn("Extra response data detected"); + setConnectionCloseForced(true); + } + } + catch (IOException e) { + LOG.error("Unexpected I/O error when testing for extra response data", e); + setConnectionCloseForced(true); + } + } if (shouldCloseConnection(responseConnection)) { responseConnection.close(); } Index: java/org/apache/commons/httpclient/params/HttpMethodParams.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/params/HttpMethodParams.java,v retrieving revision 1.5 diff -u -r1.5 HttpMethodParams.java --- java/org/apache/commons/httpclient/params/HttpMethodParams.java 22 Oct 2003 19:31:00 -0000 1.5 +++ java/org/apache/commons/httpclient/params/HttpMethodParams.java 13 Nov 2003 22:31:19 -0000 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/params/HttpMethodParams.java,v 1.5 2003/10/22 19:31:00 olegk Exp $ + * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/params/HttpMethodParams.java,v 1.5 2003/10/22 19:31:00 olegk Exp $ * $Revision: 1.5 $ * $Date: 2003/10/22 19:31:00 $ * @@ -76,6 +76,7 @@ * its value will be drawn from the parent collection of parameters. * * @author Oleg Kalnichevski + * @author Christian Kohlschuetter * * @version $Revision: 1.5 $ */ @@ -184,7 +185,41 @@ * This parameter expects a value of type {@link String}. *

*/ - public static final String COOKIE_POLICY = "http.protocol.cookie-policy"; + public static final String COOKIE_POLICY = "http.protocol.cookie-policy"; + + /** + * Defines HttpClient's behavior when a response provides more bytes than + * expected (specified with Content-Length, for example). + *

+ * Such surplus data makes the HTTP connection unreliable for keep-alive + * requests, as malicious response data (faked headers etc.) can lead to undesired + * results on the next request using that connection. + *

+ *

+ * This parameter expects a value of type {@link Boolean}. + *

+ */ + public static final String TEST_EXTRA_INPUT = "http.protocol.test-extra-input"; + + /** + * Defines the maximum number of ignorable lines before we expect + * a HTTP response's status code. + *

+ * With HTTP/1.1 persistent connections, the problem arises that + * broken scripts could return a wrong Content-Length + * (there are more bytes sent than specified).
+ * Unfortunately, in some cases, this is not possible after the bad response, + * but only before the next one.
+ * So, HttpClient must be able to skip those surplus lines this way. + *

+ *

+ * Set this to 0 to disallow any garbage lines before the status line.
+ * To specify no limit, use {@link Integer.MAX_VALUE}. + *

+ * + * This parameter expects a value of type {@link Integer}. + */ + public static final String STATUS_LINE_GARBAGE_LIMIT = "http.protocol.status-line-garbage-limit"; /** * Creates a new collection of parameters with the collection returned @@ -271,7 +306,8 @@ UNAMBIGUOUS_STATUS_LINE, SINGLE_COOKIE_HEADER, STRICT_TRANSFER_ENCODING, - REJECT_HEAD_BODY + REJECT_HEAD_BODY, + TEST_EXTRA_INPUT }; /** @@ -283,6 +319,7 @@ */ public void makeStrict() { setParameters(PROTOCOL_STRICTNESS_PARAMETERS, new Boolean(true)); + setIntParameter(STATUS_LINE_GARBAGE_LIMIT, 0); } /** @@ -293,6 +330,7 @@ */ public void makeLenient() { setParameters(PROTOCOL_STRICTNESS_PARAMETERS, new Boolean(false)); + setIntParameter(STATUS_LINE_GARBAGE_LIMIT, -1); } }