Part of netty series: using netty to implement a server supporting http2

brief introduction

In the last article, we mentioned how to configure TLS in netty to support http2. In fact, TLS is not a mandatory requirement of https. It is just a recommended standard. In addition to TLS, how do I set up netty to support http2? Let's have a look.

Basic process

netty supports http2 in two cases. The first case is to use tls. In this case, you need to add a protocol negotiation handler to negotiate the protocol after the handshake. After negotiation, you need to decide which protocol to use.

In the last article, we introduced the details of TLS supporting http2. I won't repeat it here. Interested friends can check my previous articles.

If tls is not used, there are two situations. One is to directly use http1.1. We need to add a ChannelInboundHandler for http1.1.

Another case is to use clear text to upgrade from HTTP 1.1 to HTTP 2.

HTTP/2 ClearText is also called h2c. Let's look at a simple upgrade request. First, the client request:

GET /index HTTP/1.1
Host: server.flydean.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c 
HTTP2-Settings: (SETTINGS payload) 

Then there is the response from the server. If the server does not support upgrading, it returns:

HTTP/1.1 200 OK 
Content-length: 100
Content-type: text/html

(... HTTP/1.1 response ...)

If the server supports upgrade, return:

HTTP/1.1 101 Switching Protocols 
Connection: Upgrade
Upgrade: h2c

(... HTTP/2 response ...)

CleartextHttp2ServerUpgradeHandler

With the above basic process, we only need to provide the corresponding handler class in netty to solve the support of netty for http2.

However, the above upgrade process looks complex, so netty provides us with an encapsulated class: cleartexthttp2server upgradehandler to implement the functions of h2c.

This class needs to pass in three parameters: HttpServerCodec, HttpServerUpgradeHandler and ChannelHandler.

HttpServerCodec is a coding class that handles http server. Generally, we use HttpServerCodec.

HttpServerUpgradeHandler is a processing class upgraded from http1.1 to http2.

netty also provides a ready-made class: HttpServerUpgradeHandler to handle the upgraded coding.

HttpServerUpgradeHandler requires two parameters, one is sourceCodec, which is the original HTTP coding class HttpServerCodec, the other is the factory class used to return UpgradeCodec, and the http2server UpgradeCodec provided by netty.

    public HttpServerUpgradeHandler(SourceCodec sourceCodec, UpgradeCodecFactory upgradeCodecFactory) {
        this(sourceCodec, upgradeCodecFactory, 0);
    }

ChannelHandler is the handler that really handles HTTP2. We can customize this handler as needed.

With the UpgradeHandler, you can add it to the ChannelPipeline.

Http2ConnectionHandler

Whether HttpServerUpgradeHandler or cleartexthttp2server upgradehandler, you need to pass in a handler that can actually handle http2. This handler is Http2ConnectionHandler.

Http2ConnectionHandler is an implementation class. It has implemented the processing of various inbound frame events, and then delegate these events to Http2FrameListener.

Therefore, Http2ConnectionHandler needs to be used with Http2FrameListener.

Here we will explain in detail the Http2FrameListener, which mainly handles various events of the HTTP2 frame.

Let's take a look at the event trigger method provided in http2FrameListener:

As can be seen from the above figure, there are mainly event triggering methods for various frames, including the following frames in http2:

  • DATA frame
  • HEADERS frame
  • PRIORITY frame
  • RST_STREAM frame
  • SETTINGS acknowledgment frame
  • SETTINGS frame
  • PING frame
  • PING acknowledgment
  • PUSH_PROMISE frame
  • GO_AWAY frame
  • WINDOW_UPDATE frame
  • Unknown Frame

These frames basically list all types in the http2 frame.

All we need to do is customize a handler class, inherit Http2ConnectionHandler, and then implement the Http2FrameListener interface.

    public final class CustHttp2Handler extends Http2ConnectionHandler implements Http2FrameListener

In the process of upgrading from HTTP1.1 to http2 using clear text, we need to handle two things. The first thing is to upgrade HTTP1.1 to http2 using HTTP header. You can override the userEventTriggered method inherited from Http2ConnectionHandler and trigger the method in the corresponding Http2FrameListener interface by judging whether the event type is UpgradeEvent, For example, onHeadersRead here:

    /**
     * Handling HTTP upgrade events
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof HttpServerUpgradeHandler.UpgradeEvent) {
            HttpServerUpgradeHandler.UpgradeEvent upgradeEvent =
                    (HttpServerUpgradeHandler.UpgradeEvent) evt;
            onHeadersRead(ctx, 1, upgradeToHttp2Headers(upgradeEvent.upgradeRequest()), 0 , true);
        }
        super.userEventTriggered(ctx, evt);
    }

The upgradeToHttp2Headers method converts the incoming FullHttpRequest into Http2Headers:

    private static Http2Headers upgradeToHttp2Headers(FullHttpRequest request) {
        CharSequence host = request.headers().get(HttpHeaderNames.HOST);
        Http2Headers http2Headers = new DefaultHttp2Headers()
                .method(HttpMethod.GET.asciiName())
                .path(request.uri())
                .scheme(HttpScheme.HTTP.name());
        if (host != null) {
            http2Headers.authority(host);
        }
        return http2Headers;
    }

Another method to be implemented is the sendResponse method, which writes data back to the client. The writeback needs to include headers and data, as shown below:

    /**
     * Send response data to client
     */
    private void sendResponse(ChannelHandlerContext ctx, int streamId, ByteBuf payload) {
        Http2Headers headers = new DefaultHttp2Headers().status(OK.codeAsText());
        encoder().writeHeaders(ctx, streamId, headers, 0, false, ctx.newPromise());
        encoder().writeData(ctx, streamId, payload, 0, true, ctx.newPromise());
    }

summary

At this point, a handler that handles the upgrade of clear text from HTTP 1.1 to HTTP 2 is ready. With the support of TLS extension protocol explained earlier, a complete netty server supporting http2 is formed.

Examples of this article can be referred to: learn-netty4

This article has been included in http://www.flydean.com/27-netty-http2/

The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to find!

Welcome to my official account: "those things in procedure", understand technology, know you better!

Tags: Java http

Posted on Fri, 22 Oct 2021 01:40:52 -0400 by imderek