1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http3;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.channel.socket.ChannelInputShutdownEvent;
21 import io.netty.handler.codec.ByteToMessageDecoder;
22
23 import java.util.List;
24
25 import static io.netty.handler.codec.http3.Http3CodecUtils.connectionError;
26 import static io.netty.handler.codec.http3.Http3ErrorCode.QPACK_DECODER_STREAM_ERROR;
27 import static io.netty.handler.codec.http3.QpackUtil.decodePrefixedIntegerAsInt;
28
29 final class QpackDecoderHandler extends ByteToMessageDecoder {
30
31 private boolean discard;
32 private final QpackEncoder qpackEncoder;
33
34 QpackDecoderHandler(QpackEncoder qpackEncoder) {
35 this.qpackEncoder = qpackEncoder;
36 }
37
38 @Override
39 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
40 if (!in.isReadable()) {
41 return;
42 }
43 if (discard) {
44 in.skipBytes(in.readableBytes());
45 return;
46 }
47
48 byte b = in.getByte(in.readerIndex());
49
50
51
52
53
54
55
56 if ((b & 0b1000_0000) == 0b1000_0000) {
57 long streamId = QpackUtil.decodePrefixedInteger(in, 7);
58 if (streamId < 0) {
59
60 return;
61 }
62 try {
63 qpackEncoder.sectionAcknowledgment(streamId);
64 } catch (QpackException e) {
65 connectionError(ctx, new Http3Exception(QPACK_DECODER_STREAM_ERROR,
66 "Section acknowledgment decode failed.", e), true);
67 }
68 return;
69 }
70
71
72
73
74
75
76
77 if ((b & 0b1100_0000) == 0b0100_0000) {
78 long streamId = QpackUtil.decodePrefixedInteger(in, 6);
79 if (streamId < 0) {
80
81 return;
82 }
83 try {
84 qpackEncoder.streamCancellation(streamId);
85 } catch (QpackException e) {
86 connectionError(ctx, new Http3Exception(QPACK_DECODER_STREAM_ERROR,
87 "Stream cancellation decode failed.", e), true);
88 }
89 return;
90 }
91
92
93
94
95
96
97
98 if ((b & 0b1100_0000) == 0b0000_0000) {
99 int increment = decodePrefixedIntegerAsInt(in, 6);
100 if (increment == 0) {
101 discard = true;
102
103
104
105
106 connectionError(ctx, QPACK_DECODER_STREAM_ERROR,
107 "Invalid increment '" + increment + "'.", false);
108 return;
109 }
110 if (increment < 0) {
111
112 return;
113 }
114 try {
115 qpackEncoder.insertCountIncrement(increment);
116 } catch (QpackException e) {
117 connectionError(ctx, new Http3Exception(QPACK_DECODER_STREAM_ERROR,
118 "Insert count increment decode failed.", e), true);
119 }
120 return;
121 }
122
123 discard = true;
124 connectionError(ctx, QPACK_DECODER_STREAM_ERROR,
125 "Unknown decoder instruction '" + b + "'.", false);
126 }
127
128 @Override
129 public void channelReadComplete(ChannelHandlerContext ctx) {
130 ctx.fireChannelReadComplete();
131
132
133
134 Http3CodecUtils.readIfNoAutoRead(ctx);
135 }
136
137 @Override
138 public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
139 if (evt instanceof ChannelInputShutdownEvent) {
140
141 Http3CodecUtils.criticalStreamClosed(ctx);
142 }
143 ctx.fireUserEventTriggered(evt);
144 }
145
146 @Override
147 public void channelInactive(ChannelHandlerContext ctx) {
148
149 Http3CodecUtils.criticalStreamClosed(ctx);
150 ctx.fireChannelInactive();
151 }
152 }