Index: 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.194 diff -u -r1.194 HttpMethodBase.java --- org/apache/commons/httpclient/HttpMethodBase.java 11 Dec 2003 22:54:18 -0000 1.194 +++ org/apache/commons/httpclient/HttpMethodBase.java 12 Dec 2003 13:04:45 -0000 @@ -74,6 +74,7 @@ import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.util.EncodingUtil; +import org.apache.commons.httpclient.util.HttpParser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -1716,7 +1717,9 @@ + "HttpConnection)"); getResponseHeaderGroup().clear(); - Header[] headers = HttpParser.parseHeaders(conn.getResponseInputStream()); + + HttpParser parser = getParams().getHttpParser(); + Header[] headers = parser.parseHeaders(conn.getResponseInputStream()); if (Wire.enabled()) { for (int i = 0; i < headers.length; i++) { Wire.input(headers[i].toExternalForm()); Index: 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.7 diff -u -r1.7 HttpMethodParams.java --- org/apache/commons/httpclient/params/HttpMethodParams.java 11 Dec 2003 22:54:19 -0000 1.7 +++ org/apache/commons/httpclient/params/HttpMethodParams.java 12 Dec 2003 13:04:46 -0000 @@ -65,6 +65,8 @@ import org.apache.commons.httpclient.HttpVersion; import org.apache.commons.httpclient.cookie.CookiePolicy; +import org.apache.commons.httpclient.util.DefaultHttpParser; +import org.apache.commons.httpclient.util.HttpParser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -244,6 +246,16 @@ public static final String STATUS_LINE_GARBAGE_LIMIT = "http.protocol.status-line-garbage-limit"; /** + * Defines the HttpParser instance to be used by default. + *

+ * By default, this is {@link DefaultHttpParser}. + *

+ * + * This parameter expects a value of type {@link org.apache.commons.httpclient.util.HttpParser} + */ + public static final String HTTP_PARSER_INSTANCE = "http.parser.instance"; + + /** * Creates a new collection of parameters with the collection returned * by {@link #getDefaultParams()} as a parent. The collection will defer * to its parent for a default value if a particular parameter is not @@ -364,6 +376,19 @@ */ public void setCookiePolicy(String policy) { setParameter(COOKIE_POLICY, policy); + } + + /** + * Returns the currently used HttpParser instance. + * + * @return HttpParser instance + */ + public HttpParser getHttpParser() { + HttpParser parser = (HttpParser)getParameter(HTTP_PARSER_INSTANCE); + if(parser == null) { + parser = DefaultHttpParser.getInstance(); + } + return parser; } Index: org/apache/commons/httpclient/util/DefaultHttpParser.java =================================================================== RCS file: org/apache/commons/httpclient/util/DefaultHttpParser.java diff -N org/apache/commons/httpclient/util/DefaultHttpParser.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/apache/commons/httpclient/util/DefaultHttpParser.java 12 Dec 2003 13:04:46 -0000 @@ -0,0 +1,224 @@ +/* + * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpParser.java,v 1.8 2003/07/15 02:19:58 mbecke Exp $ + * $Revision: 1.8 $ + * $Date: 2003/07/15 02:19:58 $ + * + * ==================================================================== + * + * 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", "Commons", 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 apache@apache.org. + * + * 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 + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.apache.commons.httpclient.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpConstants; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.ProtocolException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A utility class for parsing http header values. + * + * @author Michael Becke + * @author Oleg Kalnichevski + */ +public class DefaultHttpParser implements HttpParser { + /** Singleton handling */ + private static HttpParser instance = null; + public static synchronized HttpParser getInstance() { + if(instance == null) { + instance = new DefaultHttpParser(); + } + return instance; + } + + /** Log object for this class. */ + private final Log LOG = LogFactory.getLog(DefaultHttpParser.class); + + /** + * Constructor for HttpParser. + */ + private DefaultHttpParser() { } + + /** + * Return byte array from an (unchunked) input stream. + * Stop reading when "\n" terminator encountered + * If the stream ends before the line terminator is found, + * the last part of the string will still be returned. + * If no input data available, null is returned + * + * @param inputStream the stream to read from + * + * @throws IOException if an I/O problem occurs + * @return a byte array from the stream + */ + public byte[] readRawLine(InputStream inputStream) throws IOException { + LOG.trace("enter HttpParser.readRawLine()"); + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + int ch; + while ((ch = inputStream.read()) >= 0) { + buf.write(ch); + if (ch == '\n') { + break; + } + } + if (buf.size() == 0) { + return null; + } + return buf.toByteArray(); + } + + /** + * Read up to "\n" from an (unchunked) input stream. + * If the stream ends before the line terminator is found, + * the last part of the string will still be returned. + * If no input data available, null is returned + * + * @param inputStream the stream to read from + * + * @throws IOException if an I/O problem occurs + * @return a line from the stream + */ + + public String readLine(InputStream inputStream) throws IOException { + LOG.trace("enter HttpParser.readLine()"); + byte[] rawdata = readRawLine(inputStream); + if (rawdata == null) { + return null; + } + int len = rawdata.length; + int offset = 0; + if (len > 0) { + if (rawdata[len - 1] == '\n') { + offset++; + if (len > 1) { + if (rawdata[len - 2] == '\r') { + offset++; + } + } + } + } + return HttpConstants.getString(rawdata, 0, len - offset); + } + + /** + * Parses headers from the given stream. Headers with the same name are not + * combined. + * + * @param is the stream to read headers from + * + * @return an array of headers in the order in which they were parsed + * + * @throws IOException if an IO error occurs while reading from the stream + * @throws HttpException if there is an error parsing a header value + */ + public Header[] parseHeaders(InputStream is) throws IOException, HttpException { + LOG.trace("enter HeaderParser.parseHeaders(HttpConnection, HeaderGroup)"); + + ArrayList headers = new ArrayList(); + String name = null; + StringBuffer value = null; + for (; ;) { + String line = readLine(is); + if ((line == null) || (line.length() < 1)) { + break; + } + + // Parse the header name and value + // Check for folded headers first + // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2 + // discussion on folded headers + if ((line.charAt(0) == ' ') || (line.charAt(0) == '\t')) { + // we have continuation folded header + // so append value + if (value != null) { + value.append(' '); + value.append(line.trim()); + } + } else { + // make sure we save the previous name,value pair if present + if (name != null) { + headers.add(new Header(name, value.toString())); + } + + // Otherwise we should have normal HTTP header line + // Parse the header name and value + int colon = line.indexOf(":"); + if (colon < 0) { + throw new ProtocolException("Unable to parse header: " + line); + } + name = line.substring(0, colon).trim(); + value = new StringBuffer(line.substring(colon + 1).trim()); + } + + } + + // make sure we save the last name,value pair if present + if (name != null) { + headers.add(new Header(name, value.toString())); + } + + return (Header[]) headers.toArray(new Header[headers.size()]); + } + +} Index: org/apache/commons/httpclient/util/HttpParser.java =================================================================== RCS file: org/apache/commons/httpclient/util/HttpParser.java diff -N org/apache/commons/httpclient/util/HttpParser.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/apache/commons/httpclient/util/HttpParser.java 12 Dec 2003 13:04:46 -0000 @@ -0,0 +1,59 @@ +package org.apache.commons.httpclient.util; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpException; + +/** + * An interface for utility classes for parsing http header values. + * + * @author Michael Becke + * @author Oleg Kalnichevski + * @author Christian Kohlschuetter + */ +public interface HttpParser { + /** + * Return byte array from an (unchunked) input stream. + * Stop reading when "\n" terminator encountered + * If the stream ends before the line terminator is found, + * the last part of the string will still be returned. + * If no input data available, null is returned + * + * @param inputStream the stream to read from + * + * @throws IOException if an I/O problem occurs + * @return a byte array from the stream + */ + public abstract byte[] readRawLine(InputStream inputStream) + throws IOException; + + /** + * Read up to "\n" from an (unchunked) input stream. + * If the stream ends before the line terminator is found, + * the last part of the string will still be returned. + * If no input data available, null is returned + * + * @param inputStream the stream to read from + * + * @throws IOException if an I/O problem occurs + * @return a line from the stream + */ + public abstract String readLine(InputStream inputStream) + throws IOException; + + /** + * Parses headers from the given stream. Headers with the same name are not + * combined. + * + * @param is the stream to read headers from + * + * @return an array of headers in the order in which they were parsed + * + * @throws IOException if an IO error occurs while reading from the stream + * @throws HttpException if there is an error parsing a header value + */ + public abstract Header[] parseHeaders(InputStream is) + throws IOException, HttpException; +}