1 /* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/ChunkedOutputStream.java $ 3 * $Revision: 645081 $ 4 * $Date: 2008-04-05 04:36:42 -0700 (Sat, 05 Apr 2008) $ 5 * 6 * ==================================================================== 7 * Licensed to the Apache Software Foundation (ASF) under one 8 * or more contributor license agreements. See the NOTICE file 9 * distributed with this work for additional information 10 * regarding copyright ownership. The ASF licenses this file 11 * to you under the Apache License, Version 2.0 (the 12 * "License"); you may not use this file except in compliance 13 * with the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, 18 * software distributed under the License is distributed on an 19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20 * KIND, either express or implied. See the License for the 21 * specific language governing permissions and limitations 22 * under the License. 23 * ==================================================================== 24 * 25 * This software consists of voluntary contributions made by many 26 * individuals on behalf of the Apache Software Foundation. For more 27 * information on the Apache Software Foundation, please see 28 * <http://www.apache.org/>. 29 * 30 */ 31 32 package org.apache.http.impl.io; 33 34 import java.io.IOException; 35 import java.io.OutputStream; 36 37 import org.apache.http.io.SessionOutputBuffer; 38 39 /** 40 * Implements chunked transfer coding. 41 * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>, 42 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">section 3.6.1</a>. 43 * Writes are buffered to an internal buffer (2048 default size). 44 * 45 * @author Mohammad Rezaei (Goldman, Sachs & Co.) 46 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> 47 * 48 * @since 4.0 49 * 50 * @deprecated Please use {@link java.net.URL#openConnection} instead. 51 * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> 52 * for further details. 53 */ 54 @Deprecated 55 public class ChunkedOutputStream extends OutputStream { 56 57 // ----------------------------------------------------- Instance Variables 58 private final SessionOutputBuffer out; 59 60 private byte[] cache; 61 62 private int cachePosition = 0; 63 64 private boolean wroteLastChunk = false; 65 66 /** True if the stream is closed. */ 67 private boolean closed = false; 68 69 // ----------------------------------------------------------- Constructors 70 /** 71 * Wraps a session output buffer and chunks the output. 72 * @param out the session output buffer to wrap 73 * @param bufferSize minimum chunk size (excluding last chunk) 74 * @throws IOException 75 */ ChunkedOutputStream(final SessionOutputBuffer out, int bufferSize)76 public ChunkedOutputStream(final SessionOutputBuffer out, int bufferSize) 77 throws IOException { 78 super(); 79 this.cache = new byte[bufferSize]; 80 this.out = out; 81 } 82 83 /** 84 * Wraps a session output buffer and chunks the output. The default buffer 85 * size of 2048 was chosen because the chunk overhead is less than 0.5% 86 * 87 * @param out the output buffer to wrap 88 * @throws IOException 89 */ ChunkedOutputStream(final SessionOutputBuffer out)90 public ChunkedOutputStream(final SessionOutputBuffer out) 91 throws IOException { 92 this(out, 2048); 93 } 94 95 // ----------------------------------------------------------- Internal methods 96 /** 97 * Writes the cache out onto the underlying stream 98 * @throws IOException 99 */ flushCache()100 protected void flushCache() throws IOException { 101 if (this.cachePosition > 0) { 102 this.out.writeLine(Integer.toHexString(this.cachePosition)); 103 this.out.write(this.cache, 0, this.cachePosition); 104 this.out.writeLine(""); 105 this.cachePosition = 0; 106 } 107 } 108 109 /** 110 * Writes the cache and bufferToAppend to the underlying stream 111 * as one large chunk 112 * @param bufferToAppend 113 * @param off 114 * @param len 115 * @throws IOException 116 */ flushCacheWithAppend(byte bufferToAppend[], int off, int len)117 protected void flushCacheWithAppend(byte bufferToAppend[], int off, int len) throws IOException { 118 this.out.writeLine(Integer.toHexString(this.cachePosition + len)); 119 this.out.write(this.cache, 0, this.cachePosition); 120 this.out.write(bufferToAppend, off, len); 121 this.out.writeLine(""); 122 this.cachePosition = 0; 123 } 124 writeClosingChunk()125 protected void writeClosingChunk() throws IOException { 126 // Write the final chunk. 127 this.out.writeLine("0"); 128 this.out.writeLine(""); 129 } 130 131 // ----------------------------------------------------------- Public Methods 132 /** 133 * Must be called to ensure the internal cache is flushed and the closing chunk is written. 134 * @throws IOException 135 */ finish()136 public void finish() throws IOException { 137 if (!this.wroteLastChunk) { 138 flushCache(); 139 writeClosingChunk(); 140 this.wroteLastChunk = true; 141 } 142 } 143 144 // -------------------------------------------- OutputStream Methods write(int b)145 public void write(int b) throws IOException { 146 if (this.closed) { 147 throw new IOException("Attempted write to closed stream."); 148 } 149 this.cache[this.cachePosition] = (byte) b; 150 this.cachePosition++; 151 if (this.cachePosition == this.cache.length) flushCache(); 152 } 153 154 /** 155 * Writes the array. If the array does not fit within the buffer, it is 156 * not split, but rather written out as one large chunk. 157 * @param b 158 * @throws IOException 159 */ write(byte b[])160 public void write(byte b[]) throws IOException { 161 write(b, 0, b.length); 162 } 163 write(byte src[], int off, int len)164 public void write(byte src[], int off, int len) throws IOException { 165 if (this.closed) { 166 throw new IOException("Attempted write to closed stream."); 167 } 168 if (len >= this.cache.length - this.cachePosition) { 169 flushCacheWithAppend(src, off, len); 170 } else { 171 System.arraycopy(src, off, cache, this.cachePosition, len); 172 this.cachePosition += len; 173 } 174 } 175 176 /** 177 * Flushes the content buffer and the underlying stream. 178 * @throws IOException 179 */ flush()180 public void flush() throws IOException { 181 flushCache(); 182 this.out.flush(); 183 } 184 185 /** 186 * Finishes writing to the underlying stream, but does NOT close the underlying stream. 187 * @throws IOException 188 */ close()189 public void close() throws IOException { 190 if (!this.closed) { 191 this.closed = true; 192 finish(); 193 this.out.flush(); 194 } 195 } 196 } 197