001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027package org.apache.http.client.entity;
028
029import java.io.IOException;
030import java.io.InputStream;
031import java.io.OutputStream;
032
033import org.apache.http.Header;
034import org.apache.http.HttpEntity;
035import org.apache.http.entity.HttpEntityWrapper;
036import org.apache.http.util.Args;
037
038/**
039 * Common base class for decompressing {@link HttpEntity} implementations.
040 *
041 * @since 4.4
042 */
043public class DecompressingEntity extends HttpEntityWrapper {
044
045    /**
046     * Default buffer size.
047     */
048    private static final int BUFFER_SIZE = 1024 * 2;
049
050    private final InputStreamFactory inputStreamFactory;
051    /**
052     * {@link #getContent()} method must return the same {@link InputStream}
053     * instance when DecompressingEntity is wrapping a streaming entity.
054     */
055    private InputStream content;
056
057    /**
058     * Creates a new {@link DecompressingEntity}.
059     *
060     * @param wrapped the non-null {@link HttpEntity} to be wrapped
061     * @param inputStreamFactory factory to create decompressing stream.
062     */
063    public DecompressingEntity(
064            final HttpEntity wrapped,
065            final InputStreamFactory inputStreamFactory) {
066        super(wrapped);
067        this.inputStreamFactory = inputStreamFactory;
068    }
069
070    private InputStream getDecompressingStream() throws IOException {
071        final InputStream in = wrappedEntity.getContent();
072        return new LazyDecompressingInputStream(in, inputStreamFactory);
073    }
074
075    @Override
076    public InputStream getContent() throws IOException {
077        if (wrappedEntity.isStreaming()) {
078            if (content == null) {
079                content = getDecompressingStream();
080            }
081            return content;
082        } else {
083            return getDecompressingStream();
084        }
085    }
086
087    @Override
088    public void writeTo(final OutputStream outstream) throws IOException {
089        Args.notNull(outstream, "Output stream");
090        final InputStream instream = getContent();
091        try {
092            final byte[] buffer = new byte[BUFFER_SIZE];
093            int l;
094            while ((l = instream.read(buffer)) != -1) {
095                outstream.write(buffer, 0, l);
096            }
097        } finally {
098            instream.close();
099        }
100    }
101
102    @Override
103    public Header getContentEncoding() {
104        /* Content encoding is now 'identity' */
105        return null;
106    }
107
108    @Override
109    public long getContentLength() {
110        /* length of decompressed content is not known */
111        return -1;
112    }
113
114}