mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/entity/DeflateDecompressingEntity.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * ====================================================================
     3  *
     4  *  Licensed to the Apache Software Foundation (ASF) under one or more
     5  *  contributor license agreements.  See the NOTICE file distributed with
     6  *  this work for additional information regarding copyright ownership.
     7  *  The ASF licenses this file to You under the Apache License, Version 2.0
     8  *  (the "License"); you may not use this file except in compliance with
     9  *  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, software
    14  *  distributed under the License is distributed on an "AS IS" BASIS,
    15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  *  See the License for the specific language governing permissions and
    17  *  limitations under the License.
    18  * ====================================================================
    19  *
    20  * This software consists of voluntary contributions made by many
    21  * individuals on behalf of the Apache Software Foundation.  For more
    22  * information on the Apache Software Foundation, please see
    23  * <http://www.apache.org/>.
    24  *
    25 */
    26 package ch.boye.httpclientandroidlib.client.entity;
    28 import java.io.IOException;
    29 import java.io.InputStream;
    30 import java.io.PushbackInputStream;
    31 import java.util.zip.DataFormatException;
    32 import java.util.zip.Inflater;
    33 import java.util.zip.InflaterInputStream;
    35 import ch.boye.httpclientandroidlib.Header;
    36 import ch.boye.httpclientandroidlib.HttpEntity;
    37 import ch.boye.httpclientandroidlib.entity.HttpEntityWrapper;
    39 /**
    40  * {@link HttpEntityWrapper} responsible for handling deflate Content Coded responses. In RFC2616
    41  * terms, <code>deflate</code> means a <code>zlib</code> stream as defined in RFC1950. Some server
    42  * implementations have misinterpreted RFC2616 to mean that a <code>deflate</code> stream as
    43  * defined in RFC1951 should be used (or maybe they did that since that's how IE behaves?). It's
    44  * confusing that <code>deflate</code> in HTTP 1.1 means <code>zlib</code> streams rather than
    45  * <code>deflate</code> streams. We handle both types in here, since that's what is seen on the
    46  * internet. Moral - prefer <code>gzip</code>!
    47  *
    48  * @see GzipDecompressingEntity
    49  *
    50  * @since 4.1
    51  */
    52 public class DeflateDecompressingEntity extends DecompressingEntity {
    54     /**
    55      * Creates a new {@link DeflateDecompressingEntity} which will wrap the specified
    56      * {@link HttpEntity}.
    57      *
    58      * @param entity
    59      *            a non-null {@link HttpEntity} to be wrapped
    60      */
    61     public DeflateDecompressingEntity(final HttpEntity entity) {
    62         super(entity);
    63     }
    65     /**
    66      * Returns the non-null InputStream that should be returned to by all requests to
    67      * {@link #getContent()}.
    68      *
    69      * @return a non-null InputStream
    70      * @throws IOException if there was a problem
    71      */
    72     @Override
    73     InputStream getDecompressingInputStream(final InputStream wrapped) throws IOException {
    74         /*
    75          * A zlib stream will have a header.
    76          *
    77          * CMF | FLG [| DICTID ] | ...compressed data | ADLER32 |
    78          *
    79          * * CMF is one byte.
    80          *
    81          * * FLG is one byte.
    82          *
    83          * * DICTID is four bytes, and only present if FLG.FDICT is set.
    84          *
    85          * Sniff the content. Does it look like a zlib stream, with a CMF, etc? c.f. RFC1950,
    86          * section 2.2. http://tools.ietf.org/html/rfc1950#page-4
    87          *
    88          * We need to see if it looks like a proper zlib stream, or whether it is just a deflate
    89          * stream. RFC2616 calls zlib streams deflate. Confusing, isn't it? That's why some servers
    90          * implement deflate Content-Encoding using deflate streams, rather than zlib streams.
    91          *
    92          * We could start looking at the bytes, but to be honest, someone else has already read
    93          * the RFCs and implemented that for us. So we'll just use the JDK libraries and exception
    94          * handling to do this. If that proves slow, then we could potentially change this to check
    95          * the first byte - does it look like a CMF? What about the second byte - does it look like
    96          * a FLG, etc.
    97          */
    99         /* We read a small buffer to sniff the content. */
   100         byte[] peeked = new byte[6];
   102         PushbackInputStream pushback = new PushbackInputStream(wrapped, peeked.length);
   104         int headerLength = pushback.read(peeked);
   106         if (headerLength == -1) {
   107             throw new IOException("Unable to read the response");
   108         }
   110         /* We try to read the first uncompressed byte. */
   111         byte[] dummy = new byte[1];
   113         Inflater inf = new Inflater();
   115         try {
   116             int n;
   117             while ((n = inf.inflate(dummy)) == 0) {
   118                 if (inf.finished()) {
   120                     /* Not expecting this, so fail loudly. */
   121                     throw new IOException("Unable to read the response");
   122                 }
   124                 if (inf.needsDictionary()) {
   126                     /* Need dictionary - then it must be zlib stream with DICTID part? */
   127                     break;
   128                 }
   130                 if (inf.needsInput()) {
   131                     inf.setInput(peeked);
   132                 }
   133             }
   135             if (n == -1) {
   136                 throw new IOException("Unable to read the response");
   137             }
   139             /*
   140              * We read something without a problem, so it's a valid zlib stream. Just need to reset
   141              * and return an unused InputStream now.
   142              */
   143             pushback.unread(peeked, 0, headerLength);
   144             return new InflaterInputStream(pushback);
   145         } catch (DataFormatException e) {
   147             /* Presume that it's an RFC1951 deflate stream rather than RFC1950 zlib stream and try
   148              * again. */
   149             pushback.unread(peeked, 0, headerLength);
   150             return new InflaterInputStream(pushback, new Inflater(true));
   151         }
   152     }
   154     /**
   155      * {@inheritDoc}
   156      */
   157     @Override
   158     public Header getContentEncoding() {
   160         /* This HttpEntityWrapper has dealt with the Content-Encoding. */
   161         return null;
   162     }
   164     /**
   165      * {@inheritDoc}
   166      */
   167     @Override
   168     public long getContentLength() {
   170         /* Length of inflated content is unknown. */
   171         return -1;
   172     }
   174 }

mercurial