diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:16 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:16 -0800 |
commit | 069490a5ca2fd1988d29daf45d892f47ad665115 (patch) | |
tree | aea04c65769a1d9e3ca6fde36a7d23bd91dbeb98 /src/org/apache/http/impl/io | |
parent | e5d9544310b857f3ee9ec172bdbff8077323f9a1 (diff) | |
download | external_apache-http-069490a5ca2fd1988d29daf45d892f47ad665115.zip external_apache-http-069490a5ca2fd1988d29daf45d892f47ad665115.tar.gz external_apache-http-069490a5ca2fd1988d29daf45d892f47ad665115.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'src/org/apache/http/impl/io')
18 files changed, 2333 insertions, 0 deletions
diff --git a/src/org/apache/http/impl/io/AbstractMessageParser.java b/src/org/apache/http/impl/io/AbstractMessageParser.java new file mode 100644 index 0000000..679bcd1 --- /dev/null +++ b/src/org/apache/http/impl/io/AbstractMessageParser.java @@ -0,0 +1,187 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java $ + * $Revision: 576077 $ + * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.util.ArrayList; + +import org.apache.http.Header; +import org.apache.http.HttpException; +import org.apache.http.HttpMessage; +import org.apache.http.ParseException; +import org.apache.http.ProtocolException; +import org.apache.http.io.HttpMessageParser; +import org.apache.http.io.SessionInputBuffer; +import org.apache.http.message.LineParser; +import org.apache.http.message.BasicLineParser; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + +/** + * Message parser base class. + * + * @author Michael Becke + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + */ +public abstract class AbstractMessageParser implements HttpMessageParser { + + private final SessionInputBuffer sessionBuffer; + private final int maxHeaderCount; + private final int maxLineLen; + protected final LineParser lineParser; + + + public AbstractMessageParser( + final SessionInputBuffer buffer, + final LineParser parser, + final HttpParams params) { + super(); + if (buffer == null) { + throw new IllegalArgumentException("Session input buffer may not be null"); + } + if (params == null) { + throw new IllegalArgumentException("HTTP parameters may not be null"); + } + this.sessionBuffer = buffer; + this.maxHeaderCount = params.getIntParameter( + CoreConnectionPNames.MAX_HEADER_COUNT, -1); + this.maxLineLen = params.getIntParameter( + CoreConnectionPNames.MAX_LINE_LENGTH, -1); + this.lineParser = (parser != null) ? parser : BasicLineParser.DEFAULT; + } + + /** + * 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 + * @return array of HTTP headers + * + * @throws HttpException + * @throws IOException + */ + public static Header[] parseHeaders( + final SessionInputBuffer inbuffer, + int maxHeaderCount, + int maxLineLen, + LineParser parser) + throws HttpException, IOException { + + if (inbuffer == null) { + throw new IllegalArgumentException("Session input buffer may not be null"); + } + if (parser == null) + parser = BasicLineParser.DEFAULT; + + ArrayList headerLines = new ArrayList(); + + CharArrayBuffer current = null; + CharArrayBuffer previous = null; + for (;;) { + if (current == null) { + current = new CharArrayBuffer(64); + } else { + current.clear(); + } + 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()) { + char ch = current.charAt(i); + if (ch != ' ' && ch != '\t') { + break; + } + i++; + } + if (maxLineLen > 0 + && previous.length() + 1 + current.length() - i > maxLineLen) { + throw new IOException("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 IOException("Maximum header count exceeded"); + } + } + Header[] headers = new Header[headerLines.size()]; + for (int i = 0; i < headerLines.size(); i++) { + CharArrayBuffer buffer = (CharArrayBuffer) headerLines.get(i); + try { + headers[i] = parser.parseHeader(buffer); + } catch (ParseException ex) { + throw new ProtocolException(ex.getMessage()); + } + } + return headers; + } + + protected abstract HttpMessage parseHead(SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException; + + public HttpMessage parse() throws IOException, HttpException { + HttpMessage message = null; + try { + message = parseHead(this.sessionBuffer); + } catch (ParseException px) { + throw new ProtocolException(px.getMessage(), px); + } + Header[] headers = AbstractMessageParser.parseHeaders( + this.sessionBuffer, + this.maxHeaderCount, + this.maxLineLen, + this.lineParser); + message.setHeaders(headers); + return message; + } + +} diff --git a/src/org/apache/http/impl/io/AbstractMessageWriter.java b/src/org/apache/http/impl/io/AbstractMessageWriter.java new file mode 100644 index 0000000..f9644ce --- /dev/null +++ b/src/org/apache/http/impl/io/AbstractMessageWriter.java @@ -0,0 +1,85 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractMessageWriter.java $ + * $Revision: 569673 $ + * $Date: 2007-08-25 06:58:51 -0700 (Sat, 25 Aug 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.util.Iterator; + +import org.apache.http.Header; +import org.apache.http.HttpException; +import org.apache.http.HttpMessage; +import org.apache.http.io.HttpMessageWriter; +import org.apache.http.io.SessionOutputBuffer; +import org.apache.http.message.LineFormatter; +import org.apache.http.message.BasicLineFormatter; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + +public abstract class AbstractMessageWriter implements HttpMessageWriter { + + protected final SessionOutputBuffer sessionBuffer; + protected final CharArrayBuffer lineBuf; + protected final LineFormatter lineFormatter; + + public AbstractMessageWriter(final SessionOutputBuffer buffer, + final LineFormatter formatter, + final HttpParams params) { + super(); + if (buffer == null) { + throw new IllegalArgumentException("Session input buffer may not be null"); + } + this.sessionBuffer = buffer; + this.lineBuf = new CharArrayBuffer(128); + this.lineFormatter = (formatter != null) ? + formatter : BasicLineFormatter.DEFAULT; + } + + protected abstract void writeHeadLine(HttpMessage message) + throws IOException + ; + + public void write( + final HttpMessage message) throws IOException, HttpException { + if (message == null) { + throw new IllegalArgumentException("HTTP message may not be null"); + } + writeHeadLine(message); + for (Iterator it = message.headerIterator(); it.hasNext(); ) { + Header header = (Header) it.next(); + this.sessionBuffer.writeLine + (lineFormatter.formatHeader(this.lineBuf, header)); + } + this.lineBuf.clear(); + this.sessionBuffer.writeLine(this.lineBuf); + } + +} diff --git a/src/org/apache/http/impl/io/AbstractSessionInputBuffer.java b/src/org/apache/http/impl/io/AbstractSessionInputBuffer.java new file mode 100644 index 0000000..eb007a9 --- /dev/null +++ b/src/org/apache/http/impl/io/AbstractSessionInputBuffer.java @@ -0,0 +1,271 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java $ + * $Revision: 576077 $ + * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.http.io.SessionInputBuffer; +import org.apache.http.io.HttpTransportMetrics; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.ByteArrayBuffer; +import org.apache.http.util.CharArrayBuffer; + +/** + * Abstract base class for session input buffers that stream data + * from a {@link InputStream}. + * + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + */ +public abstract class AbstractSessionInputBuffer implements SessionInputBuffer { + + private InputStream instream; + private byte[] buffer; + private int bufferpos; + private int bufferlen; + + private ByteArrayBuffer linebuffer = null; + + private String charset = HTTP.US_ASCII; + private boolean ascii = true; + private int maxLineLen = -1; + + private HttpTransportMetricsImpl metrics; + + protected void init(final InputStream instream, int buffersize, final HttpParams params) { + if (instream == null) { + throw new IllegalArgumentException("Input stream may not be null"); + } + if (buffersize <= 0) { + throw new IllegalArgumentException("Buffer size may not be negative or zero"); + } + if (params == null) { + throw new IllegalArgumentException("HTTP parameters may not be null"); + } + this.instream = instream; + this.buffer = new byte[buffersize]; + this.bufferpos = 0; + this.bufferlen = 0; + this.linebuffer = new ByteArrayBuffer(buffersize); + this.charset = HttpProtocolParams.getHttpElementCharset(params); + this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII) + || this.charset.equalsIgnoreCase(HTTP.ASCII); + this.maxLineLen = params.getIntParameter(CoreConnectionPNames.MAX_LINE_LENGTH, -1); + this.metrics = new HttpTransportMetricsImpl(); + } + + protected int fillBuffer() throws IOException { + // compact the buffer if necessary + if (this.bufferpos > 0) { + 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; + } + int l; + int off = this.bufferlen; + 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 = 0; + while (!hasBufferedData()) { + noRead = fillBuffer(); + if (noRead == -1) { + return -1; + } + } + return this.buffer[this.bufferpos++] & 0xff; + } + + public int read(final byte[] b, int off, int len) throws IOException { + if (b == null) { + return 0; + } + int noRead = 0; + while (!hasBufferedData()) { + noRead = fillBuffer(); + if (noRead == -1) { + return -1; + } + } + int chunk = this.bufferlen - this.bufferpos; + if (chunk > len) { + chunk = len; + } + 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; + } + + public int readLine(final CharArrayBuffer charbuffer) throws IOException { + if (charbuffer == null) { + throw new IllegalArgumentException("Char array buffer may not be null"); + } + this.linebuffer.clear(); + int noRead = 0; + boolean retry = true; + while (retry) { + // attempt to find end of line (LF) + 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; + 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()) { + 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); + } + + private int lineFromLineBuffer(final CharArrayBuffer charbuffer) + throws IOException { + // discard LF if found + int l = this.linebuffer.length(); + if (l > 0) { + if (this.linebuffer.byteAt(l - 1) == HTTP.LF) { + l--; + this.linebuffer.setLength(l); + } + // discard CR if found + if (l > 0) { + if (this.linebuffer.byteAt(l - 1) == HTTP.CR) { + l--; + this.linebuffer.setLength(l); + } + } + } + l = this.linebuffer.length(); + if (this.ascii) { + charbuffer.append(this.linebuffer, 0, l); + } else { + // This is VERY memory inefficient, BUT since non-ASCII charsets are + // NOT meant to be used anyway, there's no point optimizing it + String s = new String(this.linebuffer.buffer(), 0, l, this.charset); + charbuffer.append(s); + } + return l; + } + + private int lineFromReadBuffer(final CharArrayBuffer charbuffer, int pos) + throws IOException { + int off = this.bufferpos; + int len; + this.bufferpos = pos + 1; + if (pos > 0 && this.buffer[pos - 1] == HTTP.CR) { + // skip CR if found + pos--; + } + len = pos - off; + if (this.ascii) { + charbuffer.append(this.buffer, off, len); + } else { + // This is VERY memory inefficient, BUT since non-ASCII charsets are + // NOT meant to be used anyway, there's no point optimizing it + String s = new String(this.buffer, off, len, this.charset); + charbuffer.append(s); + } + return len; + } + + public String readLine() throws IOException { + CharArrayBuffer charbuffer = new CharArrayBuffer(64); + int l = readLine(charbuffer); + if (l != -1) { + return charbuffer.toString(); + } else { + return null; + } + } + + public HttpTransportMetrics getMetrics() { + return this.metrics; + } + +} diff --git a/src/org/apache/http/impl/io/AbstractSessionOutputBuffer.java b/src/org/apache/http/impl/io/AbstractSessionOutputBuffer.java new file mode 100644 index 0000000..bf4e56e --- /dev/null +++ b/src/org/apache/http/impl/io/AbstractSessionOutputBuffer.java @@ -0,0 +1,179 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractSessionOutputBuffer.java $ + * $Revision: 652091 $ + * $Date: 2008-04-29 13:41:07 -0700 (Tue, 29 Apr 2008) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.http.io.SessionOutputBuffer; +import org.apache.http.io.HttpTransportMetrics; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.ByteArrayBuffer; +import org.apache.http.util.CharArrayBuffer; + +/** + * Abstract base class for session output buffers that stream data + * to an {@link OutputStream}. + * + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + */ +public abstract class AbstractSessionOutputBuffer implements SessionOutputBuffer { + + private static final byte[] CRLF = new byte[] {HTTP.CR, HTTP.LF}; + + private static final int MAX_CHUNK = 256; + + private OutputStream outstream; + private ByteArrayBuffer buffer; + + private String charset = HTTP.US_ASCII; + private boolean ascii = true; + + private HttpTransportMetricsImpl metrics; + + protected void init(final OutputStream outstream, int buffersize, final HttpParams params) { + if (outstream == null) { + throw new IllegalArgumentException("Input stream may not be null"); + } + if (buffersize <= 0) { + throw new IllegalArgumentException("Buffer size may not be negative or zero"); + } + if (params == null) { + throw new IllegalArgumentException("HTTP parameters may not be null"); + } + this.outstream = outstream; + this.buffer = new ByteArrayBuffer(buffersize); + this.charset = HttpProtocolParams.getHttpElementCharset(params); + this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII) + || this.charset.equalsIgnoreCase(HTTP.ASCII); + this.metrics = new HttpTransportMetricsImpl(); + } + + protected void flushBuffer() throws IOException { + 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, int off, int len) throws IOException { + if (b == null) { + return; + } + // Do not want to buffer largish chunks + // if the byte array is larger then MAX_CHUNK + // write it directly to the output stream + if (len > MAX_CHUNK || 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 + 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(int b) throws IOException { + if (this.buffer.isFull()) { + flushBuffer(); + } + this.buffer.append(b); + } + + public void writeLine(final String s) throws IOException { + if (s == null) { + return; + } + if (s.length() > 0) { + write(s.getBytes(this.charset)); + } + write(CRLF); + } + + public void writeLine(final CharArrayBuffer s) throws IOException { + if (s == null) { + return; + } + if (this.ascii) { + int off = 0; + int remaining = s.length(); + while (remaining > 0) { + int chunk = this.buffer.capacity() - this.buffer.length(); + chunk = Math.min(chunk, remaining); + if (chunk > 0) { + this.buffer.append(s, off, chunk); + } + if (this.buffer.isFull()) { + flushBuffer(); + } + off += chunk; + remaining -= chunk; + } + } else { + // This is VERY memory inefficient, BUT since non-ASCII charsets are + // NOT meant to be used anyway, there's no point optimizing it + byte[] tmp = s.toString().getBytes(this.charset); + write(tmp); + } + write(CRLF); + } + + public HttpTransportMetrics getMetrics() { + return this.metrics; + } + +} diff --git a/src/org/apache/http/impl/io/ChunkedInputStream.java b/src/org/apache/http/impl/io/ChunkedInputStream.java new file mode 100644 index 0000000..60cae90 --- /dev/null +++ b/src/org/apache/http/impl/io/ChunkedInputStream.java @@ -0,0 +1,294 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java $ + * $Revision: 569843 $ + * $Date: 2007-08-26 10:05:40 -0700 (Sun, 26 Aug 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.http.Header; +import org.apache.http.HttpException; +import org.apache.http.MalformedChunkCodingException; +import org.apache.http.io.SessionInputBuffer; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.CharArrayBuffer; +import org.apache.http.util.ExceptionUtils; + +/** + * Implements chunked transfer coding. + * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>, + * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">section 3.6.1</a>. + * It transparently coalesces chunks of a HTTP stream that uses chunked + * transfer coding. After the stream is read to the end, it provides access + * to the trailers, if any. + * <p> + * 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. + * </p> + * + * @author Ortwin Glueck + * @author Sean C. Sullivan + * @author Martin Elwin + * @author Eric Johnson + * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> + * @author Michael Becke + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + * @since 4.0 + * + */ +public class ChunkedInputStream extends InputStream { + + /** The session input buffer */ + private SessionInputBuffer in; + + private final CharArrayBuffer buffer; + + /** The chunk size */ + private int chunkSize; + + /** The current position within the current chunk */ + private int pos; + + /** True if we'are at the beginning of stream */ + private boolean bof = true; + + /** 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[] {}; + + public ChunkedInputStream(final SessionInputBuffer in) { + super(); + if (in == null) { + throw new IllegalArgumentException("Session input buffer may not be null"); + } + this.in = in; + this.pos = 0; + this.buffer = new CharArrayBuffer(16); + } + + /** + * <p> 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.</p> + * + * <p> Trailer headers are read automcatically at the end of the stream and + * can be obtained with the getResponseFooters() method.</p> + * + * @return -1 of the end of the stream has been reached or the next data + * byte + * @throws IOException If an IO problem occurs + */ + public int read() throws IOException { + if (this.closed) { + throw new IOException("Attempted read from closed stream."); + } + if (this.eof) { + return -1; + } + if (this.pos >= this.chunkSize) { + nextChunk(); + if (this.eof) { + return -1; + } + } + pos++; + return in.read(); + } + + /** + * 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. + * @see java.io.InputStream#read(byte[], int, int) + * @throws IOException if an IO problem occurs. + */ + public int read (byte[] b, int off, int len) throws IOException { + + if (closed) { + throw new IOException("Attempted read from closed stream."); + } + + if (eof) { + return -1; + } + if (pos >= chunkSize) { + nextChunk(); + if (eof) { + return -1; + } + } + len = Math.min(len, chunkSize - pos); + int count = in.read(b, off, len); + pos += count; + return count; + } + + /** + * 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. + * @see java.io.InputStream#read(byte[]) + * @throws IOException if an IO problem occurs. + */ + public int read (byte[] b) throws IOException { + return read(b, 0, b.length); + } + + /** + * Read the next chunk. + * @throws IOException If an IO error occurs. + */ + private void nextChunk() throws IOException { + chunkSize = getChunkSize(); + if (chunkSize < 0) { + throw new MalformedChunkCodingException("Negative chunk size"); + } + bof = false; + 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. + * + * @param in The new input stream. + * @param required <tt>true<tt/> if a valid chunk must be present, + * <tt>false<tt/> otherwise. + * + * @return the chunk size as integer + * + * @throws IOException when the chunk size could not be parsed + */ + private int getChunkSize() throws IOException { + // skip CRLF + if (!bof) { + int cr = in.read(); + int lf = in.read(); + if ((cr != HTTP.CR) || (lf != HTTP.LF)) { + throw new MalformedChunkCodingException( + "CRLF expected at end of chunk"); + } + } + //parse data + this.buffer.clear(); + int i = this.in.readLine(this.buffer); + if (i == -1) { + throw new MalformedChunkCodingException( + "Chunked stream ended unexpectedly"); + } + int separator = this.buffer.indexOf(';'); + if (separator < 0) { + separator = this.buffer.length(); + } + try { + return Integer.parseInt(this.buffer.substringTrimmed(0, separator), 16); + } catch (NumberFormatException e) { + throw new MalformedChunkCodingException("Bad chunk header"); + } + } + + /** + * Reads and stores the Trailer headers. + * @throws IOException If an IO problem occurs + */ + private void parseTrailerHeaders() throws IOException { + try { + this.footers = AbstractMessageParser.parseHeaders + (in, -1, -1, null); + } catch (HttpException e) { + IOException ioe = new MalformedChunkCodingException("Invalid footer: " + + e.getMessage()); + ExceptionUtils.initCause(ioe, e); + 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 If an IO problem occurs. + */ + public void close() throws IOException { + if (!closed) { + try { + if (!eof) { + exhaustInputStream(this); + } + } finally { + eof = true; + closed = true; + } + } + } + + public Header[] getFooters() { + return (Header[])this.footers.clone(); + } + + /** + * Exhaust an input stream, reading until EOF has been encountered. + * + * <p>Note that this function is intended as a non-public utility. + * This is a little weird, but it seemed silly to make a utility + * class for this one function, so instead it is just static and + * shared that way.</p> + * + * @param inStream The {@link InputStream} to exhaust. + * @throws IOException If an IO problem occurs + */ + static void exhaustInputStream(final InputStream inStream) throws IOException { + // read and discard the remainder of the message + byte buffer[] = new byte[1024]; + while (inStream.read(buffer) >= 0) { + ; + } + } + +} diff --git a/src/org/apache/http/impl/io/ChunkedOutputStream.java b/src/org/apache/http/impl/io/ChunkedOutputStream.java new file mode 100644 index 0000000..5ee7dd6 --- /dev/null +++ b/src/org/apache/http/impl/io/ChunkedOutputStream.java @@ -0,0 +1,191 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ChunkedOutputStream.java $ + * $Revision: 645081 $ + * $Date: 2008-04-05 04:36:42 -0700 (Sat, 05 Apr 2008) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.http.io.SessionOutputBuffer; + +/** + * Implements chunked transfer coding. + * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>, + * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">section 3.6.1</a>. + * Writes are buffered to an internal buffer (2048 default size). + * + * @author Mohammad Rezaei (Goldman, Sachs & Co.) + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + * @since 4.0 + */ +public class ChunkedOutputStream extends OutputStream { + + // ----------------------------------------------------- Instance Variables + private final SessionOutputBuffer out; + + private byte[] cache; + + private int cachePosition = 0; + + private boolean wroteLastChunk = false; + + /** True if the stream is closed. */ + private boolean closed = false; + + // ----------------------------------------------------------- Constructors + /** + * Wraps a session output buffer and chunks the output. + * @param out the session output buffer to wrap + * @param bufferSize minimum chunk size (excluding last chunk) + * @throws IOException + */ + public ChunkedOutputStream(final SessionOutputBuffer out, int bufferSize) + throws IOException { + super(); + this.cache = new byte[bufferSize]; + this.out = 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 + */ + public ChunkedOutputStream(final SessionOutputBuffer out) + throws IOException { + this(out, 2048); + } + + // ----------------------------------------------------------- Internal methods + /** + * Writes the cache out onto the underlying stream + * @throws IOException + */ + 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 + * @param bufferToAppend + * @param off + * @param len + * @throws IOException + */ + protected void flushCacheWithAppend(byte bufferToAppend[], int off, 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 + */ + public void finish() throws IOException { + if (!this.wroteLastChunk) { + flushCache(); + writeClosingChunk(); + this.wroteLastChunk = true; + } + } + + // -------------------------------------------- OutputStream Methods + public void write(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. + * @param b + * @throws IOException + */ + public void write(byte b[]) throws IOException { + write(b, 0, b.length); + } + + public void write(byte src[], int off, 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. + * @throws IOException + */ + public void flush() throws IOException { + flushCache(); + this.out.flush(); + } + + /** + * Finishes writing to the underlying stream, but does NOT close the underlying stream. + * @throws IOException + */ + public void close() throws IOException { + if (!this.closed) { + this.closed = true; + finish(); + this.out.flush(); + } + } +} diff --git a/src/org/apache/http/impl/io/ContentLengthInputStream.java b/src/org/apache/http/impl/io/ContentLengthInputStream.java new file mode 100644 index 0000000..3b19c5b --- /dev/null +++ b/src/org/apache/http/impl/io/ContentLengthInputStream.java @@ -0,0 +1,220 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ContentLengthInputStream.java $ + * $Revision: 652091 $ + * $Date: 2008-04-29 13:41:07 -0700 (Tue, 29 Apr 2008) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.http.io.SessionInputBuffer; + +/** + * Stream that cuts off after a specified number of bytes. + * 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. + * + * <p>Implementation note: Choices abound. One approach would pass + * through the {@link InputStream#mark} and {@link InputStream#reset} calls to + * the underlying stream. That's tricky, though, because you then have to + * start duplicating the work of keeping track of how much a reset rewinds. + * Further, you have to watch out for the "readLimit", and since the semantics + * for the readLimit leave room for differing implementations, you might get + * into a lot of trouble.</p> + * + * <p>Alternatively, you could make this class extend + * {@link java.io.BufferedInputStream} + * and then use the protected members of that class to avoid duplicated effort. + * That solution has the side effect of adding yet another possible layer of + * buffering.</p> + * + * <p>Then, there is the simple choice, which this takes - simply don't + * support {@link InputStream#mark} and {@link InputStream#reset}. That choice + * has the added benefit of keeping this class very simple.</p> + * + * @author Ortwin Glueck + * @author Eric Johnson + * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> + * + * @since 4.0 + */ +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 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; + + /** + * Creates a new length limited stream + * + * @param in The session input buffer to wrap + * @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, long contentLength) { + super(); + if (in == null) { + throw new IllegalArgumentException("Input stream may not be null"); + } + if (contentLength < 0) { + throw new IllegalArgumentException("Content length may not be negative"); + } + this.in = in; + this.contentLength = contentLength; + } + + /** + * <p>Reads until the end of the known length of content.</p> + * + * <p>Does not close the underlying socket input, but instead leaves it + * primed to parse the next response.</p> + * @throws IOException If an IO problem occurs. + */ + public void close() throws IOException { + if (!closed) { + try { + 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; + } + } + } + + + /** + * 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() + */ + public int read() throws IOException { + if (closed) { + throw new IOException("Attempted read from closed stream."); + } + + if (pos >= contentLength) { + return -1; + } + pos++; + return this.in.read(); + } + + /** + * 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. + */ + public int read (byte[] b, int off, int len) throws java.io.IOException { + if (closed) { + throw new IOException("Attempted read from closed stream."); + } + + if (pos >= contentLength) { + return -1; + } + + if (pos + len > contentLength) { + len = (int) (contentLength - pos); + } + int count = this.in.read(b, off, len); + 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[]) + */ + public int read(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) + */ + public long skip(long n) throws IOException { + if (n <= 0) { + return 0; + } + 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) { + int l = read(buffer, 0, (int)Math.min(BUFFER_SIZE, remaining)); + if (l == -1) { + break; + } + count += l; + remaining -= l; + } + this.pos += count; + return count; + } +} diff --git a/src/org/apache/http/impl/io/ContentLengthOutputStream.java b/src/org/apache/http/impl/io/ContentLengthOutputStream.java new file mode 100644 index 0000000..afcb883 --- /dev/null +++ b/src/org/apache/http/impl/io/ContentLengthOutputStream.java @@ -0,0 +1,132 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ContentLengthOutputStream.java $ + * $Revision: 560343 $ + * $Date: 2007-07-27 11:18:19 -0700 (Fri, 27 Jul 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.http.io.SessionOutputBuffer; + +/** + * A stream wrapper that closes itself after a defined number of bytes. + * + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + * @version $Revision: 560343 $ + * + * @since 4.0 + */ +public class ContentLengthOutputStream extends OutputStream { + + /** + * Wrapped session outbut 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; + + /** + * Creates a new length limited stream + * + * @param out The data transmitter to wrap + * @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, long contentLength) { + super(); + if (out == null) { + throw new IllegalArgumentException("Session output buffer may not be null"); + } + if (contentLength < 0) { + throw new IllegalArgumentException("Content length may not be negative"); + } + this.out = out; + this.contentLength = contentLength; + } + + /** + * <p>Does not close the underlying socket output.</p> + * + * @throws IOException If an I/O problem occurs. + */ + public void close() throws IOException { + if (!this.closed) { + this.closed = true; + this.out.flush(); + } + } + + public void flush() throws IOException { + this.out.flush(); + } + + public void write(byte[] b, int off, int len) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + if (this.total < this.contentLength) { + long max = this.contentLength - this.total; + if (len > max) { + len = (int) max; + } + this.out.write(b, off, len); + this.total += len; + } + } + + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + public void write(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/src/org/apache/http/impl/io/HttpRequestParser.java b/src/org/apache/http/impl/io/HttpRequestParser.java new file mode 100644 index 0000000..a7bae6d --- /dev/null +++ b/src/org/apache/http/impl/io/HttpRequestParser.java @@ -0,0 +1,80 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpRequestParser.java $ + * $Revision: 589374 $ + * $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; + +import org.apache.http.ConnectionClosedException; +import org.apache.http.HttpException; +import org.apache.http.HttpMessage; +import org.apache.http.HttpRequestFactory; +import org.apache.http.RequestLine; +import org.apache.http.ParseException; +import org.apache.http.io.SessionInputBuffer; +import org.apache.http.message.LineParser; +import org.apache.http.message.ParserCursor; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + +public class HttpRequestParser extends AbstractMessageParser { + + private final HttpRequestFactory requestFactory; + private final CharArrayBuffer lineBuf; + + public HttpRequestParser( + final SessionInputBuffer buffer, + final LineParser parser, + final HttpRequestFactory requestFactory, + final HttpParams params) { + super(buffer, parser, params); + if (requestFactory == null) { + throw new IllegalArgumentException("Request factory may not be null"); + } + this.requestFactory = requestFactory; + this.lineBuf = new CharArrayBuffer(128); + } + + protected HttpMessage parseHead( + final SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException { + + this.lineBuf.clear(); + int i = sessionBuffer.readLine(this.lineBuf); + if (i == -1) { + throw new ConnectionClosedException("Client closed connection"); + } + ParserCursor cursor = new ParserCursor(0, this.lineBuf.length()); + RequestLine requestline = this.lineParser.parseRequestLine(this.lineBuf, cursor); + return this.requestFactory.newHttpRequest(requestline); + } + +} diff --git a/src/org/apache/http/impl/io/HttpRequestWriter.java b/src/org/apache/http/impl/io/HttpRequestWriter.java new file mode 100644 index 0000000..b784e2d --- /dev/null +++ b/src/org/apache/http/impl/io/HttpRequestWriter.java @@ -0,0 +1,59 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpRequestWriter.java $ + * $Revision: 569673 $ + * $Date: 2007-08-25 06:58:51 -0700 (Sat, 25 Aug 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; + +import org.apache.http.HttpMessage; +import org.apache.http.HttpRequest; +import org.apache.http.io.SessionOutputBuffer; +import org.apache.http.message.LineFormatter; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + +public class HttpRequestWriter extends AbstractMessageWriter { + + public HttpRequestWriter(final SessionOutputBuffer buffer, + final LineFormatter formatter, + final HttpParams params) { + super(buffer, formatter, params); + } + + protected void writeHeadLine(final HttpMessage message) + throws IOException { + + final CharArrayBuffer buffer = lineFormatter.formatRequestLine + (this.lineBuf, ((HttpRequest) message).getRequestLine()); + this.sessionBuffer.writeLine(buffer); + } + +} diff --git a/src/org/apache/http/impl/io/HttpResponseParser.java b/src/org/apache/http/impl/io/HttpResponseParser.java new file mode 100644 index 0000000..575aa18 --- /dev/null +++ b/src/org/apache/http/impl/io/HttpResponseParser.java @@ -0,0 +1,81 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpResponseParser.java $ + * $Revision: 589374 $ + * $Date: 2007-10-28 09:25:07 -0700 (Sun, 28 Oct 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; + +import org.apache.http.HttpException; +import org.apache.http.HttpMessage; +import org.apache.http.HttpResponseFactory; +import org.apache.http.NoHttpResponseException; +import org.apache.http.StatusLine; +import org.apache.http.ParseException; +import org.apache.http.io.SessionInputBuffer; +import org.apache.http.message.LineParser; +import org.apache.http.message.ParserCursor; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + +public class HttpResponseParser extends AbstractMessageParser { + + private final HttpResponseFactory responseFactory; + private final CharArrayBuffer lineBuf; + + public HttpResponseParser( + final SessionInputBuffer buffer, + final LineParser parser, + final HttpResponseFactory responseFactory, + final HttpParams params) { + super(buffer, parser, params); + if (responseFactory == null) { + throw new IllegalArgumentException("Response factory may not be null"); + } + this.responseFactory = responseFactory; + this.lineBuf = new CharArrayBuffer(128); + } + + protected HttpMessage parseHead( + final SessionInputBuffer sessionBuffer) + throws IOException, HttpException, ParseException { + + this.lineBuf.clear(); + 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 + ParserCursor cursor = new ParserCursor(0, this.lineBuf.length()); + StatusLine statusline = lineParser.parseStatusLine(this.lineBuf, cursor); + return this.responseFactory.newHttpResponse(statusline, null); + } + +} diff --git a/src/org/apache/http/impl/io/HttpResponseWriter.java b/src/org/apache/http/impl/io/HttpResponseWriter.java new file mode 100644 index 0000000..f88791e --- /dev/null +++ b/src/org/apache/http/impl/io/HttpResponseWriter.java @@ -0,0 +1,59 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpResponseWriter.java $ + * $Revision: 569673 $ + * $Date: 2007-08-25 06:58:51 -0700 (Sat, 25 Aug 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; + +import org.apache.http.HttpMessage; +import org.apache.http.HttpResponse; +import org.apache.http.io.SessionOutputBuffer; +import org.apache.http.message.LineFormatter; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + +public class HttpResponseWriter extends AbstractMessageWriter { + + public HttpResponseWriter(final SessionOutputBuffer buffer, + final LineFormatter formatter, + final HttpParams params) { + super(buffer, formatter, params); + } + + protected void writeHeadLine(final HttpMessage message) + throws IOException { + + final CharArrayBuffer buffer = lineFormatter.formatStatusLine + (this.lineBuf, ((HttpResponse) message).getStatusLine()); + this.sessionBuffer.writeLine(buffer); + } + +} diff --git a/src/org/apache/http/impl/io/HttpTransportMetricsImpl.java b/src/org/apache/http/impl/io/HttpTransportMetricsImpl.java new file mode 100644 index 0000000..53e6772 --- /dev/null +++ b/src/org/apache/http/impl/io/HttpTransportMetricsImpl.java @@ -0,0 +1,63 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/HttpTransportMetricsImpl.java $ + * $Revision: 539755 $ + * $Date: 2007-05-19 07:05:02 -0700 (Sat, 19 May 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import org.apache.http.io.HttpTransportMetrics; + +/** + * Default implementation of {@link HttpTransportMetrics}. + */ +public class HttpTransportMetricsImpl implements HttpTransportMetrics { + + private long bytesTransferred = 0; + + public HttpTransportMetricsImpl() { + super(); + } + + public long getBytesTransferred() { + return this.bytesTransferred; + } + + public void setBytesTransferred(long count) { + this.bytesTransferred = count; + } + + public void incrementBytesTransferred(long count) { + this.bytesTransferred += count; + } + + public void reset() { + this.bytesTransferred = 0; + } + +} diff --git a/src/org/apache/http/impl/io/IdentityInputStream.java b/src/org/apache/http/impl/io/IdentityInputStream.java new file mode 100644 index 0000000..390d5b7 --- /dev/null +++ b/src/org/apache/http/impl/io/IdentityInputStream.java @@ -0,0 +1,90 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/IdentityInputStream.java $ + * $Revision: 560358 $ + * $Date: 2007-07-27 12:30:42 -0700 (Fri, 27 Jul 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.http.io.SessionInputBuffer; + +/** + * A stream for reading from a {@link SessionInputBuffer session input buffer}. + * + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + * @version $Revision: 560358 $ + * + * @since 4.0 + */ +public class IdentityInputStream extends InputStream { + + private final SessionInputBuffer in; + + private boolean closed = false; + + public IdentityInputStream(final SessionInputBuffer in) { + super(); + if (in == null) { + throw new IllegalArgumentException("Session input buffer may not be null"); + } + this.in = in; + } + + public int available() throws IOException { + if (!this.closed && this.in.isDataAvailable(10)) { + return 1; + } else { + return 0; + } + } + + public void close() throws IOException { + this.closed = true; + } + + public int read() throws IOException { + if (this.closed) { + return -1; + } else { + return this.in.read(); + } + } + + public int read(final byte[] b, int off, int len) throws IOException { + if (this.closed) { + return -1; + } else { + return this.in.read(b, off, len); + } + } + +} diff --git a/src/org/apache/http/impl/io/IdentityOutputStream.java b/src/org/apache/http/impl/io/IdentityOutputStream.java new file mode 100644 index 0000000..10b64f7 --- /dev/null +++ b/src/org/apache/http/impl/io/IdentityOutputStream.java @@ -0,0 +1,100 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/IdentityOutputStream.java $ + * $Revision: 560343 $ + * $Date: 2007-07-27 11:18:19 -0700 (Fri, 27 Jul 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.http.io.SessionOutputBuffer; + +/** + * A stream for writing with an "identity" transport encoding. + * + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + * @version $Revision: 560343 $ + * + * @since 4.0 + */ +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(); + if (out == null) { + throw new IllegalArgumentException("Session output buffer may not be null"); + } + this.out = out; + } + + /** + * <p>Does not close the underlying socket output.</p> + * + * @throws IOException If an I/O problem occurs. + */ + public void close() throws IOException { + if (!this.closed) { + this.closed = true; + this.out.flush(); + } + } + + public void flush() throws IOException { + this.out.flush(); + } + + public void write(byte[] b, int off, int len) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + this.out.write(b, off, len); + } + + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + public void write(int b) throws IOException { + if (this.closed) { + throw new IOException("Attempted write to closed stream."); + } + this.out.write(b); + } + +} diff --git a/src/org/apache/http/impl/io/SocketInputBuffer.java b/src/org/apache/http/impl/io/SocketInputBuffer.java new file mode 100644 index 0000000..925e80a --- /dev/null +++ b/src/org/apache/http/impl/io/SocketInputBuffer.java @@ -0,0 +1,115 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/SocketInputBuffer.java $ + * $Revision: 560358 $ + * $Date: 2007-07-27 12:30:42 -0700 (Fri, 27 Jul 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.Socket; + +import org.apache.http.params.HttpParams; + + +/** + * {@link Socket} bound session input buffer. + * + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + * @version $Revision: 560358 $ + * + * @since 4.0 + */ +public class SocketInputBuffer extends AbstractSessionInputBuffer { + + static private final Class SOCKET_TIMEOUT_CLASS = SocketTimeoutExceptionClass(); + + /** + * Returns <code>SocketTimeoutExceptionClass<code> or <code>null</code> if the class + * does not exist. + * + * @return <code>SocketTimeoutExceptionClass<code>, or <code>null</code> if unavailable. + */ + static private Class SocketTimeoutExceptionClass() { + try { + return Class.forName("java.net.SocketTimeoutException"); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static boolean isSocketTimeoutException(final InterruptedIOException e) { + if (SOCKET_TIMEOUT_CLASS != null) { + return SOCKET_TIMEOUT_CLASS.isInstance(e); + } else { + return true; + } + } + + private final Socket socket; + + public SocketInputBuffer( + final Socket socket, + int buffersize, + final HttpParams params) throws IOException { + super(); + if (socket == null) { + throw new IllegalArgumentException("Socket may not be null"); + } + this.socket = socket; + if (buffersize < 0) { + buffersize = socket.getReceiveBufferSize(); + } + if (buffersize < 1024) { + buffersize = 1024; + } + init(socket.getInputStream(), buffersize, params); + } + + public boolean isDataAvailable(int timeout) throws IOException { + boolean result = hasBufferedData(); + if (!result) { + int oldtimeout = this.socket.getSoTimeout(); + try { + this.socket.setSoTimeout(timeout); + fillBuffer(); + result = hasBufferedData(); + } catch (InterruptedIOException e) { + if (!isSocketTimeoutException(e)) { + throw e; + } + } finally { + socket.setSoTimeout(oldtimeout); + } + } + return result; + } + +} diff --git a/src/org/apache/http/impl/io/SocketOutputBuffer.java b/src/org/apache/http/impl/io/SocketOutputBuffer.java new file mode 100644 index 0000000..efb91e9 --- /dev/null +++ b/src/org/apache/http/impl/io/SocketOutputBuffer.java @@ -0,0 +1,79 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/SocketOutputBuffer.java $ + * $Revision: 560358 $ + * $Date: 2007-07-27 12:30:42 -0700 (Fri, 27 Jul 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.io; + +import java.io.IOException; +import java.net.Socket; + +import org.apache.http.params.HttpParams; + + +/** + * {@link Socket} bound session output buffer. + * + * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> + * + * @version $Revision: 560358 $ + * + * @since 4.0 + */ +public class SocketOutputBuffer extends AbstractSessionOutputBuffer { + + public SocketOutputBuffer( + final Socket socket, + int buffersize, + final HttpParams params) throws IOException { + super(); + if (socket == null) { + throw new IllegalArgumentException("Socket may not be null"); + } + if (buffersize < 0) { + buffersize = socket.getReceiveBufferSize(); +// BEGIN android-changed + // Workaround for http://b/issue?id=1083103. + if (buffersize > 8096) { + buffersize = 8096; + } +// END android-changed + } + if (buffersize < 1024) { + buffersize = 1024; + } + +// BEGIN android-changed + socket.setSendBufferSize(buffersize * 3); +// END andrdoid-changed + + init(socket.getOutputStream(), buffersize, params); + } + +} diff --git a/src/org/apache/http/impl/io/package.html b/src/org/apache/http/impl/io/package.html new file mode 100644 index 0000000..48eb2c1 --- /dev/null +++ b/src/org/apache/http/impl/io/package.html @@ -0,0 +1,48 @@ +<html> +<head> +<!-- +/* + * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/package.html $ + * $Revision: 567360 $ + * $Date: 2007-08-18 23:49:21 -0700 (Sat, 18 Aug 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ +--> +</head> +<body> +Default implementations for interfaces in +{@link org.apache.http.io org.apache.http.io}. + +<br/> + +There are implementations of the transport encodings used by HTTP, +in particular the chunked encoding for +{@link org.apache.http.impl.io.ChunkedOutputStream sending} and +{@link org.apache.http.impl.io.ChunkedInputStream receiving} entities. + +</body> +</html> |