HTTP/2 Server Example No Response for HTTP/1.x Only Clients
Motiviation: The HTTP/2 server example just hangs when a client is using only HTTP with no ALPN or upgrade attempts. We should still send some kind of response. Modifications: The HTTP/2 server example has a special handler to detect no upgrade HTTP clients and generate a response. Result: Clients that just use HTTP with no upgrade will no appear hung when interacting with the HTTP/2 server example.
This commit is contained in:
parent
9bf636076a
commit
04c0d77287
@ -15,7 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.example.http2.server;
|
package io.netty.example.http2.server;
|
||||||
|
|
||||||
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
@ -31,11 +33,15 @@ import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
|||||||
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
|
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP handler that responds with a "Hello World"
|
* HTTP handler that responds with a "Hello World"
|
||||||
*/
|
*/
|
||||||
public class HelloWorldHttp1Handler extends SimpleChannelInboundHandler<HttpRequest> {
|
public class HelloWorldHttp1Handler extends SimpleChannelInboundHandler<HttpRequest> {
|
||||||
|
private final String establishApproach;
|
||||||
|
|
||||||
|
public HelloWorldHttp1Handler(String establishApproach) {
|
||||||
|
this.establishApproach = checkNotNull(establishApproach, "establishApproach");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelRead0(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
|
public void channelRead0(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
|
||||||
@ -46,6 +52,7 @@ public class HelloWorldHttp1Handler extends SimpleChannelInboundHandler<HttpRequ
|
|||||||
|
|
||||||
ByteBuf content = ctx.alloc().buffer();
|
ByteBuf content = ctx.alloc().buffer();
|
||||||
content.writeBytes(HelloWorldHttp2Handler.RESPONSE_BYTES.duplicate());
|
content.writeBytes(HelloWorldHttp2Handler.RESPONSE_BYTES.duplicate());
|
||||||
|
ByteBufUtil.writeAscii(content, " - via " + req.protocolVersion() + " (" + establishApproach + ")");
|
||||||
|
|
||||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
|
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
|
||||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||||
|
@ -21,6 +21,7 @@ import static io.netty.example.http2.Http2ExampleUtil.UPGRADE_RESPONSE_HEADER;
|
|||||||
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||||
import static io.netty.handler.logging.LogLevel.INFO;
|
import static io.netty.handler.logging.LogLevel.INFO;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
||||||
@ -112,7 +113,10 @@ public class HelloWorldHttp2Handler extends Http2ConnectionHandler {
|
|||||||
Http2Headers headers, int streamDependency, short weight,
|
Http2Headers headers, int streamDependency, short weight,
|
||||||
boolean exclusive, int padding, boolean endStream) throws Http2Exception {
|
boolean exclusive, int padding, boolean endStream) throws Http2Exception {
|
||||||
if (endStream) {
|
if (endStream) {
|
||||||
sendResponse(ctx, streamId, RESPONSE_BYTES.duplicate());
|
ByteBuf content = ctx.alloc().buffer();
|
||||||
|
content.writeBytes(HelloWorldHttp2Handler.RESPONSE_BYTES.duplicate());
|
||||||
|
ByteBufUtil.writeAscii(content, " - via HTTP/2");
|
||||||
|
sendResponse(ctx, streamId, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public class Http2OrHttpHandler extends Http2OrHttpChooser {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ChannelHandler createHttp1RequestHandler() {
|
protected ChannelHandler createHttp1RequestHandler() {
|
||||||
return new HelloWorldHttp1Handler();
|
return new HelloWorldHttp1Handler("ALPN Negotiation");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -19,7 +19,9 @@ package io.netty.example.http2.server;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.codec.http.HttpMessage;
|
||||||
import io.netty.handler.codec.http.HttpServerCodec;
|
import io.netty.handler.codec.http.HttpServerCodec;
|
||||||
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
||||||
import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
|
import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
|
||||||
@ -66,6 +68,16 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
|||||||
|
|
||||||
ch.pipeline().addLast(sourceCodec);
|
ch.pipeline().addLast(sourceCodec);
|
||||||
ch.pipeline().addLast(upgradeHandler);
|
ch.pipeline().addLast(upgradeHandler);
|
||||||
|
ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpMessage>() {
|
||||||
|
@Override
|
||||||
|
protected void messageReceived(ChannelHandlerContext ctx, HttpMessage msg) throws Exception {
|
||||||
|
// If this handler is hit then no upgrade has been attempted and the client is just talking HTTP.
|
||||||
|
System.err.println("Directly talking: " + msg.protocolVersion() + " (no upgrade was attempted)");
|
||||||
|
ctx.pipeline().replace(this, "http-hello-world",
|
||||||
|
new HelloWorldHttp1Handler("Direct. No Upgrade Attempted."));
|
||||||
|
ctx.fireChannelRead(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
ch.pipeline().addLast(new UserEventLogger());
|
ch.pipeline().addLast(new UserEventLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user