summaryrefslogtreecommitdiffstats
path: root/src/org/apache/http/message
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit417f3b92ba4549b2f22340e3107d869d2b9c5bb8 (patch)
tree2e08a2a91d6d14995df54490e3667f7943fbc6d6 /src/org/apache/http/message
downloadexternal_apache-http-417f3b92ba4549b2f22340e3107d869d2b9c5bb8.zip
external_apache-http-417f3b92ba4549b2f22340e3107d869d2b9c5bb8.tar.gz
external_apache-http-417f3b92ba4549b2f22340e3107d869d2b9c5bb8.tar.bz2
Initial Contribution
Diffstat (limited to 'src/org/apache/http/message')
-rw-r--r--src/org/apache/http/message/AbstractHttpMessage.java166
-rw-r--r--src/org/apache/http/message/BasicHeader.java143
-rw-r--r--src/org/apache/http/message/BasicHeaderElement.java243
-rw-r--r--src/org/apache/http/message/BasicHeaderElementIterator.java161
-rw-r--r--src/org/apache/http/message/BasicHeaderIterator.java180
-rw-r--r--src/org/apache/http/message/BasicHeaderValueFormatter.java441
-rw-r--r--src/org/apache/http/message/BasicHeaderValueParser.java420
-rw-r--r--src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java81
-rw-r--r--src/org/apache/http/message/BasicHttpRequest.java98
-rw-r--r--src/org/apache/http/message/BasicHttpResponse.java204
-rw-r--r--src/org/apache/http/message/BasicLineFormatter.java346
-rw-r--r--src/org/apache/http/message/BasicLineParser.java504
-rw-r--r--src/org/apache/http/message/BasicListHeaderIterator.java196
-rw-r--r--src/org/apache/http/message/BasicNameValuePair.java189
-rw-r--r--src/org/apache/http/message/BasicRequestLine.java99
-rw-r--r--src/org/apache/http/message/BasicStatusLine.java124
-rw-r--r--src/org/apache/http/message/BasicTokenIterator.java429
-rw-r--r--src/org/apache/http/message/BufferedHeader.java133
-rw-r--r--src/org/apache/http/message/HeaderGroup.java295
-rw-r--r--src/org/apache/http/message/HeaderValueFormatter.java141
-rw-r--r--src/org/apache/http/message/HeaderValueParser.java214
-rw-r--r--src/org/apache/http/message/LineFormatter.java153
-rw-r--r--src/org/apache/http/message/LineParser.java156
-rw-r--r--src/org/apache/http/message/ParserCursor.java102
-rw-r--r--src/org/apache/http/message/package.html49
25 files changed, 5267 insertions, 0 deletions
diff --git a/src/org/apache/http/message/AbstractHttpMessage.java b/src/org/apache/http/message/AbstractHttpMessage.java
new file mode 100644
index 0000000..d8a6962
--- /dev/null
+++ b/src/org/apache/http/message/AbstractHttpMessage.java
@@ -0,0 +1,166 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/AbstractHttpMessage.java $
+ * $Revision: 620287 $
+ * $Date: 2008-02-10 07:15:53 -0800 (Sun, 10 Feb 2008) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.Iterator;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpMessage;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.BasicHttpParams;
+
+/**
+ * Basic implementation of an HTTP message that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 620287 $
+ *
+ * @since 4.0
+ */
+public abstract class AbstractHttpMessage implements HttpMessage {
+
+ protected HeaderGroup headergroup;
+
+ protected HttpParams params;
+
+ protected AbstractHttpMessage(final HttpParams params) {
+ super();
+ this.headergroup = new HeaderGroup();
+ this.params = params;
+ }
+
+ protected AbstractHttpMessage() {
+ this(null);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public boolean containsHeader(String name) {
+ return this.headergroup.containsHeader(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header[] getHeaders(final String name) {
+ return this.headergroup.getHeaders(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header getFirstHeader(final String name) {
+ return this.headergroup.getFirstHeader(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header getLastHeader(final String name) {
+ return this.headergroup.getLastHeader(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public Header[] getAllHeaders() {
+ return this.headergroup.getAllHeaders();
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void addHeader(final Header header) {
+ this.headergroup.addHeader(header);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void addHeader(final String name, final String value) {
+ if (name == null) {
+ throw new IllegalArgumentException("Header name may not be null");
+ }
+ this.headergroup.addHeader(new BasicHeader(name, value));
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setHeader(final Header header) {
+ this.headergroup.updateHeader(header);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setHeader(final String name, final String value) {
+ if (name == null) {
+ throw new IllegalArgumentException("Header name may not be null");
+ }
+ this.headergroup.updateHeader(new BasicHeader(name, value));
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setHeaders(final Header[] headers) {
+ this.headergroup.setHeaders(headers);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void removeHeader(final Header header) {
+ this.headergroup.removeHeader(header);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void removeHeaders(final String name) {
+ if (name == null) {
+ return;
+ }
+ for (Iterator i = this.headergroup.iterator(); i.hasNext(); ) {
+ Header header = (Header) i.next();
+ if (name.equalsIgnoreCase(header.getName())) {
+ i.remove();
+ }
+ }
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public HeaderIterator headerIterator() {
+ return this.headergroup.iterator();
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public HeaderIterator headerIterator(String name) {
+ return this.headergroup.iterator(name);
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public HttpParams getParams() {
+ if (this.params == null) {
+ this.params = new BasicHttpParams();
+ }
+ return this.params;
+ }
+
+ // non-javadoc, see interface HttpMessage
+ public void setParams(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ this.params = params;
+ }
+}
diff --git a/src/org/apache/http/message/BasicHeader.java b/src/org/apache/http/message/BasicHeader.java
new file mode 100644
index 0000000..f134d8d
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeader.java
@@ -0,0 +1,143 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeader.java $
+ * $Revision: 652956 $
+ * $Date: 2008-05-02 17:13:05 -0700 (Fri, 02 May 2008) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.ParseException;
+
+/**
+ * Represents an HTTP header field.
+ *
+ * <p>The HTTP header fields follow the same generic format as
+ * that given in Section 3.1 of RFC 822. Each header field consists
+ * of a name followed by a colon (":") and the field value. Field names
+ * are case-insensitive. The field value MAY be preceded by any amount
+ * of LWS, though a single SP is preferred.
+ *
+ *<pre>
+ * message-header = field-name ":" [ field-value ]
+ * field-name = token
+ * field-value = *( field-content | LWS )
+ * field-content = &lt;the OCTETs making up the field-value
+ * and consisting of either *TEXT or combinations
+ * of token, separators, and quoted-string&gt;
+ *</pre>
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 652956 $ $Date: 2008-05-02 17:13:05 -0700 (Fri, 02 May 2008) $
+ *
+ * @since 4.0
+ */
+public class BasicHeader implements Header, Cloneable {
+
+ /**
+ * Header name.
+ */
+ private final String name;
+
+ /**
+ * Header value.
+ */
+ private final String value;
+
+ /**
+ * Constructor with name and value
+ *
+ * @param name the header name
+ * @param value the header value
+ */
+ public BasicHeader(final String name, final String value) {
+ super();
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns the header name.
+ *
+ * @return String name The name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the header value.
+ *
+ * @return String value The current value.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+ /**
+ * Returns a {@link String} representation of the header.
+ *
+ * @return a string
+ */
+ public String toString() {
+ // no need for non-default formatting in toString()
+ return BasicLineFormatter.DEFAULT.formatHeader(null, this).toString();
+ }
+
+ /**
+ * Returns an array of {@link HeaderElement}s constructed from my value.
+ *
+ * @see BasicHeaderValueParser#parseElements(String, HeaderValueParser)
+ *
+ * @return an array of header elements
+ *
+ * @throws ParseException in case of a parse error
+ */
+ public HeaderElement[] getElements() throws ParseException {
+ if (this.value != null) {
+ // result intentionally not cached, it's probably not used again
+ return BasicHeaderValueParser.parseElements(this.value, null);
+ } else {
+ return new HeaderElement[] {};
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicHeaderElement.java b/src/org/apache/http/message/BasicHeaderElement.java
new file mode 100644
index 0000000..19a40c6
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderElement.java
@@ -0,0 +1,243 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderElement.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.LangUtils;
+
+/**
+ * One element of an HTTP header's value.
+ * <p>
+ * Some HTTP headers (such as the set-cookie header) have values that
+ * can be decomposed into multiple elements. Such headers must be in the
+ * following form:
+ * </p>
+ * <pre>
+ * header = [ element ] *( "," [ element ] )
+ * element = name [ "=" [ value ] ] *( ";" [ param ] )
+ * param = name [ "=" [ value ] ]
+ *
+ * name = token
+ * value = ( token | quoted-string )
+ *
+ * token = 1*&lt;any char except "=", ",", ";", &lt;"&gt; and
+ * white space&gt;
+ * quoted-string = &lt;"&gt; *( text | quoted-char ) &lt;"&gt;
+ * text = any char except &lt;"&gt;
+ * quoted-char = "\" char
+ * </pre>
+ * <p>
+ * 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 <var>null</var> will be stored instead.
+ * </p>
+ * <p>
+ * This class represents an individual header element, containing
+ * both a name/value pair (value may be <tt>null</tt>) and optionally
+ * a set of additional parameters.
+ * </p>
+ *
+ * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
+ * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 604625 $ $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * @since 4.0
+ */
+public class BasicHeaderElement implements HeaderElement, Cloneable {
+
+ private final String name;
+ private final String value;
+ private final NameValuePair[] parameters;
+
+ /**
+ * Constructor with name, value and parameters.
+ *
+ * @param name header element name
+ * @param value header element value. May be <tt>null</tt>
+ * @param parameters header element parameters. May be <tt>null</tt>.
+ * Parameters are copied by reference, not by value
+ */
+ public BasicHeaderElement(
+ final String name,
+ final String value,
+ final NameValuePair[] parameters) {
+ super();
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ this.value = value;
+ if (parameters != null) {
+ this.parameters = parameters;
+ } else {
+ this.parameters = new NameValuePair[] {};
+ }
+ }
+
+ /**
+ * Constructor with name and value.
+ *
+ * @param name header element name
+ * @param value header element value. May be <tt>null</tt>
+ */
+ public BasicHeaderElement(final String name, final String value) {
+ this(name, value, null);
+ }
+
+ /**
+ * Returns the name.
+ *
+ * @return String name The name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the value.
+ *
+ * @return String value The current value.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+ /**
+ * Get parameters, if any.
+ * The returned array is created for each invocation and can
+ * be modified by the caller without affecting this header element.
+ *
+ * @return parameters as an array of {@link NameValuePair}s
+ */
+ public NameValuePair[] getParameters() {
+ return (NameValuePair[])this.parameters.clone();
+ }
+
+
+ /**
+ * Obtains the number of parameters.
+ *
+ * @return the number of parameters
+ */
+ public int getParameterCount() {
+ return this.parameters.length;
+ }
+
+
+ /**
+ * Obtains the parameter with the given index.
+ *
+ * @param index the index of the parameter, 0-based
+ *
+ * @return the parameter with the given index
+ */
+ public NameValuePair getParameter(int index) {
+ // ArrayIndexOutOfBoundsException is appropriate
+ return this.parameters[index];
+ }
+
+
+ /**
+ * Returns parameter with the given name, if found. Otherwise null
+ * is returned
+ *
+ * @param name The name to search by.
+ * @return NameValuePair parameter with the given name
+ */
+ public NameValuePair getParameterByName(final String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ NameValuePair found = null;
+ for (int i = 0; i < this.parameters.length; i++) {
+ NameValuePair current = this.parameters[ i ];
+ if (current.getName().equalsIgnoreCase(name)) {
+ found = current;
+ break;
+ }
+ }
+ return found;
+ }
+
+ public boolean equals(final Object object) {
+ if (object == null) return false;
+ if (this == object) return true;
+ if (object instanceof HeaderElement) {
+ BasicHeaderElement that = (BasicHeaderElement) object;
+ return this.name.equals(that.name)
+ && LangUtils.equals(this.value, that.value)
+ && LangUtils.equals(this.parameters, that.parameters);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.name);
+ hash = LangUtils.hashCode(hash, this.value);
+ for (int i = 0; i < this.parameters.length; i++) {
+ hash = LangUtils.hashCode(hash, this.parameters[i]);
+ }
+ return hash;
+ }
+
+ public String toString() {
+ CharArrayBuffer buffer = new CharArrayBuffer(64);
+ buffer.append(this.name);
+ if (this.value != null) {
+ buffer.append("=");
+ buffer.append(this.value);
+ }
+ for (int i = 0; i < this.parameters.length; i++) {
+ buffer.append("; ");
+ buffer.append(this.parameters[i]);
+ }
+ return buffer.toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ // parameters array is considered immutable
+ // no need to make a copy of it
+ return super.clone();
+ }
+
+}
+
diff --git a/src/org/apache/http/message/BasicHeaderElementIterator.java b/src/org/apache/http/message/BasicHeaderElementIterator.java
new file mode 100644
index 0000000..46f53a8
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderElementIterator.java
@@ -0,0 +1,161 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderElementIterator.java $
+ * $Revision: 592088 $
+ * $Date: 2007-11-05 09:03:39 -0800 (Mon, 05 Nov 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.NoSuchElementException;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HeaderElementIterator;
+import org.apache.http.HeaderIterator;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Basic implementation of a {@link HeaderElementIterator}.
+ *
+ * @version $Revision: 592088 $
+ *
+ * @author Andrea Selva <selva.andre at gmail.com>
+ * @author Oleg Kalnichevski <oleg at ural.ru>
+ */
+public class BasicHeaderElementIterator implements HeaderElementIterator {
+
+ private final HeaderIterator headerIt;
+ private final HeaderValueParser parser;
+
+ private HeaderElement currentElement = null;
+ private CharArrayBuffer buffer = null;
+ private ParserCursor cursor = null;
+
+ /**
+ * Creates a new instance of BasicHeaderElementIterator
+ */
+ public BasicHeaderElementIterator(
+ final HeaderIterator headerIterator,
+ final HeaderValueParser parser) {
+ if (headerIterator == null) {
+ throw new IllegalArgumentException("Header iterator may not be null");
+ }
+ if (parser == null) {
+ throw new IllegalArgumentException("Parser may not be null");
+ }
+ this.headerIt = headerIterator;
+ this.parser = parser;
+ }
+
+
+ public BasicHeaderElementIterator(final HeaderIterator headerIterator) {
+ this(headerIterator, BasicHeaderValueParser.DEFAULT);
+ }
+
+
+ private void bufferHeaderValue() {
+ this.cursor = null;
+ this.buffer = null;
+ while (this.headerIt.hasNext()) {
+ Header h = this.headerIt.nextHeader();
+ if (h instanceof FormattedHeader) {
+ this.buffer = ((FormattedHeader) h).getBuffer();
+ this.cursor = new ParserCursor(0, this.buffer.length());
+ this.cursor.updatePos(((FormattedHeader) h).getValuePos());
+ break;
+ } else {
+ String value = h.getValue();
+ if (value != null) {
+ this.buffer = new CharArrayBuffer(value.length());
+ this.buffer.append(value);
+ this.cursor = new ParserCursor(0, this.buffer.length());
+ break;
+ }
+ }
+ }
+ }
+
+ private void parseNextElement() {
+ // loop while there are headers left to parse
+ while (this.headerIt.hasNext() || this.cursor != null) {
+ if (this.cursor == null || this.cursor.atEnd()) {
+ // get next header value
+ bufferHeaderValue();
+ }
+ // Anything buffered?
+ if (this.cursor != null) {
+ // loop while there is data in the buffer
+ while (!this.cursor.atEnd()) {
+ HeaderElement e = this.parser.parseHeaderElement(this.buffer, this.cursor);
+ if (!(e.getName().length() == 0 && e.getValue() == null)) {
+ // Found something
+ this.currentElement = e;
+ return;
+ }
+ }
+ // if at the end of the buffer
+ if (this.cursor.atEnd()) {
+ // discard it
+ this.cursor = null;
+ this.buffer = null;
+ }
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ if (this.currentElement == null) {
+ parseNextElement();
+ }
+ return this.currentElement != null;
+ }
+
+ public HeaderElement nextElement() throws NoSuchElementException {
+ if (this.currentElement == null) {
+ parseNextElement();
+ }
+
+ if (this.currentElement == null) {
+ throw new NoSuchElementException("No more header elements available");
+ }
+
+ HeaderElement element = this.currentElement;
+ this.currentElement = null;
+ return element;
+ }
+
+ public final Object next() throws NoSuchElementException {
+ return nextElement();
+ }
+
+ public void remove() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Remove not supported");
+ }
+
+} \ No newline at end of file
diff --git a/src/org/apache/http/message/BasicHeaderIterator.java b/src/org/apache/http/message/BasicHeaderIterator.java
new file mode 100644
index 0000000..32cd1c8
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderIterator.java
@@ -0,0 +1,180 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderIterator.java $
+ * $Revision: 581981 $
+ * $Date: 2007-10-04 11:26:26 -0700 (Thu, 04 Oct 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import java.util.NoSuchElementException;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+
+
+/**
+ * Basic implementation of a {@link HeaderIterator}.
+ *
+ * @version $Revision: 581981 $
+ */
+public class BasicHeaderIterator implements HeaderIterator {
+
+ /**
+ * An array of headers to iterate over.
+ * Not all elements of this array are necessarily part of the iteration.
+ * This array will never be modified by the iterator.
+ * Derived implementations are expected to adhere to this restriction.
+ */
+ protected final Header[] allHeaders;
+
+
+ /**
+ * The position of the next header in {@link #allHeaders allHeaders}.
+ * Negative if the iteration is over.
+ */
+ protected int currentIndex;
+
+
+ /**
+ * The header name to filter by.
+ * <code>null</code> to iterate over all headers in the array.
+ */
+ protected String headerName;
+
+
+
+ /**
+ * Creates a new header iterator.
+ *
+ * @param headers an array of headers over which to iterate
+ * @param name the name of the headers over which to iterate, or
+ * <code>null</code> for any
+ */
+ public BasicHeaderIterator(Header[] headers, String name) {
+ if (headers == null) {
+ throw new IllegalArgumentException
+ ("Header array must not be null.");
+ }
+
+ this.allHeaders = headers;
+ this.headerName = name;
+ this.currentIndex = findNext(-1);
+ }
+
+
+ /**
+ * Determines the index of the next header.
+ *
+ * @param from one less than the index to consider first,
+ * -1 to search for the first header
+ *
+ * @return the index of the next header that matches the filter name,
+ * or negative if there are no more headers
+ */
+ protected int findNext(int from) {
+ if (from < -1)
+ return -1;
+
+ final int to = this.allHeaders.length-1;
+ boolean found = false;
+ while (!found && (from < to)) {
+ from++;
+ found = filterHeader(from);
+ }
+ return found ? from : -1;
+ }
+
+
+ /**
+ * Checks whether a header is part of the iteration.
+ *
+ * @param index the index of the header to check
+ *
+ * @return <code>true</code> if the header should be part of the
+ * iteration, <code>false</code> to skip
+ */
+ protected boolean filterHeader(int index) {
+ return (this.headerName == null) ||
+ this.headerName.equalsIgnoreCase(this.allHeaders[index].getName());
+ }
+
+
+ // non-javadoc, see interface HeaderIterator
+ public boolean hasNext() {
+ return (this.currentIndex >= 0);
+ }
+
+
+ /**
+ * Obtains the next header from this iteration.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public Header nextHeader()
+ throws NoSuchElementException {
+
+ final int current = this.currentIndex;
+ if (current < 0) {
+ throw new NoSuchElementException("Iteration already finished.");
+ }
+
+ this.currentIndex = findNext(current);
+
+ return this.allHeaders[current];
+ }
+
+
+ /**
+ * Returns the next header.
+ * Same as {@link #nextHeader nextHeader}, but not type-safe.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public final Object next()
+ throws NoSuchElementException {
+ return nextHeader();
+ }
+
+
+ /**
+ * Removing headers is not supported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public void remove()
+ throws UnsupportedOperationException {
+
+ throw new UnsupportedOperationException
+ ("Removing headers is not supported.");
+ }
+}
diff --git a/src/org/apache/http/message/BasicHeaderValueFormatter.java b/src/org/apache/http/message/BasicHeaderValueFormatter.java
new file mode 100644
index 0000000..b63bdf7
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderValueFormatter.java
@@ -0,0 +1,441 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderValueFormatter.java $
+ * $Revision: 574185 $
+ * $Date: 2007-09-10 02:19:47 -0700 (Mon, 10 Sep 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Basic implementation for formatting header value elements.
+ * Instances of this class are stateless and thread-safe.
+ * Derived classes are expected to maintain these properties.
+ *
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ * @author and others
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 574185 $
+ *
+ * @since 4.0
+ */
+public class BasicHeaderValueFormatter implements HeaderValueFormatter {
+
+ /**
+ * A default instance of this class, for use as default or fallback.
+ * Note that {@link BasicHeaderValueFormatter} 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
+ BasicHeaderValueFormatter DEFAULT = new BasicHeaderValueFormatter();
+
+
+ /**
+ * Special characters that can be used as separators in HTTP parameters.
+ * These special characters MUST be in a quoted string to be used within
+ * a parameter value .
+ */
+ public final static String SEPARATORS = " ;,:@()<>\\\"/[]?={}\t";
+
+
+ /**
+ * Unsafe special characters that must be escaped using the backslash
+ * character
+ */
+ public final static String UNSAFE_CHARS = "\"\\";
+
+
+
+ // public default constructor
+
+
+
+ /**
+ * Formats an array of header elements.
+ *
+ * @param elems the header elements to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted header elements
+ */
+ public final static
+ String formatElements(final HeaderElement[] elems,
+ final boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatElements(null, elems, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatElements(CharArrayBuffer buffer,
+ final HeaderElement[] elems,
+ final boolean quote) {
+ if (elems == null) {
+ throw new IllegalArgumentException
+ ("Header element array must not be null.");
+ }
+
+ int len = estimateElementsLen(elems);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ for (int i=0; i<elems.length; i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ formatHeaderElement(buffer, elems[i], quote);
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of formatted header elements.
+ *
+ * @param elems the header elements to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateElementsLen(final HeaderElement[] elems) {
+ if ((elems == null) || (elems.length < 1))
+ return 0;
+
+ int result = (elems.length-1) * 2; // elements separated by ", "
+ for (int i=0; i<elems.length; i++) {
+ result += estimateHeaderElementLen(elems[i]);
+ }
+
+ return result;
+ }
+
+
+
+ /**
+ * Formats a header element.
+ *
+ * @param elem the header element to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted header element
+ */
+ public final static
+ String formatHeaderElement(final HeaderElement elem,
+ boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatHeaderElement(null, elem, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatHeaderElement(CharArrayBuffer buffer,
+ final HeaderElement elem,
+ final boolean quote) {
+ if (elem == null) {
+ throw new IllegalArgumentException
+ ("Header element must not be null.");
+ }
+
+ int len = estimateHeaderElementLen(elem);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ buffer.append(elem.getName());
+ final String value = elem.getValue();
+ if (value != null) {
+ buffer.append('=');
+ doFormatValue(buffer, value, quote);
+ }
+
+ final int parcnt = elem.getParameterCount();
+ if (parcnt > 0) {
+ for (int i=0; i<parcnt; i++) {
+ buffer.append("; ");
+ formatNameValuePair(buffer, elem.getParameter(i), quote);
+ }
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of a formatted header element.
+ *
+ * @param elem the header element to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateHeaderElementLen(final HeaderElement elem) {
+ if (elem == null)
+ return 0;
+
+ int result = elem.getName().length(); // name
+ final String value = elem.getValue();
+ if (value != null) {
+ // assume quotes, but no escaped characters
+ result += 3 + value.length(); // ="value"
+ }
+
+ final int parcnt = elem.getParameterCount();
+ if (parcnt > 0) {
+ for (int i=0; i<parcnt; i++) {
+ result += 2 + // ; <param>
+ estimateNameValuePairLen(elem.getParameter(i));
+ }
+ }
+
+ return result;
+ }
+
+
+
+
+ /**
+ * Formats a set of parameters.
+ *
+ * @param nvps the parameters to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted parameters
+ */
+ public final static
+ String formatParameters(final NameValuePair[] nvps,
+ final boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatParameters(null, nvps, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatParameters(CharArrayBuffer buffer,
+ NameValuePair[] nvps,
+ boolean quote) {
+ if (nvps == null) {
+ throw new IllegalArgumentException
+ ("Parameters must not be null.");
+ }
+
+ int len = estimateParametersLen(nvps);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ for (int i = 0; i < nvps.length; i++) {
+ if (i > 0) {
+ buffer.append("; ");
+ }
+ formatNameValuePair(buffer, nvps[i], quote);
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of formatted parameters.
+ *
+ * @param nvps the parameters to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateParametersLen(final NameValuePair[] nvps) {
+ if ((nvps == null) || (nvps.length < 1))
+ return 0;
+
+ int result = (nvps.length-1) * 2; // "; " between the parameters
+ for (int i=0; i<nvps.length; i++) {
+ result += estimateNameValuePairLen(nvps[i]);
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Formats a name-value pair.
+ *
+ * @param nvp the name-value pair to format
+ * @param quote <code>true</code> to always format with a quoted value,
+ * <code>false</code> to use quotes only when necessary
+ * @param formatter the formatter to use, or <code>null</code>
+ * for the {@link #DEFAULT default}
+ *
+ * @return the formatted name-value pair
+ */
+ public final static
+ String formatNameValuePair(final NameValuePair nvp,
+ final boolean quote,
+ HeaderValueFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicHeaderValueFormatter.DEFAULT;
+ return formatter.formatNameValuePair(null, nvp, quote).toString();
+ }
+
+
+ // non-javadoc, see interface HeaderValueFormatter
+ public CharArrayBuffer formatNameValuePair(CharArrayBuffer buffer,
+ final NameValuePair nvp,
+ final boolean quote) {
+ if (nvp == null) {
+ throw new IllegalArgumentException
+ ("NameValuePair must not be null.");
+ }
+
+ int len = estimateNameValuePairLen(nvp);
+ if (buffer == null) {
+ buffer = new CharArrayBuffer(len);
+ } else {
+ buffer.ensureCapacity(len);
+ }
+
+ buffer.append(nvp.getName());
+ final String value = nvp.getValue();
+ if (value != null) {
+ buffer.append('=');
+ doFormatValue(buffer, value, quote);
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * Estimates the length of a formatted name-value pair.
+ *
+ * @param nvp the name-value pair to format, or <code>null</code>
+ *
+ * @return a length estimate, in number of characters
+ */
+ protected int estimateNameValuePairLen(final NameValuePair nvp) {
+ if (nvp == null)
+ return 0;
+
+ int result = nvp.getName().length(); // name
+ final String value = nvp.getValue();
+ if (value != null) {
+ // assume quotes, but no escaped characters
+ result += 3 + value.length(); // ="value"
+ }
+ return result;
+ }
+
+
+ /**
+ * Actually formats the value of a name-value pair.
+ * This does not include a leading = character.
+ * Called from {@link #formatNameValuePair formatNameValuePair}.
+ *
+ * @param buffer the buffer to append to, never <code>null</code>
+ * @param value the value to append, never <code>null</code>
+ * @param quote <code>true</code> to always format with quotes,
+ * <code>false</code> to use quotes only when necessary
+ */
+ protected void doFormatValue(final CharArrayBuffer buffer,
+ final String value,
+ boolean quote) {
+
+ if (!quote) {
+ for (int i = 0; (i < value.length()) && !quote; i++) {
+ quote = isSeparator(value.charAt(i));
+ }
+ }
+
+ if (quote) {
+ buffer.append('"');
+ }
+ for (int i = 0; i < value.length(); i++) {
+ char ch = value.charAt(i);
+ if (isUnsafe(ch)) {
+ buffer.append('\\');
+ }
+ buffer.append(ch);
+ }
+ if (quote) {
+ buffer.append('"');
+ }
+ }
+
+
+ /**
+ * Checks whether a character is a {@link #SEPARATORS separator}.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is a separator,
+ * <code>false</code> otherwise
+ */
+ protected boolean isSeparator(char ch) {
+ return SEPARATORS.indexOf(ch) >= 0;
+ }
+
+
+ /**
+ * Checks whether a character is {@link #UNSAFE_CHARS unsafe}.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is unsafe,
+ * <code>false</code> otherwise
+ */
+ protected boolean isUnsafe(char ch) {
+ return UNSAFE_CHARS.indexOf(ch) >= 0;
+ }
+
+
+} // class BasicHeaderValueFormatter
diff --git a/src/org/apache/http/message/BasicHeaderValueParser.java b/src/org/apache/http/message/BasicHeaderValueParser.java
new file mode 100644
index 0000000..5216196
--- /dev/null
+++ b/src/org/apache/http/message/BasicHeaderValueParser.java
@@ -0,0 +1,420 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderValueParser.java $
+ * $Revision: 595670 $
+ * $Date: 2007-11-16 06:15:01 -0800 (Fri, 16 Nov 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.ParseException;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.CharArrayBuffer;
+
+
+
+/**
+ * Basic implementation for parsing header values into elements.
+ * Instances of this class are stateless and thread-safe.
+ * Derived classes are expected to maintain these properties.
+ *
+ * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
+ * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ * @author and others
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 595670 $
+ *
+ * @since 4.0
+ */
+public class BasicHeaderValueParser implements HeaderValueParser {
+
+ /**
+ * A default instance of this class, for use as default or fallback.
+ * Note that {@link BasicHeaderValueParser} 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
+ BasicHeaderValueParser DEFAULT = new BasicHeaderValueParser();
+
+ private final static char PARAM_DELIMITER = ';';
+ private final static char ELEM_DELIMITER = ',';
+ private final static char[] ALL_DELIMITERS = new char[] {
+ PARAM_DELIMITER,
+ ELEM_DELIMITER
+ };
+
+ // public default constructor
+
+
+ /**
+ * Parses elements with the given parser.
+ *
+ * @param value the header value to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return array holding the header elements, never <code>null</code>
+ */
+ public final static
+ HeaderElement[] parseElements(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseElements(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public HeaderElement[] parseElements(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ List elements = new ArrayList();
+ while (!cursor.atEnd()) {
+ HeaderElement element = parseHeaderElement(buffer, cursor);
+ if (!(element.getName().length() == 0 && element.getValue() == null)) {
+ elements.add(element);
+ }
+ }
+ return (HeaderElement[])
+ elements.toArray(new HeaderElement[elements.size()]);
+ }
+
+
+ /**
+ * Parses an element with the given parser.
+ *
+ * @param value the header element to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return the parsed header element
+ */
+ public final static
+ HeaderElement parseHeaderElement(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseHeaderElement(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public HeaderElement parseHeaderElement(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ NameValuePair nvp = parseNameValuePair(buffer, cursor);
+ NameValuePair[] params = null;
+ if (!cursor.atEnd()) {
+ char ch = buffer.charAt(cursor.getPos() - 1);
+ if (ch != ELEM_DELIMITER) {
+ params = parseParameters(buffer, cursor);
+ }
+ }
+ return createHeaderElement(nvp.getName(), nvp.getValue(), params);
+ }
+
+
+ /**
+ * Creates a header element.
+ * Called from {@link #parseHeaderElement}.
+ *
+ * @return a header element representing the argument
+ */
+ protected HeaderElement createHeaderElement(
+ final String name,
+ final String value,
+ final NameValuePair[] params) {
+ return new BasicHeaderElement(name, value, params);
+ }
+
+
+ /**
+ * Parses parameters with the given parser.
+ *
+ * @param value the parameter list to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return array holding the parameters, never <code>null</code>
+ */
+ public final static
+ NameValuePair[] parseParameters(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseParameters(buffer, cursor);
+ }
+
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public NameValuePair[] parseParameters(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ int pos = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ while (pos < indexTo) {
+ char ch = buffer.charAt(pos);
+ if (HTTP.isWhitespace(ch)) {
+ pos++;
+ } else {
+ break;
+ }
+ }
+ cursor.updatePos(pos);
+ if (cursor.atEnd()) {
+ return new NameValuePair[] {};
+ }
+
+ List params = new ArrayList();
+ while (!cursor.atEnd()) {
+ NameValuePair param = parseNameValuePair(buffer, cursor);
+ params.add(param);
+ char ch = buffer.charAt(cursor.getPos() - 1);
+ if (ch == ELEM_DELIMITER) {
+ break;
+ }
+ }
+
+ return (NameValuePair[])
+ params.toArray(new NameValuePair[params.size()]);
+ }
+
+ /**
+ * Parses a name-value-pair with the given parser.
+ *
+ * @param value the NVP to parse
+ * @param parser the parser to use, or <code>null</code> for default
+ *
+ * @return the parsed name-value pair
+ */
+ public final static
+ NameValuePair parseNameValuePair(final String value,
+ HeaderValueParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicHeaderValueParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseNameValuePair(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface HeaderValueParser
+ public NameValuePair parseNameValuePair(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+ return parseNameValuePair(buffer, cursor, ALL_DELIMITERS);
+ }
+
+ private static boolean isOneOf(final char ch, final char[] chs) {
+ if (chs != null) {
+ for (int i = 0; i < chs.length; i++) {
+ if (ch == chs[i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public NameValuePair parseNameValuePair(final CharArrayBuffer buffer,
+ final ParserCursor cursor,
+ final char[] delimiters) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ boolean terminated = false;
+
+ int pos = cursor.getPos();
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ // Find name
+ String name = null;
+ while (pos < indexTo) {
+ char ch = buffer.charAt(pos);
+ if (ch == '=') {
+ break;
+ }
+ if (isOneOf(ch, delimiters)) {
+ terminated = true;
+ break;
+ }
+ pos++;
+ }
+
+ if (pos == indexTo) {
+ terminated = true;
+ name = buffer.substringTrimmed(indexFrom, indexTo);
+ } else {
+ name = buffer.substringTrimmed(indexFrom, pos);
+ pos++;
+ }
+
+ if (terminated) {
+ cursor.updatePos(pos);
+ return createNameValuePair(name, null);
+ }
+
+ // Find value
+ String value = null;
+ int i1 = pos;
+
+ boolean qouted = false;
+ boolean escaped = false;
+ while (pos < indexTo) {
+ char ch = buffer.charAt(pos);
+ if (ch == '"' && !escaped) {
+ qouted = !qouted;
+ }
+ if (!qouted && !escaped && isOneOf(ch, delimiters)) {
+ terminated = true;
+ break;
+ }
+ if (escaped) {
+ escaped = false;
+ } else {
+ escaped = qouted && ch == '\\';
+ }
+ pos++;
+ }
+
+ int i2 = pos;
+ // 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--;
+ }
+ value = buffer.substring(i1, i2);
+ if (terminated) {
+ pos++;
+ }
+ cursor.updatePos(pos);
+ return createNameValuePair(name, value);
+ }
+
+ /**
+ * Creates a name-value pair.
+ * Called from {@link #parseNameValuePair}.
+ *
+ * @param name the name
+ * @param value the value, or <code>null</code>
+ *
+ * @return a name-value pair representing the arguments
+ */
+ protected NameValuePair createNameValuePair(final String name, final String value) {
+ return new BasicNameValuePair(name, value);
+ }
+
+}
+
diff --git a/src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java b/src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java
new file mode 100644
index 0000000..dbb70c8
--- /dev/null
+++ b/src/org/apache/http/message/BasicHttpEntityEnclosingRequest.java
@@ -0,0 +1,81 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHttpEntityEnclosingRequest.java $
+ * $Revision: 618017 $
+ * $Date: 2008-02-03 08:42:22 -0800 (Sun, 03 Feb 2008) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Basic implementation of a request with an entity that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 618017 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpEntityEnclosingRequest
+ extends BasicHttpRequest implements HttpEntityEnclosingRequest {
+
+ private HttpEntity entity;
+
+ public BasicHttpEntityEnclosingRequest(final String method, final String uri) {
+ super(method, uri);
+ }
+
+ public BasicHttpEntityEnclosingRequest(final String method, final String uri,
+ final ProtocolVersion ver) {
+ this(new BasicRequestLine(method, uri, ver));
+ }
+
+ public BasicHttpEntityEnclosingRequest(final RequestLine requestline) {
+ super(requestline);
+ }
+
+ public HttpEntity getEntity() {
+ return this.entity;
+ }
+
+ public void setEntity(final HttpEntity entity) {
+ this.entity = entity;
+ }
+
+ public boolean expectContinue() {
+ Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
+ return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicHttpRequest.java b/src/org/apache/http/message/BasicHttpRequest.java
new file mode 100644
index 0000000..eedf8bc
--- /dev/null
+++ b/src/org/apache/http/message/BasicHttpRequest.java
@@ -0,0 +1,98 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHttpRequest.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HttpRequest;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.params.HttpProtocolParams;
+
+/**
+ * Basic implementation of an HTTP request that can be modified.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpRequest extends AbstractHttpMessage implements HttpRequest {
+
+ private final RequestLine requestline;
+ private final String method;
+ private final String uri;
+
+ public BasicHttpRequest(final String method, final String uri) {
+ super();
+ if (method == null) {
+ throw new IllegalArgumentException("Method name may not be null");
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("Request URI may not be null");
+ }
+ this.method = method;
+ this.uri = uri;
+ this.requestline = null;
+ }
+
+ public BasicHttpRequest(final String method, final String uri, final ProtocolVersion ver) {
+ this(new BasicRequestLine(method, uri, ver));
+ }
+
+ public BasicHttpRequest(final RequestLine requestline) {
+ super();
+ if (requestline == null) {
+ throw new IllegalArgumentException("Request line may not be null");
+ }
+ this.requestline = requestline;
+ this.method = requestline.getMethod();
+ this.uri = requestline.getUri();
+ }
+
+ public ProtocolVersion getProtocolVersion() {
+ if (this.requestline != null) {
+ return this.requestline.getProtocolVersion();
+ } else {
+ return HttpProtocolParams.getVersion(getParams());
+ }
+ }
+
+ public RequestLine getRequestLine() {
+ if (this.requestline != null) {
+ return this.requestline;
+ } else {
+ ProtocolVersion ver = HttpProtocolParams.getVersion(getParams());
+ return new BasicRequestLine(this.method, this.uri, ver);
+ }
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicHttpResponse.java b/src/org/apache/http/message/BasicHttpResponse.java
new file mode 100644
index 0000000..7da4bea
--- /dev/null
+++ b/src/org/apache/http/message/BasicHttpResponse.java
@@ -0,0 +1,204 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHttpResponse.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.Locale;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+import org.apache.http.ReasonPhraseCatalog;
+
+
+/**
+ * Basic implementation of an HTTP response that can be modified.
+ * This implementation makes sure that there always is a status line.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 573864 $
+ *
+ * @since 4.0
+ */
+public class BasicHttpResponse extends AbstractHttpMessage
+ implements HttpResponse {
+
+ private StatusLine statusline;
+ private HttpEntity entity;
+ private ReasonPhraseCatalog reasonCatalog;
+ private Locale locale;
+
+
+ /**
+ * Creates a new response.
+ * This is the constructor to which all others map.
+ *
+ * @param statusline the status line
+ * @param catalog the reason phrase catalog, or
+ * <code>null</code> to disable automatic
+ * reason phrase lookup
+ * @param locale the locale for looking up reason phrases, or
+ * <code>null</code> for the system locale
+ */
+ public BasicHttpResponse(final StatusLine statusline,
+ final ReasonPhraseCatalog catalog,
+ final Locale locale) {
+ super();
+ if (statusline == null) {
+ throw new IllegalArgumentException("Status line may not be null.");
+ }
+ this.statusline = statusline;
+ this.reasonCatalog = catalog;
+ this.locale = (locale != null) ? locale : Locale.getDefault();
+ }
+
+ /**
+ * Creates a response from a status line.
+ * The response will not have a reason phrase catalog and
+ * use the system default locale.
+ *
+ * @param statusline the status line
+ */
+ public BasicHttpResponse(final StatusLine statusline) {
+ this(statusline, null, null);
+ }
+
+ /**
+ * Creates a response from elements of a status line.
+ * The response will not have a reason phrase catalog and
+ * use the system default locale.
+ *
+ * @param ver the protocol version of the response
+ * @param code the status code of the response
+ * @param reason the reason phrase to the status code, or
+ * <code>null</code>
+ */
+ public BasicHttpResponse(final ProtocolVersion ver,
+ final int code,
+ final String reason) {
+ this(new BasicStatusLine(ver, code, reason), null, null);
+ }
+
+
+ // non-javadoc, see interface HttpMessage
+ public ProtocolVersion getProtocolVersion() {
+ return this.statusline.getProtocolVersion();
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public StatusLine getStatusLine() {
+ return this.statusline;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public HttpEntity getEntity() {
+ return this.entity;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public Locale getLocale() {
+ return this.locale;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusLine(final StatusLine statusline) {
+ if (statusline == null) {
+ throw new IllegalArgumentException("Status line may not be null");
+ }
+ this.statusline = statusline;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusLine(final ProtocolVersion ver, final int code) {
+ // arguments checked in BasicStatusLine constructor
+ this.statusline = new BasicStatusLine(ver, code, getReason(code));
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusLine(final ProtocolVersion ver, final int code,
+ final String reason) {
+ // arguments checked in BasicStatusLine constructor
+ this.statusline = new BasicStatusLine(ver, code, reason);
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setStatusCode(int code) {
+ // argument checked in BasicStatusLine constructor
+ ProtocolVersion ver = this.statusline.getProtocolVersion();
+ this.statusline = new BasicStatusLine(ver, code, getReason(code));
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setReasonPhrase(String reason) {
+
+ if ((reason != null) && ((reason.indexOf('\n') >= 0) ||
+ (reason.indexOf('\r') >= 0))
+ ) {
+ throw new IllegalArgumentException("Line break in reason phrase.");
+ }
+ this.statusline = new BasicStatusLine(this.statusline.getProtocolVersion(),
+ this.statusline.getStatusCode(),
+ reason);
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setEntity(final HttpEntity entity) {
+ this.entity = entity;
+ }
+
+ // non-javadoc, see interface HttpResponse
+ public void setLocale(Locale loc) {
+ if (loc == null) {
+ throw new IllegalArgumentException("Locale may not be null.");
+ }
+ this.locale = loc;
+ final int code = this.statusline.getStatusCode();
+ this.statusline = new BasicStatusLine
+ (this.statusline.getProtocolVersion(), code, getReason(code));
+ }
+
+ /**
+ * Looks up a reason phrase.
+ * This method evaluates the currently set catalog and locale.
+ * It also handles a missing catalog.
+ *
+ * @param code the status code for which to look up the reason
+ *
+ * @return the reason phrase, or <code>null</code> if there is none
+ */
+ protected String getReason(int code) {
+ return (this.reasonCatalog == null) ?
+ null : this.reasonCatalog.getReason(code, this.locale);
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicLineFormatter.java b/src/org/apache/http/message/BasicLineFormatter.java
new file mode 100644
index 0000000..7c3bbc4
--- /dev/null
+++ b/src/org/apache/http/message/BasicLineFormatter.java
@@ -0,0 +1,346 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicLineFormatter.java $
+ * $Revision: 574185 $
+ * $Date: 2007-09-10 02:19:47 -0700 (Mon, 10 Sep 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.FormattedHeader;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Interface for formatting elements of the HEAD section of an HTTP message.
+ * This is the complement to {@link LineParser}.
+ * There are individual methods for formatting a request line, a
+ * status line, or a header line. The formatting does <i>not</i> include the
+ * trailing line break sequence CR-LF.
+ * The formatted lines are returned in memory, the formatter does not depend
+ * on any specific IO mechanism.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author and others
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 574185 $
+ *
+ * @since 4.0
+ */
+public class BasicLineFormatter implements LineFormatter {
+
+ /**
+ * A default instance of this class, for use as default or fallback.
+ * Note that {@link BasicLineFormatter} 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 BasicLineFormatter DEFAULT = new BasicLineFormatter();
+
+
+
+ // public default constructor
+
+
+ /**
+ * Obtains a buffer for formatting.
+ *
+ * @param buffer a buffer already available, or <code>null</code>
+ *
+ * @return the cleared argument buffer if there is one, or
+ * a new empty buffer that can be used for formatting
+ */
+ protected CharArrayBuffer initBuffer(CharArrayBuffer buffer) {
+ if (buffer != null) {
+ buffer.clear();
+ } else {
+ buffer = new CharArrayBuffer(64);
+ }
+ return buffer;
+ }
+
+
+ /**
+ * Formats a protocol version.
+ *
+ * @param version the protocol version to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted protocol version
+ */
+ public final static
+ String formatProtocolVersion(final ProtocolVersion version,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.appendProtocolVersion(null, version).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer appendProtocolVersion(final CharArrayBuffer buffer,
+ final ProtocolVersion version) {
+ if (version == null) {
+ throw new IllegalArgumentException
+ ("Protocol version may not be null");
+ }
+
+ // can't use initBuffer, that would clear the argument!
+ CharArrayBuffer result = buffer;
+ final int len = estimateProtocolVersionLen(version);
+ if (result == null) {
+ result = new CharArrayBuffer(len);
+ } else {
+ result.ensureCapacity(len);
+ }
+
+ result.append(version.getProtocol());
+ result.append('/');
+ result.append(Integer.toString(version.getMajor()));
+ result.append('.');
+ result.append(Integer.toString(version.getMinor()));
+
+ return result;
+ }
+
+
+ /**
+ * Guesses the length of a formatted protocol version.
+ * Needed to guess the length of a formatted request or status line.
+ *
+ * @param version the protocol version to format, or <code>null</code>
+ *
+ * @return the estimated length of the formatted protocol version,
+ * in characters
+ */
+ protected int estimateProtocolVersionLen(final ProtocolVersion version) {
+ return version.getProtocol().length() + 4; // room for "HTTP/1.1"
+ }
+
+
+ /**
+ * Formats a request line.
+ *
+ * @param reqline the request line to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted request line
+ */
+ public final static String formatRequestLine(final RequestLine reqline,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.formatRequestLine(null, reqline).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer formatRequestLine(CharArrayBuffer buffer,
+ RequestLine reqline) {
+ if (reqline == null) {
+ throw new IllegalArgumentException
+ ("Request line may not be null");
+ }
+
+ CharArrayBuffer result = initBuffer(buffer);
+ doFormatRequestLine(result, reqline);
+
+ return result;
+ }
+
+
+ /**
+ * Actually formats a request line.
+ * Called from {@link #formatRequestLine}.
+ *
+ * @param buffer the empty buffer into which to format,
+ * never <code>null</code>
+ * @param reqline the request line to format, never <code>null</code>
+ */
+ protected void doFormatRequestLine(final CharArrayBuffer buffer,
+ final RequestLine reqline) {
+ final String method = reqline.getMethod();
+ final String uri = reqline.getUri();
+
+ // room for "GET /index.html HTTP/1.1"
+ int len = method.length() + 1 + uri.length() + 1 +
+ estimateProtocolVersionLen(reqline.getProtocolVersion());
+ buffer.ensureCapacity(len);
+
+ buffer.append(method);
+ buffer.append(' ');
+ buffer.append(uri);
+ buffer.append(' ');
+ appendProtocolVersion(buffer, reqline.getProtocolVersion());
+ }
+
+
+
+ /**
+ * Formats a status line.
+ *
+ * @param statline the status line to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted status line
+ */
+ public final static String formatStatusLine(final StatusLine statline,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.formatStatusLine(null, statline).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer formatStatusLine(final CharArrayBuffer buffer,
+ final StatusLine statline) {
+ if (statline == null) {
+ throw new IllegalArgumentException
+ ("Status line may not be null");
+ }
+
+ CharArrayBuffer result = initBuffer(buffer);
+ doFormatStatusLine(result, statline);
+
+ return result;
+ }
+
+
+ /**
+ * Actually formats a status line.
+ * Called from {@link #formatStatusLine}.
+ *
+ * @param buffer the empty buffer into which to format,
+ * never <code>null</code>
+ * @param statline the status line to format, never <code>null</code>
+ */
+ protected void doFormatStatusLine(final CharArrayBuffer buffer,
+ final StatusLine statline) {
+
+ int len = estimateProtocolVersionLen(statline.getProtocolVersion())
+ + 1 + 3 + 1; // room for "HTTP/1.1 200 "
+ final String reason = statline.getReasonPhrase();
+ if (reason != null) {
+ len += reason.length();
+ }
+ buffer.ensureCapacity(len);
+
+ appendProtocolVersion(buffer, statline.getProtocolVersion());
+ buffer.append(' ');
+ buffer.append(Integer.toString(statline.getStatusCode()));
+ buffer.append(' '); // keep whitespace even if reason phrase is empty
+ if (reason != null) {
+ buffer.append(reason);
+ }
+ }
+
+
+ /**
+ * Formats a header.
+ *
+ * @param header the header to format
+ * @param formatter the formatter to use, or
+ * <code>null</code> for the
+ * {@link #DEFAULT default}
+ *
+ * @return the formatted header
+ */
+ public final static String formatHeader(final Header header,
+ LineFormatter formatter) {
+ if (formatter == null)
+ formatter = BasicLineFormatter.DEFAULT;
+ return formatter.formatHeader(null, header).toString();
+ }
+
+
+ // non-javadoc, see interface LineFormatter
+ public CharArrayBuffer formatHeader(CharArrayBuffer buffer,
+ Header header) {
+ if (header == null) {
+ throw new IllegalArgumentException
+ ("Header may not be null");
+ }
+ CharArrayBuffer result = null;
+
+ if (header instanceof FormattedHeader) {
+ // If the header is backed by a buffer, re-use the buffer
+ result = ((FormattedHeader)header).getBuffer();
+ } else {
+ result = initBuffer(buffer);
+ doFormatHeader(result, header);
+ }
+ return result;
+
+ } // formatHeader
+
+
+ /**
+ * Actually formats a header.
+ * Called from {@link #formatHeader}.
+ *
+ * @param buffer the empty buffer into which to format,
+ * never <code>null</code>
+ * @param header the header to format, never <code>null</code>
+ */
+ protected void doFormatHeader(final CharArrayBuffer buffer,
+ final Header header) {
+ final String name = header.getName();
+ final String value = header.getValue();
+
+ int len = name.length() + 2;
+ if (value != null) {
+ len += value.length();
+ }
+ buffer.ensureCapacity(len);
+
+ buffer.append(name);
+ buffer.append(": ");
+ if (value != null) {
+ buffer.append(value);
+ }
+ }
+
+
+} // class BasicLineFormatter
diff --git a/src/org/apache/http/message/BasicLineParser.java b/src/org/apache/http/message/BasicLineParser.java
new file mode 100644
index 0000000..c5e9ddb
--- /dev/null
+++ b/src/org/apache/http/message/BasicLineParser.java
@@ -0,0 +1,504 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicLineParser.java $
+ * $Revision: 591798 $
+ * $Date: 2007-11-04 08:19:29 -0800 (Sun, 04 Nov 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.ParseException;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Basic parser for lines in the head section of an HTTP message.
+ * There are individual methods for parsing a request line, a
+ * status line, or a header line.
+ * The lines to parse are passed in memory, the parser does not depend
+ * on any specific IO mechanism.
+ * Instances of this class are stateless and thread-safe.
+ * Derived classes MUST maintain these properties.
+ *
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ * @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();
+
+
+ /**
+ * A version of the protocol to parse.
+ * The version is typically not relevant, but the protocol name.
+ */
+ protected final ProtocolVersion protocol;
+
+
+ /**
+ * Creates a new line parser for the given HTTP-like protocol.
+ *
+ * @param proto a version of the protocol to parse, or
+ * <code>null</code> for HTTP. The actual version
+ * is not relevant, only the protocol name.
+ */
+ public BasicLineParser(ProtocolVersion proto) {
+ if (proto == null) {
+ proto = HttpVersion.HTTP_1_1;
+ }
+ this.protocol = proto;
+ }
+
+
+ /**
+ * Creates a new line parser for HTTP.
+ */
+ public BasicLineParser() {
+ this(null);
+ }
+
+
+
+ public final static
+ ProtocolVersion parseProtocolVersion(String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null.");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseProtocolVersion(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface LineParser
+ public ProtocolVersion parseProtocolVersion(final CharArrayBuffer buffer,
+ final ParserCursor cursor)
+ throws ParseException {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ final String protoname = this.protocol.getProtocol();
+ final int protolength = protoname.length();
+
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ skipWhitespace(buffer, cursor);
+
+ int i = cursor.getPos();
+
+ // long enough for "HTTP/1.1"?
+ if (i + protolength + 4 > indexTo) {
+ throw new ParseException
+ ("Not a valid protocol version: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ // check the protocol name and slash
+ boolean ok = true;
+ for (int j=0; ok && (j<protolength); j++) {
+ ok = (buffer.charAt(i+j) == protoname.charAt(j));
+ }
+ if (ok) {
+ ok = (buffer.charAt(i+protolength) == '/');
+ }
+ if (!ok) {
+ throw new ParseException
+ ("Not a valid protocol version: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ i += protolength+1;
+
+ int period = buffer.indexOf('.', i, indexTo);
+ if (period == -1) {
+ throw new ParseException
+ ("Invalid protocol version number: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ int major;
+ try {
+ major = Integer.parseInt(buffer.substringTrimmed(i, period));
+ } catch (NumberFormatException e) {
+ throw new ParseException
+ ("Invalid protocol major version number: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ i = period + 1;
+
+ int blank = buffer.indexOf(' ', i, indexTo);
+ if (blank == -1) {
+ blank = indexTo;
+ }
+ int minor;
+ try {
+ minor = Integer.parseInt(buffer.substringTrimmed(i, blank));
+ } catch (NumberFormatException e) {
+ throw new ParseException(
+ "Invalid protocol minor version number: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ cursor.updatePos(blank);
+
+ return createProtocolVersion(major, minor);
+
+ } // 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 ProtocolVersion createProtocolVersion(int major, int minor) {
+ return protocol.forVersion(major, minor);
+ }
+
+
+
+ // non-javadoc, see interface LineParser
+ public boolean hasProtocolVersion(final CharArrayBuffer buffer,
+ final ParserCursor cursor) {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+ int index = cursor.getPos();
+
+ final String protoname = this.protocol.getProtocol();
+ final int protolength = protoname.length();
+
+ if (buffer.length() < protolength+4)
+ return false; // not long enough for "HTTP/1.1"
+
+ if (index < 0) {
+ // end of line, no tolerance for trailing whitespace
+ // this works only for single-digit major and minor version
+ index = buffer.length() -4 -protolength;
+ } else if (index == 0) {
+ // beginning of line, tolerate leading whitespace
+ while ((index < buffer.length()) &&
+ HTTP.isWhitespace(buffer.charAt(index))) {
+ index++;
+ }
+ } // else within line, don't tolerate whitespace
+
+
+ if (index + protolength + 4 > buffer.length())
+ return false;
+
+
+ // just check protocol name and slash, no need to analyse the version
+ boolean ok = true;
+ for (int j=0; ok && (j<protolength); j++) {
+ ok = (buffer.charAt(index+j) == protoname.charAt(j));
+ }
+ if (ok) {
+ ok = (buffer.charAt(index+protolength) == '/');
+ }
+
+ return ok;
+ }
+
+
+
+ public final static
+ RequestLine parseRequestLine(final String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null.");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseRequestLine(buffer, cursor);
+ }
+
+
+ /**
+ * Parses a request line.
+ *
+ * @param buffer a buffer holding the line to parse
+ *
+ * @return the parsed request line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ public RequestLine parseRequestLine(final CharArrayBuffer buffer,
+ final ParserCursor cursor)
+ throws ParseException {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ try {
+ skipWhitespace(buffer, cursor);
+ int i = cursor.getPos();
+
+ int blank = buffer.indexOf(' ', i, indexTo);
+ if (blank < 0) {
+ throw new ParseException("Invalid request line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ String method = buffer.substringTrimmed(i, blank);
+ cursor.updatePos(blank);
+
+ skipWhitespace(buffer, cursor);
+ i = cursor.getPos();
+
+ blank = buffer.indexOf(' ', i, indexTo);
+ if (blank < 0) {
+ throw new ParseException("Invalid request line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+ String uri = buffer.substringTrimmed(i, blank);
+ cursor.updatePos(blank);
+
+ ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
+
+ skipWhitespace(buffer, cursor);
+ if (!cursor.atEnd()) {
+ throw new ParseException("Invalid request line: " +
+ buffer.substring(indexFrom, indexTo));
+ }
+
+ return createRequestLine(method, uri, ver);
+ } catch (IndexOutOfBoundsException e) {
+ throw new ParseException("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(final String method,
+ final String uri,
+ final ProtocolVersion ver) {
+ return new BasicRequestLine(method, uri, ver);
+ }
+
+
+
+ public final static
+ StatusLine parseStatusLine(final String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null.");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ ParserCursor cursor = new ParserCursor(0, value.length());
+ return parser.parseStatusLine(buffer, cursor);
+ }
+
+
+ // non-javadoc, see interface LineParser
+ public StatusLine parseStatusLine(final CharArrayBuffer buffer,
+ final ParserCursor cursor)
+ throws ParseException {
+
+ if (buffer == null) {
+ throw new IllegalArgumentException("Char array buffer may not be null");
+ }
+ if (cursor == null) {
+ throw new IllegalArgumentException("Parser cursor may not be null");
+ }
+
+ int indexFrom = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+
+ try {
+ // handle the HTTP-Version
+ ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
+
+ // handle the Status-Code
+ skipWhitespace(buffer, cursor);
+ int i = cursor.getPos();
+
+ int 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 ParseException(
+ "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 ParseException("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(final ProtocolVersion ver,
+ final int status,
+ final String reason) {
+ return new BasicStatusLine(ver, status, reason);
+ }
+
+
+
+ public final static
+ Header parseHeader(final String value,
+ LineParser parser)
+ throws ParseException {
+
+ if (value == null) {
+ throw new IllegalArgumentException
+ ("Value to parse may not be null");
+ }
+
+ if (parser == null)
+ parser = BasicLineParser.DEFAULT;
+
+ CharArrayBuffer buffer = new CharArrayBuffer(value.length());
+ buffer.append(value);
+ return parser.parseHeader(buffer);
+ }
+
+
+ // non-javadoc, see interface LineParser
+ public Header parseHeader(CharArrayBuffer buffer)
+ throws ParseException {
+
+ // the actual parser code is in the constructor of BufferedHeader
+ return new BufferedHeader(buffer);
+ }
+
+
+ /**
+ * Helper to skip whitespace.
+ */
+ protected void skipWhitespace(final CharArrayBuffer buffer, final ParserCursor cursor) {
+ int pos = cursor.getPos();
+ int indexTo = cursor.getUpperBound();
+ while ((pos < indexTo) &&
+ HTTP.isWhitespace(buffer.charAt(pos))) {
+ pos++;
+ }
+ cursor.updatePos(pos);
+ }
+
+} // class BasicLineParser
diff --git a/src/org/apache/http/message/BasicListHeaderIterator.java b/src/org/apache/http/message/BasicListHeaderIterator.java
new file mode 100644
index 0000000..69b8c06
--- /dev/null
+++ b/src/org/apache/http/message/BasicListHeaderIterator.java
@@ -0,0 +1,196 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicListHeaderIterator.java $
+ * $Revision: 584542 $
+ * $Date: 2007-10-14 06:29:34 -0700 (Sun, 14 Oct 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+
+
+/**
+ * Implementation of a {@link HeaderIterator} based on a {@link List}.
+ * For use by {@link HeaderGroup}.
+ *
+ * @version $Revision: 584542 $
+ */
+public class BasicListHeaderIterator implements HeaderIterator {
+
+ /**
+ * A list of headers to iterate over.
+ * Not all elements of this array are necessarily part of the iteration.
+ */
+ protected final List allHeaders;
+
+
+ /**
+ * The position of the next header in {@link #allHeaders allHeaders}.
+ * Negative if the iteration is over.
+ */
+ protected int currentIndex;
+
+
+ /**
+ * The position of the last returned header.
+ * Negative if none has been returned so far.
+ */
+ protected int lastIndex;
+
+
+ /**
+ * The header name to filter by.
+ * <code>null</code> to iterate over all headers in the array.
+ */
+ protected String headerName;
+
+
+
+ /**
+ * Creates a new header iterator.
+ *
+ * @param headers a list of headers over which to iterate
+ * @param name the name of the headers over which to iterate, or
+ * <code>null</code> for any
+ */
+ public BasicListHeaderIterator(List headers, String name) {
+ if (headers == null) {
+ throw new IllegalArgumentException
+ ("Header list must not be null.");
+ }
+
+ this.allHeaders = headers;
+ this.headerName = name;
+ this.currentIndex = findNext(-1);
+ this.lastIndex = -1;
+ }
+
+
+ /**
+ * Determines the index of the next header.
+ *
+ * @param from one less than the index to consider first,
+ * -1 to search for the first header
+ *
+ * @return the index of the next header that matches the filter name,
+ * or negative if there are no more headers
+ */
+ protected int findNext(int from) {
+ if (from < -1)
+ return -1;
+
+ final int to = this.allHeaders.size()-1;
+ boolean found = false;
+ while (!found && (from < to)) {
+ from++;
+ found = filterHeader(from);
+ }
+ return found ? from : -1;
+ }
+
+
+ /**
+ * Checks whether a header is part of the iteration.
+ *
+ * @param index the index of the header to check
+ *
+ * @return <code>true</code> if the header should be part of the
+ * iteration, <code>false</code> to skip
+ */
+ protected boolean filterHeader(int index) {
+ if (this.headerName == null)
+ return true;
+
+ // non-header elements, including null, will trigger exceptions
+ final String name = ((Header)this.allHeaders.get(index)).getName();
+
+ return this.headerName.equalsIgnoreCase(name);
+ }
+
+
+ // non-javadoc, see interface HeaderIterator
+ public boolean hasNext() {
+ return (this.currentIndex >= 0);
+ }
+
+
+ /**
+ * Obtains the next header from this iteration.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public Header nextHeader()
+ throws NoSuchElementException {
+
+ final int current = this.currentIndex;
+ if (current < 0) {
+ throw new NoSuchElementException("Iteration already finished.");
+ }
+
+ this.lastIndex = current;
+ this.currentIndex = findNext(current);
+
+ return (Header) this.allHeaders.get(current);
+ }
+
+
+ /**
+ * Returns the next header.
+ * Same as {@link #nextHeader nextHeader}, but not type-safe.
+ *
+ * @return the next header in this iteration
+ *
+ * @throws NoSuchElementException if there are no more headers
+ */
+ public final Object next()
+ throws NoSuchElementException {
+ return nextHeader();
+ }
+
+
+ /**
+ * Removes the header that was returned last.
+ */
+ public void remove()
+ throws UnsupportedOperationException {
+
+ if (this.lastIndex < 0) {
+ throw new IllegalStateException("No header to remove.");
+ }
+ this.allHeaders.remove(this.lastIndex);
+ this.lastIndex = -1;
+ this.currentIndex--; // adjust for the removed element
+ }
+}
diff --git a/src/org/apache/http/message/BasicNameValuePair.java b/src/org/apache/http/message/BasicNameValuePair.java
new file mode 100644
index 0000000..59fcb42
--- /dev/null
+++ b/src/org/apache/http/message/BasicNameValuePair.java
@@ -0,0 +1,189 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicNameValuePair.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.LangUtils;
+
+/**
+ * A simple class encapsulating an attribute/value pair.
+ * <p>
+ * This class comforms to the generic grammar and formatting rules outlined in the
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2">Section 2.2</a>
+ * and
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>
+ * of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>
+ * </p>
+ * <h>2.2 Basic Rules</h>
+ * <p>
+ * 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.
+ * </p>
+ * <pre>
+ * OCTET = <any 8-bit sequence of data>
+ * CHAR = <any US-ASCII character (octets 0 - 127)>
+ * UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ * LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ * ALPHA = UPALPHA | LOALPHA
+ * DIGIT = <any US-ASCII digit "0".."9">
+ * CTL = <any US-ASCII control character
+ * (octets 0 - 31) and DEL (127)>
+ * CR = <US-ASCII CR, carriage return (13)>
+ * LF = <US-ASCII LF, linefeed (10)>
+ * SP = <US-ASCII SP, space (32)>
+ * HT = <US-ASCII HT, horizontal-tab (9)>
+ * <"> = <US-ASCII double-quote mark (34)>
+ * </pre>
+ * <p>
+ * 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).
+ * <p>
+ * <pre>
+ * token = 1*<any CHAR except CTLs or separators>
+ * separators = "(" | ")" | "<" | ">" | "@"
+ * | "," | ";" | ":" | "\" | <">
+ * | "/" | "[" | "]" | "?" | "="
+ * | "{" | "}" | SP | HT
+ * </pre>
+ * <p>
+ * A string of text is parsed as a single word if it is quoted using double-quote marks.
+ * </p>
+ * <pre>
+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ * qdtext = <any TEXT except <">>
+ * </pre>
+ * <p>
+ * The backslash character ("\") MAY be used as a single-character quoting mechanism only
+ * within quoted-string and comment constructs.
+ * </p>
+ * <pre>
+ * quoted-pair = "\" CHAR
+ * </pre>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ * Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter = attribute "=" value
+ * attribute = token
+ * value = token | quoted-string
+ * </pre>
+ *
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ *
+ */
+public class BasicNameValuePair implements NameValuePair, Cloneable {
+
+ private final String name;
+ private final String value;
+
+ /**
+ * Default Constructor taking a name and a value. The value may be null.
+ *
+ * @param name The name.
+ * @param value The value.
+ */
+ public BasicNameValuePair(final String name, final String value) {
+ super();
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns the name.
+ *
+ * @return String name The name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the value.
+ *
+ * @return String value The current value.
+ */
+ public String getValue() {
+ return this.value;
+ }
+
+
+ /**
+ * Get a string representation of this pair.
+ *
+ * @return A string representation.
+ */
+ public String toString() {
+ // don't call complex default formatting for a simple toString
+
+ int len = this.name.length();
+ if (this.value != null)
+ len += 1 + this.value.length();
+ CharArrayBuffer buffer = new CharArrayBuffer(len);
+
+ buffer.append(this.name);
+ if (this.value != null) {
+ buffer.append("=");
+ buffer.append(this.value);
+ }
+ return buffer.toString();
+ }
+
+ public boolean equals(final Object object) {
+ if (object == null) return false;
+ if (this == object) return true;
+ if (object instanceof NameValuePair) {
+ BasicNameValuePair that = (BasicNameValuePair) object;
+ return this.name.equals(that.name)
+ && LangUtils.equals(this.value, that.value);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.name);
+ hash = LangUtils.hashCode(hash, this.value);
+ return hash;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicRequestLine.java b/src/org/apache/http/message/BasicRequestLine.java
new file mode 100644
index 0000000..b826064
--- /dev/null
+++ b/src/org/apache/http/message/BasicRequestLine.java
@@ -0,0 +1,99 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicRequestLine.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+
+/**
+ * The first line of an {@link org.apache.http.HttpRequest HttpRequest}.
+ * It contains the method, URI, and HTTP version of the request.
+ * For details, see RFC 2616.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 604625 $
+ *
+ * @since 4.0
+ */
+public class BasicRequestLine implements RequestLine, Cloneable {
+
+ private final ProtocolVersion protoversion;
+ private final String method;
+ private final String uri;
+
+ public BasicRequestLine(final String method,
+ final String uri,
+ final ProtocolVersion version) {
+ super();
+ if (method == null) {
+ throw new IllegalArgumentException
+ ("Method must not be null.");
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException
+ ("URI must not be null.");
+ }
+ if (version == null) {
+ throw new IllegalArgumentException
+ ("Protocol version must not be null.");
+ }
+ this.method = method;
+ this.uri = uri;
+ this.protoversion = version;
+ }
+
+ public String getMethod() {
+ return this.method;
+ }
+
+ public ProtocolVersion getProtocolVersion() {
+ return this.protoversion;
+ }
+
+ public String getUri() {
+ return this.uri;
+ }
+
+ public String toString() {
+ // no need for non-default formatting in toString()
+ return BasicLineFormatter.DEFAULT
+ .formatRequestLine(null, this).toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicStatusLine.java b/src/org/apache/http/message/BasicStatusLine.java
new file mode 100644
index 0000000..c34cefe
--- /dev/null
+++ b/src/org/apache/http/message/BasicStatusLine.java
@@ -0,0 +1,124 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicStatusLine.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+
+
+
+/**
+ * Represents a status line as returned from a HTTP server.
+ * See <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a> section 6.1.
+ * This class is immutable and therefore inherently thread safe.
+ *
+ * @see HttpStatus
+ * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @version $Id: BasicStatusLine.java 604625 2007-12-16 14:11:11Z olegk $
+ *
+ * @since 4.0
+ */
+public class BasicStatusLine implements StatusLine, Cloneable {
+
+ // ----------------------------------------------------- Instance Variables
+
+ /** The protocol version. */
+ private final ProtocolVersion protoVersion;
+
+ /** The status code. */
+ private final int statusCode;
+
+ /** The reason phrase. */
+ private final String reasonPhrase;
+
+ // ----------------------------------------------------------- Constructors
+ /**
+ * Creates a new status line with the given version, status, and reason.
+ *
+ * @param version the protocol version of the response
+ * @param statusCode the status code of the response
+ * @param reasonPhrase the reason phrase to the status code, or
+ * <code>null</code>
+ */
+ public BasicStatusLine(final ProtocolVersion version, int statusCode,
+ final String reasonPhrase) {
+ super();
+ if (version == null) {
+ throw new IllegalArgumentException
+ ("Protocol version may not be null.");
+ }
+ if (statusCode < 0) {
+ throw new IllegalArgumentException
+ ("Status code may not be negative.");
+ }
+ this.protoVersion = version;
+ this.statusCode = statusCode;
+ this.reasonPhrase = reasonPhrase;
+ }
+
+ // --------------------------------------------------------- Public Methods
+
+ /**
+ * @return the Status-Code
+ */
+ public int getStatusCode() {
+ return this.statusCode;
+ }
+
+ /**
+ * @return the HTTP-Version
+ */
+ public ProtocolVersion getProtocolVersion() {
+ return this.protoVersion;
+ }
+
+ /**
+ * @return the Reason-Phrase
+ */
+ public String getReasonPhrase() {
+ return this.reasonPhrase;
+ }
+
+ public String toString() {
+ // no need for non-default formatting in toString()
+ return BasicLineFormatter.DEFAULT
+ .formatStatusLine(null, this).toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/BasicTokenIterator.java b/src/org/apache/http/message/BasicTokenIterator.java
new file mode 100644
index 0000000..5fbf5ba
--- /dev/null
+++ b/src/org/apache/http/message/BasicTokenIterator.java
@@ -0,0 +1,429 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicTokenIterator.java $
+ * $Revision: 602520 $
+ * $Date: 2007-12-08 09:42:26 -0800 (Sat, 08 Dec 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.NoSuchElementException;
+
+import org.apache.http.HeaderIterator;
+import org.apache.http.ParseException;
+import org.apache.http.TokenIterator;
+
+/**
+ * Basic implementation of a {@link TokenIterator}.
+ * This implementation parses <tt>#token<tt> sequences as
+ * defined by RFC 2616, section 2.
+ * It extends that definition somewhat beyond US-ASCII.
+ *
+ * @version $Revision: 602520 $
+ */
+public class BasicTokenIterator implements TokenIterator {
+
+ /** The HTTP separator characters. Defined in RFC 2616, section 2.2. */
+ // the order of the characters here is adjusted to put the
+ // most likely candidates at the beginning of the collection
+ public final static String HTTP_SEPARATORS = " ,;=()<>@:\\\"/[]?{}\t";
+
+
+ /** The iterator from which to obtain the next header. */
+ protected final HeaderIterator headerIt;
+
+ /**
+ * The value of the current header.
+ * This is the header value that includes {@link #currentToken}.
+ * Undefined if the iteration is over.
+ */
+ protected String currentHeader;
+
+ /**
+ * The token to be returned by the next call to {@link #currentToken}.
+ * <code>null</code> if the iteration is over.
+ */
+ protected String currentToken;
+
+ /**
+ * The position after {@link #currentToken} in {@link #currentHeader}.
+ * Undefined if the iteration is over.
+ */
+ protected int searchPos;
+
+
+ /**
+ * Creates a new instance of {@link BasicTokenIterator}.
+ *
+ * @param headerIterator the iterator for the headers to tokenize
+ */
+ public BasicTokenIterator(final HeaderIterator headerIterator) {
+ if (headerIterator == null) {
+ throw new IllegalArgumentException
+ ("Header iterator must not be null.");
+ }
+
+ this.headerIt = headerIterator;
+ this.searchPos = findNext(-1);
+ }
+
+
+ // non-javadoc, see interface TokenIterator
+ public boolean hasNext() {
+ return (this.currentToken != null);
+ }
+
+
+ /**
+ * Obtains the next token from this iteration.
+ *
+ * @return the next token in this iteration
+ *
+ * @throws NoSuchElementException if the iteration is already over
+ * @throws ParseException if an invalid header value is encountered
+ */
+ public String nextToken()
+ throws NoSuchElementException, ParseException {
+
+ if (this.currentToken == null) {
+ throw new NoSuchElementException("Iteration already finished.");
+ }
+
+ final String result = this.currentToken;
+ // updates currentToken, may trigger ParseException:
+ this.searchPos = findNext(this.searchPos);
+
+ return result;
+ }
+
+
+ /**
+ * Returns the next token.
+ * Same as {@link #nextToken}, but with generic return type.
+ *
+ * @return the next token in this iteration
+ *
+ * @throws NoSuchElementException if there are no more tokens
+ * @throws ParseException if an invalid header value is encountered
+ */
+ public final Object next()
+ throws NoSuchElementException, ParseException {
+ return nextToken();
+ }
+
+
+ /**
+ * Removing tokens is not supported.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final void remove()
+ throws UnsupportedOperationException {
+
+ throw new UnsupportedOperationException
+ ("Removing tokens is not supported.");
+ }
+
+
+ /**
+ * Determines the next token.
+ * If found, the token is stored in {@link #currentToken}.
+ * The return value indicates the position after the token
+ * in {@link #currentHeader}. If necessary, the next header
+ * will be obtained from {@link #headerIt}.
+ * If not found, {@link #currentToken} is set to <code>null</code>.
+ *
+ * @param from the position in the current header at which to
+ * start the search, -1 to search in the first header
+ *
+ * @return the position after the found token in the current header, or
+ * negative if there was no next token
+ *
+ * @throws ParseException if an invalid header value is encountered
+ */
+ protected int findNext(int from)
+ throws ParseException {
+
+ if (from < 0) {
+ // called from the constructor, initialize the first header
+ if (!this.headerIt.hasNext()) {
+ return -1;
+ }
+ this.currentHeader = this.headerIt.nextHeader().getValue();
+ from = 0;
+ } else {
+ // called after a token, make sure there is a separator
+ from = findTokenSeparator(from);
+ }
+
+ int start = findTokenStart(from);
+ if (start < 0) {
+ this.currentToken = null;
+ return -1; // nothing found
+ }
+
+ int end = findTokenEnd(start);
+ this.currentToken = createToken(this.currentHeader, start, end);
+ return end;
+ }
+
+
+ /**
+ * Creates a new token to be returned.
+ * Called from {@link #findNext findNext} after the token is identified.
+ * The default implementation simply calls
+ * {@link java.lang.String#substring String.substring}.
+ * <br/>
+ * If header values are significantly longer than tokens, and some
+ * tokens are permanently referenced by the application, there can
+ * be problems with garbage collection. A substring will hold a
+ * reference to the full characters of the original string and
+ * therefore occupies more memory than might be expected.
+ * To avoid this, override this method and create a new string
+ * instead of a substring.
+ *
+ * @param value the full header value from which to create a token
+ * @param start the index of the first token character
+ * @param end the index after the last token character
+ *
+ * @return a string representing the token identified by the arguments
+ */
+ protected String createToken(String value, int start, int end) {
+ return value.substring(start, end);
+ }
+
+
+ /**
+ * Determines the starting position of the next token.
+ * This method will iterate over headers if necessary.
+ *
+ * @param from the position in the current header at which to
+ * start the search
+ *
+ * @return the position of the token start in the current header,
+ * negative if no token start could be found
+ */
+ protected int findTokenStart(int from) {
+ if (from < 0) {
+ throw new IllegalArgumentException
+ ("Search position must not be negative: " + from);
+ }
+
+ boolean found = false;
+ while (!found && (this.currentHeader != null)) {
+
+ final int to = this.currentHeader.length();
+ while (!found && (from < to)) {
+
+ final char ch = this.currentHeader.charAt(from);
+ if (isTokenSeparator(ch) || isWhitespace(ch)) {
+ // whitspace and token separators are skipped
+ from++;
+ } else if (isTokenChar(this.currentHeader.charAt(from))) {
+ // found the start of a token
+ found = true;
+ } else {
+ throw new ParseException
+ ("Invalid character before token (pos " + from +
+ "): " + this.currentHeader);
+ }
+ }
+ if (!found) {
+ if (this.headerIt.hasNext()) {
+ this.currentHeader = this.headerIt.nextHeader().getValue();
+ from = 0;
+ } else {
+ this.currentHeader = null;
+ }
+ }
+ } // while headers
+
+ return found ? from : -1;
+ }
+
+
+ /**
+ * Determines the position of the next token separator.
+ * Because of multi-header joining rules, the end of a
+ * header value is a token separator. This method does
+ * therefore not need to iterate over headers.
+ *
+ * @param from the position in the current header at which to
+ * start the search
+ *
+ * @return the position of a token separator in the current header,
+ * or at the end
+ *
+ * @throws ParseException
+ * if a new token is found before a token separator.
+ * RFC 2616, section 2.1 explicitly requires a comma between
+ * tokens for <tt>#</tt>.
+ */
+ protected int findTokenSeparator(int from) {
+ if (from < 0) {
+ throw new IllegalArgumentException
+ ("Search position must not be negative: " + from);
+ }
+
+ boolean found = false;
+ final int to = this.currentHeader.length();
+ while (!found && (from < to)) {
+ final char ch = this.currentHeader.charAt(from);
+ if (isTokenSeparator(ch)) {
+ found = true;
+ } else if (isWhitespace(ch)) {
+ from++;
+ } else if (isTokenChar(ch)) {
+ throw new ParseException
+ ("Tokens without separator (pos " + from +
+ "): " + this.currentHeader);
+ } else {
+ throw new ParseException
+ ("Invalid character after token (pos " + from +
+ "): " + this.currentHeader);
+ }
+ }
+
+ return from;
+ }
+
+
+ /**
+ * Determines the ending position of the current token.
+ * This method will not leave the current header value,
+ * since the end of the header value is a token boundary.
+ *
+ * @param from the position of the first character of the token
+ *
+ * @return the position after the last character of the token.
+ * The behavior is undefined if <code>from</code> does not
+ * point to a token character in the current header value.
+ */
+ protected int findTokenEnd(int from) {
+ if (from < 0) {
+ throw new IllegalArgumentException
+ ("Token start position must not be negative: " + from);
+ }
+
+ final int to = this.currentHeader.length();
+ int end = from+1;
+ while ((end < to) && isTokenChar(this.currentHeader.charAt(end))) {
+ end++;
+ }
+
+ return end;
+ }
+
+
+ /**
+ * Checks whether a character is a token separator.
+ * RFC 2616, section 2.1 defines comma as the separator for
+ * <tt>#token</tt> sequences. The end of a header value will
+ * also separate tokens, but that is not a character check.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is a token separator,
+ * <code>false</code> otherwise
+ */
+ protected boolean isTokenSeparator(char ch) {
+ return (ch == ',');
+ }
+
+
+ /**
+ * Checks whether a character is a whitespace character.
+ * RFC 2616, section 2.2 defines space and horizontal tab as whitespace.
+ * The optional preceeding line break is irrelevant, since header
+ * continuation is handled transparently when parsing messages.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is whitespace,
+ * <code>false</code> otherwise
+ */
+ protected boolean isWhitespace(char ch) {
+
+ // we do not use Character.isWhitspace(ch) here, since that allows
+ // many control characters which are not whitespace as per RFC 2616
+ return ((ch == '\t') || Character.isSpaceChar(ch));
+ }
+
+
+ /**
+ * Checks whether a character is a valid token character.
+ * Whitespace, control characters, and HTTP separators are not
+ * valid token characters. The HTTP specification (RFC 2616, section 2.2)
+ * defines tokens only for the US-ASCII character set, this
+ * method extends the definition to other character sets.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is a valid token start,
+ * <code>false</code> otherwise
+ */
+ protected boolean isTokenChar(char ch) {
+
+ // common sense extension of ALPHA + DIGIT
+ if (Character.isLetterOrDigit(ch))
+ return true;
+
+ // common sense extension of CTL
+ if (Character.isISOControl(ch))
+ return false;
+
+ // no common sense extension for this
+ if (isHttpSeparator(ch))
+ return false;
+
+ // RFC 2616, section 2.2 defines a token character as
+ // "any CHAR except CTLs or separators". The controls
+ // and separators are included in the checks above.
+ // This will yield unexpected results for Unicode format characters.
+ // If that is a problem, overwrite isHttpSeparator(char) to filter
+ // out the false positives.
+ return true;
+ }
+
+
+ /**
+ * Checks whether a character is an HTTP separator.
+ * The implementation in this class checks only for the HTTP separators
+ * defined in RFC 2616, section 2.2. If you need to detect other
+ * separators beyond the US-ASCII character set, override this method.
+ *
+ * @param ch the character to check
+ *
+ * @return <code>true</code> if the character is an HTTP separator
+ */
+ protected boolean isHttpSeparator(char ch) {
+ return (HTTP_SEPARATORS.indexOf(ch) >= 0);
+ }
+
+
+} // class BasicTokenIterator
+
diff --git a/src/org/apache/http/message/BufferedHeader.java b/src/org/apache/http/message/BufferedHeader.java
new file mode 100644
index 0000000..35c5cfc
--- /dev/null
+++ b/src/org/apache/http/message/BufferedHeader.java
@@ -0,0 +1,133 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BufferedHeader.java $
+ * $Revision: 604625 $
+ * $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.HeaderElement;
+import org.apache.http.ParseException;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * This class represents a raw HTTP header whose content is parsed 'on demand'
+ * only when the header value needs to be consumed.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 604625 $ $Date: 2007-12-16 06:11:11 -0800 (Sun, 16 Dec 2007) $
+ */
+public class BufferedHeader implements FormattedHeader, Cloneable {
+
+ /**
+ * Header name.
+ */
+ private final String name;
+
+ /**
+ * The buffer containing the entire header line.
+ */
+ private final CharArrayBuffer buffer;
+
+ /**
+ * The beginning of the header value in the buffer
+ */
+ private final int valuePos;
+
+
+ /**
+ * 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
+ *
+ * @throws ParseException in case of a parse error
+ */
+ public BufferedHeader(final CharArrayBuffer buffer)
+ throws ParseException {
+
+ super();
+ if (buffer == null) {
+ throw new IllegalArgumentException
+ ("Char array buffer may not be null");
+ }
+ int colon = buffer.indexOf(':');
+ if (colon == -1) {
+ throw new ParseException
+ ("Invalid header: " + buffer.toString());
+ }
+ String s = buffer.substringTrimmed(0, colon);
+ if (s.length() == 0) {
+ throw new ParseException
+ ("Invalid header: " + buffer.toString());
+ }
+ this.buffer = buffer;
+ this.name = s;
+ this.valuePos = colon + 1;
+ }
+
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getValue() {
+ return this.buffer.substringTrimmed(this.valuePos, this.buffer.length());
+ }
+
+ public HeaderElement[] getElements() throws ParseException {
+ ParserCursor cursor = new ParserCursor(0, this.buffer.length());
+ cursor.updatePos(this.valuePos);
+ return BasicHeaderValueParser.DEFAULT
+ .parseElements(this.buffer, cursor);
+ }
+
+ public int getValuePos() {
+ return this.valuePos;
+ }
+
+ public CharArrayBuffer getBuffer() {
+ return this.buffer;
+ }
+
+ public String toString() {
+ return this.buffer.toString();
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ // buffer is considered immutable
+ // no need to make a copy of it
+ return super.clone();
+ }
+
+}
diff --git a/src/org/apache/http/message/HeaderGroup.java b/src/org/apache/http/message/HeaderGroup.java
new file mode 100644
index 0000000..4e40db1
--- /dev/null
+++ b/src/org/apache/http/message/HeaderGroup.java
@@ -0,0 +1,295 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/HeaderGroup.java $
+ * $Revision: 659185 $
+ * $Date: 2008-05-22 11:07:36 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * A class for combining a set of headers.
+ * This class allows for multiple headers with the same name and
+ * keeps track of the order in which headers were added.
+ *
+ * @author Michael Becke
+ *
+ * @since 4.0
+ */
+public class HeaderGroup implements Cloneable {
+
+ /** The list of headers for this group, in the order in which they were added */
+ private List headers;
+
+ /**
+ * Constructor for HeaderGroup.
+ */
+ public HeaderGroup() {
+ this.headers = new ArrayList(16);
+ }
+
+ /**
+ * Removes any contained headers.
+ */
+ public void clear() {
+ headers.clear();
+ }
+
+ /**
+ * Adds the given header to the group. The order in which this header was
+ * added is preserved.
+ *
+ * @param header the header to add
+ */
+ public void addHeader(Header header) {
+ if (header == null) {
+ return;
+ }
+ headers.add(header);
+ }
+
+ /**
+ * Removes the given header.
+ *
+ * @param header the header to remove
+ */
+ public void removeHeader(Header header) {
+ if (header == null) {
+ return;
+ }
+ headers.remove(header);
+ }
+
+ /**
+ * Replaces the first occurence of the header with the same name. If no header with
+ * the same name is found the given header is added to the end of the list.
+ *
+ * @param header the new header that should replace the first header with the same
+ * name if present in the list.
+ */
+ public void updateHeader(Header header) {
+ if (header == null) {
+ return;
+ }
+ for (int i = 0; i < this.headers.size(); i++) {
+ Header current = (Header) this.headers.get(i);
+ if (current.getName().equalsIgnoreCase(header.getName())) {
+ this.headers.set(i, header);
+ return;
+ }
+ }
+ this.headers.add(header);
+ }
+
+ /**
+ * Sets all of the headers contained within this group overriding any
+ * existing headers. The headers are added in the order in which they appear
+ * in the array.
+ *
+ * @param headers the headers to set
+ */
+ public void setHeaders(Header[] headers) {
+ clear();
+ if (headers == null) {
+ return;
+ }
+ for (int i = 0; i < headers.length; i++) {
+ this.headers.add(headers[i]);
+ }
+ }
+
+ /**
+ * Gets a header representing all of the header values with the given name.
+ * If more that one header with the given name exists the values will be
+ * combined with a "," as per RFC 2616.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header(s) to get
+ * @return a header with a condensed value or <code>null</code> if no
+ * headers by the given name are present
+ */
+ public Header getCondensedHeader(String name) {
+ Header[] headers = getHeaders(name);
+
+ if (headers.length == 0) {
+ return null;
+ } else if (headers.length == 1) {
+ return headers[0];
+ } else {
+ CharArrayBuffer valueBuffer = new CharArrayBuffer(128);
+ valueBuffer.append(headers[0].getValue());
+ for (int i = 1; i < headers.length; i++) {
+ valueBuffer.append(", ");
+ valueBuffer.append(headers[i].getValue());
+ }
+
+ return new BasicHeader(name.toLowerCase(Locale.ENGLISH), valueBuffer.toString());
+ }
+ }
+
+ /**
+ * Gets all of the headers with the given name. The returned array
+ * maintains the relative order in which the headers were added.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header(s) to get
+ *
+ * @return an array of length >= 0
+ */
+ public Header[] getHeaders(String name) {
+ ArrayList headersFound = new ArrayList();
+
+ for (int i = 0; i < headers.size(); i++) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ headersFound.add(header);
+ }
+ }
+
+ return (Header[]) headersFound.toArray(new Header[headersFound.size()]);
+ }
+
+ /**
+ * Gets the first header with the given name.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header to get
+ * @return the first header or <code>null</code>
+ */
+ public Header getFirstHeader(String name) {
+ for (int i = 0; i < headers.size(); i++) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ return header;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the last header with the given name.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the name of the header to get
+ * @return the last header or <code>null</code>
+ */
+ public Header getLastHeader(String name) {
+ // start at the end of the list and work backwards
+ for (int i = headers.size() - 1; i >= 0; i--) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ return header;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets all of the headers contained within this group.
+ *
+ * @return an array of length >= 0
+ */
+ public Header[] getAllHeaders() {
+ return (Header[]) headers.toArray(new Header[headers.size()]);
+ }
+
+ /**
+ * Tests if headers with the given name are contained within this group.
+ *
+ * <p>Header name comparison is case insensitive.
+ *
+ * @param name the header name to test for
+ * @return <code>true</code> if at least one header with the name is
+ * contained, <code>false</code> otherwise
+ */
+ public boolean containsHeader(String name) {
+ for (int i = 0; i < headers.size(); i++) {
+ Header header = (Header) headers.get(i);
+ if (header.getName().equalsIgnoreCase(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an iterator over this group of headers.
+ *
+ * @return iterator over this group of headers.
+ *
+ * @since 4.0
+ */
+ public HeaderIterator iterator() {
+ return new BasicListHeaderIterator(this.headers, null);
+ }
+
+ /**
+ * Returns an iterator over the headers with a given name in this group.
+ *
+ * @param name the name of the headers over which to iterate, or
+ * <code>null</code> for all headers
+ *
+ * @return iterator over some headers in this group.
+ *
+ * @since 4.0
+ */
+ public HeaderIterator iterator(final String name) {
+ return new BasicListHeaderIterator(this.headers, name);
+ }
+
+ /**
+ * Returns a copy of this object
+ *
+ * @return copy of this object
+ */
+ public HeaderGroup copy() {
+ HeaderGroup clone = new HeaderGroup();
+ clone.headers.addAll(this.headers);
+ return clone;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ HeaderGroup clone = (HeaderGroup) super.clone();
+ clone.headers = new ArrayList(this.headers);
+ return clone;
+ }
+
+}
diff --git a/src/org/apache/http/message/HeaderValueFormatter.java b/src/org/apache/http/message/HeaderValueFormatter.java
new file mode 100644
index 0000000..4f6351f
--- /dev/null
+++ b/src/org/apache/http/message/HeaderValueFormatter.java
@@ -0,0 +1,141 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/HeaderValueFormatter.java $
+ * $Revision: 571954 $
+ * $Date: 2007-09-02 04:05:21 -0700 (Sun, 02 Sep 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.util.CharArrayBuffer;
+
+
+
+/**
+ * Interface for formatting elements of a header value.
+ * This is the complement to {@link HeaderValueParser}.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * <p>
+ * All formatting methods accept an optional buffer argument.
+ * If a buffer is passed in, the formatted element will be appended
+ * and the modified buffer is returned. If no buffer is passed in,
+ * a new buffer will be created and filled with the formatted element.
+ * In both cases, the caller is allowed to modify the returned buffer.
+ * </p>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 571954 $
+ *
+ * @since 4.0
+ */
+public interface HeaderValueFormatter {
+
+ /**
+ * Formats an array of header elements.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param elems the header elements to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted header elements.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatElements(CharArrayBuffer buffer,
+ HeaderElement[] elems,
+ boolean quote)
+ ;
+
+
+ /**
+ * Formats one header element.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param elem the header element to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted header element.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatHeaderElement(CharArrayBuffer buffer,
+ HeaderElement elem,
+ boolean quote)
+ ;
+
+
+
+ /**
+ * Formats the parameters of a header element.
+ * That's a list of name-value pairs, to be separated by semicolons.
+ * This method will <i>not</i> generate a leading semicolon.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param nvps the parameters (name-value pairs) to format
+ * @param quote <code>true</code> to always format with quoted values,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted parameters.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatParameters(CharArrayBuffer buffer,
+ NameValuePair[] nvps,
+ boolean quote)
+ ;
+
+
+ /**
+ * Formats one name-value pair, where the value is optional.
+ *
+ * @param buffer the buffer to append to, or
+ * <code>null</code> to create a new buffer
+ * @param nvp the name-value pair to format
+ * @param quote <code>true</code> to always format with a quoted value,
+ * <code>false</code> to use quotes only when necessary
+ *
+ * @return a buffer with the formatted name-value pair.
+ * If the <code>buffer</code> argument was not <code>null</code>,
+ * that buffer will be used and returned.
+ */
+ CharArrayBuffer formatNameValuePair(CharArrayBuffer buffer,
+ NameValuePair nvp,
+ boolean quote)
+ ;
+
+}
+
diff --git a/src/org/apache/http/message/HeaderValueParser.java b/src/org/apache/http/message/HeaderValueParser.java
new file mode 100644
index 0000000..74bb93c
--- /dev/null
+++ b/src/org/apache/http/message/HeaderValueParser.java
@@ -0,0 +1,214 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/HeaderValueParser.java $
+ * $Revision: 589325 $
+ * $Date: 2007-10-28 03:37:56 -0700 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.ParseException;
+import org.apache.http.util.CharArrayBuffer;
+
+
+
+/**
+ * Interface for parsing header values into elements.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 589325 $ $Date: 2007-10-28 03:37:56 -0700 (Sun, 28 Oct 2007) $
+ *
+ * @since 4.0
+ */
+public interface HeaderValueParser {
+
+ /**
+ * Parses a header value into elements.
+ * Parse errors are indicated as <code>RuntimeException</code>.
+ * <p>
+ * 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:
+ * </p>
+ * <pre>
+ * header = [ element ] *( "," [ element ] )
+ * element = name [ "=" [ value ] ] *( ";" [ param ] )
+ * param = name [ "=" [ value ] ]
+ *
+ * name = token
+ * value = ( token | quoted-string )
+ *
+ * token = 1*&lt;any char except "=", ",", ";", &lt;"&gt; and
+ * white space&gt;
+ * quoted-string = &lt;"&gt; *( text | quoted-char ) &lt;"&gt;
+ * text = any char except &lt;"&gt;
+ * quoted-char = "\" char
+ * </pre>
+ * <p>
+ * 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 <var>null</var> will be stored instead.
+ * </p>
+ *
+ * @param buffer buffer holding the header value to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return an array holding all elements of the header value
+ *
+ * @throws ParseException in case of a parse error
+ */
+ HeaderElement[] parseElements(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+ /**
+ * Parses a single header element.
+ * A header element consist of a semicolon-separate list
+ * of name=value definitions.
+ *
+ * @param buffer buffer holding the element to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed element
+ *
+ * @throws ParseException in case of a parse error
+ */
+ HeaderElement parseHeaderElement(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+ /**
+ * Parses a list of name-value pairs.
+ * These lists are used to specify parameters to a header element.
+ * Parse errors are indicated as <code>RuntimeException</code>.
+ * <p>
+ * This method comforms to the generic grammar and formatting rules
+ * outlined in the
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2"
+ * >Section 2.2</a>
+ * and
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6"
+ * >Section 3.6</a>
+ * of
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>.
+ * </p>
+ * <h>2.2 Basic Rules</h>
+ * <p>
+ * 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.
+ * </p>
+ * <pre>
+ * OCTET = <any 8-bit sequence of data>
+ * CHAR = <any US-ASCII character (octets 0 - 127)>
+ * UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ * LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ * ALPHA = UPALPHA | LOALPHA
+ * DIGIT = <any US-ASCII digit "0".."9">
+ * CTL = <any US-ASCII control character
+ * (octets 0 - 31) and DEL (127)>
+ * CR = <US-ASCII CR, carriage return (13)>
+ * LF = <US-ASCII LF, linefeed (10)>
+ * SP = <US-ASCII SP, space (32)>
+ * HT = <US-ASCII HT, horizontal-tab (9)>
+ * <"> = <US-ASCII double-quote mark (34)>
+ * </pre>
+ * <p>
+ * 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).
+ * <p>
+ * <pre>
+ * token = 1*<any CHAR except CTLs or separators>
+ * separators = "(" | ")" | "<" | ">" | "@"
+ * | "," | ";" | ":" | "\" | <">
+ * | "/" | "[" | "]" | "?" | "="
+ * | "{" | "}" | SP | HT
+ * </pre>
+ * <p>
+ * A string of text is parsed as a single word if it is quoted using
+ * double-quote marks.
+ * </p>
+ * <pre>
+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ * qdtext = <any TEXT except <">>
+ * </pre>
+ * <p>
+ * The backslash character ("\") MAY be used as a single-character
+ * quoting mechanism only within quoted-string and comment constructs.
+ * </p>
+ * <pre>
+ * quoted-pair = "\" CHAR
+ * </pre>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ * Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter = attribute "=" value
+ * attribute = token
+ * value = token | quoted-string
+ * </pre>
+ *
+ * @param buffer buffer holding the name-value list to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return an array holding all items of the name-value list
+ *
+ * @throws ParseException in case of a parse error
+ */
+ NameValuePair[] parseParameters(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Parses a name=value specification, where the = and value are optional.
+ *
+ * @param buffer the buffer holding the name-value pair to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the name-value pair, where the value is <code>null</code>
+ * if no value is specified
+ */
+ NameValuePair parseNameValuePair(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+}
+
diff --git a/src/org/apache/http/message/LineFormatter.java b/src/org/apache/http/message/LineFormatter.java
new file mode 100644
index 0000000..ccc603c
--- /dev/null
+++ b/src/org/apache/http/message/LineFormatter.java
@@ -0,0 +1,153 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/LineFormatter.java $
+ * $Revision: 573864 $
+ * $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Interface for formatting elements of the HEAD section of an HTTP message.
+ * This is the complement to {@link LineParser}.
+ * There are individual methods for formatting a request line, a
+ * status line, or a header line. The formatting does <i>not</i> include the
+ * trailing line break sequence CR-LF.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * <p>
+ * The formatted lines are returned in memory, the formatter does not depend
+ * on any specific IO mechanism.
+ * In order to avoid unnecessary creation of temporary objects,
+ * a buffer can be passed as argument to all formatting methods.
+ * The implementation may or may not actually use that buffer for formatting.
+ * If it is used, the buffer will first be cleared by the
+ * <code>formatXXX</code> methods.
+ * The argument buffer can always be re-used after the call. The buffer
+ * returned as the result, if it is different from the argument buffer,
+ * MUST NOT be modified.
+ * </p>
+ *
+ *
+ * @author <a href="mailto:rolandw AT apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 573864 $ $Date: 2007-09-08 08:53:25 -0700 (Sat, 08 Sep 2007) $
+ *
+ * @since 4.0
+ */
+public interface LineFormatter {
+
+
+
+ /**
+ * Formats a protocol version.
+ * This method does <i>not</i> follow the general contract for
+ * <code>buffer</code> arguments.
+ * It does <i>not</i> clear the argument buffer, but appends instead.
+ * The returned buffer can always be modified by the caller.
+ * Because of these differing conventions, it is not named
+ * <code>formatProtocolVersion</code>.
+ *
+ * @param buffer a buffer to which to append, or <code>null</code>
+ * @param version the protocol version to format
+ *
+ * @return a buffer with the formatted protocol version appended.
+ * The caller is allowed to modify the result buffer.
+ * If the <code>buffer</code> argument is not <code>null</code>,
+ * the returned buffer is the argument buffer.
+ */
+ CharArrayBuffer appendProtocolVersion(CharArrayBuffer buffer,
+ ProtocolVersion version)
+ ;
+
+
+ /**
+ * Formats a request line.
+ *
+ * @param buffer a buffer available for formatting, or
+ * <code>null</code>.
+ * The buffer will be cleared before use.
+ * @param reqline the request line to format
+ *
+ * @return the formatted request line
+ */
+ CharArrayBuffer formatRequestLine(CharArrayBuffer buffer,
+ RequestLine reqline)
+ ;
+
+
+ /**
+ * Formats a status line.
+ *
+ * @param buffer a buffer available for formatting, or
+ * <code>null</code>.
+ * The buffer will be cleared before use.
+ * @param statline the status line to format
+ *
+ * @return the formatted status line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ CharArrayBuffer formatStatusLine(CharArrayBuffer buffer,
+ StatusLine statline)
+ ;
+
+
+ /**
+ * Formats a header.
+ * Due to header continuation, the result may be multiple lines.
+ * In order to generate well-formed HTTP, the lines in the result
+ * must be separated by the HTTP line break sequence CR-LF.
+ * There is <i>no</i> trailing CR-LF in the result.
+ * <br/>
+ * See the class comment for details about the buffer argument.
+ *
+ * @param buffer a buffer available for formatting, or
+ * <code>null</code>.
+ * The buffer will be cleared before use.
+ * @param header the header to format
+ *
+ * @return a buffer holding the formatted header, never <code>null</code>.
+ * The returned buffer may be different from the argument buffer.
+ *
+ * @throws ParseException in case of a parse error
+ */
+ CharArrayBuffer formatHeader(CharArrayBuffer buffer,
+ Header header)
+ ;
+
+}
diff --git a/src/org/apache/http/message/LineParser.java b/src/org/apache/http/message/LineParser.java
new file mode 100644
index 0000000..d1bcd15
--- /dev/null
+++ b/src/org/apache/http/message/LineParser.java
@@ -0,0 +1,156 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/LineParser.java $
+ * $Revision: 589374 $
+ * $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+
+import org.apache.http.ProtocolVersion;
+import org.apache.http.ParseException;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+import org.apache.http.Header;
+import org.apache.http.util.CharArrayBuffer;
+
+
+/**
+ * Interface for parsing lines in the HEAD section of an HTTP message.
+ * There are individual methods for parsing a request line, a
+ * status line, or a header line.
+ * The lines to parse are passed in memory, the parser does not depend
+ * on any specific IO mechanism.
+ * Instances of this interface are expected to be stateless and thread-safe.
+ *
+ * @author <a href="mailto:rolandw AT apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines above to avoid 'svn diff' context problems -->
+ * @version $Revision: 589374 $ $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $
+ *
+ * @since 4.0
+ */
+public interface LineParser {
+
+
+ /**
+ * Parses the textual representation of a protocol version.
+ * This is needed for parsing request lines (last element)
+ * as well as status lines (first element).
+ *
+ * @param buffer a buffer holding the protocol version to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed protocol version
+ *
+ * @throws ParseException in case of a parse error
+ */
+ ProtocolVersion parseProtocolVersion(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Checks whether there likely is a protocol version in a line.
+ * This method implements a <i>heuristic</i> to check for a
+ * likely protocol version specification. It does <i>not</i>
+ * guarantee that {@link #parseProtocolVersion} would not
+ * detect a parse error.
+ * This can be used to detect garbage lines before a request
+ * or status line.
+ *
+ * @param buffer a buffer holding the line to inspect
+ * @param cursor the cursor at which to check for a protocol version, or
+ * negative for "end of line". Whether the check tolerates
+ * whitespace before or after the protocol version is
+ * implementation dependent.
+ *
+ * @return <code>true</code> if there is a protocol version at the
+ * argument index (possibly ignoring whitespace),
+ * <code>false</code> otherwise
+ */
+ boolean hasProtocolVersion(
+ CharArrayBuffer buffer,
+ ParserCursor cursor);
+
+
+ /**
+ * Parses a request line.
+ *
+ * @param buffer a buffer holding the line to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed request line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ RequestLine parseRequestLine(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Parses a status line.
+ *
+ * @param buffer a buffer holding the line to parse
+ * @param cursor the parser cursor containing the current position and
+ * the bounds within the buffer for the parsing operation
+ *
+ * @return the parsed status line
+ *
+ * @throws ParseException in case of a parse error
+ */
+ StatusLine parseStatusLine(
+ CharArrayBuffer buffer,
+ ParserCursor cursor) throws ParseException;
+
+
+ /**
+ * Creates a header from a line.
+ * The full header line is expected here. Header continuation lines
+ * must be joined by the caller before invoking this method.
+ *
+ * @param buffer a buffer holding the full header line.
+ * This buffer MUST NOT be re-used afterwards, since
+ * the returned object may reference the contents later.
+ *
+ * @return the header in the argument buffer.
+ * The returned object MAY be a wrapper for the argument buffer.
+ * The argument buffer MUST NOT be re-used or changed afterwards.
+ *
+ * @throws ParseException in case of a parse error
+ */
+ Header parseHeader(CharArrayBuffer buffer)
+ throws ParseException
+ ;
+
+
+}
diff --git a/src/org/apache/http/message/ParserCursor.java b/src/org/apache/http/message/ParserCursor.java
new file mode 100644
index 0000000..d030675
--- /dev/null
+++ b/src/org/apache/http/message/ParserCursor.java
@@ -0,0 +1,102 @@
+/*
+ * $HeadURL:https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/ParserCursor.java $
+ * $Revision:589325 $
+ * $Date:2007-10-28 11:37:56 +0100 (Sun, 28 Oct 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.message;
+
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * This class represents a context of a parsing operation:
+ * <ul>
+ * <li>the current position the parsing operation is expected to start at</li>
+ * <li>the bounds limiting the scope of the parsing operation</li>
+ * </ul>
+ *
+ * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
+ */
+public class ParserCursor {
+
+ private final int lowerBound;
+ private final int upperBound;
+ private int pos;
+
+ public ParserCursor(int lowerBound, int upperBound) {
+ super();
+ if (lowerBound < 0) {
+ throw new IndexOutOfBoundsException("Lower bound cannot be negative");
+ }
+ if (lowerBound > upperBound) {
+ throw new IndexOutOfBoundsException("Lower bound cannot be greater then upper bound");
+ }
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ this.pos = lowerBound;
+ }
+
+ public int getLowerBound() {
+ return this.lowerBound;
+ }
+
+ public int getUpperBound() {
+ return this.upperBound;
+ }
+
+ public int getPos() {
+ return this.pos;
+ }
+
+ public void updatePos(int pos) {
+ if (pos < this.lowerBound) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (pos > this.upperBound) {
+ throw new IndexOutOfBoundsException();
+ }
+ this.pos = pos;
+ }
+
+ public boolean atEnd() {
+ return this.pos >= this.upperBound;
+ }
+
+ public String toString() {
+ CharArrayBuffer buffer = new CharArrayBuffer(16);
+ buffer.append('[');
+ buffer.append(Integer.toString(this.lowerBound));
+ buffer.append('>');
+ buffer.append(Integer.toString(this.pos));
+ buffer.append('>');
+ buffer.append(Integer.toString(this.upperBound));
+ buffer.append(']');
+ return buffer.toString();
+ }
+
+}
diff --git a/src/org/apache/http/message/package.html b/src/org/apache/http/message/package.html
new file mode 100644
index 0000000..88ee617
--- /dev/null
+++ b/src/org/apache/http/message/package.html
@@ -0,0 +1,49 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/package.html $
+ * $Revision: 539755 $
+ * $Date: 2007-05-19 07:05:02 -0700 (Sat, 19 May 2007) $
+ *
+ * ====================================================================
+ * 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
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+A selection of HTTP
+{@link org.apache.http.message.AbstractHttpMessage message}
+implementations.
+
+There are basic implementations for HTTP requests
+{@link org.apache.http.message.BasicHttpEntityEnclosingRequest with}
+and {@link org.apache.http.message.BasicHttpRequest without}
+an entity, and for
+{@link org.apache.http.message.BasicHttpResponse responses}.
+
+
+</body>
+</html>