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
21 import java.util.zip.DataFormatException;
22 import java.util.zip.Inflater;
23
24 import static io.netty.handler.codec.spdy.SpdyCodecUtil.*;
25
26 final class SpdyHeaderBlockZlibDecoder extends SpdyHeaderBlockRawDecoder {
27
28 private static final int DEFAULT_BUFFER_CAPACITY = 4096;
29 private static final SpdyProtocolException INVALID_HEADER_BLOCK =
30 new SpdyProtocolException("Invalid Header Block");
31
32 private final Inflater decompressor = new Inflater();
33
34 private ByteBuf decompressed;
35
36 SpdyHeaderBlockZlibDecoder(SpdyVersion spdyVersion, int maxHeaderSize) {
37 super(spdyVersion, maxHeaderSize);
38 }
39
40 @Override
41 void decode(ByteBufAllocator alloc, ByteBuf headerBlock, SpdyHeadersFrame frame) throws Exception {
42 int len = setInput(headerBlock);
43
44 int numBytes;
45 do {
46 numBytes = decompress(alloc, frame);
47 } while (numBytes > 0);
48
49
50
51 if (decompressor.getRemaining() != 0) {
52
53 throw INVALID_HEADER_BLOCK;
54 }
55
56 headerBlock.skipBytes(len);
57 }
58
59 private int setInput(ByteBuf compressed) {
60 int len = compressed.readableBytes();
61
62 if (compressed.hasArray()) {
63 decompressor.setInput(compressed.array(), compressed.arrayOffset() + compressed.readerIndex(), len);
64 } else {
65 byte[] in = new byte[len];
66 compressed.getBytes(compressed.readerIndex(), in);
67 decompressor.setInput(in, 0, in.length);
68 }
69
70 return len;
71 }
72
73 private int decompress(ByteBufAllocator alloc, SpdyHeadersFrame frame) throws Exception {
74 ensureBuffer(alloc);
75 byte[] out = decompressed.array();
76 int off = decompressed.arrayOffset() + decompressed.writerIndex();
77 try {
78 int numBytes = decompressor.inflate(out, off, decompressed.writableBytes());
79 if (numBytes == 0 && decompressor.needsDictionary()) {
80 try {
81 decompressor.setDictionary(SPDY_DICT);
82 } catch (IllegalArgumentException ignored) {
83 throw INVALID_HEADER_BLOCK;
84 }
85 numBytes = decompressor.inflate(out, off, decompressed.writableBytes());
86 }
87 if (frame != null) {
88 decompressed.writerIndex(decompressed.writerIndex() + numBytes);
89 decodeHeaderBlock(decompressed, frame);
90 decompressed.discardReadBytes();
91 }
92
93 return numBytes;
94 } catch (DataFormatException e) {
95 throw new SpdyProtocolException("Received invalid header block", e);
96 }
97 }
98
99 private void ensureBuffer(ByteBufAllocator alloc) {
100 if (decompressed == null) {
101 decompressed = alloc.heapBuffer(DEFAULT_BUFFER_CAPACITY);
102 }
103 decompressed.ensureWritable(1);
104 }
105
106 @Override
107 void endHeaderBlock(SpdyHeadersFrame frame) throws Exception {
108 super.endHeaderBlock(frame);
109 releaseBuffer();
110 }
111
112 @Override
113 public void end() {
114 super.end();
115 releaseBuffer();
116 decompressor.end();
117 }
118
119 private void releaseBuffer() {
120 if (decompressed != null) {
121 decompressed.release();
122 decompressed = null;
123 }
124 }
125 }