summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/lib/http2
diff options
context:
space:
mode:
Diffstat (limited to 'web/server/h2o/libh2o/lib/http2')
-rw-r--r--web/server/h2o/libh2o/lib/http2/cache_digests.c201
-rw-r--r--web/server/h2o/libh2o/lib/http2/casper.c205
-rw-r--r--web/server/h2o/libh2o/lib/http2/connection.c1419
-rw-r--r--web/server/h2o/libh2o/lib/http2/frame.c290
-rw-r--r--web/server/h2o/libh2o/lib/http2/hpack.c917
-rw-r--r--web/server/h2o/libh2o/lib/http2/hpack_huffman_table.h4954
-rw-r--r--web/server/h2o/libh2o/lib/http2/hpack_static_table.h87
-rw-r--r--web/server/h2o/libh2o/lib/http2/http2_debug_state.c194
-rw-r--r--web/server/h2o/libh2o/lib/http2/scheduler.c365
-rw-r--r--web/server/h2o/libh2o/lib/http2/stream.c410
10 files changed, 9042 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/lib/http2/cache_digests.c b/web/server/h2o/libh2o/lib/http2/cache_digests.c
new file mode 100644
index 000000000..fa28bd238
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/cache_digests.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2016 DeNA Co., Ltd., Kazuho Oku
+ *
+ * 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 <limits.h>
+#include <openssl/sha.h>
+#include <stdlib.h>
+#include "golombset.h"
+#include "h2o/string_.h"
+#include "h2o/cache_digests.h"
+
+struct st_h2o_cache_digests_frame_t {
+ H2O_VECTOR(uint64_t) keys;
+ unsigned capacity_bits;
+};
+
+static void dispose_frame_vector(h2o_cache_digests_frame_vector_t *v)
+{
+ size_t i;
+ for (i = 0; i != v->size; ++i)
+ free(v->entries[i].keys.entries);
+ free(v->entries);
+}
+
+static void dispose_digests(h2o_cache_digests_t *digests)
+{
+ dispose_frame_vector(&digests->fresh.url_only);
+ dispose_frame_vector(&digests->fresh.url_and_etag);
+}
+
+void h2o_cache_digests_destroy(h2o_cache_digests_t *digests)
+{
+ dispose_digests(digests);
+ free(digests);
+}
+
+static void load_digest(h2o_cache_digests_t **digests, const char *gcs_base64, size_t gcs_base64_len, int with_validators,
+ int complete)
+{
+ h2o_cache_digests_frame_t frame = {{NULL}};
+ h2o_iovec_t gcs_bin;
+ struct st_golombset_decode_t ctx = {NULL};
+ uint64_t nbits, pbits;
+
+ /* decode base64 */
+ if ((gcs_bin = h2o_decode_base64url(NULL, gcs_base64, gcs_base64_len)).base == NULL)
+ goto Exit;
+
+ /* prepare GCS context */
+ ctx.src = (void *)(gcs_bin.base - 1);
+ ctx.src_max = (void *)(gcs_bin.base + gcs_bin.len);
+ ctx.src_shift = 0;
+
+ /* decode nbits and pbits */
+ if (golombset_decode_bits(&ctx, 5, &nbits) != 0 || golombset_decode_bits(&ctx, 5, &pbits) != 0)
+ goto Exit;
+ frame.capacity_bits = (unsigned)(nbits + pbits);
+
+ /* decode the values */
+ uint64_t value = UINT64_MAX, decoded;
+ while (golombset_decode_value(&ctx, (unsigned)pbits, &decoded) == 0) {
+ value += decoded + 1;
+ if (value >= (uint64_t)1 << frame.capacity_bits)
+ goto Exit;
+ h2o_vector_reserve(NULL, &frame.keys, frame.keys.size + 1);
+ frame.keys.entries[frame.keys.size++] = value;
+ }
+
+ /* store the result */
+ if (*digests == NULL) {
+ *digests = h2o_mem_alloc(sizeof(**digests));
+ **digests = (h2o_cache_digests_t){{{NULL}}};
+ }
+ h2o_cache_digests_frame_vector_t *target = with_validators ? &(*digests)->fresh.url_and_etag : &(*digests)->fresh.url_only;
+ h2o_vector_reserve(NULL, target, target->size + 1);
+ target->entries[target->size++] = frame;
+ frame = (h2o_cache_digests_frame_t){{NULL}};
+ (*digests)->fresh.complete = complete;
+
+Exit:
+ free(frame.keys.entries);
+ free(gcs_bin.base);
+}
+
+void h2o_cache_digests_load_header(h2o_cache_digests_t **digests, const char *value, size_t len)
+{
+ h2o_iovec_t iter = h2o_iovec_init(value, len);
+ const char *token;
+ size_t token_len;
+
+ do {
+ const char *gcs_base64;
+ size_t gcs_base64_len;
+ int reset = 0, validators = 0, complete = 0, skip = 0;
+ h2o_iovec_t token_value;
+
+ if ((gcs_base64 = h2o_next_token(&iter, ';', &gcs_base64_len, NULL)) == NULL)
+ return;
+ while ((token = h2o_next_token(&iter, ';', &token_len, &token_value)) != NULL &&
+ !h2o_memis(token, token_len, H2O_STRLIT(","))) {
+ if (h2o_lcstris(token, token_len, H2O_STRLIT("reset"))) {
+ reset = 1;
+ } else if (h2o_lcstris(token, token_len, H2O_STRLIT("validators"))) {
+ validators = 1;
+ } else if (h2o_lcstris(token, token_len, H2O_STRLIT("complete"))) {
+ complete = 1;
+ } else {
+ skip = 1;
+ }
+ }
+
+ if (reset && *digests != NULL) {
+ h2o_cache_digests_destroy(*digests);
+ *digests = NULL;
+ }
+
+ if (skip) {
+ /* not supported for the time being */
+ } else {
+ load_digest(digests, gcs_base64, gcs_base64_len, validators, complete);
+ }
+ } while (token != NULL);
+}
+
+static uint64_t calc_hash(const char *url, size_t url_len, const char *etag, size_t etag_len)
+{
+ SHA256_CTX ctx;
+ union {
+ unsigned char bytes[SHA256_DIGEST_LENGTH];
+ uint64_t u64;
+ } md;
+
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, url, url_len);
+ SHA256_Update(&ctx, etag, etag_len);
+ SHA256_Final(md.bytes, &ctx);
+
+ if (*(uint16_t *)"\xde\xad" == 0xdead)
+ return md.u64;
+ else
+ return __builtin_bswap64(md.u64);
+}
+
+static int cmp_key(const void *_x, const void *_y)
+{
+ uint64_t x = *(uint64_t *)_x, y = *(uint64_t *)_y;
+
+ if (x < y) {
+ return -1;
+ } else if (x > y) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int lookup(h2o_cache_digests_frame_vector_t *vector, const char *url, size_t url_len, const char *etag, size_t etag_len,
+ int is_fresh, int is_complete)
+{
+ if (vector->size != 0) {
+ uint64_t hash = calc_hash(url, url_len, etag, etag_len);
+ size_t i = 0;
+ do {
+ h2o_cache_digests_frame_t *frame = vector->entries + i;
+ uint64_t key = hash >> (64 - frame->capacity_bits);
+ if (frame->keys.entries != NULL &&
+ bsearch(&key, frame->keys.entries, frame->keys.size, sizeof(frame->keys.entries[0]), cmp_key) != NULL)
+ return is_fresh ? H2O_CACHE_DIGESTS_STATE_FRESH : H2O_CACHE_DIGESTS_STATE_STALE;
+ } while (++i != vector->size);
+ }
+
+ return is_complete ? H2O_CACHE_DIGESTS_STATE_NOT_CACHED : H2O_CACHE_DIGESTS_STATE_UNKNOWN;
+}
+
+h2o_cache_digests_state_t h2o_cache_digests_lookup_by_url(h2o_cache_digests_t *digests, const char *url, size_t url_len)
+{
+ return lookup(&digests->fresh.url_only, url, url_len, "", 0, 1, digests->fresh.complete);
+}
+
+h2o_cache_digests_state_t h2o_cache_digests_lookup_by_url_and_etag(h2o_cache_digests_t *digests, const char *url, size_t url_len,
+ const char *etag, size_t etag_len)
+{
+ return lookup(&digests->fresh.url_and_etag, url, url_len, etag, etag_len, 1, digests->fresh.complete);
+}
diff --git a/web/server/h2o/libh2o/lib/http2/casper.c b/web/server/h2o/libh2o/lib/http2/casper.c
new file mode 100644
index 000000000..56e00d71f
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/casper.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku
+ *
+ * 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 <openssl/sha.h>
+#include "golombset.h"
+#include "h2o/string_.h"
+#include "h2o/http2_casper.h"
+
+#define COOKIE_NAME "h2o_casper"
+#define COOKIE_ATTRIBUTES "; Path=/; Expires=Tue, 01 Jan 2030 00:00:00 GMT; Secure"
+
+struct st_h2o_http2_casper_t {
+ H2O_VECTOR(uint64_t) keys;
+ unsigned capacity_bits;
+ unsigned remainder_bits;
+ h2o_iovec_t cookie_cache;
+};
+
+static unsigned calc_key(h2o_http2_casper_t *casper, const char *path, size_t path_len)
+{
+ SHA_CTX ctx;
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, path, path_len);
+
+ union {
+ unsigned key;
+ unsigned char bytes[SHA_DIGEST_LENGTH];
+ } md;
+ SHA1_Final(md.bytes, &ctx);
+
+ return md.key & ((1 << casper->capacity_bits) - 1);
+}
+
+h2o_http2_casper_t *h2o_http2_casper_create(unsigned capacity_bits, unsigned remainder_bits)
+{
+ h2o_http2_casper_t *casper = h2o_mem_alloc(sizeof(*casper));
+
+ memset(&casper->keys, 0, sizeof(casper->keys));
+ casper->capacity_bits = capacity_bits;
+ casper->remainder_bits = remainder_bits;
+ casper->cookie_cache = (h2o_iovec_t){NULL};
+
+ return casper;
+}
+
+void h2o_http2_casper_destroy(h2o_http2_casper_t *casper)
+{
+ free(casper->keys.entries);
+ free(casper->cookie_cache.base);
+ free(casper);
+}
+
+size_t h2o_http2_casper_num_entries(h2o_http2_casper_t *casper)
+{
+ return casper->keys.size;
+}
+
+int h2o_http2_casper_lookup(h2o_http2_casper_t *casper, const char *path, size_t path_len, int set)
+{
+ unsigned key = calc_key(casper, path, path_len);
+ size_t i;
+
+ /* FIXME use binary search */
+ for (i = 0; i != casper->keys.size; ++i)
+ if (key <= casper->keys.entries[i])
+ break;
+ if (i != casper->keys.size && key == casper->keys.entries[i])
+ return 1;
+ if (!set)
+ return 0;
+
+ /* we need to set a new value */
+ free(casper->cookie_cache.base);
+ casper->cookie_cache = (h2o_iovec_t){NULL};
+ h2o_vector_reserve(NULL, &casper->keys, casper->keys.size + 1);
+ memmove(casper->keys.entries + i + 1, casper->keys.entries + i, (casper->keys.size - i) * sizeof(casper->keys.entries[0]));
+ ++casper->keys.size;
+ casper->keys.entries[i] = key;
+ return 0;
+}
+
+void h2o_http2_casper_consume_cookie(h2o_http2_casper_t *casper, const char *cookie, size_t cookie_len)
+{
+ h2o_iovec_t binary = {NULL};
+ uint64_t tiny_keys_buf[128], *keys = tiny_keys_buf;
+
+ /* check the name of the cookie */
+ if (!(cookie_len > sizeof(COOKIE_NAME "=") - 1 && memcmp(cookie, H2O_STRLIT(COOKIE_NAME "=")) == 0))
+ goto Exit;
+
+ /* base64 decode */
+ if ((binary = h2o_decode_base64url(NULL, cookie + sizeof(COOKIE_NAME "=") - 1, cookie_len - (sizeof(COOKIE_NAME "=") - 1)))
+ .base == NULL)
+ goto Exit;
+
+ /* decode GCS, either using tiny_keys_buf or using heap */
+ size_t capacity = sizeof(tiny_keys_buf) / sizeof(tiny_keys_buf[0]), num_keys;
+ while (num_keys = capacity, golombset_decode(casper->remainder_bits, binary.base, binary.len, keys, &num_keys) != 0) {
+ if (keys != tiny_keys_buf) {
+ free(keys);
+ keys = tiny_keys_buf; /* reset to something that would not trigger call to free(3) */
+ }
+ if (capacity >= (size_t)1 << casper->capacity_bits)
+ goto Exit;
+ capacity *= 2;
+ keys = h2o_mem_alloc(capacity * sizeof(*keys));
+ }
+
+ /* copy or merge the entries */
+ if (num_keys == 0) {
+ /* nothing to do */
+ } else if (casper->keys.size == 0) {
+ h2o_vector_reserve(NULL, &casper->keys, num_keys);
+ memcpy(casper->keys.entries, keys, num_keys * sizeof(*keys));
+ casper->keys.size = num_keys;
+ } else {
+ uint64_t *orig_keys = casper->keys.entries;
+ size_t num_orig_keys = casper->keys.size, orig_index = 0, new_index = 0;
+ memset(&casper->keys, 0, sizeof(casper->keys));
+ h2o_vector_reserve(NULL, &casper->keys, num_keys + num_orig_keys);
+ do {
+ if (orig_keys[orig_index] < keys[new_index]) {
+ casper->keys.entries[casper->keys.size++] = orig_keys[orig_index++];
+ } else if (orig_keys[orig_index] > keys[new_index]) {
+ casper->keys.entries[casper->keys.size++] = keys[new_index++];
+ } else {
+ casper->keys.entries[casper->keys.size++] = orig_keys[orig_index];
+ ++orig_index;
+ ++new_index;
+ }
+ } while (orig_index != num_orig_keys && new_index != num_keys);
+ if (orig_index != num_orig_keys) {
+ do {
+ casper->keys.entries[casper->keys.size++] = orig_keys[orig_index++];
+ } while (orig_index != num_orig_keys);
+ } else if (new_index != num_keys) {
+ do {
+ casper->keys.entries[casper->keys.size++] = keys[new_index++];
+ } while (new_index != num_keys);
+ }
+ free(orig_keys);
+ }
+
+Exit:
+ if (keys != tiny_keys_buf)
+ free(keys);
+ free(binary.base);
+}
+
+static size_t append_str(char *dst, const char *s, size_t l)
+{
+ memcpy(dst, s, l);
+ return l;
+}
+
+h2o_iovec_t h2o_http2_casper_get_cookie(h2o_http2_casper_t *casper)
+{
+ if (casper->cookie_cache.base != NULL)
+ return casper->cookie_cache;
+
+ if (casper->keys.size == 0)
+ return (h2o_iovec_t){NULL};
+
+ /* encode as binary */
+ char tiny_bin_buf[128], *bin_buf = tiny_bin_buf;
+ size_t bin_capacity = sizeof(tiny_bin_buf), bin_size;
+ while (bin_size = bin_capacity,
+ golombset_encode(casper->remainder_bits, casper->keys.entries, casper->keys.size, bin_buf, &bin_size) != 0) {
+ if (bin_buf != tiny_bin_buf)
+ free(bin_buf);
+ bin_capacity *= 2;
+ bin_buf = h2o_mem_alloc(bin_capacity);
+ }
+
+ char *header_bytes = h2o_mem_alloc(sizeof(COOKIE_NAME "=" COOKIE_ATTRIBUTES) - 1 + (bin_size + 3) * 4 / 3);
+ size_t header_len = 0;
+
+ header_len += append_str(header_bytes + header_len, H2O_STRLIT(COOKIE_NAME "="));
+ header_len += h2o_base64_encode(header_bytes + header_len, bin_buf, bin_size, 1);
+ header_len += append_str(header_bytes + header_len, H2O_STRLIT(COOKIE_ATTRIBUTES));
+
+ if (bin_buf != tiny_bin_buf)
+ free(bin_buf);
+
+ casper->cookie_cache = h2o_iovec_init(header_bytes, header_len);
+ return casper->cookie_cache;
+}
diff --git a/web/server/h2o/libh2o/lib/http2/connection.c b/web/server/h2o/libh2o/lib/http2/connection.c
new file mode 100644
index 000000000..e2da29304
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/connection.c
@@ -0,0 +1,1419 @@
+/*
+ * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc.
+ *
+ * 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "h2o.h"
+#include "h2o/http1.h"
+#include "h2o/http2.h"
+#include "h2o/http2_internal.h"
+
+static const h2o_iovec_t CONNECTION_PREFACE = {H2O_STRLIT("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")};
+
+const h2o_http2_priority_t h2o_http2_default_priority = {
+ 0, /* exclusive */
+ 0, /* dependency */
+ 16 /* weight */
+};
+
+const h2o_http2_settings_t H2O_HTTP2_SETTINGS_HOST = {
+ 4096, /* header_table_size */
+ 0, /* enable_push (clients are never allowed to initiate server push; RFC 7540 Section 8.2) */
+ 100, /* max_concurrent_streams */
+ 16777216, /* initial_window_size */
+ 16384 /* max_frame_size */
+};
+
+static const h2o_iovec_t SETTINGS_HOST_BIN = {H2O_STRLIT("\x00\x00\x0c" /* frame size */
+ "\x04" /* settings frame */
+ "\x00" /* no flags */
+ "\x00\x00\x00\x00" /* stream id */
+ "\x00\x03"
+ "\x00\x00\x00\x64" /* max_concurrent_streams = 100 */
+ "\x00\x04"
+ "\x01\x00\x00\x00" /* initial_window_size = 16777216 */
+ )};
+
+static __thread h2o_buffer_prototype_t wbuf_buffer_prototype = {{16}, {H2O_HTTP2_DEFAULT_OUTBUF_SIZE}};
+
+static void initiate_graceful_shutdown(h2o_context_t *ctx);
+static void close_connection_now(h2o_http2_conn_t *conn);
+static int close_connection(h2o_http2_conn_t *conn);
+static ssize_t expect_default(h2o_http2_conn_t *conn, const uint8_t *src, size_t len, const char **err_desc);
+static void do_emit_writereq(h2o_http2_conn_t *conn);
+static void on_read(h2o_socket_t *sock, const char *err);
+static void push_path(h2o_req_t *src_req, const char *abspath, size_t abspath_len);
+static int foreach_request(h2o_context_t *ctx, int (*cb)(h2o_req_t *req, void *cbdata), void *cbdata);
+static void stream_send_error(h2o_http2_conn_t *conn, uint32_t stream_id, int errnum);
+
+const h2o_protocol_callbacks_t H2O_HTTP2_CALLBACKS = {initiate_graceful_shutdown, foreach_request};
+
+static int is_idle_stream_id(h2o_http2_conn_t *conn, uint32_t stream_id)
+{
+ return (h2o_http2_stream_is_push(stream_id) ? conn->push_stream_ids.max_open : conn->pull_stream_ids.max_open) < stream_id;
+}
+
+static void enqueue_goaway(h2o_http2_conn_t *conn, int errnum, h2o_iovec_t additional_data)
+{
+ if (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING) {
+ /* http2 spec allows sending GOAWAY more than once (for one reason since errors may arise after sending the first one) */
+ h2o_http2_encode_goaway_frame(&conn->_write.buf, conn->pull_stream_ids.max_open, errnum, additional_data);
+ h2o_http2_conn_request_write(conn);
+ conn->state = H2O_HTTP2_CONN_STATE_HALF_CLOSED;
+ }
+}
+
+static void graceful_shutdown_close_stragglers(h2o_timeout_entry_t *entry)
+{
+ h2o_context_t *ctx = H2O_STRUCT_FROM_MEMBER(h2o_context_t, http2._graceful_shutdown_timeout, entry);
+ h2o_linklist_t *node, *next;
+
+ /* We've sent two GOAWAY frames, close the remaining connections */
+ for (node = ctx->http2._conns.next; node != &ctx->http2._conns; node = next) {
+ h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node);
+ next = node->next;
+ close_connection(conn);
+ }
+}
+
+static void graceful_shutdown_resend_goaway(h2o_timeout_entry_t *entry)
+{
+ h2o_context_t *ctx = H2O_STRUCT_FROM_MEMBER(h2o_context_t, http2._graceful_shutdown_timeout, entry);
+ h2o_linklist_t *node;
+ int do_close_stragglers = 0;
+
+ for (node = ctx->http2._conns.next; node != &ctx->http2._conns; node = node->next) {
+ h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node);
+ if (conn->state < H2O_HTTP2_CONN_STATE_HALF_CLOSED) {
+ enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, (h2o_iovec_t){NULL});
+ do_close_stragglers = 1;
+ }
+ }
+
+ /* After waiting a second, we still had active connections. If configured, wait one
+ * final timeout before closing the connections */
+ if (do_close_stragglers && ctx->globalconf->http2.graceful_shutdown_timeout) {
+ ctx->http2._graceful_shutdown_timeout.cb = graceful_shutdown_close_stragglers;
+ h2o_timeout_link(ctx->loop, &ctx->http2.graceful_shutdown_timeout, &ctx->http2._graceful_shutdown_timeout);
+ }
+}
+
+static void initiate_graceful_shutdown(h2o_context_t *ctx)
+{
+ /* draft-16 6.8
+ * A server that is attempting to gracefully shut down a connection SHOULD send an initial GOAWAY frame with the last stream
+ * identifier set to 231-1 and a NO_ERROR code. This signals to the client that a shutdown is imminent and that no further
+ * requests can be initiated. After waiting at least one round trip time, the server can send another GOAWAY frame with an
+ * updated last stream identifier. This ensures that a connection can be cleanly shut down without losing requests.
+ */
+ h2o_linklist_t *node;
+
+ /* only doit once */
+ if (ctx->http2._graceful_shutdown_timeout.cb != NULL)
+ return;
+ ctx->http2._graceful_shutdown_timeout.cb = graceful_shutdown_resend_goaway;
+
+ for (node = ctx->http2._conns.next; node != &ctx->http2._conns; node = node->next) {
+ h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node);
+ if (conn->state < H2O_HTTP2_CONN_STATE_HALF_CLOSED) {
+ h2o_http2_encode_goaway_frame(&conn->_write.buf, INT32_MAX, H2O_HTTP2_ERROR_NONE,
+ (h2o_iovec_t){H2O_STRLIT("graceful shutdown")});
+ h2o_http2_conn_request_write(conn);
+ }
+ }
+ h2o_timeout_link(ctx->loop, &ctx->one_sec_timeout, &ctx->http2._graceful_shutdown_timeout);
+}
+
+static void on_idle_timeout(h2o_timeout_entry_t *entry)
+{
+ h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _timeout_entry, entry);
+
+ enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, h2o_iovec_init(H2O_STRLIT("idle timeout")));
+ if (conn->_write.buf_in_flight != NULL) {
+ close_connection_now(conn);
+ } else {
+ enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, h2o_iovec_init(H2O_STRLIT("idle timeout")));
+ close_connection(conn);
+ }
+}
+
+static void update_idle_timeout(h2o_http2_conn_t *conn)
+{
+ h2o_timeout_unlink(&conn->_timeout_entry);
+
+ if (conn->num_streams.pull.half_closed + conn->num_streams.push.half_closed == 0) {
+ assert(h2o_linklist_is_empty(&conn->_pending_reqs));
+ conn->_timeout_entry.cb = on_idle_timeout;
+ h2o_timeout_link(conn->super.ctx->loop, &conn->super.ctx->http2.idle_timeout, &conn->_timeout_entry);
+ }
+}
+
+static int can_run_requests(h2o_http2_conn_t *conn)
+{
+ return conn->num_streams.pull.half_closed + conn->num_streams.push.half_closed <
+ conn->super.ctx->globalconf->http2.max_concurrent_requests_per_connection;
+}
+
+static void run_pending_requests(h2o_http2_conn_t *conn)
+{
+ while (!h2o_linklist_is_empty(&conn->_pending_reqs) && can_run_requests(conn)) {
+ /* fetch and detach a pending stream */
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, _refs.link, conn->_pending_reqs.next);
+ h2o_linklist_unlink(&stream->_refs.link);
+ /* handle it */
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_SEND_HEADERS);
+ if (!h2o_http2_stream_is_push(stream->stream_id) && conn->pull_stream_ids.max_processed < stream->stream_id)
+ conn->pull_stream_ids.max_processed = stream->stream_id;
+ h2o_process_request(&stream->req);
+ }
+}
+
+static void execute_or_enqueue_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ assert(stream->state < H2O_HTTP2_STREAM_STATE_REQ_PENDING);
+
+ if (stream->_req_body != NULL && stream->_expected_content_length != SIZE_MAX &&
+ stream->_req_body->size != stream->_expected_content_length) {
+ stream_send_error(conn, stream->stream_id, H2O_HTTP2_ERROR_PROTOCOL);
+ h2o_http2_stream_reset(conn, stream);
+ return;
+ }
+
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_REQ_PENDING);
+
+ /* TODO schedule the pending reqs using the scheduler */
+ h2o_linklist_insert(&conn->_pending_reqs, &stream->_refs.link);
+
+ run_pending_requests(conn);
+ update_idle_timeout(conn);
+}
+
+void h2o_http2_conn_register_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ khiter_t iter;
+ int r;
+
+ iter = kh_put(h2o_http2_stream_t, conn->streams, stream->stream_id, &r);
+ assert(iter != kh_end(conn->streams));
+ kh_val(conn->streams, iter) = stream;
+}
+
+void h2o_http2_conn_unregister_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ khiter_t iter = kh_get(h2o_http2_stream_t, conn->streams, stream->stream_id);
+ assert(iter != kh_end(conn->streams));
+ kh_del(h2o_http2_stream_t, conn->streams, iter);
+
+ assert(h2o_http2_scheduler_is_open(&stream->_refs.scheduler));
+ h2o_http2_scheduler_close(&stream->_refs.scheduler);
+
+ switch (stream->state) {
+ case H2O_HTTP2_STREAM_STATE_IDLE:
+ case H2O_HTTP2_STREAM_STATE_RECV_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_RECV_BODY:
+ assert(!h2o_linklist_is_linked(&stream->_refs.link));
+ break;
+ case H2O_HTTP2_STREAM_STATE_REQ_PENDING:
+ assert(h2o_linklist_is_linked(&stream->_refs.link));
+ h2o_linklist_unlink(&stream->_refs.link);
+ break;
+ case H2O_HTTP2_STREAM_STATE_SEND_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL:
+ case H2O_HTTP2_STREAM_STATE_END_STREAM:
+ if (h2o_linklist_is_linked(&stream->_refs.link))
+ h2o_linklist_unlink(&stream->_refs.link);
+ break;
+ }
+ if (stream->state != H2O_HTTP2_STREAM_STATE_END_STREAM)
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_END_STREAM);
+
+ if (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING) {
+ run_pending_requests(conn);
+ update_idle_timeout(conn);
+ }
+}
+
+void close_connection_now(h2o_http2_conn_t *conn)
+{
+ h2o_http2_stream_t *stream;
+
+ assert(!h2o_timeout_is_linked(&conn->_write.timeout_entry));
+
+ kh_foreach_value(conn->streams, stream, { h2o_http2_stream_close(conn, stream); });
+ assert(conn->num_streams.pull.open == 0);
+ assert(conn->num_streams.pull.half_closed == 0);
+ assert(conn->num_streams.pull.send_body == 0);
+ assert(conn->num_streams.push.half_closed == 0);
+ assert(conn->num_streams.push.send_body == 0);
+ assert(conn->num_streams.priority.open == 0);
+ kh_destroy(h2o_http2_stream_t, conn->streams);
+ assert(conn->_http1_req_input == NULL);
+ h2o_hpack_dispose_header_table(&conn->_input_header_table);
+ h2o_hpack_dispose_header_table(&conn->_output_header_table);
+ assert(h2o_linklist_is_empty(&conn->_pending_reqs));
+ h2o_timeout_unlink(&conn->_timeout_entry);
+ h2o_buffer_dispose(&conn->_write.buf);
+ if (conn->_write.buf_in_flight != NULL)
+ h2o_buffer_dispose(&conn->_write.buf_in_flight);
+ h2o_http2_scheduler_dispose(&conn->scheduler);
+ assert(h2o_linklist_is_empty(&conn->_write.streams_to_proceed));
+ assert(!h2o_timeout_is_linked(&conn->_write.timeout_entry));
+ if (conn->_headers_unparsed != NULL)
+ h2o_buffer_dispose(&conn->_headers_unparsed);
+ if (conn->push_memo != NULL)
+ h2o_cache_destroy(conn->push_memo);
+ if (conn->casper != NULL)
+ h2o_http2_casper_destroy(conn->casper);
+ h2o_linklist_unlink(&conn->_conns);
+
+ if (conn->sock != NULL)
+ h2o_socket_close(conn->sock);
+ free(conn);
+}
+
+int close_connection(h2o_http2_conn_t *conn)
+{
+ conn->state = H2O_HTTP2_CONN_STATE_IS_CLOSING;
+
+ if (conn->_write.buf_in_flight != NULL || h2o_timeout_is_linked(&conn->_write.timeout_entry)) {
+ /* there is a pending write, let on_write_complete actually close the connection */
+ } else {
+ close_connection_now(conn);
+ return -1;
+ }
+ return 0;
+}
+
+static void stream_send_error(h2o_http2_conn_t *conn, uint32_t stream_id, int errnum)
+{
+ assert(stream_id != 0);
+ assert(conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING);
+
+ conn->super.ctx->http2.events.protocol_level_errors[-errnum]++;
+
+ h2o_http2_encode_rst_stream_frame(&conn->_write.buf, stream_id, -errnum);
+ h2o_http2_conn_request_write(conn);
+}
+
+static void request_gathered_write(h2o_http2_conn_t *conn)
+{
+ assert(conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING);
+ if (conn->sock->_cb.write == NULL && !h2o_timeout_is_linked(&conn->_write.timeout_entry))
+ h2o_timeout_link(conn->super.ctx->loop, &conn->super.ctx->zero_timeout, &conn->_write.timeout_entry);
+}
+
+static int update_stream_output_window(h2o_http2_stream_t *stream, ssize_t delta)
+{
+ ssize_t cur = h2o_http2_window_get_window(&stream->output_window);
+ if (h2o_http2_window_update(&stream->output_window, delta) != 0)
+ return -1;
+ if (cur <= 0 && h2o_http2_window_get_window(&stream->output_window) > 0 &&
+ (h2o_http2_stream_has_pending_data(stream) || stream->state >= H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL)) {
+ assert(!h2o_linklist_is_linked(&stream->_refs.link));
+ h2o_http2_scheduler_activate(&stream->_refs.scheduler);
+ }
+ return 0;
+}
+
+static int handle_incoming_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, const uint8_t *src, size_t len,
+ const char **err_desc)
+{
+ int ret, header_exists_map;
+
+ assert(stream->state == H2O_HTTP2_STREAM_STATE_RECV_HEADERS);
+
+ header_exists_map = 0;
+ if ((ret = h2o_hpack_parse_headers(&stream->req, &conn->_input_header_table, src, len, &header_exists_map,
+ &stream->_expected_content_length, &stream->cache_digests, err_desc)) != 0) {
+ /* all errors except invalid-header-char are connection errors */
+ if (ret != H2O_HTTP2_ERROR_INVALID_HEADER_CHAR)
+ return ret;
+ }
+
+ /* handle stream-level errors */
+#define EXPECTED_MAP \
+ (H2O_HPACK_PARSE_HEADERS_METHOD_EXISTS | H2O_HPACK_PARSE_HEADERS_PATH_EXISTS | H2O_HPACK_PARSE_HEADERS_SCHEME_EXISTS)
+ if ((header_exists_map & EXPECTED_MAP) != EXPECTED_MAP) {
+ ret = H2O_HTTP2_ERROR_PROTOCOL;
+ goto SendRSTStream;
+ }
+#undef EXPECTED_MAP
+ if (conn->num_streams.pull.open > H2O_HTTP2_SETTINGS_HOST.max_concurrent_streams) {
+ ret = H2O_HTTP2_ERROR_REFUSED_STREAM;
+ goto SendRSTStream;
+ }
+
+ /* handle request to send response */
+ if (ret != 0) {
+ assert(ret == H2O_HTTP2_ERROR_INVALID_HEADER_CHAR);
+ /* fast forward the stream's state so that we can start sending the response */
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_REQ_PENDING);
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_SEND_HEADERS);
+ h2o_send_error_400(&stream->req, "Invalid Headers", *err_desc, 0);
+ return 0;
+ }
+
+ if (stream->_req_body == NULL) {
+ execute_or_enqueue_request(conn, stream);
+ } else {
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_RECV_BODY);
+ }
+ return 0;
+
+SendRSTStream:
+ stream_send_error(conn, stream->stream_id, ret);
+ h2o_http2_stream_reset(conn, stream);
+ return 0;
+}
+
+static int handle_trailing_headers(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, const uint8_t *src, size_t len,
+ const char **err_desc)
+{
+ size_t dummy_content_length;
+ int ret;
+
+ assert(stream->state == H2O_HTTP2_STREAM_STATE_RECV_BODY);
+
+ if ((ret = h2o_hpack_parse_headers(&stream->req, &conn->_input_header_table, src, len, NULL, &dummy_content_length, NULL,
+ err_desc)) != 0)
+ return ret;
+
+ execute_or_enqueue_request(conn, stream);
+ return 0;
+}
+
+static ssize_t expect_continuation_of_headers(h2o_http2_conn_t *conn, const uint8_t *src, size_t len, const char **err_desc)
+{
+ h2o_http2_frame_t frame;
+ ssize_t ret;
+ h2o_http2_stream_t *stream;
+ int hret;
+
+ if ((ret = h2o_http2_decode_frame(&frame, src, len, &H2O_HTTP2_SETTINGS_HOST, err_desc)) < 0)
+ return ret;
+ if (frame.type != H2O_HTTP2_FRAME_TYPE_CONTINUATION) {
+ *err_desc = "expected CONTINUATION frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ if (conn->state >= H2O_HTTP2_CONN_STATE_HALF_CLOSED)
+ return 0;
+
+ if ((stream = h2o_http2_conn_get_stream(conn, frame.stream_id)) == NULL ||
+ !(stream->state == H2O_HTTP2_STREAM_STATE_RECV_HEADERS || stream->state == H2O_HTTP2_STREAM_STATE_RECV_BODY)) {
+ *err_desc = "unexpected stream id in CONTINUATION frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ if (conn->_headers_unparsed->size + frame.length <= H2O_MAX_REQLEN) {
+ h2o_buffer_reserve(&conn->_headers_unparsed, frame.length);
+ memcpy(conn->_headers_unparsed->bytes + conn->_headers_unparsed->size, frame.payload, frame.length);
+ conn->_headers_unparsed->size += frame.length;
+
+ if ((frame.flags & H2O_HTTP2_FRAME_FLAG_END_HEADERS) != 0) {
+ conn->_read_expect = expect_default;
+ if (stream->state == H2O_HTTP2_STREAM_STATE_RECV_HEADERS) {
+ hret = handle_incoming_request(conn, stream, (const uint8_t *)conn->_headers_unparsed->bytes,
+ conn->_headers_unparsed->size, err_desc);
+ } else {
+ hret = handle_trailing_headers(conn, stream, (const uint8_t *)conn->_headers_unparsed->bytes,
+ conn->_headers_unparsed->size, err_desc);
+ }
+ if (hret != 0)
+ ret = hret;
+ h2o_buffer_dispose(&conn->_headers_unparsed);
+ conn->_headers_unparsed = NULL;
+ }
+ } else {
+ /* request is too large (TODO log) */
+ stream_send_error(conn, stream->stream_id, H2O_HTTP2_ERROR_REFUSED_STREAM);
+ h2o_http2_stream_reset(conn, stream);
+ }
+
+ return ret;
+}
+
+static void update_input_window(h2o_http2_conn_t *conn, uint32_t stream_id, h2o_http2_window_t *window, size_t consumed)
+{
+ h2o_http2_window_consume_window(window, consumed);
+ if (h2o_http2_window_get_window(window) * 2 < H2O_HTTP2_SETTINGS_HOST.initial_window_size) {
+ int32_t delta = (int32_t)(H2O_HTTP2_SETTINGS_HOST.initial_window_size - h2o_http2_window_get_window(window));
+ h2o_http2_encode_window_update_frame(&conn->_write.buf, stream_id, delta);
+ h2o_http2_conn_request_write(conn);
+ h2o_http2_window_update(window, delta);
+ }
+}
+
+static void set_priority(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, const h2o_http2_priority_t *priority,
+ int scheduler_is_open)
+{
+ h2o_http2_scheduler_node_t *parent_sched;
+
+ /* determine the parent */
+ if (priority->dependency != 0) {
+ h2o_http2_stream_t *parent_stream = h2o_http2_conn_get_stream(conn, priority->dependency);
+ if (parent_stream != NULL) {
+ parent_sched = &parent_stream->_refs.scheduler.node;
+ } else {
+ /* A dependency on a stream that is not currently in the tree - such as a stream in the "idle" state - results in that
+ * stream being given a default priority. (RFC 7540 5.3.1)
+ * It is possible for a stream to become closed while prioritization information that creates a dependency on that
+ * stream is in transit. If a stream identified in a dependency has no associated priority information, then the
+ * dependent stream is instead assigned a default priority. (RFC 7540 5.3.4)
+ */
+ parent_sched = &conn->scheduler;
+ priority = &h2o_http2_default_priority;
+ }
+ } else {
+ parent_sched = &conn->scheduler;
+ }
+
+ /* setup the scheduler */
+ if (!scheduler_is_open) {
+ h2o_http2_scheduler_open(&stream->_refs.scheduler, parent_sched, priority->weight, priority->exclusive);
+ } else {
+ h2o_http2_scheduler_rebind(&stream->_refs.scheduler, parent_sched, priority->weight, priority->exclusive);
+ }
+}
+
+static int handle_data_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ h2o_http2_data_payload_t payload;
+ h2o_http2_stream_t *stream;
+ int ret;
+
+ if ((ret = h2o_http2_decode_data_payload(&payload, frame, err_desc)) != 0)
+ return ret;
+
+ if (conn->state >= H2O_HTTP2_CONN_STATE_HALF_CLOSED)
+ return 0;
+
+ stream = h2o_http2_conn_get_stream(conn, frame->stream_id);
+
+ /* save the input in the request body buffer, or send error (and close the stream) */
+ if (stream == NULL) {
+ if (frame->stream_id <= conn->pull_stream_ids.max_open) {
+ stream_send_error(conn, frame->stream_id, H2O_HTTP2_ERROR_STREAM_CLOSED);
+ } else {
+ *err_desc = "invalid DATA frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ } else if (stream->state != H2O_HTTP2_STREAM_STATE_RECV_BODY) {
+ stream_send_error(conn, frame->stream_id, H2O_HTTP2_ERROR_STREAM_CLOSED);
+ h2o_http2_stream_reset(conn, stream);
+ stream = NULL;
+ } else if (stream->_req_body->size + payload.length > conn->super.ctx->globalconf->max_request_entity_size) {
+ stream_send_error(conn, frame->stream_id, H2O_HTTP2_ERROR_REFUSED_STREAM);
+ h2o_http2_stream_reset(conn, stream);
+ stream = NULL;
+ } else {
+ h2o_iovec_t buf = h2o_buffer_reserve(&stream->_req_body, payload.length);
+ if (buf.base != NULL) {
+ memcpy(buf.base, payload.data, payload.length);
+ stream->_req_body->size += payload.length;
+ /* handle request if request body is complete */
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_END_STREAM) != 0) {
+ stream->req.entity = h2o_iovec_init(stream->_req_body->bytes, stream->_req_body->size);
+ execute_or_enqueue_request(conn, stream);
+ stream = NULL; /* no need to send window update for this stream */
+ }
+ } else {
+ /* memory allocation failed */
+ stream_send_error(conn, frame->stream_id, H2O_HTTP2_ERROR_STREAM_CLOSED);
+ h2o_http2_stream_reset(conn, stream);
+ stream = NULL;
+ }
+ }
+
+ /* consume buffer (and set window_update) */
+ update_input_window(conn, 0, &conn->_input_window, frame->length);
+ if (stream != NULL)
+ update_input_window(conn, stream->stream_id, &stream->input_window, frame->length);
+
+ return 0;
+}
+
+static int handle_headers_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ h2o_http2_headers_payload_t payload;
+ h2o_http2_stream_t *stream;
+ int ret;
+
+ /* decode */
+ if ((ret = h2o_http2_decode_headers_payload(&payload, frame, err_desc)) != 0)
+ return ret;
+ if ((frame->stream_id & 1) == 0) {
+ *err_desc = "invalid stream id in HEADERS frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ if (!(conn->pull_stream_ids.max_open < frame->stream_id)) {
+ if ((stream = h2o_http2_conn_get_stream(conn, frame->stream_id)) != NULL &&
+ stream->state == H2O_HTTP2_STREAM_STATE_RECV_BODY) {
+ /* is a trailer */
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_END_STREAM) == 0) {
+ *err_desc = "trailing HEADERS frame MUST have END_STREAM flag set";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ stream->req.entity = h2o_iovec_init(stream->_req_body->bytes, stream->_req_body->size);
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_END_HEADERS) == 0)
+ goto PREPARE_FOR_CONTINUATION;
+ return handle_trailing_headers(conn, stream, payload.headers, payload.headers_len, err_desc);
+ } else if (!stream || stream->state != H2O_HTTP2_STREAM_STATE_IDLE) {
+ /* it's legit that stream exists and is IDLE if a PRIORITY frame was received earlier */
+ *err_desc = "invalid stream id in HEADERS frame";
+ return H2O_HTTP2_ERROR_STREAM_CLOSED;
+ }
+ }
+ if (frame->stream_id == payload.priority.dependency) {
+ *err_desc = "stream cannot depend on itself";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ if (conn->state >= H2O_HTTP2_CONN_STATE_HALF_CLOSED)
+ return 0;
+
+ /* open or determine the stream and prepare */
+ if ((stream = h2o_http2_conn_get_stream(conn, frame->stream_id)) != NULL) {
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_PRIORITY) != 0) {
+ set_priority(conn, stream, &payload.priority, 1);
+ stream->received_priority = payload.priority;
+ }
+ } else {
+ stream = h2o_http2_stream_open(conn, frame->stream_id, NULL, &payload.priority);
+ set_priority(conn, stream, &payload.priority, 0);
+ }
+ h2o_http2_stream_prepare_for_request(conn, stream);
+
+ /* setup container for request body if it is expected to arrive */
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_END_STREAM) == 0)
+ h2o_buffer_init(&stream->_req_body, &h2o_socket_buffer_prototype);
+
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_END_HEADERS) != 0) {
+ /* request is complete, handle it */
+ return handle_incoming_request(conn, stream, payload.headers, payload.headers_len, err_desc);
+ }
+
+PREPARE_FOR_CONTINUATION:
+ /* request is not complete, store in buffer */
+ conn->_read_expect = expect_continuation_of_headers;
+ h2o_buffer_init(&conn->_headers_unparsed, &h2o_socket_buffer_prototype);
+ h2o_buffer_reserve(&conn->_headers_unparsed, payload.headers_len);
+ memcpy(conn->_headers_unparsed->bytes, payload.headers, payload.headers_len);
+ conn->_headers_unparsed->size = payload.headers_len;
+ return 0;
+}
+
+static int handle_priority_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ h2o_http2_priority_t payload;
+ h2o_http2_stream_t *stream;
+ int ret;
+
+ if ((ret = h2o_http2_decode_priority_payload(&payload, frame, err_desc)) != 0)
+ return ret;
+ if (frame->stream_id == payload.dependency) {
+ *err_desc = "stream cannot depend on itself";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ if ((stream = h2o_http2_conn_get_stream(conn, frame->stream_id)) != NULL) {
+ stream->received_priority = payload;
+ /* ignore priority changes to pushed streams with weight=257, since that is where we are trying to be smarter than the web
+ * browsers
+ */
+ if (h2o_http2_scheduler_get_weight(&stream->_refs.scheduler) != 257)
+ set_priority(conn, stream, &payload, 1);
+ } else {
+ if (h2o_http2_stream_is_push(frame->stream_id)) {
+ /* Ignore PRIORITY frames for closed or idle pushed streams */
+ return 0;
+ } else {
+ /* Ignore PRIORITY frames for closed pull streams */
+ if (frame->stream_id <= conn->pull_stream_ids.max_open)
+ return 0;
+ }
+ if (conn->num_streams.priority.open >= conn->super.ctx->globalconf->http2.max_streams_for_priority) {
+ *err_desc = "too many streams in idle/closed state";
+ /* RFC 7540 10.5: An endpoint MAY treat activity that is suspicious as a connection error (Section 5.4.1) of type
+ * ENHANCE_YOUR_CALM.
+ */
+ return H2O_HTTP2_ERROR_ENHANCE_YOUR_CALM;
+ }
+ stream = h2o_http2_stream_open(conn, frame->stream_id, NULL, &payload);
+ set_priority(conn, stream, &payload, 0);
+ }
+
+ return 0;
+}
+
+static void resume_send(h2o_http2_conn_t *conn)
+{
+ if (h2o_http2_conn_get_buffer_window(conn) <= 0)
+ return;
+#if 0 /* TODO reenable this check for performance? */
+ if (conn->scheduler.list.size == 0)
+ return;
+#endif
+ request_gathered_write(conn);
+}
+
+static int handle_settings_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ if (frame->stream_id != 0) {
+ *err_desc = "invalid stream id in SETTINGS frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_ACK) != 0) {
+ if (frame->length != 0) {
+ *err_desc = "invalid SETTINGS frame (+ACK)";
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+ }
+ } else {
+ uint32_t prev_initial_window_size = conn->peer_settings.initial_window_size;
+ /* FIXME handle SETTINGS_HEADER_TABLE_SIZE */
+ int ret = h2o_http2_update_peer_settings(&conn->peer_settings, frame->payload, frame->length, err_desc);
+ if (ret != 0)
+ return ret;
+ { /* schedule ack */
+ h2o_iovec_t header_buf = h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE);
+ h2o_http2_encode_frame_header((void *)header_buf.base, 0, H2O_HTTP2_FRAME_TYPE_SETTINGS, H2O_HTTP2_FRAME_FLAG_ACK, 0);
+ conn->_write.buf->size += H2O_HTTP2_FRAME_HEADER_SIZE;
+ h2o_http2_conn_request_write(conn);
+ }
+ /* apply the change to window size (to all the streams but not the connection, see 6.9.2 of draft-15) */
+ if (prev_initial_window_size != conn->peer_settings.initial_window_size) {
+ ssize_t delta = (int32_t)conn->peer_settings.initial_window_size - (int32_t)prev_initial_window_size;
+ h2o_http2_stream_t *stream;
+ kh_foreach_value(conn->streams, stream, { update_stream_output_window(stream, delta); });
+ resume_send(conn);
+ }
+ }
+
+ return 0;
+}
+
+static int handle_window_update_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ h2o_http2_window_update_payload_t payload;
+ int ret, err_is_stream_level;
+
+ if ((ret = h2o_http2_decode_window_update_payload(&payload, frame, err_desc, &err_is_stream_level)) != 0) {
+ if (err_is_stream_level) {
+ h2o_http2_stream_t *stream = h2o_http2_conn_get_stream(conn, frame->stream_id);
+ if (stream != NULL)
+ h2o_http2_stream_reset(conn, stream);
+ stream_send_error(conn, frame->stream_id, ret);
+ return 0;
+ } else {
+ return ret;
+ }
+ }
+
+ if (frame->stream_id == 0) {
+ if (h2o_http2_window_update(&conn->_write.window, payload.window_size_increment) != 0) {
+ *err_desc = "flow control window overflow";
+ return H2O_HTTP2_ERROR_FLOW_CONTROL;
+ }
+ } else if (!is_idle_stream_id(conn, frame->stream_id)) {
+ h2o_http2_stream_t *stream = h2o_http2_conn_get_stream(conn, frame->stream_id);
+ if (stream != NULL) {
+ if (update_stream_output_window(stream, payload.window_size_increment) != 0) {
+ h2o_http2_stream_reset(conn, stream);
+ stream_send_error(conn, frame->stream_id, H2O_HTTP2_ERROR_FLOW_CONTROL);
+ return 0;
+ }
+ }
+ } else {
+ *err_desc = "invalid stream id in WINDOW_UPDATE frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ resume_send(conn);
+
+ return 0;
+}
+
+static int handle_goaway_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ h2o_http2_goaway_payload_t payload;
+ int ret;
+
+ if ((ret = h2o_http2_decode_goaway_payload(&payload, frame, err_desc)) != 0)
+ return ret;
+
+ /* stop opening new push streams hereafter */
+ conn->push_stream_ids.max_open = 0x7ffffffe;
+
+ return 0;
+}
+
+static int handle_ping_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ h2o_http2_ping_payload_t payload;
+ int ret;
+
+ if ((ret = h2o_http2_decode_ping_payload(&payload, frame, err_desc)) != 0)
+ return ret;
+
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_ACK) == 0) {
+ h2o_http2_encode_ping_frame(&conn->_write.buf, 1, payload.data);
+ h2o_http2_conn_request_write(conn);
+ }
+
+ return 0;
+}
+
+static int handle_rst_stream_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ h2o_http2_rst_stream_payload_t payload;
+ h2o_http2_stream_t *stream;
+ int ret;
+
+ if ((ret = h2o_http2_decode_rst_stream_payload(&payload, frame, err_desc)) != 0)
+ return ret;
+ if (is_idle_stream_id(conn, frame->stream_id)) {
+ *err_desc = "unexpected stream id in RST_STREAM frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ stream = h2o_http2_conn_get_stream(conn, frame->stream_id);
+ if (stream != NULL) {
+ /* reset the stream */
+ h2o_http2_stream_reset(conn, stream);
+ }
+ /* TODO log */
+
+ return 0;
+}
+
+static int handle_push_promise_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ *err_desc = "received PUSH_PROMISE frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+}
+
+static int handle_invalid_continuation_frame(h2o_http2_conn_t *conn, h2o_http2_frame_t *frame, const char **err_desc)
+{
+ *err_desc = "received invalid CONTINUATION frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+}
+
+ssize_t expect_default(h2o_http2_conn_t *conn, const uint8_t *src, size_t len, const char **err_desc)
+{
+ h2o_http2_frame_t frame;
+ ssize_t ret;
+ static int (*FRAME_HANDLERS[])(h2o_http2_conn_t * conn, h2o_http2_frame_t * frame, const char **err_desc) = {
+ handle_data_frame, /* DATA */
+ handle_headers_frame, /* HEADERS */
+ handle_priority_frame, /* PRIORITY */
+ handle_rst_stream_frame, /* RST_STREAM */
+ handle_settings_frame, /* SETTINGS */
+ handle_push_promise_frame, /* PUSH_PROMISE */
+ handle_ping_frame, /* PING */
+ handle_goaway_frame, /* GOAWAY */
+ handle_window_update_frame, /* WINDOW_UPDATE */
+ handle_invalid_continuation_frame /* CONTINUATION */
+ };
+
+ if ((ret = h2o_http2_decode_frame(&frame, src, len, &H2O_HTTP2_SETTINGS_HOST, err_desc)) < 0)
+ return ret;
+
+ if (frame.type < sizeof(FRAME_HANDLERS) / sizeof(FRAME_HANDLERS[0])) {
+ int hret = FRAME_HANDLERS[frame.type](conn, &frame, err_desc);
+ if (hret != 0)
+ ret = hret;
+ } else {
+ fprintf(stderr, "skipping frame (type:%d)\n", frame.type);
+ }
+
+ return ret;
+}
+
+static ssize_t expect_preface(h2o_http2_conn_t *conn, const uint8_t *src, size_t len, const char **err_desc)
+{
+ if (len < CONNECTION_PREFACE.len) {
+ return H2O_HTTP2_ERROR_INCOMPLETE;
+ }
+ if (memcmp(src, CONNECTION_PREFACE.base, CONNECTION_PREFACE.len) != 0) {
+ return H2O_HTTP2_ERROR_PROTOCOL_CLOSE_IMMEDIATELY;
+ }
+
+ { /* send SETTINGS */
+ h2o_iovec_t vec = h2o_buffer_reserve(&conn->_write.buf, SETTINGS_HOST_BIN.len);
+ memcpy(vec.base, SETTINGS_HOST_BIN.base, SETTINGS_HOST_BIN.len);
+ conn->_write.buf->size += SETTINGS_HOST_BIN.len;
+ h2o_http2_conn_request_write(conn);
+ }
+
+ conn->_read_expect = expect_default;
+ return CONNECTION_PREFACE.len;
+}
+
+static int parse_input(h2o_http2_conn_t *conn)
+{
+ /* handle the input */
+ while (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING && conn->sock->input->size != 0) {
+ /* process a frame */
+ const char *err_desc = NULL;
+ ssize_t ret = conn->_read_expect(conn, (uint8_t *)conn->sock->input->bytes, conn->sock->input->size, &err_desc);
+ if (ret == H2O_HTTP2_ERROR_INCOMPLETE) {
+ break;
+ } else if (ret < 0) {
+ if (ret != H2O_HTTP2_ERROR_PROTOCOL_CLOSE_IMMEDIATELY) {
+ enqueue_goaway(conn, (int)ret,
+ err_desc != NULL ? (h2o_iovec_t){(char *)err_desc, strlen(err_desc)} : (h2o_iovec_t){NULL});
+ }
+ return close_connection(conn);
+ }
+ /* advance to the next frame */
+ h2o_buffer_consume(&conn->sock->input, ret);
+ }
+ return 0;
+}
+
+static void on_read(h2o_socket_t *sock, const char *err)
+{
+ h2o_http2_conn_t *conn = sock->data;
+
+ if (err != NULL) {
+ conn->super.ctx->http2.events.read_closed++;
+ h2o_socket_read_stop(conn->sock);
+ close_connection(conn);
+ return;
+ }
+
+ update_idle_timeout(conn);
+ if (parse_input(conn) != 0)
+ return;
+
+ /* write immediately, if there is no write in flight and if pending write exists */
+ if (h2o_timeout_is_linked(&conn->_write.timeout_entry)) {
+ h2o_timeout_unlink(&conn->_write.timeout_entry);
+ do_emit_writereq(conn);
+ }
+}
+
+static void on_upgrade_complete(void *_conn, h2o_socket_t *sock, size_t reqsize)
+{
+ h2o_http2_conn_t *conn = _conn;
+
+ if (sock == NULL) {
+ close_connection(conn);
+ return;
+ }
+
+ conn->sock = sock;
+ sock->data = conn;
+ conn->_http1_req_input = sock->input;
+ h2o_buffer_init(&sock->input, &h2o_socket_buffer_prototype);
+
+ /* setup inbound */
+ h2o_socket_read_start(conn->sock, on_read);
+
+ /* handle the request */
+ execute_or_enqueue_request(conn, h2o_http2_conn_get_stream(conn, 1));
+
+ if (conn->_http1_req_input->size > reqsize) {
+ size_t remaining_bytes = conn->_http1_req_input->size - reqsize;
+ h2o_buffer_reserve(&sock->input, remaining_bytes);
+ memcpy(sock->input->bytes, conn->_http1_req_input->bytes + reqsize, remaining_bytes);
+ sock->input->size += remaining_bytes;
+ on_read(conn->sock, NULL);
+ }
+}
+
+static size_t bytes_in_buf(h2o_http2_conn_t *conn)
+{
+ size_t size = conn->_write.buf->size;
+ if (conn->_write.buf_in_flight != 0)
+ size += conn->_write.buf_in_flight->size;
+ return size;
+}
+
+void h2o_http2_conn_request_write(h2o_http2_conn_t *conn)
+{
+ if (conn->state == H2O_HTTP2_CONN_STATE_IS_CLOSING)
+ return;
+ if (h2o_socket_is_reading(conn->sock) && bytes_in_buf(conn) >= H2O_HTTP2_DEFAULT_OUTBUF_SOFT_MAX_SIZE)
+ h2o_socket_read_stop(conn->sock);
+ request_gathered_write(conn);
+}
+
+void h2o_http2_conn_register_for_proceed_callback(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ h2o_http2_conn_request_write(conn);
+
+ if (h2o_http2_stream_has_pending_data(stream) || stream->state >= H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL) {
+ if (h2o_http2_window_get_window(&stream->output_window) > 0) {
+ assert(!h2o_linklist_is_linked(&stream->_refs.link));
+ h2o_http2_scheduler_activate(&stream->_refs.scheduler);
+ }
+ } else {
+ h2o_linklist_insert(&conn->_write.streams_to_proceed, &stream->_refs.link);
+ }
+}
+
+static void on_notify_write(h2o_socket_t *sock, const char *err)
+{
+ h2o_http2_conn_t *conn = sock->data;
+
+ if (err != NULL) {
+ close_connection_now(conn);
+ return;
+ }
+ do_emit_writereq(conn);
+}
+
+static void on_write_complete(h2o_socket_t *sock, const char *err)
+{
+ h2o_http2_conn_t *conn = sock->data;
+
+ assert(conn->_write.buf_in_flight != NULL);
+
+ /* close by error if necessary */
+ if (err != NULL) {
+ conn->super.ctx->http2.events.write_closed++;
+ close_connection_now(conn);
+ return;
+ }
+
+ /* reset the other memory pool */
+ h2o_buffer_dispose(&conn->_write.buf_in_flight);
+ assert(conn->_write.buf_in_flight == NULL);
+
+ /* call the proceed callback of the streams that have been flushed (while unlinking them from the list) */
+ if (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING) {
+ while (!h2o_linklist_is_empty(&conn->_write.streams_to_proceed)) {
+ h2o_http2_stream_t *stream =
+ H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, _refs.link, conn->_write.streams_to_proceed.next);
+ assert(!h2o_http2_stream_has_pending_data(stream));
+ h2o_linklist_unlink(&stream->_refs.link);
+ h2o_http2_stream_proceed(conn, stream);
+ }
+ }
+
+ /* cancel the write callback if scheduled (as the generator may have scheduled a write just before this function gets called) */
+ if (h2o_timeout_is_linked(&conn->_write.timeout_entry))
+ h2o_timeout_unlink(&conn->_write.timeout_entry);
+
+ if (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING) {
+ if (!h2o_socket_is_reading(conn->sock) && bytes_in_buf(conn) < H2O_HTTP2_DEFAULT_OUTBUF_SOFT_MAX_SIZE)
+ h2o_socket_read_start(conn->sock, on_read);
+ }
+
+#if !H2O_USE_LIBUV
+ if (conn->state == H2O_HTTP2_CONN_STATE_OPEN) {
+ if (conn->_write.buf->size != 0 || h2o_http2_scheduler_is_active(&conn->scheduler))
+ h2o_socket_notify_write(sock, on_notify_write);
+ return;
+ }
+#endif
+
+ /* write more, if possible */
+ do_emit_writereq(conn);
+}
+
+static int emit_writereq_of_openref(h2o_http2_scheduler_openref_t *ref, int *still_is_active, void *cb_arg)
+{
+ h2o_http2_conn_t *conn = cb_arg;
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, _refs.scheduler, ref);
+
+ assert(h2o_http2_stream_has_pending_data(stream) || stream->state >= H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL);
+
+ *still_is_active = 0;
+
+ h2o_http2_stream_send_pending_data(conn, stream);
+ if (h2o_http2_stream_has_pending_data(stream) || stream->state == H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL) {
+ if (h2o_http2_window_get_window(&stream->output_window) <= 0) {
+ /* is blocked */
+ } else {
+ *still_is_active = 1;
+ }
+ } else {
+ h2o_linklist_insert(&conn->_write.streams_to_proceed, &stream->_refs.link);
+ }
+
+ return h2o_http2_conn_get_buffer_window(conn) > 0 ? 0 : -1;
+}
+
+void do_emit_writereq(h2o_http2_conn_t *conn)
+{
+ assert(conn->_write.buf_in_flight == NULL);
+
+ /* push DATA frames */
+ if (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING && h2o_http2_conn_get_buffer_window(conn) > 0)
+ h2o_http2_scheduler_run(&conn->scheduler, emit_writereq_of_openref, conn);
+
+ if (conn->_write.buf->size != 0) {
+ /* write and wait for completion */
+ h2o_iovec_t buf = {conn->_write.buf->bytes, conn->_write.buf->size};
+ h2o_socket_write(conn->sock, &buf, 1, on_write_complete);
+ conn->_write.buf_in_flight = conn->_write.buf;
+ h2o_buffer_init(&conn->_write.buf, &wbuf_buffer_prototype);
+ }
+
+ /* close the connection if necessary */
+ switch (conn->state) {
+ case H2O_HTTP2_CONN_STATE_OPEN:
+ break;
+ case H2O_HTTP2_CONN_STATE_HALF_CLOSED:
+ if (conn->num_streams.pull.half_closed + conn->num_streams.push.half_closed != 0)
+ break;
+ conn->state = H2O_HTTP2_CONN_STATE_IS_CLOSING;
+ /* fall-thru */
+ case H2O_HTTP2_CONN_STATE_IS_CLOSING:
+ close_connection_now(conn);
+ break;
+ }
+}
+
+static void emit_writereq(h2o_timeout_entry_t *entry)
+{
+ h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _write.timeout_entry, entry);
+
+ do_emit_writereq(conn);
+}
+
+static socklen_t get_sockname(h2o_conn_t *_conn, struct sockaddr *sa)
+{
+ h2o_http2_conn_t *conn = (void *)_conn;
+ return h2o_socket_getsockname(conn->sock, sa);
+}
+
+static socklen_t get_peername(h2o_conn_t *_conn, struct sockaddr *sa)
+{
+ h2o_http2_conn_t *conn = (void *)_conn;
+ return h2o_socket_getpeername(conn->sock, sa);
+}
+
+static h2o_socket_t *get_socket(h2o_conn_t *_conn)
+{
+ h2o_http2_conn_t *conn = (void *)_conn;
+ return conn->sock;
+}
+
+#define DEFINE_TLS_LOGGER(name) \
+ static h2o_iovec_t log_##name(h2o_req_t *req) \
+ { \
+ h2o_http2_conn_t *conn = (void *)req->conn; \
+ return h2o_socket_log_ssl_##name(conn->sock, &req->pool); \
+ }
+
+DEFINE_TLS_LOGGER(protocol_version)
+DEFINE_TLS_LOGGER(session_reused)
+DEFINE_TLS_LOGGER(cipher)
+DEFINE_TLS_LOGGER(cipher_bits)
+DEFINE_TLS_LOGGER(session_id)
+#undef DEFINE_TLS_LOGGER
+
+static h2o_iovec_t log_stream_id(h2o_req_t *req)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ char *s = h2o_mem_alloc_pool(&stream->req.pool, sizeof(H2O_UINT32_LONGEST_STR));
+ size_t len = (size_t)sprintf(s, "%" PRIu32, stream->stream_id);
+ return h2o_iovec_init(s, len);
+}
+
+static h2o_iovec_t log_priority_received(h2o_req_t *req)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ char *s = h2o_mem_alloc_pool(&stream->req.pool, sizeof("1:" H2O_UINT32_LONGEST_STR ":" H2O_UINT16_LONGEST_STR));
+ size_t len = (size_t)sprintf(s, "%c:%" PRIu32 ":%" PRIu16, stream->received_priority.exclusive ? '1' : '0',
+ stream->received_priority.dependency, stream->received_priority.weight);
+ return h2o_iovec_init(s, len);
+}
+
+static h2o_iovec_t log_priority_received_exclusive(h2o_req_t *req)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ return h2o_iovec_init(stream->received_priority.exclusive ? "1" : "0", 1);
+}
+
+static h2o_iovec_t log_priority_received_parent(h2o_req_t *req)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ char *s = h2o_mem_alloc_pool(&stream->req.pool, sizeof(H2O_UINT32_LONGEST_STR));
+ size_t len = sprintf(s, "%" PRIu32, stream->received_priority.dependency);
+ return h2o_iovec_init(s, len);
+}
+
+static h2o_iovec_t log_priority_received_weight(h2o_req_t *req)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ char *s = h2o_mem_alloc_pool(&stream->req.pool, sizeof(H2O_UINT16_LONGEST_STR));
+ size_t len = sprintf(s, "%" PRIu16, stream->received_priority.weight);
+ return h2o_iovec_init(s, len);
+}
+
+static uint32_t get_parent_stream_id(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ h2o_http2_scheduler_node_t *parent_sched = h2o_http2_scheduler_get_parent(&stream->_refs.scheduler);
+ if (parent_sched == &conn->scheduler) {
+ return 0;
+ } else {
+ h2o_http2_stream_t *parent_stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, _refs.scheduler, parent_sched);
+ return parent_stream->stream_id;
+ }
+}
+
+static h2o_iovec_t log_priority_actual(h2o_req_t *req)
+{
+ h2o_http2_conn_t *conn = (void *)req->conn;
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ char *s = h2o_mem_alloc_pool(&stream->req.pool, sizeof(H2O_UINT32_LONGEST_STR ":" H2O_UINT16_LONGEST_STR));
+ size_t len = (size_t)sprintf(s, "%" PRIu32 ":%" PRIu16, get_parent_stream_id(conn, stream),
+ h2o_http2_scheduler_get_weight(&stream->_refs.scheduler));
+ return h2o_iovec_init(s, len);
+}
+
+static h2o_iovec_t log_priority_actual_parent(h2o_req_t *req)
+{
+ h2o_http2_conn_t *conn = (void *)req->conn;
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ char *s = h2o_mem_alloc_pool(&stream->req.pool, sizeof(H2O_UINT32_LONGEST_STR));
+ size_t len = (size_t)sprintf(s, "%" PRIu32, get_parent_stream_id(conn, stream));
+ return h2o_iovec_init(s, len);
+}
+
+static h2o_iovec_t log_priority_actual_weight(h2o_req_t *req)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, req);
+ char *s = h2o_mem_alloc_pool(&stream->req.pool, sizeof(H2O_UINT16_LONGEST_STR));
+ size_t len = (size_t)sprintf(s, "%" PRIu16, h2o_http2_scheduler_get_weight(&stream->_refs.scheduler));
+ return h2o_iovec_init(s, len);
+}
+
+static h2o_http2_conn_t *create_conn(h2o_context_t *ctx, h2o_hostconf_t **hosts, h2o_socket_t *sock, struct timeval connected_at)
+{
+ static const h2o_conn_callbacks_t callbacks = {
+ get_sockname, /* stringify address */
+ get_peername, /* ditto */
+ push_path, /* HTTP2 push */
+ get_socket, /* get underlying socket */
+ h2o_http2_get_debug_state, /* get debug state */
+ {{
+ {log_protocol_version, log_session_reused, log_cipher, log_cipher_bits, log_session_id}, /* ssl */
+ {NULL}, /* http1 */
+ {log_stream_id, log_priority_received, log_priority_received_exclusive, log_priority_received_parent,
+ log_priority_received_weight, log_priority_actual, log_priority_actual_parent, log_priority_actual_weight} /* http2 */
+ }} /* loggers */
+ };
+
+ h2o_http2_conn_t *conn = (void *)h2o_create_connection(sizeof(*conn), ctx, hosts, connected_at, &callbacks);
+
+ memset((char *)conn + sizeof(conn->super), 0, sizeof(*conn) - sizeof(conn->super));
+ conn->sock = sock;
+ conn->peer_settings = H2O_HTTP2_SETTINGS_DEFAULT;
+ conn->streams = kh_init(h2o_http2_stream_t);
+ h2o_http2_scheduler_init(&conn->scheduler);
+ conn->state = H2O_HTTP2_CONN_STATE_OPEN;
+ h2o_linklist_insert(&ctx->http2._conns, &conn->_conns);
+ conn->_read_expect = expect_preface;
+ conn->_input_header_table.hpack_capacity = conn->_input_header_table.hpack_max_capacity =
+ H2O_HTTP2_SETTINGS_DEFAULT.header_table_size;
+ h2o_http2_window_init(&conn->_input_window, &H2O_HTTP2_SETTINGS_DEFAULT);
+ conn->_output_header_table.hpack_capacity = H2O_HTTP2_SETTINGS_HOST.header_table_size;
+ h2o_linklist_init_anchor(&conn->_pending_reqs);
+ h2o_buffer_init(&conn->_write.buf, &wbuf_buffer_prototype);
+ h2o_linklist_init_anchor(&conn->_write.streams_to_proceed);
+ conn->_write.timeout_entry.cb = emit_writereq;
+ h2o_http2_window_init(&conn->_write.window, &conn->peer_settings);
+
+ return conn;
+}
+
+static int update_push_memo(h2o_http2_conn_t *conn, h2o_req_t *src_req, const char *abspath, size_t abspath_len)
+{
+
+ if (conn->push_memo == NULL)
+ conn->push_memo = h2o_cache_create(0, 1024, 1, NULL);
+
+ /* uses the hash as the key */
+ h2o_cache_hashcode_t url_hash = h2o_cache_calchash(src_req->input.scheme->name.base, src_req->input.scheme->name.len) ^
+ h2o_cache_calchash(src_req->input.authority.base, src_req->input.authority.len) ^
+ h2o_cache_calchash(abspath, abspath_len);
+ return h2o_cache_set(conn->push_memo, 0, h2o_iovec_init(&url_hash, sizeof(url_hash)), url_hash, h2o_iovec_init(NULL, 0));
+}
+
+static void push_path(h2o_req_t *src_req, const char *abspath, size_t abspath_len)
+{
+ h2o_http2_conn_t *conn = (void *)src_req->conn;
+ h2o_http2_stream_t *src_stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, req, src_req);
+
+ /* RFC 7540 8.2.1: PUSH_PROMISE frames can be sent by the server in response to any client-initiated stream */
+ if (h2o_http2_stream_is_push(src_stream->stream_id))
+ return;
+
+ if (!src_stream->req.hostconf->http2.push_preload || !conn->peer_settings.enable_push ||
+ conn->num_streams.push.open >= conn->peer_settings.max_concurrent_streams)
+ return;
+
+ if (conn->push_stream_ids.max_open >= 0x7ffffff0)
+ return;
+ if (!(h2o_linklist_is_empty(&conn->_pending_reqs) && can_run_requests(conn)))
+ return;
+
+ if (h2o_find_header(&src_stream->req.headers, H2O_TOKEN_X_FORWARDED_FOR, -1) != -1)
+ return;
+
+ if (src_stream->cache_digests != NULL) {
+ h2o_iovec_t url = h2o_concat(&src_stream->req.pool, src_stream->req.input.scheme->name, h2o_iovec_init(H2O_STRLIT("://")),
+ src_stream->req.input.authority, h2o_iovec_init(abspath, abspath_len));
+ if (h2o_cache_digests_lookup_by_url(src_stream->cache_digests, url.base, url.len) == H2O_CACHE_DIGESTS_STATE_FRESH)
+ return;
+ }
+
+ /* delayed initialization of casper (cookie-based), that MAY be used together to cache-digests */
+ if (src_stream->req.hostconf->http2.casper.capacity_bits != 0) {
+ if (!src_stream->pull.casper_is_ready) {
+ src_stream->pull.casper_is_ready = 1;
+ if (conn->casper == NULL)
+ h2o_http2_conn_init_casper(conn, src_stream->req.hostconf->http2.casper.capacity_bits);
+ ssize_t header_index;
+ for (header_index = -1;
+ (header_index = h2o_find_header(&src_stream->req.headers, H2O_TOKEN_COOKIE, header_index)) != -1;) {
+ h2o_header_t *header = src_stream->req.headers.entries + header_index;
+ h2o_http2_casper_consume_cookie(conn->casper, header->value.base, header->value.len);
+ }
+ }
+ }
+
+ /* update the push memo, and if it already pushed on the same connection, return */
+ if (update_push_memo(conn, &src_stream->req, abspath, abspath_len))
+ return;
+
+ /* open the stream */
+ h2o_http2_stream_t *stream = h2o_http2_stream_open(conn, conn->push_stream_ids.max_open + 2, NULL, &h2o_http2_default_priority);
+ stream->received_priority.dependency = src_stream->stream_id;
+ stream->push.parent_stream_id = src_stream->stream_id;
+ h2o_http2_scheduler_open(&stream->_refs.scheduler, &src_stream->_refs.scheduler.node, 16, 0);
+ h2o_http2_stream_prepare_for_request(conn, stream);
+
+ /* setup request */
+ stream->req.input.method = (h2o_iovec_t){H2O_STRLIT("GET")};
+ stream->req.input.scheme = src_stream->req.input.scheme;
+ stream->req.input.authority =
+ h2o_strdup(&stream->req.pool, src_stream->req.input.authority.base, src_stream->req.input.authority.len);
+ stream->req.input.path = h2o_strdup(&stream->req.pool, abspath, abspath_len);
+ stream->req.version = 0x200;
+
+ { /* copy headers that may affect the response (of a cacheable response) */
+ size_t i;
+ for (i = 0; i != src_stream->req.headers.size; ++i) {
+ h2o_header_t *src_header = src_stream->req.headers.entries + i;
+ if (h2o_iovec_is_token(src_header->name)) {
+ h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, src_header->name);
+ if (token->copy_for_push_request) {
+ h2o_add_header(&stream->req.pool, &stream->req.headers, token, NULL,
+ h2o_strdup(&stream->req.pool, src_header->value.base, src_header->value.len).base,
+ src_header->value.len);
+ }
+ }
+ }
+ }
+
+ execute_or_enqueue_request(conn, stream);
+
+ /* send push-promise ASAP (before the parent stream gets closed), even if execute_or_enqueue_request did not trigger the
+ * invocation of send_headers */
+ if (!stream->push.promise_sent && stream->state != H2O_HTTP2_STREAM_STATE_END_STREAM)
+ h2o_http2_stream_send_push_promise(conn, stream);
+}
+
+static int foreach_request(h2o_context_t *ctx, int (*cb)(h2o_req_t *req, void *cbdata), void *cbdata)
+{
+ h2o_linklist_t *node;
+
+ for (node = ctx->http2._conns.next; node != &ctx->http2._conns; node = node->next) {
+ h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node);
+ h2o_http2_stream_t *stream;
+ kh_foreach_value(conn->streams, stream, {
+ int ret = cb(&stream->req, cbdata);
+ if (ret != 0)
+ return ret;
+ });
+ }
+ return 0;
+}
+
+void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at)
+{
+ h2o_http2_conn_t *conn = create_conn(ctx->ctx, ctx->hosts, sock, connected_at);
+ sock->data = conn;
+ h2o_socket_read_start(conn->sock, on_read);
+ update_idle_timeout(conn);
+ if (sock->input->size != 0)
+ on_read(sock, 0);
+}
+
+int h2o_http2_handle_upgrade(h2o_req_t *req, struct timeval connected_at)
+{
+ h2o_http2_conn_t *http2conn = create_conn(req->conn->ctx, req->conn->hosts, NULL, connected_at);
+ h2o_http2_stream_t *stream;
+ ssize_t connection_index, settings_index;
+ h2o_iovec_t settings_decoded;
+ const char *err_desc;
+
+ assert(req->version < 0x200); /* from HTTP/1.x */
+
+ /* check that "HTTP2-Settings" is declared in the connection header */
+ connection_index = h2o_find_header(&req->headers, H2O_TOKEN_CONNECTION, -1);
+ assert(connection_index != -1);
+ if (!h2o_contains_token(req->headers.entries[connection_index].value.base, req->headers.entries[connection_index].value.len,
+ H2O_STRLIT("http2-settings"), ',')) {
+ goto Error;
+ }
+
+ /* decode the settings */
+ if ((settings_index = h2o_find_header(&req->headers, H2O_TOKEN_HTTP2_SETTINGS, -1)) == -1) {
+ goto Error;
+ }
+ if ((settings_decoded = h2o_decode_base64url(&req->pool, req->headers.entries[settings_index].value.base,
+ req->headers.entries[settings_index].value.len))
+ .base == NULL) {
+ goto Error;
+ }
+ if (h2o_http2_update_peer_settings(&http2conn->peer_settings, (uint8_t *)settings_decoded.base, settings_decoded.len,
+ &err_desc) != 0) {
+ goto Error;
+ }
+
+ /* open the stream, now that the function is guaranteed to succeed */
+ stream = h2o_http2_stream_open(http2conn, 1, req, &h2o_http2_default_priority);
+ h2o_http2_scheduler_open(&stream->_refs.scheduler, &http2conn->scheduler, h2o_http2_default_priority.weight, 0);
+ h2o_http2_stream_prepare_for_request(http2conn, stream);
+
+ /* send response */
+ req->res.status = 101;
+ req->res.reason = "Switching Protocols";
+ h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_UPGRADE, NULL, H2O_STRLIT("h2c"));
+ h2o_http1_upgrade(req, (h2o_iovec_t *)&SETTINGS_HOST_BIN, 1, on_upgrade_complete, http2conn);
+
+ return 0;
+Error:
+ h2o_linklist_unlink(&http2conn->_conns);
+ kh_destroy(h2o_http2_stream_t, http2conn->streams);
+ free(http2conn);
+ return -1;
+}
diff --git a/web/server/h2o/libh2o/lib/http2/frame.c b/web/server/h2o/libh2o/lib/http2/frame.c
new file mode 100644
index 000000000..86abdaa48
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/frame.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * 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 "h2o.h"
+#include "h2o/http2.h"
+#include "h2o/http2_internal.h"
+
+const h2o_http2_settings_t H2O_HTTP2_SETTINGS_DEFAULT = {
+ /* header_table_size */ 4096,
+ /* enable_push */ 1,
+ /* max_concurrent_streams */ UINT32_MAX,
+ /* initial_window_size */ 65535,
+ /* max_frame_size */ 16384};
+
+int h2o_http2_update_peer_settings(h2o_http2_settings_t *settings, const uint8_t *src, size_t len, const char **err_desc)
+{
+ for (; len >= 6; len -= 6, src += 6) {
+ uint16_t identifier = h2o_http2_decode16u(src);
+ uint32_t value = h2o_http2_decode32u(src + 2);
+ switch (identifier) {
+#define SET(label, member, min, max, err_code) \
+ case H2O_HTTP2_SETTINGS_##label: \
+ if (!(min <= value && value <= max)) { \
+ *err_desc = "invalid SETTINGS frame"; \
+ return err_code; \
+ } \
+ settings->member = value; \
+ break
+ SET(HEADER_TABLE_SIZE, header_table_size, 0, UINT32_MAX, 0);
+ SET(ENABLE_PUSH, enable_push, 0, 1, H2O_HTTP2_ERROR_PROTOCOL);
+ SET(MAX_CONCURRENT_STREAMS, max_concurrent_streams, 0, UINT32_MAX, 0);
+ SET(INITIAL_WINDOW_SIZE, initial_window_size, 0, 0x7fffffff, H2O_HTTP2_ERROR_FLOW_CONTROL);
+ SET(MAX_FRAME_SIZE, max_frame_size, 16384, 16777215, H2O_HTTP2_ERROR_PROTOCOL);
+#undef SET
+ default:
+ /* ignore unknown (5.5) */
+ break;
+ }
+ }
+
+ if (len != 0)
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+ return 0;
+}
+
+uint8_t *h2o_http2_encode_frame_header(uint8_t *dst, size_t length, uint8_t type, uint8_t flags, int32_t stream_id)
+{
+ if (length > 0xffffff)
+ h2o_fatal("invalid length");
+
+ dst = h2o_http2_encode24u(dst, (uint32_t)length);
+ *dst++ = type;
+ *dst++ = flags;
+ dst = h2o_http2_encode32u(dst, stream_id);
+
+ return dst;
+}
+
+static uint8_t *allocate_frame(h2o_buffer_t **buf, size_t length, uint8_t type, uint8_t flags, int32_t stream_id)
+{
+ h2o_iovec_t alloced = h2o_buffer_reserve(buf, H2O_HTTP2_FRAME_HEADER_SIZE + length);
+ (*buf)->size += H2O_HTTP2_FRAME_HEADER_SIZE + length;
+ return h2o_http2_encode_frame_header((uint8_t *)alloced.base, length, type, flags, stream_id);
+}
+
+void h2o_http2__encode_rst_stream_frame(h2o_buffer_t **buf, uint32_t stream_id, int errnum)
+{
+ uint8_t *dst = allocate_frame(buf, 4, H2O_HTTP2_FRAME_TYPE_RST_STREAM, 0, stream_id);
+ dst = h2o_http2_encode32u(dst, errnum);
+}
+
+void h2o_http2_encode_ping_frame(h2o_buffer_t **buf, int is_ack, const uint8_t *data)
+{
+ uint8_t *dst = allocate_frame(buf, 8, H2O_HTTP2_FRAME_TYPE_PING, is_ack ? H2O_HTTP2_FRAME_FLAG_ACK : 0, 0);
+ memcpy(dst, data, 8);
+ dst += 8;
+}
+
+void h2o_http2_encode_goaway_frame(h2o_buffer_t **buf, uint32_t last_stream_id, int errnum, h2o_iovec_t additional_data)
+{
+ uint8_t *dst = allocate_frame(buf, 8 + additional_data.len, H2O_HTTP2_FRAME_TYPE_GOAWAY, 0, 0);
+ dst = h2o_http2_encode32u(dst, last_stream_id);
+ dst = h2o_http2_encode32u(dst, (uint32_t)-errnum);
+ h2o_memcpy(dst, additional_data.base, additional_data.len);
+}
+
+void h2o_http2_encode_window_update_frame(h2o_buffer_t **buf, uint32_t stream_id, int32_t window_size_increment)
+{
+ uint8_t *dst = allocate_frame(buf, 4, H2O_HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0, stream_id);
+ dst = h2o_http2_encode32u(dst, window_size_increment);
+}
+
+ssize_t h2o_http2_decode_frame(h2o_http2_frame_t *frame, const uint8_t *src, size_t len, const h2o_http2_settings_t *host_settings,
+ const char **err_desc)
+{
+ if (len < H2O_HTTP2_FRAME_HEADER_SIZE)
+ return H2O_HTTP2_ERROR_INCOMPLETE;
+
+ frame->length = h2o_http2_decode24u(src);
+ frame->type = src[3];
+ frame->flags = src[4];
+ frame->stream_id = h2o_http2_decode32u(src + 5) & 0x7fffffff;
+
+ if (frame->length > host_settings->max_frame_size)
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+
+ if (len < H2O_HTTP2_FRAME_HEADER_SIZE + frame->length)
+ return H2O_HTTP2_ERROR_INCOMPLETE;
+
+ frame->payload = src + H2O_HTTP2_FRAME_HEADER_SIZE;
+
+ return H2O_HTTP2_FRAME_HEADER_SIZE + frame->length;
+}
+
+int h2o_http2_decode_data_payload(h2o_http2_data_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc)
+{
+ if (frame->stream_id == 0) {
+ *err_desc = "invalid stream id in DATA frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_PADDED) != 0) {
+ uint8_t padding_length;
+ if (frame->length < 1) {
+ *err_desc = "invalid DATA frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ padding_length = frame->payload[0];
+ if (frame->length < 1 + padding_length) {
+ *err_desc = "invalid DATA frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ payload->data = frame->payload + 1;
+ payload->length = frame->length - (1 + padding_length);
+ } else {
+ payload->data = frame->payload;
+ payload->length = frame->length;
+ }
+ return 0;
+}
+
+static const uint8_t *decode_priority(h2o_http2_priority_t *priority, const uint8_t *src)
+{
+ uint32_t u4 = h2o_http2_decode32u(src);
+ src += 4;
+ priority->exclusive = u4 >> 31;
+ priority->dependency = u4 & 0x7fffffff;
+ priority->weight = (uint16_t)*src++ + 1;
+ return src;
+}
+
+int h2o_http2_decode_headers_payload(h2o_http2_headers_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc)
+{
+ const uint8_t *src = frame->payload, *src_end = frame->payload + frame->length;
+
+ if (frame->stream_id == 0) {
+ *err_desc = "invalid stream id in HEADERS frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_PADDED) != 0) {
+ uint32_t padlen;
+ if (src == src_end) {
+ *err_desc = "invalid HEADERS frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ padlen = *src++;
+ if (src_end - src < padlen) {
+ *err_desc = "invalid HEADERS frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ src_end -= padlen;
+ }
+
+ if ((frame->flags & H2O_HTTP2_FRAME_FLAG_PRIORITY) != 0) {
+ if (src_end - src < 5)
+ return -1;
+ src = decode_priority(&payload->priority, src);
+ } else {
+ payload->priority = h2o_http2_default_priority;
+ }
+
+ payload->headers = src;
+ payload->headers_len = src_end - src;
+
+ return 0;
+}
+
+int h2o_http2_decode_priority_payload(h2o_http2_priority_t *payload, const h2o_http2_frame_t *frame, const char **err_desc)
+{
+ if (frame->stream_id == 0) {
+ *err_desc = "invalid stream id in PRIORITY frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ if (frame->length != 5) {
+ *err_desc = "invalid PRIORITY frame";
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+ }
+
+ decode_priority(payload, frame->payload);
+ return 0;
+}
+
+int h2o_http2_decode_rst_stream_payload(h2o_http2_rst_stream_payload_t *payload, const h2o_http2_frame_t *frame,
+ const char **err_desc)
+{
+ if (frame->stream_id == 0) {
+ *err_desc = "invalid stream id in RST_STREAM frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ if (frame->length != sizeof(payload->error_code)) {
+ *err_desc = "invalid RST_STREAM frame";
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+ }
+
+ payload->error_code = h2o_http2_decode32u(frame->payload);
+ return 0;
+}
+
+int h2o_http2_decode_ping_payload(h2o_http2_ping_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc)
+{
+ if (frame->stream_id != 0) {
+ *err_desc = "invalid PING frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ if (frame->length != sizeof(payload->data)) {
+ *err_desc = "invalid PING frame";
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+ }
+
+ memcpy(payload->data, frame->payload, sizeof(payload->data));
+ return 0;
+}
+
+int h2o_http2_decode_goaway_payload(h2o_http2_goaway_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc)
+{
+ if (frame->stream_id != 0) {
+ *err_desc = "invalid stream id in GOAWAY frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ if (frame->length < 8) {
+ *err_desc = "invalid GOAWAY frame";
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+ }
+
+ payload->last_stream_id = h2o_http2_decode32u(frame->payload) & 0x7fffffff;
+ payload->error_code = h2o_http2_decode32u(frame->payload + 4);
+ if ((payload->debug_data.len = frame->length - 8) != 0)
+ payload->debug_data.base = (char *)frame->payload + 8;
+ else
+ payload->debug_data.base = NULL;
+
+ return 0;
+}
+
+int h2o_http2_decode_window_update_payload(h2o_http2_window_update_payload_t *payload, const h2o_http2_frame_t *frame,
+ const char **err_desc, int *err_is_stream_level)
+{
+ if (frame->length != 4) {
+ *err_is_stream_level = 0;
+ return H2O_HTTP2_ERROR_FRAME_SIZE;
+ }
+
+ payload->window_size_increment = h2o_http2_decode32u(frame->payload) & 0x7fffffff;
+ if (payload->window_size_increment == 0) {
+ *err_is_stream_level = frame->stream_id != 0;
+ *err_desc = "invalid WINDOW_UPDATE frame";
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+
+ return 0;
+}
diff --git a/web/server/h2o/libh2o/lib/http2/hpack.c b/web/server/h2o/libh2o/lib/http2/hpack.c
new file mode 100644
index 000000000..4adb15cd7
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/hpack.c
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc.
+ *
+ * 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "h2o.h"
+#include "h2o/http2.h"
+#include "h2o/http2_internal.h"
+
+#define HEADER_TABLE_OFFSET 62
+#define HEADER_TABLE_ENTRY_SIZE_OFFSET 32
+#define STATUS_HEADER_MAX_SIZE 5
+#define CONTENT_LENGTH_HEADER_MAX_SIZE \
+ (3 + sizeof(H2O_UINT64_LONGEST_STR) - 1) /* uses Literal Header Field without Indexing (RFC7541 6.2.2) */
+
+struct st_h2o_hpack_static_table_entry_t {
+ const h2o_token_t *name;
+ const h2o_iovec_t value;
+};
+
+struct st_h2o_decode_header_result_t {
+ h2o_iovec_t *name;
+ h2o_iovec_t *value;
+};
+
+#include "hpack_huffman_table.h"
+#include "hpack_static_table.h"
+
+static inline int value_is_part_of_static_table(const h2o_iovec_t *value)
+{
+ return &h2o_hpack_static_table[0].value <= value &&
+ value <= &h2o_hpack_static_table[sizeof(h2o_hpack_static_table) / sizeof(h2o_hpack_static_table[0]) - 1].value;
+}
+
+static h2o_iovec_t *alloc_buf(h2o_mem_pool_t *pool, size_t len)
+{
+ h2o_iovec_t *buf = h2o_mem_alloc_shared(pool, sizeof(h2o_iovec_t) + len + 1, NULL);
+ buf->base = (char *)buf + sizeof(h2o_iovec_t);
+ buf->len = len;
+ return buf;
+}
+
+/* validate a header value against https://tools.ietf.org/html/rfc7230#section-3.2 */
+static int contains_invalid_field_value_char(const char *s, size_t len)
+{
+ /* all printable chars + horizontal tab */
+ static const char valid_h2_field_value_char[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-31 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 32-63 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-95 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 96-127 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 128-159 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 160-191 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 192-223 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 224-255 */
+ };
+
+ for (; len != 0; ++s, --len) {
+ unsigned char ch = (unsigned char)*s;
+ if (!valid_h2_field_value_char[ch]) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static const char *err_found_upper_case_in_header_name = "found an upper-case letter in header name";
+static const char *soft_err_found_invalid_char_in_header_name = "found an invalid character in header name";
+static const char *soft_err_found_invalid_char_in_header_value = "found an invalid character in header value";
+
+/* validate a header name against https://tools.ietf.org/html/rfc7230#section-3.2,
+ * in addition to that, we disallow upper case chars as well.
+ * This sets @err_desc for all invalid characters, but only returns true
+ * for upper case characters, this is because we return a protocol error
+ * in that case. */
+static const char *validate_header_name(const char *s, size_t len)
+{
+ const char *ret = NULL;
+ /* all printable chars, except upper case and separator characters */
+ static const char valid_h2_header_name_char[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-31 */
+ 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 32-63 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, /* 64-95 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, /* 96-127 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-159 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160-191 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192-223 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224-255 */
+ };
+
+ for (; len != 0; ++s, --len) {
+ unsigned char ch = (unsigned char)*s;
+ if (!valid_h2_header_name_char[ch]) {
+ if (ch - 'A' < 26U) {
+ return err_found_upper_case_in_header_name;
+ }
+ ret = soft_err_found_invalid_char_in_header_name;
+ }
+ }
+ return ret;
+}
+
+static int32_t decode_int(const uint8_t **src, const uint8_t *src_end, size_t prefix_bits)
+{
+ int32_t value, mult;
+ uint8_t prefix_max = (1 << prefix_bits) - 1;
+
+ if (*src >= src_end)
+ return -1;
+
+ value = (uint8_t) * (*src)++ & prefix_max;
+ if (value != prefix_max) {
+ return value;
+ }
+
+ /* we only allow at most 4 octets (excluding prefix) to be used as int (== 2**(4*7) == 2**28) */
+ if (src_end - *src > 4)
+ src_end = *src + 4;
+
+ value = prefix_max;
+ for (mult = 1;; mult *= 128) {
+ if (*src >= src_end)
+ return -1;
+ value += (**src & 127) * mult;
+ if ((*(*src)++ & 128) == 0)
+ return value;
+ }
+}
+
+static char *huffdecode4(char *dst, uint8_t in, uint8_t *state, int *maybe_eos, uint8_t *seen_char_types)
+{
+ const nghttp2_huff_decode *entry = huff_decode_table[*state] + in;
+
+ if ((entry->flags & NGHTTP2_HUFF_FAIL) != 0)
+ return NULL;
+ if ((entry->flags & NGHTTP2_HUFF_SYM) != 0) {
+ *dst++ = entry->sym;
+ *seen_char_types |= (entry->flags & NGHTTP2_HUFF_INVALID_CHARS);
+ }
+ *state = entry->state;
+ *maybe_eos = (entry->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
+
+ return dst;
+}
+
+static h2o_iovec_t *decode_huffman(h2o_mem_pool_t *pool, const uint8_t *src, size_t len, uint8_t *seen_char_types)
+{
+ const uint8_t *src_end = src + len;
+ char *dst;
+ uint8_t state = 0;
+ int maybe_eos = 1;
+ h2o_iovec_t *dst_buf = alloc_buf(pool, len * 2); /* max compression ratio is >= 0.5 */
+
+ dst = dst_buf->base;
+ for (; src < src_end; src++) {
+ if ((dst = huffdecode4(dst, *src >> 4, &state, &maybe_eos, seen_char_types)) == NULL)
+ return NULL;
+ if ((dst = huffdecode4(dst, *src & 0xf, &state, &maybe_eos, seen_char_types)) == NULL)
+ return NULL;
+ }
+
+ if (!maybe_eos)
+ return NULL;
+
+ *dst = '\0';
+ dst_buf->len = dst - dst_buf->base;
+ return dst_buf;
+}
+
+static h2o_iovec_t *decode_string(h2o_mem_pool_t *pool, const uint8_t **src, const uint8_t *src_end, int is_header_name,
+ const char **err_desc)
+{
+ h2o_iovec_t *ret;
+ int is_huffman;
+ int32_t len;
+
+ if (*src >= src_end)
+ return NULL;
+
+ is_huffman = (**src & 0x80) != 0;
+ if ((len = decode_int(src, src_end, 7)) == -1)
+ return NULL;
+
+ if (is_huffman) {
+ uint8_t hflags = 0;
+ if (*src + len > src_end)
+ return NULL;
+ if ((ret = decode_huffman(pool, *src, len, &hflags)) == NULL)
+ return NULL;
+ if (is_header_name) {
+ if (ret->len <= 0) {
+ return NULL;
+ }
+ /* pseudo-headers are checked later in `decode_header` */
+ if (hflags & NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME && ret->base[0] != ':') {
+ if (hflags & NGHTTP2_HUFF_UPPER_CASE_CHAR) {
+ *err_desc = err_found_upper_case_in_header_name;
+ return NULL;
+ } else {
+ *err_desc = soft_err_found_invalid_char_in_header_name;
+ }
+ }
+ } else {
+ if (hflags & NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE) {
+ *err_desc = soft_err_found_invalid_char_in_header_value;
+ }
+ }
+ } else {
+ if (*src + len > src_end)
+ return NULL;
+ if (is_header_name) {
+ /* pseudo-headers are checked later in `decode_header` */
+ if (**src != (uint8_t)':') {
+ *err_desc = validate_header_name((char *)*src, len);
+ if (*err_desc == err_found_upper_case_in_header_name) {
+ return NULL;
+ }
+ }
+ } else {
+ if (contains_invalid_field_value_char((char *)*src, len)) {
+ *err_desc = soft_err_found_invalid_char_in_header_value;
+ }
+ }
+ ret = alloc_buf(pool, len);
+ memcpy(ret->base, *src, len);
+ ret->base[len] = '\0';
+ }
+ *src += len;
+
+ return ret;
+}
+
+static void header_table_evict_one(h2o_hpack_header_table_t *table)
+{
+ struct st_h2o_hpack_header_table_entry_t *entry;
+ assert(table->num_entries != 0);
+
+ entry = h2o_hpack_header_table_get(table, --table->num_entries);
+ table->hpack_size -= entry->name->len + entry->value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET;
+ if (!h2o_iovec_is_token(entry->name))
+ h2o_mem_release_shared(entry->name);
+ if (!value_is_part_of_static_table(entry->value))
+ h2o_mem_release_shared(entry->value);
+ memset(entry, 0, sizeof(*entry));
+}
+
+static struct st_h2o_hpack_header_table_entry_t *header_table_add(h2o_hpack_header_table_t *table, size_t size_add,
+ size_t max_num_entries)
+{
+ /* adjust the size */
+ while (table->num_entries != 0 && table->hpack_size + size_add > table->hpack_capacity)
+ header_table_evict_one(table);
+ while (max_num_entries <= table->num_entries)
+ header_table_evict_one(table);
+ if (table->num_entries == 0) {
+ assert(table->hpack_size == 0);
+ if (size_add > table->hpack_capacity)
+ return NULL;
+ }
+ table->hpack_size += size_add;
+
+ /* grow the entries if full */
+ if (table->num_entries == table->entry_capacity) {
+ size_t new_capacity = table->num_entries * 2;
+ if (new_capacity < 16)
+ new_capacity = 16;
+ struct st_h2o_hpack_header_table_entry_t *new_entries =
+ h2o_mem_alloc(new_capacity * sizeof(struct st_h2o_hpack_header_table_entry_t));
+ if (table->num_entries != 0) {
+ size_t src_index = table->entry_start_index, dst_index = 0;
+ do {
+ new_entries[dst_index] = table->entries[src_index];
+ ++dst_index;
+ src_index = (src_index + 1) % table->entry_capacity;
+ } while (dst_index != table->num_entries);
+ }
+ memset(new_entries + table->num_entries, 0, sizeof(*new_entries) * (new_capacity - table->num_entries));
+ free(table->entries);
+ table->entries = new_entries;
+ table->entry_capacity = new_capacity;
+ table->entry_start_index = 0;
+ }
+
+ ++table->num_entries;
+ table->entry_start_index = (table->entry_start_index + table->entry_capacity - 1) % table->entry_capacity;
+ return table->entries + table->entry_start_index;
+}
+
+static int decode_header(h2o_mem_pool_t *pool, struct st_h2o_decode_header_result_t *result,
+ h2o_hpack_header_table_t *hpack_header_table, const uint8_t **const src, const uint8_t *src_end,
+ const char **err_desc)
+{
+ int32_t index = 0;
+ int value_is_indexed = 0, do_index = 0;
+
+Redo:
+ if (*src >= src_end)
+ return H2O_HTTP2_ERROR_COMPRESSION;
+
+ /* determine the mode and handle accordingly */
+ if (**src >= 128) {
+ /* indexed header field representation */
+ if ((index = decode_int(src, src_end, 7)) <= 0)
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ value_is_indexed = 1;
+ } else if (**src >= 64) {
+ /* literal header field with incremental handling */
+ if (**src == 64) {
+ ++*src;
+ } else if ((index = decode_int(src, src_end, 6)) <= 0) {
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ }
+ do_index = 1;
+ } else if (**src < 32) {
+ /* literal header field without indexing / never indexed */
+ if ((**src & 0xf) == 0) {
+ ++*src;
+ } else if ((index = decode_int(src, src_end, 4)) <= 0) {
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ }
+ } else {
+ /* size update */
+ int new_apacity;
+ if ((new_apacity = decode_int(src, src_end, 5)) < 0) {
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ }
+ if (new_apacity > hpack_header_table->hpack_max_capacity) {
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ }
+ hpack_header_table->hpack_capacity = new_apacity;
+ while (hpack_header_table->num_entries != 0 && hpack_header_table->hpack_size > hpack_header_table->hpack_capacity) {
+ header_table_evict_one(hpack_header_table);
+ }
+ goto Redo;
+ }
+
+ /* determine the header */
+ if (index > 0) {
+ /* existing name (and value?) */
+ if (index < HEADER_TABLE_OFFSET) {
+ result->name = (h2o_iovec_t *)h2o_hpack_static_table[index - 1].name;
+ if (value_is_indexed) {
+ result->value = (h2o_iovec_t *)&h2o_hpack_static_table[index - 1].value;
+ }
+ } else if (index - HEADER_TABLE_OFFSET < hpack_header_table->num_entries) {
+ struct st_h2o_hpack_header_table_entry_t *entry =
+ h2o_hpack_header_table_get(hpack_header_table, index - HEADER_TABLE_OFFSET);
+ *err_desc = entry->err_desc;
+ result->name = entry->name;
+ if (!h2o_iovec_is_token(result->name))
+ h2o_mem_link_shared(pool, result->name);
+ if (value_is_indexed) {
+ result->value = entry->value;
+ h2o_mem_link_shared(pool, result->value);
+ }
+ } else {
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ }
+ } else {
+ /* non-existing name */
+ const h2o_token_t *name_token;
+ if ((result->name = decode_string(pool, src, src_end, 1, err_desc)) == NULL) {
+ if (*err_desc == err_found_upper_case_in_header_name) {
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ }
+ if (!*err_desc) {
+ /* predefined header names should be interned */
+ if ((name_token = h2o_lookup_token(result->name->base, result->name->len)) != NULL) {
+ result->name = (h2o_iovec_t *)&name_token->buf;
+ }
+ }
+ }
+
+ /* determine the value (if necessary) */
+ if (!value_is_indexed) {
+ if ((result->value = decode_string(pool, src, src_end, 0, err_desc)) == NULL) {
+ return H2O_HTTP2_ERROR_COMPRESSION;
+ }
+ }
+
+ /* add the decoded header to the header table if necessary */
+ if (do_index) {
+ struct st_h2o_hpack_header_table_entry_t *entry =
+ header_table_add(hpack_header_table, result->name->len + result->value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, SIZE_MAX);
+ if (entry != NULL) {
+ entry->err_desc = *err_desc;
+ entry->name = result->name;
+ if (!h2o_iovec_is_token(entry->name))
+ h2o_mem_addref_shared(entry->name);
+ entry->value = result->value;
+ if (!value_is_part_of_static_table(entry->value))
+ h2o_mem_addref_shared(entry->value);
+ }
+ }
+
+ return *err_desc ? H2O_HTTP2_ERROR_INVALID_HEADER_CHAR : 0;
+}
+
+static uint8_t *encode_status(uint8_t *dst, int status)
+{
+ /* see also: STATUS_HEADER_MAX_SIZE */
+
+ assert(100 <= status && status <= 999);
+
+ switch (status) {
+#define COMMON_CODE(code, st) \
+ case st: \
+ *dst++ = 0x80 | code; \
+ break
+ COMMON_CODE(8, 200);
+ COMMON_CODE(9, 204);
+ COMMON_CODE(10, 206);
+ COMMON_CODE(11, 304);
+ COMMON_CODE(12, 400);
+ COMMON_CODE(13, 404);
+ COMMON_CODE(14, 500);
+#undef COMMON_CODE
+ default:
+ /* use literal header field without indexing - indexed name */
+ *dst++ = 8;
+ *dst++ = 3;
+ sprintf((char *)dst, "%d", status);
+ dst += 3;
+ break;
+ }
+
+ return dst;
+}
+
+static uint8_t *encode_content_length(uint8_t *dst, size_t value)
+{
+ char buf[32], *p = buf + sizeof(buf);
+ size_t l;
+
+ do {
+ *--p = '0' + value % 10;
+ } while ((value /= 10) != 0);
+ l = buf + sizeof(buf) - p;
+ *dst++ = 0x0f;
+ *dst++ = 0x0d;
+ *dst++ = (uint8_t)l;
+ memcpy(dst, p, l);
+ dst += l;
+
+ return dst;
+}
+
+void h2o_hpack_dispose_header_table(h2o_hpack_header_table_t *header_table)
+{
+ if (header_table->num_entries != 0) {
+ size_t index = header_table->entry_start_index;
+ do {
+ struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + index;
+ if (!h2o_iovec_is_token(entry->name))
+ h2o_mem_release_shared(entry->name);
+ if (!value_is_part_of_static_table(entry->value))
+ h2o_mem_release_shared(entry->value);
+ index = (index + 1) % header_table->entry_capacity;
+ } while (--header_table->num_entries != 0);
+ }
+ free(header_table->entries);
+}
+
+int h2o_hpack_parse_headers(h2o_req_t *req, h2o_hpack_header_table_t *header_table, const uint8_t *src, size_t len,
+ int *pseudo_header_exists_map, size_t *content_length, h2o_cache_digests_t **digests,
+ const char **err_desc)
+{
+ const uint8_t *src_end = src + len;
+
+ *content_length = SIZE_MAX;
+
+ while (src != src_end) {
+ struct st_h2o_decode_header_result_t r;
+ const char *decode_err = NULL;
+ int ret = decode_header(&req->pool, &r, header_table, &src, src_end, &decode_err);
+ if (ret != 0) {
+ if (ret == H2O_HTTP2_ERROR_INVALID_HEADER_CHAR) {
+ /* this is a soft error, we continue parsing, but register only the first error */
+ if (*err_desc == NULL) {
+ *err_desc = decode_err;
+ }
+ } else {
+ *err_desc = decode_err;
+ return ret;
+ }
+ }
+ if (r.name->base[0] == ':') {
+ if (pseudo_header_exists_map != NULL) {
+ /* FIXME validate the chars in the value (e.g. reject SP in path) */
+ if (r.name == &H2O_TOKEN_AUTHORITY->buf) {
+ /* FIXME should we perform this check? */
+ if (req->input.authority.base != NULL)
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ req->input.authority = *r.value;
+ *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_AUTHORITY_EXISTS;
+ } else if (r.name == &H2O_TOKEN_METHOD->buf) {
+ if (req->input.method.base != NULL)
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ req->input.method = *r.value;
+ *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_METHOD_EXISTS;
+ } else if (r.name == &H2O_TOKEN_PATH->buf) {
+ if (req->input.path.base != NULL)
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ req->input.path = *r.value;
+ *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_PATH_EXISTS;
+ } else if (r.name == &H2O_TOKEN_SCHEME->buf) {
+ if (req->input.scheme != NULL)
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ if (h2o_memis(r.value->base, r.value->len, H2O_STRLIT("https"))) {
+ req->input.scheme = &H2O_URL_SCHEME_HTTPS;
+ } else {
+ /* draft-16 8.1.2.3 suggests quote: ":scheme is not restricted to http and https schemed URIs" */
+ req->input.scheme = &H2O_URL_SCHEME_HTTP;
+ }
+ *pseudo_header_exists_map |= H2O_HPACK_PARSE_HEADERS_SCHEME_EXISTS;
+ } else {
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ } else {
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ } else {
+ pseudo_header_exists_map = NULL;
+ if (h2o_iovec_is_token(r.name)) {
+ h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, r.name);
+ if (token == H2O_TOKEN_CONTENT_LENGTH) {
+ if ((*content_length = h2o_strtosize(r.value->base, r.value->len)) == SIZE_MAX)
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ } else {
+ /* reject headers as defined in draft-16 8.1.2.2 */
+ if (token->http2_should_reject) {
+ if (token == H2O_TOKEN_HOST) {
+ /* just skip (and :authority is used) */
+ goto Next;
+ } else if (token == H2O_TOKEN_TE && h2o_lcstris(r.value->base, r.value->len, H2O_STRLIT("trailers"))) {
+ /* do not reject */
+ } else {
+ return H2O_HTTP2_ERROR_PROTOCOL;
+ }
+ }
+ if (token == H2O_TOKEN_CACHE_DIGEST && digests != NULL) {
+ /* TODO cache the decoded result in HPACK, as well as delay the decoding of the digest until being used */
+ h2o_cache_digests_load_header(digests, r.value->base, r.value->len);
+ }
+ h2o_add_header(&req->pool, &req->headers, token, NULL, r.value->base, r.value->len);
+ }
+ } else {
+ h2o_add_header_by_str(&req->pool, &req->headers, r.name->base, r.name->len, 0, NULL, r.value->base, r.value->len);
+ }
+ }
+ Next:;
+ }
+
+ if (*err_desc) {
+ return H2O_HTTP2_ERROR_INVALID_HEADER_CHAR;
+ }
+ return 0;
+}
+
+static inline int encode_int_is_onebyte(uint32_t value, size_t prefix_bits)
+{
+ return value < (1 << prefix_bits) - 1;
+}
+
+static uint8_t *encode_int(uint8_t *dst, uint32_t value, size_t prefix_bits)
+{
+ if (encode_int_is_onebyte(value, prefix_bits)) {
+ *dst++ |= value;
+ } else {
+ /* see also: MAX_ENCODE_INT_LENGTH */
+ value -= (1 << prefix_bits) - 1;
+ if (value > 0x0fffffff)
+ h2o_fatal("value out of range");
+ *dst++ |= (1 << prefix_bits) - 1;
+ for (; value >= 128; value >>= 7) {
+ *dst++ = 0x80 | value;
+ }
+ *dst++ = value;
+ }
+ return dst;
+}
+
+static size_t encode_huffman(uint8_t *_dst, const uint8_t *src, size_t len)
+{
+ uint8_t *dst = _dst, *dst_end = dst + len;
+ const uint8_t *src_end = src + len;
+ uint64_t bits = 0;
+ int bits_left = 40;
+
+ while (src != src_end) {
+ const nghttp2_huff_sym *sym = huff_sym_table + *src++;
+ bits |= (uint64_t)sym->code << (bits_left - sym->nbits);
+ bits_left -= sym->nbits;
+ while (bits_left <= 32) {
+ *dst++ = bits >> 32;
+ bits <<= 8;
+ bits_left += 8;
+ if (dst == dst_end) {
+ return 0;
+ }
+ }
+ }
+
+ if (bits_left != 40) {
+ bits |= ((uint64_t)1 << bits_left) - 1;
+ *dst++ = bits >> 32;
+ }
+ if (dst == dst_end) {
+ return 0;
+ }
+
+ return dst - _dst;
+}
+
+static size_t encode_as_is(uint8_t *dst, const char *s, size_t len)
+{
+ uint8_t *start = dst;
+ *dst = '\0';
+ dst = encode_int(dst, (uint32_t)len, 7);
+ memcpy(dst, s, len);
+ dst += len;
+ return dst - start;
+}
+
+size_t h2o_hpack_encode_string(uint8_t *dst, const char *s, size_t len)
+{
+ if (H2O_LIKELY(len != 0)) {
+ /* try to encode using huffman */
+ size_t hufflen = encode_huffman(dst + 1, (const uint8_t *)s, len);
+ if (H2O_LIKELY(hufflen != 0)) {
+ size_t head_len;
+ if (H2O_LIKELY(encode_int_is_onebyte((uint32_t)hufflen, 7))) {
+ dst[0] = (uint8_t)(0x80 | hufflen);
+ head_len = 1;
+ } else {
+ uint8_t head[8];
+ head[0] = '\x80';
+ head_len = encode_int(head, (uint32_t)hufflen, 7) - head;
+ memmove(dst + head_len, dst + 1, hufflen);
+ memcpy(dst, head, head_len);
+ }
+ return head_len + hufflen;
+ }
+ }
+ return encode_as_is(dst, s, len);
+}
+
+static uint8_t *encode_header(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_iovec_t *name,
+ const h2o_iovec_t *value)
+{
+ int name_index = 0, dont_compress = 0, name_is_token = h2o_iovec_is_token(name);
+
+ /* try to send as indexed */
+ {
+ size_t header_table_index = header_table->entry_start_index, n;
+ for (n = header_table->num_entries; n != 0; --n) {
+ struct st_h2o_hpack_header_table_entry_t *entry = header_table->entries + header_table_index;
+ if (name_is_token) {
+ if (name != entry->name)
+ goto Next;
+ } else {
+ if (!h2o_memis(name->base, name->len, entry->name->base, entry->name->len))
+ goto Next;
+ if (name_index == 0)
+ name_index = (int)(header_table->num_entries - n + HEADER_TABLE_OFFSET);
+ }
+ /* name matched! */
+ if (!h2o_memis(value->base, value->len, entry->value->base, entry->value->len))
+ goto Next;
+ /* name and value matched! */
+ *dst = 0x80;
+ dst = encode_int(dst, (uint32_t)(header_table->num_entries - n + HEADER_TABLE_OFFSET), 7);
+ return dst;
+ Next:
+ ++header_table_index;
+ if (header_table_index == header_table->entry_capacity)
+ header_table_index = 0;
+ }
+ }
+
+ if (name_is_token) {
+ const h2o_token_t *name_token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, name);
+ name_index = name_token->http2_static_table_name_index;
+ dont_compress = (name_token->dont_compress == 1 && value->len < 20) ? 1 : 0;
+ }
+
+ if (name_index != 0) {
+ /* literal header field with indexing (indexed name). */
+ if (dont_compress == 1) {
+ /* mark the field as 'never indexed' */
+ *dst = 0x10;
+ dst = encode_int(dst, name_index, 4);
+ } else {
+ *dst = 0x40;
+ dst = encode_int(dst, name_index, 6);
+ }
+ } else {
+ /* literal header field with indexing (new name) */
+ *dst++ = 0x40;
+ dst += h2o_hpack_encode_string(dst, name->base, name->len);
+ }
+ if (dont_compress == 1) {
+ /* bypass huffman encoding */
+ dst += encode_as_is(dst, value->base, value->len);
+ } else {
+ /* add to header table (maximum number of entries in output header table is limited to 32 so that the search (see above) would
+ not take too long) */
+ dst += h2o_hpack_encode_string(dst, value->base, value->len);
+ struct st_h2o_hpack_header_table_entry_t *entry =
+ header_table_add(header_table, name->len + value->len + HEADER_TABLE_ENTRY_SIZE_OFFSET, 32);
+ if (entry != NULL) {
+ if (name_is_token) {
+ entry->name = (h2o_iovec_t *)name;
+ } else {
+ entry->name = alloc_buf(NULL, name->len);
+ entry->name->base[name->len] = '\0';
+ memcpy(entry->name->base, name->base, name->len);
+ }
+ entry->value = alloc_buf(NULL, value->len);
+ entry->value->base[value->len] = '\0';
+ memcpy(entry->value->base, value->base, value->len);
+ }
+ }
+
+ return dst;
+}
+
+static uint8_t *encode_method(h2o_hpack_header_table_t *header_table, uint8_t *dst, h2o_iovec_t value)
+{
+ if (h2o_memis(value.base, value.len, H2O_STRLIT("GET"))) {
+ *dst++ = 0x82;
+ return dst;
+ }
+ if (h2o_memis(value.base, value.len, H2O_STRLIT("POST"))) {
+ *dst++ = 0x83;
+ return dst;
+ }
+ return encode_header(header_table, dst, &H2O_TOKEN_METHOD->buf, &value);
+}
+
+static uint8_t *encode_scheme(h2o_hpack_header_table_t *header_table, uint8_t *dst, const h2o_url_scheme_t *scheme)
+{
+ if (scheme == &H2O_URL_SCHEME_HTTPS) {
+ *dst++ = 0x87;
+ return dst;
+ }
+ if (scheme == &H2O_URL_SCHEME_HTTP) {
+ *dst++ = 0x86;
+ return dst;
+ }
+ return encode_header(header_table, dst, &H2O_TOKEN_SCHEME->buf, &scheme->name);
+}
+
+static uint8_t *encode_path(h2o_hpack_header_table_t *header_table, uint8_t *dst, h2o_iovec_t value)
+{
+ if (h2o_memis(value.base, value.len, H2O_STRLIT("/"))) {
+ *dst++ = 0x84;
+ return dst;
+ }
+ if (h2o_memis(value.base, value.len, H2O_STRLIT("/index.html"))) {
+ *dst++ = 0x85;
+ return dst;
+ }
+ return encode_header(header_table, dst, &H2O_TOKEN_PATH->buf, &value);
+}
+
+static uint8_t *encode_literal_header_without_indexing(uint8_t *dst, const h2o_iovec_t *name, const h2o_iovec_t *value)
+{
+ /* literal header field without indexing / never indexed */
+ *dst++ = 0;
+ dst += h2o_hpack_encode_string(dst, name->base, name->len);
+ dst += h2o_hpack_encode_string(dst, value->base, value->len);
+ return dst;
+}
+
+static size_t calc_capacity(size_t name_len, size_t value_len)
+{
+ return name_len + value_len + 1 + H2O_HTTP2_ENCODE_INT_MAX_LENGTH * 2;
+}
+
+static size_t calc_headers_capacity(const h2o_header_t *headers, size_t num_headers)
+{
+ const h2o_header_t *header;
+ size_t capacity = 0;
+ for (header = headers; num_headers != 0; ++header, --num_headers)
+ capacity += calc_capacity(header->name->len, header->value.len);
+ return capacity;
+}
+
+static void fixup_frame_headers(h2o_buffer_t **buf, size_t start_at, uint8_t type, uint32_t stream_id, size_t max_frame_size)
+{
+ /* try to fit all data into single frame, using the preallocated space for the frame header */
+ size_t payload_size = (*buf)->size - start_at - H2O_HTTP2_FRAME_HEADER_SIZE;
+ if (payload_size <= max_frame_size) {
+ h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + start_at), payload_size, type, H2O_HTTP2_FRAME_FLAG_END_HEADERS,
+ stream_id);
+ return;
+ }
+
+ /* need to setup continuation frames */
+ size_t off;
+ h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + start_at), max_frame_size, type, 0, stream_id);
+ off = start_at + H2O_HTTP2_FRAME_HEADER_SIZE + max_frame_size;
+ while (1) {
+ size_t left = (*buf)->size - off;
+ h2o_buffer_reserve(buf, H2O_HTTP2_FRAME_HEADER_SIZE);
+ memmove((*buf)->bytes + off + H2O_HTTP2_FRAME_HEADER_SIZE, (*buf)->bytes + off, left);
+ (*buf)->size += H2O_HTTP2_FRAME_HEADER_SIZE;
+ if (left <= max_frame_size) {
+ h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + off), left, H2O_HTTP2_FRAME_TYPE_CONTINUATION,
+ H2O_HTTP2_FRAME_FLAG_END_HEADERS, stream_id);
+ break;
+ } else {
+ h2o_http2_encode_frame_header((uint8_t *)((*buf)->bytes + off), max_frame_size, H2O_HTTP2_FRAME_TYPE_CONTINUATION, 0,
+ stream_id);
+ off += H2O_HTTP2_FRAME_HEADER_SIZE + max_frame_size;
+ }
+ }
+}
+
+void h2o_hpack_flatten_request(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t stream_id,
+ size_t max_frame_size, h2o_req_t *req, uint32_t parent_stream_id)
+{
+ size_t capacity = calc_headers_capacity(req->headers.entries, req->headers.size);
+ capacity += H2O_HTTP2_FRAME_HEADER_SIZE /* first frame header */
+ + 4; /* promised stream id */
+ capacity += calc_capacity(H2O_TOKEN_METHOD->buf.len, req->input.method.len);
+ capacity += calc_capacity(H2O_TOKEN_SCHEME->buf.len, req->input.scheme->name.len);
+ capacity += calc_capacity(H2O_TOKEN_AUTHORITY->buf.len, req->input.authority.len);
+ capacity += calc_capacity(H2O_TOKEN_PATH->buf.len, req->input.path.len);
+
+ size_t start_at = (*buf)->size;
+ uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE);
+
+ /* encode */
+ dst = h2o_http2_encode32u(dst, stream_id);
+ dst = encode_method(header_table, dst, req->input.method);
+ dst = encode_scheme(header_table, dst, req->input.scheme);
+ dst = encode_header(header_table, dst, &H2O_TOKEN_AUTHORITY->buf, &req->input.authority);
+ dst = encode_path(header_table, dst, req->input.path);
+ size_t i;
+ for (i = 0; i != req->headers.size; ++i) {
+ const h2o_header_t *header = req->headers.entries + i;
+ if (header->name == &H2O_TOKEN_ACCEPT_ENCODING->buf &&
+ h2o_memis(header->value.base, header->value.len, H2O_STRLIT("gzip, deflate"))) {
+ *dst++ = 0x90;
+ } else {
+ dst = encode_header(header_table, dst, header->name, &header->value);
+ }
+ }
+ (*buf)->size = (char *)dst - (*buf)->bytes;
+
+ /* setup the frame headers */
+ fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_PUSH_PROMISE, parent_stream_id, max_frame_size);
+}
+
+void h2o_hpack_flatten_response(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t stream_id,
+ size_t max_frame_size, h2o_res_t *res, h2o_timestamp_t *ts, const h2o_iovec_t *server_name,
+ size_t content_length)
+{
+ size_t capacity = calc_headers_capacity(res->headers.entries, res->headers.size);
+ capacity += H2O_HTTP2_FRAME_HEADER_SIZE; /* for the first header */
+ capacity += STATUS_HEADER_MAX_SIZE; /* for :status: */
+#ifndef H2O_UNITTEST
+ capacity += 2 + H2O_TIMESTR_RFC1123_LEN; /* for Date: */
+ if (server_name->len) {
+ capacity += 5 + server_name->len; /* for Server: */
+ }
+#endif
+ if (content_length != SIZE_MAX)
+ capacity += CONTENT_LENGTH_HEADER_MAX_SIZE; /* for content-length: UINT64_MAX (with huffman compression applied) */
+
+ size_t start_at = (*buf)->size;
+ uint8_t *dst = (void *)(h2o_buffer_reserve(buf, capacity).base + H2O_HTTP2_FRAME_HEADER_SIZE); /* skip frame header */
+
+ /* encode */
+ dst = encode_status(dst, res->status);
+#ifndef H2O_UNITTEST
+ /* TODO keep some kind of reference to the indexed headers of Server and Date, and reuse them */
+ if (server_name->len) {
+ dst = encode_header(header_table, dst, &H2O_TOKEN_SERVER->buf, server_name);
+ }
+ h2o_iovec_t date_value = {ts->str->rfc1123, H2O_TIMESTR_RFC1123_LEN};
+ dst = encode_header(header_table, dst, &H2O_TOKEN_DATE->buf, &date_value);
+#endif
+ size_t i;
+ for (i = 0; i != res->headers.size; ++i)
+ dst = encode_header(header_table, dst, res->headers.entries[i].name, &res->headers.entries[i].value);
+ if (content_length != SIZE_MAX)
+ dst = encode_content_length(dst, content_length);
+ (*buf)->size = (char *)dst - (*buf)->bytes;
+
+ /* setup the frame headers */
+ fixup_frame_headers(buf, start_at, H2O_HTTP2_FRAME_TYPE_HEADERS, stream_id, max_frame_size);
+}
diff --git a/web/server/h2o/libh2o/lib/http2/hpack_huffman_table.h b/web/server/h2o/libh2o/lib/http2/hpack_huffman_table.h
new file mode 100644
index 000000000..8f6afab90
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/hpack_huffman_table.h
@@ -0,0 +1,4954 @@
+// !!! DO NOT EDIT !!! Generated by misc/mkhufftbl.c
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
+ * Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
+ * Copyright (c) 2016 Fastly, Inc.
+ *
+ * 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.
+ */
+
+typedef struct {
+ uint32_t nbits;
+ uint32_t code;
+} nghttp2_huff_sym;
+
+static const nghttp2_huff_sym huff_sym_table[] = {
+ {13, 0x1ff8u}, {23, 0x7fffd8u}, {28, 0xfffffe2u}, {28, 0xfffffe3u}, {28, 0xfffffe4u}, {28, 0xfffffe5u}, {28, 0xfffffe6u},
+ {28, 0xfffffe7u}, {28, 0xfffffe8u}, {24, 0xffffeau}, {30, 0x3ffffffcu}, {28, 0xfffffe9u}, {28, 0xfffffeau}, {30, 0x3ffffffdu},
+ {28, 0xfffffebu}, {28, 0xfffffecu}, {28, 0xfffffedu}, {28, 0xfffffeeu}, {28, 0xfffffefu}, {28, 0xffffff0u}, {28, 0xffffff1u},
+ {28, 0xffffff2u}, {30, 0x3ffffffeu}, {28, 0xffffff3u}, {28, 0xffffff4u}, {28, 0xffffff5u}, {28, 0xffffff6u}, {28, 0xffffff7u},
+ {28, 0xffffff8u}, {28, 0xffffff9u}, {28, 0xffffffau}, {28, 0xffffffbu}, {6, 0x14u}, {10, 0x3f8u}, {10, 0x3f9u},
+ {12, 0xffau}, {13, 0x1ff9u}, {6, 0x15u}, {8, 0xf8u}, {11, 0x7fau}, {10, 0x3fau}, {10, 0x3fbu},
+ {8, 0xf9u}, {11, 0x7fbu}, {8, 0xfau}, {6, 0x16u}, {6, 0x17u}, {6, 0x18u}, {5, 0x0u},
+ {5, 0x1u}, {5, 0x2u}, {6, 0x19u}, {6, 0x1au}, {6, 0x1bu}, {6, 0x1cu}, {6, 0x1du},
+ {6, 0x1eu}, {6, 0x1fu}, {7, 0x5cu}, {8, 0xfbu}, {15, 0x7ffcu}, {6, 0x20u}, {12, 0xffbu},
+ {10, 0x3fcu}, {13, 0x1ffau}, {6, 0x21u}, {7, 0x5du}, {7, 0x5eu}, {7, 0x5fu}, {7, 0x60u},
+ {7, 0x61u}, {7, 0x62u}, {7, 0x63u}, {7, 0x64u}, {7, 0x65u}, {7, 0x66u}, {7, 0x67u},
+ {7, 0x68u}, {7, 0x69u}, {7, 0x6au}, {7, 0x6bu}, {7, 0x6cu}, {7, 0x6du}, {7, 0x6eu},
+ {7, 0x6fu}, {7, 0x70u}, {7, 0x71u}, {7, 0x72u}, {8, 0xfcu}, {7, 0x73u}, {8, 0xfdu},
+ {13, 0x1ffbu}, {19, 0x7fff0u}, {13, 0x1ffcu}, {14, 0x3ffcu}, {6, 0x22u}, {15, 0x7ffdu}, {5, 0x3u},
+ {6, 0x23u}, {5, 0x4u}, {6, 0x24u}, {5, 0x5u}, {6, 0x25u}, {6, 0x26u}, {6, 0x27u},
+ {5, 0x6u}, {7, 0x74u}, {7, 0x75u}, {6, 0x28u}, {6, 0x29u}, {6, 0x2au}, {5, 0x7u},
+ {6, 0x2bu}, {7, 0x76u}, {6, 0x2cu}, {5, 0x8u}, {5, 0x9u}, {6, 0x2du}, {7, 0x77u},
+ {7, 0x78u}, {7, 0x79u}, {7, 0x7au}, {7, 0x7bu}, {15, 0x7ffeu}, {11, 0x7fcu}, {14, 0x3ffdu},
+ {13, 0x1ffdu}, {28, 0xffffffcu}, {20, 0xfffe6u}, {22, 0x3fffd2u}, {20, 0xfffe7u}, {20, 0xfffe8u}, {22, 0x3fffd3u},
+ {22, 0x3fffd4u}, {22, 0x3fffd5u}, {23, 0x7fffd9u}, {22, 0x3fffd6u}, {23, 0x7fffdau}, {23, 0x7fffdbu}, {23, 0x7fffdcu},
+ {23, 0x7fffddu}, {23, 0x7fffdeu}, {24, 0xffffebu}, {23, 0x7fffdfu}, {24, 0xffffecu}, {24, 0xffffedu}, {22, 0x3fffd7u},
+ {23, 0x7fffe0u}, {24, 0xffffeeu}, {23, 0x7fffe1u}, {23, 0x7fffe2u}, {23, 0x7fffe3u}, {23, 0x7fffe4u}, {21, 0x1fffdcu},
+ {22, 0x3fffd8u}, {23, 0x7fffe5u}, {22, 0x3fffd9u}, {23, 0x7fffe6u}, {23, 0x7fffe7u}, {24, 0xffffefu}, {22, 0x3fffdau},
+ {21, 0x1fffddu}, {20, 0xfffe9u}, {22, 0x3fffdbu}, {22, 0x3fffdcu}, {23, 0x7fffe8u}, {23, 0x7fffe9u}, {21, 0x1fffdeu},
+ {23, 0x7fffeau}, {22, 0x3fffddu}, {22, 0x3fffdeu}, {24, 0xfffff0u}, {21, 0x1fffdfu}, {22, 0x3fffdfu}, {23, 0x7fffebu},
+ {23, 0x7fffecu}, {21, 0x1fffe0u}, {21, 0x1fffe1u}, {22, 0x3fffe0u}, {21, 0x1fffe2u}, {23, 0x7fffedu}, {22, 0x3fffe1u},
+ {23, 0x7fffeeu}, {23, 0x7fffefu}, {20, 0xfffeau}, {22, 0x3fffe2u}, {22, 0x3fffe3u}, {22, 0x3fffe4u}, {23, 0x7ffff0u},
+ {22, 0x3fffe5u}, {22, 0x3fffe6u}, {23, 0x7ffff1u}, {26, 0x3ffffe0u}, {26, 0x3ffffe1u}, {20, 0xfffebu}, {19, 0x7fff1u},
+ {22, 0x3fffe7u}, {23, 0x7ffff2u}, {22, 0x3fffe8u}, {25, 0x1ffffecu}, {26, 0x3ffffe2u}, {26, 0x3ffffe3u}, {26, 0x3ffffe4u},
+ {27, 0x7ffffdeu}, {27, 0x7ffffdfu}, {26, 0x3ffffe5u}, {24, 0xfffff1u}, {25, 0x1ffffedu}, {19, 0x7fff2u}, {21, 0x1fffe3u},
+ {26, 0x3ffffe6u}, {27, 0x7ffffe0u}, {27, 0x7ffffe1u}, {26, 0x3ffffe7u}, {27, 0x7ffffe2u}, {24, 0xfffff2u}, {21, 0x1fffe4u},
+ {21, 0x1fffe5u}, {26, 0x3ffffe8u}, {26, 0x3ffffe9u}, {28, 0xffffffdu}, {27, 0x7ffffe3u}, {27, 0x7ffffe4u}, {27, 0x7ffffe5u},
+ {20, 0xfffecu}, {24, 0xfffff3u}, {20, 0xfffedu}, {21, 0x1fffe6u}, {22, 0x3fffe9u}, {21, 0x1fffe7u}, {21, 0x1fffe8u},
+ {23, 0x7ffff3u}, {22, 0x3fffeau}, {22, 0x3fffebu}, {25, 0x1ffffeeu}, {25, 0x1ffffefu}, {24, 0xfffff4u}, {24, 0xfffff5u},
+ {26, 0x3ffffeau}, {23, 0x7ffff4u}, {26, 0x3ffffebu}, {27, 0x7ffffe6u}, {26, 0x3ffffecu}, {26, 0x3ffffedu}, {27, 0x7ffffe7u},
+ {27, 0x7ffffe8u}, {27, 0x7ffffe9u}, {27, 0x7ffffeau}, {27, 0x7ffffebu}, {28, 0xffffffeu}, {27, 0x7ffffecu}, {27, 0x7ffffedu},
+ {27, 0x7ffffeeu}, {27, 0x7ffffefu}, {27, 0x7fffff0u}, {26, 0x3ffffeeu}, {30, 0x3fffffffu}};
+
+typedef enum {
+ NGHTTP2_HUFF_ACCEPTED = 1,
+ NGHTTP2_HUFF_SYM = 2,
+ NGHTTP2_HUFF_FAIL = 4,
+ NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME = 8,
+ NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE = 16,
+ NGHTTP2_HUFF_UPPER_CASE_CHAR = 32,
+#define NGHTTP2_HUFF_INVALID_CHARS (NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME | NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE)
+} nghttp2_huff_decode_flag;
+
+typedef struct {
+ uint8_t state;
+ uint8_t flags;
+ uint8_t sym;
+} nghttp2_huff_decode;
+
+static const nghttp2_huff_decode huff_decode_table[][16] = {
+ /* 0 */
+ {
+ {4, 0x00, 0},
+ {5, 0x00, 0},
+ {7, 0x00, 0},
+ {8, 0x00, 0},
+ {11, 0x00, 0},
+ {12, 0x00, 0},
+ {16, 0x00, 0},
+ {19, 0x00, 0},
+ {25, 0x00, 0},
+ {28, 0x00, 0},
+ {32, 0x00, 0},
+ {35, 0x00, 0},
+ {42, 0x00, 0},
+ {49, 0x00, 0},
+ {57, 0x00, 0},
+ {64, 0x01, 0},
+ },
+ /* 1 */
+ {
+ {0, 0x03, 48},
+ {0, 0x03, 49},
+ {0, 0x03, 50},
+ {0, 0x03, 97},
+ {0, 0x03, 99},
+ {0, 0x03, 101},
+ {0, 0x03, 105},
+ {0, 0x03, 111},
+ {0, 0x03, 115},
+ {0, 0x03, 116},
+ {13, 0x00, 0},
+ {14, 0x00, 0},
+ {17, 0x00, 0},
+ {18, 0x00, 0},
+ {20, 0x00, 0},
+ {21, 0x00, 0},
+ },
+ /* 2 */
+ {
+ {1, 0x02, 48},
+ {22, 0x03, 48},
+ {1, 0x02, 49},
+ {22, 0x03, 49},
+ {1, 0x02, 50},
+ {22, 0x03, 50},
+ {1, 0x02, 97},
+ {22, 0x03, 97},
+ {1, 0x02, 99},
+ {22, 0x03, 99},
+ {1, 0x02, 101},
+ {22, 0x03, 101},
+ {1, 0x02, 105},
+ {22, 0x03, 105},
+ {1, 0x02, 111},
+ {22, 0x03, 111},
+ },
+ /* 3 */
+ {
+ {2, 0x02, 48},
+ {9, 0x02, 48},
+ {23, 0x02, 48},
+ {40, 0x03, 48},
+ {2, 0x02, 49},
+ {9, 0x02, 49},
+ {23, 0x02, 49},
+ {40, 0x03, 49},
+ {2, 0x02, 50},
+ {9, 0x02, 50},
+ {23, 0x02, 50},
+ {40, 0x03, 50},
+ {2, 0x02, 97},
+ {9, 0x02, 97},
+ {23, 0x02, 97},
+ {40, 0x03, 97},
+ },
+ /* 4 */
+ {
+ {3, 0x02, 48},
+ {6, 0x02, 48},
+ {10, 0x02, 48},
+ {15, 0x02, 48},
+ {24, 0x02, 48},
+ {31, 0x02, 48},
+ {41, 0x02, 48},
+ {56, 0x03, 48},
+ {3, 0x02, 49},
+ {6, 0x02, 49},
+ {10, 0x02, 49},
+ {15, 0x02, 49},
+ {24, 0x02, 49},
+ {31, 0x02, 49},
+ {41, 0x02, 49},
+ {56, 0x03, 49},
+ },
+ /* 5 */
+ {
+ {3, 0x02, 50},
+ {6, 0x02, 50},
+ {10, 0x02, 50},
+ {15, 0x02, 50},
+ {24, 0x02, 50},
+ {31, 0x02, 50},
+ {41, 0x02, 50},
+ {56, 0x03, 50},
+ {3, 0x02, 97},
+ {6, 0x02, 97},
+ {10, 0x02, 97},
+ {15, 0x02, 97},
+ {24, 0x02, 97},
+ {31, 0x02, 97},
+ {41, 0x02, 97},
+ {56, 0x03, 97},
+ },
+ /* 6 */
+ {
+ {2, 0x02, 99},
+ {9, 0x02, 99},
+ {23, 0x02, 99},
+ {40, 0x03, 99},
+ {2, 0x02, 101},
+ {9, 0x02, 101},
+ {23, 0x02, 101},
+ {40, 0x03, 101},
+ {2, 0x02, 105},
+ {9, 0x02, 105},
+ {23, 0x02, 105},
+ {40, 0x03, 105},
+ {2, 0x02, 111},
+ {9, 0x02, 111},
+ {23, 0x02, 111},
+ {40, 0x03, 111},
+ },
+ /* 7 */
+ {
+ {3, 0x02, 99},
+ {6, 0x02, 99},
+ {10, 0x02, 99},
+ {15, 0x02, 99},
+ {24, 0x02, 99},
+ {31, 0x02, 99},
+ {41, 0x02, 99},
+ {56, 0x03, 99},
+ {3, 0x02, 101},
+ {6, 0x02, 101},
+ {10, 0x02, 101},
+ {15, 0x02, 101},
+ {24, 0x02, 101},
+ {31, 0x02, 101},
+ {41, 0x02, 101},
+ {56, 0x03, 101},
+ },
+ /* 8 */
+ {
+ {3, 0x02, 105},
+ {6, 0x02, 105},
+ {10, 0x02, 105},
+ {15, 0x02, 105},
+ {24, 0x02, 105},
+ {31, 0x02, 105},
+ {41, 0x02, 105},
+ {56, 0x03, 105},
+ {3, 0x02, 111},
+ {6, 0x02, 111},
+ {10, 0x02, 111},
+ {15, 0x02, 111},
+ {24, 0x02, 111},
+ {31, 0x02, 111},
+ {41, 0x02, 111},
+ {56, 0x03, 111},
+ },
+ /* 9 */
+ {
+ {1, 0x02, 115},
+ {22, 0x03, 115},
+ {1, 0x02, 116},
+ {22, 0x03, 116},
+ {0, 0x0b, 32},
+ {0, 0x03, 37},
+ {0, 0x03, 45},
+ {0, 0x03, 46},
+ {0, 0x0b, 47},
+ {0, 0x03, 51},
+ {0, 0x03, 52},
+ {0, 0x03, 53},
+ {0, 0x03, 54},
+ {0, 0x03, 55},
+ {0, 0x03, 56},
+ {0, 0x03, 57},
+ },
+ /* 10 */
+ {
+ {2, 0x02, 115},
+ {9, 0x02, 115},
+ {23, 0x02, 115},
+ {40, 0x03, 115},
+ {2, 0x02, 116},
+ {9, 0x02, 116},
+ {23, 0x02, 116},
+ {40, 0x03, 116},
+ {1, 0x0a, 32},
+ {22, 0x0b, 32},
+ {1, 0x02, 37},
+ {22, 0x03, 37},
+ {1, 0x02, 45},
+ {22, 0x03, 45},
+ {1, 0x02, 46},
+ {22, 0x03, 46},
+ },
+ /* 11 */
+ {
+ {3, 0x02, 115},
+ {6, 0x02, 115},
+ {10, 0x02, 115},
+ {15, 0x02, 115},
+ {24, 0x02, 115},
+ {31, 0x02, 115},
+ {41, 0x02, 115},
+ {56, 0x03, 115},
+ {3, 0x02, 116},
+ {6, 0x02, 116},
+ {10, 0x02, 116},
+ {15, 0x02, 116},
+ {24, 0x02, 116},
+ {31, 0x02, 116},
+ {41, 0x02, 116},
+ {56, 0x03, 116},
+ },
+ /* 12 */
+ {
+ {2, 0x0a, 32},
+ {9, 0x0a, 32},
+ {23, 0x0a, 32},
+ {40, 0x0b, 32},
+ {2, 0x02, 37},
+ {9, 0x02, 37},
+ {23, 0x02, 37},
+ {40, 0x03, 37},
+ {2, 0x02, 45},
+ {9, 0x02, 45},
+ {23, 0x02, 45},
+ {40, 0x03, 45},
+ {2, 0x02, 46},
+ {9, 0x02, 46},
+ {23, 0x02, 46},
+ {40, 0x03, 46},
+ },
+ /* 13 */
+ {
+ {3, 0x0a, 32},
+ {6, 0x0a, 32},
+ {10, 0x0a, 32},
+ {15, 0x0a, 32},
+ {24, 0x0a, 32},
+ {31, 0x0a, 32},
+ {41, 0x0a, 32},
+ {56, 0x0b, 32},
+ {3, 0x02, 37},
+ {6, 0x02, 37},
+ {10, 0x02, 37},
+ {15, 0x02, 37},
+ {24, 0x02, 37},
+ {31, 0x02, 37},
+ {41, 0x02, 37},
+ {56, 0x03, 37},
+ },
+ /* 14 */
+ {
+ {3, 0x02, 45},
+ {6, 0x02, 45},
+ {10, 0x02, 45},
+ {15, 0x02, 45},
+ {24, 0x02, 45},
+ {31, 0x02, 45},
+ {41, 0x02, 45},
+ {56, 0x03, 45},
+ {3, 0x02, 46},
+ {6, 0x02, 46},
+ {10, 0x02, 46},
+ {15, 0x02, 46},
+ {24, 0x02, 46},
+ {31, 0x02, 46},
+ {41, 0x02, 46},
+ {56, 0x03, 46},
+ },
+ /* 15 */
+ {
+ {1, 0x0a, 47},
+ {22, 0x0b, 47},
+ {1, 0x02, 51},
+ {22, 0x03, 51},
+ {1, 0x02, 52},
+ {22, 0x03, 52},
+ {1, 0x02, 53},
+ {22, 0x03, 53},
+ {1, 0x02, 54},
+ {22, 0x03, 54},
+ {1, 0x02, 55},
+ {22, 0x03, 55},
+ {1, 0x02, 56},
+ {22, 0x03, 56},
+ {1, 0x02, 57},
+ {22, 0x03, 57},
+ },
+ /* 16 */
+ {
+ {2, 0x0a, 47},
+ {9, 0x0a, 47},
+ {23, 0x0a, 47},
+ {40, 0x0b, 47},
+ {2, 0x02, 51},
+ {9, 0x02, 51},
+ {23, 0x02, 51},
+ {40, 0x03, 51},
+ {2, 0x02, 52},
+ {9, 0x02, 52},
+ {23, 0x02, 52},
+ {40, 0x03, 52},
+ {2, 0x02, 53},
+ {9, 0x02, 53},
+ {23, 0x02, 53},
+ {40, 0x03, 53},
+ },
+ /* 17 */
+ {
+ {3, 0x0a, 47},
+ {6, 0x0a, 47},
+ {10, 0x0a, 47},
+ {15, 0x0a, 47},
+ {24, 0x0a, 47},
+ {31, 0x0a, 47},
+ {41, 0x0a, 47},
+ {56, 0x0b, 47},
+ {3, 0x02, 51},
+ {6, 0x02, 51},
+ {10, 0x02, 51},
+ {15, 0x02, 51},
+ {24, 0x02, 51},
+ {31, 0x02, 51},
+ {41, 0x02, 51},
+ {56, 0x03, 51},
+ },
+ /* 18 */
+ {
+ {3, 0x02, 52},
+ {6, 0x02, 52},
+ {10, 0x02, 52},
+ {15, 0x02, 52},
+ {24, 0x02, 52},
+ {31, 0x02, 52},
+ {41, 0x02, 52},
+ {56, 0x03, 52},
+ {3, 0x02, 53},
+ {6, 0x02, 53},
+ {10, 0x02, 53},
+ {15, 0x02, 53},
+ {24, 0x02, 53},
+ {31, 0x02, 53},
+ {41, 0x02, 53},
+ {56, 0x03, 53},
+ },
+ /* 19 */
+ {
+ {2, 0x02, 54},
+ {9, 0x02, 54},
+ {23, 0x02, 54},
+ {40, 0x03, 54},
+ {2, 0x02, 55},
+ {9, 0x02, 55},
+ {23, 0x02, 55},
+ {40, 0x03, 55},
+ {2, 0x02, 56},
+ {9, 0x02, 56},
+ {23, 0x02, 56},
+ {40, 0x03, 56},
+ {2, 0x02, 57},
+ {9, 0x02, 57},
+ {23, 0x02, 57},
+ {40, 0x03, 57},
+ },
+ /* 20 */
+ {
+ {3, 0x02, 54},
+ {6, 0x02, 54},
+ {10, 0x02, 54},
+ {15, 0x02, 54},
+ {24, 0x02, 54},
+ {31, 0x02, 54},
+ {41, 0x02, 54},
+ {56, 0x03, 54},
+ {3, 0x02, 55},
+ {6, 0x02, 55},
+ {10, 0x02, 55},
+ {15, 0x02, 55},
+ {24, 0x02, 55},
+ {31, 0x02, 55},
+ {41, 0x02, 55},
+ {56, 0x03, 55},
+ },
+ /* 21 */
+ {
+ {3, 0x02, 56},
+ {6, 0x02, 56},
+ {10, 0x02, 56},
+ {15, 0x02, 56},
+ {24, 0x02, 56},
+ {31, 0x02, 56},
+ {41, 0x02, 56},
+ {56, 0x03, 56},
+ {3, 0x02, 57},
+ {6, 0x02, 57},
+ {10, 0x02, 57},
+ {15, 0x02, 57},
+ {24, 0x02, 57},
+ {31, 0x02, 57},
+ {41, 0x02, 57},
+ {56, 0x03, 57},
+ },
+ /* 22 */
+ {
+ {26, 0x00, 0},
+ {27, 0x00, 0},
+ {29, 0x00, 0},
+ {30, 0x00, 0},
+ {33, 0x00, 0},
+ {34, 0x00, 0},
+ {36, 0x00, 0},
+ {37, 0x00, 0},
+ {43, 0x00, 0},
+ {46, 0x00, 0},
+ {50, 0x00, 0},
+ {53, 0x00, 0},
+ {58, 0x00, 0},
+ {61, 0x00, 0},
+ {65, 0x00, 0},
+ {68, 0x01, 0},
+ },
+ /* 23 */
+ {
+ {0, 0x0b, 61},
+ {0, 0x2b, 65},
+ {0, 0x03, 95},
+ {0, 0x03, 98},
+ {0, 0x03, 100},
+ {0, 0x03, 102},
+ {0, 0x03, 103},
+ {0, 0x03, 104},
+ {0, 0x03, 108},
+ {0, 0x03, 109},
+ {0, 0x03, 110},
+ {0, 0x03, 112},
+ {0, 0x03, 114},
+ {0, 0x03, 117},
+ {38, 0x00, 0},
+ {39, 0x00, 0},
+ },
+ /* 24 */
+ {
+ {1, 0x0a, 61},
+ {22, 0x0b, 61},
+ {1, 0x2a, 65},
+ {22, 0x2b, 65},
+ {1, 0x02, 95},
+ {22, 0x03, 95},
+ {1, 0x02, 98},
+ {22, 0x03, 98},
+ {1, 0x02, 100},
+ {22, 0x03, 100},
+ {1, 0x02, 102},
+ {22, 0x03, 102},
+ {1, 0x02, 103},
+ {22, 0x03, 103},
+ {1, 0x02, 104},
+ {22, 0x03, 104},
+ },
+ /* 25 */
+ {
+ {2, 0x0a, 61},
+ {9, 0x0a, 61},
+ {23, 0x0a, 61},
+ {40, 0x0b, 61},
+ {2, 0x2a, 65},
+ {9, 0x2a, 65},
+ {23, 0x2a, 65},
+ {40, 0x2b, 65},
+ {2, 0x02, 95},
+ {9, 0x02, 95},
+ {23, 0x02, 95},
+ {40, 0x03, 95},
+ {2, 0x02, 98},
+ {9, 0x02, 98},
+ {23, 0x02, 98},
+ {40, 0x03, 98},
+ },
+ /* 26 */
+ {
+ {3, 0x0a, 61},
+ {6, 0x0a, 61},
+ {10, 0x0a, 61},
+ {15, 0x0a, 61},
+ {24, 0x0a, 61},
+ {31, 0x0a, 61},
+ {41, 0x0a, 61},
+ {56, 0x0b, 61},
+ {3, 0x2a, 65},
+ {6, 0x2a, 65},
+ {10, 0x2a, 65},
+ {15, 0x2a, 65},
+ {24, 0x2a, 65},
+ {31, 0x2a, 65},
+ {41, 0x2a, 65},
+ {56, 0x2b, 65},
+ },
+ /* 27 */
+ {
+ {3, 0x02, 95},
+ {6, 0x02, 95},
+ {10, 0x02, 95},
+ {15, 0x02, 95},
+ {24, 0x02, 95},
+ {31, 0x02, 95},
+ {41, 0x02, 95},
+ {56, 0x03, 95},
+ {3, 0x02, 98},
+ {6, 0x02, 98},
+ {10, 0x02, 98},
+ {15, 0x02, 98},
+ {24, 0x02, 98},
+ {31, 0x02, 98},
+ {41, 0x02, 98},
+ {56, 0x03, 98},
+ },
+ /* 28 */
+ {
+ {2, 0x02, 100},
+ {9, 0x02, 100},
+ {23, 0x02, 100},
+ {40, 0x03, 100},
+ {2, 0x02, 102},
+ {9, 0x02, 102},
+ {23, 0x02, 102},
+ {40, 0x03, 102},
+ {2, 0x02, 103},
+ {9, 0x02, 103},
+ {23, 0x02, 103},
+ {40, 0x03, 103},
+ {2, 0x02, 104},
+ {9, 0x02, 104},
+ {23, 0x02, 104},
+ {40, 0x03, 104},
+ },
+ /* 29 */
+ {
+ {3, 0x02, 100},
+ {6, 0x02, 100},
+ {10, 0x02, 100},
+ {15, 0x02, 100},
+ {24, 0x02, 100},
+ {31, 0x02, 100},
+ {41, 0x02, 100},
+ {56, 0x03, 100},
+ {3, 0x02, 102},
+ {6, 0x02, 102},
+ {10, 0x02, 102},
+ {15, 0x02, 102},
+ {24, 0x02, 102},
+ {31, 0x02, 102},
+ {41, 0x02, 102},
+ {56, 0x03, 102},
+ },
+ /* 30 */
+ {
+ {3, 0x02, 103},
+ {6, 0x02, 103},
+ {10, 0x02, 103},
+ {15, 0x02, 103},
+ {24, 0x02, 103},
+ {31, 0x02, 103},
+ {41, 0x02, 103},
+ {56, 0x03, 103},
+ {3, 0x02, 104},
+ {6, 0x02, 104},
+ {10, 0x02, 104},
+ {15, 0x02, 104},
+ {24, 0x02, 104},
+ {31, 0x02, 104},
+ {41, 0x02, 104},
+ {56, 0x03, 104},
+ },
+ /* 31 */
+ {
+ {1, 0x02, 108},
+ {22, 0x03, 108},
+ {1, 0x02, 109},
+ {22, 0x03, 109},
+ {1, 0x02, 110},
+ {22, 0x03, 110},
+ {1, 0x02, 112},
+ {22, 0x03, 112},
+ {1, 0x02, 114},
+ {22, 0x03, 114},
+ {1, 0x02, 117},
+ {22, 0x03, 117},
+ {0, 0x0b, 58},
+ {0, 0x2b, 66},
+ {0, 0x2b, 67},
+ {0, 0x2b, 68},
+ },
+ /* 32 */
+ {
+ {2, 0x02, 108},
+ {9, 0x02, 108},
+ {23, 0x02, 108},
+ {40, 0x03, 108},
+ {2, 0x02, 109},
+ {9, 0x02, 109},
+ {23, 0x02, 109},
+ {40, 0x03, 109},
+ {2, 0x02, 110},
+ {9, 0x02, 110},
+ {23, 0x02, 110},
+ {40, 0x03, 110},
+ {2, 0x02, 112},
+ {9, 0x02, 112},
+ {23, 0x02, 112},
+ {40, 0x03, 112},
+ },
+ /* 33 */
+ {
+ {3, 0x02, 108},
+ {6, 0x02, 108},
+ {10, 0x02, 108},
+ {15, 0x02, 108},
+ {24, 0x02, 108},
+ {31, 0x02, 108},
+ {41, 0x02, 108},
+ {56, 0x03, 108},
+ {3, 0x02, 109},
+ {6, 0x02, 109},
+ {10, 0x02, 109},
+ {15, 0x02, 109},
+ {24, 0x02, 109},
+ {31, 0x02, 109},
+ {41, 0x02, 109},
+ {56, 0x03, 109},
+ },
+ /* 34 */
+ {
+ {3, 0x02, 110},
+ {6, 0x02, 110},
+ {10, 0x02, 110},
+ {15, 0x02, 110},
+ {24, 0x02, 110},
+ {31, 0x02, 110},
+ {41, 0x02, 110},
+ {56, 0x03, 110},
+ {3, 0x02, 112},
+ {6, 0x02, 112},
+ {10, 0x02, 112},
+ {15, 0x02, 112},
+ {24, 0x02, 112},
+ {31, 0x02, 112},
+ {41, 0x02, 112},
+ {56, 0x03, 112},
+ },
+ /* 35 */
+ {
+ {2, 0x02, 114},
+ {9, 0x02, 114},
+ {23, 0x02, 114},
+ {40, 0x03, 114},
+ {2, 0x02, 117},
+ {9, 0x02, 117},
+ {23, 0x02, 117},
+ {40, 0x03, 117},
+ {1, 0x0a, 58},
+ {22, 0x0b, 58},
+ {1, 0x2a, 66},
+ {22, 0x2b, 66},
+ {1, 0x2a, 67},
+ {22, 0x2b, 67},
+ {1, 0x2a, 68},
+ {22, 0x2b, 68},
+ },
+ /* 36 */
+ {
+ {3, 0x02, 114},
+ {6, 0x02, 114},
+ {10, 0x02, 114},
+ {15, 0x02, 114},
+ {24, 0x02, 114},
+ {31, 0x02, 114},
+ {41, 0x02, 114},
+ {56, 0x03, 114},
+ {3, 0x02, 117},
+ {6, 0x02, 117},
+ {10, 0x02, 117},
+ {15, 0x02, 117},
+ {24, 0x02, 117},
+ {31, 0x02, 117},
+ {41, 0x02, 117},
+ {56, 0x03, 117},
+ },
+ /* 37 */
+ {
+ {2, 0x0a, 58},
+ {9, 0x0a, 58},
+ {23, 0x0a, 58},
+ {40, 0x0b, 58},
+ {2, 0x2a, 66},
+ {9, 0x2a, 66},
+ {23, 0x2a, 66},
+ {40, 0x2b, 66},
+ {2, 0x2a, 67},
+ {9, 0x2a, 67},
+ {23, 0x2a, 67},
+ {40, 0x2b, 67},
+ {2, 0x2a, 68},
+ {9, 0x2a, 68},
+ {23, 0x2a, 68},
+ {40, 0x2b, 68},
+ },
+ /* 38 */
+ {
+ {3, 0x0a, 58},
+ {6, 0x0a, 58},
+ {10, 0x0a, 58},
+ {15, 0x0a, 58},
+ {24, 0x0a, 58},
+ {31, 0x0a, 58},
+ {41, 0x0a, 58},
+ {56, 0x0b, 58},
+ {3, 0x2a, 66},
+ {6, 0x2a, 66},
+ {10, 0x2a, 66},
+ {15, 0x2a, 66},
+ {24, 0x2a, 66},
+ {31, 0x2a, 66},
+ {41, 0x2a, 66},
+ {56, 0x2b, 66},
+ },
+ /* 39 */
+ {
+ {3, 0x2a, 67},
+ {6, 0x2a, 67},
+ {10, 0x2a, 67},
+ {15, 0x2a, 67},
+ {24, 0x2a, 67},
+ {31, 0x2a, 67},
+ {41, 0x2a, 67},
+ {56, 0x2b, 67},
+ {3, 0x2a, 68},
+ {6, 0x2a, 68},
+ {10, 0x2a, 68},
+ {15, 0x2a, 68},
+ {24, 0x2a, 68},
+ {31, 0x2a, 68},
+ {41, 0x2a, 68},
+ {56, 0x2b, 68},
+ },
+ /* 40 */
+ {
+ {44, 0x00, 0},
+ {45, 0x00, 0},
+ {47, 0x00, 0},
+ {48, 0x00, 0},
+ {51, 0x00, 0},
+ {52, 0x00, 0},
+ {54, 0x00, 0},
+ {55, 0x00, 0},
+ {59, 0x00, 0},
+ {60, 0x00, 0},
+ {62, 0x00, 0},
+ {63, 0x00, 0},
+ {66, 0x00, 0},
+ {67, 0x00, 0},
+ {69, 0x00, 0},
+ {72, 0x01, 0},
+ },
+ /* 41 */
+ {
+ {0, 0x2b, 69},
+ {0, 0x2b, 70},
+ {0, 0x2b, 71},
+ {0, 0x2b, 72},
+ {0, 0x2b, 73},
+ {0, 0x2b, 74},
+ {0, 0x2b, 75},
+ {0, 0x2b, 76},
+ {0, 0x2b, 77},
+ {0, 0x2b, 78},
+ {0, 0x2b, 79},
+ {0, 0x2b, 80},
+ {0, 0x2b, 81},
+ {0, 0x2b, 82},
+ {0, 0x2b, 83},
+ {0, 0x2b, 84},
+ },
+ /* 42 */
+ {
+ {1, 0x2a, 69},
+ {22, 0x2b, 69},
+ {1, 0x2a, 70},
+ {22, 0x2b, 70},
+ {1, 0x2a, 71},
+ {22, 0x2b, 71},
+ {1, 0x2a, 72},
+ {22, 0x2b, 72},
+ {1, 0x2a, 73},
+ {22, 0x2b, 73},
+ {1, 0x2a, 74},
+ {22, 0x2b, 74},
+ {1, 0x2a, 75},
+ {22, 0x2b, 75},
+ {1, 0x2a, 76},
+ {22, 0x2b, 76},
+ },
+ /* 43 */
+ {
+ {2, 0x2a, 69},
+ {9, 0x2a, 69},
+ {23, 0x2a, 69},
+ {40, 0x2b, 69},
+ {2, 0x2a, 70},
+ {9, 0x2a, 70},
+ {23, 0x2a, 70},
+ {40, 0x2b, 70},
+ {2, 0x2a, 71},
+ {9, 0x2a, 71},
+ {23, 0x2a, 71},
+ {40, 0x2b, 71},
+ {2, 0x2a, 72},
+ {9, 0x2a, 72},
+ {23, 0x2a, 72},
+ {40, 0x2b, 72},
+ },
+ /* 44 */
+ {
+ {3, 0x2a, 69},
+ {6, 0x2a, 69},
+ {10, 0x2a, 69},
+ {15, 0x2a, 69},
+ {24, 0x2a, 69},
+ {31, 0x2a, 69},
+ {41, 0x2a, 69},
+ {56, 0x2b, 69},
+ {3, 0x2a, 70},
+ {6, 0x2a, 70},
+ {10, 0x2a, 70},
+ {15, 0x2a, 70},
+ {24, 0x2a, 70},
+ {31, 0x2a, 70},
+ {41, 0x2a, 70},
+ {56, 0x2b, 70},
+ },
+ /* 45 */
+ {
+ {3, 0x2a, 71},
+ {6, 0x2a, 71},
+ {10, 0x2a, 71},
+ {15, 0x2a, 71},
+ {24, 0x2a, 71},
+ {31, 0x2a, 71},
+ {41, 0x2a, 71},
+ {56, 0x2b, 71},
+ {3, 0x2a, 72},
+ {6, 0x2a, 72},
+ {10, 0x2a, 72},
+ {15, 0x2a, 72},
+ {24, 0x2a, 72},
+ {31, 0x2a, 72},
+ {41, 0x2a, 72},
+ {56, 0x2b, 72},
+ },
+ /* 46 */
+ {
+ {2, 0x2a, 73},
+ {9, 0x2a, 73},
+ {23, 0x2a, 73},
+ {40, 0x2b, 73},
+ {2, 0x2a, 74},
+ {9, 0x2a, 74},
+ {23, 0x2a, 74},
+ {40, 0x2b, 74},
+ {2, 0x2a, 75},
+ {9, 0x2a, 75},
+ {23, 0x2a, 75},
+ {40, 0x2b, 75},
+ {2, 0x2a, 76},
+ {9, 0x2a, 76},
+ {23, 0x2a, 76},
+ {40, 0x2b, 76},
+ },
+ /* 47 */
+ {
+ {3, 0x2a, 73},
+ {6, 0x2a, 73},
+ {10, 0x2a, 73},
+ {15, 0x2a, 73},
+ {24, 0x2a, 73},
+ {31, 0x2a, 73},
+ {41, 0x2a, 73},
+ {56, 0x2b, 73},
+ {3, 0x2a, 74},
+ {6, 0x2a, 74},
+ {10, 0x2a, 74},
+ {15, 0x2a, 74},
+ {24, 0x2a, 74},
+ {31, 0x2a, 74},
+ {41, 0x2a, 74},
+ {56, 0x2b, 74},
+ },
+ /* 48 */
+ {
+ {3, 0x2a, 75},
+ {6, 0x2a, 75},
+ {10, 0x2a, 75},
+ {15, 0x2a, 75},
+ {24, 0x2a, 75},
+ {31, 0x2a, 75},
+ {41, 0x2a, 75},
+ {56, 0x2b, 75},
+ {3, 0x2a, 76},
+ {6, 0x2a, 76},
+ {10, 0x2a, 76},
+ {15, 0x2a, 76},
+ {24, 0x2a, 76},
+ {31, 0x2a, 76},
+ {41, 0x2a, 76},
+ {56, 0x2b, 76},
+ },
+ /* 49 */
+ {
+ {1, 0x2a, 77},
+ {22, 0x2b, 77},
+ {1, 0x2a, 78},
+ {22, 0x2b, 78},
+ {1, 0x2a, 79},
+ {22, 0x2b, 79},
+ {1, 0x2a, 80},
+ {22, 0x2b, 80},
+ {1, 0x2a, 81},
+ {22, 0x2b, 81},
+ {1, 0x2a, 82},
+ {22, 0x2b, 82},
+ {1, 0x2a, 83},
+ {22, 0x2b, 83},
+ {1, 0x2a, 84},
+ {22, 0x2b, 84},
+ },
+ /* 50 */
+ {
+ {2, 0x2a, 77},
+ {9, 0x2a, 77},
+ {23, 0x2a, 77},
+ {40, 0x2b, 77},
+ {2, 0x2a, 78},
+ {9, 0x2a, 78},
+ {23, 0x2a, 78},
+ {40, 0x2b, 78},
+ {2, 0x2a, 79},
+ {9, 0x2a, 79},
+ {23, 0x2a, 79},
+ {40, 0x2b, 79},
+ {2, 0x2a, 80},
+ {9, 0x2a, 80},
+ {23, 0x2a, 80},
+ {40, 0x2b, 80},
+ },
+ /* 51 */
+ {
+ {3, 0x2a, 77},
+ {6, 0x2a, 77},
+ {10, 0x2a, 77},
+ {15, 0x2a, 77},
+ {24, 0x2a, 77},
+ {31, 0x2a, 77},
+ {41, 0x2a, 77},
+ {56, 0x2b, 77},
+ {3, 0x2a, 78},
+ {6, 0x2a, 78},
+ {10, 0x2a, 78},
+ {15, 0x2a, 78},
+ {24, 0x2a, 78},
+ {31, 0x2a, 78},
+ {41, 0x2a, 78},
+ {56, 0x2b, 78},
+ },
+ /* 52 */
+ {
+ {3, 0x2a, 79},
+ {6, 0x2a, 79},
+ {10, 0x2a, 79},
+ {15, 0x2a, 79},
+ {24, 0x2a, 79},
+ {31, 0x2a, 79},
+ {41, 0x2a, 79},
+ {56, 0x2b, 79},
+ {3, 0x2a, 80},
+ {6, 0x2a, 80},
+ {10, 0x2a, 80},
+ {15, 0x2a, 80},
+ {24, 0x2a, 80},
+ {31, 0x2a, 80},
+ {41, 0x2a, 80},
+ {56, 0x2b, 80},
+ },
+ /* 53 */
+ {
+ {2, 0x2a, 81},
+ {9, 0x2a, 81},
+ {23, 0x2a, 81},
+ {40, 0x2b, 81},
+ {2, 0x2a, 82},
+ {9, 0x2a, 82},
+ {23, 0x2a, 82},
+ {40, 0x2b, 82},
+ {2, 0x2a, 83},
+ {9, 0x2a, 83},
+ {23, 0x2a, 83},
+ {40, 0x2b, 83},
+ {2, 0x2a, 84},
+ {9, 0x2a, 84},
+ {23, 0x2a, 84},
+ {40, 0x2b, 84},
+ },
+ /* 54 */
+ {
+ {3, 0x2a, 81},
+ {6, 0x2a, 81},
+ {10, 0x2a, 81},
+ {15, 0x2a, 81},
+ {24, 0x2a, 81},
+ {31, 0x2a, 81},
+ {41, 0x2a, 81},
+ {56, 0x2b, 81},
+ {3, 0x2a, 82},
+ {6, 0x2a, 82},
+ {10, 0x2a, 82},
+ {15, 0x2a, 82},
+ {24, 0x2a, 82},
+ {31, 0x2a, 82},
+ {41, 0x2a, 82},
+ {56, 0x2b, 82},
+ },
+ /* 55 */
+ {
+ {3, 0x2a, 83},
+ {6, 0x2a, 83},
+ {10, 0x2a, 83},
+ {15, 0x2a, 83},
+ {24, 0x2a, 83},
+ {31, 0x2a, 83},
+ {41, 0x2a, 83},
+ {56, 0x2b, 83},
+ {3, 0x2a, 84},
+ {6, 0x2a, 84},
+ {10, 0x2a, 84},
+ {15, 0x2a, 84},
+ {24, 0x2a, 84},
+ {31, 0x2a, 84},
+ {41, 0x2a, 84},
+ {56, 0x2b, 84},
+ },
+ /* 56 */
+ {
+ {0, 0x2b, 85},
+ {0, 0x2b, 86},
+ {0, 0x2b, 87},
+ {0, 0x2b, 89},
+ {0, 0x03, 106},
+ {0, 0x03, 107},
+ {0, 0x03, 113},
+ {0, 0x03, 118},
+ {0, 0x03, 119},
+ {0, 0x03, 120},
+ {0, 0x03, 121},
+ {0, 0x03, 122},
+ {70, 0x00, 0},
+ {71, 0x00, 0},
+ {73, 0x00, 0},
+ {74, 0x01, 0},
+ },
+ /* 57 */
+ {
+ {1, 0x2a, 85},
+ {22, 0x2b, 85},
+ {1, 0x2a, 86},
+ {22, 0x2b, 86},
+ {1, 0x2a, 87},
+ {22, 0x2b, 87},
+ {1, 0x2a, 89},
+ {22, 0x2b, 89},
+ {1, 0x02, 106},
+ {22, 0x03, 106},
+ {1, 0x02, 107},
+ {22, 0x03, 107},
+ {1, 0x02, 113},
+ {22, 0x03, 113},
+ {1, 0x02, 118},
+ {22, 0x03, 118},
+ },
+ /* 58 */
+ {
+ {2, 0x2a, 85},
+ {9, 0x2a, 85},
+ {23, 0x2a, 85},
+ {40, 0x2b, 85},
+ {2, 0x2a, 86},
+ {9, 0x2a, 86},
+ {23, 0x2a, 86},
+ {40, 0x2b, 86},
+ {2, 0x2a, 87},
+ {9, 0x2a, 87},
+ {23, 0x2a, 87},
+ {40, 0x2b, 87},
+ {2, 0x2a, 89},
+ {9, 0x2a, 89},
+ {23, 0x2a, 89},
+ {40, 0x2b, 89},
+ },
+ /* 59 */
+ {
+ {3, 0x2a, 85},
+ {6, 0x2a, 85},
+ {10, 0x2a, 85},
+ {15, 0x2a, 85},
+ {24, 0x2a, 85},
+ {31, 0x2a, 85},
+ {41, 0x2a, 85},
+ {56, 0x2b, 85},
+ {3, 0x2a, 86},
+ {6, 0x2a, 86},
+ {10, 0x2a, 86},
+ {15, 0x2a, 86},
+ {24, 0x2a, 86},
+ {31, 0x2a, 86},
+ {41, 0x2a, 86},
+ {56, 0x2b, 86},
+ },
+ /* 60 */
+ {
+ {3, 0x2a, 87},
+ {6, 0x2a, 87},
+ {10, 0x2a, 87},
+ {15, 0x2a, 87},
+ {24, 0x2a, 87},
+ {31, 0x2a, 87},
+ {41, 0x2a, 87},
+ {56, 0x2b, 87},
+ {3, 0x2a, 89},
+ {6, 0x2a, 89},
+ {10, 0x2a, 89},
+ {15, 0x2a, 89},
+ {24, 0x2a, 89},
+ {31, 0x2a, 89},
+ {41, 0x2a, 89},
+ {56, 0x2b, 89},
+ },
+ /* 61 */
+ {
+ {2, 0x02, 106},
+ {9, 0x02, 106},
+ {23, 0x02, 106},
+ {40, 0x03, 106},
+ {2, 0x02, 107},
+ {9, 0x02, 107},
+ {23, 0x02, 107},
+ {40, 0x03, 107},
+ {2, 0x02, 113},
+ {9, 0x02, 113},
+ {23, 0x02, 113},
+ {40, 0x03, 113},
+ {2, 0x02, 118},
+ {9, 0x02, 118},
+ {23, 0x02, 118},
+ {40, 0x03, 118},
+ },
+ /* 62 */
+ {
+ {3, 0x02, 106},
+ {6, 0x02, 106},
+ {10, 0x02, 106},
+ {15, 0x02, 106},
+ {24, 0x02, 106},
+ {31, 0x02, 106},
+ {41, 0x02, 106},
+ {56, 0x03, 106},
+ {3, 0x02, 107},
+ {6, 0x02, 107},
+ {10, 0x02, 107},
+ {15, 0x02, 107},
+ {24, 0x02, 107},
+ {31, 0x02, 107},
+ {41, 0x02, 107},
+ {56, 0x03, 107},
+ },
+ /* 63 */
+ {
+ {3, 0x02, 113},
+ {6, 0x02, 113},
+ {10, 0x02, 113},
+ {15, 0x02, 113},
+ {24, 0x02, 113},
+ {31, 0x02, 113},
+ {41, 0x02, 113},
+ {56, 0x03, 113},
+ {3, 0x02, 118},
+ {6, 0x02, 118},
+ {10, 0x02, 118},
+ {15, 0x02, 118},
+ {24, 0x02, 118},
+ {31, 0x02, 118},
+ {41, 0x02, 118},
+ {56, 0x03, 118},
+ },
+ /* 64 */
+ {
+ {1, 0x02, 119},
+ {22, 0x03, 119},
+ {1, 0x02, 120},
+ {22, 0x03, 120},
+ {1, 0x02, 121},
+ {22, 0x03, 121},
+ {1, 0x02, 122},
+ {22, 0x03, 122},
+ {0, 0x03, 38},
+ {0, 0x03, 42},
+ {0, 0x0b, 44},
+ {0, 0x0b, 59},
+ {0, 0x2b, 88},
+ {0, 0x2b, 90},
+ {75, 0x00, 0},
+ {78, 0x00, 0},
+ },
+ /* 65 */
+ {
+ {2, 0x02, 119},
+ {9, 0x02, 119},
+ {23, 0x02, 119},
+ {40, 0x03, 119},
+ {2, 0x02, 120},
+ {9, 0x02, 120},
+ {23, 0x02, 120},
+ {40, 0x03, 120},
+ {2, 0x02, 121},
+ {9, 0x02, 121},
+ {23, 0x02, 121},
+ {40, 0x03, 121},
+ {2, 0x02, 122},
+ {9, 0x02, 122},
+ {23, 0x02, 122},
+ {40, 0x03, 122},
+ },
+ /* 66 */
+ {
+ {3, 0x02, 119},
+ {6, 0x02, 119},
+ {10, 0x02, 119},
+ {15, 0x02, 119},
+ {24, 0x02, 119},
+ {31, 0x02, 119},
+ {41, 0x02, 119},
+ {56, 0x03, 119},
+ {3, 0x02, 120},
+ {6, 0x02, 120},
+ {10, 0x02, 120},
+ {15, 0x02, 120},
+ {24, 0x02, 120},
+ {31, 0x02, 120},
+ {41, 0x02, 120},
+ {56, 0x03, 120},
+ },
+ /* 67 */
+ {
+ {3, 0x02, 121},
+ {6, 0x02, 121},
+ {10, 0x02, 121},
+ {15, 0x02, 121},
+ {24, 0x02, 121},
+ {31, 0x02, 121},
+ {41, 0x02, 121},
+ {56, 0x03, 121},
+ {3, 0x02, 122},
+ {6, 0x02, 122},
+ {10, 0x02, 122},
+ {15, 0x02, 122},
+ {24, 0x02, 122},
+ {31, 0x02, 122},
+ {41, 0x02, 122},
+ {56, 0x03, 122},
+ },
+ /* 68 */
+ {
+ {1, 0x02, 38},
+ {22, 0x03, 38},
+ {1, 0x02, 42},
+ {22, 0x03, 42},
+ {1, 0x0a, 44},
+ {22, 0x0b, 44},
+ {1, 0x0a, 59},
+ {22, 0x0b, 59},
+ {1, 0x2a, 88},
+ {22, 0x2b, 88},
+ {1, 0x2a, 90},
+ {22, 0x2b, 90},
+ {76, 0x00, 0},
+ {77, 0x00, 0},
+ {79, 0x00, 0},
+ {81, 0x00, 0},
+ },
+ /* 69 */
+ {
+ {2, 0x02, 38},
+ {9, 0x02, 38},
+ {23, 0x02, 38},
+ {40, 0x03, 38},
+ {2, 0x02, 42},
+ {9, 0x02, 42},
+ {23, 0x02, 42},
+ {40, 0x03, 42},
+ {2, 0x0a, 44},
+ {9, 0x0a, 44},
+ {23, 0x0a, 44},
+ {40, 0x0b, 44},
+ {2, 0x0a, 59},
+ {9, 0x0a, 59},
+ {23, 0x0a, 59},
+ {40, 0x0b, 59},
+ },
+ /* 70 */
+ {
+ {3, 0x02, 38},
+ {6, 0x02, 38},
+ {10, 0x02, 38},
+ {15, 0x02, 38},
+ {24, 0x02, 38},
+ {31, 0x02, 38},
+ {41, 0x02, 38},
+ {56, 0x03, 38},
+ {3, 0x02, 42},
+ {6, 0x02, 42},
+ {10, 0x02, 42},
+ {15, 0x02, 42},
+ {24, 0x02, 42},
+ {31, 0x02, 42},
+ {41, 0x02, 42},
+ {56, 0x03, 42},
+ },
+ /* 71 */
+ {
+ {3, 0x0a, 44},
+ {6, 0x0a, 44},
+ {10, 0x0a, 44},
+ {15, 0x0a, 44},
+ {24, 0x0a, 44},
+ {31, 0x0a, 44},
+ {41, 0x0a, 44},
+ {56, 0x0b, 44},
+ {3, 0x0a, 59},
+ {6, 0x0a, 59},
+ {10, 0x0a, 59},
+ {15, 0x0a, 59},
+ {24, 0x0a, 59},
+ {31, 0x0a, 59},
+ {41, 0x0a, 59},
+ {56, 0x0b, 59},
+ },
+ /* 72 */
+ {
+ {2, 0x2a, 88},
+ {9, 0x2a, 88},
+ {23, 0x2a, 88},
+ {40, 0x2b, 88},
+ {2, 0x2a, 90},
+ {9, 0x2a, 90},
+ {23, 0x2a, 90},
+ {40, 0x2b, 90},
+ {0, 0x03, 33},
+ {0, 0x0b, 34},
+ {0, 0x0b, 40},
+ {0, 0x0b, 41},
+ {0, 0x0b, 63},
+ {80, 0x00, 0},
+ {82, 0x00, 0},
+ {84, 0x00, 0},
+ },
+ /* 73 */
+ {
+ {3, 0x2a, 88},
+ {6, 0x2a, 88},
+ {10, 0x2a, 88},
+ {15, 0x2a, 88},
+ {24, 0x2a, 88},
+ {31, 0x2a, 88},
+ {41, 0x2a, 88},
+ {56, 0x2b, 88},
+ {3, 0x2a, 90},
+ {6, 0x2a, 90},
+ {10, 0x2a, 90},
+ {15, 0x2a, 90},
+ {24, 0x2a, 90},
+ {31, 0x2a, 90},
+ {41, 0x2a, 90},
+ {56, 0x2b, 90},
+ },
+ /* 74 */
+ {
+ {1, 0x02, 33},
+ {22, 0x03, 33},
+ {1, 0x0a, 34},
+ {22, 0x0b, 34},
+ {1, 0x0a, 40},
+ {22, 0x0b, 40},
+ {1, 0x0a, 41},
+ {22, 0x0b, 41},
+ {1, 0x0a, 63},
+ {22, 0x0b, 63},
+ {0, 0x03, 39},
+ {0, 0x03, 43},
+ {0, 0x03, 124},
+ {83, 0x00, 0},
+ {85, 0x00, 0},
+ {88, 0x00, 0},
+ },
+ /* 75 */
+ {
+ {2, 0x02, 33},
+ {9, 0x02, 33},
+ {23, 0x02, 33},
+ {40, 0x03, 33},
+ {2, 0x0a, 34},
+ {9, 0x0a, 34},
+ {23, 0x0a, 34},
+ {40, 0x0b, 34},
+ {2, 0x0a, 40},
+ {9, 0x0a, 40},
+ {23, 0x0a, 40},
+ {40, 0x0b, 40},
+ {2, 0x0a, 41},
+ {9, 0x0a, 41},
+ {23, 0x0a, 41},
+ {40, 0x0b, 41},
+ },
+ /* 76 */
+ {
+ {3, 0x02, 33},
+ {6, 0x02, 33},
+ {10, 0x02, 33},
+ {15, 0x02, 33},
+ {24, 0x02, 33},
+ {31, 0x02, 33},
+ {41, 0x02, 33},
+ {56, 0x03, 33},
+ {3, 0x0a, 34},
+ {6, 0x0a, 34},
+ {10, 0x0a, 34},
+ {15, 0x0a, 34},
+ {24, 0x0a, 34},
+ {31, 0x0a, 34},
+ {41, 0x0a, 34},
+ {56, 0x0b, 34},
+ },
+ /* 77 */
+ {
+ {3, 0x0a, 40},
+ {6, 0x0a, 40},
+ {10, 0x0a, 40},
+ {15, 0x0a, 40},
+ {24, 0x0a, 40},
+ {31, 0x0a, 40},
+ {41, 0x0a, 40},
+ {56, 0x0b, 40},
+ {3, 0x0a, 41},
+ {6, 0x0a, 41},
+ {10, 0x0a, 41},
+ {15, 0x0a, 41},
+ {24, 0x0a, 41},
+ {31, 0x0a, 41},
+ {41, 0x0a, 41},
+ {56, 0x0b, 41},
+ },
+ /* 78 */
+ {
+ {2, 0x0a, 63},
+ {9, 0x0a, 63},
+ {23, 0x0a, 63},
+ {40, 0x0b, 63},
+ {1, 0x02, 39},
+ {22, 0x03, 39},
+ {1, 0x02, 43},
+ {22, 0x03, 43},
+ {1, 0x02, 124},
+ {22, 0x03, 124},
+ {0, 0x03, 35},
+ {0, 0x0b, 62},
+ {86, 0x00, 0},
+ {87, 0x00, 0},
+ {89, 0x00, 0},
+ {90, 0x00, 0},
+ },
+ /* 79 */
+ {
+ {3, 0x0a, 63},
+ {6, 0x0a, 63},
+ {10, 0x0a, 63},
+ {15, 0x0a, 63},
+ {24, 0x0a, 63},
+ {31, 0x0a, 63},
+ {41, 0x0a, 63},
+ {56, 0x0b, 63},
+ {2, 0x02, 39},
+ {9, 0x02, 39},
+ {23, 0x02, 39},
+ {40, 0x03, 39},
+ {2, 0x02, 43},
+ {9, 0x02, 43},
+ {23, 0x02, 43},
+ {40, 0x03, 43},
+ },
+ /* 80 */
+ {
+ {3, 0x02, 39},
+ {6, 0x02, 39},
+ {10, 0x02, 39},
+ {15, 0x02, 39},
+ {24, 0x02, 39},
+ {31, 0x02, 39},
+ {41, 0x02, 39},
+ {56, 0x03, 39},
+ {3, 0x02, 43},
+ {6, 0x02, 43},
+ {10, 0x02, 43},
+ {15, 0x02, 43},
+ {24, 0x02, 43},
+ {31, 0x02, 43},
+ {41, 0x02, 43},
+ {56, 0x03, 43},
+ },
+ /* 81 */
+ {
+ {2, 0x02, 124},
+ {9, 0x02, 124},
+ {23, 0x02, 124},
+ {40, 0x03, 124},
+ {1, 0x02, 35},
+ {22, 0x03, 35},
+ {1, 0x0a, 62},
+ {22, 0x0b, 62},
+ {0, 0x1b, 0},
+ {0, 0x03, 36},
+ {0, 0x0b, 64},
+ {0, 0x0b, 91},
+ {0, 0x0b, 93},
+ {0, 0x03, 126},
+ {91, 0x00, 0},
+ {92, 0x00, 0},
+ },
+ /* 82 */
+ {
+ {3, 0x02, 124},
+ {6, 0x02, 124},
+ {10, 0x02, 124},
+ {15, 0x02, 124},
+ {24, 0x02, 124},
+ {31, 0x02, 124},
+ {41, 0x02, 124},
+ {56, 0x03, 124},
+ {2, 0x02, 35},
+ {9, 0x02, 35},
+ {23, 0x02, 35},
+ {40, 0x03, 35},
+ {2, 0x0a, 62},
+ {9, 0x0a, 62},
+ {23, 0x0a, 62},
+ {40, 0x0b, 62},
+ },
+ /* 83 */
+ {
+ {3, 0x02, 35},
+ {6, 0x02, 35},
+ {10, 0x02, 35},
+ {15, 0x02, 35},
+ {24, 0x02, 35},
+ {31, 0x02, 35},
+ {41, 0x02, 35},
+ {56, 0x03, 35},
+ {3, 0x0a, 62},
+ {6, 0x0a, 62},
+ {10, 0x0a, 62},
+ {15, 0x0a, 62},
+ {24, 0x0a, 62},
+ {31, 0x0a, 62},
+ {41, 0x0a, 62},
+ {56, 0x0b, 62},
+ },
+ /* 84 */
+ {
+ {1, 0x1a, 0},
+ {22, 0x1b, 0},
+ {1, 0x02, 36},
+ {22, 0x03, 36},
+ {1, 0x0a, 64},
+ {22, 0x0b, 64},
+ {1, 0x0a, 91},
+ {22, 0x0b, 91},
+ {1, 0x0a, 93},
+ {22, 0x0b, 93},
+ {1, 0x02, 126},
+ {22, 0x03, 126},
+ {0, 0x03, 94},
+ {0, 0x0b, 125},
+ {93, 0x00, 0},
+ {94, 0x00, 0},
+ },
+ /* 85 */
+ {
+ {2, 0x1a, 0},
+ {9, 0x1a, 0},
+ {23, 0x1a, 0},
+ {40, 0x1b, 0},
+ {2, 0x02, 36},
+ {9, 0x02, 36},
+ {23, 0x02, 36},
+ {40, 0x03, 36},
+ {2, 0x0a, 64},
+ {9, 0x0a, 64},
+ {23, 0x0a, 64},
+ {40, 0x0b, 64},
+ {2, 0x0a, 91},
+ {9, 0x0a, 91},
+ {23, 0x0a, 91},
+ {40, 0x0b, 91},
+ },
+ /* 86 */
+ {
+ {3, 0x1a, 0},
+ {6, 0x1a, 0},
+ {10, 0x1a, 0},
+ {15, 0x1a, 0},
+ {24, 0x1a, 0},
+ {31, 0x1a, 0},
+ {41, 0x1a, 0},
+ {56, 0x1b, 0},
+ {3, 0x02, 36},
+ {6, 0x02, 36},
+ {10, 0x02, 36},
+ {15, 0x02, 36},
+ {24, 0x02, 36},
+ {31, 0x02, 36},
+ {41, 0x02, 36},
+ {56, 0x03, 36},
+ },
+ /* 87 */
+ {
+ {3, 0x0a, 64},
+ {6, 0x0a, 64},
+ {10, 0x0a, 64},
+ {15, 0x0a, 64},
+ {24, 0x0a, 64},
+ {31, 0x0a, 64},
+ {41, 0x0a, 64},
+ {56, 0x0b, 64},
+ {3, 0x0a, 91},
+ {6, 0x0a, 91},
+ {10, 0x0a, 91},
+ {15, 0x0a, 91},
+ {24, 0x0a, 91},
+ {31, 0x0a, 91},
+ {41, 0x0a, 91},
+ {56, 0x0b, 91},
+ },
+ /* 88 */
+ {
+ {2, 0x0a, 93},
+ {9, 0x0a, 93},
+ {23, 0x0a, 93},
+ {40, 0x0b, 93},
+ {2, 0x02, 126},
+ {9, 0x02, 126},
+ {23, 0x02, 126},
+ {40, 0x03, 126},
+ {1, 0x02, 94},
+ {22, 0x03, 94},
+ {1, 0x0a, 125},
+ {22, 0x0b, 125},
+ {0, 0x0b, 60},
+ {0, 0x03, 96},
+ {0, 0x0b, 123},
+ {95, 0x00, 0},
+ },
+ /* 89 */
+ {
+ {3, 0x0a, 93},
+ {6, 0x0a, 93},
+ {10, 0x0a, 93},
+ {15, 0x0a, 93},
+ {24, 0x0a, 93},
+ {31, 0x0a, 93},
+ {41, 0x0a, 93},
+ {56, 0x0b, 93},
+ {3, 0x02, 126},
+ {6, 0x02, 126},
+ {10, 0x02, 126},
+ {15, 0x02, 126},
+ {24, 0x02, 126},
+ {31, 0x02, 126},
+ {41, 0x02, 126},
+ {56, 0x03, 126},
+ },
+ /* 90 */
+ {
+ {2, 0x02, 94},
+ {9, 0x02, 94},
+ {23, 0x02, 94},
+ {40, 0x03, 94},
+ {2, 0x0a, 125},
+ {9, 0x0a, 125},
+ {23, 0x0a, 125},
+ {40, 0x0b, 125},
+ {1, 0x0a, 60},
+ {22, 0x0b, 60},
+ {1, 0x02, 96},
+ {22, 0x03, 96},
+ {1, 0x0a, 123},
+ {22, 0x0b, 123},
+ {96, 0x00, 0},
+ {110, 0x00, 0},
+ },
+ /* 91 */
+ {
+ {3, 0x02, 94},
+ {6, 0x02, 94},
+ {10, 0x02, 94},
+ {15, 0x02, 94},
+ {24, 0x02, 94},
+ {31, 0x02, 94},
+ {41, 0x02, 94},
+ {56, 0x03, 94},
+ {3, 0x0a, 125},
+ {6, 0x0a, 125},
+ {10, 0x0a, 125},
+ {15, 0x0a, 125},
+ {24, 0x0a, 125},
+ {31, 0x0a, 125},
+ {41, 0x0a, 125},
+ {56, 0x0b, 125},
+ },
+ /* 92 */
+ {
+ {2, 0x0a, 60},
+ {9, 0x0a, 60},
+ {23, 0x0a, 60},
+ {40, 0x0b, 60},
+ {2, 0x02, 96},
+ {9, 0x02, 96},
+ {23, 0x02, 96},
+ {40, 0x03, 96},
+ {2, 0x0a, 123},
+ {9, 0x0a, 123},
+ {23, 0x0a, 123},
+ {40, 0x0b, 123},
+ {97, 0x00, 0},
+ {101, 0x00, 0},
+ {111, 0x00, 0},
+ {133, 0x00, 0},
+ },
+ /* 93 */
+ {
+ {3, 0x0a, 60},
+ {6, 0x0a, 60},
+ {10, 0x0a, 60},
+ {15, 0x0a, 60},
+ {24, 0x0a, 60},
+ {31, 0x0a, 60},
+ {41, 0x0a, 60},
+ {56, 0x0b, 60},
+ {3, 0x02, 96},
+ {6, 0x02, 96},
+ {10, 0x02, 96},
+ {15, 0x02, 96},
+ {24, 0x02, 96},
+ {31, 0x02, 96},
+ {41, 0x02, 96},
+ {56, 0x03, 96},
+ },
+ /* 94 */
+ {
+ {3, 0x0a, 123},
+ {6, 0x0a, 123},
+ {10, 0x0a, 123},
+ {15, 0x0a, 123},
+ {24, 0x0a, 123},
+ {31, 0x0a, 123},
+ {41, 0x0a, 123},
+ {56, 0x0b, 123},
+ {98, 0x00, 0},
+ {99, 0x00, 0},
+ {102, 0x00, 0},
+ {105, 0x00, 0},
+ {112, 0x00, 0},
+ {119, 0x00, 0},
+ {134, 0x00, 0},
+ {153, 0x00, 0},
+ },
+ /* 95 */
+ {
+ {0, 0x0b, 92},
+ {0, 0x0b, 195},
+ {0, 0x0b, 208},
+ {100, 0x00, 0},
+ {103, 0x00, 0},
+ {104, 0x00, 0},
+ {106, 0x00, 0},
+ {107, 0x00, 0},
+ {113, 0x00, 0},
+ {116, 0x00, 0},
+ {120, 0x00, 0},
+ {126, 0x00, 0},
+ {135, 0x00, 0},
+ {142, 0x00, 0},
+ {154, 0x00, 0},
+ {169, 0x00, 0},
+ },
+ /* 96 */
+ {
+ {1, 0x0a, 92},
+ {22, 0x0b, 92},
+ {1, 0x0a, 195},
+ {22, 0x0b, 195},
+ {1, 0x0a, 208},
+ {22, 0x0b, 208},
+ {0, 0x0b, 128},
+ {0, 0x0b, 130},
+ {0, 0x0b, 131},
+ {0, 0x0b, 162},
+ {0, 0x0b, 184},
+ {0, 0x0b, 194},
+ {0, 0x0b, 224},
+ {0, 0x0b, 226},
+ {108, 0x00, 0},
+ {109, 0x00, 0},
+ },
+ /* 97 */
+ {
+ {2, 0x0a, 92},
+ {9, 0x0a, 92},
+ {23, 0x0a, 92},
+ {40, 0x0b, 92},
+ {2, 0x0a, 195},
+ {9, 0x0a, 195},
+ {23, 0x0a, 195},
+ {40, 0x0b, 195},
+ {2, 0x0a, 208},
+ {9, 0x0a, 208},
+ {23, 0x0a, 208},
+ {40, 0x0b, 208},
+ {1, 0x0a, 128},
+ {22, 0x0b, 128},
+ {1, 0x0a, 130},
+ {22, 0x0b, 130},
+ },
+ /* 98 */
+ {
+ {3, 0x0a, 92},
+ {6, 0x0a, 92},
+ {10, 0x0a, 92},
+ {15, 0x0a, 92},
+ {24, 0x0a, 92},
+ {31, 0x0a, 92},
+ {41, 0x0a, 92},
+ {56, 0x0b, 92},
+ {3, 0x0a, 195},
+ {6, 0x0a, 195},
+ {10, 0x0a, 195},
+ {15, 0x0a, 195},
+ {24, 0x0a, 195},
+ {31, 0x0a, 195},
+ {41, 0x0a, 195},
+ {56, 0x0b, 195},
+ },
+ /* 99 */
+ {
+ {3, 0x0a, 208},
+ {6, 0x0a, 208},
+ {10, 0x0a, 208},
+ {15, 0x0a, 208},
+ {24, 0x0a, 208},
+ {31, 0x0a, 208},
+ {41, 0x0a, 208},
+ {56, 0x0b, 208},
+ {2, 0x0a, 128},
+ {9, 0x0a, 128},
+ {23, 0x0a, 128},
+ {40, 0x0b, 128},
+ {2, 0x0a, 130},
+ {9, 0x0a, 130},
+ {23, 0x0a, 130},
+ {40, 0x0b, 130},
+ },
+ /* 100 */
+ {
+ {3, 0x0a, 128},
+ {6, 0x0a, 128},
+ {10, 0x0a, 128},
+ {15, 0x0a, 128},
+ {24, 0x0a, 128},
+ {31, 0x0a, 128},
+ {41, 0x0a, 128},
+ {56, 0x0b, 128},
+ {3, 0x0a, 130},
+ {6, 0x0a, 130},
+ {10, 0x0a, 130},
+ {15, 0x0a, 130},
+ {24, 0x0a, 130},
+ {31, 0x0a, 130},
+ {41, 0x0a, 130},
+ {56, 0x0b, 130},
+ },
+ /* 101 */
+ {
+ {1, 0x0a, 131},
+ {22, 0x0b, 131},
+ {1, 0x0a, 162},
+ {22, 0x0b, 162},
+ {1, 0x0a, 184},
+ {22, 0x0b, 184},
+ {1, 0x0a, 194},
+ {22, 0x0b, 194},
+ {1, 0x0a, 224},
+ {22, 0x0b, 224},
+ {1, 0x0a, 226},
+ {22, 0x0b, 226},
+ {0, 0x0b, 153},
+ {0, 0x0b, 161},
+ {0, 0x0b, 167},
+ {0, 0x0b, 172},
+ },
+ /* 102 */
+ {
+ {2, 0x0a, 131},
+ {9, 0x0a, 131},
+ {23, 0x0a, 131},
+ {40, 0x0b, 131},
+ {2, 0x0a, 162},
+ {9, 0x0a, 162},
+ {23, 0x0a, 162},
+ {40, 0x0b, 162},
+ {2, 0x0a, 184},
+ {9, 0x0a, 184},
+ {23, 0x0a, 184},
+ {40, 0x0b, 184},
+ {2, 0x0a, 194},
+ {9, 0x0a, 194},
+ {23, 0x0a, 194},
+ {40, 0x0b, 194},
+ },
+ /* 103 */
+ {
+ {3, 0x0a, 131},
+ {6, 0x0a, 131},
+ {10, 0x0a, 131},
+ {15, 0x0a, 131},
+ {24, 0x0a, 131},
+ {31, 0x0a, 131},
+ {41, 0x0a, 131},
+ {56, 0x0b, 131},
+ {3, 0x0a, 162},
+ {6, 0x0a, 162},
+ {10, 0x0a, 162},
+ {15, 0x0a, 162},
+ {24, 0x0a, 162},
+ {31, 0x0a, 162},
+ {41, 0x0a, 162},
+ {56, 0x0b, 162},
+ },
+ /* 104 */
+ {
+ {3, 0x0a, 184},
+ {6, 0x0a, 184},
+ {10, 0x0a, 184},
+ {15, 0x0a, 184},
+ {24, 0x0a, 184},
+ {31, 0x0a, 184},
+ {41, 0x0a, 184},
+ {56, 0x0b, 184},
+ {3, 0x0a, 194},
+ {6, 0x0a, 194},
+ {10, 0x0a, 194},
+ {15, 0x0a, 194},
+ {24, 0x0a, 194},
+ {31, 0x0a, 194},
+ {41, 0x0a, 194},
+ {56, 0x0b, 194},
+ },
+ /* 105 */
+ {
+ {2, 0x0a, 224},
+ {9, 0x0a, 224},
+ {23, 0x0a, 224},
+ {40, 0x0b, 224},
+ {2, 0x0a, 226},
+ {9, 0x0a, 226},
+ {23, 0x0a, 226},
+ {40, 0x0b, 226},
+ {1, 0x0a, 153},
+ {22, 0x0b, 153},
+ {1, 0x0a, 161},
+ {22, 0x0b, 161},
+ {1, 0x0a, 167},
+ {22, 0x0b, 167},
+ {1, 0x0a, 172},
+ {22, 0x0b, 172},
+ },
+ /* 106 */
+ {
+ {3, 0x0a, 224},
+ {6, 0x0a, 224},
+ {10, 0x0a, 224},
+ {15, 0x0a, 224},
+ {24, 0x0a, 224},
+ {31, 0x0a, 224},
+ {41, 0x0a, 224},
+ {56, 0x0b, 224},
+ {3, 0x0a, 226},
+ {6, 0x0a, 226},
+ {10, 0x0a, 226},
+ {15, 0x0a, 226},
+ {24, 0x0a, 226},
+ {31, 0x0a, 226},
+ {41, 0x0a, 226},
+ {56, 0x0b, 226},
+ },
+ /* 107 */
+ {
+ {2, 0x0a, 153},
+ {9, 0x0a, 153},
+ {23, 0x0a, 153},
+ {40, 0x0b, 153},
+ {2, 0x0a, 161},
+ {9, 0x0a, 161},
+ {23, 0x0a, 161},
+ {40, 0x0b, 161},
+ {2, 0x0a, 167},
+ {9, 0x0a, 167},
+ {23, 0x0a, 167},
+ {40, 0x0b, 167},
+ {2, 0x0a, 172},
+ {9, 0x0a, 172},
+ {23, 0x0a, 172},
+ {40, 0x0b, 172},
+ },
+ /* 108 */
+ {
+ {3, 0x0a, 153},
+ {6, 0x0a, 153},
+ {10, 0x0a, 153},
+ {15, 0x0a, 153},
+ {24, 0x0a, 153},
+ {31, 0x0a, 153},
+ {41, 0x0a, 153},
+ {56, 0x0b, 153},
+ {3, 0x0a, 161},
+ {6, 0x0a, 161},
+ {10, 0x0a, 161},
+ {15, 0x0a, 161},
+ {24, 0x0a, 161},
+ {31, 0x0a, 161},
+ {41, 0x0a, 161},
+ {56, 0x0b, 161},
+ },
+ /* 109 */
+ {
+ {3, 0x0a, 167},
+ {6, 0x0a, 167},
+ {10, 0x0a, 167},
+ {15, 0x0a, 167},
+ {24, 0x0a, 167},
+ {31, 0x0a, 167},
+ {41, 0x0a, 167},
+ {56, 0x0b, 167},
+ {3, 0x0a, 172},
+ {6, 0x0a, 172},
+ {10, 0x0a, 172},
+ {15, 0x0a, 172},
+ {24, 0x0a, 172},
+ {31, 0x0a, 172},
+ {41, 0x0a, 172},
+ {56, 0x0b, 172},
+ },
+ /* 110 */
+ {
+ {114, 0x00, 0},
+ {115, 0x00, 0},
+ {117, 0x00, 0},
+ {118, 0x00, 0},
+ {121, 0x00, 0},
+ {123, 0x00, 0},
+ {127, 0x00, 0},
+ {130, 0x00, 0},
+ {136, 0x00, 0},
+ {139, 0x00, 0},
+ {143, 0x00, 0},
+ {146, 0x00, 0},
+ {155, 0x00, 0},
+ {162, 0x00, 0},
+ {170, 0x00, 0},
+ {180, 0x00, 0},
+ },
+ /* 111 */
+ {
+ {0, 0x0b, 176},
+ {0, 0x0b, 177},
+ {0, 0x0b, 179},
+ {0, 0x0b, 209},
+ {0, 0x0b, 216},
+ {0, 0x0b, 217},
+ {0, 0x0b, 227},
+ {0, 0x0b, 229},
+ {0, 0x0b, 230},
+ {122, 0x00, 0},
+ {124, 0x00, 0},
+ {125, 0x00, 0},
+ {128, 0x00, 0},
+ {129, 0x00, 0},
+ {131, 0x00, 0},
+ {132, 0x00, 0},
+ },
+ /* 112 */
+ {
+ {1, 0x0a, 176},
+ {22, 0x0b, 176},
+ {1, 0x0a, 177},
+ {22, 0x0b, 177},
+ {1, 0x0a, 179},
+ {22, 0x0b, 179},
+ {1, 0x0a, 209},
+ {22, 0x0b, 209},
+ {1, 0x0a, 216},
+ {22, 0x0b, 216},
+ {1, 0x0a, 217},
+ {22, 0x0b, 217},
+ {1, 0x0a, 227},
+ {22, 0x0b, 227},
+ {1, 0x0a, 229},
+ {22, 0x0b, 229},
+ },
+ /* 113 */
+ {
+ {2, 0x0a, 176},
+ {9, 0x0a, 176},
+ {23, 0x0a, 176},
+ {40, 0x0b, 176},
+ {2, 0x0a, 177},
+ {9, 0x0a, 177},
+ {23, 0x0a, 177},
+ {40, 0x0b, 177},
+ {2, 0x0a, 179},
+ {9, 0x0a, 179},
+ {23, 0x0a, 179},
+ {40, 0x0b, 179},
+ {2, 0x0a, 209},
+ {9, 0x0a, 209},
+ {23, 0x0a, 209},
+ {40, 0x0b, 209},
+ },
+ /* 114 */
+ {
+ {3, 0x0a, 176},
+ {6, 0x0a, 176},
+ {10, 0x0a, 176},
+ {15, 0x0a, 176},
+ {24, 0x0a, 176},
+ {31, 0x0a, 176},
+ {41, 0x0a, 176},
+ {56, 0x0b, 176},
+ {3, 0x0a, 177},
+ {6, 0x0a, 177},
+ {10, 0x0a, 177},
+ {15, 0x0a, 177},
+ {24, 0x0a, 177},
+ {31, 0x0a, 177},
+ {41, 0x0a, 177},
+ {56, 0x0b, 177},
+ },
+ /* 115 */
+ {
+ {3, 0x0a, 179},
+ {6, 0x0a, 179},
+ {10, 0x0a, 179},
+ {15, 0x0a, 179},
+ {24, 0x0a, 179},
+ {31, 0x0a, 179},
+ {41, 0x0a, 179},
+ {56, 0x0b, 179},
+ {3, 0x0a, 209},
+ {6, 0x0a, 209},
+ {10, 0x0a, 209},
+ {15, 0x0a, 209},
+ {24, 0x0a, 209},
+ {31, 0x0a, 209},
+ {41, 0x0a, 209},
+ {56, 0x0b, 209},
+ },
+ /* 116 */
+ {
+ {2, 0x0a, 216},
+ {9, 0x0a, 216},
+ {23, 0x0a, 216},
+ {40, 0x0b, 216},
+ {2, 0x0a, 217},
+ {9, 0x0a, 217},
+ {23, 0x0a, 217},
+ {40, 0x0b, 217},
+ {2, 0x0a, 227},
+ {9, 0x0a, 227},
+ {23, 0x0a, 227},
+ {40, 0x0b, 227},
+ {2, 0x0a, 229},
+ {9, 0x0a, 229},
+ {23, 0x0a, 229},
+ {40, 0x0b, 229},
+ },
+ /* 117 */
+ {
+ {3, 0x0a, 216},
+ {6, 0x0a, 216},
+ {10, 0x0a, 216},
+ {15, 0x0a, 216},
+ {24, 0x0a, 216},
+ {31, 0x0a, 216},
+ {41, 0x0a, 216},
+ {56, 0x0b, 216},
+ {3, 0x0a, 217},
+ {6, 0x0a, 217},
+ {10, 0x0a, 217},
+ {15, 0x0a, 217},
+ {24, 0x0a, 217},
+ {31, 0x0a, 217},
+ {41, 0x0a, 217},
+ {56, 0x0b, 217},
+ },
+ /* 118 */
+ {
+ {3, 0x0a, 227},
+ {6, 0x0a, 227},
+ {10, 0x0a, 227},
+ {15, 0x0a, 227},
+ {24, 0x0a, 227},
+ {31, 0x0a, 227},
+ {41, 0x0a, 227},
+ {56, 0x0b, 227},
+ {3, 0x0a, 229},
+ {6, 0x0a, 229},
+ {10, 0x0a, 229},
+ {15, 0x0a, 229},
+ {24, 0x0a, 229},
+ {31, 0x0a, 229},
+ {41, 0x0a, 229},
+ {56, 0x0b, 229},
+ },
+ /* 119 */
+ {
+ {1, 0x0a, 230},
+ {22, 0x0b, 230},
+ {0, 0x0b, 129},
+ {0, 0x0b, 132},
+ {0, 0x0b, 133},
+ {0, 0x0b, 134},
+ {0, 0x0b, 136},
+ {0, 0x0b, 146},
+ {0, 0x0b, 154},
+ {0, 0x0b, 156},
+ {0, 0x0b, 160},
+ {0, 0x0b, 163},
+ {0, 0x0b, 164},
+ {0, 0x0b, 169},
+ {0, 0x0b, 170},
+ {0, 0x0b, 173},
+ },
+ /* 120 */
+ {
+ {2, 0x0a, 230},
+ {9, 0x0a, 230},
+ {23, 0x0a, 230},
+ {40, 0x0b, 230},
+ {1, 0x0a, 129},
+ {22, 0x0b, 129},
+ {1, 0x0a, 132},
+ {22, 0x0b, 132},
+ {1, 0x0a, 133},
+ {22, 0x0b, 133},
+ {1, 0x0a, 134},
+ {22, 0x0b, 134},
+ {1, 0x0a, 136},
+ {22, 0x0b, 136},
+ {1, 0x0a, 146},
+ {22, 0x0b, 146},
+ },
+ /* 121 */
+ {
+ {3, 0x0a, 230},
+ {6, 0x0a, 230},
+ {10, 0x0a, 230},
+ {15, 0x0a, 230},
+ {24, 0x0a, 230},
+ {31, 0x0a, 230},
+ {41, 0x0a, 230},
+ {56, 0x0b, 230},
+ {2, 0x0a, 129},
+ {9, 0x0a, 129},
+ {23, 0x0a, 129},
+ {40, 0x0b, 129},
+ {2, 0x0a, 132},
+ {9, 0x0a, 132},
+ {23, 0x0a, 132},
+ {40, 0x0b, 132},
+ },
+ /* 122 */
+ {
+ {3, 0x0a, 129},
+ {6, 0x0a, 129},
+ {10, 0x0a, 129},
+ {15, 0x0a, 129},
+ {24, 0x0a, 129},
+ {31, 0x0a, 129},
+ {41, 0x0a, 129},
+ {56, 0x0b, 129},
+ {3, 0x0a, 132},
+ {6, 0x0a, 132},
+ {10, 0x0a, 132},
+ {15, 0x0a, 132},
+ {24, 0x0a, 132},
+ {31, 0x0a, 132},
+ {41, 0x0a, 132},
+ {56, 0x0b, 132},
+ },
+ /* 123 */
+ {
+ {2, 0x0a, 133},
+ {9, 0x0a, 133},
+ {23, 0x0a, 133},
+ {40, 0x0b, 133},
+ {2, 0x0a, 134},
+ {9, 0x0a, 134},
+ {23, 0x0a, 134},
+ {40, 0x0b, 134},
+ {2, 0x0a, 136},
+ {9, 0x0a, 136},
+ {23, 0x0a, 136},
+ {40, 0x0b, 136},
+ {2, 0x0a, 146},
+ {9, 0x0a, 146},
+ {23, 0x0a, 146},
+ {40, 0x0b, 146},
+ },
+ /* 124 */
+ {
+ {3, 0x0a, 133},
+ {6, 0x0a, 133},
+ {10, 0x0a, 133},
+ {15, 0x0a, 133},
+ {24, 0x0a, 133},
+ {31, 0x0a, 133},
+ {41, 0x0a, 133},
+ {56, 0x0b, 133},
+ {3, 0x0a, 134},
+ {6, 0x0a, 134},
+ {10, 0x0a, 134},
+ {15, 0x0a, 134},
+ {24, 0x0a, 134},
+ {31, 0x0a, 134},
+ {41, 0x0a, 134},
+ {56, 0x0b, 134},
+ },
+ /* 125 */
+ {
+ {3, 0x0a, 136},
+ {6, 0x0a, 136},
+ {10, 0x0a, 136},
+ {15, 0x0a, 136},
+ {24, 0x0a, 136},
+ {31, 0x0a, 136},
+ {41, 0x0a, 136},
+ {56, 0x0b, 136},
+ {3, 0x0a, 146},
+ {6, 0x0a, 146},
+ {10, 0x0a, 146},
+ {15, 0x0a, 146},
+ {24, 0x0a, 146},
+ {31, 0x0a, 146},
+ {41, 0x0a, 146},
+ {56, 0x0b, 146},
+ },
+ /* 126 */
+ {
+ {1, 0x0a, 154},
+ {22, 0x0b, 154},
+ {1, 0x0a, 156},
+ {22, 0x0b, 156},
+ {1, 0x0a, 160},
+ {22, 0x0b, 160},
+ {1, 0x0a, 163},
+ {22, 0x0b, 163},
+ {1, 0x0a, 164},
+ {22, 0x0b, 164},
+ {1, 0x0a, 169},
+ {22, 0x0b, 169},
+ {1, 0x0a, 170},
+ {22, 0x0b, 170},
+ {1, 0x0a, 173},
+ {22, 0x0b, 173},
+ },
+ /* 127 */
+ {
+ {2, 0x0a, 154},
+ {9, 0x0a, 154},
+ {23, 0x0a, 154},
+ {40, 0x0b, 154},
+ {2, 0x0a, 156},
+ {9, 0x0a, 156},
+ {23, 0x0a, 156},
+ {40, 0x0b, 156},
+ {2, 0x0a, 160},
+ {9, 0x0a, 160},
+ {23, 0x0a, 160},
+ {40, 0x0b, 160},
+ {2, 0x0a, 163},
+ {9, 0x0a, 163},
+ {23, 0x0a, 163},
+ {40, 0x0b, 163},
+ },
+ /* 128 */
+ {
+ {3, 0x0a, 154},
+ {6, 0x0a, 154},
+ {10, 0x0a, 154},
+ {15, 0x0a, 154},
+ {24, 0x0a, 154},
+ {31, 0x0a, 154},
+ {41, 0x0a, 154},
+ {56, 0x0b, 154},
+ {3, 0x0a, 156},
+ {6, 0x0a, 156},
+ {10, 0x0a, 156},
+ {15, 0x0a, 156},
+ {24, 0x0a, 156},
+ {31, 0x0a, 156},
+ {41, 0x0a, 156},
+ {56, 0x0b, 156},
+ },
+ /* 129 */
+ {
+ {3, 0x0a, 160},
+ {6, 0x0a, 160},
+ {10, 0x0a, 160},
+ {15, 0x0a, 160},
+ {24, 0x0a, 160},
+ {31, 0x0a, 160},
+ {41, 0x0a, 160},
+ {56, 0x0b, 160},
+ {3, 0x0a, 163},
+ {6, 0x0a, 163},
+ {10, 0x0a, 163},
+ {15, 0x0a, 163},
+ {24, 0x0a, 163},
+ {31, 0x0a, 163},
+ {41, 0x0a, 163},
+ {56, 0x0b, 163},
+ },
+ /* 130 */
+ {
+ {2, 0x0a, 164},
+ {9, 0x0a, 164},
+ {23, 0x0a, 164},
+ {40, 0x0b, 164},
+ {2, 0x0a, 169},
+ {9, 0x0a, 169},
+ {23, 0x0a, 169},
+ {40, 0x0b, 169},
+ {2, 0x0a, 170},
+ {9, 0x0a, 170},
+ {23, 0x0a, 170},
+ {40, 0x0b, 170},
+ {2, 0x0a, 173},
+ {9, 0x0a, 173},
+ {23, 0x0a, 173},
+ {40, 0x0b, 173},
+ },
+ /* 131 */
+ {
+ {3, 0x0a, 164},
+ {6, 0x0a, 164},
+ {10, 0x0a, 164},
+ {15, 0x0a, 164},
+ {24, 0x0a, 164},
+ {31, 0x0a, 164},
+ {41, 0x0a, 164},
+ {56, 0x0b, 164},
+ {3, 0x0a, 169},
+ {6, 0x0a, 169},
+ {10, 0x0a, 169},
+ {15, 0x0a, 169},
+ {24, 0x0a, 169},
+ {31, 0x0a, 169},
+ {41, 0x0a, 169},
+ {56, 0x0b, 169},
+ },
+ /* 132 */
+ {
+ {3, 0x0a, 170},
+ {6, 0x0a, 170},
+ {10, 0x0a, 170},
+ {15, 0x0a, 170},
+ {24, 0x0a, 170},
+ {31, 0x0a, 170},
+ {41, 0x0a, 170},
+ {56, 0x0b, 170},
+ {3, 0x0a, 173},
+ {6, 0x0a, 173},
+ {10, 0x0a, 173},
+ {15, 0x0a, 173},
+ {24, 0x0a, 173},
+ {31, 0x0a, 173},
+ {41, 0x0a, 173},
+ {56, 0x0b, 173},
+ },
+ /* 133 */
+ {
+ {137, 0x00, 0},
+ {138, 0x00, 0},
+ {140, 0x00, 0},
+ {141, 0x00, 0},
+ {144, 0x00, 0},
+ {145, 0x00, 0},
+ {147, 0x00, 0},
+ {150, 0x00, 0},
+ {156, 0x00, 0},
+ {159, 0x00, 0},
+ {163, 0x00, 0},
+ {166, 0x00, 0},
+ {171, 0x00, 0},
+ {174, 0x00, 0},
+ {181, 0x00, 0},
+ {190, 0x00, 0},
+ },
+ /* 134 */
+ {
+ {0, 0x0b, 178},
+ {0, 0x0b, 181},
+ {0, 0x0b, 185},
+ {0, 0x0b, 186},
+ {0, 0x0b, 187},
+ {0, 0x0b, 189},
+ {0, 0x0b, 190},
+ {0, 0x0b, 196},
+ {0, 0x0b, 198},
+ {0, 0x0b, 228},
+ {0, 0x0b, 232},
+ {0, 0x0b, 233},
+ {148, 0x00, 0},
+ {149, 0x00, 0},
+ {151, 0x00, 0},
+ {152, 0x00, 0},
+ },
+ /* 135 */
+ {
+ {1, 0x0a, 178},
+ {22, 0x0b, 178},
+ {1, 0x0a, 181},
+ {22, 0x0b, 181},
+ {1, 0x0a, 185},
+ {22, 0x0b, 185},
+ {1, 0x0a, 186},
+ {22, 0x0b, 186},
+ {1, 0x0a, 187},
+ {22, 0x0b, 187},
+ {1, 0x0a, 189},
+ {22, 0x0b, 189},
+ {1, 0x0a, 190},
+ {22, 0x0b, 190},
+ {1, 0x0a, 196},
+ {22, 0x0b, 196},
+ },
+ /* 136 */
+ {
+ {2, 0x0a, 178},
+ {9, 0x0a, 178},
+ {23, 0x0a, 178},
+ {40, 0x0b, 178},
+ {2, 0x0a, 181},
+ {9, 0x0a, 181},
+ {23, 0x0a, 181},
+ {40, 0x0b, 181},
+ {2, 0x0a, 185},
+ {9, 0x0a, 185},
+ {23, 0x0a, 185},
+ {40, 0x0b, 185},
+ {2, 0x0a, 186},
+ {9, 0x0a, 186},
+ {23, 0x0a, 186},
+ {40, 0x0b, 186},
+ },
+ /* 137 */
+ {
+ {3, 0x0a, 178},
+ {6, 0x0a, 178},
+ {10, 0x0a, 178},
+ {15, 0x0a, 178},
+ {24, 0x0a, 178},
+ {31, 0x0a, 178},
+ {41, 0x0a, 178},
+ {56, 0x0b, 178},
+ {3, 0x0a, 181},
+ {6, 0x0a, 181},
+ {10, 0x0a, 181},
+ {15, 0x0a, 181},
+ {24, 0x0a, 181},
+ {31, 0x0a, 181},
+ {41, 0x0a, 181},
+ {56, 0x0b, 181},
+ },
+ /* 138 */
+ {
+ {3, 0x0a, 185},
+ {6, 0x0a, 185},
+ {10, 0x0a, 185},
+ {15, 0x0a, 185},
+ {24, 0x0a, 185},
+ {31, 0x0a, 185},
+ {41, 0x0a, 185},
+ {56, 0x0b, 185},
+ {3, 0x0a, 186},
+ {6, 0x0a, 186},
+ {10, 0x0a, 186},
+ {15, 0x0a, 186},
+ {24, 0x0a, 186},
+ {31, 0x0a, 186},
+ {41, 0x0a, 186},
+ {56, 0x0b, 186},
+ },
+ /* 139 */
+ {
+ {2, 0x0a, 187},
+ {9, 0x0a, 187},
+ {23, 0x0a, 187},
+ {40, 0x0b, 187},
+ {2, 0x0a, 189},
+ {9, 0x0a, 189},
+ {23, 0x0a, 189},
+ {40, 0x0b, 189},
+ {2, 0x0a, 190},
+ {9, 0x0a, 190},
+ {23, 0x0a, 190},
+ {40, 0x0b, 190},
+ {2, 0x0a, 196},
+ {9, 0x0a, 196},
+ {23, 0x0a, 196},
+ {40, 0x0b, 196},
+ },
+ /* 140 */
+ {
+ {3, 0x0a, 187},
+ {6, 0x0a, 187},
+ {10, 0x0a, 187},
+ {15, 0x0a, 187},
+ {24, 0x0a, 187},
+ {31, 0x0a, 187},
+ {41, 0x0a, 187},
+ {56, 0x0b, 187},
+ {3, 0x0a, 189},
+ {6, 0x0a, 189},
+ {10, 0x0a, 189},
+ {15, 0x0a, 189},
+ {24, 0x0a, 189},
+ {31, 0x0a, 189},
+ {41, 0x0a, 189},
+ {56, 0x0b, 189},
+ },
+ /* 141 */
+ {
+ {3, 0x0a, 190},
+ {6, 0x0a, 190},
+ {10, 0x0a, 190},
+ {15, 0x0a, 190},
+ {24, 0x0a, 190},
+ {31, 0x0a, 190},
+ {41, 0x0a, 190},
+ {56, 0x0b, 190},
+ {3, 0x0a, 196},
+ {6, 0x0a, 196},
+ {10, 0x0a, 196},
+ {15, 0x0a, 196},
+ {24, 0x0a, 196},
+ {31, 0x0a, 196},
+ {41, 0x0a, 196},
+ {56, 0x0b, 196},
+ },
+ /* 142 */
+ {
+ {1, 0x0a, 198},
+ {22, 0x0b, 198},
+ {1, 0x0a, 228},
+ {22, 0x0b, 228},
+ {1, 0x0a, 232},
+ {22, 0x0b, 232},
+ {1, 0x0a, 233},
+ {22, 0x0b, 233},
+ {0, 0x1b, 1},
+ {0, 0x0b, 135},
+ {0, 0x0b, 137},
+ {0, 0x0b, 138},
+ {0, 0x0b, 139},
+ {0, 0x0b, 140},
+ {0, 0x0b, 141},
+ {0, 0x0b, 143},
+ },
+ /* 143 */
+ {
+ {2, 0x0a, 198},
+ {9, 0x0a, 198},
+ {23, 0x0a, 198},
+ {40, 0x0b, 198},
+ {2, 0x0a, 228},
+ {9, 0x0a, 228},
+ {23, 0x0a, 228},
+ {40, 0x0b, 228},
+ {2, 0x0a, 232},
+ {9, 0x0a, 232},
+ {23, 0x0a, 232},
+ {40, 0x0b, 232},
+ {2, 0x0a, 233},
+ {9, 0x0a, 233},
+ {23, 0x0a, 233},
+ {40, 0x0b, 233},
+ },
+ /* 144 */
+ {
+ {3, 0x0a, 198},
+ {6, 0x0a, 198},
+ {10, 0x0a, 198},
+ {15, 0x0a, 198},
+ {24, 0x0a, 198},
+ {31, 0x0a, 198},
+ {41, 0x0a, 198},
+ {56, 0x0b, 198},
+ {3, 0x0a, 228},
+ {6, 0x0a, 228},
+ {10, 0x0a, 228},
+ {15, 0x0a, 228},
+ {24, 0x0a, 228},
+ {31, 0x0a, 228},
+ {41, 0x0a, 228},
+ {56, 0x0b, 228},
+ },
+ /* 145 */
+ {
+ {3, 0x0a, 232},
+ {6, 0x0a, 232},
+ {10, 0x0a, 232},
+ {15, 0x0a, 232},
+ {24, 0x0a, 232},
+ {31, 0x0a, 232},
+ {41, 0x0a, 232},
+ {56, 0x0b, 232},
+ {3, 0x0a, 233},
+ {6, 0x0a, 233},
+ {10, 0x0a, 233},
+ {15, 0x0a, 233},
+ {24, 0x0a, 233},
+ {31, 0x0a, 233},
+ {41, 0x0a, 233},
+ {56, 0x0b, 233},
+ },
+ /* 146 */
+ {
+ {1, 0x1a, 1},
+ {22, 0x1b, 1},
+ {1, 0x0a, 135},
+ {22, 0x0b, 135},
+ {1, 0x0a, 137},
+ {22, 0x0b, 137},
+ {1, 0x0a, 138},
+ {22, 0x0b, 138},
+ {1, 0x0a, 139},
+ {22, 0x0b, 139},
+ {1, 0x0a, 140},
+ {22, 0x0b, 140},
+ {1, 0x0a, 141},
+ {22, 0x0b, 141},
+ {1, 0x0a, 143},
+ {22, 0x0b, 143},
+ },
+ /* 147 */
+ {
+ {2, 0x1a, 1},
+ {9, 0x1a, 1},
+ {23, 0x1a, 1},
+ {40, 0x1b, 1},
+ {2, 0x0a, 135},
+ {9, 0x0a, 135},
+ {23, 0x0a, 135},
+ {40, 0x0b, 135},
+ {2, 0x0a, 137},
+ {9, 0x0a, 137},
+ {23, 0x0a, 137},
+ {40, 0x0b, 137},
+ {2, 0x0a, 138},
+ {9, 0x0a, 138},
+ {23, 0x0a, 138},
+ {40, 0x0b, 138},
+ },
+ /* 148 */
+ {
+ {3, 0x1a, 1},
+ {6, 0x1a, 1},
+ {10, 0x1a, 1},
+ {15, 0x1a, 1},
+ {24, 0x1a, 1},
+ {31, 0x1a, 1},
+ {41, 0x1a, 1},
+ {56, 0x1b, 1},
+ {3, 0x0a, 135},
+ {6, 0x0a, 135},
+ {10, 0x0a, 135},
+ {15, 0x0a, 135},
+ {24, 0x0a, 135},
+ {31, 0x0a, 135},
+ {41, 0x0a, 135},
+ {56, 0x0b, 135},
+ },
+ /* 149 */
+ {
+ {3, 0x0a, 137},
+ {6, 0x0a, 137},
+ {10, 0x0a, 137},
+ {15, 0x0a, 137},
+ {24, 0x0a, 137},
+ {31, 0x0a, 137},
+ {41, 0x0a, 137},
+ {56, 0x0b, 137},
+ {3, 0x0a, 138},
+ {6, 0x0a, 138},
+ {10, 0x0a, 138},
+ {15, 0x0a, 138},
+ {24, 0x0a, 138},
+ {31, 0x0a, 138},
+ {41, 0x0a, 138},
+ {56, 0x0b, 138},
+ },
+ /* 150 */
+ {
+ {2, 0x0a, 139},
+ {9, 0x0a, 139},
+ {23, 0x0a, 139},
+ {40, 0x0b, 139},
+ {2, 0x0a, 140},
+ {9, 0x0a, 140},
+ {23, 0x0a, 140},
+ {40, 0x0b, 140},
+ {2, 0x0a, 141},
+ {9, 0x0a, 141},
+ {23, 0x0a, 141},
+ {40, 0x0b, 141},
+ {2, 0x0a, 143},
+ {9, 0x0a, 143},
+ {23, 0x0a, 143},
+ {40, 0x0b, 143},
+ },
+ /* 151 */
+ {
+ {3, 0x0a, 139},
+ {6, 0x0a, 139},
+ {10, 0x0a, 139},
+ {15, 0x0a, 139},
+ {24, 0x0a, 139},
+ {31, 0x0a, 139},
+ {41, 0x0a, 139},
+ {56, 0x0b, 139},
+ {3, 0x0a, 140},
+ {6, 0x0a, 140},
+ {10, 0x0a, 140},
+ {15, 0x0a, 140},
+ {24, 0x0a, 140},
+ {31, 0x0a, 140},
+ {41, 0x0a, 140},
+ {56, 0x0b, 140},
+ },
+ /* 152 */
+ {
+ {3, 0x0a, 141},
+ {6, 0x0a, 141},
+ {10, 0x0a, 141},
+ {15, 0x0a, 141},
+ {24, 0x0a, 141},
+ {31, 0x0a, 141},
+ {41, 0x0a, 141},
+ {56, 0x0b, 141},
+ {3, 0x0a, 143},
+ {6, 0x0a, 143},
+ {10, 0x0a, 143},
+ {15, 0x0a, 143},
+ {24, 0x0a, 143},
+ {31, 0x0a, 143},
+ {41, 0x0a, 143},
+ {56, 0x0b, 143},
+ },
+ /* 153 */
+ {
+ {157, 0x00, 0},
+ {158, 0x00, 0},
+ {160, 0x00, 0},
+ {161, 0x00, 0},
+ {164, 0x00, 0},
+ {165, 0x00, 0},
+ {167, 0x00, 0},
+ {168, 0x00, 0},
+ {172, 0x00, 0},
+ {173, 0x00, 0},
+ {175, 0x00, 0},
+ {177, 0x00, 0},
+ {182, 0x00, 0},
+ {185, 0x00, 0},
+ {191, 0x00, 0},
+ {207, 0x00, 0},
+ },
+ /* 154 */
+ {
+ {0, 0x0b, 147},
+ {0, 0x0b, 149},
+ {0, 0x0b, 150},
+ {0, 0x0b, 151},
+ {0, 0x0b, 152},
+ {0, 0x0b, 155},
+ {0, 0x0b, 157},
+ {0, 0x0b, 158},
+ {0, 0x0b, 165},
+ {0, 0x0b, 166},
+ {0, 0x0b, 168},
+ {0, 0x0b, 174},
+ {0, 0x0b, 175},
+ {0, 0x0b, 180},
+ {0, 0x0b, 182},
+ {0, 0x0b, 183},
+ },
+ /* 155 */
+ {
+ {1, 0x0a, 147},
+ {22, 0x0b, 147},
+ {1, 0x0a, 149},
+ {22, 0x0b, 149},
+ {1, 0x0a, 150},
+ {22, 0x0b, 150},
+ {1, 0x0a, 151},
+ {22, 0x0b, 151},
+ {1, 0x0a, 152},
+ {22, 0x0b, 152},
+ {1, 0x0a, 155},
+ {22, 0x0b, 155},
+ {1, 0x0a, 157},
+ {22, 0x0b, 157},
+ {1, 0x0a, 158},
+ {22, 0x0b, 158},
+ },
+ /* 156 */
+ {
+ {2, 0x0a, 147},
+ {9, 0x0a, 147},
+ {23, 0x0a, 147},
+ {40, 0x0b, 147},
+ {2, 0x0a, 149},
+ {9, 0x0a, 149},
+ {23, 0x0a, 149},
+ {40, 0x0b, 149},
+ {2, 0x0a, 150},
+ {9, 0x0a, 150},
+ {23, 0x0a, 150},
+ {40, 0x0b, 150},
+ {2, 0x0a, 151},
+ {9, 0x0a, 151},
+ {23, 0x0a, 151},
+ {40, 0x0b, 151},
+ },
+ /* 157 */
+ {
+ {3, 0x0a, 147},
+ {6, 0x0a, 147},
+ {10, 0x0a, 147},
+ {15, 0x0a, 147},
+ {24, 0x0a, 147},
+ {31, 0x0a, 147},
+ {41, 0x0a, 147},
+ {56, 0x0b, 147},
+ {3, 0x0a, 149},
+ {6, 0x0a, 149},
+ {10, 0x0a, 149},
+ {15, 0x0a, 149},
+ {24, 0x0a, 149},
+ {31, 0x0a, 149},
+ {41, 0x0a, 149},
+ {56, 0x0b, 149},
+ },
+ /* 158 */
+ {
+ {3, 0x0a, 150},
+ {6, 0x0a, 150},
+ {10, 0x0a, 150},
+ {15, 0x0a, 150},
+ {24, 0x0a, 150},
+ {31, 0x0a, 150},
+ {41, 0x0a, 150},
+ {56, 0x0b, 150},
+ {3, 0x0a, 151},
+ {6, 0x0a, 151},
+ {10, 0x0a, 151},
+ {15, 0x0a, 151},
+ {24, 0x0a, 151},
+ {31, 0x0a, 151},
+ {41, 0x0a, 151},
+ {56, 0x0b, 151},
+ },
+ /* 159 */
+ {
+ {2, 0x0a, 152},
+ {9, 0x0a, 152},
+ {23, 0x0a, 152},
+ {40, 0x0b, 152},
+ {2, 0x0a, 155},
+ {9, 0x0a, 155},
+ {23, 0x0a, 155},
+ {40, 0x0b, 155},
+ {2, 0x0a, 157},
+ {9, 0x0a, 157},
+ {23, 0x0a, 157},
+ {40, 0x0b, 157},
+ {2, 0x0a, 158},
+ {9, 0x0a, 158},
+ {23, 0x0a, 158},
+ {40, 0x0b, 158},
+ },
+ /* 160 */
+ {
+ {3, 0x0a, 152},
+ {6, 0x0a, 152},
+ {10, 0x0a, 152},
+ {15, 0x0a, 152},
+ {24, 0x0a, 152},
+ {31, 0x0a, 152},
+ {41, 0x0a, 152},
+ {56, 0x0b, 152},
+ {3, 0x0a, 155},
+ {6, 0x0a, 155},
+ {10, 0x0a, 155},
+ {15, 0x0a, 155},
+ {24, 0x0a, 155},
+ {31, 0x0a, 155},
+ {41, 0x0a, 155},
+ {56, 0x0b, 155},
+ },
+ /* 161 */
+ {
+ {3, 0x0a, 157},
+ {6, 0x0a, 157},
+ {10, 0x0a, 157},
+ {15, 0x0a, 157},
+ {24, 0x0a, 157},
+ {31, 0x0a, 157},
+ {41, 0x0a, 157},
+ {56, 0x0b, 157},
+ {3, 0x0a, 158},
+ {6, 0x0a, 158},
+ {10, 0x0a, 158},
+ {15, 0x0a, 158},
+ {24, 0x0a, 158},
+ {31, 0x0a, 158},
+ {41, 0x0a, 158},
+ {56, 0x0b, 158},
+ },
+ /* 162 */
+ {
+ {1, 0x0a, 165},
+ {22, 0x0b, 165},
+ {1, 0x0a, 166},
+ {22, 0x0b, 166},
+ {1, 0x0a, 168},
+ {22, 0x0b, 168},
+ {1, 0x0a, 174},
+ {22, 0x0b, 174},
+ {1, 0x0a, 175},
+ {22, 0x0b, 175},
+ {1, 0x0a, 180},
+ {22, 0x0b, 180},
+ {1, 0x0a, 182},
+ {22, 0x0b, 182},
+ {1, 0x0a, 183},
+ {22, 0x0b, 183},
+ },
+ /* 163 */
+ {
+ {2, 0x0a, 165},
+ {9, 0x0a, 165},
+ {23, 0x0a, 165},
+ {40, 0x0b, 165},
+ {2, 0x0a, 166},
+ {9, 0x0a, 166},
+ {23, 0x0a, 166},
+ {40, 0x0b, 166},
+ {2, 0x0a, 168},
+ {9, 0x0a, 168},
+ {23, 0x0a, 168},
+ {40, 0x0b, 168},
+ {2, 0x0a, 174},
+ {9, 0x0a, 174},
+ {23, 0x0a, 174},
+ {40, 0x0b, 174},
+ },
+ /* 164 */
+ {
+ {3, 0x0a, 165},
+ {6, 0x0a, 165},
+ {10, 0x0a, 165},
+ {15, 0x0a, 165},
+ {24, 0x0a, 165},
+ {31, 0x0a, 165},
+ {41, 0x0a, 165},
+ {56, 0x0b, 165},
+ {3, 0x0a, 166},
+ {6, 0x0a, 166},
+ {10, 0x0a, 166},
+ {15, 0x0a, 166},
+ {24, 0x0a, 166},
+ {31, 0x0a, 166},
+ {41, 0x0a, 166},
+ {56, 0x0b, 166},
+ },
+ /* 165 */
+ {
+ {3, 0x0a, 168},
+ {6, 0x0a, 168},
+ {10, 0x0a, 168},
+ {15, 0x0a, 168},
+ {24, 0x0a, 168},
+ {31, 0x0a, 168},
+ {41, 0x0a, 168},
+ {56, 0x0b, 168},
+ {3, 0x0a, 174},
+ {6, 0x0a, 174},
+ {10, 0x0a, 174},
+ {15, 0x0a, 174},
+ {24, 0x0a, 174},
+ {31, 0x0a, 174},
+ {41, 0x0a, 174},
+ {56, 0x0b, 174},
+ },
+ /* 166 */
+ {
+ {2, 0x0a, 175},
+ {9, 0x0a, 175},
+ {23, 0x0a, 175},
+ {40, 0x0b, 175},
+ {2, 0x0a, 180},
+ {9, 0x0a, 180},
+ {23, 0x0a, 180},
+ {40, 0x0b, 180},
+ {2, 0x0a, 182},
+ {9, 0x0a, 182},
+ {23, 0x0a, 182},
+ {40, 0x0b, 182},
+ {2, 0x0a, 183},
+ {9, 0x0a, 183},
+ {23, 0x0a, 183},
+ {40, 0x0b, 183},
+ },
+ /* 167 */
+ {
+ {3, 0x0a, 175},
+ {6, 0x0a, 175},
+ {10, 0x0a, 175},
+ {15, 0x0a, 175},
+ {24, 0x0a, 175},
+ {31, 0x0a, 175},
+ {41, 0x0a, 175},
+ {56, 0x0b, 175},
+ {3, 0x0a, 180},
+ {6, 0x0a, 180},
+ {10, 0x0a, 180},
+ {15, 0x0a, 180},
+ {24, 0x0a, 180},
+ {31, 0x0a, 180},
+ {41, 0x0a, 180},
+ {56, 0x0b, 180},
+ },
+ /* 168 */
+ {
+ {3, 0x0a, 182},
+ {6, 0x0a, 182},
+ {10, 0x0a, 182},
+ {15, 0x0a, 182},
+ {24, 0x0a, 182},
+ {31, 0x0a, 182},
+ {41, 0x0a, 182},
+ {56, 0x0b, 182},
+ {3, 0x0a, 183},
+ {6, 0x0a, 183},
+ {10, 0x0a, 183},
+ {15, 0x0a, 183},
+ {24, 0x0a, 183},
+ {31, 0x0a, 183},
+ {41, 0x0a, 183},
+ {56, 0x0b, 183},
+ },
+ /* 169 */
+ {
+ {0, 0x0b, 188},
+ {0, 0x0b, 191},
+ {0, 0x0b, 197},
+ {0, 0x0b, 231},
+ {0, 0x0b, 239},
+ {176, 0x00, 0},
+ {178, 0x00, 0},
+ {179, 0x00, 0},
+ {183, 0x00, 0},
+ {184, 0x00, 0},
+ {186, 0x00, 0},
+ {187, 0x00, 0},
+ {192, 0x00, 0},
+ {199, 0x00, 0},
+ {208, 0x00, 0},
+ {223, 0x00, 0},
+ },
+ /* 170 */
+ {
+ {1, 0x0a, 188},
+ {22, 0x0b, 188},
+ {1, 0x0a, 191},
+ {22, 0x0b, 191},
+ {1, 0x0a, 197},
+ {22, 0x0b, 197},
+ {1, 0x0a, 231},
+ {22, 0x0b, 231},
+ {1, 0x0a, 239},
+ {22, 0x0b, 239},
+ {0, 0x0b, 9},
+ {0, 0x0b, 142},
+ {0, 0x0b, 144},
+ {0, 0x0b, 145},
+ {0, 0x0b, 148},
+ {0, 0x0b, 159},
+ },
+ /* 171 */
+ {
+ {2, 0x0a, 188},
+ {9, 0x0a, 188},
+ {23, 0x0a, 188},
+ {40, 0x0b, 188},
+ {2, 0x0a, 191},
+ {9, 0x0a, 191},
+ {23, 0x0a, 191},
+ {40, 0x0b, 191},
+ {2, 0x0a, 197},
+ {9, 0x0a, 197},
+ {23, 0x0a, 197},
+ {40, 0x0b, 197},
+ {2, 0x0a, 231},
+ {9, 0x0a, 231},
+ {23, 0x0a, 231},
+ {40, 0x0b, 231},
+ },
+ /* 172 */
+ {
+ {3, 0x0a, 188},
+ {6, 0x0a, 188},
+ {10, 0x0a, 188},
+ {15, 0x0a, 188},
+ {24, 0x0a, 188},
+ {31, 0x0a, 188},
+ {41, 0x0a, 188},
+ {56, 0x0b, 188},
+ {3, 0x0a, 191},
+ {6, 0x0a, 191},
+ {10, 0x0a, 191},
+ {15, 0x0a, 191},
+ {24, 0x0a, 191},
+ {31, 0x0a, 191},
+ {41, 0x0a, 191},
+ {56, 0x0b, 191},
+ },
+ /* 173 */
+ {
+ {3, 0x0a, 197},
+ {6, 0x0a, 197},
+ {10, 0x0a, 197},
+ {15, 0x0a, 197},
+ {24, 0x0a, 197},
+ {31, 0x0a, 197},
+ {41, 0x0a, 197},
+ {56, 0x0b, 197},
+ {3, 0x0a, 231},
+ {6, 0x0a, 231},
+ {10, 0x0a, 231},
+ {15, 0x0a, 231},
+ {24, 0x0a, 231},
+ {31, 0x0a, 231},
+ {41, 0x0a, 231},
+ {56, 0x0b, 231},
+ },
+ /* 174 */
+ {
+ {2, 0x0a, 239},
+ {9, 0x0a, 239},
+ {23, 0x0a, 239},
+ {40, 0x0b, 239},
+ {1, 0x0a, 9},
+ {22, 0x0b, 9},
+ {1, 0x0a, 142},
+ {22, 0x0b, 142},
+ {1, 0x0a, 144},
+ {22, 0x0b, 144},
+ {1, 0x0a, 145},
+ {22, 0x0b, 145},
+ {1, 0x0a, 148},
+ {22, 0x0b, 148},
+ {1, 0x0a, 159},
+ {22, 0x0b, 159},
+ },
+ /* 175 */
+ {
+ {3, 0x0a, 239},
+ {6, 0x0a, 239},
+ {10, 0x0a, 239},
+ {15, 0x0a, 239},
+ {24, 0x0a, 239},
+ {31, 0x0a, 239},
+ {41, 0x0a, 239},
+ {56, 0x0b, 239},
+ {2, 0x0a, 9},
+ {9, 0x0a, 9},
+ {23, 0x0a, 9},
+ {40, 0x0b, 9},
+ {2, 0x0a, 142},
+ {9, 0x0a, 142},
+ {23, 0x0a, 142},
+ {40, 0x0b, 142},
+ },
+ /* 176 */
+ {
+ {3, 0x0a, 9},
+ {6, 0x0a, 9},
+ {10, 0x0a, 9},
+ {15, 0x0a, 9},
+ {24, 0x0a, 9},
+ {31, 0x0a, 9},
+ {41, 0x0a, 9},
+ {56, 0x0b, 9},
+ {3, 0x0a, 142},
+ {6, 0x0a, 142},
+ {10, 0x0a, 142},
+ {15, 0x0a, 142},
+ {24, 0x0a, 142},
+ {31, 0x0a, 142},
+ {41, 0x0a, 142},
+ {56, 0x0b, 142},
+ },
+ /* 177 */
+ {
+ {2, 0x0a, 144},
+ {9, 0x0a, 144},
+ {23, 0x0a, 144},
+ {40, 0x0b, 144},
+ {2, 0x0a, 145},
+ {9, 0x0a, 145},
+ {23, 0x0a, 145},
+ {40, 0x0b, 145},
+ {2, 0x0a, 148},
+ {9, 0x0a, 148},
+ {23, 0x0a, 148},
+ {40, 0x0b, 148},
+ {2, 0x0a, 159},
+ {9, 0x0a, 159},
+ {23, 0x0a, 159},
+ {40, 0x0b, 159},
+ },
+ /* 178 */
+ {
+ {3, 0x0a, 144},
+ {6, 0x0a, 144},
+ {10, 0x0a, 144},
+ {15, 0x0a, 144},
+ {24, 0x0a, 144},
+ {31, 0x0a, 144},
+ {41, 0x0a, 144},
+ {56, 0x0b, 144},
+ {3, 0x0a, 145},
+ {6, 0x0a, 145},
+ {10, 0x0a, 145},
+ {15, 0x0a, 145},
+ {24, 0x0a, 145},
+ {31, 0x0a, 145},
+ {41, 0x0a, 145},
+ {56, 0x0b, 145},
+ },
+ /* 179 */
+ {
+ {3, 0x0a, 148},
+ {6, 0x0a, 148},
+ {10, 0x0a, 148},
+ {15, 0x0a, 148},
+ {24, 0x0a, 148},
+ {31, 0x0a, 148},
+ {41, 0x0a, 148},
+ {56, 0x0b, 148},
+ {3, 0x0a, 159},
+ {6, 0x0a, 159},
+ {10, 0x0a, 159},
+ {15, 0x0a, 159},
+ {24, 0x0a, 159},
+ {31, 0x0a, 159},
+ {41, 0x0a, 159},
+ {56, 0x0b, 159},
+ },
+ /* 180 */
+ {
+ {0, 0x0b, 171},
+ {0, 0x0b, 206},
+ {0, 0x0b, 215},
+ {0, 0x0b, 225},
+ {0, 0x0b, 236},
+ {0, 0x0b, 237},
+ {188, 0x00, 0},
+ {189, 0x00, 0},
+ {193, 0x00, 0},
+ {196, 0x00, 0},
+ {200, 0x00, 0},
+ {203, 0x00, 0},
+ {209, 0x00, 0},
+ {216, 0x00, 0},
+ {224, 0x00, 0},
+ {238, 0x00, 0},
+ },
+ /* 181 */
+ {
+ {1, 0x0a, 171},
+ {22, 0x0b, 171},
+ {1, 0x0a, 206},
+ {22, 0x0b, 206},
+ {1, 0x0a, 215},
+ {22, 0x0b, 215},
+ {1, 0x0a, 225},
+ {22, 0x0b, 225},
+ {1, 0x0a, 236},
+ {22, 0x0b, 236},
+ {1, 0x0a, 237},
+ {22, 0x0b, 237},
+ {0, 0x0b, 199},
+ {0, 0x0b, 207},
+ {0, 0x0b, 234},
+ {0, 0x0b, 235},
+ },
+ /* 182 */
+ {
+ {2, 0x0a, 171},
+ {9, 0x0a, 171},
+ {23, 0x0a, 171},
+ {40, 0x0b, 171},
+ {2, 0x0a, 206},
+ {9, 0x0a, 206},
+ {23, 0x0a, 206},
+ {40, 0x0b, 206},
+ {2, 0x0a, 215},
+ {9, 0x0a, 215},
+ {23, 0x0a, 215},
+ {40, 0x0b, 215},
+ {2, 0x0a, 225},
+ {9, 0x0a, 225},
+ {23, 0x0a, 225},
+ {40, 0x0b, 225},
+ },
+ /* 183 */
+ {
+ {3, 0x0a, 171},
+ {6, 0x0a, 171},
+ {10, 0x0a, 171},
+ {15, 0x0a, 171},
+ {24, 0x0a, 171},
+ {31, 0x0a, 171},
+ {41, 0x0a, 171},
+ {56, 0x0b, 171},
+ {3, 0x0a, 206},
+ {6, 0x0a, 206},
+ {10, 0x0a, 206},
+ {15, 0x0a, 206},
+ {24, 0x0a, 206},
+ {31, 0x0a, 206},
+ {41, 0x0a, 206},
+ {56, 0x0b, 206},
+ },
+ /* 184 */
+ {
+ {3, 0x0a, 215},
+ {6, 0x0a, 215},
+ {10, 0x0a, 215},
+ {15, 0x0a, 215},
+ {24, 0x0a, 215},
+ {31, 0x0a, 215},
+ {41, 0x0a, 215},
+ {56, 0x0b, 215},
+ {3, 0x0a, 225},
+ {6, 0x0a, 225},
+ {10, 0x0a, 225},
+ {15, 0x0a, 225},
+ {24, 0x0a, 225},
+ {31, 0x0a, 225},
+ {41, 0x0a, 225},
+ {56, 0x0b, 225},
+ },
+ /* 185 */
+ {
+ {2, 0x0a, 236},
+ {9, 0x0a, 236},
+ {23, 0x0a, 236},
+ {40, 0x0b, 236},
+ {2, 0x0a, 237},
+ {9, 0x0a, 237},
+ {23, 0x0a, 237},
+ {40, 0x0b, 237},
+ {1, 0x0a, 199},
+ {22, 0x0b, 199},
+ {1, 0x0a, 207},
+ {22, 0x0b, 207},
+ {1, 0x0a, 234},
+ {22, 0x0b, 234},
+ {1, 0x0a, 235},
+ {22, 0x0b, 235},
+ },
+ /* 186 */
+ {
+ {3, 0x0a, 236},
+ {6, 0x0a, 236},
+ {10, 0x0a, 236},
+ {15, 0x0a, 236},
+ {24, 0x0a, 236},
+ {31, 0x0a, 236},
+ {41, 0x0a, 236},
+ {56, 0x0b, 236},
+ {3, 0x0a, 237},
+ {6, 0x0a, 237},
+ {10, 0x0a, 237},
+ {15, 0x0a, 237},
+ {24, 0x0a, 237},
+ {31, 0x0a, 237},
+ {41, 0x0a, 237},
+ {56, 0x0b, 237},
+ },
+ /* 187 */
+ {
+ {2, 0x0a, 199},
+ {9, 0x0a, 199},
+ {23, 0x0a, 199},
+ {40, 0x0b, 199},
+ {2, 0x0a, 207},
+ {9, 0x0a, 207},
+ {23, 0x0a, 207},
+ {40, 0x0b, 207},
+ {2, 0x0a, 234},
+ {9, 0x0a, 234},
+ {23, 0x0a, 234},
+ {40, 0x0b, 234},
+ {2, 0x0a, 235},
+ {9, 0x0a, 235},
+ {23, 0x0a, 235},
+ {40, 0x0b, 235},
+ },
+ /* 188 */
+ {
+ {3, 0x0a, 199},
+ {6, 0x0a, 199},
+ {10, 0x0a, 199},
+ {15, 0x0a, 199},
+ {24, 0x0a, 199},
+ {31, 0x0a, 199},
+ {41, 0x0a, 199},
+ {56, 0x0b, 199},
+ {3, 0x0a, 207},
+ {6, 0x0a, 207},
+ {10, 0x0a, 207},
+ {15, 0x0a, 207},
+ {24, 0x0a, 207},
+ {31, 0x0a, 207},
+ {41, 0x0a, 207},
+ {56, 0x0b, 207},
+ },
+ /* 189 */
+ {
+ {3, 0x0a, 234},
+ {6, 0x0a, 234},
+ {10, 0x0a, 234},
+ {15, 0x0a, 234},
+ {24, 0x0a, 234},
+ {31, 0x0a, 234},
+ {41, 0x0a, 234},
+ {56, 0x0b, 234},
+ {3, 0x0a, 235},
+ {6, 0x0a, 235},
+ {10, 0x0a, 235},
+ {15, 0x0a, 235},
+ {24, 0x0a, 235},
+ {31, 0x0a, 235},
+ {41, 0x0a, 235},
+ {56, 0x0b, 235},
+ },
+ /* 190 */
+ {
+ {194, 0x00, 0},
+ {195, 0x00, 0},
+ {197, 0x00, 0},
+ {198, 0x00, 0},
+ {201, 0x00, 0},
+ {202, 0x00, 0},
+ {204, 0x00, 0},
+ {205, 0x00, 0},
+ {210, 0x00, 0},
+ {213, 0x00, 0},
+ {217, 0x00, 0},
+ {220, 0x00, 0},
+ {225, 0x00, 0},
+ {231, 0x00, 0},
+ {239, 0x00, 0},
+ {246, 0x00, 0},
+ },
+ /* 191 */
+ {
+ {0, 0x0b, 192},
+ {0, 0x0b, 193},
+ {0, 0x0b, 200},
+ {0, 0x0b, 201},
+ {0, 0x0b, 202},
+ {0, 0x0b, 205},
+ {0, 0x0b, 210},
+ {0, 0x0b, 213},
+ {0, 0x0b, 218},
+ {0, 0x0b, 219},
+ {0, 0x0b, 238},
+ {0, 0x0b, 240},
+ {0, 0x0b, 242},
+ {0, 0x0b, 243},
+ {0, 0x0b, 255},
+ {206, 0x00, 0},
+ },
+ /* 192 */
+ {
+ {1, 0x0a, 192},
+ {22, 0x0b, 192},
+ {1, 0x0a, 193},
+ {22, 0x0b, 193},
+ {1, 0x0a, 200},
+ {22, 0x0b, 200},
+ {1, 0x0a, 201},
+ {22, 0x0b, 201},
+ {1, 0x0a, 202},
+ {22, 0x0b, 202},
+ {1, 0x0a, 205},
+ {22, 0x0b, 205},
+ {1, 0x0a, 210},
+ {22, 0x0b, 210},
+ {1, 0x0a, 213},
+ {22, 0x0b, 213},
+ },
+ /* 193 */
+ {
+ {2, 0x0a, 192},
+ {9, 0x0a, 192},
+ {23, 0x0a, 192},
+ {40, 0x0b, 192},
+ {2, 0x0a, 193},
+ {9, 0x0a, 193},
+ {23, 0x0a, 193},
+ {40, 0x0b, 193},
+ {2, 0x0a, 200},
+ {9, 0x0a, 200},
+ {23, 0x0a, 200},
+ {40, 0x0b, 200},
+ {2, 0x0a, 201},
+ {9, 0x0a, 201},
+ {23, 0x0a, 201},
+ {40, 0x0b, 201},
+ },
+ /* 194 */
+ {
+ {3, 0x0a, 192},
+ {6, 0x0a, 192},
+ {10, 0x0a, 192},
+ {15, 0x0a, 192},
+ {24, 0x0a, 192},
+ {31, 0x0a, 192},
+ {41, 0x0a, 192},
+ {56, 0x0b, 192},
+ {3, 0x0a, 193},
+ {6, 0x0a, 193},
+ {10, 0x0a, 193},
+ {15, 0x0a, 193},
+ {24, 0x0a, 193},
+ {31, 0x0a, 193},
+ {41, 0x0a, 193},
+ {56, 0x0b, 193},
+ },
+ /* 195 */
+ {
+ {3, 0x0a, 200},
+ {6, 0x0a, 200},
+ {10, 0x0a, 200},
+ {15, 0x0a, 200},
+ {24, 0x0a, 200},
+ {31, 0x0a, 200},
+ {41, 0x0a, 200},
+ {56, 0x0b, 200},
+ {3, 0x0a, 201},
+ {6, 0x0a, 201},
+ {10, 0x0a, 201},
+ {15, 0x0a, 201},
+ {24, 0x0a, 201},
+ {31, 0x0a, 201},
+ {41, 0x0a, 201},
+ {56, 0x0b, 201},
+ },
+ /* 196 */
+ {
+ {2, 0x0a, 202},
+ {9, 0x0a, 202},
+ {23, 0x0a, 202},
+ {40, 0x0b, 202},
+ {2, 0x0a, 205},
+ {9, 0x0a, 205},
+ {23, 0x0a, 205},
+ {40, 0x0b, 205},
+ {2, 0x0a, 210},
+ {9, 0x0a, 210},
+ {23, 0x0a, 210},
+ {40, 0x0b, 210},
+ {2, 0x0a, 213},
+ {9, 0x0a, 213},
+ {23, 0x0a, 213},
+ {40, 0x0b, 213},
+ },
+ /* 197 */
+ {
+ {3, 0x0a, 202},
+ {6, 0x0a, 202},
+ {10, 0x0a, 202},
+ {15, 0x0a, 202},
+ {24, 0x0a, 202},
+ {31, 0x0a, 202},
+ {41, 0x0a, 202},
+ {56, 0x0b, 202},
+ {3, 0x0a, 205},
+ {6, 0x0a, 205},
+ {10, 0x0a, 205},
+ {15, 0x0a, 205},
+ {24, 0x0a, 205},
+ {31, 0x0a, 205},
+ {41, 0x0a, 205},
+ {56, 0x0b, 205},
+ },
+ /* 198 */
+ {
+ {3, 0x0a, 210},
+ {6, 0x0a, 210},
+ {10, 0x0a, 210},
+ {15, 0x0a, 210},
+ {24, 0x0a, 210},
+ {31, 0x0a, 210},
+ {41, 0x0a, 210},
+ {56, 0x0b, 210},
+ {3, 0x0a, 213},
+ {6, 0x0a, 213},
+ {10, 0x0a, 213},
+ {15, 0x0a, 213},
+ {24, 0x0a, 213},
+ {31, 0x0a, 213},
+ {41, 0x0a, 213},
+ {56, 0x0b, 213},
+ },
+ /* 199 */
+ {
+ {1, 0x0a, 218},
+ {22, 0x0b, 218},
+ {1, 0x0a, 219},
+ {22, 0x0b, 219},
+ {1, 0x0a, 238},
+ {22, 0x0b, 238},
+ {1, 0x0a, 240},
+ {22, 0x0b, 240},
+ {1, 0x0a, 242},
+ {22, 0x0b, 242},
+ {1, 0x0a, 243},
+ {22, 0x0b, 243},
+ {1, 0x0a, 255},
+ {22, 0x0b, 255},
+ {0, 0x0b, 203},
+ {0, 0x0b, 204},
+ },
+ /* 200 */
+ {
+ {2, 0x0a, 218},
+ {9, 0x0a, 218},
+ {23, 0x0a, 218},
+ {40, 0x0b, 218},
+ {2, 0x0a, 219},
+ {9, 0x0a, 219},
+ {23, 0x0a, 219},
+ {40, 0x0b, 219},
+ {2, 0x0a, 238},
+ {9, 0x0a, 238},
+ {23, 0x0a, 238},
+ {40, 0x0b, 238},
+ {2, 0x0a, 240},
+ {9, 0x0a, 240},
+ {23, 0x0a, 240},
+ {40, 0x0b, 240},
+ },
+ /* 201 */
+ {
+ {3, 0x0a, 218},
+ {6, 0x0a, 218},
+ {10, 0x0a, 218},
+ {15, 0x0a, 218},
+ {24, 0x0a, 218},
+ {31, 0x0a, 218},
+ {41, 0x0a, 218},
+ {56, 0x0b, 218},
+ {3, 0x0a, 219},
+ {6, 0x0a, 219},
+ {10, 0x0a, 219},
+ {15, 0x0a, 219},
+ {24, 0x0a, 219},
+ {31, 0x0a, 219},
+ {41, 0x0a, 219},
+ {56, 0x0b, 219},
+ },
+ /* 202 */
+ {
+ {3, 0x0a, 238},
+ {6, 0x0a, 238},
+ {10, 0x0a, 238},
+ {15, 0x0a, 238},
+ {24, 0x0a, 238},
+ {31, 0x0a, 238},
+ {41, 0x0a, 238},
+ {56, 0x0b, 238},
+ {3, 0x0a, 240},
+ {6, 0x0a, 240},
+ {10, 0x0a, 240},
+ {15, 0x0a, 240},
+ {24, 0x0a, 240},
+ {31, 0x0a, 240},
+ {41, 0x0a, 240},
+ {56, 0x0b, 240},
+ },
+ /* 203 */
+ {
+ {2, 0x0a, 242},
+ {9, 0x0a, 242},
+ {23, 0x0a, 242},
+ {40, 0x0b, 242},
+ {2, 0x0a, 243},
+ {9, 0x0a, 243},
+ {23, 0x0a, 243},
+ {40, 0x0b, 243},
+ {2, 0x0a, 255},
+ {9, 0x0a, 255},
+ {23, 0x0a, 255},
+ {40, 0x0b, 255},
+ {1, 0x0a, 203},
+ {22, 0x0b, 203},
+ {1, 0x0a, 204},
+ {22, 0x0b, 204},
+ },
+ /* 204 */
+ {
+ {3, 0x0a, 242},
+ {6, 0x0a, 242},
+ {10, 0x0a, 242},
+ {15, 0x0a, 242},
+ {24, 0x0a, 242},
+ {31, 0x0a, 242},
+ {41, 0x0a, 242},
+ {56, 0x0b, 242},
+ {3, 0x0a, 243},
+ {6, 0x0a, 243},
+ {10, 0x0a, 243},
+ {15, 0x0a, 243},
+ {24, 0x0a, 243},
+ {31, 0x0a, 243},
+ {41, 0x0a, 243},
+ {56, 0x0b, 243},
+ },
+ /* 205 */
+ {
+ {3, 0x0a, 255},
+ {6, 0x0a, 255},
+ {10, 0x0a, 255},
+ {15, 0x0a, 255},
+ {24, 0x0a, 255},
+ {31, 0x0a, 255},
+ {41, 0x0a, 255},
+ {56, 0x0b, 255},
+ {2, 0x0a, 203},
+ {9, 0x0a, 203},
+ {23, 0x0a, 203},
+ {40, 0x0b, 203},
+ {2, 0x0a, 204},
+ {9, 0x0a, 204},
+ {23, 0x0a, 204},
+ {40, 0x0b, 204},
+ },
+ /* 206 */
+ {
+ {3, 0x0a, 203},
+ {6, 0x0a, 203},
+ {10, 0x0a, 203},
+ {15, 0x0a, 203},
+ {24, 0x0a, 203},
+ {31, 0x0a, 203},
+ {41, 0x0a, 203},
+ {56, 0x0b, 203},
+ {3, 0x0a, 204},
+ {6, 0x0a, 204},
+ {10, 0x0a, 204},
+ {15, 0x0a, 204},
+ {24, 0x0a, 204},
+ {31, 0x0a, 204},
+ {41, 0x0a, 204},
+ {56, 0x0b, 204},
+ },
+ /* 207 */
+ {
+ {211, 0x00, 0},
+ {212, 0x00, 0},
+ {214, 0x00, 0},
+ {215, 0x00, 0},
+ {218, 0x00, 0},
+ {219, 0x00, 0},
+ {221, 0x00, 0},
+ {222, 0x00, 0},
+ {226, 0x00, 0},
+ {228, 0x00, 0},
+ {232, 0x00, 0},
+ {235, 0x00, 0},
+ {240, 0x00, 0},
+ {243, 0x00, 0},
+ {247, 0x00, 0},
+ {250, 0x00, 0},
+ },
+ /* 208 */
+ {
+ {0, 0x0b, 211},
+ {0, 0x0b, 212},
+ {0, 0x0b, 214},
+ {0, 0x0b, 221},
+ {0, 0x0b, 222},
+ {0, 0x0b, 223},
+ {0, 0x0b, 241},
+ {0, 0x0b, 244},
+ {0, 0x0b, 245},
+ {0, 0x0b, 246},
+ {0, 0x0b, 247},
+ {0, 0x0b, 248},
+ {0, 0x0b, 250},
+ {0, 0x0b, 251},
+ {0, 0x0b, 252},
+ {0, 0x0b, 253},
+ },
+ /* 209 */
+ {
+ {1, 0x0a, 211},
+ {22, 0x0b, 211},
+ {1, 0x0a, 212},
+ {22, 0x0b, 212},
+ {1, 0x0a, 214},
+ {22, 0x0b, 214},
+ {1, 0x0a, 221},
+ {22, 0x0b, 221},
+ {1, 0x0a, 222},
+ {22, 0x0b, 222},
+ {1, 0x0a, 223},
+ {22, 0x0b, 223},
+ {1, 0x0a, 241},
+ {22, 0x0b, 241},
+ {1, 0x0a, 244},
+ {22, 0x0b, 244},
+ },
+ /* 210 */
+ {
+ {2, 0x0a, 211},
+ {9, 0x0a, 211},
+ {23, 0x0a, 211},
+ {40, 0x0b, 211},
+ {2, 0x0a, 212},
+ {9, 0x0a, 212},
+ {23, 0x0a, 212},
+ {40, 0x0b, 212},
+ {2, 0x0a, 214},
+ {9, 0x0a, 214},
+ {23, 0x0a, 214},
+ {40, 0x0b, 214},
+ {2, 0x0a, 221},
+ {9, 0x0a, 221},
+ {23, 0x0a, 221},
+ {40, 0x0b, 221},
+ },
+ /* 211 */
+ {
+ {3, 0x0a, 211},
+ {6, 0x0a, 211},
+ {10, 0x0a, 211},
+ {15, 0x0a, 211},
+ {24, 0x0a, 211},
+ {31, 0x0a, 211},
+ {41, 0x0a, 211},
+ {56, 0x0b, 211},
+ {3, 0x0a, 212},
+ {6, 0x0a, 212},
+ {10, 0x0a, 212},
+ {15, 0x0a, 212},
+ {24, 0x0a, 212},
+ {31, 0x0a, 212},
+ {41, 0x0a, 212},
+ {56, 0x0b, 212},
+ },
+ /* 212 */
+ {
+ {3, 0x0a, 214},
+ {6, 0x0a, 214},
+ {10, 0x0a, 214},
+ {15, 0x0a, 214},
+ {24, 0x0a, 214},
+ {31, 0x0a, 214},
+ {41, 0x0a, 214},
+ {56, 0x0b, 214},
+ {3, 0x0a, 221},
+ {6, 0x0a, 221},
+ {10, 0x0a, 221},
+ {15, 0x0a, 221},
+ {24, 0x0a, 221},
+ {31, 0x0a, 221},
+ {41, 0x0a, 221},
+ {56, 0x0b, 221},
+ },
+ /* 213 */
+ {
+ {2, 0x0a, 222},
+ {9, 0x0a, 222},
+ {23, 0x0a, 222},
+ {40, 0x0b, 222},
+ {2, 0x0a, 223},
+ {9, 0x0a, 223},
+ {23, 0x0a, 223},
+ {40, 0x0b, 223},
+ {2, 0x0a, 241},
+ {9, 0x0a, 241},
+ {23, 0x0a, 241},
+ {40, 0x0b, 241},
+ {2, 0x0a, 244},
+ {9, 0x0a, 244},
+ {23, 0x0a, 244},
+ {40, 0x0b, 244},
+ },
+ /* 214 */
+ {
+ {3, 0x0a, 222},
+ {6, 0x0a, 222},
+ {10, 0x0a, 222},
+ {15, 0x0a, 222},
+ {24, 0x0a, 222},
+ {31, 0x0a, 222},
+ {41, 0x0a, 222},
+ {56, 0x0b, 222},
+ {3, 0x0a, 223},
+ {6, 0x0a, 223},
+ {10, 0x0a, 223},
+ {15, 0x0a, 223},
+ {24, 0x0a, 223},
+ {31, 0x0a, 223},
+ {41, 0x0a, 223},
+ {56, 0x0b, 223},
+ },
+ /* 215 */
+ {
+ {3, 0x0a, 241},
+ {6, 0x0a, 241},
+ {10, 0x0a, 241},
+ {15, 0x0a, 241},
+ {24, 0x0a, 241},
+ {31, 0x0a, 241},
+ {41, 0x0a, 241},
+ {56, 0x0b, 241},
+ {3, 0x0a, 244},
+ {6, 0x0a, 244},
+ {10, 0x0a, 244},
+ {15, 0x0a, 244},
+ {24, 0x0a, 244},
+ {31, 0x0a, 244},
+ {41, 0x0a, 244},
+ {56, 0x0b, 244},
+ },
+ /* 216 */
+ {
+ {1, 0x0a, 245},
+ {22, 0x0b, 245},
+ {1, 0x0a, 246},
+ {22, 0x0b, 246},
+ {1, 0x0a, 247},
+ {22, 0x0b, 247},
+ {1, 0x0a, 248},
+ {22, 0x0b, 248},
+ {1, 0x0a, 250},
+ {22, 0x0b, 250},
+ {1, 0x0a, 251},
+ {22, 0x0b, 251},
+ {1, 0x0a, 252},
+ {22, 0x0b, 252},
+ {1, 0x0a, 253},
+ {22, 0x0b, 253},
+ },
+ /* 217 */
+ {
+ {2, 0x0a, 245},
+ {9, 0x0a, 245},
+ {23, 0x0a, 245},
+ {40, 0x0b, 245},
+ {2, 0x0a, 246},
+ {9, 0x0a, 246},
+ {23, 0x0a, 246},
+ {40, 0x0b, 246},
+ {2, 0x0a, 247},
+ {9, 0x0a, 247},
+ {23, 0x0a, 247},
+ {40, 0x0b, 247},
+ {2, 0x0a, 248},
+ {9, 0x0a, 248},
+ {23, 0x0a, 248},
+ {40, 0x0b, 248},
+ },
+ /* 218 */
+ {
+ {3, 0x0a, 245},
+ {6, 0x0a, 245},
+ {10, 0x0a, 245},
+ {15, 0x0a, 245},
+ {24, 0x0a, 245},
+ {31, 0x0a, 245},
+ {41, 0x0a, 245},
+ {56, 0x0b, 245},
+ {3, 0x0a, 246},
+ {6, 0x0a, 246},
+ {10, 0x0a, 246},
+ {15, 0x0a, 246},
+ {24, 0x0a, 246},
+ {31, 0x0a, 246},
+ {41, 0x0a, 246},
+ {56, 0x0b, 246},
+ },
+ /* 219 */
+ {
+ {3, 0x0a, 247},
+ {6, 0x0a, 247},
+ {10, 0x0a, 247},
+ {15, 0x0a, 247},
+ {24, 0x0a, 247},
+ {31, 0x0a, 247},
+ {41, 0x0a, 247},
+ {56, 0x0b, 247},
+ {3, 0x0a, 248},
+ {6, 0x0a, 248},
+ {10, 0x0a, 248},
+ {15, 0x0a, 248},
+ {24, 0x0a, 248},
+ {31, 0x0a, 248},
+ {41, 0x0a, 248},
+ {56, 0x0b, 248},
+ },
+ /* 220 */
+ {
+ {2, 0x0a, 250},
+ {9, 0x0a, 250},
+ {23, 0x0a, 250},
+ {40, 0x0b, 250},
+ {2, 0x0a, 251},
+ {9, 0x0a, 251},
+ {23, 0x0a, 251},
+ {40, 0x0b, 251},
+ {2, 0x0a, 252},
+ {9, 0x0a, 252},
+ {23, 0x0a, 252},
+ {40, 0x0b, 252},
+ {2, 0x0a, 253},
+ {9, 0x0a, 253},
+ {23, 0x0a, 253},
+ {40, 0x0b, 253},
+ },
+ /* 221 */
+ {
+ {3, 0x0a, 250},
+ {6, 0x0a, 250},
+ {10, 0x0a, 250},
+ {15, 0x0a, 250},
+ {24, 0x0a, 250},
+ {31, 0x0a, 250},
+ {41, 0x0a, 250},
+ {56, 0x0b, 250},
+ {3, 0x0a, 251},
+ {6, 0x0a, 251},
+ {10, 0x0a, 251},
+ {15, 0x0a, 251},
+ {24, 0x0a, 251},
+ {31, 0x0a, 251},
+ {41, 0x0a, 251},
+ {56, 0x0b, 251},
+ },
+ /* 222 */
+ {
+ {3, 0x0a, 252},
+ {6, 0x0a, 252},
+ {10, 0x0a, 252},
+ {15, 0x0a, 252},
+ {24, 0x0a, 252},
+ {31, 0x0a, 252},
+ {41, 0x0a, 252},
+ {56, 0x0b, 252},
+ {3, 0x0a, 253},
+ {6, 0x0a, 253},
+ {10, 0x0a, 253},
+ {15, 0x0a, 253},
+ {24, 0x0a, 253},
+ {31, 0x0a, 253},
+ {41, 0x0a, 253},
+ {56, 0x0b, 253},
+ },
+ /* 223 */
+ {
+ {0, 0x0b, 254},
+ {227, 0x00, 0},
+ {229, 0x00, 0},
+ {230, 0x00, 0},
+ {233, 0x00, 0},
+ {234, 0x00, 0},
+ {236, 0x00, 0},
+ {237, 0x00, 0},
+ {241, 0x00, 0},
+ {242, 0x00, 0},
+ {244, 0x00, 0},
+ {245, 0x00, 0},
+ {248, 0x00, 0},
+ {249, 0x00, 0},
+ {251, 0x00, 0},
+ {252, 0x00, 0},
+ },
+ /* 224 */
+ {
+ {1, 0x0a, 254},
+ {22, 0x0b, 254},
+ {0, 0x1b, 2},
+ {0, 0x1b, 3},
+ {0, 0x1b, 4},
+ {0, 0x1b, 5},
+ {0, 0x1b, 6},
+ {0, 0x1b, 7},
+ {0, 0x1b, 8},
+ {0, 0x1b, 11},
+ {0, 0x1b, 12},
+ {0, 0x1b, 14},
+ {0, 0x1b, 15},
+ {0, 0x1b, 16},
+ {0, 0x1b, 17},
+ {0, 0x1b, 18},
+ },
+ /* 225 */
+ {
+ {2, 0x0a, 254},
+ {9, 0x0a, 254},
+ {23, 0x0a, 254},
+ {40, 0x0b, 254},
+ {1, 0x1a, 2},
+ {22, 0x1b, 2},
+ {1, 0x1a, 3},
+ {22, 0x1b, 3},
+ {1, 0x1a, 4},
+ {22, 0x1b, 4},
+ {1, 0x1a, 5},
+ {22, 0x1b, 5},
+ {1, 0x1a, 6},
+ {22, 0x1b, 6},
+ {1, 0x1a, 7},
+ {22, 0x1b, 7},
+ },
+ /* 226 */
+ {
+ {3, 0x0a, 254},
+ {6, 0x0a, 254},
+ {10, 0x0a, 254},
+ {15, 0x0a, 254},
+ {24, 0x0a, 254},
+ {31, 0x0a, 254},
+ {41, 0x0a, 254},
+ {56, 0x0b, 254},
+ {2, 0x1a, 2},
+ {9, 0x1a, 2},
+ {23, 0x1a, 2},
+ {40, 0x1b, 2},
+ {2, 0x1a, 3},
+ {9, 0x1a, 3},
+ {23, 0x1a, 3},
+ {40, 0x1b, 3},
+ },
+ /* 227 */
+ {
+ {3, 0x1a, 2},
+ {6, 0x1a, 2},
+ {10, 0x1a, 2},
+ {15, 0x1a, 2},
+ {24, 0x1a, 2},
+ {31, 0x1a, 2},
+ {41, 0x1a, 2},
+ {56, 0x1b, 2},
+ {3, 0x1a, 3},
+ {6, 0x1a, 3},
+ {10, 0x1a, 3},
+ {15, 0x1a, 3},
+ {24, 0x1a, 3},
+ {31, 0x1a, 3},
+ {41, 0x1a, 3},
+ {56, 0x1b, 3},
+ },
+ /* 228 */
+ {
+ {2, 0x1a, 4},
+ {9, 0x1a, 4},
+ {23, 0x1a, 4},
+ {40, 0x1b, 4},
+ {2, 0x1a, 5},
+ {9, 0x1a, 5},
+ {23, 0x1a, 5},
+ {40, 0x1b, 5},
+ {2, 0x1a, 6},
+ {9, 0x1a, 6},
+ {23, 0x1a, 6},
+ {40, 0x1b, 6},
+ {2, 0x1a, 7},
+ {9, 0x1a, 7},
+ {23, 0x1a, 7},
+ {40, 0x1b, 7},
+ },
+ /* 229 */
+ {
+ {3, 0x1a, 4},
+ {6, 0x1a, 4},
+ {10, 0x1a, 4},
+ {15, 0x1a, 4},
+ {24, 0x1a, 4},
+ {31, 0x1a, 4},
+ {41, 0x1a, 4},
+ {56, 0x1b, 4},
+ {3, 0x1a, 5},
+ {6, 0x1a, 5},
+ {10, 0x1a, 5},
+ {15, 0x1a, 5},
+ {24, 0x1a, 5},
+ {31, 0x1a, 5},
+ {41, 0x1a, 5},
+ {56, 0x1b, 5},
+ },
+ /* 230 */
+ {
+ {3, 0x1a, 6},
+ {6, 0x1a, 6},
+ {10, 0x1a, 6},
+ {15, 0x1a, 6},
+ {24, 0x1a, 6},
+ {31, 0x1a, 6},
+ {41, 0x1a, 6},
+ {56, 0x1b, 6},
+ {3, 0x1a, 7},
+ {6, 0x1a, 7},
+ {10, 0x1a, 7},
+ {15, 0x1a, 7},
+ {24, 0x1a, 7},
+ {31, 0x1a, 7},
+ {41, 0x1a, 7},
+ {56, 0x1b, 7},
+ },
+ /* 231 */
+ {
+ {1, 0x1a, 8},
+ {22, 0x1b, 8},
+ {1, 0x1a, 11},
+ {22, 0x1b, 11},
+ {1, 0x1a, 12},
+ {22, 0x1b, 12},
+ {1, 0x1a, 14},
+ {22, 0x1b, 14},
+ {1, 0x1a, 15},
+ {22, 0x1b, 15},
+ {1, 0x1a, 16},
+ {22, 0x1b, 16},
+ {1, 0x1a, 17},
+ {22, 0x1b, 17},
+ {1, 0x1a, 18},
+ {22, 0x1b, 18},
+ },
+ /* 232 */
+ {
+ {2, 0x1a, 8},
+ {9, 0x1a, 8},
+ {23, 0x1a, 8},
+ {40, 0x1b, 8},
+ {2, 0x1a, 11},
+ {9, 0x1a, 11},
+ {23, 0x1a, 11},
+ {40, 0x1b, 11},
+ {2, 0x1a, 12},
+ {9, 0x1a, 12},
+ {23, 0x1a, 12},
+ {40, 0x1b, 12},
+ {2, 0x1a, 14},
+ {9, 0x1a, 14},
+ {23, 0x1a, 14},
+ {40, 0x1b, 14},
+ },
+ /* 233 */
+ {
+ {3, 0x1a, 8},
+ {6, 0x1a, 8},
+ {10, 0x1a, 8},
+ {15, 0x1a, 8},
+ {24, 0x1a, 8},
+ {31, 0x1a, 8},
+ {41, 0x1a, 8},
+ {56, 0x1b, 8},
+ {3, 0x1a, 11},
+ {6, 0x1a, 11},
+ {10, 0x1a, 11},
+ {15, 0x1a, 11},
+ {24, 0x1a, 11},
+ {31, 0x1a, 11},
+ {41, 0x1a, 11},
+ {56, 0x1b, 11},
+ },
+ /* 234 */
+ {
+ {3, 0x1a, 12},
+ {6, 0x1a, 12},
+ {10, 0x1a, 12},
+ {15, 0x1a, 12},
+ {24, 0x1a, 12},
+ {31, 0x1a, 12},
+ {41, 0x1a, 12},
+ {56, 0x1b, 12},
+ {3, 0x1a, 14},
+ {6, 0x1a, 14},
+ {10, 0x1a, 14},
+ {15, 0x1a, 14},
+ {24, 0x1a, 14},
+ {31, 0x1a, 14},
+ {41, 0x1a, 14},
+ {56, 0x1b, 14},
+ },
+ /* 235 */
+ {
+ {2, 0x1a, 15},
+ {9, 0x1a, 15},
+ {23, 0x1a, 15},
+ {40, 0x1b, 15},
+ {2, 0x1a, 16},
+ {9, 0x1a, 16},
+ {23, 0x1a, 16},
+ {40, 0x1b, 16},
+ {2, 0x1a, 17},
+ {9, 0x1a, 17},
+ {23, 0x1a, 17},
+ {40, 0x1b, 17},
+ {2, 0x1a, 18},
+ {9, 0x1a, 18},
+ {23, 0x1a, 18},
+ {40, 0x1b, 18},
+ },
+ /* 236 */
+ {
+ {3, 0x1a, 15},
+ {6, 0x1a, 15},
+ {10, 0x1a, 15},
+ {15, 0x1a, 15},
+ {24, 0x1a, 15},
+ {31, 0x1a, 15},
+ {41, 0x1a, 15},
+ {56, 0x1b, 15},
+ {3, 0x1a, 16},
+ {6, 0x1a, 16},
+ {10, 0x1a, 16},
+ {15, 0x1a, 16},
+ {24, 0x1a, 16},
+ {31, 0x1a, 16},
+ {41, 0x1a, 16},
+ {56, 0x1b, 16},
+ },
+ /* 237 */
+ {
+ {3, 0x1a, 17},
+ {6, 0x1a, 17},
+ {10, 0x1a, 17},
+ {15, 0x1a, 17},
+ {24, 0x1a, 17},
+ {31, 0x1a, 17},
+ {41, 0x1a, 17},
+ {56, 0x1b, 17},
+ {3, 0x1a, 18},
+ {6, 0x1a, 18},
+ {10, 0x1a, 18},
+ {15, 0x1a, 18},
+ {24, 0x1a, 18},
+ {31, 0x1a, 18},
+ {41, 0x1a, 18},
+ {56, 0x1b, 18},
+ },
+ /* 238 */
+ {
+ {0, 0x1b, 19},
+ {0, 0x1b, 20},
+ {0, 0x1b, 21},
+ {0, 0x1b, 23},
+ {0, 0x1b, 24},
+ {0, 0x1b, 25},
+ {0, 0x1b, 26},
+ {0, 0x1b, 27},
+ {0, 0x1b, 28},
+ {0, 0x1b, 29},
+ {0, 0x1b, 30},
+ {0, 0x1b, 31},
+ {0, 0x1b, 127},
+ {0, 0x0b, 220},
+ {0, 0x0b, 249},
+ {253, 0x00, 0},
+ },
+ /* 239 */
+ {
+ {1, 0x1a, 19},
+ {22, 0x1b, 19},
+ {1, 0x1a, 20},
+ {22, 0x1b, 20},
+ {1, 0x1a, 21},
+ {22, 0x1b, 21},
+ {1, 0x1a, 23},
+ {22, 0x1b, 23},
+ {1, 0x1a, 24},
+ {22, 0x1b, 24},
+ {1, 0x1a, 25},
+ {22, 0x1b, 25},
+ {1, 0x1a, 26},
+ {22, 0x1b, 26},
+ {1, 0x1a, 27},
+ {22, 0x1b, 27},
+ },
+ /* 240 */
+ {
+ {2, 0x1a, 19},
+ {9, 0x1a, 19},
+ {23, 0x1a, 19},
+ {40, 0x1b, 19},
+ {2, 0x1a, 20},
+ {9, 0x1a, 20},
+ {23, 0x1a, 20},
+ {40, 0x1b, 20},
+ {2, 0x1a, 21},
+ {9, 0x1a, 21},
+ {23, 0x1a, 21},
+ {40, 0x1b, 21},
+ {2, 0x1a, 23},
+ {9, 0x1a, 23},
+ {23, 0x1a, 23},
+ {40, 0x1b, 23},
+ },
+ /* 241 */
+ {
+ {3, 0x1a, 19},
+ {6, 0x1a, 19},
+ {10, 0x1a, 19},
+ {15, 0x1a, 19},
+ {24, 0x1a, 19},
+ {31, 0x1a, 19},
+ {41, 0x1a, 19},
+ {56, 0x1b, 19},
+ {3, 0x1a, 20},
+ {6, 0x1a, 20},
+ {10, 0x1a, 20},
+ {15, 0x1a, 20},
+ {24, 0x1a, 20},
+ {31, 0x1a, 20},
+ {41, 0x1a, 20},
+ {56, 0x1b, 20},
+ },
+ /* 242 */
+ {
+ {3, 0x1a, 21},
+ {6, 0x1a, 21},
+ {10, 0x1a, 21},
+ {15, 0x1a, 21},
+ {24, 0x1a, 21},
+ {31, 0x1a, 21},
+ {41, 0x1a, 21},
+ {56, 0x1b, 21},
+ {3, 0x1a, 23},
+ {6, 0x1a, 23},
+ {10, 0x1a, 23},
+ {15, 0x1a, 23},
+ {24, 0x1a, 23},
+ {31, 0x1a, 23},
+ {41, 0x1a, 23},
+ {56, 0x1b, 23},
+ },
+ /* 243 */
+ {
+ {2, 0x1a, 24},
+ {9, 0x1a, 24},
+ {23, 0x1a, 24},
+ {40, 0x1b, 24},
+ {2, 0x1a, 25},
+ {9, 0x1a, 25},
+ {23, 0x1a, 25},
+ {40, 0x1b, 25},
+ {2, 0x1a, 26},
+ {9, 0x1a, 26},
+ {23, 0x1a, 26},
+ {40, 0x1b, 26},
+ {2, 0x1a, 27},
+ {9, 0x1a, 27},
+ {23, 0x1a, 27},
+ {40, 0x1b, 27},
+ },
+ /* 244 */
+ {
+ {3, 0x1a, 24},
+ {6, 0x1a, 24},
+ {10, 0x1a, 24},
+ {15, 0x1a, 24},
+ {24, 0x1a, 24},
+ {31, 0x1a, 24},
+ {41, 0x1a, 24},
+ {56, 0x1b, 24},
+ {3, 0x1a, 25},
+ {6, 0x1a, 25},
+ {10, 0x1a, 25},
+ {15, 0x1a, 25},
+ {24, 0x1a, 25},
+ {31, 0x1a, 25},
+ {41, 0x1a, 25},
+ {56, 0x1b, 25},
+ },
+ /* 245 */
+ {
+ {3, 0x1a, 26},
+ {6, 0x1a, 26},
+ {10, 0x1a, 26},
+ {15, 0x1a, 26},
+ {24, 0x1a, 26},
+ {31, 0x1a, 26},
+ {41, 0x1a, 26},
+ {56, 0x1b, 26},
+ {3, 0x1a, 27},
+ {6, 0x1a, 27},
+ {10, 0x1a, 27},
+ {15, 0x1a, 27},
+ {24, 0x1a, 27},
+ {31, 0x1a, 27},
+ {41, 0x1a, 27},
+ {56, 0x1b, 27},
+ },
+ /* 246 */
+ {
+ {1, 0x1a, 28},
+ {22, 0x1b, 28},
+ {1, 0x1a, 29},
+ {22, 0x1b, 29},
+ {1, 0x1a, 30},
+ {22, 0x1b, 30},
+ {1, 0x1a, 31},
+ {22, 0x1b, 31},
+ {1, 0x1a, 127},
+ {22, 0x1b, 127},
+ {1, 0x0a, 220},
+ {22, 0x0b, 220},
+ {1, 0x0a, 249},
+ {22, 0x0b, 249},
+ {254, 0x00, 0},
+ {255, 0x00, 0},
+ },
+ /* 247 */
+ {
+ {2, 0x1a, 28},
+ {9, 0x1a, 28},
+ {23, 0x1a, 28},
+ {40, 0x1b, 28},
+ {2, 0x1a, 29},
+ {9, 0x1a, 29},
+ {23, 0x1a, 29},
+ {40, 0x1b, 29},
+ {2, 0x1a, 30},
+ {9, 0x1a, 30},
+ {23, 0x1a, 30},
+ {40, 0x1b, 30},
+ {2, 0x1a, 31},
+ {9, 0x1a, 31},
+ {23, 0x1a, 31},
+ {40, 0x1b, 31},
+ },
+ /* 248 */
+ {
+ {3, 0x1a, 28},
+ {6, 0x1a, 28},
+ {10, 0x1a, 28},
+ {15, 0x1a, 28},
+ {24, 0x1a, 28},
+ {31, 0x1a, 28},
+ {41, 0x1a, 28},
+ {56, 0x1b, 28},
+ {3, 0x1a, 29},
+ {6, 0x1a, 29},
+ {10, 0x1a, 29},
+ {15, 0x1a, 29},
+ {24, 0x1a, 29},
+ {31, 0x1a, 29},
+ {41, 0x1a, 29},
+ {56, 0x1b, 29},
+ },
+ /* 249 */
+ {
+ {3, 0x1a, 30},
+ {6, 0x1a, 30},
+ {10, 0x1a, 30},
+ {15, 0x1a, 30},
+ {24, 0x1a, 30},
+ {31, 0x1a, 30},
+ {41, 0x1a, 30},
+ {56, 0x1b, 30},
+ {3, 0x1a, 31},
+ {6, 0x1a, 31},
+ {10, 0x1a, 31},
+ {15, 0x1a, 31},
+ {24, 0x1a, 31},
+ {31, 0x1a, 31},
+ {41, 0x1a, 31},
+ {56, 0x1b, 31},
+ },
+ /* 250 */
+ {
+ {2, 0x1a, 127},
+ {9, 0x1a, 127},
+ {23, 0x1a, 127},
+ {40, 0x1b, 127},
+ {2, 0x0a, 220},
+ {9, 0x0a, 220},
+ {23, 0x0a, 220},
+ {40, 0x0b, 220},
+ {2, 0x0a, 249},
+ {9, 0x0a, 249},
+ {23, 0x0a, 249},
+ {40, 0x0b, 249},
+ {0, 0x1b, 10},
+ {0, 0x1b, 13},
+ {0, 0x1b, 22},
+ {0, 0x04, 0},
+ },
+ /* 251 */
+ {
+ {3, 0x1a, 127},
+ {6, 0x1a, 127},
+ {10, 0x1a, 127},
+ {15, 0x1a, 127},
+ {24, 0x1a, 127},
+ {31, 0x1a, 127},
+ {41, 0x1a, 127},
+ {56, 0x1b, 127},
+ {3, 0x0a, 220},
+ {6, 0x0a, 220},
+ {10, 0x0a, 220},
+ {15, 0x0a, 220},
+ {24, 0x0a, 220},
+ {31, 0x0a, 220},
+ {41, 0x0a, 220},
+ {56, 0x0b, 220},
+ },
+ /* 252 */
+ {
+ {3, 0x0a, 249},
+ {6, 0x0a, 249},
+ {10, 0x0a, 249},
+ {15, 0x0a, 249},
+ {24, 0x0a, 249},
+ {31, 0x0a, 249},
+ {41, 0x0a, 249},
+ {56, 0x0b, 249},
+ {1, 0x1a, 10},
+ {22, 0x1b, 10},
+ {1, 0x1a, 13},
+ {22, 0x1b, 13},
+ {1, 0x1a, 22},
+ {22, 0x1b, 22},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ },
+ /* 253 */
+ {
+ {2, 0x1a, 10},
+ {9, 0x1a, 10},
+ {23, 0x1a, 10},
+ {40, 0x1b, 10},
+ {2, 0x1a, 13},
+ {9, 0x1a, 13},
+ {23, 0x1a, 13},
+ {40, 0x1b, 13},
+ {2, 0x1a, 22},
+ {9, 0x1a, 22},
+ {23, 0x1a, 22},
+ {40, 0x1b, 22},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ },
+ /* 254 */
+ {
+ {3, 0x1a, 10},
+ {6, 0x1a, 10},
+ {10, 0x1a, 10},
+ {15, 0x1a, 10},
+ {24, 0x1a, 10},
+ {31, 0x1a, 10},
+ {41, 0x1a, 10},
+ {56, 0x1b, 10},
+ {3, 0x1a, 13},
+ {6, 0x1a, 13},
+ {10, 0x1a, 13},
+ {15, 0x1a, 13},
+ {24, 0x1a, 13},
+ {31, 0x1a, 13},
+ {41, 0x1a, 13},
+ {56, 0x1b, 13},
+ },
+ /* 255 */
+ {
+ {3, 0x1a, 22},
+ {6, 0x1a, 22},
+ {10, 0x1a, 22},
+ {15, 0x1a, 22},
+ {24, 0x1a, 22},
+ {31, 0x1a, 22},
+ {41, 0x1a, 22},
+ {56, 0x1b, 22},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ {0, 0x04, 0},
+ },
+};
diff --git a/web/server/h2o/libh2o/lib/http2/hpack_static_table.h b/web/server/h2o/libh2o/lib/http2/hpack_static_table.h
new file mode 100644
index 000000000..4c1243103
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/hpack_static_table.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the &quot;Software&quot;), 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 &quot;AS IS&quot;, 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.
+ */
+
+/* automatically generated by tokens.pl */
+
+static const struct st_h2o_hpack_static_table_entry_t h2o_hpack_static_table[61] = {
+ { H2O_TOKEN_AUTHORITY, { H2O_STRLIT("") } },
+ { H2O_TOKEN_METHOD, { H2O_STRLIT("GET") } },
+ { H2O_TOKEN_METHOD, { H2O_STRLIT("POST") } },
+ { H2O_TOKEN_PATH, { H2O_STRLIT("/") } },
+ { H2O_TOKEN_PATH, { H2O_STRLIT("/index.html") } },
+ { H2O_TOKEN_SCHEME, { H2O_STRLIT("http") } },
+ { H2O_TOKEN_SCHEME, { H2O_STRLIT("https") } },
+ { H2O_TOKEN_STATUS, { H2O_STRLIT("200") } },
+ { H2O_TOKEN_STATUS, { H2O_STRLIT("204") } },
+ { H2O_TOKEN_STATUS, { H2O_STRLIT("206") } },
+ { H2O_TOKEN_STATUS, { H2O_STRLIT("304") } },
+ { H2O_TOKEN_STATUS, { H2O_STRLIT("400") } },
+ { H2O_TOKEN_STATUS, { H2O_STRLIT("404") } },
+ { H2O_TOKEN_STATUS, { H2O_STRLIT("500") } },
+ { H2O_TOKEN_ACCEPT_CHARSET, { H2O_STRLIT("") } },
+ { H2O_TOKEN_ACCEPT_ENCODING, { H2O_STRLIT("gzip, deflate") } },
+ { H2O_TOKEN_ACCEPT_LANGUAGE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_ACCEPT_RANGES, { H2O_STRLIT("") } },
+ { H2O_TOKEN_ACCEPT, { H2O_STRLIT("") } },
+ { H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN, { H2O_STRLIT("") } },
+ { H2O_TOKEN_AGE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_ALLOW, { H2O_STRLIT("") } },
+ { H2O_TOKEN_AUTHORIZATION, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CACHE_CONTROL, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CONTENT_DISPOSITION, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CONTENT_ENCODING, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CONTENT_LANGUAGE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CONTENT_LENGTH, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CONTENT_LOCATION, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CONTENT_RANGE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_CONTENT_TYPE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_COOKIE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_DATE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_ETAG, { H2O_STRLIT("") } },
+ { H2O_TOKEN_EXPECT, { H2O_STRLIT("") } },
+ { H2O_TOKEN_EXPIRES, { H2O_STRLIT("") } },
+ { H2O_TOKEN_FROM, { H2O_STRLIT("") } },
+ { H2O_TOKEN_HOST, { H2O_STRLIT("") } },
+ { H2O_TOKEN_IF_MATCH, { H2O_STRLIT("") } },
+ { H2O_TOKEN_IF_MODIFIED_SINCE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_IF_NONE_MATCH, { H2O_STRLIT("") } },
+ { H2O_TOKEN_IF_RANGE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_IF_UNMODIFIED_SINCE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_LAST_MODIFIED, { H2O_STRLIT("") } },
+ { H2O_TOKEN_LINK, { H2O_STRLIT("") } },
+ { H2O_TOKEN_LOCATION, { H2O_STRLIT("") } },
+ { H2O_TOKEN_MAX_FORWARDS, { H2O_STRLIT("") } },
+ { H2O_TOKEN_PROXY_AUTHENTICATE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_PROXY_AUTHORIZATION, { H2O_STRLIT("") } },
+ { H2O_TOKEN_RANGE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_REFERER, { H2O_STRLIT("") } },
+ { H2O_TOKEN_REFRESH, { H2O_STRLIT("") } },
+ { H2O_TOKEN_RETRY_AFTER, { H2O_STRLIT("") } },
+ { H2O_TOKEN_SERVER, { H2O_STRLIT("") } },
+ { H2O_TOKEN_SET_COOKIE, { H2O_STRLIT("") } },
+ { H2O_TOKEN_STRICT_TRANSPORT_SECURITY, { H2O_STRLIT("") } },
+ { H2O_TOKEN_TRANSFER_ENCODING, { H2O_STRLIT("") } },
+ { H2O_TOKEN_USER_AGENT, { H2O_STRLIT("") } },
+ { H2O_TOKEN_VARY, { H2O_STRLIT("") } },
+ { H2O_TOKEN_VIA, { H2O_STRLIT("") } },
+ { H2O_TOKEN_WWW_AUTHENTICATE, { H2O_STRLIT("") } }
+};
diff --git a/web/server/h2o/libh2o/lib/http2/http2_debug_state.c b/web/server/h2o/libh2o/lib/http2/http2_debug_state.c
new file mode 100644
index 000000000..3ef8de37f
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/http2_debug_state.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2016 DeNA Co., Ltd., Ichito Nagata
+ *
+ * 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 <inttypes.h>
+#include "h2o.h"
+#include "h2o/http2.h"
+#include "h2o/http2_internal.h"
+
+static const char *debug_state_string_open = "OPEN";
+static const char *debug_state_string_half_closed_remote = "HALF_CLOSED_REMOTE";
+static const char *debug_state_string_reserved_local = "RESERVED_LOCAL";
+
+static const char *get_debug_state_string(h2o_http2_stream_t *stream)
+{
+ if (h2o_http2_stream_is_push(stream->stream_id)) {
+ switch (stream->state) {
+ case H2O_HTTP2_STREAM_STATE_RECV_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_RECV_BODY:
+ case H2O_HTTP2_STREAM_STATE_REQ_PENDING:
+ return debug_state_string_reserved_local;
+ case H2O_HTTP2_STREAM_STATE_SEND_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL:
+ return debug_state_string_half_closed_remote;
+ case H2O_HTTP2_STREAM_STATE_IDLE:
+ case H2O_HTTP2_STREAM_STATE_END_STREAM:
+ return NULL;
+ }
+ } else {
+ switch (stream->state) {
+ case H2O_HTTP2_STREAM_STATE_RECV_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_RECV_BODY:
+ return debug_state_string_open;
+ case H2O_HTTP2_STREAM_STATE_REQ_PENDING:
+ case H2O_HTTP2_STREAM_STATE_SEND_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL:
+ return debug_state_string_half_closed_remote;
+ case H2O_HTTP2_STREAM_STATE_IDLE:
+ case H2O_HTTP2_STREAM_STATE_END_STREAM:
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+__attribute__((format(printf, 3, 4))) static void append_chunk(h2o_mem_pool_t *pool, h2o_iovec_vector_t *chunks, const char *fmt,
+ ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ int size = vsnprintf(NULL, 0, fmt, args);
+ va_end(args);
+
+ assert(size > 0);
+
+ h2o_iovec_t v;
+ v.base = h2o_mem_alloc_pool(pool, size + 1);
+
+ va_start(args, fmt);
+ v.len = vsnprintf(v.base, size + 1, fmt, args);
+ va_end(args);
+
+ h2o_vector_reserve(pool, chunks, chunks->size + 1);
+ chunks->entries[chunks->size++] = v;
+}
+
+static void append_header_table_chunks(h2o_mem_pool_t *pool, h2o_iovec_vector_t *chunks, h2o_hpack_header_table_t *header_table)
+{
+ int i;
+ for (i = 0; i < header_table->num_entries; i++) {
+ h2o_hpack_header_table_entry_t *entry = h2o_hpack_header_table_get(header_table, i);
+ append_chunk(pool, chunks, "\n"
+ " [ \"%.*s\", \"%.*s\" ],",
+ (int)entry->name->len, entry->name->base, (int)entry->value->len, entry->value->base);
+ }
+
+ if (i > 0) {
+ // remove the last commna
+ --chunks->entries[chunks->size - 1].len;
+ }
+}
+
+h2o_http2_debug_state_t *h2o_http2_get_debug_state(h2o_req_t *req, int hpack_enabled)
+{
+ h2o_http2_conn_t *conn = (h2o_http2_conn_t *)req->conn;
+ h2o_http2_debug_state_t *state = h2o_mem_alloc_pool(&req->pool, sizeof(*state));
+ *state = (h2o_http2_debug_state_t){{NULL}};
+
+ state->conn_flow_in = conn->_write.window._avail;
+ state->conn_flow_out = conn->_write.window._avail;
+
+ append_chunk(&req->pool, &state->json, "{\n"
+ " \"version\": \"draft-01\",\n"
+ " \"settings\": {\n"
+ " \"SETTINGS_HEADER_TABLE_SIZE\": %" PRIu32 ",\n"
+ " \"SETTINGS_ENABLE_PUSH\": %" PRIu32 ",\n"
+ " \"SETTINGS_MAX_CONCURRENT_STREAMS\": %" PRIu32 ",\n"
+ " \"SETTINGS_INITIAL_WINDOW_SIZE\": %" PRIu32 ",\n"
+ " \"SETTINGS_MAX_FRAME_SIZE\": %" PRIu32 "\n"
+ " },\n"
+ " \"peerSettings\": {\n"
+ " \"SETTINGS_HEADER_TABLE_SIZE\": %" PRIu32 ",\n"
+ " \"SETTINGS_ENABLE_PUSH\": %" PRIu32 ",\n"
+ " \"SETTINGS_MAX_CONCURRENT_STREAMS\": %" PRIu32 ",\n"
+ " \"SETTINGS_INITIAL_WINDOW_SIZE\": %" PRIu32 ",\n"
+ " \"SETTINGS_MAX_FRAME_SIZE\": %" PRIu32 "\n"
+ " },\n"
+ " \"connFlowIn\": %zd,\n"
+ " \"connFlowOut\": %zd,\n"
+ " \"streams\": {",
+ H2O_HTTP2_SETTINGS_HOST.header_table_size, H2O_HTTP2_SETTINGS_HOST.enable_push,
+ H2O_HTTP2_SETTINGS_HOST.max_concurrent_streams, H2O_HTTP2_SETTINGS_HOST.initial_window_size,
+ H2O_HTTP2_SETTINGS_HOST.max_frame_size, conn->peer_settings.header_table_size, conn->peer_settings.enable_push,
+ conn->peer_settings.max_concurrent_streams, conn->peer_settings.initial_window_size,
+ conn->peer_settings.max_frame_size, conn->_input_window._avail, conn->_write.window._avail);
+
+ /* encode streams */
+ {
+ h2o_http2_stream_t *stream;
+ kh_foreach_value(conn->streams, stream, {
+ const char *state_string = get_debug_state_string(stream);
+ if (state_string == NULL)
+ continue;
+
+ append_chunk(&req->pool, &state->json, "\n"
+ " \"%" PRIu32 "\": {\n"
+ " \"state\": \"%s\",\n"
+ " \"flowIn\": %zd,\n"
+ " \"flowOut\": %zd,\n"
+ " \"dataIn\": %zu,\n"
+ " \"dataOut\": %zu,\n"
+ " \"created\": %" PRIu64 "\n"
+ " },",
+ stream->stream_id, state_string, stream->input_window._avail, stream->output_window._avail,
+ (stream->_req_body == NULL ? 0 : stream->_req_body->size), stream->req.bytes_sent,
+ (uint64_t)stream->req.timestamps.request_begin_at.tv_sec);
+ });
+
+ if (conn->streams->size > 0) {
+ // remove the last commna
+ --state->json.entries[state->json.size - 1].len;
+ }
+ }
+
+ append_chunk(&req->pool, &state->json, "\n"
+ " }");
+
+ if (hpack_enabled) {
+ /* encode inbound header table */
+ append_chunk(&req->pool, &state->json, ",\n"
+ " \"hpack\": {\n"
+ " \"inboundTableSize\": %zd,\n"
+ " \"inboundDynamicHeaderTable\": [",
+ conn->_input_header_table.num_entries);
+ append_header_table_chunks(&req->pool, &state->json, &conn->_input_header_table);
+
+ /* encode outbound header table */
+ append_chunk(&req->pool, &state->json, "\n"
+ " ],\n"
+ " \"outboundTableSize\": %zd,\n"
+ " \"outboundDynamicHeaderTable\": [",
+ conn->_output_header_table.num_entries);
+ append_header_table_chunks(&req->pool, &state->json, &conn->_output_header_table);
+
+ append_chunk(&req->pool, &state->json, "\n"
+ " ]\n"
+ " }");
+ }
+
+ append_chunk(&req->pool, &state->json, "\n"
+ "}\n");
+
+ return state;
+}
diff --git a/web/server/h2o/libh2o/lib/http2/scheduler.c b/web/server/h2o/libh2o/lib/http2/scheduler.c
new file mode 100644
index 000000000..0ea7e4591
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/scheduler.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2015 DeNA Co., Ltd.
+ *
+ * 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 "h2o.h"
+#include "h2o/http2_scheduler.h"
+
+struct st_h2o_http2_scheduler_queue_t {
+ uint64_t bits;
+ size_t offset;
+ h2o_linklist_t anchors[64];
+ h2o_linklist_t anchor257;
+};
+
+static void queue_init(h2o_http2_scheduler_queue_t *queue)
+{
+ size_t i;
+ queue->bits = 0;
+ queue->offset = 0;
+ for (i = 0; i != sizeof(queue->anchors) / sizeof(queue->anchors[0]); ++i)
+ h2o_linklist_init_anchor(queue->anchors + i);
+ h2o_linklist_init_anchor(&queue->anchor257);
+}
+
+static int queue_is_empty(h2o_http2_scheduler_queue_t *queue)
+{
+ return queue->bits == 0 && h2o_linklist_is_empty(&queue->anchor257);
+}
+
+static void queue_set(h2o_http2_scheduler_queue_t *queue, h2o_http2_scheduler_queue_node_t *node, uint16_t weight)
+{
+ /* holds 257 entries of offsets (multiplied by 65536) where nodes with weights between 1..257 should go into
+ * each entry (expect for weight=256) is calculated as: round(N / weight), where N is adjusted so that the
+ * value would become 63*65536 for weight=0.
+ * weight=257 is used internally to send data before any of the streams being pulled, and therefore has the offset set to zero.
+ */
+ static const unsigned OFFSET_TABLE[] = {
+ 4128768, 2064384, 1376256, 1032192, 825754, 688128, 589824, 516096, 458752, 412877, 375343, 344064, 317598, 294912, 275251,
+ 258048, 242869, 229376, 217304, 206438, 196608, 187671, 179512, 172032, 165151, 158799, 152917, 147456, 142371, 137626,
+ 133186, 129024, 125114, 121434, 117965, 114688, 111588, 108652, 105866, 103219, 100702, 98304, 96018, 93836, 91750,
+ 89756, 87846, 86016, 84261, 82575, 80956, 79399, 77901, 76459, 75069, 73728, 72435, 71186, 69979, 68813,
+ 67685, 66593, 65536, 64512, 63520, 62557, 61623, 60717, 59837, 58982, 58152, 57344, 56558, 55794, 55050,
+ 54326, 53620, 52933, 52263, 51610, 50972, 50351, 49744, 49152, 48574, 48009, 47457, 46918, 46391, 45875,
+ 45371, 44878, 44395, 43923, 43461, 43008, 42565, 42130, 41705, 41288, 40879, 40478, 40085, 39700, 39322,
+ 38951, 38587, 38229, 37879, 37534, 37196, 36864, 36538, 36217, 35902, 35593, 35289, 34990, 34696, 34406,
+ 34122, 33842, 33567, 33297, 33030, 32768, 32510, 32256, 32006, 31760, 31517, 31279, 31043, 30812, 30583,
+ 30359, 30137, 29919, 29703, 29491, 29282, 29076, 28873, 28672, 28474, 28279, 28087, 27897, 27710, 27525,
+ 27343, 27163, 26985, 26810, 26637, 26466, 26298, 26131, 25967, 25805, 25645, 25486, 25330, 25175, 25023,
+ 24872, 24723, 24576, 24431, 24287, 24145, 24004, 23866, 23729, 23593, 23459, 23326, 23195, 23066, 22938,
+ 22811, 22686, 22562, 22439, 22318, 22198, 22079, 21962, 21845, 21730, 21617, 21504, 21393, 21282, 21173,
+ 21065, 20958, 20852, 20748, 20644, 20541, 20439, 20339, 20239, 20140, 20043, 19946, 19850, 19755, 19661,
+ 19568, 19475, 19384, 19293, 19204, 19115, 19027, 18939, 18853, 18767, 18682, 18598, 18515, 18432, 18350,
+ 18269, 18188, 18109, 18030, 17951, 17873, 17796, 17720, 17644, 17569, 17495, 17421, 17348, 17275, 17203,
+ 17132, 17061, 16991, 16921, 16852, 16784, 16716, 16648, 16581, 16515, 16449, 16384, 16319, 16255, 16191,
+ 16128, 0};
+
+ assert(!h2o_linklist_is_linked(&node->_link));
+
+ if (weight > 256) {
+
+ h2o_linklist_insert(&queue->anchor257, &node->_link);
+
+ } else {
+
+ assert(1 <= weight);
+
+ size_t offset = OFFSET_TABLE[weight - 1] + node->_deficit;
+ node->_deficit = offset % 65536;
+ offset = offset / 65536;
+
+ queue->bits |= 1ULL << (sizeof(queue->bits) * 8 - 1 - offset);
+ h2o_linklist_insert(queue->anchors + (queue->offset + offset) % (sizeof(queue->anchors) / sizeof(queue->anchors[0])),
+ &node->_link);
+ }
+}
+
+static void queue_unset(h2o_http2_scheduler_queue_node_t *node)
+{
+ assert(h2o_linklist_is_linked(&node->_link));
+ h2o_linklist_unlink(&node->_link);
+}
+
+static h2o_http2_scheduler_queue_node_t *queue_pop(h2o_http2_scheduler_queue_t *queue)
+{
+ if (!h2o_linklist_is_empty(&queue->anchor257)) {
+ h2o_http2_scheduler_queue_node_t *node =
+ H2O_STRUCT_FROM_MEMBER(h2o_http2_scheduler_queue_node_t, _link, queue->anchor257.next);
+ h2o_linklist_unlink(&node->_link);
+ return node;
+ }
+
+ while (queue->bits != 0) {
+ int zeroes = __builtin_clzll(queue->bits);
+ queue->bits <<= zeroes;
+ queue->offset = (queue->offset + zeroes) % (sizeof(queue->anchors) / sizeof(queue->anchors[0]));
+ if (!h2o_linklist_is_empty(queue->anchors + queue->offset)) {
+ h2o_http2_scheduler_queue_node_t *node =
+ H2O_STRUCT_FROM_MEMBER(h2o_http2_scheduler_queue_node_t, _link, queue->anchors[queue->offset].next);
+ h2o_linklist_unlink(&node->_link);
+ if (h2o_linklist_is_empty(queue->anchors + queue->offset))
+ queue->bits &= (1ULL << (sizeof(queue->bits) * 8 - 1)) - 1;
+ return node;
+ }
+ queue->bits &= (1ULL << (sizeof(queue->bits) * 8 - 1)) - 1;
+ }
+ return NULL;
+}
+
+static void init_node(h2o_http2_scheduler_node_t *node, h2o_http2_scheduler_node_t *parent)
+{
+ *node = (h2o_http2_scheduler_node_t){parent};
+ h2o_linklist_init_anchor(&node->_all_refs);
+}
+
+static h2o_http2_scheduler_queue_t *get_queue(h2o_http2_scheduler_node_t *node)
+{
+ if (node->_queue == NULL) {
+ node->_queue = h2o_mem_alloc(sizeof(*node->_queue));
+ queue_init(node->_queue);
+ }
+ return node->_queue;
+}
+
+static void incr_active_cnt(h2o_http2_scheduler_node_t *node)
+{
+ h2o_http2_scheduler_openref_t *ref;
+
+ /* do nothing if node is the root */
+ if (node->_parent == NULL)
+ return;
+
+ ref = (h2o_http2_scheduler_openref_t *)node;
+ if (++ref->_active_cnt != 1)
+ return;
+ /* just changed to active */
+ queue_set(get_queue(ref->node._parent), &ref->_queue_node, ref->weight);
+ /* delegate the change towards root */
+ incr_active_cnt(ref->node._parent);
+}
+
+static void decr_active_cnt(h2o_http2_scheduler_node_t *node)
+{
+ h2o_http2_scheduler_openref_t *ref;
+
+ /* do notnig if node is the root */
+ if (node->_parent == NULL)
+ return;
+
+ ref = (h2o_http2_scheduler_openref_t *)node;
+ if (--ref->_active_cnt != 0)
+ return;
+ /* just changed to inactive */
+ queue_unset(&ref->_queue_node);
+ /* delegate the change towards root */
+ decr_active_cnt(ref->node._parent);
+}
+
+static void convert_to_exclusive(h2o_http2_scheduler_node_t *parent, h2o_http2_scheduler_openref_t *added)
+{
+ while (!h2o_linklist_is_empty(&parent->_all_refs)) {
+ h2o_http2_scheduler_openref_t *child_ref =
+ H2O_STRUCT_FROM_MEMBER(h2o_http2_scheduler_openref_t, _all_link, parent->_all_refs.next);
+ if (child_ref == added) {
+ /* precond: the added node should exist as the last item within parent */
+ assert(parent->_all_refs.prev == &added->_all_link);
+ break;
+ }
+ h2o_http2_scheduler_rebind(child_ref, &added->node, h2o_http2_scheduler_get_weight(child_ref), 0);
+ }
+}
+
+void h2o_http2_scheduler_open(h2o_http2_scheduler_openref_t *ref, h2o_http2_scheduler_node_t *parent, uint16_t weight,
+ int exclusive)
+{
+ init_node(&ref->node, parent);
+ ref->weight = weight;
+ ref->_all_link = (h2o_linklist_t){NULL};
+ ref->_active_cnt = 0;
+ ref->_self_is_active = 0;
+ ref->_queue_node = (h2o_http2_scheduler_queue_node_t){{NULL}};
+
+ h2o_linklist_insert(&parent->_all_refs, &ref->_all_link);
+
+ if (exclusive)
+ convert_to_exclusive(parent, ref);
+}
+
+void h2o_http2_scheduler_close(h2o_http2_scheduler_openref_t *ref)
+{
+ assert(h2o_http2_scheduler_is_open(ref));
+
+ /* move dependents to parent */
+ if (!h2o_linklist_is_empty(&ref->node._all_refs)) {
+ /* proportionally distribute the weight to the children (draft-16 5.3.4) */
+ uint32_t total_weight = 0, factor;
+ h2o_linklist_t *link;
+ for (link = ref->node._all_refs.next; link != &ref->node._all_refs; link = link->next) {
+ h2o_http2_scheduler_openref_t *child_ref = H2O_STRUCT_FROM_MEMBER(h2o_http2_scheduler_openref_t, _all_link, link);
+ total_weight += child_ref->weight;
+ }
+ assert(total_weight != 0);
+ factor = ((uint32_t)ref->weight * 65536 + total_weight / 2) / total_weight;
+ do {
+ h2o_http2_scheduler_openref_t *child_ref =
+ H2O_STRUCT_FROM_MEMBER(h2o_http2_scheduler_openref_t, _all_link, ref->node._all_refs.next);
+ uint16_t weight = (child_ref->weight * factor / 32768 + 1) / 2;
+ if (weight < 1)
+ weight = 1;
+ else if (weight > 256)
+ weight = 256;
+ h2o_http2_scheduler_rebind(child_ref, ref->node._parent, weight, 0);
+ } while (!h2o_linklist_is_empty(&ref->node._all_refs));
+ }
+
+ free(ref->node._queue);
+ ref->node._queue = NULL;
+
+ /* detach self */
+ h2o_linklist_unlink(&ref->_all_link);
+ if (ref->_self_is_active) {
+ assert(ref->_active_cnt == 1);
+ queue_unset(&ref->_queue_node);
+ decr_active_cnt(ref->node._parent);
+ } else {
+ assert(ref->_active_cnt == 0);
+ }
+}
+
+static void do_rebind(h2o_http2_scheduler_openref_t *ref, h2o_http2_scheduler_node_t *new_parent, int exclusive)
+{
+ /* rebind _all_link */
+ h2o_linklist_unlink(&ref->_all_link);
+ h2o_linklist_insert(&new_parent->_all_refs, &ref->_all_link);
+ /* rebind to WRR (as well as adjust active_cnt) */
+ if (ref->_active_cnt != 0) {
+ queue_unset(&ref->_queue_node);
+ queue_set(get_queue(new_parent), &ref->_queue_node, ref->weight);
+ decr_active_cnt(ref->node._parent);
+ incr_active_cnt(new_parent);
+ }
+ /* update the backlinks */
+ ref->node._parent = new_parent;
+
+ if (exclusive)
+ convert_to_exclusive(new_parent, ref);
+}
+
+void h2o_http2_scheduler_rebind(h2o_http2_scheduler_openref_t *ref, h2o_http2_scheduler_node_t *new_parent, uint16_t weight,
+ int exclusive)
+{
+ assert(h2o_http2_scheduler_is_open(ref));
+ assert(&ref->node != new_parent);
+ assert(1 <= weight);
+ assert(weight <= 257);
+
+ /* do nothing if there'd be no change at all */
+ if (ref->node._parent == new_parent && ref->weight == weight && !exclusive)
+ return;
+
+ ref->weight = weight;
+
+ { /* if new_parent is dependent to ref, make new_parent a sibling of ref before applying the final transition (see draft-16
+ 5.3.3) */
+ h2o_http2_scheduler_node_t *t;
+ for (t = new_parent; t->_parent != NULL; t = t->_parent) {
+ if (t->_parent == &ref->node) {
+ /* quoting the spec: "The moved dependency retains its weight." */
+ h2o_http2_scheduler_openref_t *new_parent_ref = (void *)new_parent;
+ do_rebind(new_parent_ref, ref->node._parent, 0);
+ break;
+ }
+ }
+ }
+
+ do_rebind(ref, new_parent, exclusive);
+}
+
+void h2o_http2_scheduler_init(h2o_http2_scheduler_node_t *root)
+{
+ init_node(root, NULL);
+}
+
+void h2o_http2_scheduler_dispose(h2o_http2_scheduler_node_t *root)
+{
+ free(root->_queue);
+ root->_queue = NULL;
+}
+
+void h2o_http2_scheduler_activate(h2o_http2_scheduler_openref_t *ref)
+{
+ if (ref->_self_is_active)
+ return;
+ ref->_self_is_active = 1;
+ incr_active_cnt(&ref->node);
+}
+
+static int proceed(h2o_http2_scheduler_node_t *node, h2o_http2_scheduler_run_cb cb, void *cb_arg)
+{
+Redo:
+ if (node->_queue == NULL)
+ return 0;
+
+ h2o_http2_scheduler_queue_node_t *drr_node = queue_pop(node->_queue);
+ if (drr_node == NULL)
+ return 0;
+
+ h2o_http2_scheduler_openref_t *ref = H2O_STRUCT_FROM_MEMBER(h2o_http2_scheduler_openref_t, _queue_node, drr_node);
+
+ if (!ref->_self_is_active) {
+ /* run the children (manually-unrolled tail recursion) */
+ queue_set(node->_queue, &ref->_queue_node, ref->weight);
+ node = &ref->node;
+ goto Redo;
+ }
+ assert(ref->_active_cnt != 0);
+
+ /* call the callbacks */
+ int still_is_active, bail_out = cb(ref, &still_is_active, cb_arg);
+ if (still_is_active) {
+ queue_set(node->_queue, &ref->_queue_node, ref->weight);
+ } else {
+ ref->_self_is_active = 0;
+ if (--ref->_active_cnt != 0) {
+ queue_set(node->_queue, &ref->_queue_node, ref->weight);
+ } else if (ref->node._parent != NULL) {
+ decr_active_cnt(ref->node._parent);
+ }
+ }
+
+ return bail_out;
+}
+
+int h2o_http2_scheduler_run(h2o_http2_scheduler_node_t *root, h2o_http2_scheduler_run_cb cb, void *cb_arg)
+{
+ if (root->_queue != NULL) {
+ while (!queue_is_empty(root->_queue)) {
+ int bail_out = proceed(root, cb, cb_arg);
+ if (bail_out)
+ return bail_out;
+ }
+ }
+ return 0;
+}
+
+int h2o_http2_scheduler_is_active(h2o_http2_scheduler_node_t *root)
+{
+ return root->_queue != NULL && !queue_is_empty(root->_queue);
+}
diff --git a/web/server/h2o/libh2o/lib/http2/stream.c b/web/server/h2o/libh2o/lib/http2/stream.c
new file mode 100644
index 000000000..1dfe2c3a3
--- /dev/null
+++ b/web/server/h2o/libh2o/lib/http2/stream.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2014 DeNA Co., Ltd.
+ *
+ * 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 "h2o.h"
+#include "h2o/http2.h"
+#include "h2o/http2_internal.h"
+
+static void finalostream_start_pull(h2o_ostream_t *self, h2o_ostream_pull_cb cb);
+static void finalostream_send(h2o_ostream_t *self, h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state);
+
+static size_t sz_min(size_t x, size_t y)
+{
+ return x < y ? x : y;
+}
+
+h2o_http2_stream_t *h2o_http2_stream_open(h2o_http2_conn_t *conn, uint32_t stream_id, h2o_req_t *src_req,
+ const h2o_http2_priority_t *received_priority)
+{
+ h2o_http2_stream_t *stream = h2o_mem_alloc(sizeof(*stream));
+
+ /* init properties (other than req) */
+ memset(stream, 0, offsetof(h2o_http2_stream_t, req));
+ stream->stream_id = stream_id;
+ stream->_ostr_final.do_send = finalostream_send;
+ stream->_ostr_final.start_pull = finalostream_start_pull;
+ stream->state = H2O_HTTP2_STREAM_STATE_IDLE;
+ h2o_http2_window_init(&stream->output_window, &conn->peer_settings);
+ h2o_http2_window_init(&stream->input_window, &H2O_HTTP2_SETTINGS_HOST);
+ stream->received_priority = *received_priority;
+ stream->_expected_content_length = SIZE_MAX;
+
+ /* init request */
+ h2o_init_request(&stream->req, &conn->super, src_req);
+ stream->req.version = 0x200;
+ if (src_req != NULL)
+ memset(&stream->req.upgrade, 0, sizeof(stream->req.upgrade));
+ stream->req._ostr_top = &stream->_ostr_final;
+
+ h2o_http2_conn_register_stream(conn, stream);
+
+ ++conn->num_streams.priority.open;
+ stream->_num_streams_slot = &conn->num_streams.priority;
+
+ return stream;
+}
+
+void h2o_http2_stream_close(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ h2o_http2_conn_unregister_stream(conn, stream);
+ if (stream->_req_body != NULL)
+ h2o_buffer_dispose(&stream->_req_body);
+ if (stream->cache_digests != NULL)
+ h2o_cache_digests_destroy(stream->cache_digests);
+ h2o_dispose_request(&stream->req);
+ if (stream->stream_id == 1 && conn->_http1_req_input != NULL)
+ h2o_buffer_dispose(&conn->_http1_req_input);
+ free(stream);
+}
+
+void h2o_http2_stream_reset(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ switch (stream->state) {
+ case H2O_HTTP2_STREAM_STATE_IDLE:
+ case H2O_HTTP2_STREAM_STATE_RECV_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_RECV_BODY:
+ case H2O_HTTP2_STREAM_STATE_REQ_PENDING:
+ h2o_http2_stream_close(conn, stream);
+ break;
+ case H2O_HTTP2_STREAM_STATE_SEND_HEADERS:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY:
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL:
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_END_STREAM);
+ /* continues */
+ case H2O_HTTP2_STREAM_STATE_END_STREAM:
+ /* clear all the queued bufs, and close the connection in the callback */
+ stream->_data.size = 0;
+ if (h2o_linklist_is_linked(&stream->_refs.link)) {
+ /* will be closed in the callback */
+ } else {
+ h2o_http2_stream_close(conn, stream);
+ }
+ break;
+ }
+}
+
+static size_t calc_max_payload_size(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ ssize_t conn_max, stream_max;
+
+ if ((conn_max = h2o_http2_conn_get_buffer_window(conn)) <= 0)
+ return 0;
+ if ((stream_max = h2o_http2_window_get_window(&stream->output_window)) <= 0)
+ return 0;
+ return sz_min(sz_min(conn_max, stream_max), conn->peer_settings.max_frame_size);
+}
+
+static void commit_data_header(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_buffer_t **outbuf, size_t length,
+ h2o_send_state_t send_state)
+{
+ assert(outbuf != NULL);
+ /* send a DATA frame if there's data or the END_STREAM flag to send */
+ if (length || send_state == H2O_SEND_STATE_FINAL) {
+ h2o_http2_encode_frame_header((void *)((*outbuf)->bytes + (*outbuf)->size), length, H2O_HTTP2_FRAME_TYPE_DATA,
+ send_state == H2O_SEND_STATE_FINAL ? H2O_HTTP2_FRAME_FLAG_END_STREAM : 0, stream->stream_id);
+ h2o_http2_window_consume_window(&conn->_write.window, length);
+ h2o_http2_window_consume_window(&stream->output_window, length);
+ (*outbuf)->size += length + H2O_HTTP2_FRAME_HEADER_SIZE;
+ stream->req.bytes_sent += length;
+ }
+ /* send a RST_STREAM if there's an error */
+ if (send_state == H2O_SEND_STATE_ERROR) {
+ h2o_http2_encode_rst_stream_frame(outbuf, stream->stream_id, -H2O_HTTP2_ERROR_PROTOCOL);
+ }
+}
+
+static h2o_send_state_t send_data_pull(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ size_t max_payload_size;
+ h2o_iovec_t cbuf;
+ h2o_send_state_t send_state = H2O_SEND_STATE_IN_PROGRESS;
+
+ if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0)
+ goto Exit;
+ /* reserve buffer */
+ h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE + max_payload_size);
+ /* obtain content */
+ cbuf.base = conn->_write.buf->bytes + conn->_write.buf->size + H2O_HTTP2_FRAME_HEADER_SIZE;
+ cbuf.len = max_payload_size;
+ send_state = h2o_pull(&stream->req, stream->_pull_cb, &cbuf);
+ /* write the header */
+ commit_data_header(conn, stream, &conn->_write.buf, cbuf.len, send_state);
+
+Exit:
+ return send_state;
+}
+
+static h2o_iovec_t *send_data_push(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_iovec_t *bufs, size_t bufcnt,
+ h2o_send_state_t send_state)
+{
+ h2o_iovec_t dst;
+ size_t max_payload_size;
+
+ if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0)
+ goto Exit;
+
+ /* reserve buffer and point dst to the payload */
+ dst.base =
+ h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE + max_payload_size).base + H2O_HTTP2_FRAME_HEADER_SIZE;
+ dst.len = max_payload_size;
+
+ /* emit data */
+ while (bufcnt != 0) {
+ if (bufs->len != 0)
+ break;
+ ++bufs;
+ --bufcnt;
+ }
+ while (bufcnt != 0) {
+ size_t fill_size = sz_min(dst.len, bufs->len);
+ memcpy(dst.base, bufs->base, fill_size);
+ dst.base += fill_size;
+ dst.len -= fill_size;
+ bufs->base += fill_size;
+ bufs->len -= fill_size;
+ while (bufs->len == 0) {
+ ++bufs;
+ --bufcnt;
+ if (bufcnt == 0)
+ break;
+ }
+ if (dst.len == 0)
+ break;
+ }
+
+ /* commit the DATA frame if we have actually emitted payload */
+ if (dst.len != max_payload_size || !h2o_send_state_is_in_progress(send_state)) {
+ size_t payload_len = max_payload_size - dst.len;
+ if (bufcnt != 0) {
+ send_state = H2O_SEND_STATE_IN_PROGRESS;
+ }
+ commit_data_header(conn, stream, &conn->_write.buf, payload_len, send_state);
+ }
+
+Exit:
+ return bufs;
+}
+
+static int is_blocking_asset(h2o_req_t *req)
+{
+ if (req->res.mime_attr == NULL)
+ h2o_req_fill_mime_attributes(req);
+ return req->res.mime_attr->priority == H2O_MIME_ATTRIBUTE_PRIORITY_HIGHEST;
+}
+
+static int send_headers(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ h2o_timestamp_t ts;
+
+ h2o_get_timestamp(conn->super.ctx, &stream->req.pool, &ts);
+
+ /* cancel push with an error response */
+ if (h2o_http2_stream_is_push(stream->stream_id)) {
+ if (400 <= stream->req.res.status)
+ goto CancelPush;
+ if (stream->cache_digests != NULL) {
+ ssize_t etag_index = h2o_find_header(&stream->req.headers, H2O_TOKEN_ETAG, -1);
+ if (etag_index != -1) {
+ h2o_iovec_t url = h2o_concat(&stream->req.pool, stream->req.input.scheme->name, h2o_iovec_init(H2O_STRLIT("://")),
+ stream->req.input.authority, stream->req.input.path);
+ h2o_iovec_t *etag = &stream->req.headers.entries[etag_index].value;
+ if (h2o_cache_digests_lookup_by_url_and_etag(stream->cache_digests, url.base, url.len, etag->base, etag->len) ==
+ H2O_CACHE_DIGESTS_STATE_FRESH)
+ goto CancelPush;
+ }
+ }
+ }
+
+ /* reset casper cookie in case cache-digests exist */
+ if (stream->cache_digests != NULL && stream->req.hostconf->http2.casper.capacity_bits != 0) {
+ h2o_add_header(&stream->req.pool, &stream->req.res.headers, H2O_TOKEN_SET_COOKIE, NULL,
+ H2O_STRLIT("h2o_casper=; Path=/; Expires=Sat, 01 Jan 2000 00:00:00 GMT"));
+ }
+
+ /* CASPER */
+ if (conn->casper != NULL) {
+ /* update casper if necessary */
+ if (stream->req.hostconf->http2.casper.track_all_types || is_blocking_asset(&stream->req)) {
+ if (h2o_http2_casper_lookup(conn->casper, stream->req.path.base, stream->req.path.len, 1)) {
+ /* cancel if the pushed resource is already marked as cached */
+ if (h2o_http2_stream_is_push(stream->stream_id))
+ goto CancelPush;
+ }
+ }
+ if (stream->cache_digests != NULL)
+ goto SkipCookie;
+ /* browsers might ignore push responses, or they may process the responses in a different order than they were pushed.
+ * Therefore H2O tries to include casper cookie only in the last stream that may be received by the client, or when the
+ * value become stable; see also: https://github.com/h2o/h2o/issues/421
+ */
+ if (h2o_http2_stream_is_push(stream->stream_id)) {
+ if (!(conn->num_streams.pull.open == 0 && (conn->num_streams.push.half_closed - conn->num_streams.push.send_body) == 1))
+ goto SkipCookie;
+ } else {
+ if (conn->num_streams.push.half_closed - conn->num_streams.push.send_body != 0)
+ goto SkipCookie;
+ }
+ h2o_iovec_t cookie = h2o_http2_casper_get_cookie(conn->casper);
+ h2o_add_header(&stream->req.pool, &stream->req.res.headers, H2O_TOKEN_SET_COOKIE, NULL, cookie.base, cookie.len);
+ SkipCookie:;
+ }
+
+ if (h2o_http2_stream_is_push(stream->stream_id)) {
+ /* for push, send the push promise */
+ if (!stream->push.promise_sent)
+ h2o_http2_stream_send_push_promise(conn, stream);
+ /* send ASAP if it is a blocking asset (even in case of Firefox we can't wait 1RTT for it to reprioritize the asset) */
+ if (is_blocking_asset(&stream->req))
+ h2o_http2_scheduler_rebind(&stream->_refs.scheduler, &conn->scheduler, 257, 0);
+ } else {
+ /* raise the priority of asset files that block rendering to highest if the user-agent is _not_ using dependency-based
+ * prioritization (e.g. that of Firefox)
+ */
+ if (conn->num_streams.priority.open == 0 && stream->req.hostconf->http2.reprioritize_blocking_assets &&
+ h2o_http2_scheduler_get_parent(&stream->_refs.scheduler) == &conn->scheduler && is_blocking_asset(&stream->req))
+ h2o_http2_scheduler_rebind(&stream->_refs.scheduler, &conn->scheduler, 257, 0);
+ }
+
+ /* send HEADERS, as well as start sending body */
+ if (h2o_http2_stream_is_push(stream->stream_id))
+ h2o_add_header_by_str(&stream->req.pool, &stream->req.res.headers, H2O_STRLIT("x-http2-push"), 0, NULL,
+ H2O_STRLIT("pushed"));
+ h2o_hpack_flatten_response(&conn->_write.buf, &conn->_output_header_table, stream->stream_id,
+ conn->peer_settings.max_frame_size, &stream->req.res, &ts, &conn->super.ctx->globalconf->server_name,
+ stream->req.res.content_length);
+ h2o_http2_conn_request_write(conn);
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_SEND_BODY);
+
+ return 0;
+
+CancelPush:
+ h2o_add_header_by_str(&stream->req.pool, &stream->req.res.headers, H2O_STRLIT("x-http2-push"), 0, NULL,
+ H2O_STRLIT("cancelled"));
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_END_STREAM);
+ h2o_linklist_insert(&conn->_write.streams_to_proceed, &stream->_refs.link);
+ if (stream->push.promise_sent) {
+ h2o_http2_encode_rst_stream_frame(&conn->_write.buf, stream->stream_id, -H2O_HTTP2_ERROR_INTERNAL);
+ h2o_http2_conn_request_write(conn);
+ }
+ return -1;
+}
+
+void finalostream_start_pull(h2o_ostream_t *self, h2o_ostream_pull_cb cb)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, _ostr_final, self);
+ h2o_http2_conn_t *conn = (void *)stream->req.conn;
+
+ assert(stream->req._ostr_top == &stream->_ostr_final);
+ assert(stream->state == H2O_HTTP2_STREAM_STATE_SEND_HEADERS);
+
+ /* register the pull callback */
+ stream->_pull_cb = cb;
+
+ /* send headers */
+ if (send_headers(conn, stream) != 0)
+ return;
+
+ /* set dummy data in the send buffer */
+ h2o_vector_reserve(&stream->req.pool, &stream->_data, 1);
+ stream->_data.entries[0].base = "<pull interface>";
+ stream->_data.entries[0].len = 1;
+ stream->_data.size = 1;
+
+ h2o_http2_conn_register_for_proceed_callback(conn, stream);
+}
+
+void finalostream_send(h2o_ostream_t *self, h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state)
+{
+ h2o_http2_stream_t *stream = H2O_STRUCT_FROM_MEMBER(h2o_http2_stream_t, _ostr_final, self);
+ h2o_http2_conn_t *conn = (h2o_http2_conn_t *)req->conn;
+
+ assert(stream->_data.size == 0);
+
+ stream->send_state = state;
+
+ /* send headers */
+ switch (stream->state) {
+ case H2O_HTTP2_STREAM_STATE_SEND_HEADERS:
+ if (send_headers(conn, stream) != 0)
+ return;
+ /* fallthru */
+ case H2O_HTTP2_STREAM_STATE_SEND_BODY:
+ if (state != H2O_SEND_STATE_IN_PROGRESS) {
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL);
+ }
+ break;
+ case H2O_HTTP2_STREAM_STATE_END_STREAM:
+ /* might get set by h2o_http2_stream_reset */
+ return;
+ default:
+ assert(!"cannot be in a receiving state");
+ }
+
+ /* save the contents in queue */
+ if (bufcnt != 0) {
+ h2o_vector_reserve(&req->pool, &stream->_data, bufcnt);
+ memcpy(stream->_data.entries, bufs, sizeof(h2o_iovec_t) * bufcnt);
+ stream->_data.size = bufcnt;
+ }
+
+ h2o_http2_conn_register_for_proceed_callback(conn, stream);
+}
+
+void h2o_http2_stream_send_pending_data(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ if (h2o_http2_window_get_window(&stream->output_window) <= 0)
+ return;
+
+ if (stream->_pull_cb != NULL) {
+ h2o_send_state_t send_state;
+ /* pull mode */
+ assert(stream->state != H2O_HTTP2_STREAM_STATE_END_STREAM);
+ send_state = send_data_pull(conn, stream);
+ if (send_state != H2O_SEND_STATE_IN_PROGRESS) {
+ /* sent all data */
+ stream->_data.size = 0;
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_END_STREAM);
+ }
+ } else {
+ /* push mode */
+ h2o_iovec_t *nextbuf = send_data_push(conn, stream, stream->_data.entries, stream->_data.size, stream->send_state);
+ if (nextbuf == stream->_data.entries + stream->_data.size) {
+ /* sent all data */
+ stream->_data.size = 0;
+ if (stream->state == H2O_HTTP2_STREAM_STATE_SEND_BODY_IS_FINAL)
+ h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_END_STREAM);
+ } else if (nextbuf != stream->_data.entries) {
+ /* adjust the buffer */
+ size_t newsize = stream->_data.size - (nextbuf - stream->_data.entries);
+ memmove(stream->_data.entries, nextbuf, sizeof(h2o_iovec_t) * newsize);
+ stream->_data.size = newsize;
+ }
+ }
+}
+
+void h2o_http2_stream_proceed(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream)
+{
+ if (stream->state == H2O_HTTP2_STREAM_STATE_END_STREAM) {
+ h2o_http2_stream_close(conn, stream);
+ } else {
+ h2o_proceed_response(&stream->req);
+ }
+}