From 58daab21cd043e1dc37024a7f99b396788372918 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 9 Mar 2024 14:19:48 +0100 Subject: Merging upstream version 1.44.3. Signed-off-by: Daniel Baumann --- web/server/h2o/libh2o/lib/http2/cache_digests.c | 201 + web/server/h2o/libh2o/lib/http2/casper.c | 205 + web/server/h2o/libh2o/lib/http2/connection.c | 1419 ++++++ web/server/h2o/libh2o/lib/http2/frame.c | 290 ++ web/server/h2o/libh2o/lib/http2/hpack.c | 917 ++++ .../h2o/libh2o/lib/http2/hpack_huffman_table.h | 4954 ++++++++++++++++++++ .../h2o/libh2o/lib/http2/hpack_static_table.h | 87 + .../h2o/libh2o/lib/http2/http2_debug_state.c | 194 + web/server/h2o/libh2o/lib/http2/scheduler.c | 365 ++ web/server/h2o/libh2o/lib/http2/stream.c | 410 ++ 10 files changed, 9042 insertions(+) create mode 100644 web/server/h2o/libh2o/lib/http2/cache_digests.c create mode 100644 web/server/h2o/libh2o/lib/http2/casper.c create mode 100644 web/server/h2o/libh2o/lib/http2/connection.c create mode 100644 web/server/h2o/libh2o/lib/http2/frame.c create mode 100644 web/server/h2o/libh2o/lib/http2/hpack.c create mode 100644 web/server/h2o/libh2o/lib/http2/hpack_huffman_table.h create mode 100644 web/server/h2o/libh2o/lib/http2/hpack_static_table.h create mode 100644 web/server/h2o/libh2o/lib/http2/http2_debug_state.c create mode 100644 web/server/h2o/libh2o/lib/http2/scheduler.c create mode 100644 web/server/h2o/libh2o/lib/http2/stream.c (limited to 'web/server/h2o/libh2o/lib/http2') 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 +#include +#include +#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 +#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 +#include +#include +#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 +#include +#include +#include +#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 "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. + */ + +/* 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 +#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 = ""; + 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); + } +} -- cgit v1.2.3