Categories
Uncategorized

Detailed http packets (2) How -web container is resolved http messages

Summary

Detailed http packets in an article detailing the structure of the text http packets. So as a server, web container is how to parse the http packets it? In this paper, jetty and undertow container, for example, to resolve how to deal with web container is http packets.

In the foregoing, we can learn from the overview, the message is actually a string http certain rules, then parse them, it is to parse the string to see if it meets the rules http agreement.

start-line: 起始行,描述请求或响应的基本信息

*( header-field CRLF ): 头

CRLF

[message-body]: 消息body,实际传输的数据

jetty

The following codes are jetty9.4.12 version

How to resolve such a long string of it, jetty by a state machine to achieve. Specific classes look org.eclipse.jetty.http.HttpParse

 public enum State
    {
        START,
        METHOD,
        
![](https://img2018.cnblogs.com/blog/1147363/201910/1147363-20191009220439773-204646534.png),
        SPACE1,
        STATUS,
        URI,
        SPACE2,
        REQUEST_VERSION,
        REASON,
        PROXY,
        HEADER,
        CONTENT,
        EOF_CONTENT,
        CHUNKED_CONTENT,
        CHUNK_SIZE,
        CHUNK_PARAMS,
        CHUNK,
        TRAILER,
        END,
        CLOSE,  // The associated stream/endpoint should be closed
        CLOSED  // The associated stream/endpoint is at EOF
    }

Divided into a total of 21 states, and then transfer between states. Each row in the starting process parseNext -> header -> body content resolves

public boolean parseNext(ByteBuffer buffer)
    {
        try
        {
            // Start a request/response
            if (_state==State.START)
            {
                // 快速判断
                if (quickStart(buffer))
                    return true;
            }

            // Request/response line 转换
            if (_state.ordinal()>= State.START.ordinal() && _state.ordinal()= State.CONTENT.ordinal() && _state.ordinal()0 && _headResponse)
                {
                    setState(State.END);
                    return handleContentMessage();
                }
                else
                {
                    if (parseContent(buffer))
                        return true;
                }
            }
         
        return false;
    }

Overall process

There are three paths overall

    Start -> start-line -> header -> End

    Start -> start-line -> header -> content -> end

  1. 开始 -> start-line -> header -> chunk-content -> 结束

Start line

start-line = request-line (request start line) / (the response start line) status-line

  1. State transition request message parsing
                Request line: START -> METHOD -> SPACE1 -> URI -> SPACE2 -> REQUEST_VERSION

  2. Response message parsing state migration
                Response line: START -> RESPONSE_VERSION -> SPACE1 -> STATUS -> SPACE2 -> REASON

header header

HEADER_IN_NAM, HEADER_VALUE, HEADER_IN_VALUE, HEADER_IN_VALUE, etc. were removed from 9.4. To improve matching efficiency, jetty uses Trie tree to quickly match header headers.

static
    {
        CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE));
        CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE));
      // 以下省略了很多了通用header头

content

Request body:

    CONTENT -> END, this is an ordinary packet with ContentLength head, HttpParser been running CONTENT state, until finally ContentLength reached the specified number, then enter the state END

  1. chunked分块传输的数据
    CHUNKED_CONTENT -> CHUNK_SIZE -> CHUNK -> CHUNK_END -> END

undertow

undertow is another web container, how is it handled differently from jetty?
State machine type is not the same, io.Undertow.util.httpString.Parsestate

    public static final int VERB = 0;
    public static final int PATH = 1;
    public static final int PATH_PARAMETERS = 2;
    public static final int QUERY_PARAMETERS = 3;
    public static final int VERSION = 4;
    public static final int AFTER_VERSION = 5;
    public static final int HEADER = 6;
    public static final int HEADER_VALUE = 7;
    public static final int PARSE_COMPLETE = 8;

Specific process flow in the abstract class HttpRequestParser

public void handle(ByteBuffer buffer, final ParseState currentState, final HttpServerExchange builder) throws BadRequestException {
        if (currentState.state == ParseState.VERB) {
            //fast path, we assume that it will parse fully so we avoid all the if statements

            // 快速处理GET
            final int position = buffer.position();
            if (buffer.remaining() > 3
                    && buffer.get(position) == 'G'
                    && buffer.get(position + 1) == 'E'
                    && buffer.get(position + 2) == 'T'
                    && buffer.get(position + 3) == ' ') {
                buffer.position(position + 4);
                builder.setRequestMethod(Methods.GET);
                currentState.state = ParseState.PATH;
            } else {
                try {
                    handleHttpVerb(buffer, currentState, builder);
                } catch (IllegalArgumentException e) {
                    throw new BadRequestException(e);
                }
            }
            // 处理path
            handlePath(buffer, currentState, builder);
           // 处理版本
            if (failed) {
                handleHttpVersion(buffer, currentState, builder);
                handleAfterVersion(buffer, currentState);
            }
            // 处理header
            while (currentState.state != ParseState.PARSE_COMPLETE && buffer.hasRemaining()) {
                handleHeader(buffer, currentState, builder);
                if (currentState.state == ParseState.HEADER_VALUE) {
                    handleHeaderValue(buffer, currentState, builder);
                }
            }
            return;
        }
        handleStateful(buffer, currentState, builder);
    }

Unlike jetty is the processing of content, after the header processing, put the data to io.undertow.server.httpserverexchange, and then depending on the type, there are different ways of reading content, such as handling fixed length FixedlengthStreamSourceConduit.

关注公众号【方丈的寺院】,第一时间收到文章的更新,与方丈一起开始技术修行之路

reference

http://www.blogjava.net/DLevin/archive/2014/04/19/411673.html

https://www.ph0ly.com/2018/10/06/jetty/connection/http-parser/

HTTP Trailers in Jetty

http://undertow.io/undertow-docs/undertow-docs-2.0.0/

Leave a Reply