From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- .../impl/io/AbstractMessageParser.java | 284 +++++++++++++++ .../impl/io/AbstractMessageWriter.java | 119 ++++++ .../impl/io/AbstractSessionInputBuffer.java | 401 +++++++++++++++++++++ .../impl/io/AbstractSessionOutputBuffer.java | 307 ++++++++++++++++ .../impl/io/ChunkedInputStream.java | 301 ++++++++++++++++ .../impl/io/ChunkedOutputStream.java | 208 +++++++++++ .../impl/io/ContentLengthInputStream.java | 232 ++++++++++++ .../impl/io/ContentLengthOutputStream.java | 136 +++++++ .../impl/io/DefaultHttpRequestParser.java | 140 +++++++ .../impl/io/DefaultHttpRequestParserFactory.java | 71 ++++ .../impl/io/DefaultHttpRequestWriter.java | 69 ++++ .../impl/io/DefaultHttpRequestWriterFactory.java | 63 ++++ .../impl/io/DefaultHttpResponseParser.java | 141 ++++++++ .../impl/io/DefaultHttpResponseParserFactory.java | 71 ++++ .../impl/io/DefaultHttpResponseWriter.java | 69 ++++ .../impl/io/DefaultHttpResponseWriterFactory.java | 63 ++++ .../impl/io/HttpRequestParser.java | 102 ++++++ .../impl/io/HttpRequestWriter.java | 62 ++++ .../impl/io/HttpResponseParser.java | 103 ++++++ .../impl/io/HttpResponseWriter.java | 62 ++++ .../impl/io/HttpTransportMetricsImpl.java | 63 ++++ .../impl/io/IdentityInputStream.java | 99 +++++ .../impl/io/IdentityOutputStream.java | 104 ++++++ .../impl/io/SessionInputBufferImpl.java | 399 ++++++++++++++++++++ .../impl/io/SessionOutputBufferImpl.java | 283 +++++++++++++++ .../impl/io/SocketInputBuffer.java | 108 ++++++ .../impl/io/SocketOutputBuffer.java | 75 ++++ .../httpclientandroidlib/impl/io/package-info.java | 32 ++ 28 files changed, 4167 insertions(+) create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageParser.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageWriter.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionInputBuffer.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionOutputBuffer.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedInputStream.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedOutputStream.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthInputStream.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthOutputStream.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParser.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParserFactory.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriter.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriterFactory.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParser.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParserFactory.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriter.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriterFactory.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestParser.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestWriter.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseParser.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseWriter.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpTransportMetricsImpl.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityInputStream.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityOutputStream.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionInputBufferImpl.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionOutputBufferImpl.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketInputBuffer.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketOutputBuffer.java create mode 100644 mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/package-info.java (limited to 'mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io') diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageParser.java new file mode 100644 index 000000000..cd7aceb52 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageParser.java @@ -0,0 +1,284 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HttpException; +import ch.boye.httpclientandroidlib.HttpMessage; +import ch.boye.httpclientandroidlib.MessageConstraintException; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.ProtocolException; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.config.MessageConstraints; +import ch.boye.httpclientandroidlib.io.HttpMessageParser; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.message.BasicLineParser; +import ch.boye.httpclientandroidlib.message.LineParser; +import ch.boye.httpclientandroidlib.params.HttpParamConfig; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Abstract base class for HTTP message parsers that obtain input from + * an instance of {@link SessionInputBuffer}. + * + * @since 4.0 + */ +@SuppressWarnings("deprecation") +@NotThreadSafe +public abstract class AbstractMessageParser implements HttpMessageParser { + + private static final int HEAD_LINE = 0; + private static final int HEADERS = 1; + + private final SessionInputBuffer sessionBuffer; + private final MessageConstraints messageConstraints; + private final List headerLines; + protected final LineParser lineParser; + + private int state; + private T message; + + /** + * Creates an instance of AbstractMessageParser. + * + * @param buffer the session input buffer. + * @param parser the line parser. + * @param params HTTP parameters. + * + * @deprecated (4.3) use {@link AbstractMessageParser#AbstractMessageParser(SessionInputBuffer, + * LineParser, MessageConstraints)} + */ + @Deprecated + public AbstractMessageParser( + final SessionInputBuffer buffer, + final LineParser parser, + final HttpParams params) { + super(); + Args.notNull(buffer, "Session input buffer"); + Args.notNull(params, "HTTP parameters"); + this.sessionBuffer = buffer; + this.messageConstraints = HttpParamConfig.getMessageConstraints(params); + this.lineParser = (parser != null) ? parser : BasicLineParser.INSTANCE; + this.headerLines = new ArrayList(); + this.state = HEAD_LINE; + } + + /** + * Creates new instance of AbstractMessageParser. + * + * @param buffer the session input buffer. + * @param lineParser the line parser. If null {@link BasicLineParser#INSTANCE} + * will be used. + * @param constraints the message constraints. If null + * {@link MessageConstraints#DEFAULT} will be used. + * + * @since 4.3 + */ + public AbstractMessageParser( + final SessionInputBuffer buffer, + final LineParser lineParser, + final MessageConstraints constraints) { + super(); + this.sessionBuffer = Args.notNull(buffer, "Session input buffer"); + this.lineParser = lineParser != null ? lineParser : BasicLineParser.INSTANCE; + this.messageConstraints = constraints != null ? constraints : MessageConstraints.DEFAULT; + this.headerLines = new ArrayList(); + this.state = HEAD_LINE; + } + + /** + * Parses HTTP headers from the data receiver stream according to the generic + * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3. + * + * @param inbuffer Session input buffer + * @param maxHeaderCount maximum number of headers allowed. If the number + * of headers received from the data stream exceeds maxCount value, an + * IOException will be thrown. Setting this parameter to a negative value + * or zero will disable the check. + * @param maxLineLen maximum number of characters for a header line, + * including the continuation lines. Setting this parameter to a negative + * value or zero will disable the check. + * @return array of HTTP headers + * @param parser line parser to use. Can be null, in which case + * the default implementation of this interface will be used. + * + * @throws IOException in case of an I/O error + * @throws HttpException in case of HTTP protocol violation + */ + public static Header[] parseHeaders( + final SessionInputBuffer inbuffer, + final int maxHeaderCount, + final int maxLineLen, + final LineParser parser) throws HttpException, IOException { + final List headerLines = new ArrayList(); + return parseHeaders(inbuffer, maxHeaderCount, maxLineLen, + parser != null ? parser : BasicLineParser.INSTANCE, + headerLines); + } + + /** + * Parses HTTP headers from the data receiver stream according to the generic + * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3. + * + * @param inbuffer Session input buffer + * @param maxHeaderCount maximum number of headers allowed. If the number + * of headers received from the data stream exceeds maxCount value, an + * IOException will be thrown. Setting this parameter to a negative value + * or zero will disable the check. + * @param maxLineLen maximum number of characters for a header line, + * including the continuation lines. Setting this parameter to a negative + * value or zero will disable the check. + * @param parser line parser to use. + * @param headerLines List of header lines. This list will be used to store + * intermediate results. This makes it possible to resume parsing of + * headers in case of a {@link java.io.InterruptedIOException}. + * + * @return array of HTTP headers + * + * @throws IOException in case of an I/O error + * @throws HttpException in case of HTTP protocol violation + * + * @since 4.1 + */ + public static Header[] parseHeaders( + final SessionInputBuffer inbuffer, + final int maxHeaderCount, + final int maxLineLen, + final LineParser parser, + final List headerLines) throws HttpException, IOException { + Args.notNull(inbuffer, "Session input buffer"); + Args.notNull(parser, "Line parser"); + Args.notNull(headerLines, "Header line list"); + + CharArrayBuffer current = null; + CharArrayBuffer previous = null; + for (;;) { + if (current == null) { + current = new CharArrayBuffer(64); + } else { + current.clear(); + } + final int l = inbuffer.readLine(current); + if (l == -1 || current.length() < 1) { + break; + } + // Parse the header name and value + // Check for folded headers first + // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2 + // discussion on folded headers + if ((current.charAt(0) == ' ' || current.charAt(0) == '\t') && previous != null) { + // we have continuation folded header + // so append value + int i = 0; + while (i < current.length()) { + final char ch = current.charAt(i); + if (ch != ' ' && ch != '\t') { + break; + } + i++; + } + if (maxLineLen > 0 + && previous.length() + 1 + current.length() - i > maxLineLen) { + throw new MessageConstraintException("Maximum line length limit exceeded"); + } + previous.append(' '); + previous.append(current, i, current.length() - i); + } else { + headerLines.add(current); + previous = current; + current = null; + } + if (maxHeaderCount > 0 && headerLines.size() >= maxHeaderCount) { + throw new MessageConstraintException("Maximum header count exceeded"); + } + } + final Header[] headers = new Header[headerLines.size()]; + for (int i = 0; i < headerLines.size(); i++) { + final CharArrayBuffer buffer = headerLines.get(i); + try { + headers[i] = parser.parseHeader(buffer); + } catch (final ParseException ex) { + throw new ProtocolException(ex.getMessage()); + } + } + return headers; + } + + /** + * Subclasses must override this method to generate an instance of + * {@link HttpMessage} based on the initial input from the session buffer. + *

+ * Usually this method is expected to read just the very first line or + * the very first valid from the data stream and based on the input generate + * an appropriate instance of {@link HttpMessage}. + * + * @param sessionBuffer the session input buffer. + * @return HTTP message based on the input from the session buffer. + * @throws IOException in case of an I/O error. + * @throws HttpException in case of HTTP protocol violation. + * @throws ParseException in case of a parse error. + */ + protected abstract T parseHead(SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException; + + public T parse() throws IOException, HttpException { + final int st = this.state; + switch (st) { + case HEAD_LINE: + try { + this.message = parseHead(this.sessionBuffer); + } catch (final ParseException px) { + throw new ProtocolException(px.getMessage(), px); + } + this.state = HEADERS; + //$FALL-THROUGH$ + case HEADERS: + final Header[] headers = AbstractMessageParser.parseHeaders( + this.sessionBuffer, + this.messageConstraints.getMaxHeaderCount(), + this.messageConstraints.getMaxLineLength(), + this.lineParser, + this.headerLines); + this.message.setHeaders(headers); + final T result = this.message; + this.message = null; + this.headerLines.clear(); + this.state = HEAD_LINE; + return result; + default: + throw new IllegalStateException("Inconsistent parser state"); + } + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageWriter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageWriter.java new file mode 100644 index 000000000..56caf58d5 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageWriter.java @@ -0,0 +1,119 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HeaderIterator; +import ch.boye.httpclientandroidlib.HttpException; +import ch.boye.httpclientandroidlib.HttpMessage; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.HttpMessageWriter; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.message.BasicLineFormatter; +import ch.boye.httpclientandroidlib.message.LineFormatter; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Abstract base class for HTTP message writers that serialize output to + * an instance of {@link SessionOutputBuffer}. + * + * @since 4.0 + */ +@SuppressWarnings("deprecation") +@NotThreadSafe +public abstract class AbstractMessageWriter implements HttpMessageWriter { + + protected final SessionOutputBuffer sessionBuffer; + protected final CharArrayBuffer lineBuf; + protected final LineFormatter lineFormatter; + + /** + * Creates an instance of AbstractMessageWriter. + * + * @param buffer the session output buffer. + * @param formatter the line formatter. + * @param params HTTP parameters. + * + * @deprecated (4.3) use + * {@link AbstractMessageWriter#AbstractMessageWriter(SessionOutputBuffer, LineFormatter)} + */ + @Deprecated + public AbstractMessageWriter(final SessionOutputBuffer buffer, + final LineFormatter formatter, + final HttpParams params) { + super(); + Args.notNull(buffer, "Session input buffer"); + this.sessionBuffer = buffer; + this.lineBuf = new CharArrayBuffer(128); + this.lineFormatter = (formatter != null) ? formatter : BasicLineFormatter.INSTANCE; + } + + /** + * Creates an instance of AbstractMessageWriter. + * + * @param buffer the session output buffer. + * @param formatter the line formatter If null {@link BasicLineFormatter#INSTANCE} + * will be used. + * + * @since 4.3 + */ + public AbstractMessageWriter( + final SessionOutputBuffer buffer, + final LineFormatter formatter) { + super(); + this.sessionBuffer = Args.notNull(buffer, "Session input buffer"); + this.lineFormatter = (formatter != null) ? formatter : BasicLineFormatter.INSTANCE; + this.lineBuf = new CharArrayBuffer(128); + } + + /** + * Subclasses must override this method to write out the first header line + * based on the {@link HttpMessage} passed as a parameter. + * + * @param message the message whose first line is to be written out. + * @throws IOException in case of an I/O error. + */ + protected abstract void writeHeadLine(T message) throws IOException; + + public void write(final T message) throws IOException, HttpException { + Args.notNull(message, "HTTP message"); + writeHeadLine(message); + for (final HeaderIterator it = message.headerIterator(); it.hasNext(); ) { + final Header header = it.nextHeader(); + this.sessionBuffer.writeLine + (lineFormatter.formatHeader(this.lineBuf, header)); + } + this.lineBuf.clear(); + this.sessionBuffer.writeLine(this.lineBuf); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionInputBuffer.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionInputBuffer.java new file mode 100644 index 000000000..e53e07a30 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionInputBuffer.java @@ -0,0 +1,401 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +import ch.boye.httpclientandroidlib.Consts; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.BufferInfo; +import ch.boye.httpclientandroidlib.io.HttpTransportMetrics; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.params.CoreConnectionPNames; +import ch.boye.httpclientandroidlib.params.CoreProtocolPNames; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.protocol.HTTP; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.ByteArrayBuffer; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Abstract base class for session input buffers that stream data from + * an arbitrary {@link InputStream}. This class buffers input data in + * an internal byte array for optimal input performance. + *

+ * {@link #readLine(CharArrayBuffer)} and {@link #readLine()} methods of this + * class treat a lone LF as valid line delimiters in addition to CR-LF required + * by the HTTP specification. + * + * @since 4.0 + * + * @deprecated (4.3) use {@link SessionInputBufferImpl} + */ +@NotThreadSafe +@Deprecated +public abstract class AbstractSessionInputBuffer implements SessionInputBuffer, BufferInfo { + + private InputStream instream; + private byte[] buffer; + private ByteArrayBuffer linebuffer; + private Charset charset; + private boolean ascii; + private int maxLineLen; + private int minChunkLimit; + private HttpTransportMetricsImpl metrics; + private CodingErrorAction onMalformedCharAction; + private CodingErrorAction onUnmappableCharAction; + + private int bufferpos; + private int bufferlen; + private CharsetDecoder decoder; + private CharBuffer cbuf; + + public AbstractSessionInputBuffer() { + } + + /** + * Initializes this session input buffer. + * + * @param instream the source input stream. + * @param buffersize the size of the internal buffer. + * @param params HTTP parameters. + */ + protected void init(final InputStream instream, final int buffersize, final HttpParams params) { + Args.notNull(instream, "Input stream"); + Args.notNegative(buffersize, "Buffer size"); + Args.notNull(params, "HTTP parameters"); + this.instream = instream; + this.buffer = new byte[buffersize]; + this.bufferpos = 0; + this.bufferlen = 0; + this.linebuffer = new ByteArrayBuffer(buffersize); + final String charset = (String) params.getParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET); + this.charset = charset != null ? Charset.forName(charset) : Consts.ASCII; + this.ascii = this.charset.equals(Consts.ASCII); + this.decoder = null; + this.maxLineLen = params.getIntParameter(CoreConnectionPNames.MAX_LINE_LENGTH, -1); + this.minChunkLimit = params.getIntParameter(CoreConnectionPNames.MIN_CHUNK_LIMIT, 512); + this.metrics = createTransportMetrics(); + final CodingErrorAction a1 = (CodingErrorAction) params.getParameter( + CoreProtocolPNames.HTTP_MALFORMED_INPUT_ACTION); + this.onMalformedCharAction = a1 != null ? a1 : CodingErrorAction.REPORT; + final CodingErrorAction a2 = (CodingErrorAction) params.getParameter( + CoreProtocolPNames.HTTP_UNMAPPABLE_INPUT_ACTION); + this.onUnmappableCharAction = a2 != null? a2 : CodingErrorAction.REPORT; + } + + /** + * @since 4.1 + */ + protected HttpTransportMetricsImpl createTransportMetrics() { + return new HttpTransportMetricsImpl(); + } + + /** + * @since 4.1 + */ + public int capacity() { + return this.buffer.length; + } + + /** + * @since 4.1 + */ + public int length() { + return this.bufferlen - this.bufferpos; + } + + /** + * @since 4.1 + */ + public int available() { + return capacity() - length(); + } + + protected int fillBuffer() throws IOException { + // compact the buffer if necessary + if (this.bufferpos > 0) { + final int len = this.bufferlen - this.bufferpos; + if (len > 0) { + System.arraycopy(this.buffer, this.bufferpos, this.buffer, 0, len); + } + this.bufferpos = 0; + this.bufferlen = len; + } + final int l; + final int off = this.bufferlen; + final int len = this.buffer.length - off; + l = this.instream.read(this.buffer, off, len); + if (l == -1) { + return -1; + } else { + this.bufferlen = off + l; + this.metrics.incrementBytesTransferred(l); + return l; + } + } + + protected boolean hasBufferedData() { + return this.bufferpos < this.bufferlen; + } + + public int read() throws IOException { + int noRead; + while (!hasBufferedData()) { + noRead = fillBuffer(); + if (noRead == -1) { + return -1; + } + } + return this.buffer[this.bufferpos++] & 0xff; + } + + public int read(final byte[] b, final int off, final int len) throws IOException { + if (b == null) { + return 0; + } + if (hasBufferedData()) { + final int chunk = Math.min(len, this.bufferlen - this.bufferpos); + System.arraycopy(this.buffer, this.bufferpos, b, off, chunk); + this.bufferpos += chunk; + return chunk; + } + // If the remaining capacity is big enough, read directly from the + // underlying input stream bypassing the buffer. + if (len > this.minChunkLimit) { + final int read = this.instream.read(b, off, len); + if (read > 0) { + this.metrics.incrementBytesTransferred(read); + } + return read; + } else { + // otherwise read to the buffer first + while (!hasBufferedData()) { + final int noRead = fillBuffer(); + if (noRead == -1) { + return -1; + } + } + final int chunk = Math.min(len, this.bufferlen - this.bufferpos); + System.arraycopy(this.buffer, this.bufferpos, b, off, chunk); + this.bufferpos += chunk; + return chunk; + } + } + + public int read(final byte[] b) throws IOException { + if (b == null) { + return 0; + } + return read(b, 0, b.length); + } + + private int locateLF() { + for (int i = this.bufferpos; i < this.bufferlen; i++) { + if (this.buffer[i] == HTTP.LF) { + return i; + } + } + return -1; + } + + /** + * Reads a complete line of characters up to a line delimiter from this + * session buffer into the given line buffer. The number of chars actually + * read is returned as an integer. The line delimiter itself is discarded. + * If no char is available because the end of the stream has been reached, + * the value -1 is returned. This method blocks until input + * data is available, end of file is detected, or an exception is thrown. + *

+ * This method treats a lone LF as a valid line delimiters in addition + * to CR-LF required by the HTTP specification. + * + * @param charbuffer the line buffer. + * @return one line of characters + * @exception IOException if an I/O error occurs. + */ + public int readLine(final CharArrayBuffer charbuffer) throws IOException { + Args.notNull(charbuffer, "Char array buffer"); + int noRead = 0; + boolean retry = true; + while (retry) { + // attempt to find end of line (LF) + final int i = locateLF(); + if (i != -1) { + // end of line found. + if (this.linebuffer.isEmpty()) { + // the entire line is preset in the read buffer + return lineFromReadBuffer(charbuffer, i); + } + retry = false; + final int len = i + 1 - this.bufferpos; + this.linebuffer.append(this.buffer, this.bufferpos, len); + this.bufferpos = i + 1; + } else { + // end of line not found + if (hasBufferedData()) { + final int len = this.bufferlen - this.bufferpos; + this.linebuffer.append(this.buffer, this.bufferpos, len); + this.bufferpos = this.bufferlen; + } + noRead = fillBuffer(); + if (noRead == -1) { + retry = false; + } + } + if (this.maxLineLen > 0 && this.linebuffer.length() >= this.maxLineLen) { + throw new IOException("Maximum line length limit exceeded"); + } + } + if (noRead == -1 && this.linebuffer.isEmpty()) { + // indicate the end of stream + return -1; + } + return lineFromLineBuffer(charbuffer); + } + + /** + * Reads a complete line of characters up to a line delimiter from this + * session buffer. The line delimiter itself is discarded. If no char is + * available because the end of the stream has been reached, + * null is returned. This method blocks until input data is + * available, end of file is detected, or an exception is thrown. + *

+ * This method treats a lone LF as a valid line delimiters in addition + * to CR-LF required by the HTTP specification. + * + * @return HTTP line as a string + * @exception IOException if an I/O error occurs. + */ + private int lineFromLineBuffer(final CharArrayBuffer charbuffer) + throws IOException { + // discard LF if found + int len = this.linebuffer.length(); + if (len > 0) { + if (this.linebuffer.byteAt(len - 1) == HTTP.LF) { + len--; + } + // discard CR if found + if (len > 0) { + if (this.linebuffer.byteAt(len - 1) == HTTP.CR) { + len--; + } + } + } + if (this.ascii) { + charbuffer.append(this.linebuffer, 0, len); + } else { + final ByteBuffer bbuf = ByteBuffer.wrap(this.linebuffer.buffer(), 0, len); + len = appendDecoded(charbuffer, bbuf); + } + this.linebuffer.clear(); + return len; + } + + private int lineFromReadBuffer(final CharArrayBuffer charbuffer, final int position) + throws IOException { + final int off = this.bufferpos; + int i = position; + this.bufferpos = i + 1; + if (i > off && this.buffer[i - 1] == HTTP.CR) { + // skip CR if found + i--; + } + int len = i - off; + if (this.ascii) { + charbuffer.append(this.buffer, off, len); + } else { + final ByteBuffer bbuf = ByteBuffer.wrap(this.buffer, off, len); + len = appendDecoded(charbuffer, bbuf); + } + return len; + } + + private int appendDecoded( + final CharArrayBuffer charbuffer, final ByteBuffer bbuf) throws IOException { + if (!bbuf.hasRemaining()) { + return 0; + } + if (this.decoder == null) { + this.decoder = this.charset.newDecoder(); + this.decoder.onMalformedInput(this.onMalformedCharAction); + this.decoder.onUnmappableCharacter(this.onUnmappableCharAction); + } + if (this.cbuf == null) { + this.cbuf = CharBuffer.allocate(1024); + } + this.decoder.reset(); + int len = 0; + while (bbuf.hasRemaining()) { + final CoderResult result = this.decoder.decode(bbuf, this.cbuf, true); + len += handleDecodingResult(result, charbuffer, bbuf); + } + final CoderResult result = this.decoder.flush(this.cbuf); + len += handleDecodingResult(result, charbuffer, bbuf); + this.cbuf.clear(); + return len; + } + + private int handleDecodingResult( + final CoderResult result, + final CharArrayBuffer charbuffer, + final ByteBuffer bbuf) throws IOException { + if (result.isError()) { + result.throwException(); + } + this.cbuf.flip(); + final int len = this.cbuf.remaining(); + while (this.cbuf.hasRemaining()) { + charbuffer.append(this.cbuf.get()); + } + this.cbuf.compact(); + return len; + } + + public String readLine() throws IOException { + final CharArrayBuffer charbuffer = new CharArrayBuffer(64); + final int l = readLine(charbuffer); + if (l != -1) { + return charbuffer.toString(); + } else { + return null; + } + } + + public HttpTransportMetrics getMetrics() { + return this.metrics; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionOutputBuffer.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionOutputBuffer.java new file mode 100644 index 000000000..a2c87d084 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionOutputBuffer.java @@ -0,0 +1,307 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +import ch.boye.httpclientandroidlib.Consts; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.BufferInfo; +import ch.boye.httpclientandroidlib.io.HttpTransportMetrics; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.params.CoreConnectionPNames; +import ch.boye.httpclientandroidlib.params.CoreProtocolPNames; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.protocol.HTTP; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.ByteArrayBuffer; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Abstract base class for session output buffers that stream data to + * an arbitrary {@link OutputStream}. This class buffers small chunks of + * output data in an internal byte array for optimal output performance. + *

+ * {@link #writeLine(CharArrayBuffer)} and {@link #writeLine(String)} methods + * of this class use CR-LF as a line delimiter. + * + * @since 4.0 + * + * @deprecated (4.3) use {@link SessionOutputBufferImpl} + */ +@NotThreadSafe +@Deprecated +public abstract class AbstractSessionOutputBuffer implements SessionOutputBuffer, BufferInfo { + + private static final byte[] CRLF = new byte[] {HTTP.CR, HTTP.LF}; + + private OutputStream outstream; + private ByteArrayBuffer buffer; + private Charset charset; + private boolean ascii; + private int minChunkLimit; + private HttpTransportMetricsImpl metrics; + private CodingErrorAction onMalformedCharAction; + private CodingErrorAction onUnmappableCharAction; + + private CharsetEncoder encoder; + private ByteBuffer bbuf; + + protected AbstractSessionOutputBuffer( + final OutputStream outstream, + final int buffersize, + final Charset charset, + final int minChunkLimit, + final CodingErrorAction malformedCharAction, + final CodingErrorAction unmappableCharAction) { + super(); + Args.notNull(outstream, "Input stream"); + Args.notNegative(buffersize, "Buffer size"); + this.outstream = outstream; + this.buffer = new ByteArrayBuffer(buffersize); + this.charset = charset != null ? charset : Consts.ASCII; + this.ascii = this.charset.equals(Consts.ASCII); + this.encoder = null; + this.minChunkLimit = minChunkLimit >= 0 ? minChunkLimit : 512; + this.metrics = createTransportMetrics(); + this.onMalformedCharAction = malformedCharAction != null ? malformedCharAction : + CodingErrorAction.REPORT; + this.onUnmappableCharAction = unmappableCharAction != null? unmappableCharAction : + CodingErrorAction.REPORT; + } + + public AbstractSessionOutputBuffer() { + } + + protected void init(final OutputStream outstream, final int buffersize, final HttpParams params) { + Args.notNull(outstream, "Input stream"); + Args.notNegative(buffersize, "Buffer size"); + Args.notNull(params, "HTTP parameters"); + this.outstream = outstream; + this.buffer = new ByteArrayBuffer(buffersize); + final String charset = (String) params.getParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET); + this.charset = charset != null ? Charset.forName(charset) : Consts.ASCII; + this.ascii = this.charset.equals(Consts.ASCII); + this.encoder = null; + this.minChunkLimit = params.getIntParameter(CoreConnectionPNames.MIN_CHUNK_LIMIT, 512); + this.metrics = createTransportMetrics(); + final CodingErrorAction a1 = (CodingErrorAction) params.getParameter( + CoreProtocolPNames.HTTP_MALFORMED_INPUT_ACTION); + this.onMalformedCharAction = a1 != null ? a1 : CodingErrorAction.REPORT; + final CodingErrorAction a2 = (CodingErrorAction) params.getParameter( + CoreProtocolPNames.HTTP_UNMAPPABLE_INPUT_ACTION); + this.onUnmappableCharAction = a2 != null? a2 : CodingErrorAction.REPORT; + } + + /** + * @since 4.1 + */ + protected HttpTransportMetricsImpl createTransportMetrics() { + return new HttpTransportMetricsImpl(); + } + + /** + * @since 4.1 + */ + public int capacity() { + return this.buffer.capacity(); + } + + /** + * @since 4.1 + */ + public int length() { + return this.buffer.length(); + } + + /** + * @since 4.1 + */ + public int available() { + return capacity() - length(); + } + + protected void flushBuffer() throws IOException { + final int len = this.buffer.length(); + if (len > 0) { + this.outstream.write(this.buffer.buffer(), 0, len); + this.buffer.clear(); + this.metrics.incrementBytesTransferred(len); + } + } + + public void flush() throws IOException { + flushBuffer(); + this.outstream.flush(); + } + + public void write(final byte[] b, final int off, final int len) throws IOException { + if (b == null) { + return; + } + // Do not want to buffer large-ish chunks + // if the byte array is larger then MIN_CHUNK_LIMIT + // write it directly to the output stream + if (len > this.minChunkLimit || len > this.buffer.capacity()) { + // flush the buffer + flushBuffer(); + // write directly to the out stream + this.outstream.write(b, off, len); + this.metrics.incrementBytesTransferred(len); + } else { + // Do not let the buffer grow unnecessarily + final int freecapacity = this.buffer.capacity() - this.buffer.length(); + if (len > freecapacity) { + // flush the buffer + flushBuffer(); + } + // buffer + this.buffer.append(b, off, len); + } + } + + public void write(final byte[] b) throws IOException { + if (b == null) { + return; + } + write(b, 0, b.length); + } + + public void write(final int b) throws IOException { + if (this.buffer.isFull()) { + flushBuffer(); + } + this.buffer.append(b); + } + + /** + * Writes characters from the specified string followed by a line delimiter + * to this session buffer. + *

+ * This method uses CR-LF as a line delimiter. + * + * @param s the line. + * @exception IOException if an I/O error occurs. + */ + public void writeLine(final String s) throws IOException { + if (s == null) { + return; + } + if (s.length() > 0) { + if (this.ascii) { + for (int i = 0; i < s.length(); i++) { + write(s.charAt(i)); + } + } else { + final CharBuffer cbuf = CharBuffer.wrap(s); + writeEncoded(cbuf); + } + } + write(CRLF); + } + + /** + * Writes characters from the specified char array followed by a line + * delimiter to this session buffer. + *

+ * This method uses CR-LF as a line delimiter. + * + * @param charbuffer the buffer containing chars of the line. + * @exception IOException if an I/O error occurs. + */ + public void writeLine(final CharArrayBuffer charbuffer) throws IOException { + if (charbuffer == null) { + return; + } + if (this.ascii) { + int off = 0; + int remaining = charbuffer.length(); + while (remaining > 0) { + int chunk = this.buffer.capacity() - this.buffer.length(); + chunk = Math.min(chunk, remaining); + if (chunk > 0) { + this.buffer.append(charbuffer, off, chunk); + } + if (this.buffer.isFull()) { + flushBuffer(); + } + off += chunk; + remaining -= chunk; + } + } else { + final CharBuffer cbuf = CharBuffer.wrap(charbuffer.buffer(), 0, charbuffer.length()); + writeEncoded(cbuf); + } + write(CRLF); + } + + private void writeEncoded(final CharBuffer cbuf) throws IOException { + if (!cbuf.hasRemaining()) { + return; + } + if (this.encoder == null) { + this.encoder = this.charset.newEncoder(); + this.encoder.onMalformedInput(this.onMalformedCharAction); + this.encoder.onUnmappableCharacter(this.onUnmappableCharAction); + } + if (this.bbuf == null) { + this.bbuf = ByteBuffer.allocate(1024); + } + this.encoder.reset(); + while (cbuf.hasRemaining()) { + final CoderResult result = this.encoder.encode(cbuf, this.bbuf, true); + handleEncodingResult(result); + } + final CoderResult result = this.encoder.flush(this.bbuf); + handleEncodingResult(result); + this.bbuf.clear(); + } + + private void handleEncodingResult(final CoderResult result) throws IOException { + if (result.isError()) { + result.throwException(); + } + this.bbuf.flip(); + while (this.bbuf.hasRemaining()) { + write(this.bbuf.get()); + } + this.bbuf.compact(); + } + + public HttpTransportMetrics getMetrics() { + return this.metrics; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedInputStream.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedInputStream.java new file mode 100644 index 000000000..447bd676d --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedInputStream.java @@ -0,0 +1,301 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.InputStream; + +import ch.boye.httpclientandroidlib.Header; +import ch.boye.httpclientandroidlib.HttpException; +import ch.boye.httpclientandroidlib.MalformedChunkCodingException; +import ch.boye.httpclientandroidlib.TruncatedChunkException; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.BufferInfo; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Implements chunked transfer coding. The content is received in small chunks. + * Entities transferred using this input stream can be of unlimited length. + * After the stream is read to the end, it provides access to the trailers, + * if any. + *

+ * Note that this class NEVER closes the underlying stream, even when close + * gets called. Instead, it will read until the "end" of its chunking on + * close, which allows for the seamless execution of subsequent HTTP 1.1 + * requests, while not requiring the client to remember to read the entire + * contents of the response. + * + * + * @since 4.0 + * + */ +@NotThreadSafe +public class ChunkedInputStream extends InputStream { + + private static final int CHUNK_LEN = 1; + private static final int CHUNK_DATA = 2; + private static final int CHUNK_CRLF = 3; + + private static final int BUFFER_SIZE = 2048; + + /** The session input buffer */ + private final SessionInputBuffer in; + + private final CharArrayBuffer buffer; + + private int state; + + /** The chunk size */ + private int chunkSize; + + /** The current position within the current chunk */ + private int pos; + + /** True if we've reached the end of stream */ + private boolean eof = false; + + /** True if this stream is closed */ + private boolean closed = false; + + private Header[] footers = new Header[] {}; + + /** + * Wraps session input stream and reads chunk coded input. + * + * @param in The session input buffer + */ + public ChunkedInputStream(final SessionInputBuffer in) { + super(); + this.in = Args.notNull(in, "Session input buffer"); + this.pos = 0; + this.buffer = new CharArrayBuffer(16); + this.state = CHUNK_LEN; + } + + @Override + public int available() throws IOException { + if (this.in instanceof BufferInfo) { + final int len = ((BufferInfo) this.in).length(); + return Math.min(len, this.chunkSize - this.pos); + } else { + return 0; + } + } + + /** + *

Returns all the data in a chunked stream in coalesced form. A chunk + * is followed by a CRLF. The method returns -1 as soon as a chunksize of 0 + * is detected.

+ * + *

Trailer headers are read automatically at the end of the stream and + * can be obtained with the getResponseFooters() method.

+ * + * @return -1 of the end of the stream has been reached or the next data + * byte + * @throws IOException in case of an I/O error + */ + @Override + public int read() throws IOException { + if (this.closed) { + throw new IOException("Attempted read from closed stream."); + } + if (this.eof) { + return -1; + } + if (state != CHUNK_DATA) { + nextChunk(); + if (this.eof) { + return -1; + } + } + final int b = in.read(); + if (b != -1) { + pos++; + if (pos >= chunkSize) { + state = CHUNK_CRLF; + } + } + return b; + } + + /** + * Read some bytes from the stream. + * @param b The byte array that will hold the contents from the stream. + * @param off The offset into the byte array at which bytes will start to be + * placed. + * @param len the maximum number of bytes that can be returned. + * @return The number of bytes returned or -1 if the end of stream has been + * reached. + * @throws IOException in case of an I/O error + */ + @Override + public int read (final byte[] b, final int off, final int len) throws IOException { + + if (closed) { + throw new IOException("Attempted read from closed stream."); + } + + if (eof) { + return -1; + } + if (state != CHUNK_DATA) { + nextChunk(); + if (eof) { + return -1; + } + } + final int bytesRead = in.read(b, off, Math.min(len, chunkSize - pos)); + if (bytesRead != -1) { + pos += bytesRead; + if (pos >= chunkSize) { + state = CHUNK_CRLF; + } + return bytesRead; + } else { + eof = true; + throw new TruncatedChunkException("Truncated chunk " + + "( expected size: " + chunkSize + + "; actual size: " + pos + ")"); + } + } + + /** + * Read some bytes from the stream. + * @param b The byte array that will hold the contents from the stream. + * @return The number of bytes returned or -1 if the end of stream has been + * reached. + * @throws IOException in case of an I/O error + */ + @Override + public int read (final byte[] b) throws IOException { + return read(b, 0, b.length); + } + + /** + * Read the next chunk. + * @throws IOException in case of an I/O error + */ + private void nextChunk() throws IOException { + chunkSize = getChunkSize(); + if (chunkSize < 0) { + throw new MalformedChunkCodingException("Negative chunk size"); + } + state = CHUNK_DATA; + pos = 0; + if (chunkSize == 0) { + eof = true; + parseTrailerHeaders(); + } + } + + /** + * Expects the stream to start with a chunksize in hex with optional + * comments after a semicolon. The line must end with a CRLF: "a3; some + * comment\r\n" Positions the stream at the start of the next line. + */ + private int getChunkSize() throws IOException { + final int st = this.state; + switch (st) { + case CHUNK_CRLF: + this.buffer.clear(); + final int bytesRead1 = this.in.readLine(this.buffer); + if (bytesRead1 == -1) { + return 0; + } + if (!this.buffer.isEmpty()) { + throw new MalformedChunkCodingException( + "Unexpected content at the end of chunk"); + } + state = CHUNK_LEN; + //$FALL-THROUGH$ + case CHUNK_LEN: + this.buffer.clear(); + final int bytesRead2 = this.in.readLine(this.buffer); + if (bytesRead2 == -1) { + return 0; + } + int separator = this.buffer.indexOf(';'); + if (separator < 0) { + separator = this.buffer.length(); + } + try { + return Integer.parseInt(this.buffer.substringTrimmed(0, separator), 16); + } catch (final NumberFormatException e) { + throw new MalformedChunkCodingException("Bad chunk header"); + } + default: + throw new IllegalStateException("Inconsistent codec state"); + } + } + + /** + * Reads and stores the Trailer headers. + * @throws IOException in case of an I/O error + */ + private void parseTrailerHeaders() throws IOException { + try { + this.footers = AbstractMessageParser.parseHeaders + (in, -1, -1, null); + } catch (final HttpException ex) { + final IOException ioe = new MalformedChunkCodingException("Invalid footer: " + + ex.getMessage()); + ioe.initCause(ex); + throw ioe; + } + } + + /** + * Upon close, this reads the remainder of the chunked message, + * leaving the underlying socket at a position to start reading the + * next response without scanning. + * @throws IOException in case of an I/O error + */ + @Override + public void close() throws IOException { + if (!closed) { + try { + if (!eof) { + // read and discard the remainder of the message + final byte buff[] = new byte[BUFFER_SIZE]; + while (read(buff) >= 0) { + } + } + } finally { + eof = true; + closed = true; + } + } + } + + public Header[] getFooters() { + return this.footers.clone(); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedOutputStream.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedOutputStream.java new file mode 100644 index 000000000..828df923c --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedOutputStream.java @@ -0,0 +1,208 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.OutputStream; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; + +/** + * Implements chunked transfer coding. The content is sent in small chunks. + * Entities transferred using this output stream can be of unlimited length. + * Writes are buffered to an internal buffer (2048 default size). + *

+ * Note that this class NEVER closes the underlying stream, even when close + * gets called. Instead, the stream will be marked as closed and no further + * output will be permitted. + * + * + * @since 4.0 + */ +@NotThreadSafe +public class ChunkedOutputStream extends OutputStream { + + // ----------------------------------------------------- Instance Variables + private final SessionOutputBuffer out; + + private final byte[] cache; + + private int cachePosition = 0; + + private boolean wroteLastChunk = false; + + /** True if the stream is closed. */ + private boolean closed = false; + + /** + * Wraps a session output buffer and chunk-encodes the output. + * + * @param out The session output buffer + * @param bufferSize The minimum chunk size (excluding last chunk) + * @throws IOException not thrown + * + * @deprecated (4.3) use {@link ChunkedOutputStream#ChunkedOutputStream(int, SessionOutputBuffer)} + */ + @Deprecated + public ChunkedOutputStream(final SessionOutputBuffer out, final int bufferSize) + throws IOException { + this(bufferSize, out); + } + + /** + * Wraps a session output buffer and chunks the output. The default buffer + * size of 2048 was chosen because the chunk overhead is less than 0.5% + * + * @param out the output buffer to wrap + * @throws IOException not thrown + * + * @deprecated (4.3) use {@link ChunkedOutputStream#ChunkedOutputStream(int, SessionOutputBuffer)} + */ + @Deprecated + public ChunkedOutputStream(final SessionOutputBuffer out) + throws IOException { + this(2048, out); + } + + /** + * Wraps a session output buffer and chunk-encodes the output. + * + * @param bufferSize The minimum chunk size (excluding last chunk) + * @param out The session output buffer + */ + public ChunkedOutputStream(final int bufferSize, final SessionOutputBuffer out) { + super(); + this.cache = new byte[bufferSize]; + this.out = out; + } + + /** + * Writes the cache out onto the underlying stream + */ + protected void flushCache() throws IOException { + if (this.cachePosition > 0) { + this.out.writeLine(Integer.toHexString(this.cachePosition)); + this.out.write(this.cache, 0, this.cachePosition); + this.out.writeLine(""); + this.cachePosition = 0; + } + } + + /** + * Writes the cache and bufferToAppend to the underlying stream + * as one large chunk + */ + protected void flushCacheWithAppend(final byte bufferToAppend[], final int off, final int len) throws IOException { + this.out.writeLine(Integer.toHexString(this.cachePosition + len)); + this.out.write(this.cache, 0, this.cachePosition); + this.out.write(bufferToAppend, off, len); + this.out.writeLine(""); + this.cachePosition = 0; + } + + protected void writeClosingChunk() throws IOException { + // Write the final chunk. + this.out.writeLine("0"); + this.out.writeLine(""); + } + + // ----------------------------------------------------------- Public Methods + /** + * Must be called to ensure the internal cache is flushed and the closing + * chunk is written. + * @throws IOException in case of an I/O error + */ + public void finish() throws IOException { + if (!this.wroteLastChunk) { + flushCache(); + writeClosingChunk(); + this.wroteLastChunk = true; + } + } + + // -------------------------------------------- OutputStream Methods + @Override + public void write(final int b) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + this.cache[this.cachePosition] = (byte) b; + this.cachePosition++; + if (this.cachePosition == this.cache.length) { + flushCache(); + } + } + + /** + * Writes the array. If the array does not fit within the buffer, it is + * not split, but rather written out as one large chunk. + */ + @Override + public void write(final byte b[]) throws IOException { + write(b, 0, b.length); + } + + /** + * Writes the array. If the array does not fit within the buffer, it is + * not split, but rather written out as one large chunk. + */ + @Override + public void write(final byte src[], final int off, final int len) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + if (len >= this.cache.length - this.cachePosition) { + flushCacheWithAppend(src, off, len); + } else { + System.arraycopy(src, off, cache, this.cachePosition, len); + this.cachePosition += len; + } + } + + /** + * Flushes the content buffer and the underlying stream. + */ + @Override + public void flush() throws IOException { + flushCache(); + this.out.flush(); + } + + /** + * Finishes writing to the underlying stream, but does NOT close the underlying stream. + */ + @Override + public void close() throws IOException { + if (!this.closed) { + this.closed = true; + finish(); + this.out.flush(); + } + } +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthInputStream.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthInputStream.java new file mode 100644 index 000000000..65a271cb8 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthInputStream.java @@ -0,0 +1,232 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.InputStream; + +import ch.boye.httpclientandroidlib.ConnectionClosedException; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.BufferInfo; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Input stream that cuts off after a defined number of bytes. This class + * is used to receive content of HTTP messages where the end of the content + * entity is determined by the value of the Content-Length header. + * Entities transferred using this stream can be maximum {@link Long#MAX_VALUE} + * long. + *

+ * Note that this class NEVER closes the underlying stream, even when close + * gets called. Instead, it will read until the "end" of its limit on + * close, which allows for the seamless execution of subsequent HTTP 1.1 + * requests, while not requiring the client to remember to read the entire + * contents of the response. + * + * + * @since 4.0 + */ +@NotThreadSafe +public class ContentLengthInputStream extends InputStream { + + private static final int BUFFER_SIZE = 2048; + /** + * The maximum number of bytes that can be read from the stream. Subsequent + * read operations will return -1. + */ + private final long contentLength; + + /** The current position */ + private long pos = 0; + + /** True if the stream is closed. */ + private boolean closed = false; + + /** + * Wrapped input stream that all calls are delegated to. + */ + private SessionInputBuffer in = null; + + /** + * Wraps a session input buffer and cuts off output after a defined number + * of bytes. + * + * @param in The session input buffer + * @param contentLength The maximum number of bytes that can be read from + * the stream. Subsequent read operations will return -1. + */ + public ContentLengthInputStream(final SessionInputBuffer in, final long contentLength) { + super(); + this.in = Args.notNull(in, "Session input buffer"); + this.contentLength = Args.notNegative(contentLength, "Content length"); + } + + /** + *

Reads until the end of the known length of content.

+ * + *

Does not close the underlying socket input, but instead leaves it + * primed to parse the next response.

+ * @throws IOException If an IO problem occurs. + */ + @Override + public void close() throws IOException { + if (!closed) { + try { + if (pos < contentLength) { + final byte buffer[] = new byte[BUFFER_SIZE]; + while (read(buffer) >= 0) { + } + } + } finally { + // close after above so that we don't throw an exception trying + // to read after closed! + closed = true; + } + } + } + + @Override + public int available() throws IOException { + if (this.in instanceof BufferInfo) { + final int len = ((BufferInfo) this.in).length(); + return Math.min(len, (int) (this.contentLength - this.pos)); + } else { + return 0; + } + } + + /** + * Read the next byte from the stream + * @return The next byte or -1 if the end of stream has been reached. + * @throws IOException If an IO problem occurs + * @see java.io.InputStream#read() + */ + @Override + public int read() throws IOException { + if (closed) { + throw new IOException("Attempted read from closed stream."); + } + + if (pos >= contentLength) { + return -1; + } + final int b = this.in.read(); + if (b == -1) { + if (pos < contentLength) { + throw new ConnectionClosedException( + "Premature end of Content-Length delimited message body (expected: " + + contentLength + "; received: " + pos); + } + } else { + pos++; + } + return b; + } + + /** + * Does standard {@link InputStream#read(byte[], int, int)} behavior, but + * also notifies the watcher when the contents have been consumed. + * + * @param b The byte array to fill. + * @param off Start filling at this position. + * @param len The number of bytes to attempt to read. + * @return The number of bytes read, or -1 if the end of content has been + * reached. + * + * @throws java.io.IOException Should an error occur on the wrapped stream. + */ + @Override + public int read (final byte[] b, final int off, final int len) throws java.io.IOException { + if (closed) { + throw new IOException("Attempted read from closed stream."); + } + + if (pos >= contentLength) { + return -1; + } + + int chunk = len; + if (pos + len > contentLength) { + chunk = (int) (contentLength - pos); + } + final int count = this.in.read(b, off, chunk); + if (count == -1 && pos < contentLength) { + throw new ConnectionClosedException( + "Premature end of Content-Length delimited message body (expected: " + + contentLength + "; received: " + pos); + } + if (count > 0) { + pos += count; + } + return count; + } + + + /** + * Read more bytes from the stream. + * @param b The byte array to put the new data in. + * @return The number of bytes read into the buffer. + * @throws IOException If an IO problem occurs + * @see java.io.InputStream#read(byte[]) + */ + @Override + public int read(final byte[] b) throws IOException { + return read(b, 0, b.length); + } + + /** + * Skips and discards a number of bytes from the input stream. + * @param n The number of bytes to skip. + * @return The actual number of bytes skipped. <= 0 if no bytes + * are skipped. + * @throws IOException If an error occurs while skipping bytes. + * @see InputStream#skip(long) + */ + @Override + public long skip(final long n) throws IOException { + if (n <= 0) { + return 0; + } + final byte[] buffer = new byte[BUFFER_SIZE]; + // make sure we don't skip more bytes than are + // still available + long remaining = Math.min(n, this.contentLength - this.pos); + // skip and keep track of the bytes actually skipped + long count = 0; + while (remaining > 0) { + final int l = read(buffer, 0, (int)Math.min(BUFFER_SIZE, remaining)); + if (l == -1) { + break; + } + count += l; + remaining -= l; + } + return count; + } +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthOutputStream.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthOutputStream.java new file mode 100644 index 000000000..1c4e588d0 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ContentLengthOutputStream.java @@ -0,0 +1,136 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.OutputStream; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Output stream that cuts off after a defined number of bytes. This class + * is used to send content of HTTP messages where the end of the content entity + * is determined by the value of the Content-Length header. + * Entities transferred using this stream can be maximum {@link Long#MAX_VALUE} + * long. + *

+ * Note that this class NEVER closes the underlying stream, even when close + * gets called. Instead, the stream will be marked as closed and no further + * output will be permitted. + * + * @since 4.0 + */ +@NotThreadSafe +public class ContentLengthOutputStream extends OutputStream { + + /** + * Wrapped session output buffer. + */ + private final SessionOutputBuffer out; + + /** + * The maximum number of bytes that can be written the stream. Subsequent + * write operations will be ignored. + */ + private final long contentLength; + + /** Total bytes written */ + private long total = 0; + + /** True if the stream is closed. */ + private boolean closed = false; + + /** + * Wraps a session output buffer and cuts off output after a defined number + * of bytes. + * + * @param out The session output buffer + * @param contentLength The maximum number of bytes that can be written to + * the stream. Subsequent write operations will be ignored. + * + * @since 4.0 + */ + public ContentLengthOutputStream(final SessionOutputBuffer out, final long contentLength) { + super(); + this.out = Args.notNull(out, "Session output buffer"); + this.contentLength = Args.notNegative(contentLength, "Content length"); + } + + /** + *

Does not close the underlying socket output.

+ * + * @throws IOException If an I/O problem occurs. + */ + @Override + public void close() throws IOException { + if (!this.closed) { + this.closed = true; + this.out.flush(); + } + } + + @Override + public void flush() throws IOException { + this.out.flush(); + } + + @Override + public void write(final byte[] b, final int off, final int len) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + if (this.total < this.contentLength) { + final long max = this.contentLength - this.total; + int chunk = len; + if (chunk > max) { + chunk = (int) max; + } + this.out.write(b, off, chunk); + this.total += chunk; + } + } + + @Override + public void write(final byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(final int b) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + if (this.total < this.contentLength) { + this.out.write(b); + this.total++; + } + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParser.java new file mode 100644 index 000000000..70383a22e --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParser.java @@ -0,0 +1,140 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.ConnectionClosedException; +import ch.boye.httpclientandroidlib.HttpException; +import ch.boye.httpclientandroidlib.HttpRequest; +import ch.boye.httpclientandroidlib.HttpRequestFactory; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.config.MessageConstraints; +import ch.boye.httpclientandroidlib.impl.DefaultHttpRequestFactory; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.message.LineParser; +import ch.boye.httpclientandroidlib.message.ParserCursor; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * HTTP request parser that obtain its input from an instance + * of {@link SessionInputBuffer}. + * + * @since 4.2 + */ +@SuppressWarnings("deprecation") +@NotThreadSafe +public class DefaultHttpRequestParser extends AbstractMessageParser { + + private final HttpRequestFactory requestFactory; + private final CharArrayBuffer lineBuf; + + /** + * Creates an instance of this class. + * + * @param buffer the session input buffer. + * @param lineParser the line parser. + * @param requestFactory the factory to use to create + * {@link HttpRequest}s. + * @param params HTTP parameters. + * + * @deprecated (4.3) use + * {@link DefaultHttpRequestParser#DefaultHttpRequestParser(SessionInputBuffer, LineParser, + * HttpRequestFactory, MessageConstraints)} + */ + @Deprecated + public DefaultHttpRequestParser( + final SessionInputBuffer buffer, + final LineParser lineParser, + final HttpRequestFactory requestFactory, + final HttpParams params) { + super(buffer, lineParser, params); + this.requestFactory = Args.notNull(requestFactory, "Request factory"); + this.lineBuf = new CharArrayBuffer(128); + } + + /** + * Creates new instance of DefaultHttpRequestParser. + * + * @param buffer the session input buffer. + * @param lineParser the line parser. If null + * {@link ch.boye.httpclientandroidlib.message.BasicLineParser#INSTANCE} will be used. + * @param requestFactory the response factory. If null + * {@link DefaultHttpRequestFactory#INSTANCE} will be used. + * @param constraints the message constraints. If null + * {@link MessageConstraints#DEFAULT} will be used. + * + * @since 4.3 + */ + public DefaultHttpRequestParser( + final SessionInputBuffer buffer, + final LineParser lineParser, + final HttpRequestFactory requestFactory, + final MessageConstraints constraints) { + super(buffer, lineParser, constraints); + this.requestFactory = requestFactory != null ? requestFactory : + DefaultHttpRequestFactory.INSTANCE; + this.lineBuf = new CharArrayBuffer(128); + } + + /** + * @since 4.3 + */ + public DefaultHttpRequestParser( + final SessionInputBuffer buffer, + final MessageConstraints constraints) { + this(buffer, null, null, constraints); + } + + /** + * @since 4.3 + */ + public DefaultHttpRequestParser(final SessionInputBuffer buffer) { + this(buffer, null, null, MessageConstraints.DEFAULT); + } + + @Override + protected HttpRequest parseHead( + final SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException { + + this.lineBuf.clear(); + final int i = sessionBuffer.readLine(this.lineBuf); + if (i == -1) { + throw new ConnectionClosedException("Client closed connection"); + } + final ParserCursor cursor = new ParserCursor(0, this.lineBuf.length()); + final RequestLine requestline = this.lineParser.parseRequestLine(this.lineBuf, cursor); + return this.requestFactory.newHttpRequest(requestline); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParserFactory.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParserFactory.java new file mode 100644 index 000000000..81e886059 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestParserFactory.java @@ -0,0 +1,71 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import ch.boye.httpclientandroidlib.HttpRequest; +import ch.boye.httpclientandroidlib.HttpRequestFactory; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.config.MessageConstraints; +import ch.boye.httpclientandroidlib.impl.DefaultHttpRequestFactory; +import ch.boye.httpclientandroidlib.io.HttpMessageParser; +import ch.boye.httpclientandroidlib.io.HttpMessageParserFactory; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.message.BasicLineParser; +import ch.boye.httpclientandroidlib.message.LineParser; + +/** + * Default factory for request message parsers. + * + * @since 4.3 + */ +@Immutable +public class DefaultHttpRequestParserFactory implements HttpMessageParserFactory { + + public static final DefaultHttpRequestParserFactory INSTANCE = new DefaultHttpRequestParserFactory(); + + private final LineParser lineParser; + private final HttpRequestFactory requestFactory; + + public DefaultHttpRequestParserFactory(final LineParser lineParser, + final HttpRequestFactory requestFactory) { + super(); + this.lineParser = lineParser != null ? lineParser : BasicLineParser.INSTANCE; + this.requestFactory = requestFactory != null ? requestFactory + : DefaultHttpRequestFactory.INSTANCE; + } + + public DefaultHttpRequestParserFactory() { + this(null, null); + } + + public HttpMessageParser create(final SessionInputBuffer buffer, + final MessageConstraints constraints) { + return new DefaultHttpRequestParser(buffer, lineParser, requestFactory, constraints); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriter.java new file mode 100644 index 000000000..0f3b31e18 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriter.java @@ -0,0 +1,69 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.HttpRequest; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.message.LineFormatter; + +/** + * HTTP request writer that serializes its output to an instance of {@link SessionOutputBuffer}. + * + * @since 4.3 + */ +@NotThreadSafe +public class DefaultHttpRequestWriter extends AbstractMessageWriter { + + /** + * Creates an instance of DefaultHttpRequestWriter. + * + * @param buffer the session output buffer. + * @param formatter the line formatter If null + * {@link ch.boye.httpclientandroidlib.message.BasicLineFormatter#INSTANCE} + * will be used. + */ + public DefaultHttpRequestWriter( + final SessionOutputBuffer buffer, + final LineFormatter formatter) { + super(buffer, formatter); + } + + public DefaultHttpRequestWriter(final SessionOutputBuffer buffer) { + this(buffer, null); + } + + @Override + protected void writeHeadLine(final HttpRequest message) throws IOException { + lineFormatter.formatRequestLine(this.lineBuf, message.getRequestLine()); + this.sessionBuffer.writeLine(this.lineBuf); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriterFactory.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriterFactory.java new file mode 100644 index 000000000..410cc2ac3 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpRequestWriterFactory.java @@ -0,0 +1,63 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import ch.boye.httpclientandroidlib.HttpRequest; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.io.HttpMessageWriter; +import ch.boye.httpclientandroidlib.io.HttpMessageWriterFactory; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.message.BasicLineFormatter; +import ch.boye.httpclientandroidlib.message.LineFormatter; + +/** + * Default factory for request message writers. + * + * @since 4.3 + */ +@Immutable +public class DefaultHttpRequestWriterFactory implements HttpMessageWriterFactory { + + public static final DefaultHttpRequestWriterFactory INSTANCE = new DefaultHttpRequestWriterFactory(); + + private final LineFormatter lineFormatter; + + public DefaultHttpRequestWriterFactory(final LineFormatter lineFormatter) { + super(); + this.lineFormatter = lineFormatter != null ? lineFormatter : BasicLineFormatter.INSTANCE; + } + + public DefaultHttpRequestWriterFactory() { + this(null); + } + + public HttpMessageWriter create(final SessionOutputBuffer buffer) { + return new DefaultHttpRequestWriter(buffer, lineFormatter); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParser.java new file mode 100644 index 000000000..a8428e812 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParser.java @@ -0,0 +1,141 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.HttpException; +import ch.boye.httpclientandroidlib.HttpResponse; +import ch.boye.httpclientandroidlib.HttpResponseFactory; +import ch.boye.httpclientandroidlib.NoHttpResponseException; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.config.MessageConstraints; +import ch.boye.httpclientandroidlib.impl.DefaultHttpResponseFactory; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.message.LineParser; +import ch.boye.httpclientandroidlib.message.ParserCursor; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * HTTP response parser that obtain its input from an instance + * of {@link SessionInputBuffer}. + * + * @since 4.2 + */ +@SuppressWarnings("deprecation") +@NotThreadSafe +public class DefaultHttpResponseParser extends AbstractMessageParser { + + private final HttpResponseFactory responseFactory; + private final CharArrayBuffer lineBuf; + + /** + * Creates an instance of this class. + * + * @param buffer the session input buffer. + * @param lineParser the line parser. + * @param responseFactory the factory to use to create + * {@link HttpResponse}s. + * @param params HTTP parameters. + * + * @deprecated (4.3) use + * {@link DefaultHttpResponseParser#DefaultHttpResponseParser(SessionInputBuffer, LineParser, + * HttpResponseFactory, MessageConstraints)} + */ + @Deprecated + public DefaultHttpResponseParser( + final SessionInputBuffer buffer, + final LineParser lineParser, + final HttpResponseFactory responseFactory, + final HttpParams params) { + super(buffer, lineParser, params); + this.responseFactory = Args.notNull(responseFactory, "Response factory"); + this.lineBuf = new CharArrayBuffer(128); + } + + /** + * Creates new instance of DefaultHttpResponseParser. + * + * @param buffer the session input buffer. + * @param lineParser the line parser. If null + * {@link ch.boye.httpclientandroidlib.message.BasicLineParser#INSTANCE} will be used + * @param responseFactory the response factory. If null + * {@link DefaultHttpResponseFactory#INSTANCE} will be used. + * @param constraints the message constraints. If null + * {@link MessageConstraints#DEFAULT} will be used. + * + * @since 4.3 + */ + public DefaultHttpResponseParser( + final SessionInputBuffer buffer, + final LineParser lineParser, + final HttpResponseFactory responseFactory, + final MessageConstraints constraints) { + super(buffer, lineParser, constraints); + this.responseFactory = responseFactory != null ? responseFactory : + DefaultHttpResponseFactory.INSTANCE; + this.lineBuf = new CharArrayBuffer(128); + } + + /** + * @since 4.3 + */ + public DefaultHttpResponseParser( + final SessionInputBuffer buffer, + final MessageConstraints constraints) { + this(buffer, null, null, constraints); + } + + /** + * @since 4.3 + */ + public DefaultHttpResponseParser(final SessionInputBuffer buffer) { + this(buffer, null, null, MessageConstraints.DEFAULT); + } + + @Override + protected HttpResponse parseHead( + final SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException { + + this.lineBuf.clear(); + final int i = sessionBuffer.readLine(this.lineBuf); + if (i == -1) { + throw new NoHttpResponseException("The target server failed to respond"); + } + //create the status line from the status string + final ParserCursor cursor = new ParserCursor(0, this.lineBuf.length()); + final StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, cursor); + return this.responseFactory.newHttpResponse(statusline, null); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParserFactory.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParserFactory.java new file mode 100644 index 000000000..318abcf70 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseParserFactory.java @@ -0,0 +1,71 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import ch.boye.httpclientandroidlib.HttpResponse; +import ch.boye.httpclientandroidlib.HttpResponseFactory; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.config.MessageConstraints; +import ch.boye.httpclientandroidlib.impl.DefaultHttpResponseFactory; +import ch.boye.httpclientandroidlib.io.HttpMessageParser; +import ch.boye.httpclientandroidlib.io.HttpMessageParserFactory; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.message.BasicLineParser; +import ch.boye.httpclientandroidlib.message.LineParser; + +/** + * Default factory for response message parsers. + * + * @since 4.3 + */ +@Immutable +public class DefaultHttpResponseParserFactory implements HttpMessageParserFactory { + + public static final DefaultHttpResponseParserFactory INSTANCE = new DefaultHttpResponseParserFactory(); + + private final LineParser lineParser; + private final HttpResponseFactory responseFactory; + + public DefaultHttpResponseParserFactory(final LineParser lineParser, + final HttpResponseFactory responseFactory) { + super(); + this.lineParser = lineParser != null ? lineParser : BasicLineParser.INSTANCE; + this.responseFactory = responseFactory != null ? responseFactory + : DefaultHttpResponseFactory.INSTANCE; + } + + public DefaultHttpResponseParserFactory() { + this(null, null); + } + + public HttpMessageParser create(final SessionInputBuffer buffer, + final MessageConstraints constraints) { + return new DefaultHttpResponseParser(buffer, lineParser, responseFactory, constraints); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriter.java new file mode 100644 index 000000000..8cdef00a5 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriter.java @@ -0,0 +1,69 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.HttpResponse; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.message.LineFormatter; + +/** + * HTTP response writer that serializes its output to an instance of {@link SessionOutputBuffer}. + * + * @since 4.3 + */ +@NotThreadSafe +public class DefaultHttpResponseWriter extends AbstractMessageWriter { + + /** + * Creates an instance of DefaultHttpResponseWriter. + * + * @param buffer the session output buffer. + * @param formatter the line formatter If null + * {@link ch.boye.httpclientandroidlib.message.BasicLineFormatter#INSTANCE} + * will be used. + */ + public DefaultHttpResponseWriter( + final SessionOutputBuffer buffer, + final LineFormatter formatter) { + super(buffer, formatter); + } + + public DefaultHttpResponseWriter(final SessionOutputBuffer buffer) { + super(buffer, null); + } + + @Override + protected void writeHeadLine(final HttpResponse message) throws IOException { + lineFormatter.formatStatusLine(this.lineBuf, message.getStatusLine()); + this.sessionBuffer.writeLine(this.lineBuf); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriterFactory.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriterFactory.java new file mode 100644 index 000000000..9dc29606d --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/DefaultHttpResponseWriterFactory.java @@ -0,0 +1,63 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import ch.boye.httpclientandroidlib.HttpResponse; +import ch.boye.httpclientandroidlib.annotation.Immutable; +import ch.boye.httpclientandroidlib.io.HttpMessageWriter; +import ch.boye.httpclientandroidlib.io.HttpMessageWriterFactory; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.message.BasicLineFormatter; +import ch.boye.httpclientandroidlib.message.LineFormatter; + +/** + * Default factory for response message writers. + * + * @since 4.3 + */ +@Immutable +public class DefaultHttpResponseWriterFactory implements HttpMessageWriterFactory { + + public static final DefaultHttpResponseWriterFactory INSTANCE = new DefaultHttpResponseWriterFactory(); + + private final LineFormatter lineFormatter; + + public DefaultHttpResponseWriterFactory(final LineFormatter lineFormatter) { + super(); + this.lineFormatter = lineFormatter != null ? lineFormatter : BasicLineFormatter.INSTANCE; + } + + public DefaultHttpResponseWriterFactory() { + this(null); + } + + public HttpMessageWriter create(final SessionOutputBuffer buffer) { + return new DefaultHttpResponseWriter(buffer, lineFormatter); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestParser.java new file mode 100644 index 000000000..9c68b6938 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestParser.java @@ -0,0 +1,102 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.ConnectionClosedException; +import ch.boye.httpclientandroidlib.HttpException; +import ch.boye.httpclientandroidlib.HttpMessage; +import ch.boye.httpclientandroidlib.HttpRequestFactory; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.RequestLine; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.message.LineParser; +import ch.boye.httpclientandroidlib.message.ParserCursor; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * HTTP request parser that obtain its input from an instance + * of {@link SessionInputBuffer}. + *

+ * The following parameters can be used to customize the behavior of this + * class: + *

    + *
  • {@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_HEADER_COUNT}
  • + *
  • {@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_LINE_LENGTH}
  • + *
+ * + * @since 4.0 + * + * @deprecated (4.2) use {@link DefaultHttpRequestParser} + */ +@Deprecated +@NotThreadSafe +public class HttpRequestParser extends AbstractMessageParser { + + private final HttpRequestFactory requestFactory; + private final CharArrayBuffer lineBuf; + + /** + * Creates an instance of this class. + * + * @param buffer the session input buffer. + * @param parser the line parser. + * @param requestFactory the factory to use to create + * {@link ch.boye.httpclientandroidlib.HttpRequest}s. + * @param params HTTP parameters. + */ + public HttpRequestParser( + final SessionInputBuffer buffer, + final LineParser parser, + final HttpRequestFactory requestFactory, + final HttpParams params) { + super(buffer, parser, params); + this.requestFactory = Args.notNull(requestFactory, "Request factory"); + this.lineBuf = new CharArrayBuffer(128); + } + + @Override + protected HttpMessage parseHead( + final SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException { + + this.lineBuf.clear(); + final int i = sessionBuffer.readLine(this.lineBuf); + if (i == -1) { + throw new ConnectionClosedException("Client closed connection"); + } + final ParserCursor cursor = new ParserCursor(0, this.lineBuf.length()); + final RequestLine requestline = this.lineParser.parseRequestLine(this.lineBuf, cursor); + return this.requestFactory.newHttpRequest(requestline); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestWriter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestWriter.java new file mode 100644 index 000000000..3603ef573 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpRequestWriter.java @@ -0,0 +1,62 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.HttpRequest; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.message.LineFormatter; +import ch.boye.httpclientandroidlib.params.HttpParams; + +/** + * HTTP request writer that serializes its output to an instance + * of {@link SessionOutputBuffer}. + * + * @since 4.0 + * + * @deprecated (4.3) use {@link DefaultHttpRequestWriter} + */ +@NotThreadSafe +@Deprecated +public class HttpRequestWriter extends AbstractMessageWriter { + + public HttpRequestWriter(final SessionOutputBuffer buffer, + final LineFormatter formatter, + final HttpParams params) { + super(buffer, formatter, params); + } + + @Override + protected void writeHeadLine(final HttpRequest message) throws IOException { + lineFormatter.formatRequestLine(this.lineBuf, message.getRequestLine()); + this.sessionBuffer.writeLine(this.lineBuf); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseParser.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseParser.java new file mode 100644 index 000000000..a94eae36c --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseParser.java @@ -0,0 +1,103 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.HttpException; +import ch.boye.httpclientandroidlib.HttpMessage; +import ch.boye.httpclientandroidlib.HttpResponseFactory; +import ch.boye.httpclientandroidlib.NoHttpResponseException; +import ch.boye.httpclientandroidlib.ParseException; +import ch.boye.httpclientandroidlib.StatusLine; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.message.LineParser; +import ch.boye.httpclientandroidlib.message.ParserCursor; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * HTTP response parser that obtain its input from an instance + * of {@link SessionInputBuffer}. + *

+ * The following parameters can be used to customize the behavior of this + * class: + *

    + *
  • {@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_HEADER_COUNT}
  • + *
  • {@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_LINE_LENGTH}
  • + *
+ * + * @since 4.0 + * + * @deprecated (4.2) use {@link DefaultHttpResponseParser} + */ +@Deprecated +@NotThreadSafe +public class HttpResponseParser extends AbstractMessageParser { + + private final HttpResponseFactory responseFactory; + private final CharArrayBuffer lineBuf; + + /** + * Creates an instance of this class. + * + * @param buffer the session input buffer. + * @param parser the line parser. + * @param responseFactory the factory to use to create + * {@link ch.boye.httpclientandroidlib.HttpResponse}s. + * @param params HTTP parameters. + */ + public HttpResponseParser( + final SessionInputBuffer buffer, + final LineParser parser, + final HttpResponseFactory responseFactory, + final HttpParams params) { + super(buffer, parser, params); + this.responseFactory = Args.notNull(responseFactory, "Response factory"); + this.lineBuf = new CharArrayBuffer(128); + } + + @Override + protected HttpMessage parseHead( + final SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException { + + this.lineBuf.clear(); + final int i = sessionBuffer.readLine(this.lineBuf); + if (i == -1) { + throw new NoHttpResponseException("The target server failed to respond"); + } + //create the status line from the status string + final ParserCursor cursor = new ParserCursor(0, this.lineBuf.length()); + final StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, cursor); + return this.responseFactory.newHttpResponse(statusline, null); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseWriter.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseWriter.java new file mode 100644 index 000000000..2e82ade18 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpResponseWriter.java @@ -0,0 +1,62 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; + +import ch.boye.httpclientandroidlib.HttpResponse; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.message.LineFormatter; +import ch.boye.httpclientandroidlib.params.HttpParams; + +/** + * HTTP response writer that serializes its output to an instance + * of {@link SessionOutputBuffer}. + * + * @since 4.0 + * + * @deprecated (4.3) use {@link DefaultHttpResponseWriter} + */ +@NotThreadSafe +@Deprecated +public class HttpResponseWriter extends AbstractMessageWriter { + + public HttpResponseWriter(final SessionOutputBuffer buffer, + final LineFormatter formatter, + final HttpParams params) { + super(buffer, formatter, params); + } + + @Override + protected void writeHeadLine(final HttpResponse message) throws IOException { + lineFormatter.formatStatusLine(this.lineBuf, message.getStatusLine()); + this.sessionBuffer.writeLine(this.lineBuf); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpTransportMetricsImpl.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpTransportMetricsImpl.java new file mode 100644 index 000000000..8bd4eae5f --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/HttpTransportMetricsImpl.java @@ -0,0 +1,63 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.HttpTransportMetrics; + +/** + * Default implementation of {@link HttpTransportMetrics}. + * + * @since 4.0 + */ +@NotThreadSafe +public class HttpTransportMetricsImpl implements HttpTransportMetrics { + + private long bytesTransferred = 0; + + public HttpTransportMetricsImpl() { + super(); + } + + public long getBytesTransferred() { + return this.bytesTransferred; + } + + public void setBytesTransferred(final long count) { + this.bytesTransferred = count; + } + + public void incrementBytesTransferred(final long count) { + this.bytesTransferred += count; + } + + public void reset() { + this.bytesTransferred = 0; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityInputStream.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityInputStream.java new file mode 100644 index 000000000..98e1cf81a --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityInputStream.java @@ -0,0 +1,99 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.InputStream; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.BufferInfo; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Input stream that reads data without any transformation. The end of the + * content entity is demarcated by closing the underlying connection + * (EOF condition). Entities transferred using this input stream can be of + * unlimited length. + *

+ * Note that this class NEVER closes the underlying stream, even when close + * gets called. Instead, it will read until the end of the stream (until + * -1 is returned). + * + * @since 4.0 + */ +@NotThreadSafe +public class IdentityInputStream extends InputStream { + + private final SessionInputBuffer in; + + private boolean closed = false; + + /** + * Wraps session input stream and reads input until the the end of stream. + * + * @param in The session input buffer + */ + public IdentityInputStream(final SessionInputBuffer in) { + super(); + this.in = Args.notNull(in, "Session input buffer"); + } + + @Override + public int available() throws IOException { + if (this.in instanceof BufferInfo) { + return ((BufferInfo) this.in).length(); + } else { + return 0; + } + } + + @Override + public void close() throws IOException { + this.closed = true; + } + + @Override + public int read() throws IOException { + if (this.closed) { + return -1; + } else { + return this.in.read(); + } + } + + @Override + public int read(final byte[] b, final int off, final int len) throws IOException { + if (this.closed) { + return -1; + } else { + return this.in.read(b, off, len); + } + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityOutputStream.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityOutputStream.java new file mode 100644 index 000000000..ac2f613b7 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/IdentityOutputStream.java @@ -0,0 +1,104 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.OutputStream; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * Output stream that writes data without any transformation. The end of + * the content entity is demarcated by closing the underlying connection + * (EOF condition). Entities transferred using this input stream can be of + * unlimited length. + *

+ * Note that this class NEVER closes the underlying stream, even when close + * gets called. Instead, the stream will be marked as closed and no further + * output will be permitted. + * + * @since 4.0 + */ +@NotThreadSafe +public class IdentityOutputStream extends OutputStream { + + /** + * Wrapped session output buffer. + */ + private final SessionOutputBuffer out; + + /** True if the stream is closed. */ + private boolean closed = false; + + public IdentityOutputStream(final SessionOutputBuffer out) { + super(); + this.out = Args.notNull(out, "Session output buffer"); + } + + /** + *

Does not close the underlying socket output.

+ * + * @throws IOException If an I/O problem occurs. + */ + @Override + public void close() throws IOException { + if (!this.closed) { + this.closed = true; + this.out.flush(); + } + } + + @Override + public void flush() throws IOException { + this.out.flush(); + } + + @Override + public void write(final byte[] b, final int off, final int len) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + this.out.write(b, off, len); + } + + @Override + public void write(final byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(final int b) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + this.out.write(b); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionInputBufferImpl.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionInputBufferImpl.java new file mode 100644 index 000000000..ed86cb94b --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionInputBufferImpl.java @@ -0,0 +1,399 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; + +import ch.boye.httpclientandroidlib.MessageConstraintException; +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.config.MessageConstraints; +import ch.boye.httpclientandroidlib.io.BufferInfo; +import ch.boye.httpclientandroidlib.io.HttpTransportMetrics; +import ch.boye.httpclientandroidlib.io.SessionInputBuffer; +import ch.boye.httpclientandroidlib.protocol.HTTP; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.Asserts; +import ch.boye.httpclientandroidlib.util.ByteArrayBuffer; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Abstract base class for session input buffers that stream data from + * an arbitrary {@link InputStream}. This class buffers input data in + * an internal byte array for optimal input performance. + *

+ * {@link #readLine(CharArrayBuffer)} and {@link #readLine()} methods of this + * class treat a lone LF as valid line delimiters in addition to CR-LF required + * by the HTTP specification. + * + * @since 4.3 + */ +@NotThreadSafe +public class SessionInputBufferImpl implements SessionInputBuffer, BufferInfo { + + private final HttpTransportMetricsImpl metrics; + private final byte[] buffer; + private final ByteArrayBuffer linebuffer; + private final int minChunkLimit; + private final MessageConstraints constraints; + private final CharsetDecoder decoder; + + private InputStream instream; + private int bufferpos; + private int bufferlen; + private CharBuffer cbuf; + + /** + * Creates new instance of SessionInputBufferImpl. + * + * @param metrics HTTP transport metrics. + * @param buffersize buffer size. Must be a positive number. + * @param minChunkLimit size limit below which data chunks should be buffered in memory + * in order to minimize native method invocations on the underlying network socket. + * The optimal value of this parameter can be platform specific and defines a trade-off + * between performance of memory copy operations and that of native method invocation. + * If negative default chunk limited will be used. + * @param constraints Message constraints. If null + * {@link MessageConstraints#DEFAULT} will be used. + * @param chardecoder chardecoder to be used for decoding HTTP protocol elements. + * If null simple type cast will be used for byte to char conversion. + */ + public SessionInputBufferImpl( + final HttpTransportMetricsImpl metrics, + final int buffersize, + final int minChunkLimit, + final MessageConstraints constraints, + final CharsetDecoder chardecoder) { + Args.notNull(metrics, "HTTP transport metrcis"); + Args.positive(buffersize, "Buffer size"); + this.metrics = metrics; + this.buffer = new byte[buffersize]; + this.bufferpos = 0; + this.bufferlen = 0; + this.minChunkLimit = minChunkLimit >= 0 ? minChunkLimit : 512; + this.constraints = constraints != null ? constraints : MessageConstraints.DEFAULT; + this.linebuffer = new ByteArrayBuffer(buffersize); + this.decoder = chardecoder; + } + + public SessionInputBufferImpl( + final HttpTransportMetricsImpl metrics, + final int buffersize) { + this(metrics, buffersize, buffersize, null, null); + } + + public void bind(final InputStream instream) { + this.instream = instream; + } + + public boolean isBound() { + return this.instream != null; + } + + public int capacity() { + return this.buffer.length; + } + + public int length() { + return this.bufferlen - this.bufferpos; + } + + public int available() { + return capacity() - length(); + } + + private int streamRead(final byte[] b, final int off, final int len) throws IOException { + Asserts.notNull(this.instream, "Input stream"); + return this.instream.read(b, off, len); + } + + public int fillBuffer() throws IOException { + // compact the buffer if necessary + if (this.bufferpos > 0) { + final int len = this.bufferlen - this.bufferpos; + if (len > 0) { + System.arraycopy(this.buffer, this.bufferpos, this.buffer, 0, len); + } + this.bufferpos = 0; + this.bufferlen = len; + } + final int l; + final int off = this.bufferlen; + final int len = this.buffer.length - off; + l = streamRead(this.buffer, off, len); + if (l == -1) { + return -1; + } else { + this.bufferlen = off + l; + this.metrics.incrementBytesTransferred(l); + return l; + } + } + + public boolean hasBufferedData() { + return this.bufferpos < this.bufferlen; + } + + public void clear() { + this.bufferpos = 0; + this.bufferlen = 0; + } + + public int read() throws IOException { + int noRead; + while (!hasBufferedData()) { + noRead = fillBuffer(); + if (noRead == -1) { + return -1; + } + } + return this.buffer[this.bufferpos++] & 0xff; + } + + public int read(final byte[] b, final int off, final int len) throws IOException { + if (b == null) { + return 0; + } + if (hasBufferedData()) { + final int chunk = Math.min(len, this.bufferlen - this.bufferpos); + System.arraycopy(this.buffer, this.bufferpos, b, off, chunk); + this.bufferpos += chunk; + return chunk; + } + // If the remaining capacity is big enough, read directly from the + // underlying input stream bypassing the buffer. + if (len > this.minChunkLimit) { + final int read = streamRead(b, off, len); + if (read > 0) { + this.metrics.incrementBytesTransferred(read); + } + return read; + } else { + // otherwise read to the buffer first + while (!hasBufferedData()) { + final int noRead = fillBuffer(); + if (noRead == -1) { + return -1; + } + } + final int chunk = Math.min(len, this.bufferlen - this.bufferpos); + System.arraycopy(this.buffer, this.bufferpos, b, off, chunk); + this.bufferpos += chunk; + return chunk; + } + } + + public int read(final byte[] b) throws IOException { + if (b == null) { + return 0; + } + return read(b, 0, b.length); + } + + private int locateLF() { + for (int i = this.bufferpos; i < this.bufferlen; i++) { + if (this.buffer[i] == HTTP.LF) { + return i; + } + } + return -1; + } + + /** + * Reads a complete line of characters up to a line delimiter from this + * session buffer into the given line buffer. The number of chars actually + * read is returned as an integer. The line delimiter itself is discarded. + * If no char is available because the end of the stream has been reached, + * the value -1 is returned. This method blocks until input + * data is available, end of file is detected, or an exception is thrown. + *

+ * This method treats a lone LF as a valid line delimiters in addition + * to CR-LF required by the HTTP specification. + * + * @param charbuffer the line buffer. + * @return one line of characters + * @exception IOException if an I/O error occurs. + */ + public int readLine(final CharArrayBuffer charbuffer) throws IOException { + Args.notNull(charbuffer, "Char array buffer"); + int noRead = 0; + boolean retry = true; + while (retry) { + // attempt to find end of line (LF) + final int i = locateLF(); + if (i != -1) { + // end of line found. + if (this.linebuffer.isEmpty()) { + // the entire line is preset in the read buffer + return lineFromReadBuffer(charbuffer, i); + } + retry = false; + final int len = i + 1 - this.bufferpos; + this.linebuffer.append(this.buffer, this.bufferpos, len); + this.bufferpos = i + 1; + } else { + // end of line not found + if (hasBufferedData()) { + final int len = this.bufferlen - this.bufferpos; + this.linebuffer.append(this.buffer, this.bufferpos, len); + this.bufferpos = this.bufferlen; + } + noRead = fillBuffer(); + if (noRead == -1) { + retry = false; + } + } + final int maxLineLen = this.constraints.getMaxLineLength(); + if (maxLineLen > 0 && this.linebuffer.length() >= maxLineLen) { + throw new MessageConstraintException("Maximum line length limit exceeded"); + } + } + if (noRead == -1 && this.linebuffer.isEmpty()) { + // indicate the end of stream + return -1; + } + return lineFromLineBuffer(charbuffer); + } + + /** + * Reads a complete line of characters up to a line delimiter from this + * session buffer. The line delimiter itself is discarded. If no char is + * available because the end of the stream has been reached, + * null is returned. This method blocks until input data is + * available, end of file is detected, or an exception is thrown. + *

+ * This method treats a lone LF as a valid line delimiters in addition + * to CR-LF required by the HTTP specification. + * + * @return HTTP line as a string + * @exception IOException if an I/O error occurs. + */ + private int lineFromLineBuffer(final CharArrayBuffer charbuffer) + throws IOException { + // discard LF if found + int len = this.linebuffer.length(); + if (len > 0) { + if (this.linebuffer.byteAt(len - 1) == HTTP.LF) { + len--; + } + // discard CR if found + if (len > 0) { + if (this.linebuffer.byteAt(len - 1) == HTTP.CR) { + len--; + } + } + } + if (this.decoder == null) { + charbuffer.append(this.linebuffer, 0, len); + } else { + final ByteBuffer bbuf = ByteBuffer.wrap(this.linebuffer.buffer(), 0, len); + len = appendDecoded(charbuffer, bbuf); + } + this.linebuffer.clear(); + return len; + } + + private int lineFromReadBuffer(final CharArrayBuffer charbuffer, final int position) + throws IOException { + int pos = position; + final int off = this.bufferpos; + int len; + this.bufferpos = pos + 1; + if (pos > off && this.buffer[pos - 1] == HTTP.CR) { + // skip CR if found + pos--; + } + len = pos - off; + if (this.decoder == null) { + charbuffer.append(this.buffer, off, len); + } else { + final ByteBuffer bbuf = ByteBuffer.wrap(this.buffer, off, len); + len = appendDecoded(charbuffer, bbuf); + } + return len; + } + + private int appendDecoded( + final CharArrayBuffer charbuffer, final ByteBuffer bbuf) throws IOException { + if (!bbuf.hasRemaining()) { + return 0; + } + if (this.cbuf == null) { + this.cbuf = CharBuffer.allocate(1024); + } + this.decoder.reset(); + int len = 0; + while (bbuf.hasRemaining()) { + final CoderResult result = this.decoder.decode(bbuf, this.cbuf, true); + len += handleDecodingResult(result, charbuffer, bbuf); + } + final CoderResult result = this.decoder.flush(this.cbuf); + len += handleDecodingResult(result, charbuffer, bbuf); + this.cbuf.clear(); + return len; + } + + private int handleDecodingResult( + final CoderResult result, + final CharArrayBuffer charbuffer, + final ByteBuffer bbuf) throws IOException { + if (result.isError()) { + result.throwException(); + } + this.cbuf.flip(); + final int len = this.cbuf.remaining(); + while (this.cbuf.hasRemaining()) { + charbuffer.append(this.cbuf.get()); + } + this.cbuf.compact(); + return len; + } + + public String readLine() throws IOException { + final CharArrayBuffer charbuffer = new CharArrayBuffer(64); + final int l = readLine(charbuffer); + if (l != -1) { + return charbuffer.toString(); + } else { + return null; + } + } + + public boolean isDataAvailable(final int timeout) throws IOException { + return hasBufferedData(); + } + + public HttpTransportMetrics getMetrics() { + return this.metrics; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionOutputBufferImpl.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionOutputBufferImpl.java new file mode 100644 index 000000000..99ca871ce --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SessionOutputBufferImpl.java @@ -0,0 +1,283 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.BufferInfo; +import ch.boye.httpclientandroidlib.io.HttpTransportMetrics; +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; +import ch.boye.httpclientandroidlib.protocol.HTTP; +import ch.boye.httpclientandroidlib.util.Args; +import ch.boye.httpclientandroidlib.util.Asserts; +import ch.boye.httpclientandroidlib.util.ByteArrayBuffer; +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; + +/** + * Abstract base class for session output buffers that stream data to + * an arbitrary {@link OutputStream}. This class buffers small chunks of + * output data in an internal byte array for optimal output performance. + *

+ * {@link #writeLine(CharArrayBuffer)} and {@link #writeLine(String)} methods + * of this class use CR-LF as a line delimiter. + * + * @since 4.3 + */ +@NotThreadSafe +public class SessionOutputBufferImpl implements SessionOutputBuffer, BufferInfo { + + private static final byte[] CRLF = new byte[] {HTTP.CR, HTTP.LF}; + + private final HttpTransportMetricsImpl metrics; + private final ByteArrayBuffer buffer; + private final int fragementSizeHint; + private final CharsetEncoder encoder; + + private OutputStream outstream; + private ByteBuffer bbuf; + + /** + * Creates new instance of SessionOutputBufferImpl. + * + * @param metrics HTTP transport metrics. + * @param buffersize buffer size. Must be a positive number. + * @param fragementSizeHint fragment size hint defining a minimal size of a fragment + * that should be written out directly to the socket bypassing the session buffer. + * Value 0 disables fragment buffering. + * @param charencoder charencoder to be used for encoding HTTP protocol elements. + * If null simple type cast will be used for char to byte conversion. + */ + public SessionOutputBufferImpl( + final HttpTransportMetricsImpl metrics, + final int buffersize, + final int fragementSizeHint, + final CharsetEncoder charencoder) { + super(); + Args.positive(buffersize, "Buffer size"); + Args.notNull(metrics, "HTTP transport metrcis"); + this.metrics = metrics; + this.buffer = new ByteArrayBuffer(buffersize); + this.fragementSizeHint = fragementSizeHint >= 0 ? fragementSizeHint : 0; + this.encoder = charencoder; + } + + public SessionOutputBufferImpl( + final HttpTransportMetricsImpl metrics, + final int buffersize) { + this(metrics, buffersize, buffersize, null); + } + + public void bind(final OutputStream outstream) { + this.outstream = outstream; + } + + public boolean isBound() { + return this.outstream != null; + } + + public int capacity() { + return this.buffer.capacity(); + } + + public int length() { + return this.buffer.length(); + } + + public int available() { + return capacity() - length(); + } + + private void streamWrite(final byte[] b, final int off, final int len) throws IOException { + Asserts.notNull(outstream, "Output stream"); + this.outstream.write(b, off, len); + } + + private void flushStream() throws IOException { + if (this.outstream != null) { + this.outstream.flush(); + } + } + + private void flushBuffer() throws IOException { + final int len = this.buffer.length(); + if (len > 0) { + streamWrite(this.buffer.buffer(), 0, len); + this.buffer.clear(); + this.metrics.incrementBytesTransferred(len); + } + } + + public void flush() throws IOException { + flushBuffer(); + flushStream(); + } + + public void write(final byte[] b, final int off, final int len) throws IOException { + if (b == null) { + return; + } + // Do not want to buffer large-ish chunks + // if the byte array is larger then MIN_CHUNK_LIMIT + // write it directly to the output stream + if (len > this.fragementSizeHint || len > this.buffer.capacity()) { + // flush the buffer + flushBuffer(); + // write directly to the out stream + streamWrite(b, off, len); + this.metrics.incrementBytesTransferred(len); + } else { + // Do not let the buffer grow unnecessarily + final int freecapacity = this.buffer.capacity() - this.buffer.length(); + if (len > freecapacity) { + // flush the buffer + flushBuffer(); + } + // buffer + this.buffer.append(b, off, len); + } + } + + public void write(final byte[] b) throws IOException { + if (b == null) { + return; + } + write(b, 0, b.length); + } + + public void write(final int b) throws IOException { + if (this.fragementSizeHint > 0) { + if (this.buffer.isFull()) { + flushBuffer(); + } + this.buffer.append(b); + } else { + flushBuffer(); + this.outstream.write(b); + } + } + + /** + * Writes characters from the specified string followed by a line delimiter + * to this session buffer. + *

+ * This method uses CR-LF as a line delimiter. + * + * @param s the line. + * @exception IOException if an I/O error occurs. + */ + public void writeLine(final String s) throws IOException { + if (s == null) { + return; + } + if (s.length() > 0) { + if (this.encoder == null) { + for (int i = 0; i < s.length(); i++) { + write(s.charAt(i)); + } + } else { + final CharBuffer cbuf = CharBuffer.wrap(s); + writeEncoded(cbuf); + } + } + write(CRLF); + } + + /** + * Writes characters from the specified char array followed by a line + * delimiter to this session buffer. + *

+ * This method uses CR-LF as a line delimiter. + * + * @param charbuffer the buffer containing chars of the line. + * @exception IOException if an I/O error occurs. + */ + public void writeLine(final CharArrayBuffer charbuffer) throws IOException { + if (charbuffer == null) { + return; + } + if (this.encoder == null) { + int off = 0; + int remaining = charbuffer.length(); + while (remaining > 0) { + int chunk = this.buffer.capacity() - this.buffer.length(); + chunk = Math.min(chunk, remaining); + if (chunk > 0) { + this.buffer.append(charbuffer, off, chunk); + } + if (this.buffer.isFull()) { + flushBuffer(); + } + off += chunk; + remaining -= chunk; + } + } else { + final CharBuffer cbuf = CharBuffer.wrap(charbuffer.buffer(), 0, charbuffer.length()); + writeEncoded(cbuf); + } + write(CRLF); + } + + private void writeEncoded(final CharBuffer cbuf) throws IOException { + if (!cbuf.hasRemaining()) { + return; + } + if (this.bbuf == null) { + this.bbuf = ByteBuffer.allocate(1024); + } + this.encoder.reset(); + while (cbuf.hasRemaining()) { + final CoderResult result = this.encoder.encode(cbuf, this.bbuf, true); + handleEncodingResult(result); + } + final CoderResult result = this.encoder.flush(this.bbuf); + handleEncodingResult(result); + this.bbuf.clear(); + } + + private void handleEncodingResult(final CoderResult result) throws IOException { + if (result.isError()) { + result.throwException(); + } + this.bbuf.flip(); + while (this.bbuf.hasRemaining()) { + write(this.bbuf.get()); + } + this.bbuf.compact(); + } + + public HttpTransportMetrics getMetrics() { + return this.metrics; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketInputBuffer.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketInputBuffer.java new file mode 100644 index 000000000..4bba8f894 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketInputBuffer.java @@ -0,0 +1,108 @@ +/* + * ==================================================================== + * 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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.net.Socket; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.io.EofSensor; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * {@link ch.boye.httpclientandroidlib.io.SessionInputBuffer} implementation + * bound to a {@link Socket}. + * + * @since 4.0 + * + * @deprecated (4.3) use {@link SessionInputBufferImpl} + */ +@NotThreadSafe +@Deprecated +public class SocketInputBuffer extends AbstractSessionInputBuffer implements EofSensor { + + private final Socket socket; + + private boolean eof; + + /** + * Creates an instance of this class. + * + * @param socket the socket to read data from. + * @param buffersize the size of the internal buffer. If this number is less + * than 0 it is set to the value of + * {@link Socket#getReceiveBufferSize()}. If resultant number is less + * than 1024 it is set to 1024. + * @param params HTTP parameters. + */ + public SocketInputBuffer( + final Socket socket, + final int buffersize, + final HttpParams params) throws IOException { + super(); + Args.notNull(socket, "Socket"); + this.socket = socket; + this.eof = false; + int n = buffersize; + if (n < 0) { + n = socket.getReceiveBufferSize(); + } + if (n < 1024) { + n = 1024; + } + init(socket.getInputStream(), n, params); + } + + @Override + protected int fillBuffer() throws IOException { + final int i = super.fillBuffer(); + this.eof = i == -1; + return i; + } + + public boolean isDataAvailable(final int timeout) throws IOException { + boolean result = hasBufferedData(); + if (!result) { + final int oldtimeout = this.socket.getSoTimeout(); + try { + this.socket.setSoTimeout(timeout); + fillBuffer(); + result = hasBufferedData(); + } finally { + socket.setSoTimeout(oldtimeout); + } + } + return result; + } + + public boolean isEof() { + return this.eof; + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketOutputBuffer.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketOutputBuffer.java new file mode 100644 index 000000000..9c9ff2d9f --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/SocketOutputBuffer.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 + * . + * + */ + +package ch.boye.httpclientandroidlib.impl.io; + +import java.io.IOException; +import java.net.Socket; + +import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; +import ch.boye.httpclientandroidlib.params.HttpParams; +import ch.boye.httpclientandroidlib.util.Args; + +/** + * {@link ch.boye.httpclientandroidlib.io.SessionOutputBuffer} implementation + * bound to a {@link Socket}. + * + * @since 4.0 + * + * @deprecated (4.3) use {@link SessionOutputBufferImpl} + */ +@NotThreadSafe +@Deprecated +public class SocketOutputBuffer extends AbstractSessionOutputBuffer { + + /** + * Creates an instance of this class. + * + * @param socket the socket to write data to. + * @param buffersize the size of the internal buffer. If this number is less + * than 0 it is set to the value of + * {@link Socket#getSendBufferSize()}. If resultant number is less + * than 1024 it is set to 1024. + * @param params HTTP parameters. + */ + public SocketOutputBuffer( + final Socket socket, + final int buffersize, + final HttpParams params) throws IOException { + super(); + Args.notNull(socket, "Socket"); + int n = buffersize; + if (n < 0) { + n = socket.getSendBufferSize(); + } + if (n < 1024) { + n = 1024; + } + init(socket.getOutputStream(), n, params); + } + +} diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/package-info.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/package-info.java new file mode 100644 index 000000000..24c7bee79 --- /dev/null +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/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 + * . + * + */ + +/** + * Default implementations of message parses and writers + * for synchronous, blocking communication. + */ +package ch.boye.httpclientandroidlib.impl.io; -- cgit v1.2.3