mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/ChunkedOutputStream.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2  * ====================================================================
     3  * Licensed to the Apache Software Foundation (ASF) under one
     4  * or more contributor license agreements.  See the NOTICE file
     5  * distributed with this work for additional information
     6  * regarding copyright ownership.  The ASF licenses this file
     7  * to you under the Apache License, Version 2.0 (the
     8  * "License"); you may not use this file except in compliance
     9  * with the License.  You may obtain a copy of the License at
    10  *
    11  *   http://www.apache.org/licenses/LICENSE-2.0
    12  *
    13  * Unless required by applicable law or agreed to in writing,
    14  * software distributed under the License is distributed on an
    15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    16  * KIND, either express or implied.  See the License for the
    17  * specific language governing permissions and limitations
    18  * under the License.
    19  * ====================================================================
    20  *
    21  * This software consists of voluntary contributions made by many
    22  * individuals on behalf of the Apache Software Foundation.  For more
    23  * information on the Apache Software Foundation, please see
    24  * <http://www.apache.org/>.
    25  *
    26  */
    28 package ch.boye.httpclientandroidlib.impl.io;
    30 import java.io.IOException;
    31 import java.io.OutputStream;
    33 import ch.boye.httpclientandroidlib.io.SessionOutputBuffer;
    35 /**
    36  * Implements chunked transfer coding. The content is sent in small chunks.
    37  * Entities transferred using this output stream can be of unlimited length.
    38  * Writes are buffered to an internal buffer (2048 default size).
    39  * <p>
    40  * Note that this class NEVER closes the underlying stream, even when close
    41  * gets called.  Instead, the stream will be marked as closed and no further
    42  * output will be permitted.
    43  *
    44  *
    45  * @since 4.0
    46  */
    47 public class ChunkedOutputStream extends OutputStream {
    49     // ----------------------------------------------------- Instance Variables
    50     private final SessionOutputBuffer out;
    52     private byte[] cache;
    54     private int cachePosition = 0;
    56     private boolean wroteLastChunk = false;
    58     /** True if the stream is closed. */
    59     private boolean closed = false;
    61     // ----------------------------------------------------------- Constructors
    62     /**
    63      * Wraps a session output buffer and chunk-encodes the output.
    64      *
    65      * @param out The session output buffer
    66      * @param bufferSize The minimum chunk size (excluding last chunk)
    67      * @throws IOException in case of an I/O error
    68      */
    69     public ChunkedOutputStream(final SessionOutputBuffer out, int bufferSize)
    70             throws IOException {
    71         super();
    72         this.cache = new byte[bufferSize];
    73         this.out = out;
    74     }
    76     /**
    77      * Wraps a session output buffer and chunks the output. The default buffer
    78      * size of 2048 was chosen because the chunk overhead is less than 0.5%
    79      *
    80      * @param out       the output buffer to wrap
    81      * @throws IOException in case of an I/O error
    82      */
    83     public ChunkedOutputStream(final SessionOutputBuffer out)
    84             throws IOException {
    85         this(out, 2048);
    86     }
    88     // ----------------------------------------------------------- Internal methods
    89     /**
    90      * Writes the cache out onto the underlying stream
    91      */
    92     protected void flushCache() throws IOException {
    93         if (this.cachePosition > 0) {
    94             this.out.writeLine(Integer.toHexString(this.cachePosition));
    95             this.out.write(this.cache, 0, this.cachePosition);
    96             this.out.writeLine("");
    97             this.cachePosition = 0;
    98         }
    99     }
   101     /**
   102      * Writes the cache and bufferToAppend to the underlying stream
   103      * as one large chunk
   104      */
   105     protected void flushCacheWithAppend(byte bufferToAppend[], int off, int len) throws IOException {
   106         this.out.writeLine(Integer.toHexString(this.cachePosition + len));
   107         this.out.write(this.cache, 0, this.cachePosition);
   108         this.out.write(bufferToAppend, off, len);
   109         this.out.writeLine("");
   110         this.cachePosition = 0;
   111     }
   113     protected void writeClosingChunk() throws IOException {
   114         // Write the final chunk.
   115         this.out.writeLine("0");
   116         this.out.writeLine("");
   117     }
   119     // ----------------------------------------------------------- Public Methods
   120     /**
   121      * Must be called to ensure the internal cache is flushed and the closing
   122      * chunk is written.
   123      * @throws IOException in case of an I/O error
   124      */
   125     public void finish() throws IOException {
   126         if (!this.wroteLastChunk) {
   127             flushCache();
   128             writeClosingChunk();
   129             this.wroteLastChunk = true;
   130         }
   131     }
   133     // -------------------------------------------- OutputStream Methods
   134     public void write(int b) throws IOException {
   135         if (this.closed) {
   136             throw new IOException("Attempted write to closed stream.");
   137         }
   138         this.cache[this.cachePosition] = (byte) b;
   139         this.cachePosition++;
   140         if (this.cachePosition == this.cache.length) flushCache();
   141     }
   143     /**
   144      * Writes the array. If the array does not fit within the buffer, it is
   145      * not split, but rather written out as one large chunk.
   146      */
   147     public void write(byte b[]) throws IOException {
   148         write(b, 0, b.length);
   149     }
   151     /**
   152      * Writes the array. If the array does not fit within the buffer, it is
   153      * not split, but rather written out as one large chunk.
   154      */
   155     public void write(byte src[], int off, int len) throws IOException {
   156         if (this.closed) {
   157             throw new IOException("Attempted write to closed stream.");
   158         }
   159         if (len >= this.cache.length - this.cachePosition) {
   160             flushCacheWithAppend(src, off, len);
   161         } else {
   162             System.arraycopy(src, off, cache, this.cachePosition, len);
   163             this.cachePosition += len;
   164         }
   165     }
   167     /**
   168      * Flushes the content buffer and the underlying stream.
   169      */
   170     public void flush() throws IOException {
   171         flushCache();
   172         this.out.flush();
   173     }
   175     /**
   176      * Finishes writing to the underlying stream, but does NOT close the underlying stream.
   177      */
   178     public void close() throws IOException {
   179         if (!this.closed) {
   180             this.closed = true;
   181             finish();
   182             this.out.flush();
   183         }
   184     }
   185 }

mercurial