Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, Home of Professional Open Source.
   * Copyright 2014 Red Hat, Inc., and individual contributors
   * as indicated by the @author tags.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
 
 package io.undertow.server.protocol.http;
 
 import java.util.Map;
 
 import  io.undertow.annotationprocessor.HttpParserConfig;
 
 import static io.undertow.util.Headers.ACCEPT_CHARSET_STRING;
 import static io.undertow.util.Headers.ACCEPT_ENCODING_STRING;
 import static io.undertow.util.Headers.ACCEPT_LANGUAGE_STRING;
 import static io.undertow.util.Headers.ACCEPT_RANGES_STRING;
 import static io.undertow.util.Headers.ACCEPT_STRING;
 import static io.undertow.util.Headers.AUTHORIZATION_STRING;
 import static io.undertow.util.Headers.CACHE_CONTROL_STRING;
 import static io.undertow.util.Headers.CONNECTION_STRING;
 import static io.undertow.util.Headers.CONTENT_LENGTH_STRING;
 import static io.undertow.util.Headers.CONTENT_TYPE_STRING;
 import static io.undertow.util.Headers.COOKIE_STRING;
 import static io.undertow.util.Headers.EXPECT_STRING;
 import static io.undertow.util.Headers.FROM_STRING;
 import static io.undertow.util.Headers.HOST_STRING;
 import static io.undertow.util.Headers.IF_MATCH_STRING;
 import static io.undertow.util.Headers.IF_MODIFIED_SINCE_STRING;
 import static io.undertow.util.Headers.IF_NONE_MATCH_STRING;
 import static io.undertow.util.Headers.IF_RANGE_STRING;
 import static io.undertow.util.Headers.IF_UNMODIFIED_SINCE_STRING;
 import static io.undertow.util.Headers.MAX_FORWARDS_STRING;
 import static io.undertow.util.Headers.ORIGIN_STRING;
 import static io.undertow.util.Headers.PRAGMA_STRING;
 import static io.undertow.util.Headers.PROXY_AUTHORIZATION_STRING;
 import static io.undertow.util.Headers.RANGE_STRING;
 import static io.undertow.util.Headers.REFERER_STRING;
 import static io.undertow.util.Headers.REFRESH_STRING;
 import static io.undertow.util.Headers.SEC_WEB_SOCKET_KEY_STRING;
 import static io.undertow.util.Headers.SEC_WEB_SOCKET_VERSION_STRING;
 import static io.undertow.util.Headers.SERVER_STRING;
 import static io.undertow.util.Headers.SSL_CIPHER_STRING;
 import static io.undertow.util.Headers.SSL_CIPHER_USEKEYSIZE_STRING;
 import static io.undertow.util.Headers.SSL_CLIENT_CERT_STRING;
 import static io.undertow.util.Headers.SSL_SESSION_ID_STRING;
 import static io.undertow.util.Headers.STRICT_TRANSPORT_SECURITY_STRING;
 import static io.undertow.util.Headers.TRAILER_STRING;
 import static io.undertow.util.Headers.TRANSFER_ENCODING_STRING;
 import static io.undertow.util.Headers.UPGRADE_STRING;
 import static io.undertow.util.Headers.USER_AGENT_STRING;
 import static io.undertow.util.Headers.VIA_STRING;
 import static io.undertow.util.Headers.WARNING_STRING;
 import static io.undertow.util.Methods.CONNECT_STRING;
 import static io.undertow.util.Methods.DELETE_STRING;
 import static io.undertow.util.Methods.GET_STRING;
 import static io.undertow.util.Methods.HEAD_STRING;
 import static io.undertow.util.Methods.OPTIONS_STRING;
 import static io.undertow.util.Methods.POST_STRING;
 import static io.undertow.util.Methods.PUT_STRING;
 import static io.undertow.util.Methods.TRACE_STRING;
 import static io.undertow.util.Protocols.HTTP_0_9_STRING;
 import static io.undertow.util.Protocols.HTTP_1_0_STRING;
 import static io.undertow.util.Protocols.HTTP_1_1_STRING;

The basic HTTP parser. The actual parser is a sub class of this class that is generated as part of the build process by the io.undertow.annotationprocessor.AbstractParserGenerator annotation processor.

The actual processor is a state machine, that means that for common header, method, protocol values it will return an interned string, rather than creating a new string for each one.

Author(s):
Stuart Douglas
@HttpParserConfig(methods = {
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        },
        protocols = {
                
        },
        headers = {
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                ,
                
        })
public abstract class HttpRequestParser {
    private static final byte[] HTTP;
    public static final int HTTP_LENGTH;
    private final int maxParameters;
    private final int maxHeaders;
    private final boolean allowEncodedSlash;
    private final boolean decode;
    private final String charset;
    static {
        try {
             = "HTTP/1.".getBytes("ASCII");
             = .;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    public HttpRequestParser(OptionMap options) {
         = options.get(., 1000);
         = options.get(., 200);
         = options.get(.false);
         = options.get(.true);
         = options.get(."UTF-8");
    }
    public static final HttpRequestParser instance(final OptionMap options) {
        try {
            final Class<?> cls = Class.forName(HttpRequestParser.class.getName() + "$$generated"falseHttpRequestParser.class.getClassLoader());
            Constructor<?> ctor = cls.getConstructor(OptionMap.class);
            return (HttpRequestParserctor.newInstance(options);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public void handle(ByteBuffer bufferfinal ParseState currentStatefinal HttpServerExchange builder) {
        if (currentState.state == .) {
            //fast path, we assume that it will parse fully so we avoid all the if statements
            //fast path HTTP GET requests, basically just assume all requests are get
            //and fall out to the state machine if it is not
            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(.);
                currentState.state = .;
            } else {
                handleHttpVerb(buffercurrentStatebuilder);
            }
            handlePath(buffercurrentStatebuilder);
            boolean failed = false;
            if (buffer.remaining() >  + 3) {
                int pos = buffer.position();
                for (int i = 0; i < ; ++i) {
                    if ([i] != buffer.get(pos + i)) {
                        failed = true;
                        break;
                    }
                }
                if (!failed) {
                    final byte b = buffer.get(pos + );
                    final byte b2 = buffer.get(pos +  + 1);
                    final byte b3 = buffer.get(pos +  + 2);
                    if (b2 == '\r' && b3 == '\n') {
                        if (b == '1') {
                            builder.setProtocol(.);
                            buffer.position(pos +  + 3);
                            currentState.state = .;
                        } else if (b == '0') {
                            builder.setProtocol(.);
                            buffer.position(pos +  + 3);
                            currentState.state = .;
                        } else {
                            failed = true;
                        }
                    } else {
                        failed = true;
                    }
                }
            } else {
                failed = true;
            }
            if (failed) {
                handleHttpVersion(buffercurrentStatebuilder);
                handleAfterVersion(buffercurrentState);
            }
            while (currentState.state != . && buffer.hasRemaining()) {
                handleHeader(buffercurrentStatebuilder);
                if (currentState.state == .) {
                    handleHeaderValue(buffercurrentStatebuilder);
                }
            }
            return;
        }
        handleStateful(buffercurrentStatebuilder);
    }
    private void handleStateful(ByteBuffer bufferParseState currentStateHttpServerExchange builder) {
        if (currentState.state == .) {
            handlePath(buffercurrentStatebuilder);
            if (!buffer.hasRemaining()) {
                return;
            }
        }
        if (currentState.state == .) {
            handleQueryParameters(buffercurrentStatebuilder);
            if (!buffer.hasRemaining()) {
                return;
            }
        }
        if (currentState.state == .) {
            handlePathParameters(buffercurrentStatebuilder);
            if (!buffer.hasRemaining()) {
                return;
            }
        }
        if (currentState.state == .) {
            handleHttpVersion(buffercurrentStatebuilder);
            if (!buffer.hasRemaining()) {
                return;
            }
        }
        if (currentState.state == .) {
            handleAfterVersion(buffercurrentState);
            if (!buffer.hasRemaining()) {
                return;
            }
        }
        while (currentState.state != .) {
            if (currentState.state == .) {
                handleHeader(buffercurrentStatebuilder);
                if (!buffer.hasRemaining()) {
                    return;
                }
            }
            if (currentState.state == .) {
                handleHeaderValue(buffercurrentStatebuilder);
                if (!buffer.hasRemaining()) {
                    return;
                }
            }
        }
    }
    abstract void handleHttpVerb(ByteBuffer bufferfinal ParseState currentStatefinal HttpServerExchange builder);
    abstract void handleHttpVersion(ByteBuffer bufferfinal ParseState currentStatefinal HttpServerExchange builder);
    abstract void handleHeader(ByteBuffer bufferfinal ParseState currentStatefinal HttpServerExchange builder);

    
The parse states for parsing the path.
    private static final int START = 0;
    private static final int FIRST_COLON = 1;
    private static final int FIRST_SLASH = 2;
    private static final int SECOND_SLASH = 3;
    private static final int IN_PATH = 4;
    private static final int HOST_DONE = 5;

    
Parses a path value

Parameters:
buffer The buffer
state The current state
exchange The exchange builder
Returns:
The number of bytes remaining
    @SuppressWarnings("unused")
    final void handlePath(ByteBuffer bufferParseState stateHttpServerExchange exchange) {
        StringBuilder stringBuilder = state.stringBuilder;
        int parseState = state.parseState;
        int canonicalPathStart = state.pos;
        boolean urlDecodeRequired = state.urlDecodeRequired;
        while (buffer.hasRemaining()) {
            char next = (char) (buffer.get() & 0xFF);
            if (next == ' ' || next == '\t') {
                if (stringBuilder.length() != 0) {
                    final String path = stringBuilder.toString();
                    if (parseState < ) {
                        String decodedPath = decode(pathurlDecodeRequiredstate);
                        exchange.setRequestPath(decodedPath);
                        exchange.setRelativePath(decodedPath);
                        exchange.setRequestURI(path);
                    } else {
                        handleFullUrl(stateexchangecanonicalPathStarturlDecodeRequiredpath);
                    }
                    exchange.setQueryString("");
                    state.state = .;
                    state.stringBuilder.setLength(0);
                    state.parseState = 0;
                    state.pos = 0;
                    state.urlDecodeRequired = false;
                    return;
                }
            } else if (next == '\r' || next == '\n') {
                throw ..failedToParsePath();
            } else if (next == '?' && (parseState ==  || parseState ==  || parseState == )) {
                beginQueryParameters(bufferstateexchangestringBuilderparseStatecanonicalPathStarturlDecodeRequired);
                return;
            } else if (next == ';' && (parseState ==  || parseState ==  || parseState == )) {
                beginPathParameters(stateexchangestringBuilderparseStatecanonicalPathStarturlDecodeRequired);
                handlePathParameters(bufferstateexchange);
                return;
            } else {
                if ( && (next == '+' || next == '%' || next > 127)) {
                    urlDecodeRequired = true;
                } else if (next == ':' && parseState == ) {
                    parseState = ;
                } else if (next == '/' && parseState == ) {
                    parseState = ;
                } else if (next == '/' && parseState == ) {
                    parseState = ;
                } else if (next == '/' && parseState == ) {
                    parseState = ;
                    canonicalPathStart = stringBuilder.length();
                } else if (parseState ==  || parseState == ) {
                    parseState = ;
                } else if (next == '/' && parseState != ) {
                    parseState = ;
                }
                stringBuilder.append(next);
            }
        }
        state.parseState = parseState;
        state.pos = canonicalPathStart;
        state.urlDecodeRequired = urlDecodeRequired;
    }
    private void beginPathParameters(ParseState stateHttpServerExchange exchangeStringBuilder stringBuilderint parseStateint canonicalPathStartboolean urlDecodeRequired) {
        final String path = stringBuilder.toString();
        if (parseState < ) {
            String decodedPath = decode(pathurlDecodeRequiredstate);
            exchange.setRequestPath(decodedPath);
            exchange.setRelativePath(decodedPath);
            exchange.setRequestURI(path);
        } else {
            String thePath = path.substring(canonicalPathStart);
            exchange.setRequestPath(thePath);
            exchange.setRelativePath(thePath);
            exchange.setRequestURI(pathtrue);
        }
        state.state = .;
        state.stringBuilder.setLength(0);
        state.parseState = 0;
        state.pos = 0;
        state.urlDecodeRequired = false;
    }
    private void beginQueryParameters(ByteBuffer bufferParseState stateHttpServerExchange exchangeStringBuilder stringBuilderint parseStateint canonicalPathStartboolean urlDecodeRequired) {
        final String path = stringBuilder.toString();
        if (parseState < ) {
            String decodedPath = decode(pathurlDecodeRequiredstate);
            exchange.setRequestPath(decodedPath);
            exchange.setRelativePath(decodedPath);
            exchange.setRequestURI(pathfalse);
        } else {
            handleFullUrl(stateexchangecanonicalPathStarturlDecodeRequiredpath);
        }
        state.state = .;
        state.stringBuilder.setLength(0);
        state.parseState = 0;
        state.pos = 0;
        state.urlDecodeRequired = false;
        handleQueryParameters(bufferstateexchange);
    }
    private void handleFullUrl(ParseState stateHttpServerExchange exchangeint canonicalPathStartboolean urlDecodeRequiredString path) {
        String thePath = decode(path.substring(canonicalPathStart), urlDecodeRequiredstate);
        exchange.setRequestPath(thePath);
        exchange.setRelativePath(thePath);
        exchange.setRequestURI(pathtrue);
    }


    
Parses a path value

Parameters:
buffer The buffer
state The current state
exchange The exchange builder
Returns:
The number of bytes remaining
    @SuppressWarnings("unused")
    final void handleQueryParameters(ByteBuffer bufferParseState stateHttpServerExchange exchange) {
        StringBuilder stringBuilder = state.stringBuilder;
        int queryParamPos = state.pos;
        int mapCount = state.mapCount;
        boolean urlDecodeRequired = state.urlDecodeRequired;
        String nextQueryParam = state.nextQueryParam;
        //so this is a bit funky, because it not only deals with parsing, but
        //also deals with URL decoding the query parameters as well, while also
        //maintaining a non-decoded version to use as the query string
        //In most cases these string will be the same, and as we do not want to
        //build up two separate strings we don't use encodedStringBuilder unless
        //we encounter an encoded character
        while (buffer.hasRemaining()) {
            char next = (char) (buffer.get() & 0xFF);
            if (next == ' ' || next == '\t') {
                final String queryString = stringBuilder.toString();
                exchange.setQueryString(queryString);
                if (nextQueryParam == null) {
                    if (queryParamPos != stringBuilder.length()) {
                        exchange.addQueryParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue), "");
                    }
                } else {
                    exchange.addQueryParam(nextQueryParamdecode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue));
                }
                state.state = .;
                state.stringBuilder.setLength(0);
                state.pos = 0;
                state.nextQueryParam = null;
                state.urlDecodeRequired = false;
                state.mapCount = 0;
                return;
            } else if (next == '\r' || next == '\n') {
                throw ..failedToParsePath();
            } else {
                if ( && (next == '+' || next == '%' || next > 127)) {
                    urlDecodeRequired = true;
                } else if (next == '=' && nextQueryParam == null) {
                    nextQueryParam = decode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue);
                    urlDecodeRequired = false;
                    queryParamPos = stringBuilder.length() + 1;
                } else if (next == '&' && nextQueryParam == null) {
                    if (mapCount++ > ) {
                        throw ..tooManyQueryParameters();
                    }
                    if (queryParamPos != stringBuilder.length()) {
                        exchange.addQueryParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue), "");
                    }
                    urlDecodeRequired = false;
                    queryParamPos = stringBuilder.length() + 1;
                } else if (next == '&') {
                    if (mapCount++ > ) {
                        throw ..tooManyQueryParameters();
                    }
                    exchange.addQueryParam(nextQueryParamdecode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue));
                    urlDecodeRequired = false;
                    queryParamPos = stringBuilder.length() + 1;
                    nextQueryParam = null;
                }
                stringBuilder.append(next);
            }
        }
        state.pos = queryParamPos;
        state.nextQueryParam = nextQueryParam;
        state.urlDecodeRequired = urlDecodeRequired;
        state.mapCount = 0;
    }
    private String decode(final String valueboolean urlDecodeRequiredParseState statefinal boolean allowEncodedSlash) {
        if (urlDecodeRequired) {
            return URLUtils.decode(valueallowEncodedSlashstate.decodeBuffer);
        } else {
            return value;
        }
    }
    final void handlePathParameters(ByteBuffer bufferParseState stateHttpServerExchange exchange) {
        StringBuilder stringBuilder = state.stringBuilder;
        int queryParamPos = state.pos;
        int mapCount = state.mapCount;
        boolean urlDecodeRequired = state.urlDecodeRequired;
        String nextQueryParam = state.nextQueryParam;
        //so this is a bit funky, because it not only deals with parsing, but
        //also deals with URL decoding the query parameters as well, while also
        //maintaining a non-decoded version to use as the query string
        //In most cases these string will be the same, and as we do not want to
        //build up two separate strings we don't use encodedStringBuilder unless
        //we encounter an encoded character
        while (buffer.hasRemaining()) {
            char next = (char) (buffer.get() & 0xFF);
            if (next == ' ' || next == '\t' || next == '?') {
                if (nextQueryParam == null) {
                    if (queryParamPos != stringBuilder.length()) {
                        exchange.addPathParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue), "");
                    }
                } else {
                    exchange.addPathParam(nextQueryParamdecode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue));
                }
                exchange.setRequestURI(exchange.getRequestURI() + ';' + stringBuilder.toString(), state.parseState > );
                state.stringBuilder.setLength(0);
                state.pos = 0;
                state.nextQueryParam = null;
                state.mapCount = 0;
                state.urlDecodeRequired = false;
                if (next == '?') {
                    state.state = .;
                    handleQueryParameters(bufferstateexchange);
                } else {
                    state.state = .;
                }
                return;
            } else if (next == '\r' || next == '\n') {
                throw ..failedToParsePath();
            } else {
                if ( && (next == '+' || next == '%' || next > 127)) {
                    urlDecodeRequired = true;
                }
                if (next == '=' && nextQueryParam == null) {
                    nextQueryParam = decode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue);
                    urlDecodeRequired = false;
                    queryParamPos = stringBuilder.length() + 1;
                } else if (next == '&' && nextQueryParam == null) {
                    if (mapCount++ > ) {
                        throw ..tooManyQueryParameters();
                    }
                    exchange.addPathParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue), "");
                    urlDecodeRequired = false;
                    queryParamPos = stringBuilder.length() + 1;
                } else if (next == '&') {
                    if (mapCount++ > ) {
                        throw ..tooManyQueryParameters();
                    }
                    exchange.addPathParam(nextQueryParamdecode(stringBuilder.substring(queryParamPos), urlDecodeRequiredstatetrue));
                    urlDecodeRequired = false;
                    queryParamPos = stringBuilder.length() + 1;
                    nextQueryParam = null;
                }
                stringBuilder.append(next);
            }
        }
        state.pos = queryParamPos;
        state.nextQueryParam = nextQueryParam;
        state.mapCount = 0;
        state.urlDecodeRequired = urlDecodeRequired;
    }


    
The parse states for parsing heading values
    private static final int NORMAL = 0;
    private static final int WHITESPACE = 1;
    private static final int BEGIN_LINE_END = 2;
    private static final int LINE_END = 3;
    private static final int AWAIT_DATA_END = 4;

    
Parses a header value. This is called from the generated bytecode.

Parameters:
buffer The buffer
state The current state
builder The exchange builder
Returns:
The number of bytes remaining
    @SuppressWarnings("unused")
    final void handleHeaderValue(ByteBuffer bufferParseState stateHttpServerExchange builder) {
        HttpString headerName = state.nextHeader;
        StringBuilder stringBuilder = state.stringBuilder;
        HashMap<HttpStringStringheaderValuesCache = state.headerValuesCache;
        if (stringBuilder.length() == 0) {
            String existing = headerValuesCache.get(headerName);
            if (existing != null) {
                if (handleCachedHeader(existingbufferstatebuilder)) {
                    return;
                }
            }
        }
        handleHeaderValueCacheMiss(bufferstatebuilderheaderNameheaderValuesCachestringBuilder);
    }
    private void handleHeaderValueCacheMiss(ByteBuffer bufferParseState stateHttpServerExchange builderHttpString headerNameHashMap<HttpStringStringheaderValuesCacheStringBuilder stringBuilder) {
        int parseState = state.parseState;
        while (buffer.hasRemaining() && parseState == ) {
            final byte next = buffer.get();
            if (next == '\r') {
                parseState = ;
            } else if (next == '\n') {
                parseState = ;
            } else if (next == ' ' || next == '\t') {
                parseState = ;
            } else {
                stringBuilder.append((char) (next & 0xFF));
            }
        }
        while (buffer.hasRemaining()) {
            final byte next = buffer.get();
            switch (parseState) {
                case : {
                    if (next == '\r') {
                        parseState = ;
                    } else if (next == '\n') {
                        parseState = ;
                    } else if (next == ' ' || next == '\t') {
                        parseState = ;
                    } else {
                        stringBuilder.append((char) (next & 0xFF));
                    }
                    break;
                }
                case : {
                    if (next == '\r') {
                        parseState = ;
                    } else if (next == '\n') {
                        parseState = ;
                    } else if (next == ' ' || next == '\t') {
                    } else {
                        if (stringBuilder.length() > 0) {
                            stringBuilder.append(' ');
                        }
                        stringBuilder.append((char) (next & 0xFF));
                        parseState = ;
                    }
                    break;
                }
                case :
                case : {
                    if (next == '\n' && parseState == ) {
                        parseState = ;
                    } else if (next == '\t' ||
                            next == ' ') {
                        //this is a continuation
                        parseState = ;
                    } else {
                        //we have a header
                        String headerValue = stringBuilder.toString();
                        if (state.mapCount++ > ) {
                            throw ..tooManyHeaders();
                        }
                        //TODO: we need to decode this according to RFC-2047 if we have seen a =? symbol
                        builder.getRequestHeaders().add(headerNameheaderValue);
                        if(headerValuesCache.size() < ) {
                            //we have a limit on how many we can cache
                            //to prevent memory filling and hash collision attacks
                            headerValuesCache.put(headerNameheaderValue);
                        }
                        state.nextHeader = null;
                        state.leftOver = next;
                        state.stringBuilder.setLength(0);
                        if (next == '\r') {
                            parseState = ;
                        } else if (next == '\n') {
                            state.state = .;
                            return;
                        } else {
                            state.state = .;
                            state.parseState = 0;
                            return;
                        }
                    }
                    break;
                }
                case : {
                    state.state = .;
                    return;
                }
            }
        }
        //we only write to the state if we did not finish parsing
        state.parseState = parseState;
    }
    protected boolean handleCachedHeader(String existingByteBuffer bufferParseState stateHttpServerExchange builder) {
        int pos = buffer.position();
        while (pos < buffer.limit() && buffer.get(pos) == ' ') {
            pos++;
        }
        if (existing.length() + 3 + pos > buffer.limit()) {
            return false;
        }
        int i = 0;
        while (i < existing.length()) {
            byte b = buffer.get(pos + i);
            if (b != existing.charAt(i)) {
                return false;
            }
            ++i;
        }
        if (buffer.get(pos + i++) != '\r') {
            return false;
        }
        if (buffer.get(pos + i++) != '\n') {
            return false;
        }
        int next = buffer.get(pos + i);
        if (next == '\t' || next == ' ') {
            //continuation
            return false;
        }
        buffer.position(pos + i);
        if (state.mapCount++ > ) {
            throw ..tooManyHeaders();
        }
        //TODO: we need to decode this according to RFC-2047 if we have seen a =? symbol
        builder.getRequestHeaders().add(state.nextHeaderexisting);
        state.nextHeader = null;
        state.state = .;
        state.parseState = 0;
        return true;
    }
    protected void handleAfterVersion(ByteBuffer bufferParseState state) {
        boolean newLine = state.leftOver == '\n';
        while (buffer.hasRemaining()) {
            final byte next = buffer.get();
            if (newLine) {
                if (next == '\n') {
                    state.state = .;
                    return;
                } else {
                    state.state = .;
                    state.leftOver = next;
                    return;
                }
            } else {
                if (next == '\n') {
                    newLine = true;
                } else if (next != '\r' && next != ' ' && next != '\t') {
                    state.state = .;
                    state.leftOver = next;
                    return;
                } else {
                    throw ..badRequest();
                }
            }
        }
        if (newLine) {
            state.leftOver = '\n';
        }
    }

    
This is a bit of hack to enable the parser to get access to the HttpString's that are sorted in the static fields of the relevant classes. This means that in most cases a HttpString comparison will take the fast path == route, as they will be the same object

Returns:
    protected static Map<StringHttpStringhttpStrings() {
        final Map<StringHttpStringresults = new HashMap<>();
        final Class[] classs = {Headers.classMethods.classProtocols.class};
        for (Class<?> c : classs) {
            for (Field field : c.getDeclaredFields()) {
                if (field.getType().equals(HttpString.class)) {
                    field.setAccessible(true);
                    HttpString result = null;
                    try {
                        result = (HttpStringfield.get(null);
                        results.put(result.toString(), result);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return results;
    }
New to GrepCode? Check out our FAQ X