Skip to content

Commit

Permalink
Handle HTTP connections when the server does not have handler for the…
Browse files Browse the repository at this point in the history
… channel event loop, it happens when the server has accepted a connection and assigned an event loop but the all the handlers for this event loop have been removed, as the event loop is already assigned the channel cannot be processed - fixes #2291
  • Loading branch information
vietj committed Jan 29, 2018
1 parent 1d5239e commit ab4ce8a
Showing 1 changed file with 31 additions and 10 deletions.
41 changes: 31 additions & 10 deletions src/main/java/io/vertx/core/http/impl/HttpServerImpl.java
Expand Up @@ -86,6 +86,7 @@
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -276,12 +277,12 @@ protected void initChannel(Channel ch) throws Exception {
SslHandler sslHandler = pipeline.get(SslHandler.class); SslHandler sslHandler = pipeline.get(SslHandler.class);
String protocol = sslHandler.applicationProtocol(); String protocol = sslHandler.applicationProtocol();
if ("h2".equals(protocol)) { if ("h2".equals(protocol)) {
handleHttp2(pipeline.channel()); handleHttp2(ch);
} else { } else {
configureHttp1(pipeline); handleHttp1(ch);
} }
} else { } else {
configureHttp1(pipeline); handleHttp1(ch);
} }
} else { } else {
HandlerHolder<HttpHandlers> handler = httpHandlerMgr.chooseHandler(ch.eventLoop()); HandlerHolder<HttpHandlers> handler = httpHandlerMgr.chooseHandler(ch.eventLoop());
Expand All @@ -290,7 +291,7 @@ protected void initChannel(Channel ch) throws Exception {
}); });
} else { } else {
if (DISABLE_HC2) { if (DISABLE_HC2) {
configureHttp1(pipeline); handleHttp1(ch);
} else { } else {
IdleStateHandler idle; IdleStateHandler idle;
if (options.getIdleTimeout() > 0) { if (options.getIdleTimeout() > 0) {
Expand All @@ -311,7 +312,7 @@ protected void configure(ChannelHandlerContext ctx, boolean h2c) {
if (h2c) { if (h2c) {
handleHttp2(ctx.channel()); handleHttp2(ctx.channel());
} else { } else {
configureHttp1(ctx.pipeline()); handleHttp1(ch);
} }
} }


Expand Down Expand Up @@ -423,7 +424,7 @@ private VertxHttp2ConnectionHandler<Http2ServerConnection> setHandler(HandlerHol
return handler; return handler;
} }


private void configureHttp1(ChannelPipeline pipeline) { private void configureHttp1(ChannelPipeline pipeline, HandlerHolder<HttpHandlers> holder) {
if (logEnabled) { if (logEnabled) {
pipeline.addLast("logging", new LoggingHandler()); pipeline.addLast("logging", new LoggingHandler());
} }
Expand All @@ -449,7 +450,6 @@ private void configureHttp1(ChannelPipeline pipeline) {
if (!DISABLE_HC2) { if (!DISABLE_HC2) {
pipeline.addLast("h2c", new Http2UpgradeHandler()); pipeline.addLast("h2c", new Http2UpgradeHandler());
} }
HandlerHolder<HttpHandlers> holder = httpHandlerMgr.chooseHandler(pipeline.channel().eventLoop());
Http1xServerHandler handler; Http1xServerHandler handler;
if (DISABLE_WEBSOCKETS) { if (DISABLE_WEBSOCKETS) {
// As a performance optimisation you can set a system property to disable websockets altogether which avoids // As a performance optimisation you can set a system property to disable websockets altogether which avoids
Expand All @@ -467,13 +467,34 @@ private void configureHttp1(ChannelPipeline pipeline) {
pipeline.addLast("handler", handler); pipeline.addLast("handler", handler);
} }


public void handleHttp2(Channel ch) { private void handleHttp1(Channel ch) {
HandlerHolder<HttpHandlers> holder = httpHandlerMgr.chooseHandler(ch.eventLoop()); HandlerHolder<HttpHandlers> holder = httpHandlerMgr.chooseHandler(ch.eventLoop());
if (holder == null) {
sendServiceUnavailable(ch);
return;
}
configureHttp1(ch.pipeline(), holder);
}

private void sendServiceUnavailable(Channel ch) {
ch.writeAndFlush(
Unpooled.copiedBuffer("HTTP/1.1 503 Service Unavailable\r\n" +
"Content-Length:0\r\n" +
"\r\n", StandardCharsets.ISO_8859_1))
.addListener(ChannelFutureListener.CLOSE);
}

private void handleHttp2(Channel ch) {
HandlerHolder<HttpHandlers> holder = httpHandlerMgr.chooseHandler(ch.eventLoop());
if (holder == null) {
ch.close();
return;
}
configureHttp2(ch.pipeline()); configureHttp2(ch.pipeline());
setHandler(holder, null, ch); setHandler(holder, null, ch);
} }


public void configureHttp2(ChannelPipeline pipeline) { private void configureHttp2(ChannelPipeline pipeline) {
if (options.getIdleTimeout() > 0) { if (options.getIdleTimeout() > 0) {
pipeline.addLast("idle", new IdleStateHandler(0, 0, options.getIdleTimeout())); pipeline.addLast("idle", new IdleStateHandler(0, 0, options.getIdleTimeout()));
} }
Expand Down Expand Up @@ -934,7 +955,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
} else if (msg instanceof LastHttpContent) { } else if (msg instanceof LastHttpContent) {
if (settings != null) { if (settings != null) {
HandlerHolder<HttpHandlers> reqHandler = httpHandlerMgr.chooseHandler(ctx.channel().eventLoop()); HandlerHolder<HttpHandlers> reqHandler = httpHandlerMgr.chooseHandler(ctx.channel().eventLoop());
if (reqHandler.context.isEventLoopContext()) { if (reqHandler != null && reqHandler.context.isEventLoopContext()) {
ChannelPipeline pipeline = ctx.pipeline(); ChannelPipeline pipeline = ctx.pipeline();
DefaultFullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, SWITCHING_PROTOCOLS, Unpooled.EMPTY_BUFFER, false); DefaultFullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, SWITCHING_PROTOCOLS, Unpooled.EMPTY_BUFFER, false);
res.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE); res.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE);
Expand Down

0 comments on commit ab4ce8a

Please sign in to comment.