2828import io .netty .channel .nio .NioEventLoopGroup ;
2929import io .netty .channel .socket .SocketChannel ;
3030import io .netty .channel .socket .nio .NioServerSocketChannel ;
31+ import io .netty .handler .codec .http .DefaultFullHttpResponse ;
32+ import io .netty .handler .codec .http .FullHttpRequest ;
33+ import io .netty .handler .codec .http .HttpHeaderNames ;
34+ import io .netty .handler .codec .http .HttpHeaderValues ;
3135import io .netty .handler .codec .http .HttpObjectAggregator ;
3236import io .netty .handler .codec .http .HttpResponseStatus ;
3337import io .netty .handler .codec .http .HttpServerCodec ;
3438import io .netty .handler .codec .http .HttpServerUpgradeHandler ;
39+ import io .netty .handler .codec .http .HttpVersion ;
3540import io .netty .handler .codec .http2 .DefaultHttp2DataFrame ;
3641import io .netty .handler .codec .http2 .DefaultHttp2GoAwayFrame ;
3742import io .netty .handler .codec .http2 .DefaultHttp2Headers ;
@@ -164,12 +169,14 @@ public Http2ServerInitializer(Http2ServerHandler serverHandler) {
164169 public void handlerAdded (ChannelHandlerContext ctx ) throws Exception {
165170 ChannelPipeline pipeline = ctx .pipeline ();
166171
172+ System .out .println ("Setting up HTTP/2 server pipeline with upgrade support" );
173+
167174 // HTTP/1.1 codec for initial handshake and upgrade
168175 HttpServerCodec sourceCodec = new HttpServerCodec ();
169- pipeline .addLast (sourceCodec );
176+ pipeline .addLast ("http-codec" , sourceCodec );
170177
171178 // Aggregator for HTTP/1.1 messages (needed for upgrade)
172- pipeline .addLast (new HttpObjectAggregator (Integer .MAX_VALUE ));
179+ pipeline .addLast ("aggregator" , new HttpObjectAggregator (Integer .MAX_VALUE ));
173180
174181 // Build HTTP/2 codec
175182 Http2FrameCodecBuilder http2Builder = Http2FrameCodecBuilder .forServer ()
@@ -179,20 +186,73 @@ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
179186 HttpServerUpgradeHandler upgradeHandler = new HttpServerUpgradeHandler (
180187 sourceCodec ,
181188 protocol -> {
189+ System .out .println ("Upgrade requested for protocol: " + protocol );
182190 if (AsciiString .contentEquals (Http2CodecUtil .HTTP_UPGRADE_PROTOCOL_NAME , protocol )) {
183191 return new Http2ServerUpgradeCodec (http2Builder .build (), serverHandler );
184192 }
185193 return null ;
186194 }
187195 );
188196
189- pipeline .addLast (upgradeHandler );
197+ pipeline .addLast ("upgrade-handler" , upgradeHandler );
198+
199+ // Fallback handler for non-upgraded HTTP/1.1 requests
200+ pipeline .addLast ("http1-fallback" , new Http1FallbackHandler (serverHandler .goawayAfter ));
190201
191202 // Remove this initializer
192203 pipeline .remove (this );
193204 }
194205 }
195206
207+ /**
208+ * Fallback handler for HTTP/1.1 requests that don't upgrade to HTTP/2
209+ */
210+ private static final class Http1FallbackHandler extends ChannelInboundHandlerAdapter {
211+ private final AtomicInteger goawayAfter ;
212+
213+ public Http1FallbackHandler (AtomicInteger goawayAfter ) {
214+ this .goawayAfter = goawayAfter ;
215+ }
216+
217+ @ Override
218+ public void channelRead (ChannelHandlerContext ctx , Object msg ) throws Exception {
219+ if (msg instanceof FullHttpRequest ) {
220+ System .out .println ("Received HTTP/1.1 request (no upgrade): " + ((FullHttpRequest ) msg ).uri ());
221+ FullHttpRequest request = (FullHttpRequest ) msg ;
222+
223+ // Send HTTP/1.1 response
224+ ByteBuf content = Unpooled .copiedBuffer ("Hello from HTTP/2 server (HTTP/1.1 fallback)" , CharsetUtil .UTF_8 );
225+ DefaultFullHttpResponse response = new DefaultFullHttpResponse (
226+ HttpVersion .HTTP_1_1 ,
227+ HttpResponseStatus .OK ,
228+ content
229+ );
230+ response .headers ().set (HttpHeaderNames .CONTENT_TYPE , HttpHeaderValues .TEXT_PLAIN );
231+ response .headers ().set (HttpHeaderNames .CONTENT_LENGTH , content .readableBytes ());
232+ response .headers ().set (HttpHeaderNames .CONNECTION , HttpHeaderValues .CLOSE );
233+
234+ ctx .writeAndFlush (response ).addListener (future -> {
235+ if (goawayAfter .decrementAndGet () == 0 ) {
236+ System .out .println ("Request count reached, closing connection" );
237+ }
238+ ctx .close ();
239+ });
240+
241+ request .release ();
242+ } else {
243+ System .out .println ("Passing through message of type: " + msg .getClass ().getName ());
244+ super .channelRead (ctx , msg );
245+ }
246+ }
247+
248+ @ Override
249+ public void exceptionCaught (ChannelHandlerContext ctx , Throwable cause ) {
250+ System .err .println ("Exception in HTTP/1.1 fallback handler: " + cause .getMessage ());
251+ cause .printStackTrace ();
252+ ctx .close ();
253+ }
254+ }
255+
196256 private static final class Http2ServerHandler extends ChannelInboundHandlerAdapter {
197257
198258 private AtomicInteger goawayAfter ;
@@ -211,13 +271,17 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception {
211271
212272 @ Override
213273 public void channelRead (ChannelHandlerContext ctx , Object msg ) throws Exception {
274+ System .out .println ("Http2ServerHandler received message of type: " + msg .getClass ().getName ());
214275 if (msg instanceof Http2HeadersFrame ) {
215276 Http2HeadersFrame headersFrame = (Http2HeadersFrame ) msg ;
216277 sendResponse (ctx , headersFrame );
217278 if (goawayAfter .decrementAndGet () == 0 ) {
218279 System .out .println ("Request count reached , sending GOAWAY" );
219280 sendGoaway (ctx );
220281 }
282+ } else {
283+ System .out .println ("Http2ServerHandler: Not an Http2HeadersFrame, passing through" );
284+ super .channelRead (ctx , msg );
221285 }
222286 }
223287
0 commit comments