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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/entity/DeflateDecompressingEntity.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,174 @@
     1.4 +/*
     1.5 + * ====================================================================
     1.6 + *
     1.7 + *  Licensed to the Apache Software Foundation (ASF) under one or more
     1.8 + *  contributor license agreements.  See the NOTICE file distributed with
     1.9 + *  this work for additional information regarding copyright ownership.
    1.10 + *  The ASF licenses this file to You under the Apache License, Version 2.0
    1.11 + *  (the "License"); you may not use this file except in compliance with
    1.12 + *  the License.  You may obtain a copy of the License at
    1.13 + *
    1.14 + *      http://www.apache.org/licenses/LICENSE-2.0
    1.15 + *
    1.16 + *  Unless required by applicable law or agreed to in writing, software
    1.17 + *  distributed under the License is distributed on an "AS IS" BASIS,
    1.18 + *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.19 + *  See the License for the specific language governing permissions and
    1.20 + *  limitations under the License.
    1.21 + * ====================================================================
    1.22 + *
    1.23 + * This software consists of voluntary contributions made by many
    1.24 + * individuals on behalf of the Apache Software Foundation.  For more
    1.25 + * information on the Apache Software Foundation, please see
    1.26 + * <http://www.apache.org/>.
    1.27 + *
    1.28 +*/
    1.29 +package ch.boye.httpclientandroidlib.client.entity;
    1.30 +
    1.31 +import java.io.IOException;
    1.32 +import java.io.InputStream;
    1.33 +import java.io.PushbackInputStream;
    1.34 +import java.util.zip.DataFormatException;
    1.35 +import java.util.zip.Inflater;
    1.36 +import java.util.zip.InflaterInputStream;
    1.37 +
    1.38 +import ch.boye.httpclientandroidlib.Header;
    1.39 +import ch.boye.httpclientandroidlib.HttpEntity;
    1.40 +import ch.boye.httpclientandroidlib.entity.HttpEntityWrapper;
    1.41 +
    1.42 +/**
    1.43 + * {@link HttpEntityWrapper} responsible for handling deflate Content Coded responses. In RFC2616
    1.44 + * terms, <code>deflate</code> means a <code>zlib</code> stream as defined in RFC1950. Some server
    1.45 + * implementations have misinterpreted RFC2616 to mean that a <code>deflate</code> stream as
    1.46 + * defined in RFC1951 should be used (or maybe they did that since that's how IE behaves?). It's
    1.47 + * confusing that <code>deflate</code> in HTTP 1.1 means <code>zlib</code> streams rather than
    1.48 + * <code>deflate</code> streams. We handle both types in here, since that's what is seen on the
    1.49 + * internet. Moral - prefer <code>gzip</code>!
    1.50 + *
    1.51 + * @see GzipDecompressingEntity
    1.52 + *
    1.53 + * @since 4.1
    1.54 + */
    1.55 +public class DeflateDecompressingEntity extends DecompressingEntity {
    1.56 +
    1.57 +    /**
    1.58 +     * Creates a new {@link DeflateDecompressingEntity} which will wrap the specified
    1.59 +     * {@link HttpEntity}.
    1.60 +     *
    1.61 +     * @param entity
    1.62 +     *            a non-null {@link HttpEntity} to be wrapped
    1.63 +     */
    1.64 +    public DeflateDecompressingEntity(final HttpEntity entity) {
    1.65 +        super(entity);
    1.66 +    }
    1.67 +
    1.68 +    /**
    1.69 +     * Returns the non-null InputStream that should be returned to by all requests to
    1.70 +     * {@link #getContent()}.
    1.71 +     *
    1.72 +     * @return a non-null InputStream
    1.73 +     * @throws IOException if there was a problem
    1.74 +     */
    1.75 +    @Override
    1.76 +    InputStream getDecompressingInputStream(final InputStream wrapped) throws IOException {
    1.77 +        /*
    1.78 +         * A zlib stream will have a header.
    1.79 +         *
    1.80 +         * CMF | FLG [| DICTID ] | ...compressed data | ADLER32 |
    1.81 +         *
    1.82 +         * * CMF is one byte.
    1.83 +         *
    1.84 +         * * FLG is one byte.
    1.85 +         *
    1.86 +         * * DICTID is four bytes, and only present if FLG.FDICT is set.
    1.87 +         *
    1.88 +         * Sniff the content. Does it look like a zlib stream, with a CMF, etc? c.f. RFC1950,
    1.89 +         * section 2.2. http://tools.ietf.org/html/rfc1950#page-4
    1.90 +         *
    1.91 +         * We need to see if it looks like a proper zlib stream, or whether it is just a deflate
    1.92 +         * stream. RFC2616 calls zlib streams deflate. Confusing, isn't it? That's why some servers
    1.93 +         * implement deflate Content-Encoding using deflate streams, rather than zlib streams.
    1.94 +         *
    1.95 +         * We could start looking at the bytes, but to be honest, someone else has already read
    1.96 +         * the RFCs and implemented that for us. So we'll just use the JDK libraries and exception
    1.97 +         * handling to do this. If that proves slow, then we could potentially change this to check
    1.98 +         * the first byte - does it look like a CMF? What about the second byte - does it look like
    1.99 +         * a FLG, etc.
   1.100 +         */
   1.101 +
   1.102 +        /* We read a small buffer to sniff the content. */
   1.103 +        byte[] peeked = new byte[6];
   1.104 +
   1.105 +        PushbackInputStream pushback = new PushbackInputStream(wrapped, peeked.length);
   1.106 +
   1.107 +        int headerLength = pushback.read(peeked);
   1.108 +
   1.109 +        if (headerLength == -1) {
   1.110 +            throw new IOException("Unable to read the response");
   1.111 +        }
   1.112 +
   1.113 +        /* We try to read the first uncompressed byte. */
   1.114 +        byte[] dummy = new byte[1];
   1.115 +
   1.116 +        Inflater inf = new Inflater();
   1.117 +
   1.118 +        try {
   1.119 +            int n;
   1.120 +            while ((n = inf.inflate(dummy)) == 0) {
   1.121 +                if (inf.finished()) {
   1.122 +
   1.123 +                    /* Not expecting this, so fail loudly. */
   1.124 +                    throw new IOException("Unable to read the response");
   1.125 +                }
   1.126 +
   1.127 +                if (inf.needsDictionary()) {
   1.128 +
   1.129 +                    /* Need dictionary - then it must be zlib stream with DICTID part? */
   1.130 +                    break;
   1.131 +                }
   1.132 +
   1.133 +                if (inf.needsInput()) {
   1.134 +                    inf.setInput(peeked);
   1.135 +                }
   1.136 +            }
   1.137 +
   1.138 +            if (n == -1) {
   1.139 +                throw new IOException("Unable to read the response");
   1.140 +            }
   1.141 +
   1.142 +            /*
   1.143 +             * We read something without a problem, so it's a valid zlib stream. Just need to reset
   1.144 +             * and return an unused InputStream now.
   1.145 +             */
   1.146 +            pushback.unread(peeked, 0, headerLength);
   1.147 +            return new InflaterInputStream(pushback);
   1.148 +        } catch (DataFormatException e) {
   1.149 +
   1.150 +            /* Presume that it's an RFC1951 deflate stream rather than RFC1950 zlib stream and try
   1.151 +             * again. */
   1.152 +            pushback.unread(peeked, 0, headerLength);
   1.153 +            return new InflaterInputStream(pushback, new Inflater(true));
   1.154 +        }
   1.155 +    }
   1.156 +
   1.157 +    /**
   1.158 +     * {@inheritDoc}
   1.159 +     */
   1.160 +    @Override
   1.161 +    public Header getContentEncoding() {
   1.162 +
   1.163 +        /* This HttpEntityWrapper has dealt with the Content-Encoding. */
   1.164 +        return null;
   1.165 +    }
   1.166 +
   1.167 +    /**
   1.168 +     * {@inheritDoc}
   1.169 +     */
   1.170 +    @Override
   1.171 +    public long getContentLength() {
   1.172 +
   1.173 +        /* Length of inflated content is unknown. */
   1.174 +        return -1;
   1.175 +    }
   1.176 +
   1.177 +}

mercurial