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 &amp; 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