private boolean upgrade(ChannelHandlerContext ctx, HttpRequest request) {
        // Select the best protocol based on those requested in the UPGRADE header.
        final List<String> requestedProtocols =
                COMMA_SPLITTER.splitToList(request.headers().get(HttpHeaderNames.UPGRADE));
        final int numRequestedProtocols = requestedProtocols.size();
        for (int i = 0; i < numRequestedProtocols; i++) {
            final CharSequence protocol = requestedProtocols.get(i);
            if (!AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {
                continue;
            }
            upgradeCodec = upgradeCodecFactory.newUpgradeCodec();
            break;
        }

        if (upgradeCodec == null) {
            // None of the requested protocols are supported, don't upgrade.
            return false;
        }

        // Make sure the CONNECTION header is present.
        final List<String> connectionHeaderValues = request.headers().getAll(HttpHeaderNames.CONNECTION);

        if (connectionHeaderValues == null || connectionHeaderValues.isEmpty()) {
            return false;
        }

        final List<CharSequence> values = connectionHeaderValues.stream()
                                                                .flatMap(COMMA_SPLITTER::splitToStream)
                                                                .collect(toImmutableList());
        // Make sure the CONNECTION header contains UPGRADE as well as all protocol-specific headers.
        if (!(containsContentEqualsIgnoreCase(values, HttpHeaderNames.UPGRADE) &&
              containsContentEqualsIgnoreCase(values, Http2CodecUtil.HTTP_UPGRADE_SETTINGS_HEADER))) {
            return false;
        }

        // Ensure that HTTP2-Settings headers are found in the request.
        if (!request.headers().contains(Http2CodecUtil.HTTP_UPGRADE_SETTINGS_HEADER)) {
            return false;
        }

        // 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.
        if (!upgradeCodec.prepareUpgradeResponse(ctx, request)) {
            ctx.writeAndFlush(invalidSettingsHeaderResponse.duplicate()).addListener(CLOSE);
            handlingInvalidSettingsHeader = true;
            return false;
        }

        // Create the user event to be fired once the upgrade completes.
        final UpgradeEvent event = new UpgradeEvent(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 {
            final ChannelFuture writeComplete = ctx.writeAndFlush(UPGRADE_RESPONSE.retain());

            // The request could not be fully received yet.
            // The HTTP/1 codec will be completely removed after receiving the entire request.
            sourceCodec.removeOutboundHandler();

            // Perform the upgrade to the new protocol.
            assert upgradeCodec != null;
            upgradeCodec.upgradeTo(ctx);

            // 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(CLOSE_ON_FAILURE);
        } finally {
            // Release the event if the upgrade event wasn't fired.
            event.release();
        }
        return true;
    }
Attempts to upgrade to the protocol(s) identified by the {@link HttpHeaderNames#UPGRADE} header
(if provided in the request).

@param ctx the context for this handler.
@param request the HTTP request.
@return {@code true} if the upgrade occurred, otherwise {@code false}.
core/src/main/java/com/linecorp/armeria/server/HttpServerUpgradeHandler.java