Index: module-main/src/main/java/org/apache/http/message/HeaderValueParser.java
===================================================================
--- module-main/src/main/java/org/apache/http/message/HeaderValueParser.java (revision 0)
+++ module-main/src/main/java/org/apache/http/message/HeaderValueParser.java (revision 0)
@@ -0,0 +1,182 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * 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
+ *
+ * Some HTTP headers (such as the set-cookie header) have values that + * can be decomposed into multiple elements. In order to be processed + * by this parser, such headers must be in the following form: + *
+ *+ * header = [ element ] *( "," [ element ] ) + * element = name [ "=" [ value ] ] *( ";" [ param ] ) + * param = name [ "=" [ value ] ] + * + * name = token + * value = ( token | quoted-string ) + * + * token = 1*<any char except "=", ",", ";", <"> and + * white space> + * quoted-string = <"> *( text | quoted-char ) <"> + * text = any char except <"> + * quoted-char = "\" char + *+ *
+ * Any amount of white space is allowed between any part of the + * header, element or param and is ignored. A missing value in any + * element or param will be stored as the empty {@link String}; + * if the "=" is also missing null will be stored instead. + *
+ * + * @param buffer buffer holding the header value to parse + * + * @return an array holding all elements of the header value + * + * @throws RuntimeException + * in case of invalid arguments or a parse error + */ + public HeaderElement[] parseElements(final CharArrayBuffer buffer, + final int indexFrom, + final int indexTo) + throws RuntimeException + ; + + + /** + * Parses a list of name-value pairs. + * These lists are used to specify parameters to a header element. + *+ * This method comforms to the generic grammar and formatting rules + * outlined in the + * Section 2.2 + * and + * Section 3.6 + * of + * RFC 2616. + *
+ *+ * The following rules are used throughout this specification to + * describe basic parsing constructs. + * The US-ASCII coded character set is defined by ANSI X3.4-1986. + *
+ *+ * OCTET =+ *+ * CHAR = + * UPALPHA = + * LOALPHA = + * ALPHA = UPALPHA | LOALPHA + * DIGIT = + * CTL = + * CR = + * LF = + * SP = + * HT = + * <"> = + *
+ * Many HTTP/1.1 header field values consist of words separated + * by LWS or special characters. These special characters MUST be + * in a quoted string to be used within + * a parameter value (as defined in section 3.6). + *
+ *
+ * token = 1*+ *+ * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + *
+ * A string of text is parsed as a single word if it is quoted using + * double-quote marks. + *
+ *+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) + * qdtext =+ *> + *
+ * The backslash character ("\") MAY be used as a single-character + * quoting mechanism only within quoted-string and comment constructs. + *
+ *+ * quoted-pair = "\" CHAR + *+ *
+ * Parameters are in the form of attribute/value pairs. + *
+ *+ * parameter = attribute "=" value + * attribute = token + * value = token | quoted-string + *+ * + * @param buffer buffer holding the name-value list to parse + * + * @return an array holding all items of the name-value list + * + * @throws RuntimeException + * in case of invalid arguments or a parse error + */ + public NameValuePair[] parseParameters(final CharArrayBuffer buffer, + final int indexFrom, + final int indexTo) + throws RuntimeException + ; + +} + Property changes on: module-main/src/main/java/org/apache/http/message/HeaderValueParser.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Date Author Id Revision HeadURL Name: svn:eol-style + native Index: module-main/src/main/java/org/apache/http/message/LineParser.java =================================================================== --- module-main/src/main/java/org/apache/http/message/LineParser.java (revision 0) +++ module-main/src/main/java/org/apache/http/message/LineParser.java (revision 0) @@ -0,0 +1,130 @@ +/* + * $HeadURL$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * 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 + *
null
+ * if no value is specified
+ */
+ protected NameValuePair parseNameValuePair(final CharArrayBuffer buffer,
+ final int indexFrom,
+ final int indexTo) {
+ if (buffer == null) {
+ throw new IllegalArgumentException
+ ("Char array buffer may not be null");
+ }
+ if (indexFrom < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (indexTo > buffer.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (indexFrom > indexTo) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ int eq = buffer.indexOf('=', indexFrom, indexTo);
+ if (eq < 0) {
+ return createNameValuePair(buffer.substringTrimmed(indexFrom, indexTo), null);
+ }
+ String name = buffer.substringTrimmed(indexFrom, eq);
+ int i1 = eq + 1;
+ int i2 = indexTo;
+ // Trim leading white spaces
+ while (i1 < i2 && (HTTP.isWhitespace(buffer.charAt(i1)))) {
+ i1++;
+ }
+ // Trim trailing white spaces
+ while ((i2 > i1) && (HTTP.isWhitespace(buffer.charAt(i2 - 1)))) {
+ i2--;
+ }
+ // Strip away quotes if necessary
+ if (((i2 - i1) >= 2)
+ && (buffer.charAt(i1) == '"')
+ && (buffer.charAt(i2 - 1) == '"')) {
+ i1++;
+ i2--;
+ }
+ String value = buffer.substring(i1, i2);
+ return createNameValuePair(name, value);
+ }
+
+
+ /**
+ * Creates a name-value pair.
+ * Called from {@link #parseNameValuePair}.
+ *
+ * @param name the name
+ * @param value the value, or null
+ *
+ * @return a name-value pair representing the arguments
+ */
+ protected NameValuePair createNameValuePair(String name, String value) {
+ return new BasicNameValuePair(name, value);
+ }
+
+
+}
+
Property changes on: module-main/src/main/java/org/apache/http/message/BasicHeaderValueParser.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Date Author Id Revision HeadURL
Name: svn:eol-style
+ native
Index: module-main/src/main/java/org/apache/http/message/BasicHeaderElement.java
===================================================================
--- module-main/src/main/java/org/apache/http/message/BasicHeaderElement.java (revision 567629)
+++ module-main/src/main/java/org/apache/http/message/BasicHeaderElement.java (working copy)
@@ -93,7 +93,7 @@
private final String value;
private final NameValuePair[] parameters;
- private BasicHeaderElement(final NameValuePair[] nvps) {
+ public BasicHeaderElement(final NameValuePair[] nvps) {
super();
if (nvps.length > 0) {
NameValuePair nvp = nvps[0];
Index: module-main/src/main/java/org/apache/http/message/BasicLineParser.java
===================================================================
--- module-main/src/main/java/org/apache/http/message/BasicLineParser.java (revision 0)
+++ module-main/src/main/java/org/apache/http/message/BasicLineParser.java (revision 0)
@@ -0,0 +1,346 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * 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
+ * + * Note: This class was created by refactoring parsing code located in + * various other classes. The author tags from those other classes have + * been replicated here, although the association with the parsing code + * taken from there has not been traced. + *
+ * + * @author Jeff Dever + * @author Mike Bowler + * @author Oleg Kalnichevski + * @author and others + */ +public class BasicLineParser implements LineParser { + + /** + * A default instance of this class, for use as default or fallback. + * Note that {@link BasicLineParser} is not a singleton, there can + * be many instances of the class itself and of derived classes. + * The instance here provides non-customized, default behavior. + */ + public final static BasicLineParser DEFAULT = new BasicLineParser(); + + + + // public default constructor + + + // non-javadoc, see interface LineParser + public HttpVersion parseProtocolVersion(final CharArrayBuffer buffer, + final int indexFrom, + final int indexTo) + throws ProtocolException { + + if (buffer == null) { + throw new IllegalArgumentException + ("Char array buffer may not be null"); + } + if (indexFrom < 0) { + throw new IndexOutOfBoundsException(); + } + if (indexTo > buffer.length()) { + throw new IndexOutOfBoundsException(); + } + if (indexFrom > indexTo) { + throw new IndexOutOfBoundsException(); + } + try { + int major, minor; + + int i = indexFrom; + while (HTTP.isWhitespace(buffer.charAt(i))) { + i++; + } + if (buffer.charAt(i ) != 'H' + || buffer.charAt(i + 1) != 'T' + || buffer.charAt(i + 2) != 'T' + || buffer.charAt(i + 3) != 'P' + || buffer.charAt(i + 4) != '/') { + throw new ProtocolException("Not a valid HTTP version string: " + + buffer.substring(indexFrom, indexTo)); + } + i += 5; + int period = buffer.indexOf('.', i, indexTo); + if (period == -1) { + throw new ProtocolException("Invalid HTTP version number: " + + buffer.substring(indexFrom, indexTo)); + } + try { + major = Integer.parseInt(buffer.substringTrimmed(i, period)); + } catch (NumberFormatException e) { + throw new ProtocolException("Invalid HTTP major version number: " + + buffer.substring(indexFrom, indexTo)); + } + try { + minor = Integer.parseInt(buffer.substringTrimmed(period + 1, indexTo)); + } catch (NumberFormatException e) { + throw new ProtocolException("Invalid HTTP minor version number: " + + buffer.substring(indexFrom, indexTo)); + } + return createProtocolVersion(major, minor); + + } catch (IndexOutOfBoundsException e) { + throw new ProtocolException("Invalid HTTP version string: " + + buffer.substring(indexFrom, indexTo)); + } + } // parseProtocolVersion + + + /** + * Creates a protocol version. + * Called from {@link #parseProtocolVersion}. + * + * @param major the major version number, for example 1 in HTTP/1.0 + * @param minor the minor version number, for example 0 in HTTP/1.0 + * + * @return the protocol version + */ + protected HttpVersion createProtocolVersion(int major, int minor) { + return new HttpVersion(major, minor); + } + + + /** + * Parses a request line. + * + * @param buffer a buffer holding the line to parse + * + * @return the parsed request line + * + * @throws ProtocolException in case of a parse error + */ + public RequestLine parseRequestLine(final CharArrayBuffer buffer, + final int indexFrom, + final int indexTo) + throws ProtocolException { + + if (buffer == null) { + throw new IllegalArgumentException + ("Char array buffer may not be null"); + } + if (indexFrom < 0) { + throw new IndexOutOfBoundsException(); + } + if (indexTo > buffer.length()) { + throw new IndexOutOfBoundsException(); + } + if (indexFrom > indexTo) { + throw new IndexOutOfBoundsException(); + } + + try { + int i = indexFrom; + while (HTTP.isWhitespace(buffer.charAt(i))) { + i++; + } + int blank = buffer.indexOf(' ', i, indexTo); + if (blank < 0) { + throw new ProtocolException("Invalid request line: " + + buffer.substring(indexFrom, indexTo)); + } + String method = buffer.substringTrimmed(i, blank); + i = blank; + while (HTTP.isWhitespace(buffer.charAt(i))) { + i++; + } + blank = buffer.indexOf(' ', i, indexTo); + if (blank < 0) { + throw new ProtocolException("Invalid request line: " + + buffer.substring(indexFrom, indexTo)); + } + String uri = buffer.substringTrimmed(i, blank); + HttpVersion ver = parseProtocolVersion(buffer, blank, indexTo); + return createRequestLine(method, uri, ver); + } catch (IndexOutOfBoundsException e) { + throw new ProtocolException("Invalid request line: " + + buffer.substring(indexFrom, indexTo)); + } + } // parseRequestLine + + + /** + * Instantiates a new request line. + * Called from {@link #parseRequestLine}. + * + * @param method the request method + * @param uri the requested URI + * @param ver the protocol version + * + * @return a new status line with the given data + */ + protected RequestLine createRequestLine(String method, + String uri, + HttpVersion ver) { + return new BasicRequestLine(method, uri, ver); + } + + + // non-javadoc, see interface LineParser + public StatusLine parseStatusLine(final CharArrayBuffer buffer, + final int indexFrom, + final int indexTo) + throws ProtocolException { + + if (buffer == null) { + throw new IllegalArgumentException + ("Char array buffer may not be null"); + } + if (indexFrom < 0) { + throw new IndexOutOfBoundsException(); + } + if (indexTo > buffer.length()) { + throw new IndexOutOfBoundsException(); + } + if (indexFrom > indexTo) { + throw new IndexOutOfBoundsException(); + } + + try { + int i = indexFrom; + //handle the HTTP-Version + while (HTTP.isWhitespace(buffer.charAt(i))) { + i++; + } + int blank = buffer.indexOf(' ', i, indexTo); + if (blank <= 0) { + throw new ProtocolException( + "Unable to parse HTTP-Version from the status line: " + + buffer.substring(indexFrom, indexTo)); + } + HttpVersion ver = parseProtocolVersion(buffer, i, blank); + + i = blank; + //advance through spaces + while (HTTP.isWhitespace(buffer.charAt(i))) { + i++; + } + + //handle the Status-Code + blank = buffer.indexOf(' ', i, indexTo); + if (blank < 0) { + blank = indexTo; + } + int statusCode = 0; + try { + statusCode = + Integer.parseInt(buffer.substringTrimmed(i, blank)); + } catch (NumberFormatException e) { + throw new ProtocolException( + "Unable to parse status code from status line: " + + buffer.substring(indexFrom, indexTo)); + } + //handle the Reason-Phrase + i = blank; + String reasonPhrase = null; + if (i < indexTo) { + reasonPhrase = buffer.substringTrimmed(i, indexTo); + } else { + reasonPhrase = ""; + } + return createStatusLine(ver, statusCode, reasonPhrase); + + } catch (IndexOutOfBoundsException e) { + throw new ProtocolException("Invalid status line: " + + buffer.substring(indexFrom, indexTo)); + } + } // parseStatusLine + + + /** + * Instantiates a new status line. + * Called from {@link #parseStatusLine}. + * + * @param ver the protocol version + * @param status the status code + * @param reason the reason phrase + * + * @return a new status line with the given data + */ + protected StatusLine createStatusLine(HttpVersion ver, + int status, String reason) { + return new BasicStatusLine(ver, status, reason); + } + + + // non-javadoc, see interface LineParser + public Header parseHeader(CharArrayBuffer buffer) + throws ProtocolException { + + Header result = null; + try { + // the actual parser code is in the constructor of BufferedHeader + result = new BufferedHeader(buffer, getHeaderValueParser()); + } catch (IllegalArgumentException iax) { + throw new ProtocolException(iax.getMessage(), iax); + } + return result; + } + + + /** + * Obtains the header value parser to use. + * Called by {@link #parseHeader}. + * + * @return the header value parser, or + *null for the default
+ */
+ protected HeaderValueParser getHeaderValueParser() {
+ return null;
+ }
+
+
+} // class BasicLineParser
Property changes on: module-main/src/main/java/org/apache/http/message/BasicLineParser.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:keywords
+ Date Author Id Revision HeadURL
Name: svn:eol-style
+ native
Index: module-main/src/main/java/org/apache/http/message/BufferedHeader.java
===================================================================
--- module-main/src/main/java/org/apache/http/message/BufferedHeader.java (revision 567629)
+++ module-main/src/main/java/org/apache/http/message/BufferedHeader.java (working copy)
@@ -62,15 +62,22 @@
*/
private final int valuePos;
+ /**
+ * The parser for the header value, or null.
+ */
+ private HeaderValueParser parser;
+
/**
* Creates a new header from a buffer.
* The name of the header will be parsed immediately,
* the value only if it is accessed.
*
* @param buffer the buffer containing the header to represent
+ * @param parser the header value parser, or null
*/
- public BufferedHeader(final CharArrayBuffer buffer) {
+ public BufferedHeader(final CharArrayBuffer buffer,
+ final HeaderValueParser parser) {
super();
if (buffer == null) {
throw new IllegalArgumentException("Char array buffer may not be null");
@@ -86,8 +93,14 @@
this.buffer = buffer;
this.name = s;
this.valuePos = colon + 1;
+ this.parser = parser;
}
+ public BufferedHeader(final CharArrayBuffer buffer) {
+ this(buffer, null);
+ }
+
+
public String getName() {
return this.name;
}
@@ -97,7 +110,11 @@
}
public HeaderElement[] getElements() {
- return BasicHeaderElement.parseAll(this.buffer, this.valuePos, this.buffer.length());
+ HeaderValueParser hvp = this.parser;
+ if (hvp == null)
+ hvp = BasicHeaderValueParser.DEFAULT;
+ return hvp.parseElements(this.buffer,
+ this.valuePos, this.buffer.length());
}
public int getValuePos() {
Index: module-main/src/main/java/org/apache/http/impl/io/HttpRequestParser.java
===================================================================
--- module-main/src/main/java/org/apache/http/impl/io/HttpRequestParser.java (revision 567629)
+++ module-main/src/main/java/org/apache/http/impl/io/HttpRequestParser.java (working copy)
@@ -67,7 +67,7 @@
if (i == -1) {
throw new ConnectionClosedException("Client closed connection");
}
- RequestLine requestline = BasicRequestLine.parse(this.lineBuf, 0, this.lineBuf.length());
+ RequestLine requestline = lineParser.parseRequestLine(this.lineBuf, 0, this.lineBuf.length());
return this.requestFactory.newHttpRequest(requestline);
}
Index: module-main/src/main/java/org/apache/http/impl/io/HttpResponseParser.java
===================================================================
--- module-main/src/main/java/org/apache/http/impl/io/HttpResponseParser.java (revision 567629)
+++ module-main/src/main/java/org/apache/http/impl/io/HttpResponseParser.java (working copy)
@@ -68,7 +68,7 @@
throw new NoHttpResponseException("The target server failed to respond");
}
//create the status line from the status string
- StatusLine statusline = BasicStatusLine.parse(this.lineBuf, 0, this.lineBuf.length());
+ StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, 0, this.lineBuf.length());
return this.responseFactory.newHttpResponse(statusline, null);
}
Index: module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java
===================================================================
--- module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java (revision 567629)
+++ module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java (working copy)
@@ -41,6 +41,8 @@
import org.apache.http.io.HttpMessageParser;
import org.apache.http.io.SessionInputBuffer;
import org.apache.http.message.BufferedHeader;
+import org.apache.http.message.LineParser;
+import org.apache.http.message.BasicLineParser;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.CharArrayBuffer;
@@ -56,7 +58,9 @@
private final SessionInputBuffer sessionBuffer;
private final int maxHeaderCount;
private final int maxLineLen;
+ protected final LineParser lineParser;
+
public AbstractMessageParser(
final SessionInputBuffer buffer,
final HttpParams params) {
@@ -72,6 +76,7 @@
HttpConnectionParams.MAX_HEADER_COUNT, -1);
this.maxLineLen = params.getIntParameter(
HttpConnectionParams.MAX_LINE_LENGTH, -1);
+ this.lineParser = BasicLineParser.DEFAULT; //@@@ allow as argument
}
/**
@@ -93,10 +98,16 @@
public static Header[] parseHeaders(
final SessionInputBuffer inbuffer,
int maxHeaderCount,
- int maxLineLen) throws HttpException, IOException {
+ int maxLineLen,
+ LineParser parser)
+ throws HttpException, IOException {
+
if (inbuffer == null) {
throw new IllegalArgumentException("Session input buffer may not be null");
}
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
ArrayList headerLines = new ArrayList();
CharArrayBuffer current = null;
@@ -145,7 +156,7 @@
for (int i = 0; i < headerLines.size(); i++) {
CharArrayBuffer buffer = (CharArrayBuffer) headerLines.get(i);
try {
- headers[i] = new BufferedHeader(buffer);
+ headers[i] = parser.parseHeader(buffer);
} catch (IllegalArgumentException ex) {
throw new ProtocolException(ex.getMessage());
}
@@ -153,9 +164,16 @@
return headers;
}
+ public static Header[] parseHeaders(
+ final SessionInputBuffer inbuffer,
+ int maxHeaderCount,
+ int maxLineLen) throws HttpException, IOException {
+ return parseHeaders(inbuffer, maxHeaderCount, maxLineLen, null);
+ }
+
public static Header[] parseHeaders(final SessionInputBuffer inbuffer)
throws HttpException, IOException {
- return parseHeaders(inbuffer, -1, -1);
+ return parseHeaders(inbuffer, -1, -1, null);
}
protected abstract HttpMessage parseHead(SessionInputBuffer sessionBuffer)
@@ -166,7 +184,8 @@
Header[] headers = AbstractMessageParser.parseHeaders(
this.sessionBuffer,
this.maxHeaderCount,
- this.maxLineLen);
+ this.maxLineLen,
+ this.lineParser);
message.setHeaders(headers);
return message;
}