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
32 import java.util.List;
33
34
35
36
37
38 abstract class DeflateDecoder extends WebSocketExtensionDecoder {
39
40 static final byte[] FRAME_TAIL = new byte[] {0x00, 0x00, (byte) 0xff, (byte) 0xff};
41
42 private final boolean noContext;
43
44 private EmbeddedChannel decoder;
45
46
47
48
49
50 public DeflateDecoder(boolean noContext) {
51 this.noContext = noContext;
52 }
53
54 protected abstract boolean appendFrameTail(WebSocketFrame msg);
55
56 protected abstract int newRsv(WebSocketFrame msg);
57
58 @Override
59 protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List<Object> out) throws Exception {
60 if (decoder == null) {
61 if (!(msg instanceof TextWebSocketFrame) && !(msg instanceof BinaryWebSocketFrame)) {
62 throw new CodecException("unexpected initial frame type: " + msg.getClass().getName());
63 }
64 decoder = new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.NONE));
65 }
66
67 boolean readable = msg.content().isReadable();
68 decoder.writeInbound(msg.content().retain());
69 if (appendFrameTail(msg)) {
70 decoder.writeInbound(Unpooled.wrappedBuffer(FRAME_TAIL));
71 }
72
73 CompositeByteBuf compositeUncompressedContent = ctx.alloc().compositeBuffer();
74 for (;;) {
75 ByteBuf partUncompressedContent = decoder.readInbound();
76 if (partUncompressedContent == null) {
77 break;
78 }
79 if (!partUncompressedContent.isReadable()) {
80 partUncompressedContent.release();
81 continue;
82 }
83 compositeUncompressedContent.addComponent(true, partUncompressedContent);
84 }
85
86
87 if (readable && compositeUncompressedContent.numComponents() <= 0) {
88 compositeUncompressedContent.release();
89 throw new CodecException("cannot read uncompressed buffer");
90 }
91
92 if (msg.isFinalFragment() && noContext) {
93 cleanup();
94 }
95
96 WebSocketFrame outMsg;
97 if (msg instanceof TextWebSocketFrame) {
98 outMsg = new TextWebSocketFrame(msg.isFinalFragment(), newRsv(msg), compositeUncompressedContent);
99 } else if (msg instanceof BinaryWebSocketFrame) {
100 outMsg = new BinaryWebSocketFrame(msg.isFinalFragment(), newRsv(msg), compositeUncompressedContent);
101 } else if (msg instanceof ContinuationWebSocketFrame) {
102 outMsg = new ContinuationWebSocketFrame(msg.isFinalFragment(), newRsv(msg),
103 compositeUncompressedContent);
104 } else {
105 throw new CodecException("unexpected frame type: " + msg.getClass().getName());
106 }
107 out.add(outMsg);
108 }
109
110 @Override
111 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
112 cleanup();
113 super.handlerRemoved(ctx);
114 }
115
116 @Override
117 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
118 cleanup();
119 super.channelInactive(ctx);
120 }
121
122 private void cleanup() {
123 if (decoder != null) {
124
125 if (decoder.finish()) {
126 for (;;) {
127 ByteBuf buf = decoder.readOutbound();
128 if (buf == null) {
129 break;
130 }
131
132 buf.release();
133 }
134 }
135 decoder = null;
136 }
137 }
138 }