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.SPDY_DICT;
25 import static io.netty.util.internal.ObjectUtil.checkNotNullWithIAE;
26
27 class SpdyHeaderBlockZlibEncoder extends SpdyHeaderBlockRawEncoder {
28
29 private final Deflater compressor;
30
31 private boolean finished;
32
33 SpdyHeaderBlockZlibEncoder(SpdyVersion spdyVersion, int compressionLevel) {
34 super(spdyVersion);
35 if (compressionLevel < 0 || compressionLevel > 9) {
36 throw new IllegalArgumentException(
37 "compressionLevel: " + compressionLevel + " (expected: 0-9)");
38 }
39 compressor = new Deflater(compressionLevel);
40 compressor.setDictionary(SPDY_DICT);
41 }
42
43 private int setInput(ByteBuf decompressed) {
44 int len = decompressed.readableBytes();
45
46 if (decompressed.hasArray()) {
47 compressor.setInput(decompressed.array(), decompressed.arrayOffset() + decompressed.readerIndex(), len);
48 } else {
49 byte[] in = new byte[len];
50 decompressed.getBytes(decompressed.readerIndex(), in);
51 compressor.setInput(in, 0, in.length);
52 }
53
54 return len;
55 }
56
57 private ByteBuf encode(ByteBufAllocator alloc, int len) {
58 ByteBuf compressed = alloc.heapBuffer(len);
59 boolean release = true;
60 try {
61 while (compressInto(compressed)) {
62
63 compressed.ensureWritable(compressed.capacity() << 1);
64 }
65 release = false;
66 return compressed;
67 } finally {
68 if (release) {
69 compressed.release();
70 }
71 }
72 }
73
74 private boolean compressInto(ByteBuf compressed) {
75 byte[] out = compressed.array();
76 int off = compressed.arrayOffset() + compressed.writerIndex();
77 int toWrite = compressed.writableBytes();
78 final int numBytes = compressor.deflate(out, off, toWrite, Deflater.SYNC_FLUSH);
79 compressed.writerIndex(compressed.writerIndex() + numBytes);
80 return numBytes == toWrite;
81 }
82
83 @Override
84 public ByteBuf encode(ByteBufAllocator alloc, SpdyHeadersFrame frame) throws Exception {
85 checkNotNullWithIAE(alloc, "alloc");
86 checkNotNullWithIAE(frame, "frame");
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 }