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 */
27 package org.apache.hc.client5.http.entity;
28
29 import java.io.FilterInputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.PushbackInputStream;
33 import java.util.zip.Deflater;
34 import java.util.zip.Inflater;
35 import java.util.zip.InflaterInputStream;
36 import java.util.zip.ZipException;
37
38 /**
39 * Deflates an input stream. This class includes logic needed for various RFCs in order
40 * to reasonably implement the "deflate" compression algorithm.
41 */
42 public class DeflateInputStream extends FilterInputStream {
43
44 public DeflateInputStream(final InputStream wrapped) throws IOException {
45 super(null);
46 final PushbackInputStream pushback = new PushbackInputStream(wrapped, 2);
47 final int i1 = pushback.read();
48 final int i2 = pushback.read();
49 if (i1 == -1 || i2 == -1) {
50 throw new ZipException("Unexpected end of stream");
51 }
52
53 pushback.unread(i2);
54 pushback.unread(i1);
55
56 boolean nowrap = true;
57 final int b1 = i1 & 0xFF;
58 final int compressionMethod = b1 & 0xF;
59 final int compressionInfo = b1 >> 4 & 0xF;
60 final int b2 = i2 & 0xFF;
61 if (compressionMethod == Deflater.DEFLATED && compressionInfo <= 7 && ((b1 << 8) | b2) % 31 == 0) {
62 nowrap = false;
63 }
64 in = new DeflateStream(pushback, new Inflater(nowrap));
65 }
66
67 private static class DeflateStream extends InflaterInputStream {
68
69 private boolean closed;
70
71 private DeflateStream(final InputStream in, final Inflater inflater) {
72 super(in, inflater);
73 }
74
75 @Override
76 public void close() throws IOException {
77 if (closed) {
78 return;
79 }
80 closed = true;
81 inf.end();
82 super.close();
83 }
84
85 }
86
87 }