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.DataFormatException;
22 import java.util.zip.Inflater;
23
24 import static org.jboss.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 ChannelBuffer decompressed;
35
36 SpdyHeaderBlockZlibDecoder(SpdyVersion spdyVersion, int maxHeaderSize) {
37 super(spdyVersion, maxHeaderSize);
38 }
39
40 @Override
41 void decode(ChannelBuffer headerBlock, SpdyHeadersFrame frame) throws Exception {
42 if (headerBlock == null) {
43 throw new NullPointerException("headerBlock");
44 }
45 if (frame == null) {
46 throw new NullPointerException("frame");
47 }
48
49 int len = setInput(headerBlock);
50
51 int numBytes;
52 do {
53 numBytes = decompress(frame);
54 } while (numBytes > 0);
55
56
57
58 if (decompressor.getRemaining() != 0) {
59
60 throw INVALID_HEADER_BLOCK;
61 }
62
63 headerBlock.skipBytes(len);
64 }
65
66 private int setInput(ChannelBuffer compressed) {
67 int len = compressed.readableBytes();
68
69 if (compressed.hasArray()) {
70 decompressor.setInput(compressed.array(), compressed.arrayOffset() + compressed.readerIndex(), len);
71 } else {
72 byte[] in = new byte[len];
73 compressed.getBytes(compressed.readerIndex(), in);
74 decompressor.setInput(in, 0, in.length);
75 }
76
77 return len;
78 }
79
80 private int decompress(SpdyHeadersFrame frame) throws Exception {
81 ensureBuffer();
82 byte[] out = decompressed.array();
83 int off = decompressed.arrayOffset() + decompressed.writerIndex();
84 try {
85 int numBytes = decompressor.inflate(out, off, decompressed.writableBytes());
86 if (numBytes == 0 && decompressor.needsDictionary()) {
87 try {
88 decompressor.setDictionary(SPDY_DICT);
89 } catch (IllegalArgumentException e) {
90 throw INVALID_HEADER_BLOCK;
91 }
92 numBytes = decompressor.inflate(out, off, decompressed.writableBytes());
93 }
94
95 decompressed.writerIndex(decompressed.writerIndex() + numBytes);
96 super.decodeHeaderBlock(decompressed, frame);
97 decompressed.discardReadBytes();
98
99 return numBytes;
100 } catch (DataFormatException e) {
101 throw INVALID_HEADER_BLOCK;
102 }
103 }
104
105 private void ensureBuffer() {
106 if (decompressed == null) {
107 decompressed = ChannelBuffers.dynamicBuffer(DEFAULT_BUFFER_CAPACITY);
108 }
109 decompressed.ensureWritableBytes(1);
110 }
111
112 @Override
113 void endHeaderBlock(SpdyHeadersFrame frame) throws Exception {
114 super.endHeaderBlock(frame);
115 decompressed = null;
116 }
117
118 @Override
119 public void end() {
120 super.end();
121 decompressed = null;
122 decompressor.end();
123 }
124 }