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