1 /*
2  * JBoss, Home of Professional Open Source.
3  * Copyright 2014 Red Hat, Inc., and individual contributors
4  * as indicated by the @author tags.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */

18
19 package io.undertow.conduits;
20
21 import io.undertow.server.Connectors;
22 import io.undertow.server.HttpServerExchange;
23 import io.undertow.util.ConduitFactory;
24 import io.undertow.util.ObjectPool;
25 import org.xnio.conduits.StreamSinkConduit;
26
27 import java.util.zip.CRC32;
28 import java.util.zip.Deflater;
29
30 /**
31  * @author Stuart Douglas
32  */

33 public class GzipStreamSinkConduit extends DeflatingStreamSinkConduit {
34
35     /*
36      * GZIP header magic number.
37      */

38     private static final int GZIP_MAGIC = 0x8b1f;
39     private static final byte[] HEADER = new byte[]{
40             (byte) GZIP_MAGIC,        // Magic number (short)
41             (byte) (GZIP_MAGIC >> 8),  // Magic number (short)
42             Deflater.DEFLATED,        // Compression method (CM)
43             0,                        // Flags (FLG)
44             0,                        // Modification time MTIME (int)
45             0,                        // Modification time MTIME (int)
46             0,                        // Modification time MTIME (int)
47             0,                        // Modification time MTIME (int)
48             0,                        // Extra flags (XFLG)
49             0                         // Operating system (OS)
50     };
51
52     /**
53      * CRC-32 of uncompressed data.
54      */

55     protected CRC32 crc = new CRC32();
56
57     public GzipStreamSinkConduit(ConduitFactory<StreamSinkConduit> conduitFactory, HttpServerExchange exchange) {
58         this(conduitFactory, exchange, Deflater.DEFAULT_COMPRESSION);
59     }
60
61     public GzipStreamSinkConduit(
62             ConduitFactory<StreamSinkConduit> conduitFactory,
63             HttpServerExchange exchange,
64             int deflateLevel) {
65         this(conduitFactory, exchange, newInstanceDeflaterPool(deflateLevel));
66     }
67
68     public GzipStreamSinkConduit(
69             ConduitFactory<StreamSinkConduit> conduitFactory,
70             HttpServerExchange exchange,
71             ObjectPool deflaterPool) {
72         super(conduitFactory, exchange, deflaterPool);
73         writeHeader();
74         Connectors.updateResponseBytesSent(exchange, HEADER.length);
75     }
76
77     private void writeHeader() {
78         currentBuffer.getBuffer().put(HEADER);
79     }
80
81     @Override
82     protected void preDeflate(byte[] data) {
83         crc.update(data);
84     }
85
86     @Override
87     protected byte[] getTrailer() {
88         byte[] ret = new byte[8];
89         int checksum = (int) crc.getValue();
90         int total = deflater.getTotalIn();
91         ret[0] = (byte) ((checksum) & 0xFF);
92         ret[1] = (byte) ((checksum >> 8) & 0xFF);
93         ret[2] = (byte) ((checksum >> 16) & 0xFF);
94         ret[3] = (byte) ((checksum >> 24) & 0xFF);
95         ret[4] = (byte) ((total) & 0xFF);
96         ret[5] = (byte) ((total >> 8) & 0xFF);
97         ret[6] = (byte) ((total >> 16) & 0xFF);
98         ret[7] = (byte) ((total >> 24) & 0xFF);
99         return ret;
100     }
101 }
102