olegk 2003/10/19 11:46:03
Modified: httpclient/src/java/org/apache/commons/httpclient
HttpMethodBase.java StatusLine.java
httpclient/src/test/org/apache/commons/httpclient
TestNoHost.java TestStatusLine.java
Added: httpclient/src/test/org/apache/commons/httpclient
TestHttpParser.java
Log:
HTTP status line parser changed to be more robust when dealing with non-compliant
HTTP responses (leading blanks before 'HTTP' signature)
Problem reported by Tim McCune <tmccune at hmsonline.com>
Contributed by Oleg Kalnichevski
Reviewed by Michael Becke
Revision Changes Path
1.183 +11 -11
jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java
Index: HttpMethodBase.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v
retrieving revision 1.182
retrieving revision 1.183
diff -u -r1.182 -r1.183
--- HttpMethodBase.java 13 Oct 2003 12:22:24 -0000 1.182
+++ HttpMethodBase.java 19 Oct 2003 18:46:02 -0000 1.183
@@ -1825,14 +1825,14 @@
LOG.trace("enter HttpMethodBase.readStatusLine(HttpState, HttpConnection)");
//read out the HTTP status string
- String statusString = conn.readLine();
- while ((statusString != null) && !statusString.startsWith("HTTP")) {
+ String s = conn.readLine();
+ while ((s != null) && !StatusLine.startsWithHTTP(s)) {
if (Wire.enabled()) {
- Wire.input(statusString + "\r\n");
+ Wire.input(s + "\r\n");
}
- statusString = conn.readLine();
+ s = conn.readLine();
}
- if (statusString == null) {
+ if (s == null) {
// A null statusString means the connection was lost before we got a
// response. Try again.
throw new HttpRecoverableException("Error in parsing the status "
@@ -1840,10 +1840,10 @@
+ " \"HTTP\"");
}
if (Wire.enabled()) {
- Wire.input(statusString + "\r\n");
+ Wire.input(s + "\r\n");
}
//create the status line from the status string
- statusLine = new StatusLine(statusString);
+ statusLine = new StatusLine(s);
//check for a valid HTTP-Version
String versionStr = statusLine.getHttpVersion();
1.11 +40 -17
jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/StatusLine.java
Index: StatusLine.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/StatusLine.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- StatusLine.java 15 Jul 2003 02:19:58 -0000 1.10
+++ StatusLine.java 19 Oct 2003 18:46:03 -0000 1.11
@@ -112,28 +112,31 @@
* @param statusLine the status line returned from the HTTP server
* @throws HttpException if the status line is invalid
*/
- public StatusLine(String statusLine)
- throws HttpException {
+ public StatusLine(final String statusLine) throws HttpException {
- //save the original Status-Line
- this.statusLine = new String(statusLine);
int length = statusLine.length();
-
-
- //check validity of the Status-Line
- if (!statusLine.startsWith("HTTP")) {
- throw new ProtocolException("Status-Line '" + statusLine
- + "' does not start with HTTP");
+ int at = 0;
+ int start = 0;
+ try {
+ while (Character.isWhitespace(statusLine.charAt(at))) {
+ ++at;
+ ++start;
+ }
+ if (!"HTTP".equals(statusLine.substring(at, at += 4))) {
+ throw new HttpException("Status-Line '" + statusLine
+ + "' does not start with HTTP");
+ }
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new HttpException("Status-Line '" + statusLine + "' is not
valid");
}
-
//handle the HTTP-Version
- int at = statusLine.indexOf(" ");
+ at = statusLine.indexOf(" ", at);
if (at <= 0) {
throw new ProtocolException(
"Unable to parse HTTP-Version from the status line: '"
+ statusLine + "'");
}
- this.httpVersion = (statusLine.substring(0, at)).toUpperCase();
+ this.httpVersion = (statusLine.substring(start, at)).toUpperCase();
//advance through spaces
while (statusLine.charAt(at) == ' ') {
@@ -165,6 +168,8 @@
throw new ProtocolException("Status text not specified: '"
+ statusLine + "'");
}
+ //save the original Status-Line
+ this.statusLine = new String(statusLine);
}
@@ -197,5 +202,23 @@
*/
public final String toString() {
return statusLine;
+ }
+
+ /**
+ * Tests if the string starts with 'HTTP' signature.
+ * @param s string to test
+ * @return <tt>true</tt> if the line starts with 'HTTP'
+ * signature, <tt>false</tt> otherwise.
+ */
+ public static boolean startsWithHTTP(final String s) {
+ try {
+ int at = 0;
+ while (Character.isWhitespace(s.charAt(at))) {
+ ++at;
+ }
+ return ("HTTP".equals(s.substring(at, at + 4)));
+ } catch (StringIndexOutOfBoundsException e) {
+ return false;
+ }
}
}
1.26 +5 -4
jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java
Index: TestNoHost.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- TestNoHost.java 5 Aug 2003 19:29:30 -0000 1.25
+++ TestNoHost.java 19 Oct 2003 18:46:03 -0000 1.26
@@ -107,6 +107,7 @@
suite.addTest(TestMethodCharEncoding.suite());
suite.addTest(TestExceptions.suite());
suite.addTest(TestHttpVersion.suite());
+ suite.addTest(TestHttpParser.suite());
return suite;
}
1.7 +26 -4
jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestStatusLine.java
Index: TestStatusLine.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestStatusLine.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- TestStatusLine.java 7 Feb 2003 04:50:03 -0000 1.6
+++ TestStatusLine.java 19 Oct 2003 18:46:03 -0000 1.7
@@ -96,6 +96,16 @@
// ----------------------------------------------------------- Test Methods
+ public void testIfStatusLine() throws Exception {
+ assertTrue(StatusLine.startsWithHTTP("HTTP"));
+ assertTrue(StatusLine.startsWithHTTP(" HTTP"));
+ assertTrue(StatusLine.startsWithHTTP("\rHTTP"));
+ assertTrue(StatusLine.startsWithHTTP("\tHTTP"));
+ assertFalse(StatusLine.startsWithHTTP("crap"));
+ assertFalse(StatusLine.startsWithHTTP("HTT"));
+ assertFalse(StatusLine.startsWithHTTP("http"));
+ }
+
public void testSuccess() throws Exception {
//typical status line
statusLine = new StatusLine("HTTP/1.1 200 OK");
@@ -131,6 +141,18 @@
statusLine = new StatusLine("HTTP/1.1 200 OK");
assertEquals(200, statusLine.getStatusCode());
assertEquals("OK", statusLine.getReasonPhrase());
+
+ //this is not strictly valid, but is lienent
+ statusLine = new StatusLine("\rHTTP/1.1 200 OK");
+ assertEquals(200, statusLine.getStatusCode());
+ assertEquals("OK", statusLine.getReasonPhrase());
+ assertEquals("HTTP/1.1", statusLine.getHttpVersion());
+
+ //this is not strictly valid, but is lienent
+ statusLine = new StatusLine(" HTTP/1.1 200 OK");
+ assertEquals(200, statusLine.getStatusCode());
+ assertEquals("OK", statusLine.getReasonPhrase());
+ assertEquals("HTTP/1.1", statusLine.getHttpVersion());
}
public void testFailure() throws Exception {
1.1
jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpParser.java
Index: TestHttpParser.java
===================================================================
/*
* $Header:
/home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpParser.java,v
1.1 2003/10/19 18:46:03 olegk Exp $
* $Revision: 1.1 $
* $Date: 2003/10/19 18:46:03 $
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.commons.httpclient;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import junit.framework.*;
/**
* Simple tests for [EMAIL PROTECTED] HttpParser}.
*
* @author Oleg Kalnichevski
* @version $Id: TestHttpParser.java,v 1.1 2003/10/19 18:46:03 olegk Exp $
*/
public class TestHttpParser extends TestCase {
// ------------------------------------------------------------ Constructor
public TestHttpParser(String testName) {
super(testName);
}
// ------------------------------------------------------------------- Main
public static void main(String args[]) {
String[] testCaseName = { TestHeader.class.getName() };
junit.textui.TestRunner.main(testCaseName);
}
// ------------------------------------------------------- TestCase Methods
public static Test suite() {
return new TestSuite(TestHttpParser.class);
}
public void testReadHttpLine() throws Exception {
InputStream instream = new ByteArrayInputStream(
"\r\r\nstuff\r\n".getBytes("US-ASCII"));
assertEquals("\r", HttpParser.readLine(instream));
assertEquals("stuff", HttpParser.readLine(instream));
assertEquals(null, HttpParser.readLine(instream));
instream = new ByteArrayInputStream(
"\n\r\nstuff\r\n".getBytes("US-ASCII"));
assertEquals("", HttpParser.readLine(instream));
assertEquals("", HttpParser.readLine(instream));
assertEquals("stuff", HttpParser.readLine(instream));
assertEquals(null, HttpParser.readLine(instream));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]