// Bind and start the server ChannelFuturefuture= bootstrap.bind(8080).sync(); System.out.println("Server started and listening on port 8080");
// Wait until the server socket is closed future.channel().closeFuture().sync(); } finally { // Shut down the event loop groups bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }
if (!handlingUpgrade) { // Not handling an upgrade request yet. Check if we received a new upgrade request. if (msg instanceof HttpRequest) { HttpRequestreq= (HttpRequest) msg; if (req.headers().contains(HttpHeaderNames.UPGRADE) && shouldHandleUpgradeRequest(req)) { handlingUpgrade = true; } else { ReferenceCountUtil.retain(msg); ctx.fireChannelRead(msg); return; } } else { ReferenceCountUtil.retain(msg); ctx.fireChannelRead(msg); return; } }
FullHttpRequest fullRequest; if (msg instanceof FullHttpRequest) { fullRequest = (FullHttpRequest) msg; ReferenceCountUtil.retain(msg); out.add(msg); } else { // Call the base class to handle the aggregation of the full request. super.decode(ctx, msg, out); if (out.isEmpty()) { // The full request hasn't been created yet, still awaiting more data. return; }
// Finished aggregating the full request, get it from the output list. assert out.size() == 1; handlingUpgrade = false; fullRequest = (FullHttpRequest) out.get(0); }
if (upgrade(ctx, fullRequest)) { // The upgrade was successful, remove the message from the output list // so that it's not propagated to the next handler. This request will // be propagated as a user event instead. out.clear(); }
// The upgrade did not succeed, just allow the full request to propagate to the // next handler. }
privatebooleanupgrade(final ChannelHandlerContext ctx, final FullHttpRequest request) { // Select the best protocol based on those requested in the UPGRADE header. final List<CharSequence> requestedProtocols = splitHeader(request.headers().get(HttpHeaderNames.UPGRADE)); finalintnumRequestedProtocols= requestedProtocols.size(); UpgradeCodecupgradeCodec=null; CharSequenceupgradeProtocol=null; for (inti=0; i < numRequestedProtocols; i ++) { finalCharSequencep= requestedProtocols.get(i); finalUpgradeCodecc= upgradeCodecFactory.newUpgradeCodec(p); if (c != null) { upgradeProtocol = p; upgradeCodec = c; break; } }
if (upgradeCodec == null) { // None of the requested protocols are supported, don't upgrade. returnfalse; }
// Make sure the CONNECTION header is present. List<String> connectionHeaderValues = request.headers().getAll(HttpHeaderNames.CONNECTION);
if (connectionHeaderValues == null || connectionHeaderValues.isEmpty()) { returnfalse; }
// Make sure the CONNECTION header contains UPGRADE as well as all protocol-specific headers. Collection<CharSequence> requiredHeaders = upgradeCodec.requiredUpgradeHeaders(); List<CharSequence> values = splitHeader(concatenatedConnectionValue); if (!containsContentEqualsIgnoreCase(values, HttpHeaderNames.UPGRADE) || !containsAllContentEqualsIgnoreCase(values, requiredHeaders)) { returnfalse; }
// Ensure that all required protocol-specific headers are found in the request. for (CharSequence requiredHeader : requiredHeaders) { if (!request.headers().contains(requiredHeader)) { returnfalse; } }
// Prepare and send the upgrade response. Wait for this write to complete before upgrading, // since we need the old codec in-place to properly encode the response. finalFullHttpResponseupgradeResponse= createUpgradeResponse(upgradeProtocol); if (!upgradeCodec.prepareUpgradeResponse(ctx, request, upgradeResponse.headers())) { returnfalse; }
// Create the user event to be fired once the upgrade completes. finalUpgradeEventevent=newUpgradeEvent(upgradeProtocol, request);
// After writing the upgrade response we immediately prepare the // pipeline for the next protocol to avoid a race between completion // of the write future and receiving data before the pipeline is // restructured. try { finalChannelFuturewriteComplete= ctx.writeAndFlush(upgradeResponse); // Perform the upgrade to the new protocol. sourceCodec.upgradeFrom(ctx); upgradeCodec.upgradeTo(ctx, request);
// Remove this handler from the pipeline. ctx.pipeline().remove(HttpServerUpgradeHandler.this);
// Notify that the upgrade has occurred. Retain the event to offset // the release() in the finally block. ctx.fireUserEventTriggered(event.retain());
// Add the listener last to avoid firing upgrade logic after // the channel is already closed since the listener may fire // immediately if the write failed eagerly. writeComplete.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); } finally { // Release the event if the upgrade event wasn't fired. event.release(); } returntrue; }