diff options
Diffstat (limited to 'mobile/android/thirdparty/ch/boye/httpclientandroidlib/message')
25 files changed, 4701 insertions, 0 deletions
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/AbstractHttpMessage.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/AbstractHttpMessage.java new file mode 100644 index 000000000..24f7aef4e --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/AbstractHttpMessage.java @@ -0,0 +1,164 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HeaderIterator; +import ch.boye.httpclientandroidlib.HttpMessage; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.params.BasicHttpParams; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Basic implementation of {@link HttpMessage}. + * + * @since 4.0 + */ +@SuppressWarnings("deprecation") +@NotThreadSafe +public abstract class AbstractHttpMessage implements HttpMessage { + + protected HeaderGroup headergroup; + + @Deprecated + protected HttpParams params; + + /** + * @deprecated (4.3) use {@link AbstractHttpMessage#AbstractHttpMessage()} + */ + @Deprecated + 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(final 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) { + Args.notNull(name, "Header name"); + 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) { + Args.notNull(name, "Header name"); + 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 (final HeaderIterator i = this.headergroup.iterator(); i.hasNext(); ) { + final Header header = i.nextHeader(); + 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(final String name) { + return this.headergroup.iterator(name); + } + + /** + * @deprecated (4.3) use constructor parameters of configuration API provided by HttpClient + */ + @Deprecated + public HttpParams getParams() { + if (this.params == null) { + this.params = new BasicHttpParams(); + } + return this.params; + } + + /** + * @deprecated (4.3) use constructor parameters of configuration API provided by HttpClient + */ + @Deprecated + public void setParams(final HttpParams params) { + this.params = Args.notNull(params, "HTTP parameters"); + } +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeader.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeader.java new file mode 100644 index 000000000..170bf6bfe --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeader.java @@ -0,0 +1,91 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.io.Serializable; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Basic implementation of {@link Header}. + * + * @since 4.0 + */ +@Immutable +public class BasicHeader implements Header, Cloneable, Serializable { + + private static final long serialVersionUID = -5427236326487562174L; + + private final String name; + 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(); + this.name = Args.notNull(name, "Name"); + this.value = value; + } + + public String getName() { + return this.name; + } + + public String getValue() { + return this.value; + } + + @Override + public String toString() { + // no need for non-default formatting in toString() + return BasicLineFormatter.INSTANCE.formatHeader(null, this).toString(); + } + + 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[] {}; + } + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderElement.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderElement.java new file mode 100644 index 000000000..e815f2cb1 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderElement.java @@ -0,0 +1,162 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.NameValuePair; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.LangUtils; + +/** + * Basic implementation of {@link HeaderElement} + * + * @since 4.0 + */ +@NotThreadSafe +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(); + this.name = Args.notNull(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); + } + + public String getName() { + return this.name; + } + + public String getValue() { + return this.value; + } + + public NameValuePair[] getParameters() { + return this.parameters.clone(); + } + + public int getParameterCount() { + return this.parameters.length; + } + + public NameValuePair getParameter(final int index) { + // ArrayIndexOutOfBoundsException is appropriate + return this.parameters[index]; + } + + public NameValuePair getParameterByName(final String name) { + Args.notNull(name, "Name"); + NameValuePair found = null; + for (final NameValuePair current : this.parameters) { + if (current.getName().equalsIgnoreCase(name)) { + found = current; + break; + } + } + return found; + } + + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (object instanceof HeaderElement) { + final 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; + } + } + + @Override + public int hashCode() { + int hash = LangUtils.HASH_SEED; + hash = LangUtils.hashCode(hash, this.name); + hash = LangUtils.hashCode(hash, this.value); + for (final NameValuePair parameter : this.parameters) { + hash = LangUtils.hashCode(hash, parameter); + } + return hash; + } + + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append(this.name); + if (this.value != null) { + buffer.append("="); + buffer.append(this.value); + } + for (final NameValuePair parameter : this.parameters) { + buffer.append("; "); + buffer.append(parameter); + } + return buffer.toString(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + // parameters array is considered immutable + // no need to make a copy of it + return super.clone(); + } + +} + diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderElementIterator.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderElementIterator.java new file mode 100644 index 000000000..f14f00f0d --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderElementIterator.java @@ -0,0 +1,151 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.util.NoSuchElementException; + +import ch.boye.httpclientandroidlib.FormattedHeader; +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.HeaderElementIterator; +import ch.boye.httpclientandroidlib.HeaderIterator; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Basic implementation of a {@link HeaderElementIterator}. + * + * @since 4.0 + */ +@NotThreadSafe +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) { + this.headerIt = Args.notNull(headerIterator, "Header iterator"); + this.parser = Args.notNull(parser, "Parser"); + } + + + public BasicHeaderElementIterator(final HeaderIterator headerIterator) { + this(headerIterator, BasicHeaderValueParser.INSTANCE); + } + + + private void bufferHeaderValue() { + this.cursor = null; + this.buffer = null; + while (this.headerIt.hasNext()) { + final 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 { + final 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()) { + final 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"); + } + + final 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"); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderIterator.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderIterator.java new file mode 100644 index 000000000..5c8c87fbf --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderIterator.java @@ -0,0 +1,175 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.util.NoSuchElementException; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HeaderIterator; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Basic implementation of a {@link HeaderIterator}. + * + * @since 4.0 + */ +@NotThreadSafe +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(final Header[] headers, final String name) { + super(); + this.allHeaders = Args.notNull(headers, "Header array"); + this.headerName = name; + this.currentIndex = findNext(-1); + } + + + /** + * Determines the index of the next header. + * + * @param pos 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(final int pos) { + int from = pos; + 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(final 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/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderValueFormatter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderValueFormatter.java new file mode 100644 index 000000000..b7e731759 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderValueFormatter.java @@ -0,0 +1,422 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.NameValuePair; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.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. + * + * @since 4.0 + */ +@Immutable +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. + * + * @deprecated (4.3) use {@link #INSTANCE} + */ + @Deprecated + public final static + BasicHeaderValueFormatter DEFAULT = new BasicHeaderValueFormatter(); + + public final static BasicHeaderValueFormatter INSTANCE = 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 BasicHeaderValueFormatter() { + super(); + } + + /** + * 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 #INSTANCE default} + * + * @return the formatted header elements + */ + public static + String formatElements(final HeaderElement[] elems, + final boolean quote, + final HeaderValueFormatter formatter) { + return (formatter != null ? formatter : BasicHeaderValueFormatter.INSTANCE) + .formatElements(null, elems, quote).toString(); + } + + + // non-javadoc, see interface HeaderValueFormatter + public CharArrayBuffer formatElements(final CharArrayBuffer charBuffer, + final HeaderElement[] elems, + final boolean quote) { + Args.notNull(elems, "Header element array"); + final int len = estimateElementsLen(elems); + CharArrayBuffer buffer = charBuffer; + 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 (final HeaderElement elem : elems) { + result += estimateHeaderElementLen(elem); + } + + 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 #INSTANCE default} + * + * @return the formatted header element + */ + public static + String formatHeaderElement(final HeaderElement elem, + final boolean quote, + final HeaderValueFormatter formatter) { + return (formatter != null ? formatter : BasicHeaderValueFormatter.INSTANCE) + .formatHeaderElement(null, elem, quote).toString(); + } + + + // non-javadoc, see interface HeaderValueFormatter + public CharArrayBuffer formatHeaderElement(final CharArrayBuffer charBuffer, + final HeaderElement elem, + final boolean quote) { + Args.notNull(elem, "Header element"); + final int len = estimateHeaderElementLen(elem); + CharArrayBuffer buffer = charBuffer; + 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 #INSTANCE default} + * + * @return the formatted parameters + */ + public static + String formatParameters(final NameValuePair[] nvps, + final boolean quote, + final HeaderValueFormatter formatter) { + return (formatter != null ? formatter : BasicHeaderValueFormatter.INSTANCE) + .formatParameters(null, nvps, quote).toString(); + } + + + // non-javadoc, see interface HeaderValueFormatter + public CharArrayBuffer formatParameters(final CharArrayBuffer charBuffer, + final NameValuePair[] nvps, + final boolean quote) { + Args.notNull(nvps, "Header parameter array"); + final int len = estimateParametersLen(nvps); + CharArrayBuffer buffer = charBuffer; + 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 (final NameValuePair nvp : nvps) { + result += estimateNameValuePairLen(nvp); + } + + 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 #INSTANCE default} + * + * @return the formatted name-value pair + */ + public static + String formatNameValuePair(final NameValuePair nvp, + final boolean quote, + final HeaderValueFormatter formatter) { + return (formatter != null ? formatter : BasicHeaderValueFormatter.INSTANCE) + .formatNameValuePair(null, nvp, quote).toString(); + } + + + // non-javadoc, see interface HeaderValueFormatter + public CharArrayBuffer formatNameValuePair(final CharArrayBuffer charBuffer, + final NameValuePair nvp, + final boolean quote) { + Args.notNull(nvp, "Name / value pair"); + final int len = estimateNameValuePairLen(nvp); + CharArrayBuffer buffer = charBuffer; + 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, + final boolean quote) { + + boolean quoteFlag = quote; + if (!quoteFlag) { + for (int i = 0; (i < value.length()) && !quoteFlag; i++) { + quoteFlag = isSeparator(value.charAt(i)); + } + } + + if (quoteFlag) { + buffer.append('"'); + } + for (int i = 0; i < value.length(); i++) { + final char ch = value.charAt(i); + if (isUnsafe(ch)) { + buffer.append('\\'); + } + buffer.append(ch); + } + if (quoteFlag) { + 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(final 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(final char ch) { + return UNSAFE_CHARS.indexOf(ch) >= 0; + } + + +} // class BasicHeaderValueFormatter diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderValueParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderValueParser.java new file mode 100644 index 000000000..2e23b23bf --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHeaderValueParser.java @@ -0,0 +1,359 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.util.ArrayList; +import java.util.List; + +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.NameValuePair; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.protocol.HTTP; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.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. + * + * @since 4.0 + */ +@Immutable +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. + * + * @deprecated (4.3) use {@link #INSTANCE} + */ + @Deprecated + public final static + BasicHeaderValueParser DEFAULT = new BasicHeaderValueParser(); + + public final static BasicHeaderValueParser INSTANCE = 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 BasicHeaderValueParser() { + super(); + } + + /** + * 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 static + HeaderElement[] parseElements(final String value, + final HeaderValueParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + final ParserCursor cursor = new ParserCursor(0, value.length()); + return (parser != null ? parser : BasicHeaderValueParser.INSTANCE) + .parseElements(buffer, cursor); + } + + + // non-javadoc, see interface HeaderValueParser + public HeaderElement[] parseElements(final CharArrayBuffer buffer, + final ParserCursor cursor) { + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + final List<HeaderElement> elements = new ArrayList<HeaderElement>(); + while (!cursor.atEnd()) { + final HeaderElement element = parseHeaderElement(buffer, cursor); + if (!(element.getName().length() == 0 && element.getValue() == null)) { + elements.add(element); + } + } + return 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 static + HeaderElement parseHeaderElement(final String value, + final HeaderValueParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + final ParserCursor cursor = new ParserCursor(0, value.length()); + return (parser != null ? parser : BasicHeaderValueParser.INSTANCE) + .parseHeaderElement(buffer, cursor); + } + + + // non-javadoc, see interface HeaderValueParser + public HeaderElement parseHeaderElement(final CharArrayBuffer buffer, + final ParserCursor cursor) { + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + final NameValuePair nvp = parseNameValuePair(buffer, cursor); + NameValuePair[] params = null; + if (!cursor.atEnd()) { + final 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 static + NameValuePair[] parseParameters(final String value, + final HeaderValueParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + final ParserCursor cursor = new ParserCursor(0, value.length()); + return (parser != null ? parser : BasicHeaderValueParser.INSTANCE) + .parseParameters(buffer, cursor); + } + + + + // non-javadoc, see interface HeaderValueParser + public NameValuePair[] parseParameters(final CharArrayBuffer buffer, + final ParserCursor cursor) { + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + int pos = cursor.getPos(); + final int indexTo = cursor.getUpperBound(); + + while (pos < indexTo) { + final char ch = buffer.charAt(pos); + if (HTTP.isWhitespace(ch)) { + pos++; + } else { + break; + } + } + cursor.updatePos(pos); + if (cursor.atEnd()) { + return new NameValuePair[] {}; + } + + final List<NameValuePair> params = new ArrayList<NameValuePair>(); + while (!cursor.atEnd()) { + final NameValuePair param = parseNameValuePair(buffer, cursor); + params.add(param); + final char ch = buffer.charAt(cursor.getPos() - 1); + if (ch == ELEM_DELIMITER) { + break; + } + } + + return 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 static + NameValuePair parseNameValuePair(final String value, + final HeaderValueParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + final ParserCursor cursor = new ParserCursor(0, value.length()); + return (parser != null ? parser : BasicHeaderValueParser.INSTANCE) + .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 (final char ch2 : chs) { + if (ch == ch2) { + return true; + } + } + } + return false; + } + + public NameValuePair parseNameValuePair(final CharArrayBuffer buffer, + final ParserCursor cursor, + final char[] delimiters) { + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + + boolean terminated = false; + + int pos = cursor.getPos(); + final int indexFrom = cursor.getPos(); + final int indexTo = cursor.getUpperBound(); + + // Find name + final String name; + while (pos < indexTo) { + final 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 + final String value; + int i1 = pos; + + boolean qouted = false; + boolean escaped = false; + while (pos < indexTo) { + final 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/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpEntityEnclosingRequest.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpEntityEnclosingRequest.java new file mode 100644 index 000000000..fcb560ccd --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpEntityEnclosingRequest.java @@ -0,0 +1,75 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HttpEntity; +import ch.boye.httpclientandroidlib.HttpEntityEnclosingRequest; +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.protocol.HTTP; + +/** + * Basic implementation of {@link HttpEntityEnclosingRequest}. + * + * @since 4.0 + */ +@NotThreadSafe +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) { + super(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() { + final Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE); + return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue()); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpRequest.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpRequest.java new file mode 100644 index 000000000..be795a08e --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpRequest.java @@ -0,0 +1,114 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.HttpRequest; +import ch.boye.httpclientandroidlib.HttpVersion; +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Basic implementation of {@link HttpRequest}. + * + * @since 4.0 + */ +@NotThreadSafe +public class BasicHttpRequest extends AbstractHttpMessage implements HttpRequest { + + private final String method; + private final String uri; + + private RequestLine requestline; + + /** + * Creates an instance of this class using the given request method + * and URI. + * + * @param method request method. + * @param uri request URI. + */ + public BasicHttpRequest(final String method, final String uri) { + super(); + this.method = Args.notNull(method, "Method name"); + this.uri = Args.notNull(uri, "Request URI"); + this.requestline = null; + } + + /** + * Creates an instance of this class using the given request method, URI + * and the HTTP protocol version. + * + * @param method request method. + * @param uri request URI. + * @param ver HTTP protocol version. + */ + public BasicHttpRequest(final String method, final String uri, final ProtocolVersion ver) { + this(new BasicRequestLine(method, uri, ver)); + } + + /** + * Creates an instance of this class using the given request line. + * + * @param requestline request line. + */ + public BasicHttpRequest(final RequestLine requestline) { + super(); + this.requestline = Args.notNull(requestline, "Request line"); + this.method = requestline.getMethod(); + this.uri = requestline.getUri(); + } + + /** + * Returns the HTTP protocol version to be used for this request. + * + * @see #BasicHttpRequest(String, String) + */ + public ProtocolVersion getProtocolVersion() { + return getRequestLine().getProtocolVersion(); + } + + /** + * Returns the request line of this request. + * + * @see #BasicHttpRequest(String, String) + */ + public RequestLine getRequestLine() { + if (this.requestline == null) { + this.requestline = new BasicRequestLine(this.method, this.uri, HttpVersion.HTTP_1_1); + } + return this.requestline; + } + + @Override + public String toString() { + return this.method + " " + this.uri + " " + this.headergroup; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpResponse.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpResponse.java new file mode 100644 index 000000000..f16b1ca59 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicHttpResponse.java @@ -0,0 +1,218 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.util.Locale; + +import ch.boye.httpclientandroidlib.HttpEntity; +import ch.boye.httpclientandroidlib.HttpResponse; +import ch.boye.httpclientandroidlib.HttpVersion; +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.ReasonPhraseCatalog; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Basic implementation of {@link HttpResponse}. + * + * @see ch.boye.httpclientandroidlib.impl.DefaultHttpResponseFactory + * + * @since 4.0 + */ +@NotThreadSafe +public class BasicHttpResponse extends AbstractHttpMessage implements HttpResponse { + + private StatusLine statusline; + private ProtocolVersion ver; + private int code; + private String reasonPhrase; + private HttpEntity entity; + private final 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(); + this.statusline = Args.notNull(statusline, "Status line"); + this.ver = statusline.getProtocolVersion(); + this.code = statusline.getStatusCode(); + this.reasonPhrase = statusline.getReasonPhrase(); + this.reasonCatalog = catalog; + this.locale = locale; + } + + /** + * 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) { + super(); + this.statusline = Args.notNull(statusline, "Status line"); + this.ver = statusline.getProtocolVersion(); + this.code = statusline.getStatusCode(); + this.reasonPhrase = statusline.getReasonPhrase(); + this.reasonCatalog = null; + this.locale = 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) { + super(); + Args.notNegative(code, "Status code"); + this.statusline = null; + this.ver = ver; + this.code = code; + this.reasonPhrase = reason; + this.reasonCatalog = null; + this.locale = null; + } + + + // non-javadoc, see interface HttpMessage + public ProtocolVersion getProtocolVersion() { + return this.ver; + } + + // non-javadoc, see interface HttpResponse + public StatusLine getStatusLine() { + if (this.statusline == null) { + this.statusline = new BasicStatusLine( + this.ver != null ? this.ver : HttpVersion.HTTP_1_1, + this.code, + this.reasonPhrase != null ? this.reasonPhrase : getReason(this.code)); + } + return this.statusline; + } + + // non-javadoc, see interface HttpResponse + public HttpEntity getEntity() { + return this.entity; + } + + public Locale getLocale() { + return this.locale; + } + + // non-javadoc, see interface HttpResponse + public void setStatusLine(final StatusLine statusline) { + this.statusline = Args.notNull(statusline, "Status line"); + this.ver = statusline.getProtocolVersion(); + this.code = statusline.getStatusCode(); + this.reasonPhrase = statusline.getReasonPhrase(); + } + + // non-javadoc, see interface HttpResponse + public void setStatusLine(final ProtocolVersion ver, final int code) { + Args.notNegative(code, "Status code"); + this.statusline = null; + this.ver = ver; + this.code = code; + this.reasonPhrase = null; + } + + // non-javadoc, see interface HttpResponse + public void setStatusLine( + final ProtocolVersion ver, final int code, final String reason) { + Args.notNegative(code, "Status code"); + this.statusline = null; + this.ver = ver; + this.code = code; + this.reasonPhrase = reason; + } + + // non-javadoc, see interface HttpResponse + public void setStatusCode(final int code) { + Args.notNegative(code, "Status code"); + this.statusline = null; + this.code = code; + this.reasonPhrase = null; + } + + // non-javadoc, see interface HttpResponse + public void setReasonPhrase(final String reason) { + this.statusline = null; + this.reasonPhrase = reason; + } + + // non-javadoc, see interface HttpResponse + public void setEntity(final HttpEntity entity) { + this.entity = entity; + } + + public void setLocale(final Locale locale) { + this.locale = Args.notNull(locale, "Locale"); + this.statusline = null; + } + + /** + * 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(final int code) { + return this.reasonCatalog != null ? this.reasonCatalog.getReason(code, + this.locale != null ? this.locale : Locale.getDefault()) : null; + } + + @Override + public String toString() { + return getStatusLine() + " " + this.headergroup; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicLineFormatter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicLineFormatter.java new file mode 100644 index 000000000..6eabfd48f --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicLineFormatter.java @@ -0,0 +1,319 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.FormattedHeader; +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.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. + * + * @since 4.0 + */ +@Immutable +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. + * + * @deprecated (4.3) use {@link #INSTANCE} + */ + @Deprecated + public final static BasicLineFormatter DEFAULT = new BasicLineFormatter(); + + public final static BasicLineFormatter INSTANCE = new BasicLineFormatter(); + + public BasicLineFormatter() { + super(); + } + + /** + * Obtains a buffer for formatting. + * + * @param charBuffer 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(final CharArrayBuffer charBuffer) { + CharArrayBuffer buffer = charBuffer; + 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 #INSTANCE default} + * + * @return the formatted protocol version + */ + public static + String formatProtocolVersion(final ProtocolVersion version, + final LineFormatter formatter) { + return (formatter != null ? formatter : BasicLineFormatter.INSTANCE) + .appendProtocolVersion(null, version).toString(); + } + + + // non-javadoc, see interface LineFormatter + public CharArrayBuffer appendProtocolVersion(final CharArrayBuffer buffer, + final ProtocolVersion version) { + Args.notNull(version, "Protocol version"); + // 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 #INSTANCE default} + * + * @return the formatted request line + */ + public static String formatRequestLine(final RequestLine reqline, + final LineFormatter formatter) { + return (formatter != null ? formatter : BasicLineFormatter.INSTANCE) + .formatRequestLine(null, reqline).toString(); + } + + + // non-javadoc, see interface LineFormatter + public CharArrayBuffer formatRequestLine(final CharArrayBuffer buffer, + final RequestLine reqline) { + Args.notNull(reqline, "Request line"); + final 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" + final 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 #INSTANCE default} + * + * @return the formatted status line + */ + public static String formatStatusLine(final StatusLine statline, + final LineFormatter formatter) { + return (formatter != null ? formatter : BasicLineFormatter.INSTANCE) + .formatStatusLine(null, statline).toString(); + } + + + // non-javadoc, see interface LineFormatter + public CharArrayBuffer formatStatusLine(final CharArrayBuffer buffer, + final StatusLine statline) { + Args.notNull(statline, "Status line"); + final 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 #INSTANCE default} + * + * @return the formatted header + */ + public static String formatHeader(final Header header, + final LineFormatter formatter) { + return (formatter != null ? formatter : BasicLineFormatter.INSTANCE) + .formatHeader(null, header).toString(); + } + + + // non-javadoc, see interface LineFormatter + public CharArrayBuffer formatHeader(final CharArrayBuffer buffer, + final Header header) { + Args.notNull(header, "Header"); + final CharArrayBuffer result; + + 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/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicLineParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicLineParser.java new file mode 100644 index 000000000..dabde0f62 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicLineParser.java @@ -0,0 +1,456 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HttpVersion; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.protocol.HTTP; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.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> + * + * @since 4.0 + */ +@Immutable +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. + * + * @deprecated (4.3) use {@link #INSTANCE} + */ + @Deprecated + public final static BasicLineParser DEFAULT = new BasicLineParser(); + + public final static BasicLineParser INSTANCE = 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(final ProtocolVersion proto) { + this.protocol = proto != null? proto : HttpVersion.HTTP_1_1; + } + + + /** + * Creates a new line parser for HTTP. + */ + public BasicLineParser() { + this(null); + } + + + public static + ProtocolVersion parseProtocolVersion(final String value, + final LineParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + final ParserCursor cursor = new ParserCursor(0, value.length()); + return (parser != null ? parser : BasicLineParser.INSTANCE) + .parseProtocolVersion(buffer, cursor); + } + + + // non-javadoc, see interface LineParser + public ProtocolVersion parseProtocolVersion(final CharArrayBuffer buffer, + final ParserCursor cursor) throws ParseException { + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + final String protoname = this.protocol.getProtocol(); + final int protolength = protoname.length(); + + final int indexFrom = cursor.getPos(); + final 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; + + final int period = buffer.indexOf('.', i, indexTo); + if (period == -1) { + throw new ParseException + ("Invalid protocol version number: " + + buffer.substring(indexFrom, indexTo)); + } + final int major; + try { + major = Integer.parseInt(buffer.substringTrimmed(i, period)); + } catch (final 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; + } + final int minor; + try { + minor = Integer.parseInt(buffer.substringTrimmed(i, blank)); + } catch (final 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(final int major, final int minor) { + return protocol.forVersion(major, minor); + } + + + + // non-javadoc, see interface LineParser + public boolean hasProtocolVersion(final CharArrayBuffer buffer, + final ParserCursor cursor) { + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + 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 static + RequestLine parseRequestLine(final String value, + final LineParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + final ParserCursor cursor = new ParserCursor(0, value.length()); + return (parser != null ? parser : BasicLineParser.INSTANCE) + .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 { + + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + final int indexFrom = cursor.getPos(); + final 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)); + } + final 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)); + } + final String uri = buffer.substringTrimmed(i, blank); + cursor.updatePos(blank); + + final 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 (final 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 static + StatusLine parseStatusLine(final String value, + final LineParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + final ParserCursor cursor = new ParserCursor(0, value.length()); + return (parser != null ? parser : BasicLineParser.INSTANCE) + .parseStatusLine(buffer, cursor); + } + + + // non-javadoc, see interface LineParser + public StatusLine parseStatusLine(final CharArrayBuffer buffer, + final ParserCursor cursor) throws ParseException { + Args.notNull(buffer, "Char array buffer"); + Args.notNull(cursor, "Parser cursor"); + final int indexFrom = cursor.getPos(); + final int indexTo = cursor.getUpperBound(); + + try { + // handle the HTTP-Version + final 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; + } + final int statusCode; + final String s = buffer.substringTrimmed(i, blank); + for (int j = 0; j < s.length(); j++) { + if (!Character.isDigit(s.charAt(j))) { + throw new ParseException( + "Status line contains invalid status code: " + + buffer.substring(indexFrom, indexTo)); + } + } + try { + statusCode = Integer.parseInt(s); + } catch (final NumberFormatException e) { + throw new ParseException( + "Status line contains invalid status code: " + + buffer.substring(indexFrom, indexTo)); + } + //handle the Reason-Phrase + i = blank; + final String reasonPhrase; + if (i < indexTo) { + reasonPhrase = buffer.substringTrimmed(i, indexTo); + } else { + reasonPhrase = ""; + } + return createStatusLine(ver, statusCode, reasonPhrase); + + } catch (final 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 static + Header parseHeader(final String value, + final LineParser parser) throws ParseException { + Args.notNull(value, "Value"); + + final CharArrayBuffer buffer = new CharArrayBuffer(value.length()); + buffer.append(value); + return (parser != null ? parser : BasicLineParser.INSTANCE) + .parseHeader(buffer); + } + + + // non-javadoc, see interface LineParser + public Header parseHeader(final 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(); + final int indexTo = cursor.getUpperBound(); + while ((pos < indexTo) && + HTTP.isWhitespace(buffer.charAt(pos))) { + pos++; + } + cursor.updatePos(pos); + } + +} // class BasicLineParser diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicListHeaderIterator.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicListHeaderIterator.java new file mode 100644 index 000000000..ce9db2657 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicListHeaderIterator.java @@ -0,0 +1,190 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.util.List; +import java.util.NoSuchElementException; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HeaderIterator; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.Asserts; + +/** + * Implementation of a {@link HeaderIterator} based on a {@link List}. + * For use by {@link HeaderGroup}. + * + * @since 4.0 + */ +@NotThreadSafe +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<Header> 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(final List<Header> headers, final String name) { + super(); + this.allHeaders = Args.notNull(headers, "Header list"); + this.headerName = name; + this.currentIndex = findNext(-1); + this.lastIndex = -1; + } + + + /** + * Determines the index of the next header. + * + * @param pos 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(final int pos) { + int from = pos; + 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(final int index) { + if (this.headerName == null) { + return true; + } + + // non-header elements, including null, will trigger exceptions + final String name = (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 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 { + Asserts.check(this.lastIndex >= 0, "No header to remove"); + this.allHeaders.remove(this.lastIndex); + this.lastIndex = -1; + this.currentIndex--; // adjust for the removed element + } +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicNameValuePair.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicNameValuePair.java new file mode 100644 index 000000000..530e5042e --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicNameValuePair.java @@ -0,0 +1,111 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.io.Serializable; + +import ch.boye.httpclientandroidlib.NameValuePair; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.LangUtils; + +/** + * Basic implementation of {@link NameValuePair}. + * + * @since 4.0 + */ +@Immutable +public class BasicNameValuePair implements NameValuePair, Cloneable, Serializable { + + private static final long serialVersionUID = -6437800749411518984L; + + 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(); + this.name = Args.notNull(name, "Name"); + this.value = value; + } + + public String getName() { + return this.name; + } + + public String getValue() { + return this.value; + } + + @Override + public String toString() { + // don't call complex default formatting for a simple toString + + if (this.value == null) { + return name; + } + final int len = this.name.length() + 1 + this.value.length(); + final StringBuilder buffer = new StringBuilder(len); + buffer.append(this.name); + buffer.append("="); + buffer.append(this.value); + return buffer.toString(); + } + + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (object instanceof NameValuePair) { + final BasicNameValuePair that = (BasicNameValuePair) object; + return this.name.equals(that.name) + && LangUtils.equals(this.value, that.value); + } + return false; + } + + @Override + public int hashCode() { + int hash = LangUtils.HASH_SEED; + hash = LangUtils.hashCode(hash, this.name); + hash = LangUtils.hashCode(hash, this.value); + return hash; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicRequestLine.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicRequestLine.java new file mode 100644 index 000000000..40c838b12 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicRequestLine.java @@ -0,0 +1,83 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.io.Serializable; + +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Basic implementation of {@link RequestLine}. + * + * @since 4.0 + */ +@Immutable +public class BasicRequestLine implements RequestLine, Cloneable, Serializable { + + private static final long serialVersionUID = 2810581718468737193L; + + private final ProtocolVersion protoversion; + private final String method; + private final String uri; + + public BasicRequestLine(final String method, + final String uri, + final ProtocolVersion version) { + super(); + this.method = Args.notNull(method, "Method"); + this.uri = Args.notNull(uri, "URI"); + this.protoversion = Args.notNull(version, "Version"); + } + + public String getMethod() { + return this.method; + } + + public ProtocolVersion getProtocolVersion() { + return this.protoversion; + } + + public String getUri() { + return this.uri; + } + + @Override + public String toString() { + // no need for non-default formatting in toString() + return BasicLineFormatter.INSTANCE.formatRequestLine(null, this).toString(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicStatusLine.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicStatusLine.java new file mode 100644 index 000000000..cce1f25d7 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicStatusLine.java @@ -0,0 +1,100 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.io.Serializable; + +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Basic implementation of {@link StatusLine} + * + * @since 4.0 + */ +@Immutable +public class BasicStatusLine implements StatusLine, Cloneable, Serializable { + + private static final long serialVersionUID = -2443303766890459269L; + + // ----------------------------------------------------- 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, final int statusCode, + final String reasonPhrase) { + super(); + this.protoVersion = Args.notNull(version, "Version"); + this.statusCode = Args.notNegative(statusCode, "Status code"); + this.reasonPhrase = reasonPhrase; + } + + // --------------------------------------------------------- Public Methods + + public int getStatusCode() { + return this.statusCode; + } + + public ProtocolVersion getProtocolVersion() { + return this.protoVersion; + } + + public String getReasonPhrase() { + return this.reasonPhrase; + } + + @Override + public String toString() { + // no need for non-default formatting in toString() + return BasicLineFormatter.INSTANCE.formatStatusLine(null, this).toString(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicTokenIterator.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicTokenIterator.java new file mode 100644 index 000000000..98bd841b5 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BasicTokenIterator.java @@ -0,0 +1,414 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.util.NoSuchElementException; + +import ch.boye.httpclientandroidlib.HeaderIterator; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.TokenIterator; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * 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. + * + * @since 4.0 + */ +@NotThreadSafe +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 #nextToken()}. + * <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) { + super(); + this.headerIt = Args.notNull(headerIterator, "Header iterator"); + 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 pos 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(final int pos) throws ParseException { + int from = pos; + 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); + } + + final int start = findTokenStart(from); + if (start < 0) { + this.currentToken = null; + return -1; // nothing found + } + + final 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(final String value, final int start, final int end) { + return value.substring(start, end); + } + + + /** + * Determines the starting position of the next token. + * This method will iterate over headers if necessary. + * + * @param pos 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(final int pos) { + int from = Args.notNegative(pos, "Search position"); + 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 pos 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(final int pos) { + int from = Args.notNegative(pos, "Search position"); + 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(final int from) { + Args.notNegative(from, "Search position"); + 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(final 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(final 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(final 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(final char ch) { + return (HTTP_SEPARATORS.indexOf(ch) >= 0); + } + + +} // class BasicTokenIterator + diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BufferedHeader.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BufferedHeader.java new file mode 100644 index 000000000..11b70bdcb --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/BufferedHeader.java @@ -0,0 +1,130 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.io.Serializable; + +import ch.boye.httpclientandroidlib.FormattedHeader; +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * This class represents a raw HTTP header whose content is parsed 'on demand' + * only when the header value needs to be consumed. + * + * @since 4.0 + */ +@NotThreadSafe +public class BufferedHeader implements FormattedHeader, Cloneable, Serializable { + + private static final long serialVersionUID = -2768352615787625448L; + + /** + * 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(); + Args.notNull(buffer, "Char array buffer"); + final int colon = buffer.indexOf(':'); + if (colon == -1) { + throw new ParseException + ("Invalid header: " + buffer.toString()); + } + final 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 { + final ParserCursor cursor = new ParserCursor(0, this.buffer.length()); + cursor.updatePos(this.valuePos); + return BasicHeaderValueParser.INSTANCE.parseElements(this.buffer, cursor); + } + + public int getValuePos() { + return this.valuePos; + } + + public CharArrayBuffer getBuffer() { + return this.buffer; + } + + @Override + public String toString() { + return this.buffer.toString(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + // buffer is considered immutable + // no need to make a copy of it + return super.clone(); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderGroup.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderGroup.java new file mode 100644 index 000000000..fe8cdce95 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderGroup.java @@ -0,0 +1,311 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HeaderIterator; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.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. + * + * + * @since 4.0 + */ +@NotThreadSafe +public class HeaderGroup implements Cloneable, Serializable { + + private static final long serialVersionUID = 2608834160639271617L; + + /** The list of headers for this group, in the order in which they were added */ + private final List<Header> headers; + + /** + * Constructor for HeaderGroup. + */ + public HeaderGroup() { + this.headers = new ArrayList<Header>(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(final Header header) { + if (header == null) { + return; + } + headers.add(header); + } + + /** + * Removes the given header. + * + * @param header the header to remove + */ + public void removeHeader(final 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(final Header header) { + if (header == null) { + return; + } + // HTTPCORE-361 : we don't use the for-each syntax, i.e. + // for (Header header : headers) + // as that creates an Iterator that needs to be garbage-collected + for (int i = 0; i < this.headers.size(); i++) { + final Header current = 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(final Header[] headers) { + clear(); + if (headers == null) { + return; + } + Collections.addAll(this.headers, headers); + } + + /** + * 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(final String name) { + final Header[] hdrs = getHeaders(name); + + if (hdrs.length == 0) { + return null; + } else if (hdrs.length == 1) { + return hdrs[0]; + } else { + final CharArrayBuffer valueBuffer = new CharArrayBuffer(128); + valueBuffer.append(hdrs[0].getValue()); + for (int i = 1; i < hdrs.length; i++) { + valueBuffer.append(", "); + valueBuffer.append(hdrs[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(final String name) { + final List<Header> headersFound = new ArrayList<Header>(); + // HTTPCORE-361 : we don't use the for-each syntax, i.e. + // for (Header header : headers) + // as that creates an Iterator that needs to be garbage-collected + for (int i = 0; i < this.headers.size(); i++) { + final Header header = this.headers.get(i); + if (header.getName().equalsIgnoreCase(name)) { + headersFound.add(header); + } + } + + return 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(final String name) { + // HTTPCORE-361 : we don't use the for-each syntax, i.e. + // for (Header header : headers) + // as that creates an Iterator that needs to be garbage-collected + for (int i = 0; i < this.headers.size(); i++) { + final Header header = this.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(final String name) { + // start at the end of the list and work backwards + for (int i = headers.size() - 1; i >= 0; i--) { + final 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 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(final String name) { + // HTTPCORE-361 : we don't use the for-each syntax, i.e. + // for (Header header : headers) + // as that creates an Iterator that needs to be garbage-collected + for (int i = 0; i < this.headers.size(); i++) { + final Header header = this.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 + * + * @since 4.0 + */ + public HeaderGroup copy() { + final HeaderGroup clone = new HeaderGroup(); + clone.headers.addAll(this.headers); + return clone; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + @Override + public String toString() { + return this.headers.toString(); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderValueFormatter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderValueFormatter.java new file mode 100644 index 000000000..8a1acc04e --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderValueFormatter.java @@ -0,0 +1,122 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.NameValuePair; +import ch.boye.httpclientandroidlib.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> + * + * @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/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderValueParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderValueParser.java new file mode 100644 index 000000000..5286249c7 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/HeaderValueParser.java @@ -0,0 +1,134 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.HeaderElement; +import ch.boye.httpclientandroidlib.NameValuePair; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Interface for parsing header values into elements. + * Instances of this interface are expected to be stateless and thread-safe. + * + * @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>ParseException</code>. + * + * @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/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/LineFormatter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/LineFormatter.java new file mode 100644 index 000000000..33e751a75 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/LineFormatter.java @@ -0,0 +1,131 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.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> + * + * @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 ch.boye.httpclientandroidlib.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 ch.boye.httpclientandroidlib.ParseException in case of a parse error + */ + CharArrayBuffer formatHeader(CharArrayBuffer buffer, + Header header); + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/LineParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/LineParser.java new file mode 100644 index 000000000..d94ca3d75 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/LineParser.java @@ -0,0 +1,137 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.ProtocolVersion; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.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. + * + * @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/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/ParserCursor.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/ParserCursor.java new file mode 100644 index 000000000..163352bb7 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/ParserCursor.java @@ -0,0 +1,100 @@ +/* + * ==================================================================== + * 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 ch.boye.httpclientandroidlib.message; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; + +/** + * 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> + * + * @since 4.0 + */ +@NotThreadSafe +public class ParserCursor { + + private final int lowerBound; + private final int upperBound; + private int pos; + + public ParserCursor(final int lowerBound, final 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(final int pos) { + if (pos < this.lowerBound) { + throw new IndexOutOfBoundsException("pos: "+pos+" < lowerBound: "+this.lowerBound); + } + if (pos > this.upperBound) { + throw new IndexOutOfBoundsException("pos: "+pos+" > upperBound: "+this.upperBound); + } + this.pos = pos; + } + + public boolean atEnd() { + return this.pos >= this.upperBound; + } + + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + 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/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/package-info.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/package-info.java new file mode 100644 index 000000000..bac6c2e32 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/message/package-info.java @@ -0,0 +1,32 @@ +/* + * ==================================================================== + * 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/>. + * + */ + +/** + * Core HTTP message components, message element parser + * and writer APIs and their default implementations. + */ +package ch.boye.httpclientandroidlib.message; |