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.
This commit is contained in:
parent
20042b6522
commit
52411233d3
@ -110,15 +110,18 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
|
||||
public static final int HTTP_CACHE_SECONDS = 60;
|
||||
|
||||
private FullHttpRequest request;
|
||||
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
|
||||
this.request = request;
|
||||
if (!request.decoderResult().isSuccess()) {
|
||||
sendError(ctx, BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GET.equals(request.method())) {
|
||||
sendError(ctx, METHOD_NOT_ALLOWED);
|
||||
this.sendError(ctx, METHOD_NOT_ALLOWED);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -126,21 +129,21 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
final String uri = request.uri();
|
||||
final String path = sanitizeUri(uri);
|
||||
if (path == null) {
|
||||
sendError(ctx, FORBIDDEN);
|
||||
this.sendError(ctx, FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
File file = new File(path);
|
||||
if (file.isHidden() || !file.exists()) {
|
||||
sendError(ctx, NOT_FOUND);
|
||||
this.sendError(ctx, NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
if (uri.endsWith("/")) {
|
||||
sendListing(ctx, file, uri, keepAlive);
|
||||
this.sendListing(ctx, file, uri);
|
||||
} else {
|
||||
sendRedirect(ctx, uri + '/', keepAlive);
|
||||
this.sendRedirect(ctx, uri + '/');
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -161,7 +164,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000;
|
||||
long fileLastModifiedSeconds = file.lastModified() / 1000;
|
||||
if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
|
||||
sendNotModified(ctx, keepAlive);
|
||||
this.sendNotModified(ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -182,6 +185,8 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
|
||||
if (!keepAlive) {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||
} else if (request.protocolVersion().equals(HTTP_1_0)) {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
// Write the initial line and the header.
|
||||
@ -266,7 +271,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
|
||||
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[^-\\._]?[^<>&\\\"]*");
|
||||
|
||||
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<Ful
|
||||
response.content().writeBytes(buffer);
|
||||
buffer.release();
|
||||
|
||||
sendAndCleanupConnection(ctx, response, keepAlive);
|
||||
this.sendAndCleanupConnection(ctx, response);
|
||||
}
|
||||
|
||||
private static void sendRedirect(ChannelHandlerContext ctx, String newUri, boolean keepAlive) {
|
||||
private void sendRedirect(ChannelHandlerContext ctx, String newUri) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, FOUND);
|
||||
response.headers().set(HttpHeaderNames.LOCATION, newUri);
|
||||
|
||||
sendAndCleanupConnection(ctx, response, keepAlive);
|
||||
this.sendAndCleanupConnection(ctx, response);
|
||||
}
|
||||
|
||||
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
|
||||
private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||
HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8));
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
|
||||
sendAndCleanupConnection(ctx, response, false);
|
||||
this.sendAndCleanupConnection(ctx, response);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,24 +335,27 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
* @param ctx
|
||||
* Context
|
||||
*/
|
||||
private static void sendNotModified(ChannelHandlerContext ctx, boolean keepAlive) {
|
||||
private void sendNotModified(ChannelHandlerContext ctx) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, NOT_MODIFIED);
|
||||
setDateHeader(response);
|
||||
|
||||
sendAndCleanupConnection(ctx, response, keepAlive);
|
||||
this.sendAndCleanupConnection(ctx, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* If Keep-Alive is disabled, attaches "Connection: close" header to the response
|
||||
* and closes the connection after the response being sent.
|
||||
*/
|
||||
private static void sendAndCleanupConnection(ChannelHandlerContext ctx, FullHttpResponse response,
|
||||
boolean keepAlive) {
|
||||
private void sendAndCleanupConnection(ChannelHandlerContext ctx, FullHttpResponse response) {
|
||||
final FullHttpRequest request = this.request;
|
||||
final boolean keepAlive = HttpUtil.isKeepAlive(request);
|
||||
HttpUtil.setContentLength(response, response.content().readableBytes());
|
||||
if (!keepAlive) {
|
||||
// We're going to close the connection as soon as the response is sent,
|
||||
// so we should also make it clear for the client.
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||
} else if (request.protocolVersion().equals(HTTP_1_0)) {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
ChannelFuture flushPromise = ctx.writeAndFlush(response);
|
||||
|
@ -16,27 +16,28 @@
|
||||
package io.netty.example.http.helloworld;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpObject;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
||||
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.HttpResponseStatus.OK;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
|
||||
public class HttpHelloWorldServerHandler extends SimpleChannelInboundHandler<HttpObject> {
|
||||
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<Htt
|
||||
response.headers().set(CONTENT_TYPE, "text/plain");
|
||||
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
|
||||
|
||||
if (!keepAlive) {
|
||||
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
} else {
|
||||
if (keepAlive && req.protocolVersion().equals(HttpVersion.HTTP_1_0)) {
|
||||
response.headers().set(CONNECTION, KEEP_ALIVE);
|
||||
ctx.write(response);
|
||||
} else {
|
||||
// Tell the client we're going to close the connection.
|
||||
response.headers().set(CONNECTION, CLOSE);
|
||||
}
|
||||
|
||||
ChannelFuture f = ctx.write(response);
|
||||
|
||||
if (!keepAlive) {
|
||||
f.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,8 +155,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
} catch (ErrorDataDecoderException e1) {
|
||||
e1.printStackTrace();
|
||||
responseContent.append(e1.getMessage());
|
||||
writeResponse(ctx.channel());
|
||||
ctx.channel().close();
|
||||
writeResponse(ctx.channel(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -180,8 +179,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
} catch (ErrorDataDecoderException e1) {
|
||||
e1.printStackTrace();
|
||||
responseContent.append(e1.getMessage());
|
||||
writeResponse(ctx.channel());
|
||||
ctx.channel().close();
|
||||
writeResponse(ctx.channel(), true);
|
||||
return;
|
||||
}
|
||||
responseContent.append('o');
|
||||
@ -307,24 +305,27 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
}
|
||||
|
||||
private void writeResponse(Channel channel) {
|
||||
writeResponse(channel, false);
|
||||
}
|
||||
|
||||
private void writeResponse(Channel channel, boolean forceClose) {
|
||||
// Convert the response content to a ChannelBuffer.
|
||||
ByteBuf buf = copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
|
||||
responseContent.setLength(0);
|
||||
|
||||
// Decide whether to close the connection or not.
|
||||
boolean close = request.headers().contains(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE, true)
|
||||
|| request.protocolVersion().equals(HttpVersion.HTTP_1_0)
|
||||
&& !request.headers().contains(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE, true);
|
||||
boolean keepAlive = HttpUtil.isKeepAlive(request) && !forceClose;
|
||||
|
||||
// Build the response object.
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
|
||||
|
||||
if (!close) {
|
||||
// There's no need to add 'Content-Length' header
|
||||
// if this is the last response.
|
||||
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
|
||||
if (!keepAlive) {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||
} else if (request.protocolVersion().equals(HttpVersion.HTTP_1_0)) {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
Set<Cookie> cookies;
|
||||
@ -343,7 +344,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
// Write the response.
|
||||
ChannelFuture future = channel.writeAndFlush(response);
|
||||
// Close the connection after the write operation is done if necessary.
|
||||
if (close) {
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
@ -428,8 +429,20 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
|
||||
|
||||
// Decide whether to close the connection or not.
|
||||
boolean keepAlive = HttpUtil.isKeepAlive(request);
|
||||
if (!keepAlive) {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||
} else if (request.protocolVersion().equals(HttpVersion.HTTP_1_0)) {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
ctx.channel().writeAndFlush(response);
|
||||
ChannelFuture future = ctx.channel().writeAndFlush(response);
|
||||
// Close the connection after the write operation is done if necessary.
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,7 +17,6 @@ package io.netty.example.http.websocketx.benchmarkserver;
|
||||
|
||||
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.SimpleChannelInboundHandler;
|
||||
@ -36,9 +35,16 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpMethod.*;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
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.OK;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_0;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
|
||||
/**
|
||||
* Handles handshakes and messages
|
||||
@ -137,9 +143,15 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<FullH
|
||||
ByteBuf content = WebSocketServerIndexPage.getContent(webSocketLocation);
|
||||
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
|
||||
|
||||
res.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
HttpUtil.setContentLength(res, content.readableBytes());
|
||||
|
||||
sendHttpResponse(ctx, req, res);
|
||||
@ -94,9 +98,15 @@ public class WebSocketIndexPageHandler extends SimpleChannelInboundHandler<FullH
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,11 @@ package io.netty.example.http2.helloworld.server;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
||||
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.HttpResponseStatus.CONTINUE;
|
||||
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;
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
|
||||
@ -32,7 +35,6 @@ import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
|
||||
/**
|
||||
* HTTP handler that responds with a "Hello World"
|
||||
@ -59,11 +61,15 @@ public class HelloWorldHttp1Handler extends SimpleChannelInboundHandler<FullHttp
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
|
||||
|
||||
if (!keepAlive) {
|
||||
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
} else {
|
||||
response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
if (keepAlive) {
|
||||
if (req.protocolVersion().equals(HTTP_1_0)) {
|
||||
response.headers().set(CONNECTION, KEEP_ALIVE);
|
||||
}
|
||||
ctx.write(response);
|
||||
} else {
|
||||
// Tell the client we're going to close the connection.
|
||||
response.headers().set(CONNECTION, CLOSE);
|
||||
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,11 @@
|
||||
package io.netty.example.http2.tiles;
|
||||
|
||||
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.HttpUtil.isKeepAlive;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_0;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@ -26,7 +29,6 @@ import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -51,9 +53,13 @@ public final class Http1RequestHandler extends Http2RequestHandler {
|
||||
@Override
|
||||
public void run() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -22,16 +22,22 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpUtil.*;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
||||
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.HttpResponseStatus.CONTINUE;
|
||||
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;
|
||||
import static io.netty.handler.codec.http.HttpUtil.is100ContinueExpected;
|
||||
import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
|
||||
|
||||
/**
|
||||
* HTTP handler that responds with a "Hello World"
|
||||
@ -51,14 +57,18 @@ public class SpdyServerHandler extends SimpleChannelInboundHandler<Object> {
|
||||
ByteBuf content = Unpooled.copiedBuffer("Hello World " + new Date(), CharsetUtil.UTF_8);
|
||||
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
|
||||
|
||||
if (!keepAlive) {
|
||||
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
} else {
|
||||
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
if (keepAlive) {
|
||||
if (req.protocolVersion().equals(HTTP_1_0)) {
|
||||
response.headers().set(CONNECTION, KEEP_ALIVE);
|
||||
}
|
||||
ctx.write(response);
|
||||
} else {
|
||||
// Tell the client we're going to close the connection.
|
||||
response.headers().set(CONNECTION, CLOSE);
|
||||
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user