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.Channel;
20 import io.netty.channel.ChannelHandler;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.channel.ChannelInboundHandlerAdapter;
23 import io.netty.handler.codec.ByteToMessageDecoder;
24 import io.netty.handler.codec.http3.Http3FrameCodec.Http3FrameCodecFactory;
25 import io.netty.util.AttributeKey;
26 import io.netty.util.ReferenceCountUtil;
27 import org.jetbrains.annotations.Nullable;
28
29 import java.util.List;
30 import java.util.function.LongFunction;
31 import java.util.function.Supplier;
32
33 import static io.netty.handler.codec.http3.Http3CodecUtils.HTTP3_CONTROL_STREAM_TYPE;
34 import static io.netty.handler.codec.http3.Http3CodecUtils.HTTP3_PUSH_STREAM_TYPE;
35 import static io.netty.handler.codec.http3.Http3CodecUtils.HTTP3_QPACK_DECODER_STREAM_TYPE;
36 import static io.netty.handler.codec.http3.Http3CodecUtils.HTTP3_QPACK_ENCODER_STREAM_TYPE;
37 import static io.netty.handler.codec.http3.Http3RequestStreamCodecState.NO_STATE;
38
39
40
41
42 abstract class Http3UnidirectionalStreamInboundHandler extends ByteToMessageDecoder {
43 private static final AttributeKey<Boolean> REMOTE_CONTROL_STREAM = AttributeKey.valueOf("H3_REMOTE_CONTROL_STREAM");
44 private static final AttributeKey<Boolean> REMOTE_QPACK_DECODER_STREAM =
45 AttributeKey.valueOf("H3_REMOTE_QPACK_DECODER_STREAM");
46 private static final AttributeKey<Boolean> REMOTE_QPACK_ENCODER_STREAM =
47 AttributeKey.valueOf("H3_REMOTE_QPACK_ENCODER_STREAM");
48
49 final Http3FrameCodecFactory codecFactory;
50 final Http3ControlStreamInboundHandler localControlStreamHandler;
51 final Http3ControlStreamOutboundHandler remoteControlStreamHandler;
52 final Supplier<ChannelHandler> qpackEncoderHandlerFactory;
53 final Supplier<ChannelHandler> qpackDecoderHandlerFactory;
54 final LongFunction<ChannelHandler> unknownStreamHandlerFactory;
55
56 Http3UnidirectionalStreamInboundHandler(Http3FrameCodecFactory codecFactory,
57 Http3ControlStreamInboundHandler localControlStreamHandler,
58 Http3ControlStreamOutboundHandler remoteControlStreamHandler,
59 @Nullable LongFunction<ChannelHandler> unknownStreamHandlerFactory,
60 Supplier<ChannelHandler> qpackEncoderHandlerFactory,
61 Supplier<ChannelHandler> qpackDecoderHandlerFactory) {
62 this.codecFactory = codecFactory;
63 this.localControlStreamHandler = localControlStreamHandler;
64 this.remoteControlStreamHandler = remoteControlStreamHandler;
65 this.qpackEncoderHandlerFactory = qpackEncoderHandlerFactory;
66 this.qpackDecoderHandlerFactory = qpackDecoderHandlerFactory;
67 if (unknownStreamHandlerFactory == null) {
68
69 unknownStreamHandlerFactory = type -> ReleaseHandler.INSTANCE;
70 }
71 this.unknownStreamHandlerFactory = unknownStreamHandlerFactory;
72 }
73
74 @Override
75 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
76 if (!in.isReadable()) {
77 return;
78 }
79 int len = Http3CodecUtils.numBytesForVariableLengthInteger(in.getByte(in.readerIndex()));
80 if (in.readableBytes() < len) {
81 return;
82 }
83 long type = Http3CodecUtils.readVariableLengthInteger(in, len);
84 switch ((int) type) {
85 case HTTP3_CONTROL_STREAM_TYPE:
86 initControlStream(ctx);
87 break;
88 case HTTP3_PUSH_STREAM_TYPE:
89 int pushIdLen = Http3CodecUtils.numBytesForVariableLengthInteger(in.getByte(in.readerIndex()));
90 if (in.readableBytes() < pushIdLen) {
91 return;
92 }
93 long pushId = Http3CodecUtils.readVariableLengthInteger(in, pushIdLen);
94 initPushStream(ctx, pushId);
95 break;
96 case HTTP3_QPACK_ENCODER_STREAM_TYPE:
97
98 initQpackEncoderStream(ctx);
99 break;
100 case HTTP3_QPACK_DECODER_STREAM_TYPE:
101
102 initQpackDecoderStream(ctx);
103 break;
104 default:
105 initUnknownStream(ctx, type);
106 break;
107 }
108 }
109
110
111
112
113
114 private void initControlStream(ChannelHandlerContext ctx) {
115 if (ctx.channel().parent().attr(REMOTE_CONTROL_STREAM).setIfAbsent(true) == null) {
116 ctx.pipeline().addLast(localControlStreamHandler);
117
118 ctx.pipeline().replace(this, null,
119 codecFactory.newCodec(Http3ControlStreamFrameTypeValidator.INSTANCE, NO_STATE,
120 NO_STATE));
121 } else {
122
123
124 Http3CodecUtils.connectionError(ctx, Http3ErrorCode.H3_STREAM_CREATION_ERROR,
125 "Received multiple control streams.", false);
126 }
127 }
128
129 private boolean ensureStreamNotExistsYet(ChannelHandlerContext ctx, AttributeKey<Boolean> key) {
130 return ctx.channel().parent().attr(key).setIfAbsent(true) == null;
131 }
132
133
134
135
136
137 abstract void initPushStream(ChannelHandlerContext ctx, long id);
138
139
140
141
142
143
144 private void initQpackEncoderStream(ChannelHandlerContext ctx) {
145 if (ensureStreamNotExistsYet(ctx, REMOTE_QPACK_ENCODER_STREAM)) {
146
147 ctx.pipeline().replace(this, null, qpackEncoderHandlerFactory.get());
148 } else {
149
150
151 Http3CodecUtils.connectionError(ctx, Http3ErrorCode.H3_STREAM_CREATION_ERROR,
152 "Received multiple QPACK encoder streams.", false);
153 }
154 }
155
156
157
158
159
160 private void initQpackDecoderStream(ChannelHandlerContext ctx) {
161 if (ensureStreamNotExistsYet(ctx, REMOTE_QPACK_DECODER_STREAM)) {
162 ctx.pipeline().replace(this, null, qpackDecoderHandlerFactory.get());
163 } else {
164
165
166 Http3CodecUtils.connectionError(ctx, Http3ErrorCode.H3_STREAM_CREATION_ERROR,
167 "Received multiple QPACK decoder streams.", false);
168 }
169 }
170
171
172
173
174
175 private void initUnknownStream(ChannelHandlerContext ctx, long streamType) {
176 ctx.pipeline().replace(this, null, unknownStreamHandlerFactory.apply(streamType));
177 }
178
179 static final class ReleaseHandler extends ChannelInboundHandlerAdapter {
180 static final ReleaseHandler INSTANCE = new ReleaseHandler();
181
182 @Override
183 public boolean isSharable() {
184 return true;
185 }
186
187 @Override
188 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
189 ReferenceCountUtil.release(msg);
190 }
191 }
192 }