1069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/* 2069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java $ 3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Revision: 569843 $ 4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Date: 2007-08-26 10:05:40 -0700 (Sun, 26 Aug 2007) $ 5069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 6069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ==================================================================== 7069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one 8069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * or more contributor license agreements. See the NOTICE file 9069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * distributed with this work for additional information 10069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * regarding copyright ownership. The ASF licenses this file 11069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * to you under the Apache License, Version 2.0 (the 12069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "License"); you may not use this file except in compliance 13069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * with the License. You may obtain a copy of the License at 14069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 15069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 16069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 17069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Unless required by applicable law or agreed to in writing, 18069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * software distributed under the License is distributed on an 19069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * KIND, either express or implied. See the License for the 21069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * specific language governing permissions and limitations 22069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * under the License. 23069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ==================================================================== 24069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 25069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This software consists of voluntary contributions made by many 26069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * individuals on behalf of the Apache Software Foundation. For more 27069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * information on the Apache Software Foundation, please see 28069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <http://www.apache.org/>. 29069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 30069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 31069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 32069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpackage org.apache.http.impl.io; 33069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 34069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.io.IOException; 35069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.io.InputStream; 36069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 37069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.Header; 38069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.HttpException; 39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.MalformedChunkCodingException; 40069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.io.SessionInputBuffer; 41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.protocol.HTTP; 42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.util.CharArrayBuffer; 43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.util.ExceptionUtils; 44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/** 46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Implements chunked transfer coding. 47069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>, 48069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">section 3.6.1</a>. 49069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * It transparently coalesces chunks of a HTTP stream that uses chunked 50069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * transfer coding. After the stream is read to the end, it provides access 51069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * to the trailers, if any. 52069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <p> 53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Note that this class NEVER closes the underlying stream, even when close 54069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * gets called. Instead, it will read until the "end" of its chunking on 55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * close, which allows for the seamless execution of subsequent HTTP 1.1 56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * requests, while not requiring the client to remember to read the entire 57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * contents of the response. 58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * </p> 59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Ortwin Glueck 61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Sean C. Sullivan 62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Martin Elwin 63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Eric Johnson 64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> 65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Michael Becke 66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> 67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @since 4.0 69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic class ChunkedInputStream extends InputStream { 72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** The session input buffer */ 74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private SessionInputBuffer in; 75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private final CharArrayBuffer buffer; 77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** The chunk size */ 79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private int chunkSize; 80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** The current position within the current chunk */ 82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private int pos; 83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** True if we'are at the beginning of stream */ 85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean bof = true; 86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** True if we've reached the end of stream */ 88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean eof = false; 89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** True if this stream is closed */ 91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean closed = false; 92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private Header[] footers = new Header[] {}; 94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public ChunkedInputStream(final SessionInputBuffer in) { 96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project super(); 97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (in == null) { 98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new IllegalArgumentException("Session input buffer may not be null"); 99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.in = in; 101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.pos = 0; 102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.buffer = new CharArrayBuffer(16); 103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <p> Returns all the data in a chunked stream in coalesced form. A chunk 107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * is followed by a CRLF. The method returns -1 as soon as a chunksize of 0 108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * is detected.</p> 109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <p> Trailer headers are read automcatically at the end of the stream and 111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * can be obtained with the getResponseFooters() method.</p> 112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return -1 of the end of the stream has been reached or the next data 114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * byte 115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException If an IO problem occurs 116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public int read() throws IOException { 118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.closed) { 119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new IOException("Attempted read from closed stream."); 120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.eof) { 122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return -1; 123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.pos >= this.chunkSize) { 125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project nextChunk(); 126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.eof) { 127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return -1; 128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project pos++; 131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return in.read(); 132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Read some bytes from the stream. 136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param b The byte array that will hold the contents from the stream. 137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param off The offset into the byte array at which bytes will start to be 138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * placed. 139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param len the maximum number of bytes that can be returned. 140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return The number of bytes returned or -1 if the end of stream has been 141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * reached. 142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @see java.io.InputStream#read(byte[], int, int) 143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException if an IO problem occurs. 144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public int read (byte[] b, int off, int len) throws IOException { 146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (closed) { 148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new IOException("Attempted read from closed stream."); 149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (eof) { 152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return -1; 153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (pos >= chunkSize) { 155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project nextChunk(); 156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (eof) { 157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return -1; 158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project len = Math.min(len, chunkSize - pos); 161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project int count = in.read(b, off, len); 162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project pos += count; 163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return count; 164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Read some bytes from the stream. 168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param b The byte array that will hold the contents from the stream. 169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return The number of bytes returned or -1 if the end of stream has been 170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * reached. 171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @see java.io.InputStream#read(byte[]) 172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException if an IO problem occurs. 173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public int read (byte[] b) throws IOException { 175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return read(b, 0, b.length); 176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Read the next chunk. 180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException If an IO error occurs. 181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private void nextChunk() throws IOException { 183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project chunkSize = getChunkSize(); 184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (chunkSize < 0) { 185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new MalformedChunkCodingException("Negative chunk size"); 186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project bof = false; 188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project pos = 0; 189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (chunkSize == 0) { 190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project eof = true; 191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project parseTrailerHeaders(); 192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Expects the stream to start with a chunksize in hex with optional 197069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * comments after a semicolon. The line must end with a CRLF: "a3; some 198069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * comment\r\n" Positions the stream at the start of the next line. 199069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 200069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param in The new input stream. 201069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param required <tt>true<tt/> if a valid chunk must be present, 202069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <tt>false<tt/> otherwise. 203069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 204069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return the chunk size as integer 205069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 206069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException when the chunk size could not be parsed 207069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 208069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private int getChunkSize() throws IOException { 209069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // skip CRLF 210069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!bof) { 211069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project int cr = in.read(); 212069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project int lf = in.read(); 213069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ((cr != HTTP.CR) || (lf != HTTP.LF)) { 214069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new MalformedChunkCodingException( 215069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project "CRLF expected at end of chunk"); 216069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 217069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 218069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project //parse data 219069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.buffer.clear(); 220069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project int i = this.in.readLine(this.buffer); 221069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (i == -1) { 222069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new MalformedChunkCodingException( 223069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project "Chunked stream ended unexpectedly"); 224069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 225069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project int separator = this.buffer.indexOf(';'); 226069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (separator < 0) { 227069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project separator = this.buffer.length(); 228069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 229069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project try { 230069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return Integer.parseInt(this.buffer.substringTrimmed(0, separator), 16); 231069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } catch (NumberFormatException e) { 232069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new MalformedChunkCodingException("Bad chunk header"); 233069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 234069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 235069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 236069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 237069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Reads and stores the Trailer headers. 238069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException If an IO problem occurs 239069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 240069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private void parseTrailerHeaders() throws IOException { 241069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project try { 242069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.footers = AbstractMessageParser.parseHeaders 243069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (in, -1, -1, null); 244069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } catch (HttpException e) { 245069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project IOException ioe = new MalformedChunkCodingException("Invalid footer: " 246069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project + e.getMessage()); 247069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project ExceptionUtils.initCause(ioe, e); 248069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw ioe; 249069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 250069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 251069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 252069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 253069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Upon close, this reads the remainder of the chunked message, 254069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * leaving the underlying socket at a position to start reading the 255069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * next response without scanning. 256069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException If an IO problem occurs. 257069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 258069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void close() throws IOException { 259069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!closed) { 260069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project try { 261069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!eof) { 262069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project exhaustInputStream(this); 263069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 264069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } finally { 265069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project eof = true; 266069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project closed = true; 267069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 268069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 269069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 270069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 271069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public Header[] getFooters() { 272069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return (Header[])this.footers.clone(); 273069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 274069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 275069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 276069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Exhaust an input stream, reading until EOF has been encountered. 277069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 278069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <p>Note that this function is intended as a non-public utility. 279069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This is a little weird, but it seemed silly to make a utility 280069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * class for this one function, so instead it is just static and 281069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * shared that way.</p> 282069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 283069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param inStream The {@link InputStream} to exhaust. 284069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException If an IO problem occurs 285069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 286069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project static void exhaustInputStream(final InputStream inStream) throws IOException { 287069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // read and discard the remainder of the message 288069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project byte buffer[] = new byte[1024]; 289069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project while (inStream.read(buffer) >= 0) { 290069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project ; 291069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 292069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 293069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 294069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project} 295