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