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/ChunkedOutputStream.java $ 3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Revision: 645081 $ 4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Date: 2008-04-05 04:36:42 -0700 (Sat, 05 Apr 2008) $ 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.OutputStream; 36069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 37069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.io.SessionOutputBuffer; 38069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/** 40069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Implements chunked transfer coding. 41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>, 42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">section 3.6.1</a>. 43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Writes are buffered to an internal buffer (2048 default size). 44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Mohammad Rezaei (Goldman, Sachs & Co.) 46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> 47069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 48069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @since 4.0 49d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath * 50d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath * @deprecated Please use {@link java.net.URL#openConnection} instead. 51d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> 52d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath * for further details. 53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 54d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath@Deprecated 55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic class ChunkedOutputStream extends OutputStream { 56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // ----------------------------------------------------- Instance Variables 58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private final SessionOutputBuffer out; 59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private byte[] cache; 61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private int cachePosition = 0; 63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean wroteLastChunk = false; 65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** True if the stream is closed. */ 67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean closed = false; 68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // ----------------------------------------------------------- Constructors 70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Wraps a session output buffer and chunks the output. 72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param out the session output buffer to wrap 73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param bufferSize minimum chunk size (excluding last chunk) 74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public ChunkedOutputStream(final SessionOutputBuffer out, int bufferSize) 77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throws IOException { 78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project super(); 79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.cache = new byte[bufferSize]; 80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out = out; 81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Wraps a session output buffer and chunks the output. The default buffer 85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * size of 2048 was chosen because the chunk overhead is less than 0.5% 86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param out the output buffer to wrap 88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public ChunkedOutputStream(final SessionOutputBuffer out) 91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throws IOException { 92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this(out, 2048); 93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // ----------------------------------------------------------- Internal methods 96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Writes the cache out onto the underlying stream 98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project protected void flushCache() throws IOException { 101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.cachePosition > 0) { 102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.writeLine(Integer.toHexString(this.cachePosition)); 103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.write(this.cache, 0, this.cachePosition); 104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.writeLine(""); 105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.cachePosition = 0; 106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Writes the cache and bufferToAppend to the underlying stream 111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * as one large chunk 112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param bufferToAppend 113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param off 114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param len 115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project protected void flushCacheWithAppend(byte bufferToAppend[], int off, int len) throws IOException { 118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.writeLine(Integer.toHexString(this.cachePosition + len)); 119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.write(this.cache, 0, this.cachePosition); 120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.write(bufferToAppend, off, len); 121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.writeLine(""); 122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.cachePosition = 0; 123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project protected void writeClosingChunk() throws IOException { 126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // Write the final chunk. 127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.writeLine("0"); 128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.writeLine(""); 129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // ----------------------------------------------------------- Public Methods 132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Must be called to ensure the internal cache is flushed and the closing chunk is written. 134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void finish() throws IOException { 137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!this.wroteLastChunk) { 138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project flushCache(); 139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project writeClosingChunk(); 140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.wroteLastChunk = true; 141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // -------------------------------------------- OutputStream Methods 145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void write(int b) throws IOException { 146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.closed) { 147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new IOException("Attempted write to closed stream."); 148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.cache[this.cachePosition] = (byte) b; 150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.cachePosition++; 151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.cachePosition == this.cache.length) flushCache(); 152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Writes the array. If the array does not fit within the buffer, it is 156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * not split, but rather written out as one large chunk. 157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param b 158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void write(byte b[]) throws IOException { 161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project write(b, 0, b.length); 162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void write(byte src[], int off, int len) throws IOException { 165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (this.closed) { 166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new IOException("Attempted write to closed stream."); 167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (len >= this.cache.length - this.cachePosition) { 169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project flushCacheWithAppend(src, off, len); 170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project System.arraycopy(src, off, cache, this.cachePosition, len); 172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.cachePosition += len; 173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Flushes the content buffer and the underlying stream. 178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void flush() throws IOException { 181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project flushCache(); 182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.flush(); 183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Finishes writing to the underlying stream, but does NOT close the underlying stream. 187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws IOException 188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void close() throws IOException { 190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!this.closed) { 191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.closed = true; 192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project finish(); 193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project this.out.flush(); 194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project} 197