From d0beb8dea14e88718d6d06f0867ba8582dce4762 Mon Sep 17 00:00:00 2001 From: Oleksii Kachaiev Date: Tue, 2 Apr 2019 12:10:11 -0700 Subject: [PATCH] Carefully manage Keep-Alive/Close connection headers in all examples (#8966) Motivation: "Connection: close" header should be specified each time we're going to close an underlying TCP connection when sending HTTP/1.1 reply. Modifications: Introduces changes made in #8914 for the following examples: * WebSocket index page and WebSocket server handler * HelloWorld server * SPDY server handler * HTTP/1.1 server handler from HTTP/2 HelloWorld example * HTTP/1.1 server handler from tiles example Result: Keep-Alive connections management conforms with RFCs. --- .../file/HttpStaticFileServerHandler.java | 40 +++++++++++-------- .../HttpHelloWorldServerHandler.java | 33 +++++++++------ .../http/upload/HttpUploadServerHandler.java | 39 ++++++++++++------ .../WebSocketServerHandler.java | 24 ++++++++--- .../server/WebSocketIndexPageHandler.java | 18 +++++++-- .../server/HelloWorldHttp1Handler.java | 16 +++++--- .../http2/tiles/Http1RequestHandler.java | 10 ++++- 7 files changed, 121 insertions(+), 59 deletions(-) diff --git a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java index d5e875102e..d3903437c6 100644 --- a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java @@ -110,15 +110,18 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler&\\\"]*"); - private static void sendListing(ChannelHandlerContext ctx, File dir, String dirPath, boolean keepAlive) { + private void sendListing(ChannelHandlerContext ctx, File dir, String dirPath) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8"); @@ -306,22 +311,22 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler { private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }; - private static final AsciiString CONTENT_TYPE = AsciiString.cached("Content-Type"); - private static final AsciiString CONTENT_LENGTH = AsciiString.cached("Content-Length"); - private static final AsciiString CONNECTION = AsciiString.cached("Connection"); - private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive"); - @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); @@ -52,11 +53,17 @@ public class HttpHelloWorldServerHandler extends SimpleChannelInboundHandler cookies; @@ -343,7 +344,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler } // Send the response and close the connection if necessary. - ChannelFuture f = ctx.channel().writeAndFlush(res); if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) { - f.addListener(ChannelFutureListener.CLOSE); + // Tell the client we're going to close the connection. + res.headers().set(CONNECTION, CLOSE); + ctx.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE); + } else { + if (req.protocolVersion().equals(HTTP_1_0)) { + res.headers().set(CONNECTION, KEEP_ALIVE); + } + ctx.writeAndFlush(res); } } diff --git a/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketIndexPageHandler.java b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketIndexPageHandler.java index 124415d12a..9807dcef5b 100644 --- a/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketIndexPageHandler.java +++ b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketIndexPageHandler.java @@ -17,7 +17,6 @@ package io.netty.example.http.websocketx.server; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; @@ -31,11 +30,16 @@ import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.ssl.SslHandler; import io.netty.util.CharsetUtil; +import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; +import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION; +import static io.netty.handler.codec.http.HttpHeaderValues.CLOSE; +import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE; import static io.netty.handler.codec.http.HttpMethod.GET; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_0; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; /** @@ -69,7 +73,7 @@ public class WebSocketIndexPageHandler extends SimpleChannelInboundHandler { if (isKeepAlive(request)) { - response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE); + if (request.protocolVersion().equals(HTTP_1_0)) { + response.headers().set(CONNECTION, KEEP_ALIVE); + } ctx.writeAndFlush(response); } else { + // Tell the client we're going to close the connection. + response.headers().set(CONNECTION, CLOSE); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } }, latency, TimeUnit.MILLISECONDS);