diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 417f3b92ba4549b2f22340e3107d869d2b9c5bb8 (patch) | |
tree | 2e08a2a91d6d14995df54490e3667f7943fbc6d6 /src/org/apache/http/message | |
download | external_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')
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 = <the OCTETs making up the field-value + * and consisting of either *TEXT or combinations + * of token, separators, and quoted-string> + *</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*<any char except "=", ",", ";", <"> and + * white space> + * quoted-string = <"> *( text | quoted-char ) <"> + * text = any char except <"> + * 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*<any char except "=", ",", ";", <"> and + * white space> + * quoted-string = <"> *( text | quoted-char ) <"> + * text = any char except <"> + * 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> |