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