1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.spdy;
17
18 import org.jboss.netty.buffer.ChannelBuffer;
19 import org.jboss.netty.buffer.ChannelBuffers;
20
21 import java.util.zip.Deflater;
22
23 import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*;
24
25 class SpdyHeaderBlockZlibEncoder extends SpdyHeaderBlockRawEncoder {
26
27 private final Deflater compressor;
28
29 private boolean finished;
30
31 SpdyHeaderBlockZlibEncoder(SpdyVersion spdyVersion, int compressionLevel) {
32 super(spdyVersion);
33 if (compressionLevel < 0 || compressionLevel > 9) {
34 throw new IllegalArgumentException(
35 "compressionLevel: " + compressionLevel + " (expected: 0-9)");
36 }
37 compressor = new Deflater(compressionLevel);
38 compressor.setDictionary(SPDY_DICT);
39 }
40
41 private int setInput(ChannelBuffer decompressed) {
42 int len = decompressed.readableBytes();
43
44 if (decompressed.hasArray()) {
45 compressor.setInput(decompressed.array(), decompressed.arrayOffset() + decompressed.readerIndex(), len);
46 } else {
47 byte[] in = new byte[len];
48 decompressed.getBytes(decompressed.readerIndex(), in);
49 compressor.setInput(in, 0, in.length);
50 }
51
52 return len;
53 }
54
55 private void encode(ChannelBuffer compressed) {
56 while (compressInto(compressed)) {
57
58 compressed.ensureWritableBytes(compressed.capacity() << 1);
59 }
60 }
61
62 private boolean compressInto(ChannelBuffer compressed) {
63 byte[] out = compressed.array();
64 int off = compressed.arrayOffset() + compressed.writerIndex();
65 int toWrite = compressed.writableBytes();
66 int numBytes = compressor.deflate(out, off, toWrite, Deflater.SYNC_FLUSH);
67 compressed.writerIndex(compressed.writerIndex() + numBytes);
68 return numBytes == toWrite;
69 }
70
71 @Override
72 public synchronized ChannelBuffer encode(SpdyHeadersFrame frame) throws Exception {
73 if (frame == null) {
74 throw new IllegalArgumentException("frame");
75 }
76
77 if (finished) {
78 return ChannelBuffers.EMPTY_BUFFER;
79 }
80
81 ChannelBuffer decompressed = super.encode(frame);
82 if (decompressed.readableBytes() == 0) {
83 return ChannelBuffers.EMPTY_BUFFER;
84 }
85
86 ChannelBuffer compressed = ChannelBuffers.dynamicBuffer(decompressed.readableBytes());
87 int len = setInput(decompressed);
88 encode(compressed);
89 decompressed.skipBytes(len);
90
91 return compressed;
92 }
93
94 @Override
95 public synchronized void end() {
96 if (finished) {
97 return;
98 }
99 finished = true;
100 compressor.end();
101 super.end();
102 }
103 }