%PDF- <> %âãÏÓ endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 28 0 R 29 0 R] /MediaBox[ 0 0 595.5 842.25] /Contents 4 0 R/Group<>/Tabs/S>> endobj ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµù Õ5sLOšuY>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<> endobj 2 0 obj<>endobj 2 0 obj<>es 3 0 R>> endobj 2 0 obj<> ox[ 0.000000 0.000000 609.600000 935.600000]/Fi endobj 3 0 obj<> endobj 7 1 obj<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Subtype/Form>> stream

nadelinn - rinduu

Command :

ikan Uploader :
Directory :  /home/ubuntu/node-v16.18.1/deps/ngtcp2/nghttp3/lib/
Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 
Current File : //home/ubuntu/node-v16.18.1/deps/ngtcp2/nghttp3/lib/nghttp3_http.c
/*
 * nghttp3
 *
 * Copyright (c) 2019 nghttp3 contributors
 * Copyright (c) 2015 nghttp2 contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "nghttp3_http.h"

#include <string.h>
#include <assert.h>

#include "nghttp3_stream.h"
#include "nghttp3_macro.h"
#include "nghttp3_conv.h"

static uint8_t downcase(uint8_t c) {
  return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
}

/*
 * memieq returns 1 if the data pointed by |a| of length |n| equals to
 * |b| of the same length in case-insensitive manner.  The data
 * pointed by |a| must not include upper cased letters (A-Z).
 */
static int memieq(const void *a, const void *b, size_t n) {
  size_t i;
  const uint8_t *aa = a, *bb = b;

  for (i = 0; i < n; ++i) {
    if (aa[i] != downcase(bb[i])) {
      return 0;
    }
  }
  return 1;
}

#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))

static int64_t parse_uint(const uint8_t *s, size_t len) {
  int64_t n = 0;
  size_t i;
  if (len == 0) {
    return -1;
  }
  for (i = 0; i < len; ++i) {
    if ('0' <= s[i] && s[i] <= '9') {
      if (n > INT64_MAX / 10) {
        return -1;
      }
      n *= 10;
      if (n > INT64_MAX - (s[i] - '0')) {
        return -1;
      }
      n += s[i] - '0';
      continue;
    }
    return -1;
  }
  return n;
}

static int check_pseudo_header(nghttp3_http_state *http,
                               const nghttp3_qpack_nv *nv, uint32_t flag) {
  if ((http->flags & flag) || nv->value->len == 0) {
    return 0;
  }
  http->flags |= flag;
  return 1;
}

static int expect_response_body(nghttp3_http_state *http) {
  return (http->flags & NGHTTP3_HTTP_FLAG_METH_HEAD) == 0 &&
         http->status_code / 100 != 1 && http->status_code != 304 &&
         http->status_code != 204;
}

/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
   header field to represent system-wide OPTIONS request.  Otherwise,
   :path header field value must start with "/".  This function must
   be called after ":method" header field was received.  This function
   returns nonzero if path is valid.*/
static int check_path_flags(nghttp3_http_state *http) {
  return (http->flags & NGHTTP3_HTTP_FLAG_SCHEME_HTTP) == 0 ||
         ((http->flags & NGHTTP3_HTTP_FLAG_PATH_REGULAR) ||
          ((http->flags & NGHTTP3_HTTP_FLAG_METH_OPTIONS) &&
           (http->flags & NGHTTP3_HTTP_FLAG_PATH_ASTERISK)));
}

/* Generated by genchartbl.py */
static const int SF_KEY_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 0 /* !    */, 0 /* "    */,
    0 /* #    */, 0 /* $    */, 0 /* %    */, 0 /* &    */, 0 /* '    */,
    0 /* (    */, 0 /* )    */, 1 /* *    */, 0 /* +    */, 0 /* ,    */,
    1 /* -    */, 1 /* .    */, 0 /* /    */, 1 /* 0    */, 1 /* 1    */,
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
    0 /* A    */, 0 /* B    */, 0 /* C    */, 0 /* D    */, 0 /* E    */,
    0 /* F    */, 0 /* G    */, 0 /* H    */, 0 /* I    */, 0 /* J    */,
    0 /* K    */, 0 /* L    */, 0 /* M    */, 0 /* N    */, 0 /* O    */,
    0 /* P    */, 0 /* Q    */, 0 /* R    */, 0 /* S    */, 0 /* T    */,
    0 /* U    */, 0 /* V    */, 0 /* W    */, 0 /* X    */, 0 /* Y    */,
    0 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 0 /* ^    */,
    1 /* _    */, 0 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 0 /* |    */,
    0 /* }    */, 0 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
    0 /* 0xff */,
};

static nghttp3_ssize sf_parse_key(const uint8_t *begin, const uint8_t *end) {
  const uint8_t *p = begin;

  if ((*p < 'a' || 'z' < *p) && *p != '*') {
    return -1;
  }

  for (; p != end && SF_KEY_CHARS[*p]; ++p)
    ;

  return p - begin;
}

static nghttp3_ssize sf_parse_integer_or_decimal(nghttp3_sf_value *dest,
                                                 const uint8_t *begin,
                                                 const uint8_t *end) {
  const uint8_t *p = begin;
  int sign = 1;
  int64_t value = 0;
  int type = NGHTTP3_SF_VALUE_TYPE_INTEGER;
  size_t len = 0;
  size_t fpos = 0;
  size_t i;

  if (*p == '-') {
    if (++p == end) {
      return -1;
    }

    sign = -1;
  }

  if (*p < '0' || '9' < *p) {
    return -1;
  }

  for (; p != end; ++p) {
    switch (*p) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      value *= 10;
      value += *p - '0';

      if (++len > 15) {
        return -1;
      }

      break;
    case '.':
      if (type != NGHTTP3_SF_VALUE_TYPE_INTEGER) {
        goto fin;
      }

      if (len > 12) {
        return -1;
      }
      fpos = len;
      type = NGHTTP3_SF_VALUE_TYPE_DECIMAL;

      break;
    default:
      goto fin;
    };
  }

fin:
  switch (type) {
  case NGHTTP3_SF_VALUE_TYPE_INTEGER:
    if (dest) {
      dest->type = (uint8_t)type;
      dest->i = value * sign;
    }

    return p - begin;
  case NGHTTP3_SF_VALUE_TYPE_DECIMAL:
    if (fpos == len || len - fpos > 3) {
      return -1;
    }

    if (dest) {
      dest->type = (uint8_t)type;
      dest->d = (double)value;
      for (i = len - fpos; i > 0; --i) {
        dest->d /= (double)10;
      }
      dest->d *= sign;
    }

    return p - begin;
  default:
    assert(0);
    abort();
  }
}

/* Generated by genchartbl.py */
static const int SF_DQUOTE_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
    0 /* RS   */, 0 /* US   */, 1 /* SPC  */, 1 /* !    */, 0 /* "    */,
    1 /* #    */, 1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
    1 /* (    */, 1 /* )    */, 1 /* *    */, 1 /* +    */, 1 /* ,    */,
    1 /* -    */, 1 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 1 /* :    */, 1 /* ;    */,
    1 /* <    */, 1 /* =    */, 1 /* >    */, 1 /* ?    */, 1 /* @    */,
    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
    1 /* Z    */, 1 /* [    */, 0 /* \    */, 1 /* ]    */, 1 /* ^    */,
    1 /* _    */, 1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 1 /* {    */, 1 /* |    */,
    1 /* }    */, 1 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
    0 /* 0xff */,
};

static nghttp3_ssize sf_parse_string(nghttp3_sf_value *dest,
                                     const uint8_t *begin, const uint8_t *end) {
  const uint8_t *p = begin;

  if (*p++ != '"') {
    return -1;
  }

  for (; p != end; ++p) {
    switch (*p) {
    case '\\':
      if (++p == end) {
        return -1;
      }

      switch (*p) {
      case '"':
      case '\\':
        break;
      default:
        return -1;
      }

      break;
    case '"':
      if (dest) {
        dest->type = NGHTTP3_SF_VALUE_TYPE_STRING;
        dest->s.base = begin + 1;
        dest->s.len = (size_t)(p - dest->s.base);
      }

      ++p;

      return p - begin;
    default:
      if (!SF_DQUOTE_CHARS[*p]) {
        return -1;
      }
    }
  }

  return -1;
}

/* Generated by genchartbl.py */
static const int SF_TOKEN_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 1 /* !    */, 0 /* "    */,
    1 /* #    */, 1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
    0 /* (    */, 0 /* )    */, 1 /* *    */, 1 /* +    */, 0 /* ,    */,
    1 /* -    */, 1 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 1 /* :    */, 0 /* ;    */,
    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
    1 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 1 /* ^    */,
    1 /* _    */, 1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 1 /* |    */,
    0 /* }    */, 1 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
    0 /* 0xff */,
};

static nghttp3_ssize sf_parse_token(nghttp3_sf_value *dest,
                                    const uint8_t *begin, const uint8_t *end) {
  const uint8_t *p = begin;

  if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
    return -1;
  }

  for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
    ;

  if (dest) {
    dest->type = NGHTTP3_SF_VALUE_TYPE_TOKEN;
    dest->s.base = begin;
    dest->s.len = (size_t)(p - begin);
  }

  return p - begin;
}

/* Generated by genchartbl.py */
static const int SF_BYTESEQ_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 0 /* !    */, 0 /* "    */,
    0 /* #    */, 0 /* $    */, 0 /* %    */, 0 /* &    */, 0 /* '    */,
    0 /* (    */, 0 /* )    */, 0 /* *    */, 1 /* +    */, 0 /* ,    */,
    0 /* -    */, 0 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
    0 /* <    */, 1 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
    1 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 0 /* ^    */,
    0 /* _    */, 0 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 0 /* |    */,
    0 /* }    */, 0 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
    0 /* 0xff */,
};

static nghttp3_ssize sf_parse_byteseq(nghttp3_sf_value *dest,
                                      const uint8_t *begin,
                                      const uint8_t *end) {
  const uint8_t *p = begin;

  if (*p++ != ':') {
    return -1;
  }

  for (; p != end; ++p) {
    switch (*p) {
    case ':':
      if (dest) {
        dest->type = NGHTTP3_SF_VALUE_TYPE_BYTESEQ;
        dest->s.base = begin + 1;
        dest->s.len = (size_t)(p - dest->s.base);
      }

      ++p;

      return p - begin;
    default:
      if (!SF_BYTESEQ_CHARS[*p]) {
        return -1;
      }
    }
  }

  return -1;
}

static nghttp3_ssize sf_parse_boolean(nghttp3_sf_value *dest,
                                      const uint8_t *begin,
                                      const uint8_t *end) {
  const uint8_t *p = begin;
  int b;

  if (*p++ != '?') {
    return -1;
  }

  if (p == end) {
    return -1;
  }

  switch (*p++) {
  case '0':
    b = 0;
    break;
  case '1':
    b = 1;
    break;
  default:
    return -1;
  }

  if (dest) {
    dest->type = NGHTTP3_SF_VALUE_TYPE_BOOLEAN;
    dest->b = b;
  }

  return p - begin;
}

static nghttp3_ssize sf_parse_bare_item(nghttp3_sf_value *dest,
                                        const uint8_t *begin,
                                        const uint8_t *end) {
  switch (*begin) {
  case '-':
  case '0':
  case '1':
  case '2':
  case '3':
  case '4':
  case '5':
  case '6':
  case '7':
  case '8':
  case '9':
    return sf_parse_integer_or_decimal(dest, begin, end);
  case '"':
    return sf_parse_string(dest, begin, end);
  case '*':
    return sf_parse_token(dest, begin, end);
  case ':':
    return sf_parse_byteseq(dest, begin, end);
  case '?':
    return sf_parse_boolean(dest, begin, end);
  default:
    if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
      return sf_parse_token(dest, begin, end);
    }
    return -1;
  }
}

#define sf_discard_sp_end_err(BEGIN, END, ERR)                                 \
  for (;; ++(BEGIN)) {                                                         \
    if ((BEGIN) == (END)) {                                                    \
      return (ERR);                                                            \
    }                                                                          \
    if (*(BEGIN) != ' ') {                                                     \
      break;                                                                   \
    }                                                                          \
  }

static nghttp3_ssize sf_parse_params(const uint8_t *begin, const uint8_t *end) {
  const uint8_t *p = begin;
  nghttp3_ssize slen;

  for (; p != end && *p == ';';) {
    ++p;

    sf_discard_sp_end_err(p, end, -1);

    slen = sf_parse_key(p, end);
    if (slen < 0) {
      return -1;
    }

    p += slen;

    if (p == end || *p != '=') {
      /* Boolean true */
    } else if (++p == end) {
      return -1;
    } else {
      slen = sf_parse_bare_item(NULL, p, end);
      if (slen < 0) {
        return -1;
      }

      p += slen;
    }
  }

  return p - begin;
}

static nghttp3_ssize sf_parse_item(nghttp3_sf_value *dest, const uint8_t *begin,
                                   const uint8_t *end) {
  const uint8_t *p = begin;
  nghttp3_ssize slen;

  slen = sf_parse_bare_item(dest, p, end);
  if (slen < 0) {
    return -1;
  }

  p += slen;

  slen = sf_parse_params(p, end);
  if (slen < 0) {
    return -1;
  }

  p += slen;

  return p - begin;
}

nghttp3_ssize nghttp3_sf_parse_item(nghttp3_sf_value *dest,
                                    const uint8_t *begin, const uint8_t *end) {
  return sf_parse_item(dest, begin, end);
}

static nghttp3_ssize sf_parse_inner_list(nghttp3_sf_value *dest,
                                         const uint8_t *begin,
                                         const uint8_t *end) {
  const uint8_t *p = begin;
  nghttp3_ssize slen;

  if (*p++ != '(') {
    return -1;
  }

  for (;;) {
    sf_discard_sp_end_err(p, end, -1);

    if (*p == ')') {
      ++p;

      slen = sf_parse_params(p, end);
      if (slen < 0) {
        return -1;
      }

      p += slen;

      if (dest) {
        dest->type = NGHTTP3_SF_VALUE_TYPE_INNER_LIST;
      }

      return p - begin;
    }

    slen = sf_parse_item(NULL, p, end);
    if (slen < 0) {
      return -1;
    }

    p += slen;

    if (p == end || (*p != ' ' && *p != ')')) {
      return -1;
    }
  }
}

nghttp3_ssize nghttp3_sf_parse_inner_list(nghttp3_sf_value *dest,
                                          const uint8_t *begin,
                                          const uint8_t *end) {
  return sf_parse_inner_list(dest, begin, end);
}

static nghttp3_ssize sf_parse_item_or_inner_list(nghttp3_sf_value *dest,
                                                 const uint8_t *begin,
                                                 const uint8_t *end) {
  if (*begin == '(') {
    return sf_parse_inner_list(dest, begin, end);
  }

  return sf_parse_item(dest, begin, end);
}

#define sf_discard_ows(BEGIN, END)                                             \
  for (;; ++(BEGIN)) {                                                         \
    if ((BEGIN) == (END)) {                                                    \
      goto fin;                                                                \
    }                                                                          \
    if (*(BEGIN) != ' ' && *(BEGIN) != '\t') {                                 \
      break;                                                                   \
    }                                                                          \
  }

#define sf_discard_ows_end_err(BEGIN, END, ERR)                                \
  for (;; ++(BEGIN)) {                                                         \
    if ((BEGIN) == (END)) {                                                    \
      return (ERR);                                                            \
    }                                                                          \
    if (*(BEGIN) != ' ' && *(BEGIN) != '\t') {                                 \
      break;                                                                   \
    }                                                                          \
  }

int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value,
                                size_t valuelen) {
  const uint8_t *p = value, *end = value + valuelen;
  nghttp3_ssize slen;
  nghttp3_sf_value val;
  nghttp3_pri pri = *dest;
  const uint8_t *key;
  size_t keylen;

  for (; p != end && *p == ' '; ++p)
    ;

  for (; p != end;) {
    slen = sf_parse_key(p, end);
    if (slen < 0) {
      return NGHTTP3_ERR_INVALID_ARGUMENT;
    }

    key = p;
    keylen = (size_t)slen;

    p += slen;

    if (p == end || *p != '=') {
      /* Boolean true */
      val.type = NGHTTP3_SF_VALUE_TYPE_BOOLEAN;
      val.b = 1;

      slen = sf_parse_params(p, end);
      if (slen < 0) {
        return NGHTTP3_ERR_INVALID_ARGUMENT;
      }
    } else if (++p == end) {
      return NGHTTP3_ERR_INVALID_ARGUMENT;
    } else {
      slen = sf_parse_item_or_inner_list(&val, p, end);
      if (slen < 0) {
        return NGHTTP3_ERR_INVALID_ARGUMENT;
      }
    }

    p += slen;

    if (keylen == 1) {
      switch (key[0]) {
      case 'i':
        if (val.type != NGHTTP3_SF_VALUE_TYPE_BOOLEAN) {
          return NGHTTP3_ERR_INVALID_ARGUMENT;
        }

        pri.inc = val.b;

        break;
      case 'u':
        if (val.type != NGHTTP3_SF_VALUE_TYPE_INTEGER ||
            val.i < NGHTTP3_URGENCY_HIGH || NGHTTP3_URGENCY_LOW < val.i) {
          return NGHTTP3_ERR_INVALID_ARGUMENT;
        }

        pri.urgency = (uint32_t)val.i;

        break;
      }
    }

    sf_discard_ows(p, end);

    if (*p++ != ',') {
      return NGHTTP3_ERR_INVALID_ARGUMENT;
    }

    sf_discard_ows_end_err(p, end, NGHTTP3_ERR_INVALID_ARGUMENT);
  }

fin:
  *dest = pri;

  return 0;
}

static int http_request_on_header(nghttp3_http_state *http,
                                  nghttp3_qpack_nv *nv, int trailers,
                                  int connect_protocol) {
  nghttp3_pri pri;

  if (nv->name->base[0] == ':') {
    if (trailers ||
        (http->flags & NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
  }

  switch (nv->token) {
  case NGHTTP3_QPACK_TOKEN__AUTHORITY:
    if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__AUTHORITY)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  case NGHTTP3_QPACK_TOKEN__METHOD:
    if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__METHOD)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    switch (nv->value->len) {
    case 4:
      if (lstreq("HEAD", nv->value->base, nv->value->len)) {
        http->flags |= NGHTTP3_HTTP_FLAG_METH_HEAD;
      }
      break;
    case 7:
      switch (nv->value->base[6]) {
      case 'T':
        if (lstreq("CONNECT", nv->value->base, nv->value->len)) {
          http->flags |= NGHTTP3_HTTP_FLAG_METH_CONNECT;
        }
        break;
      case 'S':
        if (lstreq("OPTIONS", nv->value->base, nv->value->len)) {
          http->flags |= NGHTTP3_HTTP_FLAG_METH_OPTIONS;
        }
        break;
      }
      break;
    }
    break;
  case NGHTTP3_QPACK_TOKEN__PATH:
    if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__PATH)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    if (nv->value->base[0] == '/') {
      http->flags |= NGHTTP3_HTTP_FLAG_PATH_REGULAR;
    } else if (nv->value->len == 1 && nv->value->base[0] == '*') {
      http->flags |= NGHTTP3_HTTP_FLAG_PATH_ASTERISK;
    }
    break;
  case NGHTTP3_QPACK_TOKEN__SCHEME:
    if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__SCHEME)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    /* scheme is case-insensitive:
       https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 */
    if (lstrieq("http", nv->value->base, nv->value->len) ||
        lstrieq("https", nv->value->base, nv->value->len)) {
      http->flags |= NGHTTP3_HTTP_FLAG_SCHEME_HTTP;
    }
    break;
  case NGHTTP3_QPACK_TOKEN__PROTOCOL:
    if (!connect_protocol) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }

    if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__PROTOCOL)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  case NGHTTP3_QPACK_TOKEN_HOST:
    if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG_HOST)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  case NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH: {
    /* https://tools.ietf.org/html/rfc7230#section-4.1.2: A sender
       MUST NOT generate a trailer that contains a field necessary for
       message framing (e.g., Transfer-Encoding and Content-Length),
       ... */
    if (trailers) {
      return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
    }
    if (http->content_length != -1) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    http->content_length = parse_uint(nv->value->base, nv->value->len);
    if (http->content_length == -1) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  }
  /* disallowed header fields */
  case NGHTTP3_QPACK_TOKEN_CONNECTION:
  case NGHTTP3_QPACK_TOKEN_KEEP_ALIVE:
  case NGHTTP3_QPACK_TOKEN_PROXY_CONNECTION:
  case NGHTTP3_QPACK_TOKEN_TRANSFER_ENCODING:
  case NGHTTP3_QPACK_TOKEN_UPGRADE:
    return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
  case NGHTTP3_QPACK_TOKEN_TE:
    if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  case NGHTTP3_QPACK_TOKEN_PRIORITY:
    if (!trailers && !(http->flags & NGHTTP3_HTTP_FLAG_BAD_PRIORITY)) {
      pri.urgency = nghttp3_pri_uint8_urgency(http->pri);
      pri.inc = nghttp3_pri_uint8_inc(http->pri);
      if (nghttp3_http_parse_priority(&pri, nv->value->base, nv->value->len) ==
          0) {
        http->pri = nghttp3_pri_to_uint8(&pri);
        http->flags |= NGHTTP3_HTTP_FLAG_PRIORITY;
      } else {
        http->flags &= ~NGHTTP3_HTTP_FLAG_PRIORITY;
        http->flags |= NGHTTP3_HTTP_FLAG_BAD_PRIORITY;
      }
    }
    break;
  default:
    if (nv->name->base[0] == ':') {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
  }

  return 0;
}

static int http_response_on_header(nghttp3_http_state *http,
                                   nghttp3_qpack_nv *nv, int trailers) {
  if (nv->name->base[0] == ':') {
    if (trailers ||
        (http->flags & NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
  }

  switch (nv->token) {
  case NGHTTP3_QPACK_TOKEN__STATUS: {
    if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__STATUS)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    if (nv->value->len != 3) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    http->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
    if (http->status_code < 100 || http->status_code == 101) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  }
  case NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH: {
    /* https://tools.ietf.org/html/rfc7230#section-4.1.2: A sender
       MUST NOT generate a trailer that contains a field necessary for
       message framing (e.g., Transfer-Encoding and Content-Length),
       ... */
    if (trailers) {
      return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
    }
    if (http->status_code == 204) {
      /* content-length header field in 204 response is prohibited by
         RFC 7230.  But some widely used servers send content-length:
         0.  Until they get fixed, we ignore it. */
      if (http->content_length != -1) {
        /* Found multiple content-length field */
        return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
      }
      if (!lstrieq("0", nv->value->base, nv->value->len)) {
        return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
      }
      http->content_length = 0;
      return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
    }
    if (http->status_code / 100 == 1) {
      return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
    }
    /* https://tools.ietf.org/html/rfc7230#section-3.3.3 */
    if (http->status_code / 100 == 2 &&
        (http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT)) {
      return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
    }
    if (http->content_length != -1) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    http->content_length = parse_uint(nv->value->base, nv->value->len);
    if (http->content_length == -1) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  }
  /* disallowed header fields */
  case NGHTTP3_QPACK_TOKEN_CONNECTION:
  case NGHTTP3_QPACK_TOKEN_KEEP_ALIVE:
  case NGHTTP3_QPACK_TOKEN_PROXY_CONNECTION:
  case NGHTTP3_QPACK_TOKEN_TRANSFER_ENCODING:
  case NGHTTP3_QPACK_TOKEN_UPGRADE:
    return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
  case NGHTTP3_QPACK_TOKEN_TE:
    if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    break;
  default:
    if (nv->name->base[0] == ':') {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
  }

  return 0;
}

/* Generated by genauthroitychartbl.py */
static char VALID_AUTHORITY_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
    0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
    0 /* BS   */, 0 /* HT   */, 0 /* LF   */, 0 /* VT   */,
    0 /* FF   */, 0 /* CR   */, 0 /* SO   */, 0 /* SI   */,
    0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */,
    0 /* CAN  */, 0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */,
    0 /* FS   */, 0 /* GS   */, 0 /* RS   */, 0 /* US   */,
    0 /* SPC  */, 1 /* !    */, 0 /* "    */, 0 /* #    */,
    1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
    1 /* (    */, 1 /* )    */, 1 /* *    */, 1 /* +    */,
    1 /* ,    */, 1 /* -    */, 1 /* .    */, 0 /* /    */,
    1 /* 0    */, 1 /* 1    */, 1 /* 2    */, 1 /* 3    */,
    1 /* 4    */, 1 /* 5    */, 1 /* 6    */, 1 /* 7    */,
    1 /* 8    */, 1 /* 9    */, 1 /* :    */, 1 /* ;    */,
    0 /* <    */, 1 /* =    */, 0 /* >    */, 0 /* ?    */,
    1 /* @    */, 1 /* A    */, 1 /* B    */, 1 /* C    */,
    1 /* D    */, 1 /* E    */, 1 /* F    */, 1 /* G    */,
    1 /* H    */, 1 /* I    */, 1 /* J    */, 1 /* K    */,
    1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */,
    1 /* T    */, 1 /* U    */, 1 /* V    */, 1 /* W    */,
    1 /* X    */, 1 /* Y    */, 1 /* Z    */, 1 /* [    */,
    0 /* \    */, 1 /* ]    */, 0 /* ^    */, 1 /* _    */,
    0 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */,
    1 /* h    */, 1 /* i    */, 1 /* j    */, 1 /* k    */,
    1 /* l    */, 1 /* m    */, 1 /* n    */, 1 /* o    */,
    1 /* p    */, 1 /* q    */, 1 /* r    */, 1 /* s    */,
    1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */,
    0 /* |    */, 0 /* }    */, 1 /* ~    */, 0 /* DEL  */,
    0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
    0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
    0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
    0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
    0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
    0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
    0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
    0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
    0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
    0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
    0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
    0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
    0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
    0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
    0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
    0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
    0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
    0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
    0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
    0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
    0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
    0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
    0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
    0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
    0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
    0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
};

static int check_authority(const uint8_t *value, size_t len) {
  const uint8_t *last;
  for (last = value + len; value != last; ++value) {
    if (!VALID_AUTHORITY_CHARS[*value]) {
      return 0;
    }
  }
  return 1;
}

static int check_scheme(const uint8_t *value, size_t len) {
  const uint8_t *last;
  if (len == 0) {
    return 0;
  }

  if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
    return 0;
  }

  last = value + len;
  ++value;

  for (; value != last; ++value) {
    if (!(('A' <= *value && *value <= 'Z') ||
          ('a' <= *value && *value <= 'z') ||
          ('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
          *value == '.')) {
      return 0;
    }
  }
  return 1;
}

/* Generated by genmethodchartbl.py */
static char VALID_METHOD_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
    0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
    0 /* BS   */, 0 /* HT   */, 0 /* LF   */, 0 /* VT   */,
    0 /* FF   */, 0 /* CR   */, 0 /* SO   */, 0 /* SI   */,
    0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */,
    0 /* CAN  */, 0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */,
    0 /* FS   */, 0 /* GS   */, 0 /* RS   */, 0 /* US   */,
    0 /* SPC  */, 1 /* !    */, 0 /* "    */, 1 /* #    */,
    1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
    0 /* (    */, 0 /* )    */, 1 /* *    */, 1 /* +    */,
    0 /* ,    */, 1 /* -    */, 1 /* .    */, 0 /* /    */,
    1 /* 0    */, 1 /* 1    */, 1 /* 2    */, 1 /* 3    */,
    1 /* 4    */, 1 /* 5    */, 1 /* 6    */, 1 /* 7    */,
    1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */,
    0 /* @    */, 1 /* A    */, 1 /* B    */, 1 /* C    */,
    1 /* D    */, 1 /* E    */, 1 /* F    */, 1 /* G    */,
    1 /* H    */, 1 /* I    */, 1 /* J    */, 1 /* K    */,
    1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */,
    1 /* T    */, 1 /* U    */, 1 /* V    */, 1 /* W    */,
    1 /* X    */, 1 /* Y    */, 1 /* Z    */, 0 /* [    */,
    0 /* \    */, 0 /* ]    */, 1 /* ^    */, 1 /* _    */,
    1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */,
    1 /* h    */, 1 /* i    */, 1 /* j    */, 1 /* k    */,
    1 /* l    */, 1 /* m    */, 1 /* n    */, 1 /* o    */,
    1 /* p    */, 1 /* q    */, 1 /* r    */, 1 /* s    */,
    1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */,
    1 /* |    */, 0 /* }    */, 1 /* ~    */, 0 /* DEL  */,
    0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
    0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
    0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
    0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
    0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
    0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
    0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
    0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
    0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
    0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
    0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
    0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
    0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
    0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
    0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
    0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
    0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
    0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
    0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
    0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
    0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
    0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
    0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
    0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
    0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
    0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
};

static int check_method(const uint8_t *value, size_t len) {
  const uint8_t *last;
  if (len == 0) {
    return 0;
  }
  for (last = value + len; value != last; ++value) {
    if (!VALID_METHOD_CHARS[*value]) {
      return 0;
    }
  }
  return 1;
}

/* Generated by genpathchartbl.py */
static char VALID_PATH_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
    0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
    0 /* BS   */, 0 /* HT   */, 0 /* LF   */, 0 /* VT   */,
    0 /* FF   */, 0 /* CR   */, 0 /* SO   */, 0 /* SI   */,
    0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */,
    0 /* CAN  */, 0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */,
    0 /* FS   */, 0 /* GS   */, 0 /* RS   */, 0 /* US   */,
    0 /* SPC  */, 1 /* !    */, 1 /* "    */, 1 /* #    */,
    1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
    1 /* (    */, 1 /* )    */, 1 /* *    */, 1 /* +    */,
    1 /* ,    */, 1 /* -    */, 1 /* .    */, 1 /* /    */,
    1 /* 0    */, 1 /* 1    */, 1 /* 2    */, 1 /* 3    */,
    1 /* 4    */, 1 /* 5    */, 1 /* 6    */, 1 /* 7    */,
    1 /* 8    */, 1 /* 9    */, 1 /* :    */, 1 /* ;    */,
    1 /* <    */, 1 /* =    */, 1 /* >    */, 1 /* ?    */,
    1 /* @    */, 1 /* A    */, 1 /* B    */, 1 /* C    */,
    1 /* D    */, 1 /* E    */, 1 /* F    */, 1 /* G    */,
    1 /* H    */, 1 /* I    */, 1 /* J    */, 1 /* K    */,
    1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */,
    1 /* T    */, 1 /* U    */, 1 /* V    */, 1 /* W    */,
    1 /* X    */, 1 /* Y    */, 1 /* Z    */, 1 /* [    */,
    1 /* \    */, 1 /* ]    */, 1 /* ^    */, 1 /* _    */,
    1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */,
    1 /* h    */, 1 /* i    */, 1 /* j    */, 1 /* k    */,
    1 /* l    */, 1 /* m    */, 1 /* n    */, 1 /* o    */,
    1 /* p    */, 1 /* q    */, 1 /* r    */, 1 /* s    */,
    1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 1 /* {    */,
    1 /* |    */, 1 /* }    */, 1 /* ~    */, 0 /* DEL  */,
    1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
    1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
    1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
    1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
    1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
    1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
    1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
    1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
    1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
    1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
    1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
    1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
    1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
    1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
    1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
    1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
    1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
    1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
    1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
    1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
    1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
    1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
    1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
    1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
    1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
    1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
    1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
    1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
    1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
    1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
    1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
    1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
};

static int check_path(const uint8_t *value, size_t len) {
  const uint8_t *last;
  for (last = value + len; value != last; ++value) {
    if (!VALID_PATH_CHARS[*value]) {
      return 0;
    }
  }
  return 1;
}

int nghttp3_http_on_header(nghttp3_http_state *http, nghttp3_qpack_nv *nv,
                           int request, int trailers, int connect_protocol) {
  int rv;
  size_t i;
  uint8_t c;

  if (!nghttp3_check_header_name(nv->name->base, nv->name->len)) {
    if (nv->name->len > 0 && nv->name->base[0] == ':') {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    /* header field name must be lower-cased without exception */
    for (i = 0; i < nv->name->len; ++i) {
      c = nv->name->base[i];
      if ('A' <= c && c <= 'Z') {
        return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
      }
    }
    /* When ignoring regular header fields, we set this flag so that
       we still enforce header field ordering rule for pseudo header
       fields. */
    http->flags |= NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
    return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
  }

  assert(nv->name->len > 0);

  switch (nv->token) {
  case NGHTTP3_QPACK_TOKEN__METHOD:
    rv = check_method(nv->value->base, nv->value->len);
    break;
  case NGHTTP3_QPACK_TOKEN__SCHEME:
    rv = check_scheme(nv->value->base, nv->value->len);
    break;
  case NGHTTP3_QPACK_TOKEN__AUTHORITY:
  case NGHTTP3_QPACK_TOKEN_HOST:
    if (request) {
      rv = check_authority(nv->value->base, nv->value->len);
    } else {
      /* The use of host field in response field section is
         undefined. */
      rv = nghttp3_check_header_value(nv->value->base, nv->value->len);
    }
    break;
  case NGHTTP3_QPACK_TOKEN__PATH:
    rv = check_path(nv->value->base, nv->value->len);
    break;
  default:
    rv = nghttp3_check_header_value(nv->value->base, nv->value->len);
  }

  if (rv == 0) {
    if (nv->name->base[0] == ':') {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    /* When ignoring regular header fields, we set this flag so that
       we still enforce header field ordering rule for pseudo header
       fields. */
    http->flags |= NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
    return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
  }

  if (request) {
    rv = http_request_on_header(http, nv, trailers, connect_protocol);
  } else {
    rv = http_response_on_header(http, nv, trailers);
  }

  if (nv->name->base[0] != ':') {
    switch (rv) {
    case 0:
    case NGHTTP3_ERR_REMOVE_HTTP_HEADER:
      http->flags |= NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
      break;
    }
  }

  return rv;
}

int nghttp3_http_on_request_headers(nghttp3_http_state *http) {
  if (!(http->flags & NGHTTP3_HTTP_FLAG__PROTOCOL) &&
      (http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT)) {
    if ((http->flags & (NGHTTP3_HTTP_FLAG__SCHEME | NGHTTP3_HTTP_FLAG__PATH)) ||
        (http->flags & NGHTTP3_HTTP_FLAG__AUTHORITY) == 0) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    http->content_length = -1;
  } else {
    if ((http->flags & NGHTTP3_HTTP_FLAG_REQ_HEADERS) !=
            NGHTTP3_HTTP_FLAG_REQ_HEADERS ||
        (http->flags &
         (NGHTTP3_HTTP_FLAG__AUTHORITY | NGHTTP3_HTTP_FLAG_HOST)) == 0) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    if ((http->flags & NGHTTP3_HTTP_FLAG__PROTOCOL) &&
        ((http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) == 0 ||
         (http->flags & NGHTTP3_HTTP_FLAG__AUTHORITY) == 0)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
    if (!check_path_flags(http)) {
      return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
    }
  }

  return 0;
}

int nghttp3_http_on_response_headers(nghttp3_http_state *http) {
  if ((http->flags & NGHTTP3_HTTP_FLAG__STATUS) == 0) {
    return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
  }

  if (http->status_code / 100 == 1) {
    /* non-final response */
    http->flags = (http->flags & NGHTTP3_HTTP_FLAG_METH_ALL) |
                  NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
    http->content_length = -1;
    http->status_code = -1;
    return 0;
  }

  http->flags &= ~NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE;

  if (!expect_response_body(http)) {
    http->content_length = 0;
  } else if (http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) {
    http->content_length = -1;
  }

  return 0;
}

int nghttp3_http_on_remote_end_stream(nghttp3_stream *stream) {
  if ((stream->rx.http.flags & NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
      (stream->rx.http.content_length != -1 &&
       stream->rx.http.content_length != stream->rx.http.recv_content_length)) {
    return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
  }

  return 0;
}

int nghttp3_http_on_data_chunk(nghttp3_stream *stream, size_t n) {
  stream->rx.http.recv_content_length += (int64_t)n;

  if ((stream->rx.http.flags & NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
      (stream->rx.http.content_length != -1 &&
       stream->rx.http.recv_content_length > stream->rx.http.content_length)) {
    return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
  }

  return 0;
}

void nghttp3_http_record_request_method(nghttp3_stream *stream,
                                        const nghttp3_nv *nva, size_t nvlen) {
  size_t i;
  const nghttp3_nv *nv;

  /* TODO we should do this strictly. */
  for (i = 0; i < nvlen; ++i) {
    nv = &nva[i];
    if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
          memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
      continue;
    }
    if (lstreq("CONNECT", nv->value, nv->valuelen)) {
      stream->rx.http.flags |= NGHTTP3_HTTP_FLAG_METH_CONNECT;
      return;
    }
    if (lstreq("HEAD", nv->value, nv->valuelen)) {
      stream->rx.http.flags |= NGHTTP3_HTTP_FLAG_METH_HEAD;
      return;
    }
    return;
  }
}

/* Generated by gennmchartbl.py */
static const int VALID_HD_NAME_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
    0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
    0 /* BS   */, 0 /* HT   */, 0 /* LF   */, 0 /* VT   */,
    0 /* FF   */, 0 /* CR   */, 0 /* SO   */, 0 /* SI   */,
    0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */,
    0 /* CAN  */, 0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */,
    0 /* FS   */, 0 /* GS   */, 0 /* RS   */, 0 /* US   */,
    0 /* SPC  */, 1 /* !    */, 0 /* "    */, 1 /* #    */,
    1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
    0 /* (    */, 0 /* )    */, 1 /* *    */, 1 /* +    */,
    0 /* ,    */, 1 /* -    */, 1 /* .    */, 0 /* /    */,
    1 /* 0    */, 1 /* 1    */, 1 /* 2    */, 1 /* 3    */,
    1 /* 4    */, 1 /* 5    */, 1 /* 6    */, 1 /* 7    */,
    1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */,
    0 /* @    */, 0 /* A    */, 0 /* B    */, 0 /* C    */,
    0 /* D    */, 0 /* E    */, 0 /* F    */, 0 /* G    */,
    0 /* H    */, 0 /* I    */, 0 /* J    */, 0 /* K    */,
    0 /* L    */, 0 /* M    */, 0 /* N    */, 0 /* O    */,
    0 /* P    */, 0 /* Q    */, 0 /* R    */, 0 /* S    */,
    0 /* T    */, 0 /* U    */, 0 /* V    */, 0 /* W    */,
    0 /* X    */, 0 /* Y    */, 0 /* Z    */, 0 /* [    */,
    0 /* \    */, 0 /* ]    */, 1 /* ^    */, 1 /* _    */,
    1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */,
    1 /* h    */, 1 /* i    */, 1 /* j    */, 1 /* k    */,
    1 /* l    */, 1 /* m    */, 1 /* n    */, 1 /* o    */,
    1 /* p    */, 1 /* q    */, 1 /* r    */, 1 /* s    */,
    1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */,
    1 /* |    */, 0 /* }    */, 1 /* ~    */, 0 /* DEL  */,
    0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
    0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
    0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
    0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
    0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
    0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
    0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
    0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
    0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
    0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
    0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
    0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
    0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
    0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
    0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
    0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
    0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
    0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
    0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
    0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
    0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
    0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
    0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
    0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
    0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
    0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
};

int nghttp3_check_header_name(const uint8_t *name, size_t len) {
  const uint8_t *last;
  if (len == 0) {
    return 0;
  }
  if (*name == ':') {
    if (len == 1) {
      return 0;
    }
    ++name;
    --len;
  }
  for (last = name + len; name != last; ++name) {
    if (!VALID_HD_NAME_CHARS[*name]) {
      return 0;
    }
  }
  return 1;
}

/* Generated by genvchartbl.py */
static const int VALID_HD_VALUE_CHARS[] = {
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */,
    0 /* EOT  */, 0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */,
    0 /* BS   */, 1 /* HT   */, 0 /* LF   */, 0 /* VT   */,
    0 /* FF   */, 0 /* CR   */, 0 /* SO   */, 0 /* SI   */,
    0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */,
    0 /* CAN  */, 0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */,
    0 /* FS   */, 0 /* GS   */, 0 /* RS   */, 0 /* US   */,
    1 /* SPC  */, 1 /* !    */, 1 /* "    */, 1 /* #    */,
    1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
    1 /* (    */, 1 /* )    */, 1 /* *    */, 1 /* +    */,
    1 /* ,    */, 1 /* -    */, 1 /* .    */, 1 /* /    */,
    1 /* 0    */, 1 /* 1    */, 1 /* 2    */, 1 /* 3    */,
    1 /* 4    */, 1 /* 5    */, 1 /* 6    */, 1 /* 7    */,
    1 /* 8    */, 1 /* 9    */, 1 /* :    */, 1 /* ;    */,
    1 /* <    */, 1 /* =    */, 1 /* >    */, 1 /* ?    */,
    1 /* @    */, 1 /* A    */, 1 /* B    */, 1 /* C    */,
    1 /* D    */, 1 /* E    */, 1 /* F    */, 1 /* G    */,
    1 /* H    */, 1 /* I    */, 1 /* J    */, 1 /* K    */,
    1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */,
    1 /* T    */, 1 /* U    */, 1 /* V    */, 1 /* W    */,
    1 /* X    */, 1 /* Y    */, 1 /* Z    */, 1 /* [    */,
    1 /* \    */, 1 /* ]    */, 1 /* ^    */, 1 /* _    */,
    1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */,
    1 /* h    */, 1 /* i    */, 1 /* j    */, 1 /* k    */,
    1 /* l    */, 1 /* m    */, 1 /* n    */, 1 /* o    */,
    1 /* p    */, 1 /* q    */, 1 /* r    */, 1 /* s    */,
    1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
    1 /* x    */, 1 /* y    */, 1 /* z    */, 1 /* {    */,
    1 /* |    */, 1 /* }    */, 1 /* ~    */, 0 /* DEL  */,
    1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
    1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
    1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
    1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
    1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
    1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
    1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
    1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
    1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
    1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
    1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
    1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
    1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
    1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
    1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
    1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
    1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
    1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
    1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
    1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
    1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
    1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
    1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
    1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
    1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
    1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
    1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
    1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
    1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
    1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
    1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
    1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
};

int nghttp3_check_header_value(const uint8_t *value, size_t len) {
  const uint8_t *last;

  switch (len) {
  case 0:
    return 1;
  case 1:
    return !(*value == ' ' || *value == '\t');
  default:
    if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' ||
        *(value + len - 1) == '\t') {
      return 0;
    }
  }

  for (last = value + len; value != last; ++value) {
    if (!VALID_HD_VALUE_CHARS[*value]) {
      return 0;
    }
  }
  return 1;
}

Kontol Shell Bypass