1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.websocketx.extensions.compression;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.CompositeByteBuf;
20 import io.netty.buffer.Unpooled;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.channel.embedded.EmbeddedChannel;
23 import io.netty.handler.codec.CodecException;
24 import io.netty.handler.codec.compression.ZlibCodecFactory;
25 import io.netty.handler.codec.compression.ZlibWrapper;
26 import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
27 import io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame;
28 import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
29 import io.netty.handler.codec.http.websocketx.WebSocketFrame;
30 import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionDecoder;
31 import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilter;
32
33 import java.util.List;
34
35 import static io.netty.util.internal.ObjectUtil.*;
36
37
38
39
40
41 abstract class DeflateDecoder extends WebSocketExtensionDecoder {
42
43 static final ByteBuf FRAME_TAIL = Unpooled.unreleasableBuffer(
44 Unpooled.wrappedBuffer(new byte[] {0x00, 0x00, (byte) 0xff, (byte) 0xff}))
45 .asReadOnly();
46
47 static final ByteBuf EMPTY_DEFLATE_BLOCK = Unpooled.unreleasableBuffer(
48 Unpooled.wrappedBuffer(new byte[] { 0x00 }))
49 .asReadOnly();
50
51 private final boolean noContext;
52 private final WebSocketExtensionFilter extensionDecoderFilter;
53
54 private EmbeddedChannel decoder;
55
56
57
58
59
60
61
62 DeflateDecoder(boolean noContext, WebSocketExtensionFilter extensionDecoderFilter) {
63 this.noContext = noContext;
64 this.extensionDecoderFilter = checkNotNull(extensionDecoderFilter, "extensionDecoderFilter");
65 }
66
67
68
69
70 protected WebSocketExtensionFilter extensionDecoderFilter() {
71 return extensionDecoderFilter;
72 }
73
74 protected abstract boolean appendFrameTail(WebSocketFrame msg);
75
76 protected abstract int newRsv(WebSocketFrame msg);
77
78 @Override
79 protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List<Object> out) throws Exception {
80 final ByteBuf decompressedContent = decompressContent(ctx, msg);
81
82 final WebSocketFrame outMsg;
83 if (msg instanceof TextWebSocketFrame) {
84 outMsg = new TextWebSocketFrame(msg.isFinalFragment(), newRsv(msg), decompressedContent);
85 } else if (msg instanceof BinaryWebSocketFrame) {
86 outMsg = new BinaryWebSocketFrame(msg.isFinalFragment(), newRsv(msg), decompressedContent);
87 } else if (msg instanceof ContinuationWebSocketFrame) {
88 outMsg = new ContinuationWebSocketFrame(msg.isFinalFragment(), newRsv(msg), decompressedContent);
89 } else {
90 throw new CodecException("unexpected frame type: " + msg.getClass().getName());
91 }
92
93 out.add(outMsg);
94 }
95
96 @Override
97 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
98 cleanup();
99 super.handlerRemoved(ctx);
100 }
101
102 @Override
103 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
104 cleanup();
105 super.channelInactive(ctx);
106 }
107
108 private ByteBuf decompressContent(ChannelHandlerContext ctx, WebSocketFrame msg) {
109 if (decoder == null) {
110 if (!(msg instanceof TextWebSocketFrame) && !(msg instanceof BinaryWebSocketFrame)) {
111 throw new CodecException("unexpected initial frame type: " + msg.getClass().getName());
112 }
113 decoder = new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.NONE));
114 }
115
116 boolean readable = msg.content().isReadable();
117 boolean emptyDeflateBlock = EMPTY_DEFLATE_BLOCK.equals(msg.content());
118
119 decoder.writeInbound(msg.content().retain());
120 if (appendFrameTail(msg)) {
121 decoder.writeInbound(FRAME_TAIL.duplicate());
122 }
123
124 CompositeByteBuf compositeDecompressedContent = ctx.alloc().compositeBuffer();
125 for (;;) {
126 ByteBuf partUncompressedContent = decoder.readInbound();
127 if (partUncompressedContent == null) {
128 break;
129 }
130 if (!partUncompressedContent.isReadable()) {
131 partUncompressedContent.release();
132 continue;
133 }
134 compositeDecompressedContent.addComponent(true, partUncompressedContent);
135 }
136
137
138 if (!emptyDeflateBlock && readable && compositeDecompressedContent.numComponents() <= 0) {
139
140
141 if (!(msg instanceof ContinuationWebSocketFrame)) {
142 compositeDecompressedContent.release();
143 throw new CodecException("cannot read uncompressed buffer");
144 }
145 }
146
147 if (msg.isFinalFragment() && noContext) {
148 cleanup();
149 }
150
151 return compositeDecompressedContent;
152 }
153
154 private void cleanup() {
155 if (decoder != null) {
156
157 decoder.finishAndReleaseAll();
158 decoder = null;
159 }
160 }
161 }