VRT 391,192 CVEs tracked · 15,442 in RASP scope · data as of 18 hours ago

CVE-2016-6816

7.1 High Protected by RASP

Description

The code in Apache Tomcat 9.0.0.M1 to 9.0.0.M11, 8.5.0 to 8.5.6, 8.0.0.RC1 to 8.0.38, 7.0.0 to 7.0.72, and 6.0.0 to 6.0.47 that parsed the HTTP request line permitted invalid characters. This could be exploited, in conjunction with a proxy that also permitted the invalid characters but with a different interpretation, to inject data into the HTTP response. By manipulating the HTTP response the attacker could poison a web-cache, perform an XSS attack and/or obtain sensitive information from requests other then their own.

CWE-20 · Improper input validation

Exploitation Status

Working exploit published

A reviewed exploit catalogue carries this CVE. Somebody has published code a stranger can run.

CVSS E:P

  • CISA KEV not listed
  • CISA Vulnrichment exploitation: none
  • Indexed PoC 1 indexed Published artifacts you can open, in Exploit-DB; first seen 2017-04-04.
  • EPSS 40% chance in 30 days A model prediction, not an observation. Higher than 99% of all scored CVEs.
IndexArtifactStarsFirst seen
Exploit-DB Apache Tomcat 6/7/8/9 - Information Disclosure 2017-04-04

Waratek Defense Posture

Protected by RASP

A Waratek agent blocks this today.

Applicable rule: CVE has an ARMR patch rule that provides mitigation

  • Protection full a patch rule written for this CVE
  • Action available patch rule
  • Review human armr-file
  • Record active
Decided by armr-patch-file : An ARMR patch file on disk for this CVE
Finding CVE has an ARMR patch rule that provides mitigation

ARMR rule files

1 file

Shipped files covering this CVE. A CVE genuinely takes more than one: separate Maven artifacts hooking different parser classes, the same patch built for two ARMR versions, or a fix at both the framework and the container.

rules/appservers/tomcat/CVE-2016-6816/patch/2.6/CVE-2016-6816.armr patch rule updated 2026-03-04
app("APACHE TOMCAT"):
    requires(version: ARMR/2.6)

    /***************************************************************************
        CVE-2016-6816 (APACHE TOMCAT)

        CVSS 3.0 Summary:
            Base Score          | 7.1
            Attack Vector       | Network
            Attack Complexity   | Low
            Privileges Required | None
            User Interaction    | Required
            Scope               | Changed
            Confidentiality     | Low
            Integrity           | Low
            Availability        | Low

        Description:
            The code that parsed the HTTP request line permitted invalid
            characters. This could be exploited, in conjunction with a proxy
            that also permitted the invalid characters but with a different
            interpretation, to inject data into the HTTP response. By
            manipulating the HTTP response the attacker could poison a
            web-cache, perform an XSS attack and/or obtain sensitive information
            from requests other then their own.

        Resources:
            https://www.exploit-db.com/exploits/41783/
            https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html
            https://github.com/apache/tomcat80/commit/779d5d34e68e50d2f721897050b147106992f566
            https://tomcat.apache.org/security-6.html#Fixed_in_Apache_Tomcat_6.0.48
            http://svn.apache.org/viewvc?view=revision&revision=1767683

        Affected Operating Systems:
            Any

        Affected Versions:
            Apache Tomcat:
                6.0.0 - 6.0.47
                7.0.0 - 7.0.72
                8.0.0.RC1 - 8.0.38
                8.5.0 - 8.5.6
                9.0.0.M1 - 9.0.0.M11

        Tested Versions:
            Apache Tomcat 6.0.45, 6.0.47, 8.0.38

        Protection Provided:
            Functional

        Patch Version:
            1.0
    ***************************************************************************/

    /***************************************************************************
        CVE-2016-6816: Tomcat 6.0.45, 6.0.47
    ***************************************************************************/

    patch("CVE-2016-6816 :TC6 01"):
        function("org/apache/coyote/http11/InternalNioInputBuffer.parseRequestLine(Z)Z",
            checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
            occurrences: [4])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(2);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self, true, false);
                        if (!fill) {
                            frame.returnBoolean(false);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in method name. HTTP method names must be tokens"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 02"):
        function("org/apache/coyote/http11/InternalNioInputBuffer.parseRequestLine(Z)Z",
            checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
            occurrences: [6])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaField parsingRequestLineQPosField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
                parsingRequestLineQPosField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.parsingRequestLineQPos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(3);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);
                int parsingRequestLineQPos = parsingRequestLineQPosField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self, true, false);
                        if (!fill) {
                            frame.returnBoolean(false);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
                        return;
                    } else if ((buf[pos] == Constants.QUESTION) && (parsingRequestLineQPos == -1)) {
                        parsingRequestLineQPos = pos;
                    } else if (isNotRequestTarget(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isNotRequestTarget(int c) {
                try {
                    return IS_NOT_REQUEST_TARGET[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return true;
                }
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 03"):
        function("org/apache/coyote/http11/InternalNioInputBuffer.parseRequestLine(Z)Z",
            checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
            occurrences: [8])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaField parsingRequestLineEolField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
                parsingRequestLineEolField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.parsingRequestLineEol");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);
                boolean parsingRequestLineEol = parsingRequestLineEolField.readBoolean(self);

                while (!parsingRequestLineEol) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self, true, false);
                        if (!fill) {
                            frame.returnBoolean(false);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.CR) {
                        ;
                    } else if (buf[pos] == Constants.LF) {
                        return;
                    } else if (!isHttpProtocol(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isHttpProtocol(int c) {
                try {
                    return IS_HTTP_PROTOCOL[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the HTTP protocol"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 04"):
        function("org/apache/coyote/http11/InternalNioInputBuffer.parseHeader()Lorg/apache/coyote/http11/InternalNioInputBuffer$HeaderParseStatus;",
            checksums: ["5e07e435fc", "8959354f2b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalNioInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaField headerParsePosField;
            private static JavaField HEADER_NAME_Field;
            private static JavaField NEED_MORE_DATA_Field;
            private static JavaField lastSignificantCharField;
            private static JavaField headerDataField;
            private static JavaMethod skipLineMethod;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.pos");
                headerParsePosField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.headerParsePos");
                HEADER_NAME_Field =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer$HeaderParsePosition.HEADER_NAME");
                NEED_MORE_DATA_Field =
                    JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus.NEED_MORE_DATA");
                lastSignificantCharField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer$HeaderParseData.lastSignificantChar");
                headerDataField =
                    JavaField.load("org/apache/coyote/http11/InternalNioInputBuffer.headerData");
                skipLineMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.skipLine()Lorg/apache/coyote/http11/InternalNioInputBuffer$HeaderParseStatus;");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalNioInputBuffer.fill(ZZ)Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                byte chr = frame.loadByteVariable(1);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);
                Object headerParsePos = headerParsePosField.readObject(self);
                Object HEADER_NAME = HEADER_NAME_Field.readObject(null);

                while (headerParsePos == HEADER_NAME) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self, true, false);
                        if (!fill) {
                            Object NEED_MORE_DATA = NEED_MORE_DATA_Field.readObject(null);
                            frame.returnObject(NEED_MORE_DATA);
                            return;
                        }
                    }
                    chr = buf[pos];
                    if (chr == Constants.COLON) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        Object headerData = headerDataField.readObject(self);
                        lastSignificantCharField.writeInt(headerData, pos);
                        frame.returnObject(skipLineMethod.call(self));
                        return;
                    }
                    if ((chr >= Constants.A) && (chr <= Constants.Z)) {
                        buf[pos] = (byte) (chr - Constants.LC_OFFSET);
                    }
                    pos++;
                 }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }
         endcode
     endpatch

    patch("CVE-2016-6816 :TC6 05"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
            checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [3])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(4);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in method name. HTTP method names must be tokens"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 06"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
            checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [5])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(4);
                int questionPos = frame.loadIntVariable(6);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
                        return;
                    } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
                        questionPos = pos;
                    } else if (isNotRequestTarget(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isNotRequestTarget(int c) {
                try {
                    return IS_NOT_REQUEST_TARGET[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return true;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 07"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
            checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [7])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean eol = frame.loadBooleanVariable(7);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!eol) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.CR) {
                        ;
                    } else if (buf[pos] == Constants.LF) {
                        return;
                    } else if (!isHttpProtocol(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isHttpProtocol(int c) {
                try {
                    return IS_HTTP_PROTOCOL[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the HTTP protocol"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 08"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseHeader()Z",
            checksums: ["8bc38655b2", "2a87e6b643"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;
            private static JavaMethod skipLineMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalAprInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill()Z");
                skipLineMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.skipLine(I)V");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                byte chr = frame.loadByteVariable(1);
                int start = frame.loadIntVariable(2);
                boolean colon = frame.loadBooleanVariable(3);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!colon) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.COLON) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        skipLineMethod.call(self, start);
                        frame.returnBoolean(true);
                        return;
                    }
                    chr = buf[pos];
                    if ((chr >= Constants.A) && (chr <= Constants.Z)) {
                        buf[pos] = (byte) (chr - Constants.LC_OFFSET);
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }
        endcode
    endpatch



    patch("CVE-2016-6816 :TC6 09"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine()V",
            checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(3);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in method name. HTTP method names must be tokens"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 10"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine()V",
            checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [4])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(3);
                int questionPos = frame.loadIntVariable(5);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
                        return;
                    } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
                        questionPos = pos;
                    } else if (isNotRequestTarget(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isNotRequestTarget(int c) {
                try {
                    return IS_NOT_REQUEST_TARGET[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return true;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 11"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine()V",
            checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [6])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean eol = frame.loadBooleanVariable(6);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!eol) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.CR) {
                        ;
                    } else if (buf[pos] == Constants.LF) {
                        return;
                    } else if (!isHttpProtocol(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isHttpProtocol(int c) {
                try {
                    return IS_HTTP_PROTOCOL[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException(
                        "Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the HTTP protocol"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC6 12"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseHeader()V",
            checksums: ["28e6907564", "21eb5af62b"]) // 6.0.45, 6.0.47
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;
            private static JavaMethod skipLineMethod;

            public void load() {
                bufField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.buf");
                posField =
                    JavaField.load("org/apache/coyote/http11/InternalInputBuffer.pos");
                fillMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
                skipLineMethod =
                    JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.skipLine(I)V");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                byte chr = frame.loadByteVariable(1);
                int start = frame.loadIntVariable(2);
                boolean colon = frame.loadBooleanVariable(3);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!colon) {
                    if (pos >= lastValid) {
                        boolean fill = (Boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.COLON) {
                        return;
                    } else if (!isToken(buf[pos])) {

                        skipLine.call(self, start);
                        frame.returnBoolean(true);
                        return;
                    }
                    chr = buf[pos];
                    if ((chr >= Constants.A) && (chr <= Constants.Z)) {
                        buf[pos] = (byte) (chr - Constants.LC_OFFSET);
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }
        endcode
    endpatch

    /***************************************************************************
        CVE-2016-6816: Tomcat 8.0.38
    ***************************************************************************/

    patch("CVE-2016-6816 :TC8 01"):
        function("org/apache/coyote/http11/AbstractInputBuffer.<init>()V",
            checksums: ["da7deb64b7"])   // 8.0.38
        entry()

        code(language: java, import: ["java.util.Collections",
                                      "java.util.HashMap",
                                      "java.util.Map"]):
            private static final String BUFFER_MAP = "bufferMap";
            private static final String ANIB_PRL_3 = "anib_prl_3";
            private static final String ANIB_PRL_5 = "anib_prl_5";
            private static final String ANIB_PRL_7 = "anib_prl_7";
            private static final String ANIB_PH_2 = "anib_ph_2";

            private static final String IAIB_PRL_3 = "iaib_prl_3";
            private static final String IAIB_PRL_5 = "iaib_prl_5";
            private static final String IAIB_PRL_7 = "iaib_prl_7";
            private static final String IAIB_PH_2 = "iaib_ph_2";

            private static final String IIB_PRL_2 = "iib_prl_2";
            private static final String IIB_PRL_4 = "iib_prl_4";
            private static final String IIB_PRL_6 = "iib_prl_6";
            private static final String IIB_PH_2 = "iib_ph_2";

            private static final Map<String, Boolean> bufferMap =
                Collections.synchronizedMap(new HashMap<String, Boolean>());

            public void patch(JavaFrame frame) {
                // The initial value is 'false', which means the patch
                // has not run. Each patch will set it's respective value
                // to 'true' once the patch has run.
                bufferMap.put(ANIB_PRL_3, false);
                bufferMap.put(ANIB_PRL_5, false);
                bufferMap.put(ANIB_PRL_7, false);
                bufferMap.put(ANIB_PH_2, false);

                bufferMap.put(IAIB_PRL_3, false);
                bufferMap.put(IAIB_PRL_5, false);
                bufferMap.put(IAIB_PRL_7, false);
                bufferMap.put(IAIB_PH_2, false);

                bufferMap.put(IIB_PRL_2, false);
                bufferMap.put(IIB_PRL_4, false);
                bufferMap.put(IIB_PRL_6, false);
                bufferMap.put(IIB_PH_2, false);

                saveValue(BUFFER_MAP, bufferMap);
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 02"):
        function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
            checksums: ["b0ea19cc74"])   // 8.0.38
        readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
            occurrences: [3])

        code(language: java, import: ["java.util.Map",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static final String BUFFER_MAP = "bufferMap";
            private static final String ANIB_PRL_3 = "anib_prl_3";

            private static JavaField lastValidField;
            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            private Object self;

            public void load() {
                lastValidField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.lastValid");
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
            }

            public void patch(JavaFrame frame) {
                Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
                if (bufferMap.get(ANIB_PRL_3)) {
                    return;
                }
                bufferMap.put(ANIB_PRL_3, true);
                self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(2);
                int originalPos = pos();

                while (!space) {
                    if (pos() >= lastValid()) {
                        boolean fill = (boolean) fillMethod.call(self, false);
                        if (!fill) {
                            frame.returnBoolean(false);
                            return;
                        }
                    }
                    if (buf()[pos()] == Constants.SP || buf()[pos()] == Constants.HT) {
                        pos(originalPos);
                        return;
                    } else if (!isToken(buf()[pos()])) {
                        bufferMap.put(ANIB_PRL_3, false);
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos(pos() + 1);
                }
            }

            private int lastValid() {
                return lastValidField.readInt(self);
            }

            private byte[] buf() {
                return (byte[]) bufField.readObject(self);
            }

            private int pos() {
                return posField.readInt(self);
            }

            private void pos(int i) {
                posField.writeInt(self, i);
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in method name. HTTP method names must be tokens"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 03"):
        function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
            checksums: ["b0ea19cc74"])   // 8.0.38
        readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
            occurrences: [5])

        code(language: java, import: ["java.util.Map",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static final String BUFFER_MAP = "bufferMap";
            private static final String ANIB_PRL_5 = "anib_prl_5";

            private static JavaField lastValidField;
            private static JavaField bufField;
            private static JavaField posField;
            private static JavaField parsingRequestLineQPosField;
            private static JavaMethod fillMethod;

            private Object self;

            public void load() {
                lastValidField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.lastValid");
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                parsingRequestLineQPosField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.parsingRequestLineQPos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
            }

            public void patch(JavaFrame frame) {
                Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
                if (bufferMap.get(ANIB_PRL_5)) {
                    return;
                }
                bufferMap.put(ANIB_PRL_5, true);
                self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(3);
                int originalPos = pos();
                int parsingRequestLineQPos = parsingRequestLineQPos();

                while (!space) {
                    if (pos() >= lastValid()) {
                        boolean fill = (boolean) fillMethod.call(self, false);
                        if (!fill) {
                            frame.returnBoolean(false);
                            return;
                        }
                    }
                    if (buf()[pos()] == Constants.SP || buf()[pos()] == Constants.HT) {
                        pos(originalPos);
                        return;
                    } else if (buf()[pos()] == Constants.CR || buf()[pos()] == Constants.LF) {
                        pos(originalPos);
                        return;
                    } else if (buf()[pos()] == Constants.QUESTION && parsingRequestLineQPos == -1) {
                         parsingRequestLineQPos = pos();
                    } else if (isNotRequestTarget(buf()[pos()])) {
                        bufferMap.put(ANIB_PRL_5, false);
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos(pos() + 1);
                }
            }

            private int lastValid() {
                return lastValidField.readInt(self);
            }

            private byte[] buf() {
                return (byte[]) bufField.readObject(self);
            }

            private int pos() {
                return posField.readInt(self);
            }

            private void pos(int i) {
                posField.writeInt(self, i);
            }

            private int parsingRequestLineQPos() {
                return parsingRequestLineQPosField.readInt(self);
            }

            public boolean isNotRequestTarget(int c) {
                try {
                    return IS_NOT_REQUEST_TARGET[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return true;
                }
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 04"):
        function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
            checksums: ["b0ea19cc74"])   // 8.0.38
        readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
            occurrences: [7])

        code(language: java, import: ["java.util.Map",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static final String BUFFER_MAP = "bufferMap";
            private static final String ANIB_PRL_7 = "anib_prl_7";

            private static JavaField lastValidField;
            private static JavaField bufField;
            private static JavaField posField;
            private static JavaField parsingRequestLineQPosField;
            private static JavaField parsingRequestLineEolField;
            private static JavaMethod fillMethod;

            private Object self;

            public void load() {
                lastValidField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.lastValid");
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                parsingRequestLineQPosField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.parsingRequestLineQPos");
                parsingRequestLineEolField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.parsingRequestLineEol");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
            }

            public void patch(JavaFrame frame) {
                Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
                if (bufferMap.get(ANIB_PRL_7)) {
                    return;
                }
                bufferMap.put(ANIB_PRL_7, true);
                self = frame.loadThisVariable();
                int lastValid = frame.loadIntOperand(0);

                boolean parsingRequestLineEol = parsingRequestLineEolField.readBoolean(self);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!parsingRequestLineEol) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self, false);
                        if (!fill) {
                            frame.returnBoolean(false);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.CR) {
                        ;
                    } else if (buf[pos] == Constants.LF) {
                        return;
                    } else if (!isHttpProtocol(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            public boolean isHttpProtocol(int c) {
                try {
                    return IS_HTTP_PROTOCOL[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the HTTP protocol"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 05"):
        function("org/apache/coyote/http11/AbstractNioInputBuffer.parseHeader()Lorg/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus;",
            checksums: ["b0ea19cc74"])   // 8.0.38
        readreturn("org/apache/coyote/http11/AbstractNioInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.util.Map",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaField headerParsePosField;
            private static JavaMethod fillMethod;
            private static JavaField lastSignificantCharField;
            private static JavaMethod skipLineMethod;
            private static JavaField headerDataField;

            private static Object HEADER_NAME;
            private static Object NEED_MORE_DATA;
            private static boolean shouldInit = true;

            public void init() {
                HEADER_NAME =
                    JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParsePosition.HEADER_NAME")
                             .readObject(null);
                NEED_MORE_DATA =
                    JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus.NEED_MORE_DATA")
                             .readObject(null);
                shouldInit = false;
            }

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                headerParsePosField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.headerParsePos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/AbstractInputBuffer.fill(Z)Z");
                lastSignificantCharField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseData.lastSignificantChar");
                skipLineMethod = JavaMethod.load("org/apache/coyote/http11/AbstractNioInputBuffer.skipLine()Lorg/apache/coyote/http11/AbstractNioInputBuffer$HeaderParseStatus;");
                headerDataField = JavaField.load("org/apache/coyote/http11/AbstractNioInputBuffer.headerData");
            }

            public void patch(JavaFrame frame) {
                if (shouldInit) {
                    init();
                }
                Object self = frame.loadThisVariable();
                byte chr = frame.loadByteVariable(1);
                int lastValid = frame.loadIntOperand(0);

                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);
                Object headerParsePos = headerParsePosField.readObject(self);

                while (headerParsePos == HEADER_NAME) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self, false);
                        if (!fill) {
                            frame.returnObject(NEED_MORE_DATA);
                            return;
                        }
                    }
                    chr = buf[pos];
                    if (chr == Constants.COLON) {
                        return;
                    } else if (!isToken(chr)) {
                        Object headerData = headerDataField.readObject(self);
                        lastSignificantCharField.writeInt(headerData, pos);
                        frame.returnObject(skipLineMethod.call(self));
                        return;
                    }
                    if ((chr >= Constants.A) && (chr <= Constants.Z)) {
                        buf[pos] = (byte) (chr - Constants.LC_OFFSET);
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 06"):
        function("org/apache/coyote/http11/AbstractNioInputBuffer.parseRequestLine(Z)Z",
            checksums: ["b0ea19cc74"])   // 8.0.38
        exit()

        code(language: java, import: ["java.util.Collections",
                                      "java.util.HashMap",
                                      "java.util.Map"]):
            private static final String BUFFER_MAP = "bufferMap";
            private static final String ANIB_PRL_3 = "anib_prl_3";
            private static final String ANIB_PRL_5 = "anib_prl_5";
            private static final String ANIB_PRL_7 = "anib_prl_7";
            private static final String ANIB_PH_2 = "anib_ph_2";

            public void patch(JavaFrame frame) {
                Map<String, Boolean> bufferMap = (Map<String, Boolean>) restoreValue(BUFFER_MAP);
                bufferMap.put(ANIB_PRL_3, false);
                bufferMap.put(ANIB_PRL_5, false);
                bufferMap.put(ANIB_PRL_7, false);
                bufferMap.put(ANIB_PH_2, false);
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 07"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
            checksums: ["679efed66a"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [3])

        code(language: java, import: ["java.util.Map",
                                        "java.io.EOFException",
                                        "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(4);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self, true);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in method name. HTTP method names must be tokens"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 08"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
            checksums: ["679efed66a"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [5])

        code(language: java, import: ["java.util.Map",
                                      "java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(4);
                int questionPos = frame.loadIntVariable(6);
                boolean eol = frame.loadBooleanVariable(7);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self, true);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
                        return;
                    } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
                        questionPos = pos;
                    } else if (isNotRequestTarget(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            public boolean isNotRequestTarget(int c) {
                try {
                    return IS_NOT_REQUEST_TARGET[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return true;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 09"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseRequestLine(Z)Z",
            checksums: ["679efed66a"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [7])

        code(language: java, import: ["java.util.Map",
                                      "java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(4);
                boolean eol = frame.loadBooleanVariable(7);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!eol) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self, true);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.CR) {
                        ;
                    } else if (buf[pos] == Constants.LF) {
                        return;
                    } else if (!isHttpProtocol(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isHttpProtocol(int c) {
                try {
                    return IS_HTTP_PROTOCOL[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the HTTP protocol"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 10"):
        function("org/apache/coyote/http11/InternalAprInputBuffer.parseHeader()Z",
            checksums: ["679efed66a"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalAprInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.util.Map",
                                      "java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;
            private static JavaMethod skipLineMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.fill(Z)Z");
                skipLineMethod = JavaMethod.load("org/apache/coyote/http11/InternalAprInputBuffer.skipLine(I)V");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                byte chr = frame.loadByteVariable(1);
                int start = frame.loadIntVariable(2);
                boolean colon = frame.loadBooleanVariable(3);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!colon) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self, true);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.COLON) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        skipLineMethod.call(self, start);
                        frame.returnBoolean(true);
                        return;
                    }
                    chr = buf[pos];
                    if ((chr >= Constants.A) && (chr <= Constants.Z)) {
                        buf[pos] = (byte) (chr - Constants.LC_OFFSET);
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 11"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine(Z)Z",
            checksums: ["bcdfe811f1"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.util.Map",
                                      "java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(4);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in method name. HTTP method names must be tokens"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 12"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine(Z)Z",
            checksums: ["bcdfe811f1"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [4])

        code(language: java, import: ["java.util.Map",
                                      "java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                boolean space = frame.loadBooleanVariable(4);
                int questionPos = frame.loadIntVariable(6);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!space) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
                        return;
                    } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) {
                        return;
                    } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) {
                        questionPos = pos;
                    } else if (isNotRequestTarget(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            public boolean isNotRequestTarget(int c) {
                try {
                    return IS_NOT_REQUEST_TARGET[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return true;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 13"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseRequestLine(Z)Z",
            checksums: ["bcdfe811f1"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [6])

        code(language: java, import: ["java.util.Map",
                                      "java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
            }

            public void patch(JavaFrame frame) {
                final Object self = frame.loadThisVariable();
                boolean eol = frame.loadBooleanVariable(7);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!eol) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.CR) {
                        ;
                    } else if (buf[pos] == Constants.LF) {
                        return;
                    } else if (!isHttpProtocol(buf[pos])) {
                        throwIllegalArgumentException(frame);
                        return;
                    }
                    pos++;
                }
            }

            public boolean isHttpProtocol(int c) {
                try {
                    return IS_HTTP_PROTOCOL[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException(
                    new EOFException("Unexpected EOF read on the socket"));
            }

            private void throwIllegalArgumentException(JavaFrame frame) {
                frame.raiseException(
                    new IllegalArgumentException(
                        "Invalid character found in the HTTP protocol"));
            }
        endcode
    endpatch

    patch("CVE-2016-6816 :TC8 14"):
        function("org/apache/coyote/http11/InternalInputBuffer.parseHeader()Z",
            checksums: ["bcdfe811f1"])   // 8.0.38
        readreturn("org/apache/coyote/http11/InternalInputBuffer.lastValid",
            occurrences: [2])

        code(language: java, import: ["java.util.Map",
                                      "java.io.EOFException",
                                      "org.apache.coyote.http11.Constants"]):
            private static final int ARRAY_SIZE = 128;
            private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];
            private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

            static {
                for (int i = 0; i < ARRAY_SIZE; i++) {
                    // Control> 0-31, 127
                    if (i < 32 || i == 127) {
                        IS_CONTROL[i] = true;
                    }

                    // Separator
                    if (    i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                            i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                            i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                            i == '{' || i == '}' || i == ' ' || i == '\t') {
                        IS_SEPARATOR[i] = true;
                    }

                    // Token: Anything 0-127 that is not a control and not a separator
                    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) {
                        IS_TOKEN[i] = true;
                    }

                    // Hex: 0-9, a-f, A-F
                    if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {
                        IS_HEX[i] = true;
                    }

                    // Not valid for request target.
                    // Combination of multiple rules from RFC7230 and RFC 3986. Must be
                    // ASCII, no controls plus a few additional characters excluded
                    if (IS_CONTROL[i] || i > 127 ||
                            i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' ||
                            i == '^' || i == '`'  || i == '{' || i == '|' || i == '}') {
                        IS_NOT_REQUEST_TARGET[i] = true;
                    }

                    // Not valid for HTTP protocol
                    // "HTTP/" DIGIT "." DIGIT
                    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {
                        IS_HTTP_PROTOCOL[i] = true;
                    }
                }
            }

            private static JavaField bufField;
            private static JavaField posField;
            private static JavaMethod fillMethod;
            private static JavaMethod skipLineMethod;

            public void load() {
                bufField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.buf");
                posField = JavaField.load("org/apache/coyote/http11/AbstractInputBuffer.pos");
                fillMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.fill()Z");
                skipLineMethod = JavaMethod.load("org/apache/coyote/http11/InternalInputBuffer.skipLine(I)V");
            }

            public void patch(JavaFrame frame) {
                Object self = frame.loadThisVariable();
                byte chr = frame.loadByteVariable(1);
                int start = frame.loadIntVariable(2);
                boolean colon = frame.loadBooleanVariable(3);
                int lastValid = frame.loadIntOperand(0);
                byte[] buf = (byte[]) bufField.readObject(self);
                int pos = posField.readInt(self);

                while (!colon) {
                    if (pos >= lastValid) {
                        boolean fill = (boolean) fillMethod.call(self);
                        if (!fill) {
                            throwEOFException(frame);
                            return;
                        }
                    }
                    if (buf[pos] == Constants.COLON) {
                        return;
                    } else if (!isToken(buf[pos])) {
                        skipLineMethod.call(self, start);
                        frame.returnBoolean(true);
                        return;
                    }
                    chr = buf[pos];
                    if ((chr >= Constants.A) && (chr <= Constants.Z)) {
                        buf[pos] = (byte) (chr - Constants.LC_OFFSET);
                    }
                    pos++;
                }
            }

            private boolean isToken(int c) {
                try {
                    return IS_TOKEN[c];
                } catch (ArrayIndexOutOfBoundsException ex) {
                    return false;
                }
            }

            private void throwEOFException(JavaFrame frame) {
                frame.raiseException
                    (new EOFException("Unexpected EOF read on the socket"));
            }
        endcode
    endpatch

endapp

CVSS

7.1 HIGH v3.0 CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L 2 metrics

VRT selects the newest version's highest entry and publishes it as cvssScore, newest rather than largest because scores are not comparable across versions, and highest rather than first because the first entry is frequently a CNA placeholder scoring 0.0 over NVD's own analysis.

VersionScoreBandVectorAssignerType
CVSS 3.0 7.1 HIGH CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L NVD Primary published
CVSS 2.0 6.8 no band published AV:N/AC:M/Au:N/C:P/I:P/A:P NVD Primary

Affected Software & Releases

☕ Maven Library Packages

Artifact coordinates and fix boundaries from OSV.dev
Package CoordinateIntroducedFixedLast affected
org.apache.tomcat:tomcat-coyote 9.0.0.M1 9.0.0.M12 unbounded
org.apache.tomcat:tomcat-coyote 8.5.0 8.5.8 unbounded
org.apache.tomcat:tomcat-coyote 8.0.0RC1 8.0.39 unbounded
org.apache.tomcat:tomcat-coyote 7.0.0 7.0.73 unbounded
org.apache.tomcat:tomcat-coyote 6.0.0 6.0.48 unbounded

🖥️ Product CPEs & Version Ranges

2 product(s) over 183 version claims (uncapped)
SourceVendorProductSchemeAffected Versions
nvd apache tomcat generic 6.0.0 · 6.0.1 · 6.0.2 · 6.0.3 · 6.0.4 · 6.0.5 · 6.0.6 · 6.0.7 · 6.0.8 · 6.0.9 · 6.0.10 · 6.0.11 · 6.0.12 · 6.0.13 · 6.0.14 · 6.0.15 · 6.0.16 · 6.0.17 · 6.0.18 · 6.0.19 · 6.0.20 · 6.0.21 · 6.0.22 · 6.0.23 · 6.0.24 · 6.0.25 · 6.0.26 · 6.0.27 · 6.0.28 · 6.0.29 · 6.0.30 · 6.0.31 · 6.0.32 · 6.0.33 · 6.0.34 · 6.0.35 · 6.0.36 · 6.0.37 · 6.0.38 · 6.0.39 · 6.0.40 · 6.0.41 · 6.0.42 · 6.0.43 · 6.0.44 · 6.0.45 · 6.0.46 · 6.0.47 · 7.0.0 · 7.0.1 · 7.0.2 · 7.0.3 · 7.0.4 · 7.0.5 · 7.0.6 · 7.0.7 · 7.0.8 · 7.0.9 · 7.0.10 · 7.0.11 · 7.0.12 · 7.0.13 · 7.0.14 · 7.0.15 · 7.0.16 · 7.0.17 · 7.0.18 · 7.0.19 · 7.0.20 · 7.0.21 · 7.0.22 · 7.0.23 · 7.0.24 · 7.0.25 · 7.0.26 · 7.0.27 · 7.0.28 · 7.0.29 · 7.0.30 · 7.0.31 · 7.0.32 · 7.0.33 · 7.0.34 · 7.0.35 · 7.0.36 · 7.0.37 · 7.0.38 · 7.0.39 · 7.0.40 · 7.0.41 · 7.0.42 · 7.0.43 · 7.0.44 · 7.0.45 · 7.0.46 · 7.0.47 · 7.0.48 · 7.0.49 · 7.0.50 · 7.0.51 · 7.0.52 · 7.0.53 · 7.0.54 · 7.0.55 · 7.0.56 · 7.0.57 · 7.0.58 · 7.0.59 · 7.0.60 · 7.0.61 · 7.0.62 · 7.0.63 · 7.0.64 · 7.0.65 · 7.0.66 · 7.0.67 · 7.0.68 · 7.0.69 · 7.0.70 · 7.0.71 · 7.0.72 · 8.0.0 · 8.0.1 · 8.0.2 · 8.0.3 · 8.0.4 · 8.0.5 · 8.0.6 · 8.0.7 · 8.0.8 · 8.0.9 · 8.0.10 · 8.0.11 · 8.0.12 · 8.0.13 · 8.0.14 · 8.0.15 · 8.0.16 · 8.0.17 · 8.0.18 · 8.0.19 · 8.0.20 · 8.0.21 · 8.0.22 · 8.0.23 · 8.0.24 · 8.0.25 · 8.0.26 · 8.0.27 · 8.0.28 · 8.0.29 · 8.0.30 · 8.0.31 · 8.0.32 · 8.0.33 · 8.0.34 · 8.0.35 · 8.0.36 · 8.0.37 · 8.0.38 · 8.5.0 · 8.5.1 · 8.5.2 · 8.5.3 · 8.5.4 · 8.5.5 · 8.5.6 · 9.0.0:milestone1 · 9.0.0:milestone10 · 9.0.0:milestone11 · 9.0.0:milestone2 · 9.0.0:milestone3 · 9.0.0:milestone4 · 9.0.0:milestone5 · 9.0.0:milestone6 · 9.0.0:milestone7 · 9.0.0:milestone8 · 9.0.0:milestone9
osv org.apache.tomcat tomcat-coyote generic ≥ 6.0.0 and < 6.0.48 · ≥ 7.0.0 and < 7.0.73 · ≥ 8.0.0 and < 8.0.39 · ≥ 8.5.0 and < 8.5.8 · ≥ 9.0.0 and < 9.0.0

References

URLTags
https://github.com/apache/tomcat/commit/516bda676ac8d0284da3e0295a7df70391315360 WEB
https://github.com/apache/tomcat/commit/cdc0a935c2173aff60039a0b85e57a461381107c WEB
https://github.com/apache/tomcat/commit/f96f5751d418ae5a2f550be040daf9c5f7d99256 WEB
https://github.com/apache/tomcat80/commit/779d5d34e68e50d2f721897050b147106992f566 WEB
https://access.redhat.com/errata/RHSA-2017:0455 WEB
https://lists.apache.org/thread.html/b8a1bf18155b552dcf9a928ba808cbadad84c236d85eab3033662cfb@%3Cdev.tomcat.apache.org%3E WEB
https://lists.apache.org/thread.html/r03c597a64de790ba42c167efacfa23300c3d6c9fe589ab87fe02859c%40%3Cdev.tomcat.apache.org%3E WEB
https://lists.apache.org/thread.html/r03c597a64de790ba42c167efacfa23300c3d6c9fe589ab87fe02859c@%3Cdev.tomcat.apache.org%3E WEB
https://lists.apache.org/thread.html/r587e50b86c1a96ee301f751d50294072d142fd6dc08a8987ae9f3a9b%40%3Cdev.tomcat.apache.org%3E WEB
https://lists.apache.org/thread.html/r587e50b86c1a96ee301f751d50294072d142fd6dc08a8987ae9f3a9b@%3Cdev.tomcat.apache.org%3E WEB

Timeline

Published 2017-03-20 Last modified 2026-06-17
Published2017-03-20By the CVE Program.
ARMR remediation last updated2026-03-04Most recent commit touching this CVE's ARMR patch or security rule.
Last VRT activity2026-03-04Most recent commit touching this CVE's classification, patch or rule file.
NVD record modified2026-06-17NVD's own last-modified date for this record.