From 5da14042f70711ea5cf66e034699730335462f66 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 5 May 2024 14:08:03 +0200 Subject: Merging upstream version 1.45.3+dfsg. Signed-off-by: Daniel Baumann --- web/server/h2o/libh2o/lib/common/cache.c | 273 -- web/server/h2o/libh2o/lib/common/file.c | 68 - web/server/h2o/libh2o/lib/common/filecache.c | 170 - web/server/h2o/libh2o/lib/common/hostinfo.c | 229 - web/server/h2o/libh2o/lib/common/http1client.c | 582 --- web/server/h2o/libh2o/lib/common/memcached.c | 429 -- web/server/h2o/libh2o/lib/common/memory.c | 400 -- web/server/h2o/libh2o/lib/common/multithread.c | 274 -- web/server/h2o/libh2o/lib/common/serverutil.c | 317 -- web/server/h2o/libh2o/lib/common/socket.c | 1433 ------ web/server/h2o/libh2o/lib/common/socket/evloop.c.h | 624 --- .../h2o/libh2o/lib/common/socket/evloop/epoll.c.h | 203 - .../h2o/libh2o/lib/common/socket/evloop/kqueue.c.h | 186 - .../h2o/libh2o/lib/common/socket/evloop/poll.c.h | 178 - .../h2o/libh2o/lib/common/socket/uv-binding.c.h | 283 -- web/server/h2o/libh2o/lib/common/socketpool.c | 342 -- web/server/h2o/libh2o/lib/common/string.c | 594 --- web/server/h2o/libh2o/lib/common/time.c | 175 - web/server/h2o/libh2o/lib/common/timeout.c | 90 - web/server/h2o/libh2o/lib/common/url.c | 409 -- web/server/h2o/libh2o/lib/core/config.c | 325 -- web/server/h2o/libh2o/lib/core/configurator.c | 1102 ----- web/server/h2o/libh2o/lib/core/context.c | 201 - web/server/h2o/libh2o/lib/core/headers.c | 155 - web/server/h2o/libh2o/lib/core/logconf.c | 793 ---- web/server/h2o/libh2o/lib/core/proxy.c | 610 --- web/server/h2o/libh2o/lib/core/request.c | 696 --- web/server/h2o/libh2o/lib/core/token.c | 28 - web/server/h2o/libh2o/lib/core/token_table.h | 408 -- web/server/h2o/libh2o/lib/core/util.c | 562 --- web/server/h2o/libh2o/lib/handler/access_log.c | 153 - web/server/h2o/libh2o/lib/handler/chunked.c | 113 - web/server/h2o/libh2o/lib/handler/compress.c | 144 - .../h2o/libh2o/lib/handler/compress/brotli.cc | 138 - web/server/h2o/libh2o/lib/handler/compress/gzip.c | 190 - .../libh2o/lib/handler/configurator/access_log.c | 143 - .../h2o/libh2o/lib/handler/configurator/compress.c | 172 - .../h2o/libh2o/lib/handler/configurator/errordoc.c | 203 - .../h2o/libh2o/lib/handler/configurator/expires.c | 123 - .../h2o/libh2o/lib/handler/configurator/fastcgi.c | 388 -- .../h2o/libh2o/lib/handler/configurator/file.c | 197 - .../h2o/libh2o/lib/handler/configurator/headers.c | 74 - .../libh2o/lib/handler/configurator/headers_util.c | 143 - .../lib/handler/configurator/http2_debug_state.c | 46 - .../h2o/libh2o/lib/handler/configurator/mruby.c | 177 - .../h2o/libh2o/lib/handler/configurator/proxy.c | 392 -- .../h2o/libh2o/lib/handler/configurator/redirect.c | 76 - .../h2o/libh2o/lib/handler/configurator/reproxy.c | 81 - .../h2o/libh2o/lib/handler/configurator/status.c | 87 - .../lib/handler/configurator/throttle_resp.c | 73 - web/server/h2o/libh2o/lib/handler/errordoc.c | 145 - web/server/h2o/libh2o/lib/handler/expires.c | 84 - web/server/h2o/libh2o/lib/handler/fastcgi.c | 856 ---- web/server/h2o/libh2o/lib/handler/file.c | 966 ---- .../h2o/libh2o/lib/handler/file/_templates.c.h | 90 - .../h2o/libh2o/lib/handler/file/templates.c.h | 171 - web/server/h2o/libh2o/lib/handler/headers.c | 58 - web/server/h2o/libh2o/lib/handler/headers_util.c | 114 - .../h2o/libh2o/lib/handler/http2_debug_state.c | 69 - web/server/h2o/libh2o/lib/handler/mimemap.c | 419 -- .../h2o/libh2o/lib/handler/mimemap/defaults.c.h | 109 - web/server/h2o/libh2o/lib/handler/mruby.c | 938 ---- web/server/h2o/libh2o/lib/handler/mruby/chunked.c | 270 -- .../h2o/libh2o/lib/handler/mruby/embedded.c.h | 111 - .../libh2o/lib/handler/mruby/embedded/chunked.rb | 35 - .../h2o/libh2o/lib/handler/mruby/embedded/core.rb | 81 - .../lib/handler/mruby/embedded/http_request.rb | 54 - .../h2o/libh2o/lib/handler/mruby/http_request.c | 500 -- web/server/h2o/libh2o/lib/handler/proxy.c | 165 - web/server/h2o/libh2o/lib/handler/redirect.c | 106 - web/server/h2o/libh2o/lib/handler/reproxy.c | 66 - web/server/h2o/libh2o/lib/handler/status.c | 270 -- .../h2o/libh2o/lib/handler/status/durations.c | 207 - web/server/h2o/libh2o/lib/handler/status/events.c | 112 - .../h2o/libh2o/lib/handler/status/requests.c | 151 - web/server/h2o/libh2o/lib/handler/throttle_resp.c | 156 - web/server/h2o/libh2o/lib/http1.c | 859 ---- 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 -- web/server/h2o/libh2o/lib/tunnel.c | 138 - web/server/h2o/libh2o/lib/websocket.c | 238 - 89 files changed, 31832 deletions(-) delete mode 100644 web/server/h2o/libh2o/lib/common/cache.c delete mode 100644 web/server/h2o/libh2o/lib/common/file.c delete mode 100644 web/server/h2o/libh2o/lib/common/filecache.c delete mode 100644 web/server/h2o/libh2o/lib/common/hostinfo.c delete mode 100644 web/server/h2o/libh2o/lib/common/http1client.c delete mode 100644 web/server/h2o/libh2o/lib/common/memcached.c delete mode 100644 web/server/h2o/libh2o/lib/common/memory.c delete mode 100644 web/server/h2o/libh2o/lib/common/multithread.c delete mode 100644 web/server/h2o/libh2o/lib/common/serverutil.c delete mode 100644 web/server/h2o/libh2o/lib/common/socket.c delete mode 100644 web/server/h2o/libh2o/lib/common/socket/evloop.c.h delete mode 100644 web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h delete mode 100644 web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h delete mode 100644 web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h delete mode 100644 web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h delete mode 100644 web/server/h2o/libh2o/lib/common/socketpool.c delete mode 100644 web/server/h2o/libh2o/lib/common/string.c delete mode 100644 web/server/h2o/libh2o/lib/common/time.c delete mode 100644 web/server/h2o/libh2o/lib/common/timeout.c delete mode 100644 web/server/h2o/libh2o/lib/common/url.c delete mode 100644 web/server/h2o/libh2o/lib/core/config.c delete mode 100644 web/server/h2o/libh2o/lib/core/configurator.c delete mode 100644 web/server/h2o/libh2o/lib/core/context.c delete mode 100644 web/server/h2o/libh2o/lib/core/headers.c delete mode 100644 web/server/h2o/libh2o/lib/core/logconf.c delete mode 100644 web/server/h2o/libh2o/lib/core/proxy.c delete mode 100644 web/server/h2o/libh2o/lib/core/request.c delete mode 100644 web/server/h2o/libh2o/lib/core/token.c delete mode 100644 web/server/h2o/libh2o/lib/core/token_table.h delete mode 100644 web/server/h2o/libh2o/lib/core/util.c delete mode 100644 web/server/h2o/libh2o/lib/handler/access_log.c delete mode 100644 web/server/h2o/libh2o/lib/handler/chunked.c delete mode 100644 web/server/h2o/libh2o/lib/handler/compress.c delete mode 100644 web/server/h2o/libh2o/lib/handler/compress/brotli.cc delete mode 100644 web/server/h2o/libh2o/lib/handler/compress/gzip.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/access_log.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/compress.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/errordoc.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/expires.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/fastcgi.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/file.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/headers.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/headers_util.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/http2_debug_state.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/mruby.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/proxy.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/redirect.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/reproxy.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/status.c delete mode 100644 web/server/h2o/libh2o/lib/handler/configurator/throttle_resp.c delete mode 100644 web/server/h2o/libh2o/lib/handler/errordoc.c delete mode 100644 web/server/h2o/libh2o/lib/handler/expires.c delete mode 100644 web/server/h2o/libh2o/lib/handler/fastcgi.c delete mode 100644 web/server/h2o/libh2o/lib/handler/file.c delete mode 100644 web/server/h2o/libh2o/lib/handler/file/_templates.c.h delete mode 100644 web/server/h2o/libh2o/lib/handler/file/templates.c.h delete mode 100644 web/server/h2o/libh2o/lib/handler/headers.c delete mode 100644 web/server/h2o/libh2o/lib/handler/headers_util.c delete mode 100644 web/server/h2o/libh2o/lib/handler/http2_debug_state.c delete mode 100644 web/server/h2o/libh2o/lib/handler/mimemap.c delete mode 100644 web/server/h2o/libh2o/lib/handler/mimemap/defaults.c.h delete mode 100644 web/server/h2o/libh2o/lib/handler/mruby.c delete mode 100644 web/server/h2o/libh2o/lib/handler/mruby/chunked.c delete mode 100644 web/server/h2o/libh2o/lib/handler/mruby/embedded.c.h delete mode 100644 web/server/h2o/libh2o/lib/handler/mruby/embedded/chunked.rb delete mode 100644 web/server/h2o/libh2o/lib/handler/mruby/embedded/core.rb delete mode 100644 web/server/h2o/libh2o/lib/handler/mruby/embedded/http_request.rb delete mode 100644 web/server/h2o/libh2o/lib/handler/mruby/http_request.c delete mode 100644 web/server/h2o/libh2o/lib/handler/proxy.c delete mode 100644 web/server/h2o/libh2o/lib/handler/redirect.c delete mode 100644 web/server/h2o/libh2o/lib/handler/reproxy.c delete mode 100644 web/server/h2o/libh2o/lib/handler/status.c delete mode 100644 web/server/h2o/libh2o/lib/handler/status/durations.c delete mode 100644 web/server/h2o/libh2o/lib/handler/status/events.c delete mode 100644 web/server/h2o/libh2o/lib/handler/status/requests.c delete mode 100644 web/server/h2o/libh2o/lib/handler/throttle_resp.c delete mode 100644 web/server/h2o/libh2o/lib/http1.c delete mode 100644 web/server/h2o/libh2o/lib/http2/cache_digests.c delete mode 100644 web/server/h2o/libh2o/lib/http2/casper.c delete mode 100644 web/server/h2o/libh2o/lib/http2/connection.c delete mode 100644 web/server/h2o/libh2o/lib/http2/frame.c delete mode 100644 web/server/h2o/libh2o/lib/http2/hpack.c delete mode 100644 web/server/h2o/libh2o/lib/http2/hpack_huffman_table.h delete mode 100644 web/server/h2o/libh2o/lib/http2/hpack_static_table.h delete mode 100644 web/server/h2o/libh2o/lib/http2/http2_debug_state.c delete mode 100644 web/server/h2o/libh2o/lib/http2/scheduler.c delete mode 100644 web/server/h2o/libh2o/lib/http2/stream.c delete mode 100644 web/server/h2o/libh2o/lib/tunnel.c delete mode 100644 web/server/h2o/libh2o/lib/websocket.c (limited to 'web/server/h2o/libh2o/lib') diff --git a/web/server/h2o/libh2o/lib/common/cache.c b/web/server/h2o/libh2o/lib/common/cache.c deleted file mode 100644 index cc8d8f007..000000000 --- a/web/server/h2o/libh2o/lib/common/cache.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2014-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 "khash.h" -#include "h2o/cache.h" -#include "h2o/linklist.h" -#include "h2o/memory.h" -#include "h2o/string_.h" - -static h2o_cache_hashcode_t get_keyhash(h2o_cache_ref_t *ref); -static int is_equal(h2o_cache_ref_t *x, h2o_cache_ref_t *y); - -KHASH_INIT(cache, h2o_cache_ref_t *, char, 0, get_keyhash, is_equal) - -struct st_h2o_cache_t { - int flags; - khash_t(cache) * table; - size_t size; - size_t capacity; - h2o_linklist_t lru; - h2o_linklist_t age; - uint64_t duration; - void (*destroy_cb)(h2o_iovec_t value); - pthread_mutex_t mutex; /* only used if (flags & H2O_CACHE_FLAG_MULTITHREADED) != 0 */ -}; - -static h2o_cache_hashcode_t get_keyhash(h2o_cache_ref_t *ref) -{ - return ref->keyhash; -} - -static int is_equal(h2o_cache_ref_t *x, h2o_cache_ref_t *y) -{ - return x->key.len == y->key.len && memcmp(x->key.base, y->key.base, x->key.len) == 0; -} - -static void lock_cache(h2o_cache_t *cache) -{ - if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0) - pthread_mutex_lock(&cache->mutex); -} - -static void unlock_cache(h2o_cache_t *cache) -{ - if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0) - pthread_mutex_unlock(&cache->mutex); -} - -static void erase_ref(h2o_cache_t *cache, khiter_t iter, int reuse) -{ - h2o_cache_ref_t *ref = kh_key(cache->table, iter); - - if (!reuse) - kh_del(cache, cache->table, iter); - h2o_linklist_unlink(&ref->_lru_link); - h2o_linklist_unlink(&ref->_age_link); - cache->size -= ref->value.len; - - h2o_cache_release(cache, ref); -} - -static int64_t get_timeleft(h2o_cache_t *cache, h2o_cache_ref_t *ref, uint64_t now) -{ - return (int64_t)(ref->at + cache->duration) - now; -} - -static void purge(h2o_cache_t *cache, uint64_t now) -{ - /* by cache size */ - while (cache->capacity < cache->size) { - h2o_cache_ref_t *last; - assert(!h2o_linklist_is_empty(&cache->lru)); - last = H2O_STRUCT_FROM_MEMBER(h2o_cache_ref_t, _lru_link, cache->lru.next); - erase_ref(cache, kh_get(cache, cache->table, last), 0); - } - /* by TTL */ - while (!h2o_linklist_is_empty(&cache->age)) { - h2o_cache_ref_t *oldest = H2O_STRUCT_FROM_MEMBER(h2o_cache_ref_t, _age_link, cache->age.next); - if (get_timeleft(cache, oldest, now) >= 0) - break; - erase_ref(cache, kh_get(cache, cache->table, oldest), 0); - } -} - -h2o_cache_hashcode_t h2o_cache_calchash(const char *s, size_t l) -{ - h2o_cache_hashcode_t h = 0; - for (; l != 0; --l) - h = (h << 5) - h + ((unsigned char *)s)[l - 1]; - return h; -} - -h2o_cache_t *h2o_cache_create(int flags, size_t capacity, uint64_t duration, void (*destroy_cb)(h2o_iovec_t value)) -{ - h2o_cache_t *cache = h2o_mem_alloc(sizeof(*cache)); - - cache->flags = flags; - cache->table = kh_init(cache); - cache->size = 0; - cache->capacity = capacity; - h2o_linklist_init_anchor(&cache->lru); - h2o_linklist_init_anchor(&cache->age); - cache->duration = duration; - cache->destroy_cb = destroy_cb; - if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0) - pthread_mutex_init(&cache->mutex, NULL); - - return cache; -} - -void h2o_cache_destroy(h2o_cache_t *cache) -{ - h2o_cache_clear(cache); - kh_destroy(cache, cache->table); - if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0) - pthread_mutex_destroy(&cache->mutex); - free(cache); -} - -void h2o_cache_clear(h2o_cache_t *cache) -{ - lock_cache(cache); - - while (!h2o_linklist_is_empty(&cache->lru)) { - h2o_cache_ref_t *ref = H2O_STRUCT_FROM_MEMBER(h2o_cache_ref_t, _lru_link, cache->lru.next); - erase_ref(cache, kh_get(cache, cache->table, ref), 0); - } - assert(h2o_linklist_is_linked(&cache->age)); - assert(kh_size(cache->table) == 0); - assert(cache->size == 0); - - unlock_cache(cache); -} - -h2o_cache_ref_t *h2o_cache_fetch(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash) -{ - h2o_cache_ref_t search_key, *ref; - khiter_t iter; - int64_t timeleft; - - if (keyhash == 0) - keyhash = h2o_cache_calchash(key.base, key.len); - search_key.key = key; - search_key.keyhash = keyhash; - - lock_cache(cache); - - purge(cache, now); - - if ((iter = kh_get(cache, cache->table, &search_key)) == kh_end(cache->table)) - goto NotFound; - - /* found */ - ref = kh_key(cache->table, iter); - timeleft = get_timeleft(cache, ref, now); - if (timeleft < 0) - goto NotFound; - if ((cache->flags & H2O_CACHE_FLAG_EARLY_UPDATE) != 0 && timeleft < 10 && !ref->_requested_early_update) { - ref->_requested_early_update = 1; - goto NotFound; - } - /* move the entry to the top of LRU */ - h2o_linklist_unlink(&ref->_lru_link); - h2o_linklist_insert(&cache->lru, &ref->_lru_link); - __sync_fetch_and_add(&ref->_refcnt, 1); - - /* unlock and return the found entry */ - unlock_cache(cache); - return ref; - -NotFound: - unlock_cache(cache); - return NULL; -} - -void h2o_cache_release(h2o_cache_t *cache, h2o_cache_ref_t *ref) -{ - if (__sync_fetch_and_sub(&ref->_refcnt, 1) == 1) { - assert(!h2o_linklist_is_linked(&ref->_lru_link)); - assert(!h2o_linklist_is_linked(&ref->_age_link)); - if (cache->destroy_cb != NULL) - cache->destroy_cb(ref->value); - free(ref->key.base); - free(ref); - } -} - -int h2o_cache_set(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash, h2o_iovec_t value) -{ - h2o_cache_ref_t *newref; - khiter_t iter; - int existed; - - if (keyhash == 0) - keyhash = h2o_cache_calchash(key.base, key.len); - - /* create newref */ - newref = h2o_mem_alloc(sizeof(*newref)); - *newref = (h2o_cache_ref_t){h2o_strdup(NULL, key.base, key.len), keyhash, now, value, 0, {NULL}, {NULL}, 1}; - - lock_cache(cache); - - /* set or replace the named value */ - iter = kh_get(cache, cache->table, newref); - if (iter != kh_end(cache->table)) { - erase_ref(cache, iter, 1); - kh_key(cache->table, iter) = newref; - existed = 1; - } else { - int unused; - kh_put(cache, cache->table, newref, &unused); - existed = 0; - } - h2o_linklist_insert(&cache->lru, &newref->_lru_link); - h2o_linklist_insert(&cache->age, &newref->_age_link); - cache->size += newref->value.len; - - purge(cache, now); - - unlock_cache(cache); - - return existed; -} - -void h2o_cache_delete(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash) -{ - h2o_cache_ref_t search_key; - khiter_t iter; - - if (keyhash == 0) - keyhash = h2o_cache_calchash(key.base, key.len); - search_key.key = key; - search_key.keyhash = keyhash; - - lock_cache(cache); - - purge(cache, now); - - if ((iter = kh_get(cache, cache->table, &search_key)) != kh_end(cache->table)) - erase_ref(cache, iter, 0); - - unlock_cache(cache); -} - -size_t h2o_cache_get_capacity(h2o_cache_t *cache) -{ - return cache->capacity; -} - -uint64_t h2o_cache_get_duration(h2o_cache_t *cache) -{ - return cache->duration; -} diff --git a/web/server/h2o/libh2o/lib/common/file.c b/web/server/h2o/libh2o/lib/common/file.c deleted file mode 100644 index 3cf5ac5d1..000000000 --- a/web/server/h2o/libh2o/lib/common/file.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include "h2o/file.h" - -h2o_iovec_t h2o_file_read(const char *fn) -{ - int fd; - struct stat st; - h2o_iovec_t ret = {NULL}; - - /* open */ - if ((fd = open(fn, O_RDONLY | O_CLOEXEC)) == -1) - goto Error; - if (fstat(fd, &st)) - goto Error; - /* allocate memory */ - if (st.st_size > SIZE_MAX) { - errno = ENOMEM; - goto Error; - } - if ((ret.base = malloc((size_t)st.st_size)) == NULL) - goto Error; - /* read */ - while (ret.len != (size_t)st.st_size) { - ssize_t r; - while ((r = read(fd, ret.base + ret.len, (size_t)st.st_size - ret.len)) == -1 && errno == EINTR) - ; - if (r <= 0) - goto Error; - ret.len += r; - } - /* close */ - close(fd); - return ret; - -Error: - if (fd != -1) - close(fd); - free(ret.base); - return (h2o_iovec_t){NULL}; -} diff --git a/web/server/h2o/libh2o/lib/common/filecache.c b/web/server/h2o/libh2o/lib/common/filecache.c deleted file mode 100644 index 747a1ffa6..000000000 --- a/web/server/h2o/libh2o/lib/common/filecache.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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 -#include -#include -#include -#include "khash.h" -#include "h2o/memory.h" -#include "h2o/filecache.h" - -KHASH_SET_INIT_STR(opencache_set) - -struct st_h2o_filecache_t { - khash_t(opencache_set) * hash; - h2o_linklist_t lru; - size_t capacity; -}; - -static inline void release_from_cache(h2o_filecache_t *cache, khiter_t iter) -{ - const char *path = kh_key(cache->hash, iter); - h2o_filecache_ref_t *ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _path, path); - - /* detach from list */ - kh_del(opencache_set, cache->hash, iter); - h2o_linklist_unlink(&ref->_lru); - - /* and close */ - h2o_filecache_close_file(ref); -} - -h2o_filecache_t *h2o_filecache_create(size_t capacity) -{ - h2o_filecache_t *cache = h2o_mem_alloc(sizeof(*cache)); - - cache->hash = kh_init(opencache_set); - h2o_linklist_init_anchor(&cache->lru); - cache->capacity = capacity; - - return cache; -} - -void h2o_filecache_destroy(h2o_filecache_t *cache) -{ - h2o_filecache_clear(cache); - assert(kh_size(cache->hash) == 0); - assert(h2o_linklist_is_empty(&cache->lru)); - kh_destroy(opencache_set, cache->hash); - free(cache); -} - -void h2o_filecache_clear(h2o_filecache_t *cache) -{ - khiter_t iter; - for (iter = kh_begin(cache->hash); iter != kh_end(cache->hash); ++iter) { - if (!kh_exist(cache->hash, iter)) - continue; - release_from_cache(cache, iter); - } - assert(kh_size(cache->hash) == 0); -} - -h2o_filecache_ref_t *h2o_filecache_open_file(h2o_filecache_t *cache, const char *path, int oflag) -{ - khiter_t iter = kh_get(opencache_set, cache->hash, path); - h2o_filecache_ref_t *ref; - int dummy; - - /* lookup cache, and return the one if found */ - if (iter != kh_end(cache->hash)) { - ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _path, kh_key(cache->hash, iter)); - ++ref->_refcnt; - goto Exit; - } - - /* create a new cache entry */ - ref = h2o_mem_alloc(offsetof(h2o_filecache_ref_t, _path) + strlen(path) + 1); - ref->_refcnt = 1; - ref->_lru = (h2o_linklist_t){NULL}; - strcpy(ref->_path, path); - - /* if cache is used, then... */ - if (cache->capacity != 0) { - /* purge one entry from LRU if cache is full */ - if (kh_size(cache->hash) == cache->capacity) { - h2o_filecache_ref_t *purge_ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _lru, cache->lru.prev); - khiter_t purge_iter = kh_get(opencache_set, cache->hash, purge_ref->_path); - assert(purge_iter != kh_end(cache->hash)); - release_from_cache(cache, purge_iter); - } - /* assign the new entry */ - ++ref->_refcnt; - kh_put(opencache_set, cache->hash, ref->_path, &dummy); - h2o_linklist_insert(cache->lru.next, &ref->_lru); - } - - /* open the file, or memoize the error */ - if ((ref->fd = open(path, oflag)) != -1 && fstat(ref->fd, &ref->st) == 0) { - ref->_last_modified.str[0] = '\0'; - ref->_etag.len = 0; - } else { - ref->open_err = errno; - if (ref->fd != -1) { - close(ref->fd); - ref->fd = -1; - } - } - -Exit: - /* if the cache entry retains an error, return it instead of the reference */ - if (ref->fd == -1) { - errno = ref->open_err; - h2o_filecache_close_file(ref); - ref = NULL; - } - return ref; -} - -void h2o_filecache_close_file(h2o_filecache_ref_t *ref) -{ - if (--ref->_refcnt != 0) - return; - assert(!h2o_linklist_is_linked(&ref->_lru)); - if (ref->fd != -1) { - close(ref->fd); - ref->fd = -1; - } - free(ref); -} - -struct tm *h2o_filecache_get_last_modified(h2o_filecache_ref_t *ref, char *outbuf) -{ - assert(ref->fd != -1); - if (ref->_last_modified.str[0] == '\0') { - gmtime_r(&ref->st.st_mtime, &ref->_last_modified.gm); - h2o_time2str_rfc1123(ref->_last_modified.str, &ref->_last_modified.gm); - } - if (outbuf != NULL) - memcpy(outbuf, ref->_last_modified.str, H2O_TIMESTR_RFC1123_LEN + 1); - return &ref->_last_modified.gm; -} - -size_t h2o_filecache_get_etag(h2o_filecache_ref_t *ref, char *outbuf) -{ - assert(ref->fd != -1); - if (ref->_etag.len == 0) - ref->_etag.len = sprintf(ref->_etag.buf, "\"%08x-%zx\"", (unsigned)ref->st.st_mtime, (size_t)ref->st.st_size); - memcpy(outbuf, ref->_etag.buf, ref->_etag.len + 1); - return ref->_etag.len; -} diff --git a/web/server/h2o/libh2o/lib/common/hostinfo.c b/web/server/h2o/libh2o/lib/common/hostinfo.c deleted file mode 100644 index 7b481e296..000000000 --- a/web/server/h2o/libh2o/lib/common/hostinfo.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * 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 "h2o/hostinfo.h" - -struct st_h2o_hostinfo_getaddr_req_t { - h2o_multithread_receiver_t *_receiver; - h2o_hostinfo_getaddr_cb _cb; - void *cbdata; - h2o_linklist_t _pending; - union { - struct { - char *name; - char *serv; - struct addrinfo hints; - } _in; - struct { - h2o_multithread_message_t message; - const char *errstr; - struct addrinfo *ai; - } _out; - }; -}; - -static struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - h2o_linklist_t pending; /* anchor of h2o_hostinfo_getaddr_req_t::_pending */ - size_t num_threads; - size_t num_threads_idle; -} queue = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, {&queue.pending, &queue.pending}, 0, 0}; - -size_t h2o_hostinfo_max_threads = 1; - -static void lookup_and_respond(h2o_hostinfo_getaddr_req_t *req) -{ - struct addrinfo *res; - - int ret = getaddrinfo(req->_in.name, req->_in.serv, &req->_in.hints, &res); - req->_out.message = (h2o_multithread_message_t){{NULL}}; - if (ret != 0) { - req->_out.errstr = gai_strerror(ret); - req->_out.ai = NULL; - } else { - req->_out.errstr = NULL; - req->_out.ai = res; - } - - h2o_multithread_send_message(req->_receiver, &req->_out.message); -} - -static void *lookup_thread_main(void *_unused) -{ - pthread_mutex_lock(&queue.mutex); - - while (1) { - --queue.num_threads_idle; - while (!h2o_linklist_is_empty(&queue.pending)) { - h2o_hostinfo_getaddr_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_hostinfo_getaddr_req_t, _pending, queue.pending.next); - h2o_linklist_unlink(&req->_pending); - pthread_mutex_unlock(&queue.mutex); - lookup_and_respond(req); - pthread_mutex_lock(&queue.mutex); - } - ++queue.num_threads_idle; - pthread_cond_wait(&queue.cond, &queue.mutex); - } - - h2o_fatal("unreachable"); - return NULL; -} - -static void create_lookup_thread(void) -{ - pthread_t tid; - pthread_attr_t attr; - int ret; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, 1); - pthread_attr_setstacksize(&attr, 100 * 1024); - if ((ret = pthread_create(&tid, NULL, lookup_thread_main, NULL)) != 0) { - if (queue.num_threads == 0) { - fprintf(stderr, "failed to start first thread for getaddrinfo:%s\n", strerror(ret)); - abort(); - } else { - perror("pthread_create(for getaddrinfo)"); - } - return; - } - - ++queue.num_threads; - ++queue.num_threads_idle; -} - -h2o_hostinfo_getaddr_req_t *h2o_hostinfo_getaddr(h2o_multithread_receiver_t *receiver, h2o_iovec_t name, h2o_iovec_t serv, - int family, int socktype, int protocol, int flags, h2o_hostinfo_getaddr_cb cb, - void *cbdata) -{ - h2o_hostinfo_getaddr_req_t *req = h2o_mem_alloc(sizeof(*req) + name.len + 1 + serv.len + 1); - req->_receiver = receiver; - req->_cb = cb; - req->cbdata = cbdata; - req->_pending = (h2o_linklist_t){NULL}; - req->_in.name = (char *)req + sizeof(*req); - memcpy(req->_in.name, name.base, name.len); - req->_in.name[name.len] = '\0'; - req->_in.serv = req->_in.name + name.len + 1; - memcpy(req->_in.serv, serv.base, serv.len); - req->_in.serv[serv.len] = '\0'; - memset(&req->_in.hints, 0, sizeof(req->_in.hints)); - req->_in.hints.ai_family = family; - req->_in.hints.ai_socktype = socktype; - req->_in.hints.ai_protocol = protocol; - req->_in.hints.ai_flags = flags; - - h2o__hostinfo_getaddr_dispatch(req); - - return req; -} - -void h2o__hostinfo_getaddr_dispatch(h2o_hostinfo_getaddr_req_t *req) -{ - pthread_mutex_lock(&queue.mutex); - - h2o_linklist_insert(&queue.pending, &req->_pending); - - if (queue.num_threads_idle == 0 && queue.num_threads < h2o_hostinfo_max_threads) - create_lookup_thread(); - - pthread_cond_signal(&queue.cond); - pthread_mutex_unlock(&queue.mutex); -} - -void h2o_hostinfo_getaddr_cancel(h2o_hostinfo_getaddr_req_t *req) -{ - int should_free = 0; - - pthread_mutex_lock(&queue.mutex); - - if (h2o_linklist_is_linked(&req->_pending)) { - h2o_linklist_unlink(&req->_pending); - should_free = 1; - } else { - req->_cb = NULL; - } - - pthread_mutex_unlock(&queue.mutex); - - if (should_free) - free(req); -} - -void h2o_hostinfo_getaddr_receiver(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages) -{ - while (!h2o_linklist_is_empty(messages)) { - h2o_hostinfo_getaddr_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_hostinfo_getaddr_req_t, _out.message.link, messages->next); - h2o_linklist_unlink(&req->_out.message.link); - h2o_hostinfo_getaddr_cb cb = req->_cb; - if (cb != NULL) { - req->_cb = NULL; - cb(req, req->_out.errstr, req->_out.ai, req->cbdata); - } - if (req->_out.ai != NULL) - freeaddrinfo(req->_out.ai); - free(req); - } -} - -static const char *fetch_aton_digit(const char *p, const char *end, unsigned char *value) -{ - size_t ndigits = 0; - int v = 0; - - while (p != end && ('0' <= *p && *p <= '9')) { - v = v * 10 + *p++ - '0'; - ++ndigits; - } - if (!(1 <= ndigits && ndigits <= 3)) - return NULL; - if (v > 255) - return NULL; - *value = (unsigned char)v; - return p; -} - -int h2o_hostinfo_aton(h2o_iovec_t host, struct in_addr *addr) -{ - union { - int32_t n; - unsigned char c[4]; - } value; - const char *p = host.base, *end = p + host.len; - size_t ndots = 0; - - while (1) { - if ((p = fetch_aton_digit(p, end, value.c + ndots)) == NULL) - return -1; - if (ndots == 3) - break; - if (p == end || !(*p == '.')) - return -1; - ++p; - ++ndots; - } - if (p != end) - return -1; - - addr->s_addr = value.n; - return 0; -} diff --git a/web/server/h2o/libh2o/lib/common/http1client.c b/web/server/h2o/libh2o/lib/common/http1client.c deleted file mode 100644 index 8547ea817..000000000 --- a/web/server/h2o/libh2o/lib/common/http1client.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include "picohttpparser.h" -#include "h2o.h" - -struct st_h2o_http1client_private_t { - h2o_http1client_t super; - union { - h2o_http1client_connect_cb on_connect; - h2o_http1client_head_cb on_head; - h2o_http1client_body_cb on_body; - } _cb; - h2o_timeout_entry_t _timeout; - int _method_is_head; - h2o_hostinfo_getaddr_req_t *_getaddr_req; - int _can_keepalive; - union { - struct { - size_t bytesleft; - } content_length; - struct { - struct phr_chunked_decoder decoder; - size_t bytes_decoded_in_buf; - } chunked; - } _body_decoder; -}; - -static void close_client(struct st_h2o_http1client_private_t *client) -{ - if (client->_getaddr_req != NULL) { - h2o_hostinfo_getaddr_cancel(client->_getaddr_req); - client->_getaddr_req = NULL; - } - if (client->super.ssl.server_name != NULL) - free(client->super.ssl.server_name); - if (client->super.sock != NULL) { - if (client->super.sockpool.pool != NULL && client->_can_keepalive) { - /* we do not send pipelined requests, and thus can trash all the received input at the end of the request */ - h2o_buffer_consume(&client->super.sock->input, client->super.sock->input->size); - h2o_socketpool_return(client->super.sockpool.pool, client->super.sock); - } else { - h2o_socket_close(client->super.sock); - } - } else { - if (client->super.sockpool.connect_req != NULL) { - h2o_socketpool_cancel_connect(client->super.sockpool.connect_req); - client->super.sockpool.connect_req = NULL; - } - } - if (h2o_timeout_is_linked(&client->_timeout)) - h2o_timeout_unlink(&client->_timeout); - free(client); -} - -static void on_body_error(struct st_h2o_http1client_private_t *client, const char *errstr) -{ - client->_can_keepalive = 0; - client->_cb.on_body(&client->super, errstr); - close_client(client); -} - -static void on_body_timeout(h2o_timeout_entry_t *entry) -{ - struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry); - on_body_error(client, "I/O timeout"); -} - -static void on_body_until_close(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1client_private_t *client = sock->data; - - h2o_timeout_unlink(&client->_timeout); - - if (err != NULL) { - client->_cb.on_body(&client->super, h2o_http1client_error_is_eos); - close_client(client); - return; - } - - if (sock->bytes_read != 0) { - if (client->_cb.on_body(&client->super, NULL) != 0) { - close_client(client); - return; - } - } - - h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout); -} - -static void on_body_content_length(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1client_private_t *client = sock->data; - - h2o_timeout_unlink(&client->_timeout); - - if (err != NULL) { - on_body_error(client, "I/O error (body; content-length)"); - return; - } - - if (sock->bytes_read != 0 || client->_body_decoder.content_length.bytesleft == 0) { - const char *errstr; - int ret; - if (client->_body_decoder.content_length.bytesleft <= sock->bytes_read) { - if (client->_body_decoder.content_length.bytesleft < sock->bytes_read) { - /* remove the trailing garbage from buf, and disable keepalive */ - client->super.sock->input->size -= sock->bytes_read - client->_body_decoder.content_length.bytesleft; - client->_can_keepalive = 0; - } - client->_body_decoder.content_length.bytesleft = 0; - errstr = h2o_http1client_error_is_eos; - } else { - client->_body_decoder.content_length.bytesleft -= sock->bytes_read; - errstr = NULL; - } - ret = client->_cb.on_body(&client->super, errstr); - if (errstr == h2o_http1client_error_is_eos) { - close_client(client); - return; - } else if (ret != 0) { - client->_can_keepalive = 0; - close_client(client); - return; - } - } - - h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout); -} - -static void on_body_chunked(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1client_private_t *client = sock->data; - h2o_buffer_t *inbuf; - - h2o_timeout_unlink(&client->_timeout); - - if (err != NULL) { - if (err == h2o_socket_error_closed && !phr_decode_chunked_is_in_data(&client->_body_decoder.chunked.decoder)) { - /* - * if the peer closed after a full chunk, treat this - * as if the transfer had complete, browsers appear to ignore - * a missing 0\r\n chunk - */ - client->_can_keepalive = 0; - client->_cb.on_body(&client->super, h2o_http1client_error_is_eos); - close_client(client); - } else { - on_body_error(client, "I/O error (body; chunked)"); - } - return; - } - - inbuf = client->super.sock->input; - if (sock->bytes_read != 0) { - const char *errstr; - int cb_ret; - size_t newsz = sock->bytes_read; - switch (phr_decode_chunked(&client->_body_decoder.chunked.decoder, inbuf->bytes + inbuf->size - newsz, &newsz)) { - case -1: /* error */ - newsz = sock->bytes_read; - client->_can_keepalive = 0; - errstr = "failed to parse the response (chunked)"; - break; - case -2: /* incomplete */ - errstr = NULL; - break; - default: /* complete, with garbage on tail; should disable keepalive */ - client->_can_keepalive = 0; - /* fallthru */ - case 0: /* complete */ - errstr = h2o_http1client_error_is_eos; - break; - } - inbuf->size -= sock->bytes_read - newsz; - cb_ret = client->_cb.on_body(&client->super, errstr); - if (errstr != NULL) { - close_client(client); - return; - } else if (cb_ret != 0) { - client->_can_keepalive = 0; - close_client(client); - return; - } - } - - h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout); -} - -static void on_error_before_head(struct st_h2o_http1client_private_t *client, const char *errstr) -{ - assert(!client->_can_keepalive); - client->_cb.on_head(&client->super, errstr, 0, 0, h2o_iovec_init(NULL, 0), NULL, 0, 0); - close_client(client); -} - -static void on_head(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1client_private_t *client = sock->data; - int minor_version, http_status, rlen, is_eos; - const char *msg; -#define MAX_HEADERS 100 - h2o_header_t *headers; - h2o_iovec_t *header_names; - size_t msg_len, num_headers, i; - h2o_socket_cb reader; - h2o_mem_pool_t pool; - - h2o_timeout_unlink(&client->_timeout); - - if (err != NULL) { - on_error_before_head(client, "I/O error (head)"); - return; - } - - h2o_mem_init_pool(&pool); - - headers = h2o_mem_alloc_pool(&pool, sizeof(*headers) * MAX_HEADERS); - header_names = h2o_mem_alloc_pool(&pool, sizeof(*header_names) * MAX_HEADERS); - - /* continue parsing the responses until we see a final one */ - while (1) { - /* parse response */ - struct phr_header src_headers[MAX_HEADERS]; - num_headers = MAX_HEADERS; - rlen = phr_parse_response(sock->input->bytes, sock->input->size, &minor_version, &http_status, &msg, &msg_len, src_headers, - &num_headers, 0); - switch (rlen) { - case -1: /* error */ - on_error_before_head(client, "failed to parse the response"); - goto Exit; - case -2: /* incomplete */ - h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout); - goto Exit; - } - /* fill-in the headers */ - for (i = 0; i != num_headers; ++i) { - const h2o_token_t *token; - char *orig_name = h2o_strdup(&pool, src_headers[i].name, src_headers[i].name_len).base; - h2o_strtolower((char *)src_headers[i].name, src_headers[i].name_len); - token = h2o_lookup_token(src_headers[i].name, src_headers[i].name_len); - if (token != NULL) { - headers[i].name = (h2o_iovec_t *)&token->buf; - } else { - header_names[i] = h2o_iovec_init(src_headers[i].name, src_headers[i].name_len); - headers[i].name = &header_names[i]; - } - headers[i].value = h2o_iovec_init(src_headers[i].value, src_headers[i].value_len); - headers[i].orig_name = orig_name; - } - - if (!(100 <= http_status && http_status <= 199 && http_status != 101)) - break; - - if (client->super.informational_cb != NULL && - client->super.informational_cb(&client->super, minor_version, http_status, h2o_iovec_init(msg, msg_len), headers, - num_headers) != 0) { - close_client(client); - goto Exit; - } - h2o_buffer_consume(&client->super.sock->input, rlen); - if (client->super.sock->input->size == 0) { - h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout); - goto Exit; - } - } - - /* parse the headers */ - reader = on_body_until_close; - client->_can_keepalive = minor_version >= 1; - for (i = 0; i != num_headers; ++i) { - if (headers[i].name == &H2O_TOKEN_CONNECTION->buf) { - if (h2o_contains_token(headers[i].value.base, headers[i].value.len, H2O_STRLIT("keep-alive"), ',')) { - client->_can_keepalive = 1; - } else { - client->_can_keepalive = 0; - } - } else if (headers[i].name == &H2O_TOKEN_TRANSFER_ENCODING->buf) { - if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("chunked"))) { - /* precond: _body_decoder.chunked is zero-filled */ - client->_body_decoder.chunked.decoder.consume_trailer = 1; - reader = on_body_chunked; - } else if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("identity"))) { - /* continue */ - } else { - on_error_before_head(client, "unexpected type of transfer-encoding"); - goto Exit; - } - } else if (headers[i].name == &H2O_TOKEN_CONTENT_LENGTH->buf) { - if ((client->_body_decoder.content_length.bytesleft = h2o_strtosize(headers[i].value.base, headers[i].value.len)) == - SIZE_MAX) { - on_error_before_head(client, "invalid content-length"); - goto Exit; - } - if (reader != on_body_chunked) - reader = on_body_content_length; - } - } - - /* RFC 2616 4.4 */ - if (client->_method_is_head || http_status == 101 || http_status == 204 || http_status == 304) { - is_eos = 1; - } else { - is_eos = 0; - /* close the connection if impossible to determine the end of the response (RFC 7230 3.3.3) */ - if (reader == on_body_until_close) - client->_can_keepalive = 0; - } - - /* call the callback. sock may be stealed and stealed sock need rlen.*/ - client->_cb.on_body = client->_cb.on_head(&client->super, is_eos ? h2o_http1client_error_is_eos : NULL, minor_version, - http_status, h2o_iovec_init(msg, msg_len), headers, num_headers, rlen); - - if (is_eos) { - close_client(client); - goto Exit; - } else if (client->_cb.on_body == NULL) { - client->_can_keepalive = 0; - close_client(client); - goto Exit; - } - - h2o_buffer_consume(&client->super.sock->input, rlen); - client->super.sock->bytes_read = client->super.sock->input->size; - - client->_timeout.cb = on_body_timeout; - h2o_socket_read_start(sock, reader); - reader(client->super.sock, 0); - -Exit: - h2o_mem_clear_pool(&pool); -#undef MAX_HEADERS -} - -static void on_head_timeout(h2o_timeout_entry_t *entry) -{ - struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry); - on_error_before_head(client, "I/O timeout"); -} - -static void on_send_request(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1client_private_t *client = sock->data; - - h2o_timeout_unlink(&client->_timeout); - - if (err != NULL) { - on_error_before_head(client, "I/O error (send request)"); - return; - } - - h2o_socket_read_start(client->super.sock, on_head); - client->_timeout.cb = on_head_timeout; - h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout); -} - -static void on_send_timeout(h2o_timeout_entry_t *entry) -{ - struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry); - on_error_before_head(client, "I/O timeout"); -} - -static void on_connect_error(struct st_h2o_http1client_private_t *client, const char *errstr) -{ - assert(errstr != NULL); - client->_cb.on_connect(&client->super, errstr, NULL, NULL, NULL); - close_client(client); -} - -static void on_connection_ready(struct st_h2o_http1client_private_t *client) -{ - h2o_iovec_t *reqbufs; - size_t reqbufcnt; - - if ((client->_cb.on_head = client->_cb.on_connect(&client->super, NULL, &reqbufs, &reqbufcnt, &client->_method_is_head)) == - NULL) { - close_client(client); - return; - } - h2o_socket_write(client->super.sock, reqbufs, reqbufcnt, on_send_request); - /* TODO no need to set the timeout if all data has been written into TCP sendbuf */ - client->_timeout.cb = on_send_timeout; - h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout); -} - -static void on_handshake_complete(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1client_private_t *client = sock->data; - - h2o_timeout_unlink(&client->_timeout); - - if (err == NULL) { - /* success */ - } else if (err == h2o_socket_error_ssl_cert_name_mismatch && - (SSL_CTX_get_verify_mode(client->super.ctx->ssl_ctx) & SSL_VERIFY_PEER) == 0) { - /* peer verification skipped */ - } else { - on_connect_error(client, err); - return; - } - - on_connection_ready(client); -} - -static void on_connect(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1client_private_t *client = sock->data; - - if (err != NULL) { - h2o_timeout_unlink(&client->_timeout); - on_connect_error(client, err); - return; - } - if (client->super.ssl.server_name != NULL && client->super.sock->ssl == NULL) { - h2o_socket_ssl_handshake(client->super.sock, client->super.ctx->ssl_ctx, client->super.ssl.server_name, - on_handshake_complete); - return; - } - - h2o_timeout_unlink(&client->_timeout); - - on_connection_ready(client); -} - -static void on_pool_connect(h2o_socket_t *sock, const char *errstr, void *data) -{ - struct st_h2o_http1client_private_t *client = data; - - client->super.sockpool.connect_req = NULL; - - if (sock == NULL) { - assert(errstr != NULL); - on_connect_error(client, errstr); - return; - } - - client->super.sock = sock; - sock->data = client; - on_connect(sock, NULL); -} - -static void on_connect_timeout(h2o_timeout_entry_t *entry) -{ - struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry); - on_connect_error(client, "connection timeout"); -} - -static void start_connect(struct st_h2o_http1client_private_t *client, struct sockaddr *addr, socklen_t addrlen) -{ - if ((client->super.sock = h2o_socket_connect(client->super.ctx->loop, addr, addrlen, on_connect)) == NULL) { - on_connect_error(client, "socket create error"); - return; - } - client->super.sock->data = client; -} - -static void on_getaddr(h2o_hostinfo_getaddr_req_t *getaddr_req, const char *errstr, struct addrinfo *res, void *_client) -{ - struct st_h2o_http1client_private_t *client = _client; - - assert(getaddr_req == client->_getaddr_req); - client->_getaddr_req = NULL; - - if (errstr != NULL) { - on_connect_error(client, errstr); - return; - } - - /* start connecting */ - struct addrinfo *selected = h2o_hostinfo_select_one(res); - start_connect(client, selected->ai_addr, selected->ai_addrlen); -} - -static struct st_h2o_http1client_private_t *create_client(h2o_http1client_t **_client, void *data, h2o_http1client_ctx_t *ctx, - h2o_iovec_t ssl_server_name, h2o_http1client_connect_cb cb) -{ - struct st_h2o_http1client_private_t *client = h2o_mem_alloc(sizeof(*client)); - - *client = (struct st_h2o_http1client_private_t){{ctx}}; - if (ssl_server_name.base != NULL) - client->super.ssl.server_name = h2o_strdup(NULL, ssl_server_name.base, ssl_server_name.len).base; - client->super.data = data; - client->_cb.on_connect = cb; - /* caller needs to setup _cb, timeout.cb, sock, and sock->data */ - - if (_client != NULL) - *_client = &client->super; - return client; -} - -const char *const h2o_http1client_error_is_eos = "end of stream"; - -void h2o_http1client_connect(h2o_http1client_t **_client, void *data, h2o_http1client_ctx_t *ctx, h2o_iovec_t host, uint16_t port, - int is_ssl, h2o_http1client_connect_cb cb) -{ - struct st_h2o_http1client_private_t *client; - char serv[sizeof("65536")]; - - /* setup */ - client = create_client(_client, data, ctx, is_ssl ? host : h2o_iovec_init(NULL, 0), cb); - client->_timeout.cb = on_connect_timeout; - h2o_timeout_link(ctx->loop, ctx->io_timeout, &client->_timeout); - - { /* directly call connect(2) if `host` is an IP address */ - struct sockaddr_in sin; - memset(&sin, 0, sizeof(sin)); - if (h2o_hostinfo_aton(host, &sin.sin_addr) == 0) { - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - start_connect(client, (void *)&sin, sizeof(sin)); - return; - } - } - { /* directly call connect(2) if `host` refers to an UNIX-domain socket */ - struct sockaddr_un sa; - const char *to_sa_err; - if ((to_sa_err = h2o_url_host_to_sun(host, &sa)) != h2o_url_host_to_sun_err_is_not_unix_socket) { - if (to_sa_err != NULL) { - on_connect_error(client, to_sa_err); - return; - } - start_connect(client, (void *)&sa, sizeof(sa)); - return; - } - } - /* resolve destination and then connect */ - client->_getaddr_req = - h2o_hostinfo_getaddr(ctx->getaddr_receiver, host, h2o_iovec_init(serv, sprintf(serv, "%u", (unsigned)port)), AF_UNSPEC, - SOCK_STREAM, IPPROTO_TCP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, client); -} - -void h2o_http1client_connect_with_pool(h2o_http1client_t **_client, void *data, h2o_http1client_ctx_t *ctx, - h2o_socketpool_t *sockpool, h2o_http1client_connect_cb cb) -{ - struct st_h2o_http1client_private_t *client = - create_client(_client, data, ctx, sockpool->is_ssl ? sockpool->peer.host : h2o_iovec_init(NULL, 0), cb); - client->super.sockpool.pool = sockpool; - client->_timeout.cb = on_connect_timeout; - h2o_timeout_link(ctx->loop, ctx->io_timeout, &client->_timeout); - h2o_socketpool_connect(&client->super.sockpool.connect_req, sockpool, ctx->loop, ctx->getaddr_receiver, on_pool_connect, - client); -} - -void h2o_http1client_cancel(h2o_http1client_t *_client) -{ - struct st_h2o_http1client_private_t *client = (void *)_client; - client->_can_keepalive = 0; - close_client(client); -} - -h2o_socket_t *h2o_http1client_steal_socket(h2o_http1client_t *_client) -{ - struct st_h2o_http1client_private_t *client = (void *)_client; - h2o_socket_t *sock = client->super.sock; - h2o_socket_read_stop(sock); - client->super.sock = NULL; - return sock; -} diff --git a/web/server/h2o/libh2o/lib/common/memcached.c b/web/server/h2o/libh2o/lib/common/memcached.c deleted file mode 100644 index 752ea2fcb..000000000 --- a/web/server/h2o/libh2o/lib/common/memcached.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * 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 -#include -#include "yrmcds.h" -#include "h2o/linklist.h" -#include "h2o/memcached.h" -#include "h2o/rand.h" -#include "h2o/string_.h" - -struct st_h2o_memcached_context_t { - pthread_mutex_t mutex; - pthread_cond_t cond; - h2o_linklist_t pending; - size_t num_threads_connected; - char *host; - uint16_t port; - int text_protocol; - h2o_iovec_t prefix; -}; - -struct st_h2o_memcached_conn_t { - h2o_memcached_context_t *ctx; - yrmcds yrmcds; - pthread_mutex_t mutex; - h2o_linklist_t inflight; - int writer_exit_requested; -}; - -enum en_h2o_memcached_req_type_t { REQ_TYPE_GET, REQ_TYPE_SET, REQ_TYPE_DELETE }; - -struct st_h2o_memcached_req_t { - enum en_h2o_memcached_req_type_t type; - h2o_linklist_t pending; - h2o_linklist_t inflight; - union { - struct { - h2o_multithread_receiver_t *receiver; - h2o_multithread_message_t message; - h2o_memcached_get_cb cb; - void *cb_data; - int value_is_encoded; - h2o_iovec_t value; - uint32_t serial; - } get; - struct { - h2o_iovec_t value; - uint32_t expiration; - } set; - } data; - struct { - size_t len; - char base[1]; - } key; -}; - -static h2o_memcached_req_t *create_req(h2o_memcached_context_t *ctx, enum en_h2o_memcached_req_type_t type, h2o_iovec_t key, - int encode_key) -{ - h2o_memcached_req_t *req = h2o_mem_alloc(offsetof(h2o_memcached_req_t, key.base) + ctx->prefix.len + - (encode_key ? (key.len + 2) / 3 * 4 + 1 : key.len)); - req->type = type; - req->pending = (h2o_linklist_t){NULL}; - req->inflight = (h2o_linklist_t){NULL}; - memset(&req->data, 0, sizeof(req->data)); - if (ctx->prefix.len != 0) - memcpy(req->key.base, ctx->prefix.base, ctx->prefix.len); - req->key.len = ctx->prefix.len; - if (encode_key) { - req->key.len += h2o_base64_encode(req->key.base + req->key.len, key.base, key.len, 1); - } else { - memcpy(req->key.base + req->key.len, key.base, key.len); - req->key.len += key.len; - } - return req; -} - -static void free_req(h2o_memcached_req_t *req) -{ - assert(!h2o_linklist_is_linked(&req->pending)); - switch (req->type) { - case REQ_TYPE_GET: - assert(!h2o_linklist_is_linked(&req->data.get.message.link)); - h2o_mem_set_secure(req->data.get.value.base, 0, req->data.get.value.len); - free(req->data.get.value.base); - break; - case REQ_TYPE_SET: - h2o_mem_set_secure(req->data.set.value.base, 0, req->data.set.value.len); - free(req->data.set.value.base); - break; - case REQ_TYPE_DELETE: - break; - default: - assert(!"FIXME"); - break; - } - free(req); -} - -static void discard_req(h2o_memcached_req_t *req) -{ - switch (req->type) { - case REQ_TYPE_GET: - h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message); - break; - default: - free_req(req); - break; - } -} - -static h2o_memcached_req_t *pop_inflight(struct st_h2o_memcached_conn_t *conn, uint32_t serial) -{ - h2o_memcached_req_t *req; - - pthread_mutex_lock(&conn->mutex); - - if (conn->yrmcds.text_mode) { - /* in text mode, responses are returned in order (and we may receive responses for commands other than GET) */ - if (!h2o_linklist_is_empty(&conn->inflight)) { - req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, conn->inflight.next); - assert(req->type == REQ_TYPE_GET); - if (req->data.get.serial == serial) - goto Found; - } - } else { - /* in binary mode, responses are received out-of-order (and we would only recieve responses for GET) */ - h2o_linklist_t *node; - for (node = conn->inflight.next; node != &conn->inflight; node = node->next) { - req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, node); - assert(req->type == REQ_TYPE_GET); - if (req->data.get.serial == serial) - goto Found; - } - } - - /* not found */ - pthread_mutex_unlock(&conn->mutex); - return NULL; - -Found: - h2o_linklist_unlink(&req->inflight); - pthread_mutex_unlock(&conn->mutex); - return req; -} - -static void *writer_main(void *_conn) -{ - struct st_h2o_memcached_conn_t *conn = _conn; - yrmcds_error err; - - pthread_mutex_lock(&conn->ctx->mutex); - - while (!__sync_add_and_fetch(&conn->writer_exit_requested, 0)) { - while (!h2o_linklist_is_empty(&conn->ctx->pending)) { - h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, pending, conn->ctx->pending.next); - h2o_linklist_unlink(&req->pending); - pthread_mutex_unlock(&conn->ctx->mutex); - - switch (req->type) { - case REQ_TYPE_GET: - pthread_mutex_lock(&conn->mutex); - h2o_linklist_insert(&conn->inflight, &req->inflight); - pthread_mutex_unlock(&conn->mutex); - if ((err = yrmcds_get(&conn->yrmcds, req->key.base, req->key.len, 0, &req->data.get.serial)) != YRMCDS_OK) - goto Error; - break; - case REQ_TYPE_SET: - err = yrmcds_set(&conn->yrmcds, req->key.base, req->key.len, req->data.set.value.base, req->data.set.value.len, 0, - req->data.set.expiration, 0, !conn->yrmcds.text_mode, NULL); - discard_req(req); - if (err != YRMCDS_OK) - goto Error; - break; - case REQ_TYPE_DELETE: - err = yrmcds_remove(&conn->yrmcds, req->key.base, req->key.len, !conn->yrmcds.text_mode, NULL); - discard_req(req); - if (err != YRMCDS_OK) - goto Error; - break; - default: - fprintf(stderr, "[lib/common/memcached.c] unknown type:%d\n", (int)req->type); - err = YRMCDS_NOT_IMPLEMENTED; - goto Error; - } - - pthread_mutex_lock(&conn->ctx->mutex); - } - pthread_cond_wait(&conn->ctx->cond, &conn->ctx->mutex); - } - - pthread_mutex_unlock(&conn->ctx->mutex); - return NULL; - -Error: - fprintf(stderr, "[lib/common/memcached.c] failed to send request; %s\n", yrmcds_strerror(err)); - /* doc says the call can be used to interrupt yrmcds_recv */ - yrmcds_shutdown(&conn->yrmcds); - - return NULL; -} - -static void connect_to_server(h2o_memcached_context_t *ctx, yrmcds *yrmcds) -{ - size_t failcnt; - yrmcds_error err; - - for (failcnt = 0; (err = yrmcds_connect(yrmcds, ctx->host, ctx->port)) != YRMCDS_OK; ++failcnt) { - if (failcnt == 0) { - fprintf(stderr, "[lib/common/memcached.c] failed to connect to memcached at %s:%" PRIu16 ", %s\n", ctx->host, ctx->port, - yrmcds_strerror(err)); - } - ++failcnt; - usleep(2000000 + h2o_rand() % 3000000); /* sleep 2 to 5 seconds */ - } - /* connected */ - if (ctx->text_protocol) - yrmcds_text_mode(yrmcds); - fprintf(stderr, "[lib/common/memcached.c] connected to memcached at %s:%" PRIu16 "\n", ctx->host, ctx->port); -} - -static void reader_main(h2o_memcached_context_t *ctx) -{ - struct st_h2o_memcached_conn_t conn = {ctx, {0}, PTHREAD_MUTEX_INITIALIZER, {&conn.inflight, &conn.inflight}, 0}; - pthread_t writer_thread; - yrmcds_response resp; - yrmcds_error err; - - /* connect to server and start the writer thread */ - connect_to_server(conn.ctx, &conn.yrmcds); - if (pthread_create(&writer_thread, NULL, writer_main, &conn) != 0) { - perror("pthread_create"); - abort(); - } - - pthread_mutex_lock(&conn.ctx->mutex); - ++conn.ctx->num_threads_connected; - pthread_mutex_unlock(&conn.ctx->mutex); - - /* receive data until an error occurs */ - while (1) { - if ((err = yrmcds_recv(&conn.yrmcds, &resp)) != YRMCDS_OK) { - fprintf(stderr, "[lib/common/memcached.c] yrmcds_recv:%s\n", yrmcds_strerror(err)); - break; - } - h2o_memcached_req_t *req = pop_inflight(&conn, resp.serial); - if (req == NULL) { - if (conn.yrmcds.text_mode) - continue; - fprintf(stderr, "[lib/common/memcached.c] received unexpected serial\n"); - break; - } - if (resp.status == YRMCDS_STATUS_OK) { - req->data.get.value = h2o_iovec_init(h2o_mem_alloc(resp.data_len), resp.data_len); - memcpy(req->data.get.value.base, resp.data, resp.data_len); - h2o_mem_set_secure((void *)resp.data, 0, resp.data_len); - } - h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message); - } - - /* send error to all the reqs in-flight */ - pthread_mutex_lock(&conn.mutex); - while (!h2o_linklist_is_empty(&conn.inflight)) { - h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, conn.inflight.next); - h2o_linklist_unlink(&req->inflight); - assert(req->type == REQ_TYPE_GET); - h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message); - } - pthread_mutex_unlock(&conn.mutex); - - /* stop the writer thread */ - __sync_add_and_fetch(&conn.writer_exit_requested, 1); - pthread_mutex_lock(&conn.ctx->mutex); - pthread_cond_broadcast(&conn.ctx->cond); - pthread_mutex_unlock(&conn.ctx->mutex); - pthread_join(writer_thread, NULL); - - /* decrement num_threads_connected, and discard all the pending requests if no connections are alive */ - pthread_mutex_lock(&conn.ctx->mutex); - if (--conn.ctx->num_threads_connected == 0) { - while (!h2o_linklist_is_empty(&conn.ctx->pending)) { - h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, pending, conn.ctx->pending.next); - h2o_linklist_unlink(&req->pending); - discard_req(req); - } - } - pthread_mutex_unlock(&conn.ctx->mutex); - - /* close the connection */ - yrmcds_close(&conn.yrmcds); -} - -static void *thread_main(void *_ctx) -{ - h2o_memcached_context_t *ctx = _ctx; - - while (1) - reader_main(ctx); - return NULL; -} - -static void dispatch(h2o_memcached_context_t *ctx, h2o_memcached_req_t *req) -{ - pthread_mutex_lock(&ctx->mutex); - - if (ctx->num_threads_connected != 0) { - h2o_linklist_insert(&ctx->pending, &req->pending); - pthread_cond_signal(&ctx->cond); - } else { - discard_req(req); - } - - pthread_mutex_unlock(&ctx->mutex); -} - -void h2o_memcached_receiver(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages) -{ - while (!h2o_linklist_is_empty(messages)) { - h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, data.get.message.link, messages->next); - h2o_linklist_unlink(&req->data.get.message.link); - assert(req->type == REQ_TYPE_GET); - if (req->data.get.cb != NULL) { - if (req->data.get.value_is_encoded && req->data.get.value.len != 0) { - h2o_iovec_t decoded = h2o_decode_base64url(NULL, req->data.get.value.base, req->data.get.value.len); - h2o_mem_set_secure(req->data.get.value.base, 0, req->data.get.value.len); - free(req->data.get.value.base); - req->data.get.value = decoded; - } - req->data.get.cb(req->data.get.value, req->data.get.cb_data); - } - free_req(req); - } -} - -h2o_memcached_req_t *h2o_memcached_get(h2o_memcached_context_t *ctx, h2o_multithread_receiver_t *receiver, h2o_iovec_t key, - h2o_memcached_get_cb cb, void *cb_data, int flags) -{ - h2o_memcached_req_t *req = create_req(ctx, REQ_TYPE_GET, key, (flags & H2O_MEMCACHED_ENCODE_KEY) != 0); - req->data.get.receiver = receiver; - req->data.get.cb = cb; - req->data.get.cb_data = cb_data; - req->data.get.value_is_encoded = (flags & H2O_MEMCACHED_ENCODE_VALUE) != 0; - dispatch(ctx, req); - return req; -} - -void h2o_memcached_cancel_get(h2o_memcached_context_t *ctx, h2o_memcached_req_t *req) -{ - int do_free = 0; - - pthread_mutex_lock(&ctx->mutex); - req->data.get.cb = NULL; - if (h2o_linklist_is_linked(&req->pending)) { - h2o_linklist_unlink(&req->pending); - do_free = 1; - } - pthread_mutex_unlock(&ctx->mutex); - - if (do_free) - free_req(req); -} - -void h2o_memcached_set(h2o_memcached_context_t *ctx, h2o_iovec_t key, h2o_iovec_t value, uint32_t expiration, int flags) -{ - h2o_memcached_req_t *req = create_req(ctx, REQ_TYPE_SET, key, (flags & H2O_MEMCACHED_ENCODE_KEY) != 0); - if ((flags & H2O_MEMCACHED_ENCODE_VALUE) != 0) { - req->data.set.value.base = h2o_mem_alloc((value.len + 2) / 3 * 4 + 1); - req->data.set.value.len = h2o_base64_encode(req->data.set.value.base, value.base, value.len, 1); - } else { - req->data.set.value = h2o_iovec_init(h2o_mem_alloc(value.len), value.len); - memcpy(req->data.set.value.base, value.base, value.len); - } - req->data.set.expiration = expiration; - dispatch(ctx, req); -} - -void h2o_memcached_delete(h2o_memcached_context_t *ctx, h2o_iovec_t key, int flags) -{ - h2o_memcached_req_t *req = create_req(ctx, REQ_TYPE_DELETE, key, (flags & H2O_MEMCACHED_ENCODE_KEY) != 0); - dispatch(ctx, req); -} - -h2o_memcached_context_t *h2o_memcached_create_context(const char *host, uint16_t port, int text_protocol, size_t num_threads, - const char *prefix) -{ - h2o_memcached_context_t *ctx = h2o_mem_alloc(sizeof(*ctx)); - - pthread_mutex_init(&ctx->mutex, NULL); - pthread_cond_init(&ctx->cond, NULL); - h2o_linklist_init_anchor(&ctx->pending); - ctx->num_threads_connected = 0; - ctx->host = h2o_strdup(NULL, host, SIZE_MAX).base; - ctx->port = port; - ctx->text_protocol = text_protocol; - ctx->prefix = h2o_strdup(NULL, prefix, SIZE_MAX); - - { /* start the threads */ - pthread_t tid; - pthread_attr_t attr; - size_t i; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, 1); - for (i = 0; i != num_threads; ++i) - h2o_multithread_create_thread(&tid, &attr, thread_main, ctx); - pthread_attr_destroy(&attr); - } - - return ctx; -} diff --git a/web/server/h2o/libh2o/lib/common/memory.c b/web/server/h2o/libh2o/lib/common/memory.c deleted file mode 100644 index ba9f2dba2..000000000 --- a/web/server/h2o/libh2o/lib/common/memory.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "h2o/memory.h" - -#if defined(__linux__) -#define USE_POSIX_FALLOCATE 1 -#elif __FreeBSD__ >= 9 -#define USE_POSIX_FALLOCATE 1 -#elif __NetBSD__ >= 7 -#define USE_POSIX_FALLOCATE 1 -#else -#define USE_POSIX_FALLOCATE 0 -#endif - -struct st_h2o_mem_recycle_chunk_t { - struct st_h2o_mem_recycle_chunk_t *next; -}; - -struct st_h2o_mem_pool_chunk_t { - struct st_h2o_mem_pool_chunk_t *next; - size_t _dummy; /* align to 2*sizeof(void*) */ - char bytes[4096 - sizeof(void *) * 2]; -}; - -struct st_h2o_mem_pool_direct_t { - struct st_h2o_mem_pool_direct_t *next; - size_t _dummy; /* align to 2*sizeof(void*) */ - char bytes[1]; -}; - -struct st_h2o_mem_pool_shared_ref_t { - struct st_h2o_mem_pool_shared_ref_t *next; - struct st_h2o_mem_pool_shared_entry_t *entry; -}; - -void *(*h2o_mem__set_secure)(void *, int, size_t) = memset; - -static __thread h2o_mem_recycle_t mempool_allocator = {16}; - -void h2o__fatal(const char *msg) -{ - fprintf(stderr, "fatal:%s\n", msg); - abort(); -} - -void *h2o_mem_alloc_recycle(h2o_mem_recycle_t *allocator, size_t sz) -{ - struct st_h2o_mem_recycle_chunk_t *chunk; - if (allocator->cnt == 0) - return h2o_mem_alloc(sz); - /* detach and return the pooled pointer */ - chunk = allocator->_link; - assert(chunk != NULL); - allocator->_link = chunk->next; - --allocator->cnt; - return chunk; -} - -void h2o_mem_free_recycle(h2o_mem_recycle_t *allocator, void *p) -{ - struct st_h2o_mem_recycle_chunk_t *chunk; - if (allocator->cnt == allocator->max) { - free(p); - return; - } - /* register the pointer to the pool */ - chunk = p; - chunk->next = allocator->_link; - allocator->_link = chunk; - ++allocator->cnt; -} - -void h2o_mem_init_pool(h2o_mem_pool_t *pool) -{ - pool->chunks = NULL; - pool->chunk_offset = sizeof(pool->chunks->bytes); - pool->directs = NULL; - pool->shared_refs = NULL; -} - -void h2o_mem_clear_pool(h2o_mem_pool_t *pool) -{ - /* release the refcounted chunks */ - if (pool->shared_refs != NULL) { - struct st_h2o_mem_pool_shared_ref_t *ref = pool->shared_refs; - do { - h2o_mem_release_shared(ref->entry->bytes); - } while ((ref = ref->next) != NULL); - pool->shared_refs = NULL; - } - /* release the direct chunks */ - if (pool->directs != NULL) { - struct st_h2o_mem_pool_direct_t *direct = pool->directs, *next; - do { - next = direct->next; - free(direct); - } while ((direct = next) != NULL); - pool->directs = NULL; - } - /* free chunks, and reset the first chunk */ - while (pool->chunks != NULL) { - struct st_h2o_mem_pool_chunk_t *next = pool->chunks->next; - h2o_mem_free_recycle(&mempool_allocator, pool->chunks); - pool->chunks = next; - } - pool->chunk_offset = sizeof(pool->chunks->bytes); -} - -void *h2o_mem_alloc_pool(h2o_mem_pool_t *pool, size_t sz) -{ - void *ret; - - if (sz >= sizeof(pool->chunks->bytes) / 4) { - /* allocate large requests directly */ - struct st_h2o_mem_pool_direct_t *newp = h2o_mem_alloc(offsetof(struct st_h2o_mem_pool_direct_t, bytes) + sz); - newp->next = pool->directs; - pool->directs = newp; - return newp->bytes; - } - - /* return a valid pointer even for 0 sized allocs */ - if (sz == 0) - sz = 1; - - /* 16-bytes rounding */ - sz = (sz + 15) & ~15; - if (sizeof(pool->chunks->bytes) - pool->chunk_offset < sz) { - /* allocate new chunk */ - struct st_h2o_mem_pool_chunk_t *newp = h2o_mem_alloc_recycle(&mempool_allocator, sizeof(*newp)); - newp->next = pool->chunks; - pool->chunks = newp; - pool->chunk_offset = 0; - } - - ret = pool->chunks->bytes + pool->chunk_offset; - pool->chunk_offset += sz; - return ret; -} - -static void link_shared(h2o_mem_pool_t *pool, struct st_h2o_mem_pool_shared_entry_t *entry) -{ - struct st_h2o_mem_pool_shared_ref_t *ref = h2o_mem_alloc_pool(pool, sizeof(struct st_h2o_mem_pool_shared_ref_t)); - ref->entry = entry; - ref->next = pool->shared_refs; - pool->shared_refs = ref; -} - -void *h2o_mem_alloc_shared(h2o_mem_pool_t *pool, size_t sz, void (*dispose)(void *)) -{ - struct st_h2o_mem_pool_shared_entry_t *entry = h2o_mem_alloc(offsetof(struct st_h2o_mem_pool_shared_entry_t, bytes) + sz); - entry->refcnt = 1; - entry->dispose = dispose; - if (pool != NULL) - link_shared(pool, entry); - return entry->bytes; -} - -void h2o_mem_link_shared(h2o_mem_pool_t *pool, void *p) -{ - h2o_mem_addref_shared(p); - link_shared(pool, H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p)); -} - -static size_t topagesize(size_t capacity) -{ - size_t pagesize = getpagesize(); - return (offsetof(h2o_buffer_t, _buf) + capacity + pagesize - 1) / pagesize * pagesize; -} - -void h2o_buffer__do_free(h2o_buffer_t *buffer) -{ - /* caller should assert that the buffer is not part of the prototype */ - if (buffer->capacity == buffer->_prototype->_initial_buf.capacity) { - h2o_mem_free_recycle(&buffer->_prototype->allocator, buffer); - } else if (buffer->_fd != -1) { - close(buffer->_fd); - munmap((void *)buffer, topagesize(buffer->capacity)); - } else { - free(buffer); - } -} - -h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee) -{ - h2o_buffer_t *inbuf = *_inbuf; - h2o_iovec_t ret; - - if (inbuf->bytes == NULL) { - h2o_buffer_prototype_t *prototype = H2O_STRUCT_FROM_MEMBER(h2o_buffer_prototype_t, _initial_buf, inbuf); - if (min_guarantee <= prototype->_initial_buf.capacity) { - min_guarantee = prototype->_initial_buf.capacity; - inbuf = h2o_mem_alloc_recycle(&prototype->allocator, offsetof(h2o_buffer_t, _buf) + min_guarantee); - } else { - inbuf = h2o_mem_alloc(offsetof(h2o_buffer_t, _buf) + min_guarantee); - } - *_inbuf = inbuf; - inbuf->size = 0; - inbuf->bytes = inbuf->_buf; - inbuf->capacity = min_guarantee; - inbuf->_prototype = prototype; - inbuf->_fd = -1; - } else { - if (min_guarantee <= inbuf->capacity - inbuf->size - (inbuf->bytes - inbuf->_buf)) { - /* ok */ - } else if ((inbuf->size + min_guarantee) * 2 <= inbuf->capacity) { - /* the capacity should be less than or equal to 2 times of: size + guarantee */ - memmove(inbuf->_buf, inbuf->bytes, inbuf->size); - inbuf->bytes = inbuf->_buf; - } else { - size_t new_capacity = inbuf->capacity; - do { - new_capacity *= 2; - } while (new_capacity - inbuf->size < min_guarantee); - if (inbuf->_prototype->mmap_settings != NULL && inbuf->_prototype->mmap_settings->threshold <= new_capacity) { - size_t new_allocsize = topagesize(new_capacity); - int fd; - h2o_buffer_t *newp; - if (inbuf->_fd == -1) { - char *tmpfn = alloca(strlen(inbuf->_prototype->mmap_settings->fn_template) + 1); - strcpy(tmpfn, inbuf->_prototype->mmap_settings->fn_template); - if ((fd = mkstemp(tmpfn)) == -1) { - fprintf(stderr, "failed to create temporary file:%s:%s\n", tmpfn, strerror(errno)); - goto MapError; - } - unlink(tmpfn); - } else { - fd = inbuf->_fd; - } - int fallocate_ret; -#if USE_POSIX_FALLOCATE - fallocate_ret = posix_fallocate(fd, 0, new_allocsize); -#else - fallocate_ret = ftruncate(fd, new_allocsize); -#endif - if (fallocate_ret != 0) { - perror("failed to resize temporary file"); - goto MapError; - } - if ((newp = (void *)mmap(NULL, new_allocsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { - perror("mmap failed"); - goto MapError; - } - if (inbuf->_fd == -1) { - /* copy data (moving from malloc to mmap) */ - newp->size = inbuf->size; - newp->bytes = newp->_buf; - newp->capacity = new_capacity; - newp->_prototype = inbuf->_prototype; - newp->_fd = fd; - memcpy(newp->_buf, inbuf->bytes, inbuf->size); - h2o_buffer__do_free(inbuf); - *_inbuf = inbuf = newp; - } else { - /* munmap */ - size_t offset = inbuf->bytes - inbuf->_buf; - munmap((void *)inbuf, topagesize(inbuf->capacity)); - *_inbuf = inbuf = newp; - inbuf->capacity = new_capacity; - inbuf->bytes = newp->_buf + offset; - } - } else { - h2o_buffer_t *newp = h2o_mem_alloc(offsetof(h2o_buffer_t, _buf) + new_capacity); - newp->size = inbuf->size; - newp->bytes = newp->_buf; - newp->capacity = new_capacity; - newp->_prototype = inbuf->_prototype; - newp->_fd = -1; - memcpy(newp->_buf, inbuf->bytes, inbuf->size); - h2o_buffer__do_free(inbuf); - *_inbuf = inbuf = newp; - } - } - } - - ret.base = inbuf->bytes + inbuf->size; - ret.len = inbuf->_buf + inbuf->capacity - ret.base; - - return ret; - -MapError: - ret.base = NULL; - ret.len = 0; - return ret; -} - -void h2o_buffer_consume(h2o_buffer_t **_inbuf, size_t delta) -{ - h2o_buffer_t *inbuf = *_inbuf; - - if (delta != 0) { - assert(inbuf->bytes != NULL); - if (inbuf->size == delta) { - *_inbuf = &inbuf->_prototype->_initial_buf; - h2o_buffer__do_free(inbuf); - } else { - inbuf->size -= delta; - inbuf->bytes += delta; - } - } -} - -void h2o_buffer__dispose_linked(void *p) -{ - h2o_buffer_t **buf = p; - h2o_buffer_dispose(buf); -} - -void h2o_vector__expand(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t element_size, size_t new_capacity) -{ - void *new_entries; - assert(vector->capacity < new_capacity); - if (vector->capacity == 0) - vector->capacity = 4; - while (vector->capacity < new_capacity) - vector->capacity *= 2; - if (pool != NULL) { - new_entries = h2o_mem_alloc_pool(pool, element_size * vector->capacity); - h2o_memcpy(new_entries, vector->entries, element_size * vector->size); - } else { - new_entries = h2o_mem_realloc(vector->entries, element_size * vector->capacity); - } - vector->entries = new_entries; -} - -void h2o_mem_swap(void *_x, void *_y, size_t len) -{ - char *x = _x, *y = _y; - char buf[256]; - - while (len != 0) { - size_t blocksz = len < sizeof(buf) ? len : sizeof(buf); - memcpy(buf, x, blocksz); - memcpy(x, y, blocksz); - memcpy(y, buf, blocksz); - len -= blocksz; - x += blocksz; - y += blocksz; - } -} - -void h2o_dump_memory(FILE *fp, const char *buf, size_t len) -{ - size_t i, j; - - for (i = 0; i < len; i += 16) { - fprintf(fp, "%08zx", i); - for (j = 0; j != 16; ++j) { - if (i + j < len) - fprintf(fp, " %02x", (int)(unsigned char)buf[i + j]); - else - fprintf(fp, " "); - } - fprintf(fp, " "); - for (j = 0; j != 16 && i + j < len; ++j) { - int ch = buf[i + j]; - fputc(' ' <= ch && ch < 0x7f ? ch : '.', fp); - } - fprintf(fp, "\n"); - } -} - -void h2o_append_to_null_terminated_list(void ***list, void *element) -{ - size_t cnt; - - for (cnt = 0; (*list)[cnt] != NULL; ++cnt) - ; - *list = h2o_mem_realloc(*list, (cnt + 2) * sizeof(void *)); - (*list)[cnt++] = element; - (*list)[cnt] = NULL; -} diff --git a/web/server/h2o/libh2o/lib/common/multithread.c b/web/server/h2o/libh2o/lib/common/multithread.c deleted file mode 100644 index b4e8ba836..000000000 --- a/web/server/h2o/libh2o/lib/common/multithread.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2015-2016 DeNA Co., Ltd., Kazuho Oku, Tatsuhiko Kubo, - * Chul-Woong Yang - * - * 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 "cloexec.h" -#include "h2o/multithread.h" - -struct st_h2o_multithread_queue_t { -#if H2O_USE_LIBUV - uv_async_t async; -#else - struct { - int write; - h2o_socket_t *read; - } async; -#endif - pthread_mutex_t mutex; - struct { - h2o_linklist_t active; - h2o_linklist_t inactive; - } receivers; -}; - -static void queue_cb(h2o_multithread_queue_t *queue) -{ - pthread_mutex_lock(&queue->mutex); - - while (!h2o_linklist_is_empty(&queue->receivers.active)) { - h2o_multithread_receiver_t *receiver = - H2O_STRUCT_FROM_MEMBER(h2o_multithread_receiver_t, _link, queue->receivers.active.next); - /* detach all the messages from the receiver */ - h2o_linklist_t messages; - h2o_linklist_init_anchor(&messages); - h2o_linklist_insert_list(&messages, &receiver->_messages); - /* relink the receiver to the inactive list */ - h2o_linklist_unlink(&receiver->_link); - h2o_linklist_insert(&queue->receivers.inactive, &receiver->_link); - - /* dispatch the messages */ - pthread_mutex_unlock(&queue->mutex); - receiver->cb(receiver, &messages); - assert(h2o_linklist_is_empty(&messages)); - pthread_mutex_lock(&queue->mutex); - } - - pthread_mutex_unlock(&queue->mutex); -} - -#ifdef H2O_NO_64BIT_ATOMICS -pthread_mutex_t h2o_conn_id_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -#if H2O_USE_LIBUV -#else - -#include -#include -#include - -static void on_read(h2o_socket_t *sock, const char *err) -{ - if (err != NULL) { - fprintf(stderr, "pipe error\n"); - abort(); - } - - h2o_buffer_consume(&sock->input, sock->input->size); - queue_cb(sock->data); -} - -static void init_async(h2o_multithread_queue_t *queue, h2o_loop_t *loop) -{ - int fds[2]; - - if (cloexec_pipe(fds) != 0) { - perror("pipe"); - abort(); - } - fcntl(fds[1], F_SETFL, O_NONBLOCK); - queue->async.write = fds[1]; - queue->async.read = h2o_evloop_socket_create(loop, fds[0], 0); - queue->async.read->data = queue; - h2o_socket_read_start(queue->async.read, on_read); -} - -#endif - -h2o_multithread_queue_t *h2o_multithread_create_queue(h2o_loop_t *loop) -{ - h2o_multithread_queue_t *queue = h2o_mem_alloc(sizeof(*queue)); - memset(queue, 0, sizeof(*queue)); - -#if H2O_USE_LIBUV - uv_async_init(loop, &queue->async, (uv_async_cb)queue_cb); -#else - init_async(queue, loop); -#endif - pthread_mutex_init(&queue->mutex, NULL); - h2o_linklist_init_anchor(&queue->receivers.active); - h2o_linklist_init_anchor(&queue->receivers.inactive); - - return queue; -} - -void h2o_multithread_destroy_queue(h2o_multithread_queue_t *queue) -{ - assert(h2o_linklist_is_empty(&queue->receivers.active)); - assert(h2o_linklist_is_empty(&queue->receivers.inactive)); -#if H2O_USE_LIBUV - uv_close((uv_handle_t *)&queue->async, (uv_close_cb)free); -#else - h2o_socket_read_stop(queue->async.read); - h2o_socket_close(queue->async.read); - close(queue->async.write); -#endif - pthread_mutex_destroy(&queue->mutex); -} - -void h2o_multithread_register_receiver(h2o_multithread_queue_t *queue, h2o_multithread_receiver_t *receiver, - h2o_multithread_receiver_cb cb) -{ - receiver->queue = queue; - receiver->_link = (h2o_linklist_t){NULL}; - h2o_linklist_init_anchor(&receiver->_messages); - receiver->cb = cb; - - pthread_mutex_lock(&queue->mutex); - h2o_linklist_insert(&queue->receivers.inactive, &receiver->_link); - pthread_mutex_unlock(&queue->mutex); -} - -void h2o_multithread_unregister_receiver(h2o_multithread_queue_t *queue, h2o_multithread_receiver_t *receiver) -{ - assert(queue == receiver->queue); - assert(h2o_linklist_is_empty(&receiver->_messages)); - pthread_mutex_lock(&queue->mutex); - h2o_linklist_unlink(&receiver->_link); - pthread_mutex_unlock(&queue->mutex); -} - -void h2o_multithread_send_message(h2o_multithread_receiver_t *receiver, h2o_multithread_message_t *message) -{ - int do_send = 0; - - pthread_mutex_lock(&receiver->queue->mutex); - if (message != NULL) { - assert(!h2o_linklist_is_linked(&message->link)); - if (h2o_linklist_is_empty(&receiver->_messages)) { - h2o_linklist_unlink(&receiver->_link); - h2o_linklist_insert(&receiver->queue->receivers.active, &receiver->_link); - do_send = 1; - } - h2o_linklist_insert(&receiver->_messages, &message->link); - } else { - if (h2o_linklist_is_empty(&receiver->_messages)) - do_send = 1; - } - pthread_mutex_unlock(&receiver->queue->mutex); - - if (do_send) { -#if H2O_USE_LIBUV - uv_async_send(&receiver->queue->async); -#else - while (write(receiver->queue->async.write, "", 1) == -1 && errno == EINTR) - ; -#endif - } -} - -void h2o_multithread_create_thread(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *arg) -{ - if (pthread_create(tid, attr, func, arg) != 0) { - perror("pthread_create"); - abort(); - } -} - -void h2o_sem_init(h2o_sem_t *sem, ssize_t capacity) -{ - pthread_mutex_init(&sem->_mutex, NULL); - pthread_cond_init(&sem->_cond, NULL); - sem->_cur = capacity; - sem->_capacity = capacity; -} - -void h2o_sem_destroy(h2o_sem_t *sem) -{ - assert(sem->_cur == sem->_capacity); - pthread_cond_destroy(&sem->_cond); - pthread_mutex_destroy(&sem->_mutex); -} - -void h2o_sem_wait(h2o_sem_t *sem) -{ - pthread_mutex_lock(&sem->_mutex); - while (sem->_cur <= 0) - pthread_cond_wait(&sem->_cond, &sem->_mutex); - --sem->_cur; - pthread_mutex_unlock(&sem->_mutex); -} - -void h2o_sem_post(h2o_sem_t *sem) -{ - pthread_mutex_lock(&sem->_mutex); - ++sem->_cur; - pthread_cond_signal(&sem->_cond); - pthread_mutex_unlock(&sem->_mutex); -} - -void h2o_sem_set_capacity(h2o_sem_t *sem, ssize_t new_capacity) -{ - pthread_mutex_lock(&sem->_mutex); - sem->_cur += new_capacity - sem->_capacity; - sem->_capacity = new_capacity; - pthread_cond_broadcast(&sem->_cond); - pthread_mutex_unlock(&sem->_mutex); -} - -/* barrier */ - -void h2o_barrier_init(h2o_barrier_t *barrier, size_t count) -{ - pthread_mutex_init(&barrier->_mutex, NULL); - pthread_cond_init(&barrier->_cond, NULL); - barrier->_count = count; -} - -int h2o_barrier_wait(h2o_barrier_t *barrier) -{ - int ret; - pthread_mutex_lock(&barrier->_mutex); - barrier->_count--; - if (barrier->_count == 0) { - pthread_cond_broadcast(&barrier->_cond); - ret = 1; - } else { - while (barrier->_count) - pthread_cond_wait(&barrier->_cond, &barrier->_mutex); - ret = 0; - } - pthread_mutex_unlock(&barrier->_mutex); - return ret; -} - -int h2o_barrier_done(h2o_barrier_t *barrier) -{ - return __sync_add_and_fetch(&barrier->_count, 0) == 0; -} - -void h2o_barrier_destroy(h2o_barrier_t *barrier) -{ - pthread_mutex_destroy(&barrier->_mutex); - pthread_cond_destroy(&barrier->_cond); -} diff --git a/web/server/h2o/libh2o/lib/common/serverutil.c b/web/server/h2o/libh2o/lib/common/serverutil.c deleted file mode 100644 index 8226f6efc..000000000 --- a/web/server/h2o/libh2o/lib/common/serverutil.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Nick Desaulniers - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_SC_NPROCESSORS_ONLN) -#include -#endif -#include "cloexec.h" -#include "h2o/memory.h" -#include "h2o/serverutil.h" -#include "h2o/socket.h" -#include "h2o/string_.h" - -void h2o_set_signal_handler(int signo, void (*cb)(int signo)) -{ - struct sigaction action; - - memset(&action, 0, sizeof(action)); - sigemptyset(&action.sa_mask); - action.sa_handler = cb; - sigaction(signo, &action, NULL); -} - -int h2o_setuidgid(const char *user) -{ - struct passwd pwbuf, *pw; - char buf[65536]; /* should be large enough */ - - errno = 0; - if (getpwnam_r(user, &pwbuf, buf, sizeof(buf), &pw) != 0) { - perror("getpwnam_r"); - return -1; - } - if (pw == NULL) { - fprintf(stderr, "unknown user:%s\n", user); - return -1; - } - if (setgid(pw->pw_gid) != 0) { - fprintf(stderr, "setgid(%d) failed:%s\n", (int)pw->pw_gid, strerror(errno)); - return -1; - } - if (initgroups(pw->pw_name, pw->pw_gid) != 0) { - fprintf(stderr, "initgroups(%s, %d) failed:%s\n", pw->pw_name, (int)pw->pw_gid, strerror(errno)); - return -1; - } - if (setuid(pw->pw_uid) != 0) { - fprintf(stderr, "setuid(%d) failed:%s\n", (int)pw->pw_uid, strerror(errno)); - return -1; - } - - return 0; -} - -size_t h2o_server_starter_get_fds(int **_fds) -{ - const char *ports_env, *start, *end, *eq; - size_t t; - H2O_VECTOR(int) fds = {NULL}; - - if ((ports_env = getenv("SERVER_STARTER_PORT")) == NULL) - return 0; - if (ports_env[0] == '\0') { - fprintf(stderr, "$SERVER_STARTER_PORT is empty\n"); - return SIZE_MAX; - } - - /* ports_env example: 127.0.0.1:80=3;/tmp/sock=4 */ - for (start = ports_env; *start != '\0'; start = *end == ';' ? end + 1 : end) { - if ((end = strchr(start, ';')) == NULL) - end = start + strlen(start); - if ((eq = memchr(start, '=', end - start)) == NULL) { - fprintf(stderr, "invalid $SERVER_STARTER_PORT, an element without `=` in: %s\n", ports_env); - goto Error; - } - if ((t = h2o_strtosize(eq + 1, end - eq - 1)) == SIZE_MAX) { - fprintf(stderr, "invalid file descriptor number in $SERVER_STARTER_PORT: %s\n", ports_env); - goto Error; - } - h2o_vector_reserve(NULL, &fds, fds.size + 1); - fds.entries[fds.size++] = (int)t; - } - - *_fds = fds.entries; - return fds.size; -Error: - free(fds.entries); - return SIZE_MAX; -} - -static char **build_spawn_env(void) -{ - extern char **environ; - size_t num; - - /* calculate number of envvars, as well as looking for H2O_ROOT= */ - for (num = 0; environ[num] != NULL; ++num) - if (strncmp(environ[num], "H2O_ROOT=", sizeof("H2O_ROOT=") - 1) == 0) - return NULL; - - /* not found */ - char **newenv = h2o_mem_alloc(sizeof(*newenv) * (num + 2) + sizeof("H2O_ROOT=" H2O_TO_STR(H2O_ROOT))); - memcpy(newenv, environ, sizeof(*newenv) * num); - newenv[num] = (char *)(newenv + num + 2); - newenv[num + 1] = NULL; - strcpy(newenv[num], "H2O_ROOT=" H2O_TO_STR(H2O_ROOT)); - - return newenv; -} - -pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked) -{ -#if defined(__linux__) - - /* posix_spawnp of Linux does not return error if the executable does not exist, see - * https://gist.github.com/kazuho/0c233e6f86d27d6e4f09 - */ - extern char **environ; - int pipefds[2] = {-1, -1}, errnum; - pid_t pid; - - /* create pipe, used for sending error codes */ - if (pipe2(pipefds, O_CLOEXEC) != 0) - goto Error; - - /* fork */ - if (!cloexec_mutex_is_locked) - pthread_mutex_lock(&cloexec_mutex); - if ((pid = fork()) == 0) { - /* in child process, map the file descriptors and execute; return the errnum through pipe if exec failed */ - if (mapped_fds != NULL) { - for (; *mapped_fds != -1; mapped_fds += 2) { - if (mapped_fds[0] != mapped_fds[1]) { - if (mapped_fds[1] != -1) - dup2(mapped_fds[0], mapped_fds[1]); - close(mapped_fds[0]); - } - } - } - char **env = build_spawn_env(); - if (env != NULL) - environ = env; - execvp(cmd, argv); - errnum = errno; - write(pipefds[1], &errnum, sizeof(errnum)); - _exit(EX_SOFTWARE); - } - if (!cloexec_mutex_is_locked) - pthread_mutex_unlock(&cloexec_mutex); - if (pid == -1) - goto Error; - - /* parent process */ - close(pipefds[1]); - pipefds[1] = -1; - ssize_t rret; - errnum = 0; - while ((rret = read(pipefds[0], &errnum, sizeof(errnum))) == -1 && errno == EINTR) - ; - if (rret != 0) { - /* spawn failed */ - while (waitpid(pid, NULL, 0) != pid) - ; - pid = -1; - errno = errnum; - goto Error; - } - - /* spawn succeeded */ - close(pipefds[0]); - return pid; - -Error: - errnum = errno; - if (pipefds[0] != -1) - close(pipefds[0]); - if (pipefds[1] != -1) - close(pipefds[1]); - errno = errnum; - return -1; - -#else - - posix_spawn_file_actions_t file_actions; - pid_t pid; - extern char **environ; - char **env = build_spawn_env(); - posix_spawn_file_actions_init(&file_actions); - if (mapped_fds != NULL) { - for (; *mapped_fds != -1; mapped_fds += 2) { - if (mapped_fds[1] != -1) - posix_spawn_file_actions_adddup2(&file_actions, mapped_fds[0], mapped_fds[1]); - posix_spawn_file_actions_addclose(&file_actions, mapped_fds[0]); - } - } - if (!cloexec_mutex_is_locked) - pthread_mutex_lock(&cloexec_mutex); - errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, env != NULL ? env : environ); - if (!cloexec_mutex_is_locked) - pthread_mutex_unlock(&cloexec_mutex); - free(env); - if (errno != 0) - return -1; - - return pid; - -#endif -} - -int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) -{ - int respfds[2] = {-1, -1}; - pid_t pid = -1; - int mutex_locked = 0, ret = -1; - - h2o_buffer_init(resp, &h2o_socket_buffer_prototype); - - pthread_mutex_lock(&cloexec_mutex); - mutex_locked = 1; - - /* create pipe for reading the result */ - if (pipe(respfds) != 0) - goto Exit; - if (fcntl(respfds[0], F_SETFD, O_CLOEXEC) < 0) - goto Exit; - - /* spawn */ - int mapped_fds[] = {respfds[1], 1, /* stdout of the child process is read from the pipe */ - -1}; - if ((pid = h2o_spawnp(cmd, argv, mapped_fds, 1)) == -1) - goto Exit; - close(respfds[1]); - respfds[1] = -1; - - pthread_mutex_unlock(&cloexec_mutex); - mutex_locked = 0; - - /* read the response from pipe */ - while (1) { - h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192); - ssize_t r; - while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) - ; - if (r <= 0) - break; - (*resp)->size += r; - } - -Exit: - if (mutex_locked) - pthread_mutex_unlock(&cloexec_mutex); - if (pid != -1) { - /* wait for the child to complete */ - pid_t r; - while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR) - ; - if (r == pid) { - /* success */ - ret = 0; - } - } - if (respfds[0] != -1) - close(respfds[0]); - if (respfds[1] != -1) - close(respfds[1]); - if (ret != 0) - h2o_buffer_dispose(resp); - - return ret; -} - -size_t h2o_numproc(void) -{ -#if defined(_SC_NPROCESSORS_ONLN) - return (size_t)sysconf(_SC_NPROCESSORS_ONLN); -#elif defined(CTL_HW) && defined(HW_AVAILCPU) - int name[] = {CTL_HW, HW_AVAILCPU}; - int ncpu; - size_t ncpu_sz = sizeof(ncpu); - if (sysctl(name, sizeof(name) / sizeof(name[0]), &ncpu, &ncpu_sz, NULL, 0) != 0 || sizeof(ncpu) != ncpu_sz) { - fprintf(stderr, "[ERROR] failed to obtain number of CPU cores, assuming as one\n"); - ncpu = 1; - } - return ncpu; -#else - return 1; -#endif -} diff --git a/web/server/h2o/libh2o/lib/common/socket.c b/web/server/h2o/libh2o/lib/common/socket.c deleted file mode 100644 index 5b1c37e04..000000000 --- a/web/server/h2o/libh2o/lib/common/socket.c +++ /dev/null @@ -1,1433 +0,0 @@ -/* - * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu - * - * 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 -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#endif -#if H2O_USE_PICOTLS -#include "picotls.h" -#endif -#include "h2o/socket.h" -#include "h2o/timeout.h" - -#if defined(__APPLE__) && defined(__clang__) -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - -#ifndef IOV_MAX -#define IOV_MAX UIO_MAXIOV -#endif - -/* kernel-headers bundled with Ubuntu 14.04 does not have the constant defined in netinet/tcp.h */ -#if defined(__linux__) && !defined(TCP_NOTSENT_LOWAT) -#define TCP_NOTSENT_LOWAT 25 -#endif - -#define OPENSSL_HOSTNAME_VALIDATION_LINKAGE static -#include "../../deps/ssl-conservatory/openssl/openssl_hostname_validation.c" - -struct st_h2o_socket_ssl_t { - SSL_CTX *ssl_ctx; - SSL *ossl; -#if H2O_USE_PICOTLS - ptls_t *ptls; -#endif - int *did_write_in_read; /* used for detecting and closing the connection upon renegotiation (FIXME implement renegotiation) */ - size_t record_overhead; - struct { - h2o_socket_cb cb; - union { - struct { - struct { - enum { - ASYNC_RESUMPTION_STATE_COMPLETE = 0, /* just pass thru */ - ASYNC_RESUMPTION_STATE_RECORD, /* record first input, restore SSL state if it changes to REQUEST_SENT - */ - ASYNC_RESUMPTION_STATE_REQUEST_SENT /* async request has been sent, and is waiting for response */ - } state; - SSL_SESSION *session_data; - } async_resumption; - } server; - struct { - char *server_name; - h2o_cache_t *session_cache; - h2o_iovec_t session_cache_key; - h2o_cache_hashcode_t session_cache_key_hash; - } client; - }; - } handshake; - struct { - h2o_buffer_t *encrypted; - } input; - struct { - H2O_VECTOR(h2o_iovec_t) bufs; - h2o_mem_pool_t pool; /* placed at the last */ - } output; -}; - -struct st_h2o_ssl_context_t { - SSL_CTX *ctx; - const h2o_iovec_t *protocols; - h2o_iovec_t _npn_list_of_protocols; -}; - -/* backend functions */ -static void do_dispose_socket(h2o_socket_t *sock); -static void do_write(h2o_socket_t *sock, h2o_iovec_t *bufs, size_t bufcnt, h2o_socket_cb cb); -static void do_read_start(h2o_socket_t *sock); -static void do_read_stop(h2o_socket_t *sock); -static int do_export(h2o_socket_t *_sock, h2o_socket_export_t *info); -static h2o_socket_t *do_import(h2o_loop_t *loop, h2o_socket_export_t *info); -static socklen_t get_peername_uncached(h2o_socket_t *sock, struct sockaddr *sa); - -/* internal functions called from the backend */ -static const char *decode_ssl_input(h2o_socket_t *sock); -static void on_write_complete(h2o_socket_t *sock, const char *err); - -#if H2O_USE_LIBUV -#include "socket/uv-binding.c.h" -#else -#include "socket/evloop.c.h" -#endif - -h2o_buffer_mmap_settings_t h2o_socket_buffer_mmap_settings = { - 32 * 1024 * 1024, /* 32MB, should better be greater than max frame size of HTTP2 for performance reasons */ - "/tmp/h2o.b.XXXXXX"}; - -__thread h2o_buffer_prototype_t h2o_socket_buffer_prototype = { - {16}, /* keep 16 recently used chunks */ - {H2O_SOCKET_INITIAL_INPUT_BUFFER_SIZE * 2}, /* minimum initial capacity */ - &h2o_socket_buffer_mmap_settings}; - -const char *h2o_socket_error_out_of_memory = "out of memory"; -const char *h2o_socket_error_io = "I/O error"; -const char *h2o_socket_error_closed = "socket closed by peer"; -const char *h2o_socket_error_conn_fail = "connection failure"; -const char *h2o_socket_error_ssl_no_cert = "no certificate"; -const char *h2o_socket_error_ssl_cert_invalid = "invalid certificate"; -const char *h2o_socket_error_ssl_cert_name_mismatch = "certificate name mismatch"; -const char *h2o_socket_error_ssl_decode = "SSL decode error"; - -static void (*resumption_get_async)(h2o_socket_t *sock, h2o_iovec_t session_id); -static void (*resumption_new)(h2o_iovec_t session_id, h2o_iovec_t session_data); - -static int read_bio(BIO *b, char *out, int len) -{ - h2o_socket_t *sock = BIO_get_data(b); - - if (len == 0) - return 0; - - if (sock->ssl->input.encrypted->size == 0) { - BIO_set_retry_read(b); - return -1; - } - - if (sock->ssl->input.encrypted->size < len) { - len = (int)sock->ssl->input.encrypted->size; - } - memcpy(out, sock->ssl->input.encrypted->bytes, len); - h2o_buffer_consume(&sock->ssl->input.encrypted, len); - - return len; -} - -static void write_ssl_bytes(h2o_socket_t *sock, const void *in, size_t len) -{ - if (len != 0) { - void *bytes_alloced = h2o_mem_alloc_pool(&sock->ssl->output.pool, len); - memcpy(bytes_alloced, in, len); - h2o_vector_reserve(&sock->ssl->output.pool, &sock->ssl->output.bufs, sock->ssl->output.bufs.size + 1); - sock->ssl->output.bufs.entries[sock->ssl->output.bufs.size++] = h2o_iovec_init(bytes_alloced, len); - } -} - -static int write_bio(BIO *b, const char *in, int len) -{ - h2o_socket_t *sock = BIO_get_data(b); - - /* FIXME no support for SSL renegotiation (yet) */ - if (sock->ssl->did_write_in_read != NULL) { - *sock->ssl->did_write_in_read = 1; - return -1; - } - - write_ssl_bytes(sock, in, len); - return len; -} - -static int puts_bio(BIO *b, const char *str) -{ - return write_bio(b, str, (int)strlen(str)); -} - -static long ctrl_bio(BIO *b, int cmd, long num, void *ptr) -{ - switch (cmd) { - case BIO_CTRL_GET_CLOSE: - return BIO_get_shutdown(b); - case BIO_CTRL_SET_CLOSE: - BIO_set_shutdown(b, (int)num); - return 1; - case BIO_CTRL_FLUSH: - return 1; - default: - return 0; - } -} - -static void setup_bio(h2o_socket_t *sock) -{ - static BIO_METHOD *bio_methods = NULL; - if (bio_methods == NULL) { - static pthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&init_lock); - if (bio_methods == NULL) { - BIO_METHOD *biom = BIO_meth_new(BIO_TYPE_FD, "h2o_socket"); - BIO_meth_set_write(biom, write_bio); - BIO_meth_set_read(biom, read_bio); - BIO_meth_set_puts(biom, puts_bio); - BIO_meth_set_ctrl(biom, ctrl_bio); - __sync_synchronize(); - bio_methods = biom; - } - pthread_mutex_unlock(&init_lock); - } - - BIO *bio = BIO_new(bio_methods); - if (bio == NULL) - h2o_fatal("no memory"); - BIO_set_data(bio, sock); - BIO_set_init(bio, 1); - SSL_set_bio(sock->ssl->ossl, bio, bio); -} - -const char *decode_ssl_input(h2o_socket_t *sock) -{ - assert(sock->ssl != NULL); - assert(sock->ssl->handshake.cb == NULL); - -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - if (sock->ssl->input.encrypted->size != 0) { - const char *src = sock->ssl->input.encrypted->bytes, *src_end = src + sock->ssl->input.encrypted->size; - h2o_iovec_t reserved; - ptls_buffer_t rbuf; - int ret; - if ((reserved = h2o_buffer_reserve(&sock->input, sock->ssl->input.encrypted->size)).base == NULL) - return h2o_socket_error_out_of_memory; - ptls_buffer_init(&rbuf, reserved.base, reserved.len); - do { - size_t consumed = src_end - src; - if ((ret = ptls_receive(sock->ssl->ptls, &rbuf, src, &consumed)) != 0) - break; - src += consumed; - } while (src != src_end); - h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size - (src_end - src)); - if (rbuf.is_allocated) { - if ((reserved = h2o_buffer_reserve(&sock->input, rbuf.off)).base == NULL) - return h2o_socket_error_out_of_memory; - memcpy(reserved.base, rbuf.base, rbuf.off); - sock->input->size += rbuf.off; - ptls_buffer_dispose(&rbuf); - } else { - sock->input->size += rbuf.off; - } - if (!(ret == 0 || ret == PTLS_ERROR_IN_PROGRESS)) - return h2o_socket_error_ssl_decode; - } - return NULL; - } -#endif - - while (sock->ssl->input.encrypted->size != 0 || SSL_pending(sock->ssl->ossl)) { - int rlen; - h2o_iovec_t buf = h2o_buffer_reserve(&sock->input, 4096); - if (buf.base == NULL) - return h2o_socket_error_out_of_memory; - { /* call SSL_read (while detecting SSL renegotiation and reporting it as error) */ - int did_write_in_read = 0; - sock->ssl->did_write_in_read = &did_write_in_read; - ERR_clear_error(); - rlen = SSL_read(sock->ssl->ossl, buf.base, (int)buf.len); - sock->ssl->did_write_in_read = NULL; - if (did_write_in_read) - return "ssl renegotiation not supported"; - } - if (rlen == -1) { - if (SSL_get_error(sock->ssl->ossl, rlen) != SSL_ERROR_WANT_READ) { - return h2o_socket_error_ssl_decode; - } - break; - } else if (rlen == 0) { - break; - } else { - sock->input->size += rlen; - } - } - - return 0; -} - -static void flush_pending_ssl(h2o_socket_t *sock, h2o_socket_cb cb) -{ - do_write(sock, sock->ssl->output.bufs.entries, sock->ssl->output.bufs.size, cb); -} - -static void clear_output_buffer(struct st_h2o_socket_ssl_t *ssl) -{ - memset(&ssl->output.bufs, 0, sizeof(ssl->output.bufs)); - h2o_mem_clear_pool(&ssl->output.pool); -} - -static void destroy_ssl(struct st_h2o_socket_ssl_t *ssl) -{ -#if H2O_USE_PICOTLS - if (ssl->ptls != NULL) { - ptls_free(ssl->ptls); - ssl->ptls = NULL; - } -#endif - if (ssl->ossl != NULL) { - if (!SSL_is_server(ssl->ossl)) { - free(ssl->handshake.client.server_name); - free(ssl->handshake.client.session_cache_key.base); - } - SSL_free(ssl->ossl); - ssl->ossl = NULL; - } - h2o_buffer_dispose(&ssl->input.encrypted); - clear_output_buffer(ssl); - free(ssl); -} - -static void dispose_socket(h2o_socket_t *sock, const char *err) -{ - void (*close_cb)(void *data); - void *close_cb_data; - - if (sock->ssl != NULL) { - destroy_ssl(sock->ssl); - sock->ssl = NULL; - } - h2o_buffer_dispose(&sock->input); - if (sock->_peername != NULL) { - free(sock->_peername); - sock->_peername = NULL; - } - - close_cb = sock->on_close.cb; - close_cb_data = sock->on_close.data; - - do_dispose_socket(sock); - - if (close_cb != NULL) - close_cb(close_cb_data); -} - -static void shutdown_ssl(h2o_socket_t *sock, const char *err) -{ - int ret; - - if (err != NULL) - goto Close; - - if (sock->_cb.write != NULL) { - /* note: libuv calls the write callback after the socket is closed by uv_close (with status set to 0 if the write succeeded) - */ - sock->_cb.write = NULL; - goto Close; - } - -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - ptls_buffer_t wbuf; - uint8_t wbuf_small[32]; - ptls_buffer_init(&wbuf, wbuf_small, sizeof(wbuf_small)); - if ((ret = ptls_send_alert(sock->ssl->ptls, &wbuf, PTLS_ALERT_LEVEL_WARNING, PTLS_ALERT_CLOSE_NOTIFY)) != 0) - goto Close; - write_ssl_bytes(sock, wbuf.base, wbuf.off); - ptls_buffer_dispose(&wbuf); - ret = 1; /* close the socket after sending close_notify */ - } else -#endif - if (sock->ssl->ossl != NULL) { - ERR_clear_error(); - if ((ret = SSL_shutdown(sock->ssl->ossl)) == -1) - goto Close; - } else { - goto Close; - } - - if (sock->ssl->output.bufs.size != 0) { - h2o_socket_read_stop(sock); - flush_pending_ssl(sock, ret == 1 ? dispose_socket : shutdown_ssl); - } else if (ret == 2 && SSL_get_error(sock->ssl->ossl, ret) == SSL_ERROR_WANT_READ) { - h2o_socket_read_start(sock, shutdown_ssl); - } else { - goto Close; - } - - return; -Close: - dispose_socket(sock, err); -} - -void h2o_socket_dispose_export(h2o_socket_export_t *info) -{ - assert(info->fd != -1); - if (info->ssl != NULL) { - destroy_ssl(info->ssl); - info->ssl = NULL; - } - h2o_buffer_dispose(&info->input); - close(info->fd); - info->fd = -1; -} - -int h2o_socket_export(h2o_socket_t *sock, h2o_socket_export_t *info) -{ - static h2o_buffer_prototype_t nonpooling_prototype; - - assert(!h2o_socket_is_writing(sock)); - - if (do_export(sock, info) == -1) - return -1; - - if ((info->ssl = sock->ssl) != NULL) { - sock->ssl = NULL; - h2o_buffer_set_prototype(&info->ssl->input.encrypted, &nonpooling_prototype); - } - info->input = sock->input; - h2o_buffer_set_prototype(&info->input, &nonpooling_prototype); - h2o_buffer_init(&sock->input, &h2o_socket_buffer_prototype); - - h2o_socket_close(sock); - - return 0; -} - -h2o_socket_t *h2o_socket_import(h2o_loop_t *loop, h2o_socket_export_t *info) -{ - h2o_socket_t *sock; - - assert(info->fd != -1); - - sock = do_import(loop, info); - info->fd = -1; /* just in case */ - if ((sock->ssl = info->ssl) != NULL) { - setup_bio(sock); - h2o_buffer_set_prototype(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); - } - sock->input = info->input; - h2o_buffer_set_prototype(&sock->input, &h2o_socket_buffer_prototype); - return sock; -} - -void h2o_socket_close(h2o_socket_t *sock) -{ - if (sock->ssl == NULL) { - dispose_socket(sock, 0); - } else { - shutdown_ssl(sock, 0); - } -} - -static uint16_t calc_suggested_tls_payload_size(h2o_socket_t *sock, uint16_t suggested_tls_record_size) -{ - uint16_t ps = suggested_tls_record_size; - if (sock->ssl != NULL && sock->ssl->record_overhead < ps) - ps -= sock->ssl->record_overhead; - return ps; -} - -static void disable_latency_optimized_write(h2o_socket_t *sock, int (*adjust_notsent_lowat)(h2o_socket_t *, unsigned)) -{ - if (sock->_latency_optimization.notsent_is_minimized) { - adjust_notsent_lowat(sock, 0); - sock->_latency_optimization.notsent_is_minimized = 0; - } - sock->_latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DISABLED; - sock->_latency_optimization.suggested_tls_payload_size = 16384; - sock->_latency_optimization.suggested_write_size = SIZE_MAX; -} - -static inline void prepare_for_latency_optimized_write(h2o_socket_t *sock, - const h2o_socket_latency_optimization_conditions_t *conditions, uint32_t rtt, - uint32_t mss, uint32_t cwnd_size, uint32_t cwnd_avail, uint64_t loop_time, - int (*adjust_notsent_lowat)(h2o_socket_t *, unsigned)) -{ - /* check RTT */ - if (rtt < conditions->min_rtt * (uint64_t)1000) - goto Disable; - if (rtt * conditions->max_additional_delay < loop_time * 1000 * 100) - goto Disable; - - /* latency-optimization is enabled */ - sock->_latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED; - - /* no need to: - * 1) adjust the write size if single_write_size << cwnd_size - * 2) align TLS record boundary to TCP packet boundary if packet loss-rate is low and BW isn't small (implied by cwnd size) - */ - if (mss * cwnd_size < conditions->max_cwnd) { - if (!sock->_latency_optimization.notsent_is_minimized) { - if (adjust_notsent_lowat(sock, 1 /* cannot be set to zero on Linux */) != 0) - goto Disable; - sock->_latency_optimization.notsent_is_minimized = 1; - } - sock->_latency_optimization.suggested_tls_payload_size = calc_suggested_tls_payload_size(sock, mss); - sock->_latency_optimization.suggested_write_size = - cwnd_avail * (size_t)sock->_latency_optimization.suggested_tls_payload_size; - } else { - if (sock->_latency_optimization.notsent_is_minimized) { - if (adjust_notsent_lowat(sock, 0) != 0) - goto Disable; - sock->_latency_optimization.notsent_is_minimized = 0; - } - sock->_latency_optimization.suggested_tls_payload_size = 16384; - sock->_latency_optimization.suggested_write_size = SIZE_MAX; - } - return; - -Disable: - disable_latency_optimized_write(sock, adjust_notsent_lowat); -} - -/** - * Obtains RTT, MSS, size of CWND (in the number of packets). - * Also writes to cwnd_avail minimum number of packets (of MSS size) sufficient to shut up poll-for-write under the precondition - * that TCP_NOTSENT_LOWAT is set to 1. - */ -static int obtain_tcp_info(int fd, uint32_t *rtt, uint32_t *mss, uint32_t *cwnd_size, uint32_t *cwnd_avail) -{ -#define CALC_CWND_PAIR_FROM_BYTE_UNITS(cwnd_bytes, inflight_bytes) \ - do { \ - *cwnd_size = (cwnd_bytes + *mss / 2) / *mss; \ - *cwnd_avail = cwnd_bytes > inflight_bytes ? (cwnd_bytes - inflight_bytes) / *mss + 2 : 2; \ - } while (0) - -#if defined(__linux__) && defined(TCP_INFO) - - struct tcp_info tcpi; - socklen_t tcpisz = sizeof(tcpi); - if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tcpisz) != 0) - return -1; - *rtt = tcpi.tcpi_rtt; - *mss = tcpi.tcpi_snd_mss; - *cwnd_size = tcpi.tcpi_snd_cwnd; - *cwnd_avail = tcpi.tcpi_snd_cwnd > tcpi.tcpi_unacked ? tcpi.tcpi_snd_cwnd - tcpi.tcpi_unacked + 2 : 2; - return 0; - -#elif defined(__FreeBSD__) && defined(TCP_INFO) && 0 /* disabled since we wouldn't use it anyways; OS lacks TCP_NOTSENT_LOWAT */ - - struct tcp_info tcpi; - socklen_t tcpisz = sizeof(tcpi); - int bytes_inflight; - if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tcpisz) != 0 || ioctl(fd, FIONWRITE, &bytes_inflight) == -1) - return -1; - *rtt = tcpi.tcpi_rtt; - *mss = tcpi.tcpi_snd_mss; - CALC_CWND_PAIR_FROM_BYTE_UNITS(tcpi.tcpi_snd_cwnd, bytes_inflight); - return 0; - -#elif defined(__APPLE__) && defined(TCP_CONNECTION_INFO) - - struct tcp_connection_info tcpi; - socklen_t tcpisz = sizeof(tcpi); - if (getsockopt(fd, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcpi, &tcpisz) != 0 || tcpi.tcpi_maxseg == 0) - return -1; - *rtt = tcpi.tcpi_srtt * 1000; - *mss = tcpi.tcpi_maxseg; - CALC_CWND_PAIR_FROM_BYTE_UNITS(tcpi.tcpi_snd_cwnd, tcpi.tcpi_snd_sbbytes); - return 0; - -#else - /* TODO add support for NetBSD; note that the OS returns the number of packets for tcpi_snd_cwnd; see - * http://twitter.com/n_soda/status/740719125878575105 - */ - return -1; -#endif - -#undef CALC_CWND_PAIR_FROM_BYTE_UNITS -} - -#ifdef TCP_NOTSENT_LOWAT -static int adjust_notsent_lowat(h2o_socket_t *sock, unsigned notsent_lowat) -{ - return setsockopt(h2o_socket_get_fd(sock), IPPROTO_TCP, TCP_NOTSENT_LOWAT, ¬sent_lowat, sizeof(notsent_lowat)); -} -#else -#define adjust_notsent_lowat NULL -#endif - -size_t h2o_socket_do_prepare_for_latency_optimized_write(h2o_socket_t *sock, - const h2o_socket_latency_optimization_conditions_t *conditions) -{ - uint32_t rtt = 0, mss = 0, cwnd_size = 0, cwnd_avail = 0; - uint64_t loop_time = UINT64_MAX; - int can_prepare = 1; - -#if !defined(TCP_NOTSENT_LOWAT) - /* the feature cannot be setup unless TCP_NOTSENT_LOWAT is available */ - can_prepare = 0; -#endif - -#if H2O_USE_LIBUV - /* poll-then-write is impossible with libuv */ - can_prepare = 0; -#else - if (can_prepare) - loop_time = h2o_evloop_get_execution_time(h2o_socket_get_loop(sock)); -#endif - - /* obtain TCP states */ - if (can_prepare && obtain_tcp_info(h2o_socket_get_fd(sock), &rtt, &mss, &cwnd_size, &cwnd_avail) != 0) - can_prepare = 0; - - /* determine suggested_write_size, suggested_tls_record_size and adjust TCP_NOTSENT_LOWAT based on the obtained information */ - if (can_prepare) { - prepare_for_latency_optimized_write(sock, conditions, rtt, mss, cwnd_size, cwnd_avail, loop_time, adjust_notsent_lowat); - } else { - disable_latency_optimized_write(sock, adjust_notsent_lowat); - } - - return sock->_latency_optimization.suggested_write_size; - -#undef CALC_CWND_PAIR_FROM_BYTE_UNITS -} - -void h2o_socket_write(h2o_socket_t *sock, h2o_iovec_t *bufs, size_t bufcnt, h2o_socket_cb cb) -{ - size_t i, prev_bytes_written = sock->bytes_written; - - for (i = 0; i != bufcnt; ++i) { - sock->bytes_written += bufs[i].len; -#if H2O_SOCKET_DUMP_WRITE - fprintf(stderr, "writing %zu bytes to fd:%d\n", bufs[i].len, h2o_socket_get_fd(sock)); - h2o_dump_memory(stderr, bufs[i].base, bufs[i].len); -#endif - } - - if (sock->ssl == NULL) { - do_write(sock, bufs, bufcnt, cb); - } else { - assert(sock->ssl->output.bufs.size == 0); - /* fill in the data */ - size_t ssl_record_size; - switch (sock->_latency_optimization.state) { - case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_TBD: - case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DISABLED: - ssl_record_size = prev_bytes_written < 200 * 1024 ? calc_suggested_tls_payload_size(sock, 1400) : 16384; - break; - case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED: - sock->_latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE; - /* fallthru */ - default: - ssl_record_size = sock->_latency_optimization.suggested_tls_payload_size; - break; - } - for (; bufcnt != 0; ++bufs, --bufcnt) { - size_t off = 0; - while (off != bufs[0].len) { - int ret; - size_t sz = bufs[0].len - off; - if (sz > ssl_record_size) - sz = ssl_record_size; -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - size_t dst_size = sz + ptls_get_record_overhead(sock->ssl->ptls); - void *dst = h2o_mem_alloc_pool(&sock->ssl->output.pool, dst_size); - ptls_buffer_t wbuf; - ptls_buffer_init(&wbuf, dst, dst_size); - ret = ptls_send(sock->ssl->ptls, &wbuf, bufs[0].base + off, sz); - assert(ret == 0); - assert(!wbuf.is_allocated); - h2o_vector_reserve(&sock->ssl->output.pool, &sock->ssl->output.bufs, sock->ssl->output.bufs.size + 1); - sock->ssl->output.bufs.entries[sock->ssl->output.bufs.size++] = h2o_iovec_init(dst, wbuf.off); - } else -#endif - { - ret = SSL_write(sock->ssl->ossl, bufs[0].base + off, (int)sz); - if (ret != sz) { - /* The error happens if SSL_write is called after SSL_read returns a fatal error (e.g. due to corrupt TCP - * packet being received). We need to take care of this since some protocol implementations send data after - * the read-side of the connection gets closed (note that protocol implementations are (yet) incapable of - * distinguishing a normal shutdown and close due to an error using the `status` value of the read - * callback). - */ - clear_output_buffer(sock->ssl); - flush_pending_ssl(sock, cb); -#ifndef H2O_USE_LIBUV - ((struct st_h2o_evloop_socket_t *)sock)->_flags |= H2O_SOCKET_FLAG_IS_WRITE_ERROR; -#endif - return; - } - } - off += sz; - } - } - flush_pending_ssl(sock, cb); - } -} - -void on_write_complete(h2o_socket_t *sock, const char *err) -{ - h2o_socket_cb cb; - - if (sock->ssl != NULL) - clear_output_buffer(sock->ssl); - - cb = sock->_cb.write; - sock->_cb.write = NULL; - cb(sock, err); -} - -void h2o_socket_read_start(h2o_socket_t *sock, h2o_socket_cb cb) -{ - sock->_cb.read = cb; - do_read_start(sock); -} - -void h2o_socket_read_stop(h2o_socket_t *sock) -{ - sock->_cb.read = NULL; - do_read_stop(sock); -} - -void h2o_socket_setpeername(h2o_socket_t *sock, struct sockaddr *sa, socklen_t len) -{ - if (sock->_peername != NULL) - free(sock->_peername); - sock->_peername = h2o_mem_alloc(offsetof(struct st_h2o_socket_peername_t, addr) + len); - sock->_peername->len = len; - memcpy(&sock->_peername->addr, sa, len); -} - -socklen_t h2o_socket_getpeername(h2o_socket_t *sock, struct sockaddr *sa) -{ - /* return cached, if exists */ - if (sock->_peername != NULL) { - memcpy(sa, &sock->_peername->addr, sock->_peername->len); - return sock->_peername->len; - } - /* call, copy to cache, and return */ - socklen_t len = get_peername_uncached(sock, sa); - h2o_socket_setpeername(sock, sa, len); - return len; -} - -const char *h2o_socket_get_ssl_protocol_version(h2o_socket_t *sock) -{ - if (sock->ssl != NULL) { -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) - return "TLSv1.3"; -#endif - if (sock->ssl->ossl != NULL) - return SSL_get_version(sock->ssl->ossl); - } - return NULL; -} - -int h2o_socket_get_ssl_session_reused(h2o_socket_t *sock) -{ - if (sock->ssl != NULL) { -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) - return ptls_is_psk_handshake(sock->ssl->ptls); -#endif - if (sock->ssl->ossl != NULL) - return (int)SSL_session_reused(sock->ssl->ossl); - } - return -1; -} - -const char *h2o_socket_get_ssl_cipher(h2o_socket_t *sock) -{ - if (sock->ssl != NULL) { -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - ptls_cipher_suite_t *cipher = ptls_get_cipher(sock->ssl->ptls); - if (cipher != NULL) - return cipher->aead->name; - } else -#endif - if (sock->ssl->ossl != NULL) - return SSL_get_cipher_name(sock->ssl->ossl); - } - return NULL; -} - -int h2o_socket_get_ssl_cipher_bits(h2o_socket_t *sock) -{ - if (sock->ssl != NULL) { -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - ptls_cipher_suite_t *cipher = ptls_get_cipher(sock->ssl->ptls); - if (cipher == NULL) - return 0; - return (int)cipher->aead->key_size; - } else -#endif - if (sock->ssl->ossl != NULL) - return SSL_get_cipher_bits(sock->ssl->ossl, NULL); - } - return 0; -} - -h2o_iovec_t h2o_socket_get_ssl_session_id(h2o_socket_t *sock) -{ - if (sock->ssl != NULL) { -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - /* FIXME */ - } else -#endif - if (sock->ssl->ossl != NULL) { - SSL_SESSION *session; - if (sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_COMPLETE && - (session = SSL_get_session(sock->ssl->ossl)) != NULL) { - unsigned id_len; - const unsigned char *id = SSL_SESSION_get_id(session, &id_len); - return h2o_iovec_init(id, id_len); - } - } - } - - return h2o_iovec_init(NULL, 0); -} - -h2o_iovec_t h2o_socket_log_ssl_session_id(h2o_socket_t *sock, h2o_mem_pool_t *pool) -{ - h2o_iovec_t base64id, rawid = h2o_socket_get_ssl_session_id(sock); - - if (rawid.base == NULL) - return h2o_iovec_init(NULL, 0); - - base64id.base = pool != NULL ? h2o_mem_alloc_pool(pool, h2o_base64_encode_capacity(rawid.len)) - : h2o_mem_alloc(h2o_base64_encode_capacity(rawid.len)); - base64id.len = h2o_base64_encode(base64id.base, rawid.base, rawid.len, 1); - return base64id; -} - -h2o_iovec_t h2o_socket_log_ssl_cipher_bits(h2o_socket_t *sock, h2o_mem_pool_t *pool) -{ - int bits = h2o_socket_get_ssl_cipher_bits(sock); - if (bits != 0) { - char *s = (char *)(pool != NULL ? h2o_mem_alloc_pool(pool, sizeof(H2O_INT16_LONGEST_STR)) - : h2o_mem_alloc(sizeof(H2O_INT16_LONGEST_STR))); - size_t len = sprintf(s, "%" PRId16, (int16_t)bits); - return h2o_iovec_init(s, len); - } else { - return h2o_iovec_init(NULL, 0); - } -} - -int h2o_socket_compare_address(struct sockaddr *x, struct sockaddr *y) -{ -#define CMP(a, b) \ - if (a != b) \ - return a < b ? -1 : 1 - - CMP(x->sa_family, y->sa_family); - - if (x->sa_family == AF_UNIX) { - struct sockaddr_un *xun = (void *)x, *yun = (void *)y; - int r = strcmp(xun->sun_path, yun->sun_path); - if (r != 0) - return r; - } else if (x->sa_family == AF_INET) { - struct sockaddr_in *xin = (void *)x, *yin = (void *)y; - CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr)); - CMP(ntohs(xin->sin_port), ntohs(yin->sin_port)); - } else if (x->sa_family == AF_INET6) { - struct sockaddr_in6 *xin6 = (void *)x, *yin6 = (void *)y; - int r = memcmp(xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr, sizeof(xin6->sin6_addr.s6_addr)); - if (r != 0) - return r; - CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port)); - CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo); - CMP(xin6->sin6_scope_id, yin6->sin6_scope_id); - } else { - assert(!"unknown sa_family"); - } - -#undef CMP - return 0; -} - -size_t h2o_socket_getnumerichost(struct sockaddr *sa, socklen_t salen, char *buf) -{ - if (sa->sa_family == AF_INET) { - /* fast path for IPv4 addresses */ - struct sockaddr_in *sin = (void *)sa; - uint32_t addr; - addr = htonl(sin->sin_addr.s_addr); - return sprintf(buf, "%d.%d.%d.%d", addr >> 24, (addr >> 16) & 255, (addr >> 8) & 255, addr & 255); - } - - if (getnameinfo(sa, salen, buf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) - return SIZE_MAX; - return strlen(buf); -} - -int32_t h2o_socket_getport(struct sockaddr *sa) -{ - switch (sa->sa_family) { - case AF_INET: - return htons(((struct sockaddr_in *)sa)->sin_port); - case AF_INET6: - return htons(((struct sockaddr_in6 *)sa)->sin6_port); - default: - return -1; - } -} - -static void create_ossl(h2o_socket_t *sock) -{ - sock->ssl->ossl = SSL_new(sock->ssl->ssl_ctx); - setup_bio(sock); -} - -static SSL_SESSION *on_async_resumption_get(SSL *ssl, -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER) - const -#endif - unsigned char *data, - int len, int *copy) -{ - h2o_socket_t *sock = BIO_get_data(SSL_get_rbio(ssl)); - - switch (sock->ssl->handshake.server.async_resumption.state) { - case ASYNC_RESUMPTION_STATE_RECORD: - sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_REQUEST_SENT; - resumption_get_async(sock, h2o_iovec_init(data, len)); - return NULL; - case ASYNC_RESUMPTION_STATE_COMPLETE: - *copy = 1; - return sock->ssl->handshake.server.async_resumption.session_data; - default: - assert(!"FIXME"); - return NULL; - } -} - -static int on_async_resumption_new(SSL *ssl, SSL_SESSION *session) -{ - h2o_iovec_t data; - const unsigned char *id; - unsigned id_len; - unsigned char *p; - - /* build data */ - data.len = i2d_SSL_SESSION(session, NULL); - data.base = alloca(data.len); - p = (void *)data.base; - i2d_SSL_SESSION(session, &p); - - id = SSL_SESSION_get_id(session, &id_len); - resumption_new(h2o_iovec_init(id, id_len), data); - return 0; -} - -static void on_handshake_complete(h2o_socket_t *sock, const char *err) -{ - if (err == NULL) { -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - sock->ssl->record_overhead = ptls_get_record_overhead(sock->ssl->ptls); - } else -#endif - { - const SSL_CIPHER *cipher = SSL_get_current_cipher(sock->ssl->ossl); - switch (SSL_CIPHER_get_id(cipher)) { - case TLS1_CK_RSA_WITH_AES_128_GCM_SHA256: - case TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256: - case TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256: - case TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: - case TLS1_CK_RSA_WITH_AES_256_GCM_SHA384: - case TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384: - case TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384: - case TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: - sock->ssl->record_overhead = 5 /* header */ + 8 /* record_iv_length (RFC 5288 3) */ + 16 /* tag (RFC 5116 5.1) */; - break; -#if defined(TLS1_CK_DHE_RSA_CHACHA20_POLY1305) - case TLS1_CK_DHE_RSA_CHACHA20_POLY1305: - case TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305: - case TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305: - sock->ssl->record_overhead = 5 /* header */ + 16 /* tag */; - break; -#endif - default: - sock->ssl->record_overhead = 32; /* sufficiently large number that can hold most payloads */ - break; - } - } - } - - /* set ssl session into the cache */ - if (sock->ssl->ossl != NULL && !SSL_is_server(sock->ssl->ossl) && sock->ssl->handshake.client.session_cache != NULL) { - if (err == NULL || err == h2o_socket_error_ssl_cert_name_mismatch) { - SSL_SESSION *session = SSL_get1_session(sock->ssl->ossl); - h2o_cache_set(sock->ssl->handshake.client.session_cache, h2o_now(h2o_socket_get_loop(sock)), - sock->ssl->handshake.client.session_cache_key, sock->ssl->handshake.client.session_cache_key_hash, - h2o_iovec_init(session, 1)); - } - } - - h2o_socket_cb handshake_cb = sock->ssl->handshake.cb; - sock->_cb.write = NULL; - sock->ssl->handshake.cb = NULL; - if (err == NULL) - decode_ssl_input(sock); - handshake_cb(sock, err); -} - -static void proceed_handshake(h2o_socket_t *sock, const char *err) -{ - h2o_iovec_t first_input = {NULL}; - int ret = 0; - - sock->_cb.write = NULL; - - if (err != NULL) { - goto Complete; - } - - if (sock->ssl->ossl == NULL) { -#if H2O_USE_PICOTLS - /* prepare I/O */ - size_t consumed = sock->ssl->input.encrypted->size; - ptls_buffer_t wbuf; - ptls_buffer_init(&wbuf, "", 0); - - if (sock->ssl->ptls != NULL) { - /* picotls in action, proceed the handshake */ - ret = ptls_handshake(sock->ssl->ptls, &wbuf, sock->ssl->input.encrypted->bytes, &consumed, NULL); - } else { - /* start using picotls if the first packet contains TLS 1.3 CH */ - ptls_context_t *ptls_ctx = h2o_socket_ssl_get_picotls_context(sock->ssl->ssl_ctx); - if (ptls_ctx != NULL) { - ptls_t *ptls = ptls_new(ptls_ctx, 1); - if (ptls == NULL) - h2o_fatal("no memory"); - ret = ptls_handshake(ptls, &wbuf, sock->ssl->input.encrypted->bytes, &consumed, NULL); - if ((ret == 0 || ret == PTLS_ERROR_IN_PROGRESS) && wbuf.off != 0) { - sock->ssl->ptls = ptls; - sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; - } else { - ptls_free(ptls); - } - } - } - - if (sock->ssl->ptls != NULL) { - /* complete I/O done by picotls */ - h2o_buffer_consume(&sock->ssl->input.encrypted, consumed); - switch (ret) { - case 0: - case PTLS_ERROR_IN_PROGRESS: - if (wbuf.off != 0) { - h2o_socket_read_stop(sock); - write_ssl_bytes(sock, wbuf.base, wbuf.off); - flush_pending_ssl(sock, ret == 0 ? on_handshake_complete : proceed_handshake); - } else { - h2o_socket_read_start(sock, proceed_handshake); - } - break; - default: - /* FIXME send alert in wbuf before calling the callback */ - on_handshake_complete(sock, "picotls handshake error"); - break; - } - ptls_buffer_dispose(&wbuf); - return; - } - ptls_buffer_dispose(&wbuf); -#endif - - /* fallback to openssl if the attempt failed */ - create_ossl(sock); - } - - if (sock->ssl->ossl != NULL && SSL_is_server(sock->ssl->ossl) && - sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_RECORD) { - if (sock->ssl->input.encrypted->size <= 1024) { - /* retain a copy of input if performing async resumption */ - first_input = h2o_iovec_init(alloca(sock->ssl->input.encrypted->size), sock->ssl->input.encrypted->size); - memcpy(first_input.base, sock->ssl->input.encrypted->bytes, first_input.len); - } else { - sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; - } - } - -Redo: - ERR_clear_error(); - if (SSL_is_server(sock->ssl->ossl)) { - ret = SSL_accept(sock->ssl->ossl); - switch (sock->ssl->handshake.server.async_resumption.state) { - case ASYNC_RESUMPTION_STATE_COMPLETE: - break; - case ASYNC_RESUMPTION_STATE_RECORD: - /* async resumption has not been triggered; proceed the state to complete */ - sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; - break; - case ASYNC_RESUMPTION_STATE_REQUEST_SENT: { - /* sent async request, reset the ssl state, and wait for async response */ - assert(ret < 0); - SSL_free(sock->ssl->ossl); - create_ossl(sock); - clear_output_buffer(sock->ssl); - h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size); - h2o_buffer_reserve(&sock->ssl->input.encrypted, first_input.len); - memcpy(sock->ssl->input.encrypted->bytes, first_input.base, first_input.len); - sock->ssl->input.encrypted->size = first_input.len; - h2o_socket_read_stop(sock); - return; - } - default: - h2o_fatal("unexpected async resumption state"); - break; - } - } else { - ret = SSL_connect(sock->ssl->ossl); - } - - if (ret == 0 || (ret < 0 && SSL_get_error(sock->ssl->ossl, ret) != SSL_ERROR_WANT_READ)) { - /* failed */ - long verify_result = SSL_get_verify_result(sock->ssl->ossl); - if (verify_result != X509_V_OK) { - err = X509_verify_cert_error_string(verify_result); - } else { - err = "ssl handshake failure"; - } - goto Complete; - } - - if (sock->ssl->output.bufs.size != 0) { - h2o_socket_read_stop(sock); - flush_pending_ssl(sock, ret == 1 ? on_handshake_complete : proceed_handshake); - } else { - if (ret == 1) { - if (!SSL_is_server(sock->ssl->ossl)) { - X509 *cert = SSL_get_peer_certificate(sock->ssl->ossl); - if (cert != NULL) { - switch (validate_hostname(sock->ssl->handshake.client.server_name, cert)) { - case MatchFound: - /* ok */ - break; - case MatchNotFound: - err = h2o_socket_error_ssl_cert_name_mismatch; - break; - default: - err = h2o_socket_error_ssl_cert_invalid; - break; - } - X509_free(cert); - } else { - err = h2o_socket_error_ssl_no_cert; - } - } - goto Complete; - } - if (sock->ssl->input.encrypted->size != 0) - goto Redo; - h2o_socket_read_start(sock, proceed_handshake); - } - return; - -Complete: - h2o_socket_read_stop(sock); - on_handshake_complete(sock, err); -} - -void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb) -{ - sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); - memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); - - sock->ssl->ssl_ctx = ssl_ctx; - - /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ - h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); - if (sock->input->size != 0) { - h2o_buffer_t *tmp = sock->input; - sock->input = sock->ssl->input.encrypted; - sock->ssl->input.encrypted = tmp; - } - - h2o_mem_init_pool(&sock->ssl->output.pool); - - sock->ssl->handshake.cb = handshake_cb; - if (server_name == NULL) { - /* is server */ - if (SSL_CTX_sess_get_get_cb(sock->ssl->ssl_ctx) != NULL) - sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_RECORD; - if (sock->ssl->input.encrypted->size != 0) - proceed_handshake(sock, 0); - else - h2o_socket_read_start(sock, proceed_handshake); - } else { - create_ossl(sock); - h2o_cache_t *session_cache = h2o_socket_ssl_get_session_cache(sock->ssl->ssl_ctx); - if (session_cache != NULL) { - struct sockaddr_storage sa; - int32_t port; - if (h2o_socket_getpeername(sock, (struct sockaddr *)&sa) != 0 && - (port = h2o_socket_getport((struct sockaddr *)&sa)) != -1) { - /* session cache is available */ - h2o_iovec_t session_cache_key; - session_cache_key.base = h2o_mem_alloc(strlen(server_name) + sizeof(":" H2O_UINT16_LONGEST_STR)); - session_cache_key.len = sprintf(session_cache_key.base, "%s:%" PRIu16, server_name, (uint16_t)port); - sock->ssl->handshake.client.session_cache = session_cache; - sock->ssl->handshake.client.session_cache_key = session_cache_key; - sock->ssl->handshake.client.session_cache_key_hash = - h2o_cache_calchash(session_cache_key.base, session_cache_key.len); - - /* fetch from session cache */ - h2o_cache_ref_t *cacheref = h2o_cache_fetch(session_cache, h2o_now(h2o_socket_get_loop(sock)), - sock->ssl->handshake.client.session_cache_key, - sock->ssl->handshake.client.session_cache_key_hash); - if (cacheref != NULL) { - SSL_set_session(sock->ssl->ossl, (SSL_SESSION *)cacheref->value.base); - h2o_cache_release(session_cache, cacheref); - } - } - } - sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base; - SSL_set_tlsext_host_name(sock->ssl->ossl, sock->ssl->handshake.client.server_name); - proceed_handshake(sock, 0); - } -} - -void h2o_socket_ssl_resume_server_handshake(h2o_socket_t *sock, h2o_iovec_t session_data) -{ - if (session_data.len != 0) { - const unsigned char *p = (void *)session_data.base; - sock->ssl->handshake.server.async_resumption.session_data = d2i_SSL_SESSION(NULL, &p, (long)session_data.len); - /* FIXME warn on failure */ - } - - sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; - proceed_handshake(sock, 0); - - if (sock->ssl->handshake.server.async_resumption.session_data != NULL) { - SSL_SESSION_free(sock->ssl->handshake.server.async_resumption.session_data); - sock->ssl->handshake.server.async_resumption.session_data = NULL; - } -} - -void h2o_socket_ssl_async_resumption_init(h2o_socket_ssl_resumption_get_async_cb get_async_cb, - h2o_socket_ssl_resumption_new_cb new_cb) -{ - resumption_get_async = get_async_cb; - resumption_new = new_cb; -} - -void h2o_socket_ssl_async_resumption_setup_ctx(SSL_CTX *ctx) -{ - SSL_CTX_sess_set_get_cb(ctx, on_async_resumption_get); - SSL_CTX_sess_set_new_cb(ctx, on_async_resumption_new); - /* if necessary, it is the responsibility of the caller to disable the internal cache */ -} - -#if H2O_USE_PICOTLS - -static int get_ptls_index(void) -{ - static int index = -1; - - if (index == -1) { - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&mutex); - if (index == -1) { - index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); - assert(index != -1); - } - pthread_mutex_unlock(&mutex); - } - - return index; -} - -ptls_context_t *h2o_socket_ssl_get_picotls_context(SSL_CTX *ossl) -{ - return SSL_CTX_get_ex_data(ossl, get_ptls_index()); -} - -void h2o_socket_ssl_set_picotls_context(SSL_CTX *ossl, ptls_context_t *ptls) -{ - SSL_CTX_set_ex_data(ossl, get_ptls_index(), ptls); -} - -#endif - -static void on_dispose_ssl_ctx_session_cache(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) -{ - h2o_cache_t *ssl_session_cache = (h2o_cache_t *)ptr; - if (ssl_session_cache != NULL) - h2o_cache_destroy(ssl_session_cache); -} - -static int get_ssl_session_cache_index(void) -{ - static int index = -1; - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&mutex); - if (index == -1) { - index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, on_dispose_ssl_ctx_session_cache); - assert(index != -1); - } - pthread_mutex_unlock(&mutex); - return index; -} - -h2o_cache_t *h2o_socket_ssl_get_session_cache(SSL_CTX *ctx) -{ - return (h2o_cache_t *)SSL_CTX_get_ex_data(ctx, get_ssl_session_cache_index()); -} - -void h2o_socket_ssl_set_session_cache(SSL_CTX *ctx, h2o_cache_t *cache) -{ - SSL_CTX_set_ex_data(ctx, get_ssl_session_cache_index(), cache); -} - -void h2o_socket_ssl_destroy_session_cache_entry(h2o_iovec_t value) -{ - SSL_SESSION *session = (SSL_SESSION *)value.base; - SSL_SESSION_free(session); -} - -h2o_iovec_t h2o_socket_ssl_get_selected_protocol(h2o_socket_t *sock) -{ - const unsigned char *data = NULL; - unsigned len = 0; - - assert(sock->ssl != NULL); - -#if H2O_USE_PICOTLS - if (sock->ssl->ptls != NULL) { - const char *proto = ptls_get_negotiated_protocol(sock->ssl->ptls); - return proto != NULL ? h2o_iovec_init(proto, strlen(proto)) : h2o_iovec_init(NULL, 0); - } -#endif - -#if H2O_USE_ALPN - if (len == 0) - SSL_get0_alpn_selected(sock->ssl->ossl, &data, &len); -#endif -#if H2O_USE_NPN - if (len == 0) - SSL_get0_next_proto_negotiated(sock->ssl->ossl, &data, &len); -#endif - - return h2o_iovec_init(data, len); -} - -static int on_alpn_select(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *_in, unsigned int inlen, - void *_protocols) -{ - const h2o_iovec_t *protocols = _protocols; - size_t i; - - for (i = 0; protocols[i].len != 0; ++i) { - const unsigned char *in = _in, *in_end = in + inlen; - while (in != in_end) { - size_t cand_len = *in++; - if (in_end - in < cand_len) { - /* broken request */ - return SSL_TLSEXT_ERR_NOACK; - } - if (cand_len == protocols[i].len && memcmp(in, protocols[i].base, cand_len) == 0) { - goto Found; - } - in += cand_len; - } - } - /* not found */ - return SSL_TLSEXT_ERR_NOACK; - -Found: - *out = (const unsigned char *)protocols[i].base; - *outlen = (unsigned char)protocols[i].len; - return SSL_TLSEXT_ERR_OK; -} - -#if H2O_USE_ALPN - -void h2o_ssl_register_alpn_protocols(SSL_CTX *ctx, const h2o_iovec_t *protocols) -{ - SSL_CTX_set_alpn_select_cb(ctx, on_alpn_select, (void *)protocols); -} - -#endif - -#if H2O_USE_NPN - -static int on_npn_advertise(SSL *ssl, const unsigned char **out, unsigned *outlen, void *protocols) -{ - *out = protocols; - *outlen = (unsigned)strlen(protocols); - return SSL_TLSEXT_ERR_OK; -} - -void h2o_ssl_register_npn_protocols(SSL_CTX *ctx, const char *protocols) -{ - SSL_CTX_set_next_protos_advertised_cb(ctx, on_npn_advertise, (void *)protocols); -} - -#endif - -void h2o_sliding_counter_stop(h2o_sliding_counter_t *counter, uint64_t now) -{ - uint64_t elapsed; - - assert(counter->cur.start_at != 0); - - /* calculate the time used, and reset cur */ - if (now <= counter->cur.start_at) - elapsed = 0; - else - elapsed = now - counter->cur.start_at; - counter->cur.start_at = 0; - - /* adjust prev */ - counter->prev.sum += elapsed; - counter->prev.sum -= counter->prev.slots[counter->prev.index]; - counter->prev.slots[counter->prev.index] = elapsed; - if (++counter->prev.index >= sizeof(counter->prev.slots) / sizeof(counter->prev.slots[0])) - counter->prev.index = 0; - - /* recalc average */ - counter->average = counter->prev.sum / (sizeof(counter->prev.slots) / sizeof(counter->prev.slots[0])); -} diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop.c.h deleted file mode 100644 index 754ed23b9..000000000 --- a/web/server/h2o/libh2o/lib/common/socket/evloop.c.h +++ /dev/null @@ -1,624 +0,0 @@ -/* - * 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 -#include -#include -#include "cloexec.h" -#include "h2o/linklist.h" - -#if !defined(H2O_USE_ACCEPT4) -#ifdef __linux__ -#define H2O_USE_ACCEPT4 1 -#elif __FreeBSD__ >= 10 -#define H2O_USE_ACCEPT4 1 -#else -#define H2O_USE_ACCEPT4 0 -#endif -#endif - -struct st_h2o_evloop_socket_t { - h2o_socket_t super; - int fd; - int _flags; - h2o_evloop_t *loop; - struct { - size_t cnt; - h2o_iovec_t *bufs; - union { - h2o_iovec_t *alloced_ptr; - h2o_iovec_t smallbufs[4]; - }; - } _wreq; - struct st_h2o_evloop_socket_t *_next_pending; - struct st_h2o_evloop_socket_t *_next_statechanged; -}; - -static void link_to_pending(struct st_h2o_evloop_socket_t *sock); -static void write_pending(struct st_h2o_evloop_socket_t *sock); -static h2o_evloop_t *create_evloop(size_t sz); -static void update_now(h2o_evloop_t *loop); -static int32_t adjust_max_wait(h2o_evloop_t *loop, int32_t max_wait); - -/* functions to be defined in the backends */ -static int evloop_do_proceed(h2o_evloop_t *loop, int32_t max_wait); -static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock); -static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock); -static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock); - -#if H2O_USE_POLL || H2O_USE_EPOLL || H2O_USE_KQUEUE -/* explicitly specified */ -#else -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#define H2O_USE_KQUEUE 1 -#elif defined(__linux) -#define H2O_USE_EPOLL 1 -#else -#define H2O_USE_POLL 1 -#endif -#endif - -#if H2O_USE_POLL -#include "evloop/poll.c.h" -#elif H2O_USE_EPOLL -#include "evloop/epoll.c.h" -#elif H2O_USE_KQUEUE -#include "evloop/kqueue.c.h" -#else -#error "poller not specified" -#endif - -void link_to_pending(struct st_h2o_evloop_socket_t *sock) -{ - if (sock->_next_pending == sock) { - struct st_h2o_evloop_socket_t **slot = (sock->_flags & H2O_SOCKET_FLAG_IS_ACCEPTED_CONNECTION) != 0 - ? &sock->loop->_pending_as_server - : &sock->loop->_pending_as_client; - sock->_next_pending = *slot; - *slot = sock; - } -} - -static void link_to_statechanged(struct st_h2o_evloop_socket_t *sock) -{ - if (sock->_next_statechanged == sock) { - sock->_next_statechanged = NULL; - *sock->loop->_statechanged.tail_ref = sock; - sock->loop->_statechanged.tail_ref = &sock->_next_statechanged; - } -} - -static const char *on_read_core(int fd, h2o_buffer_t **input) -{ - int read_any = 0; - - while (1) { - ssize_t rret; - h2o_iovec_t buf = h2o_buffer_reserve(input, 4096); - if (buf.base == NULL) { - /* memory allocation failed */ - return h2o_socket_error_out_of_memory; - } - while ((rret = read(fd, buf.base, buf.len <= INT_MAX / 2 ? buf.len : INT_MAX / 2 + 1)) == -1 && errno == EINTR) - ; - if (rret == -1) { - if (errno == EAGAIN) - break; - else - return h2o_socket_error_io; - } else if (rret == 0) { - if (!read_any) - return h2o_socket_error_closed; /* TODO notify close */ - break; - } - (*input)->size += rret; - if (buf.len != rret) - break; - read_any = 1; - } - return NULL; -} - -static void wreq_free_buffer_if_allocated(struct st_h2o_evloop_socket_t *sock) -{ - if (sock->_wreq.smallbufs <= sock->_wreq.bufs && - sock->_wreq.bufs <= sock->_wreq.smallbufs + sizeof(sock->_wreq.smallbufs) / sizeof(sock->_wreq.smallbufs[0])) { - /* no need to free */ - } else { - free(sock->_wreq.alloced_ptr); - sock->_wreq.bufs = sock->_wreq.smallbufs; - } -} - -static int write_core(int fd, h2o_iovec_t **bufs, size_t *bufcnt) -{ - int iovcnt; - ssize_t wret; - - if (*bufcnt != 0) { - do { - /* write */ - iovcnt = IOV_MAX; - if (*bufcnt < iovcnt) - iovcnt = (int)*bufcnt; - while ((wret = writev(fd, (struct iovec *)*bufs, iovcnt)) == -1 && errno == EINTR) - ; - if (wret == -1) { - if (errno != EAGAIN) - return -1; - break; - } - /* adjust the buffer */ - while ((*bufs)->len < wret) { - wret -= (*bufs)->len; - ++*bufs; - --*bufcnt; - assert(*bufcnt != 0); - } - if (((*bufs)->len -= wret) == 0) { - ++*bufs; - --*bufcnt; - } else { - (*bufs)->base += wret; - } - } while (*bufcnt != 0 && iovcnt == IOV_MAX); - } - - return 0; -} - -void write_pending(struct st_h2o_evloop_socket_t *sock) -{ - assert(sock->super._cb.write != NULL); - - /* DONT_WRITE poll */ - if (sock->_wreq.cnt == 0) - goto Complete; - - /* write */ - if (write_core(sock->fd, &sock->_wreq.bufs, &sock->_wreq.cnt) == 0 && sock->_wreq.cnt != 0) { - /* partial write */ - return; - } - - /* either completed or failed */ - wreq_free_buffer_if_allocated(sock); - -Complete: - sock->_flags |= H2O_SOCKET_FLAG_IS_WRITE_NOTIFY; - link_to_pending(sock); - link_to_statechanged(sock); /* might need to disable the write polling */ -} - -static void read_on_ready(struct st_h2o_evloop_socket_t *sock) -{ - const char *err = 0; - size_t prev_bytes_read = sock->super.input->size; - - if ((sock->_flags & H2O_SOCKET_FLAG_DONT_READ) != 0) - goto Notify; - - if ((err = on_read_core(sock->fd, sock->super.ssl == NULL ? &sock->super.input : &sock->super.ssl->input.encrypted)) != NULL) - goto Notify; - - if (sock->super.ssl != NULL && sock->super.ssl->handshake.cb == NULL) - err = decode_ssl_input(&sock->super); - -Notify: - /* the application may get notified even if no new data is avaiable. The - * behavior is intentional; it is designed as such so that the applications - * can update their timeout counters when a partial SSL record arrives. - */ - sock->super.bytes_read = sock->super.input->size - prev_bytes_read; - sock->super._cb.read(&sock->super, err); -} - -void do_dispose_socket(h2o_socket_t *_sock) -{ - struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock; - - evloop_do_on_socket_close(sock); - wreq_free_buffer_if_allocated(sock); - if (sock->fd != -1) { - close(sock->fd); - sock->fd = -1; - } - sock->_flags = H2O_SOCKET_FLAG_IS_DISPOSED; - link_to_statechanged(sock); -} - -void do_write(h2o_socket_t *_sock, h2o_iovec_t *_bufs, size_t bufcnt, h2o_socket_cb cb) -{ - struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock; - h2o_iovec_t *bufs; - h2o_iovec_t *tofree = NULL; - - assert(sock->super._cb.write == NULL); - assert(sock->_wreq.cnt == 0); - sock->super._cb.write = cb; - - /* cap the number of buffers, since we're using alloca */ - if (bufcnt > 10000) - bufs = tofree = h2o_mem_alloc(sizeof(*bufs) * bufcnt); - else - bufs = alloca(sizeof(*bufs) * bufcnt); - - memcpy(bufs, _bufs, sizeof(*bufs) * bufcnt); - - /* try to write now */ - if (write_core(sock->fd, &bufs, &bufcnt) != 0) { - /* fill in _wreq.bufs with fake data to indicate error */ - sock->_wreq.bufs = sock->_wreq.smallbufs; - sock->_wreq.cnt = 1; - *sock->_wreq.bufs = h2o_iovec_init(H2O_STRLIT("deadbeef")); - sock->_flags |= H2O_SOCKET_FLAG_IS_WRITE_NOTIFY; - link_to_pending(sock); - goto Out; - } - if (bufcnt == 0) { - /* write complete, schedule the callback */ - sock->_flags |= H2O_SOCKET_FLAG_IS_WRITE_NOTIFY; - link_to_pending(sock); - goto Out; - } - - - /* setup the buffer to send pending data */ - if (bufcnt <= sizeof(sock->_wreq.smallbufs) / sizeof(sock->_wreq.smallbufs[0])) { - sock->_wreq.bufs = sock->_wreq.smallbufs; - } else { - sock->_wreq.bufs = h2o_mem_alloc(sizeof(h2o_iovec_t) * bufcnt); - sock->_wreq.alloced_ptr = sock->_wreq.bufs; - } - memcpy(sock->_wreq.bufs, bufs, sizeof(h2o_iovec_t) * bufcnt); - sock->_wreq.cnt = bufcnt; - - /* schedule the write */ - link_to_statechanged(sock); -Out: - free(tofree); -} - -int h2o_socket_get_fd(h2o_socket_t *_sock) -{ - struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock; - return sock->fd; -} - -void do_read_start(h2o_socket_t *_sock) -{ - struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock; - - link_to_statechanged(sock); -} - -void do_read_stop(h2o_socket_t *_sock) -{ - struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock; - - sock->_flags &= ~H2O_SOCKET_FLAG_IS_READ_READY; - link_to_statechanged(sock); -} - -void h2o_socket_dont_read(h2o_socket_t *_sock, int dont_read) -{ - struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock; - - if (dont_read) { - sock->_flags |= H2O_SOCKET_FLAG_DONT_READ; - } else { - sock->_flags &= ~H2O_SOCKET_FLAG_DONT_READ; - } -} - -int do_export(h2o_socket_t *_sock, h2o_socket_export_t *info) -{ - struct st_h2o_evloop_socket_t *sock = (void *)_sock; - - assert((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) == 0); - evloop_do_on_socket_export(sock); - sock->_flags = H2O_SOCKET_FLAG_IS_DISPOSED; - - info->fd = sock->fd; - sock->fd = -1; - - return 0; -} - -h2o_socket_t *do_import(h2o_loop_t *loop, h2o_socket_export_t *info) -{ - return h2o_evloop_socket_create(loop, info->fd, 0); -} - -h2o_loop_t *h2o_socket_get_loop(h2o_socket_t *_sock) -{ - struct st_h2o_evloop_socket_t *sock = (void *)_sock; - return sock->loop; -} - -socklen_t h2o_socket_getsockname(h2o_socket_t *_sock, struct sockaddr *sa) -{ - struct st_h2o_evloop_socket_t *sock = (void *)_sock; - socklen_t len = sizeof(struct sockaddr_storage); - if (getsockname(sock->fd, sa, &len) != 0) - return 0; - return len; -} - -socklen_t get_peername_uncached(h2o_socket_t *_sock, struct sockaddr *sa) -{ - struct st_h2o_evloop_socket_t *sock = (void *)_sock; - socklen_t len = sizeof(struct sockaddr_storage); - if (getpeername(sock->fd, sa, &len) != 0) - return 0; - return len; -} - -static struct st_h2o_evloop_socket_t *create_socket(h2o_evloop_t *loop, int fd, int flags) -{ - struct st_h2o_evloop_socket_t *sock; - - fcntl(fd, F_SETFL, O_NONBLOCK); - - sock = h2o_mem_alloc(sizeof(*sock)); - memset(sock, 0, sizeof(*sock)); - h2o_buffer_init(&sock->super.input, &h2o_socket_buffer_prototype); - sock->loop = loop; - sock->fd = fd; - sock->_flags = flags; - sock->_wreq.bufs = sock->_wreq.smallbufs; - sock->_next_pending = sock; - sock->_next_statechanged = sock; - - evloop_do_on_socket_create(sock); - - return sock; -} - -static struct st_h2o_evloop_socket_t *create_socket_set_nodelay(h2o_evloop_t *loop, int fd, int flags) -{ - int on = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - return create_socket(loop, fd, flags); -} - -h2o_socket_t *h2o_evloop_socket_create(h2o_evloop_t *loop, int fd, int flags) -{ - fcntl(fd, F_SETFL, O_NONBLOCK); - return &create_socket(loop, fd, flags)->super; -} - -h2o_socket_t *h2o_evloop_socket_accept(h2o_socket_t *_listener) -{ - struct st_h2o_evloop_socket_t *listener = (struct st_h2o_evloop_socket_t *)_listener; - int fd; - -#if H2O_USE_ACCEPT4 - if ((fd = accept4(listener->fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) - return NULL; -#else - if ((fd = cloexec_accept(listener->fd, NULL, NULL)) == -1) - return NULL; - fcntl(fd, F_SETFL, O_NONBLOCK); -#endif - - return &create_socket_set_nodelay(listener->loop, fd, H2O_SOCKET_FLAG_IS_ACCEPTED_CONNECTION)->super; -} - -h2o_socket_t *h2o_socket_connect(h2o_loop_t *loop, struct sockaddr *addr, socklen_t addrlen, h2o_socket_cb cb) -{ - int fd; - struct st_h2o_evloop_socket_t *sock; - - if ((fd = cloexec_socket(addr->sa_family, SOCK_STREAM, 0)) == -1) - return NULL; - fcntl(fd, F_SETFL, O_NONBLOCK); - if (!(connect(fd, addr, addrlen) == 0 || errno == EINPROGRESS)) { - close(fd); - return NULL; - } - - sock = create_socket_set_nodelay(loop, fd, H2O_SOCKET_FLAG_IS_CONNECTING); - h2o_socket_notify_write(&sock->super, cb); - return &sock->super; -} - -h2o_evloop_t *create_evloop(size_t sz) -{ - h2o_evloop_t *loop = h2o_mem_alloc(sz); - - memset(loop, 0, sz); - loop->_statechanged.tail_ref = &loop->_statechanged.head; - h2o_linklist_init_anchor(&loop->_timeouts); - - update_now(loop); - - return loop; -} - -void update_now(h2o_evloop_t *loop) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - loop->_now = (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -int32_t adjust_max_wait(h2o_evloop_t *loop, int32_t max_wait) -{ - uint64_t wake_at = h2o_timeout_get_wake_at(&loop->_timeouts); - - update_now(loop); - - if (wake_at <= loop->_now) { - max_wait = 0; - } else { - uint64_t delta = wake_at - loop->_now; - if (delta < max_wait) - max_wait = (int32_t)delta; - } - - return max_wait; -} - -void h2o_socket_notify_write(h2o_socket_t *_sock, h2o_socket_cb cb) -{ - struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock; - assert(sock->super._cb.write == NULL); - assert(sock->_wreq.cnt == 0); - - sock->super._cb.write = cb; - link_to_statechanged(sock); -} - -static void run_socket(struct st_h2o_evloop_socket_t *sock) -{ - if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) { - /* is freed in updatestates phase */ - return; - } - - if ((sock->_flags & H2O_SOCKET_FLAG_IS_READ_READY) != 0) { - sock->_flags &= ~H2O_SOCKET_FLAG_IS_READ_READY; - read_on_ready(sock); - } - - if ((sock->_flags & H2O_SOCKET_FLAG_IS_WRITE_NOTIFY) != 0) { - const char *err = NULL; - assert(sock->super._cb.write != NULL); - sock->_flags &= ~H2O_SOCKET_FLAG_IS_WRITE_NOTIFY; - if (sock->_wreq.cnt != 0) { - /* error */ - err = h2o_socket_error_io; - sock->_wreq.cnt = 0; - } else if ((sock->_flags & H2O_SOCKET_FLAG_IS_CONNECTING) != 0) { - sock->_flags &= ~H2O_SOCKET_FLAG_IS_CONNECTING; - int so_err = 0; - socklen_t l = sizeof(so_err); - so_err = 0; - if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &so_err, &l) != 0 || so_err != 0) { - /* FIXME lookup the error table */ - err = h2o_socket_error_conn_fail; - } - } - on_write_complete(&sock->super, err); - } -} - -static void run_pending(h2o_evloop_t *loop) -{ - struct st_h2o_evloop_socket_t *sock; - - while (loop->_pending_as_server != NULL || loop->_pending_as_client != NULL) { - while ((sock = loop->_pending_as_client) != NULL) { - loop->_pending_as_client = sock->_next_pending; - sock->_next_pending = sock; - run_socket(sock); - } - if ((sock = loop->_pending_as_server) != NULL) { - loop->_pending_as_server = sock->_next_pending; - sock->_next_pending = sock; - run_socket(sock); - } - } -} - -void h2o_evloop_destroy(h2o_evloop_t *loop) -{ - struct st_h2o_evloop_socket_t *sock; - - /* timeouts are governed by the application and MUST be destroyed prior to destroying the loop */ - assert(h2o_linklist_is_empty(&loop->_timeouts)); - - /* dispose all socket */ - while ((sock = loop->_pending_as_client) != NULL) { - loop->_pending_as_client = sock->_next_pending; - sock->_next_pending = sock; - h2o_socket_close((h2o_socket_t *)sock); - } - while ((sock = loop->_pending_as_server) != NULL) { - loop->_pending_as_server = sock->_next_pending; - sock->_next_pending = sock; - h2o_socket_close((h2o_socket_t *)sock); - } - - /* now all socket are disposedand and placed in linked list statechanged - * we can freeing memory in cycle by next_statechanged, - */ - while ((sock = loop->_statechanged.head) != NULL) { - loop->_statechanged.head = sock->_next_statechanged; - free(sock); - } - - /* lastly we need to free loop memory */ - free(loop); -} - -int h2o_evloop_run(h2o_evloop_t *loop, int32_t max_wait) -{ - h2o_linklist_t *node; - - /* update socket states, poll, set readable flags, perform pending writes */ - if (evloop_do_proceed(loop, max_wait) != 0) - return -1; - - /* run the pending callbacks */ - run_pending(loop); - - /* run the timeouts */ - for (node = loop->_timeouts.next; node != &loop->_timeouts; node = node->next) { - h2o_timeout_t *timeout = H2O_STRUCT_FROM_MEMBER(h2o_timeout_t, _link, node); - h2o_timeout_run(loop, timeout, loop->_now); - } - /* assert h2o_timeout_run has called run_pending */ - assert(loop->_pending_as_client == NULL); - assert(loop->_pending_as_server == NULL); - - if (h2o_sliding_counter_is_running(&loop->exec_time_counter)) { - update_now(loop); - h2o_sliding_counter_stop(&loop->exec_time_counter, loop->_now); - } - - return 0; -} - -void h2o_timeout__do_init(h2o_evloop_t *loop, h2o_timeout_t *timeout) -{ - h2o_linklist_insert(&loop->_timeouts, &timeout->_link); -} - -void h2o_timeout__do_dispose(h2o_evloop_t *loop, h2o_timeout_t *timeout) -{ - h2o_linklist_unlink(&timeout->_link); -} - -void h2o_timeout__do_link(h2o_evloop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry) -{ - /* nothing to do */ -} - -void h2o_timeout__do_post_callback(h2o_evloop_t *loop) -{ - run_pending(loop); -} diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h deleted file mode 100644 index 247dac893..000000000 --- a/web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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 -#include -#include -#include - -#if 0 -#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__) -#else -#define DEBUG_LOG(...) -#endif - -struct st_h2o_evloop_epoll_t { - h2o_evloop_t super; - int ep; -}; - -static int update_status(struct st_h2o_evloop_epoll_t *loop) -{ - while (loop->super._statechanged.head != NULL) { - /* detach the top */ - struct st_h2o_evloop_socket_t *sock = loop->super._statechanged.head; - loop->super._statechanged.head = sock->_next_statechanged; - sock->_next_statechanged = sock; - /* update the state */ - if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) { - free(sock); - } else { - int changed = 0, op, ret; - struct epoll_event ev; - ev.events = 0; - if (h2o_socket_is_reading(&sock->super)) { - ev.events |= EPOLLIN; - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) == 0) { - sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_READ; - changed = 1; - } - } else { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) { - sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_READ; - changed = 1; - } - } - if (h2o_socket_is_writing(&sock->super)) { - ev.events |= EPOLLOUT; - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) == 0) { - sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE; - changed = 1; - } - } else { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) { - sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE; - changed = 1; - } - } - if (changed) { - if ((sock->_flags & H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED) != 0) { - if (ev.events != 0) - op = EPOLL_CTL_MOD; - else - op = EPOLL_CTL_DEL; - } else { - assert(ev.events != 0); - op = EPOLL_CTL_ADD; - } - ev.data.ptr = sock; - while ((ret = epoll_ctl(loop->ep, op, sock->fd, &ev)) != 0 && errno == EINTR) - ; - if (ret != 0) - return -1; - if (op == EPOLL_CTL_DEL) - sock->_flags &= ~H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED; - else - sock->_flags |= H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED; - } - } - } - loop->super._statechanged.tail_ref = &loop->super._statechanged.head; - - return 0; -} - -int evloop_do_proceed(h2o_evloop_t *_loop, int32_t max_wait) -{ - struct st_h2o_evloop_epoll_t *loop = (struct st_h2o_evloop_epoll_t *)_loop; - struct epoll_event events[256]; - int nevents, i; - - /* collect (and update) status */ - if (update_status(loop) != 0) - return -1; - - /* poll */ - max_wait = adjust_max_wait(&loop->super, max_wait); - nevents = epoll_wait(loop->ep, events, sizeof(events) / sizeof(events[0]), max_wait); - update_now(&loop->super); - if (nevents == -1) - return -1; - - if (nevents != 0) - h2o_sliding_counter_start(&loop->super.exec_time_counter, loop->super._now); - - /* update readable flags, perform writes */ - for (i = 0; i != nevents; ++i) { - struct st_h2o_evloop_socket_t *sock = events[i].data.ptr; - int notified = 0; - if ((events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) != 0) { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) { - sock->_flags |= H2O_SOCKET_FLAG_IS_READ_READY; - link_to_pending(sock); - notified = 1; - } - } - if ((events[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) != 0) { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) { - write_pending(sock); - notified = 1; - } - } - if (!notified) { - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - static time_t last_reported = 0; - time_t now = time(NULL); - pthread_mutex_lock(&lock); - if (last_reported + 60 < now) { - last_reported = now; - fprintf(stderr, "ignoring epoll event (fd:%d,event:%x)\n", sock->fd, (int)events[i].events); - } - pthread_mutex_unlock(&lock); - } - } - - return 0; -} - -static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock) -{ -} - -static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock) -{ - struct st_h2o_evloop_epoll_t *loop = (void *)sock->loop; - int ret; - - if (sock->fd == -1) - return; - if ((sock->_flags & H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED) == 0) - return; - while ((ret = epoll_ctl(loop->ep, EPOLL_CTL_DEL, sock->fd, NULL)) != 0 && errno == EINTR) - ; - if (ret != 0) - fprintf(stderr, "socket_close: epoll(DEL) returned error %d (fd=%d)\n", errno, sock->fd); -} - -static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock) -{ - struct st_h2o_evloop_epoll_t *loop = (void *)sock->loop; - int ret; - - if ((sock->_flags & H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED) == 0) - return; - while ((ret = epoll_ctl(loop->ep, EPOLL_CTL_DEL, sock->fd, NULL)) != 0 && errno == EINTR) - ; - if (ret != 0) - fprintf(stderr, "socket_export: epoll(DEL) returned error %d (fd=%d)\n", errno, sock->fd); -} - -h2o_evloop_t *h2o_evloop_create(void) -{ - struct st_h2o_evloop_epoll_t *loop = (struct st_h2o_evloop_epoll_t *)create_evloop(sizeof(*loop)); - - pthread_mutex_lock(&cloexec_mutex); - loop->ep = epoll_create(10); - while (fcntl(loop->ep, F_SETFD, FD_CLOEXEC) == -1) { - if (errno != EAGAIN) { - fprintf(stderr, "h2o_evloop_create: failed to set FD_CLOEXEC to the epoll fd (errno=%d)\n", errno); - abort(); - } - } - pthread_mutex_unlock(&cloexec_mutex); - - return &loop->super; -} diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h deleted file mode 100644 index 21288ed7c..000000000 --- a/web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#if 0 -#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__) -#else -#define DEBUG_LOG(...) -#endif - -struct st_h2o_socket_loop_kqueue_t { - h2o_evloop_t super; - int kq; -}; - -static void ev_set(struct kevent *ev, int fd, int filter, int flags, struct st_h2o_evloop_socket_t *sock) -{ -#ifdef __NetBSD__ - EV_SET(ev, fd, filter, flags, 0, 0, (intptr_t)sock); -#else - EV_SET(ev, fd, filter, flags, 0, 0, sock); -#endif -} - -static int collect_status(struct st_h2o_socket_loop_kqueue_t *loop, struct kevent *changelist, int changelist_capacity) -{ - int change_index = 0; - -#define SET_AND_UPDATE(filter, flags) \ - do { \ - ev_set(changelist + change_index++, sock->fd, filter, flags, sock); \ - if (change_index == changelist_capacity) { \ - int ret; \ - while ((ret = kevent(loop->kq, changelist, change_index, NULL, 0, NULL)) != 0 && errno == EINTR) \ - ; \ - if (ret == -1) \ - return -1; \ - change_index = 0; \ - } \ - } while (0) - - while (loop->super._statechanged.head != NULL) { - /* detach the top */ - struct st_h2o_evloop_socket_t *sock = loop->super._statechanged.head; - loop->super._statechanged.head = sock->_next_statechanged; - sock->_next_statechanged = sock; - /* update the state */ - if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) { - free(sock); - } else { - if (h2o_socket_is_reading(&sock->super)) { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) == 0) { - sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_READ; - SET_AND_UPDATE(EVFILT_READ, EV_ADD); - } - } else { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) { - sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_READ; - SET_AND_UPDATE(EVFILT_READ, EV_DELETE); - } - } - if (h2o_socket_is_writing(&sock->super)) { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) == 0) { - sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE; - SET_AND_UPDATE(EVFILT_WRITE, EV_ADD); - } - } else { - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) { - sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE; - SET_AND_UPDATE(EVFILT_WRITE, EV_DELETE); - } - } - } - } - loop->super._statechanged.tail_ref = &loop->super._statechanged.head; - - return change_index; - -#undef SET_AND_UPDATE -} - -int evloop_do_proceed(h2o_evloop_t *_loop, int32_t max_wait) -{ - struct st_h2o_socket_loop_kqueue_t *loop = (struct st_h2o_socket_loop_kqueue_t *)_loop; - struct kevent changelist[64], events[128]; - int nchanges, nevents, i; - struct timespec ts; - - /* collect (and update) status */ - if ((nchanges = collect_status(loop, changelist, sizeof(changelist) / sizeof(changelist[0]))) == -1) - return -1; - - /* poll */ - max_wait = adjust_max_wait(&loop->super, max_wait); - ts.tv_sec = max_wait / 1000; - ts.tv_nsec = max_wait % 1000 * 1000 * 1000; - nevents = kevent(loop->kq, changelist, nchanges, events, sizeof(events) / sizeof(events[0]), &ts); - - update_now(&loop->super); - if (nevents == -1) - return -1; - - if (nevents != 0) - h2o_sliding_counter_start(&loop->super.exec_time_counter, loop->super._now); - - /* update readable flags, perform writes */ - for (i = 0; i != nevents; ++i) { - struct st_h2o_evloop_socket_t *sock = (void *)events[i].udata; - assert(sock->fd == events[i].ident); - switch (events[i].filter) { - case EVFILT_READ: - if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) { - sock->_flags |= H2O_SOCKET_FLAG_IS_READ_READY; - link_to_pending(sock); - } - break; - case EVFILT_WRITE: - if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) { - write_pending(sock); - } - break; - default: - break; /* ??? */ - } - } - - return 0; -} - -static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock) -{ -} - -static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock) -{ -} - -static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock) -{ - struct st_h2o_socket_loop_kqueue_t *loop = (void *)sock->loop; - struct kevent changelist[2]; - int change_index = 0, ret; - - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) - ev_set(changelist + change_index++, sock->fd, EVFILT_READ, EV_DELETE, 0); - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) - ev_set(changelist + change_index++, sock->fd, EVFILT_WRITE, EV_DELETE, 0); - if (change_index == 0) - return; - while ((ret = kevent(loop->kq, changelist, change_index, NULL, 0, NULL)) != 0 && errno == EINTR) - ; - if (ret == -1) - fprintf(stderr, "kevent returned error %d (fd=%d)", errno, sock->fd); -} - -h2o_evloop_t *h2o_evloop_create(void) -{ - struct st_h2o_socket_loop_kqueue_t *loop = (struct st_h2o_socket_loop_kqueue_t *)create_evloop(sizeof(*loop)); - - loop->kq = kqueue(); - - return &loop->super; -} diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h deleted file mode 100644 index 8b3f3d149..000000000 --- a/web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2014,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 - -#if 0 -#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__) -#else -#define DEBUG_LOG(...) -#endif - -struct st_h2o_evloop_poll_t { - h2o_evloop_t super; - H2O_VECTOR(struct st_h2o_evloop_socket_t *) socks; -}; - -static void update_socks(struct st_h2o_evloop_poll_t *loop) -{ - /* update loop->socks */ - while (loop->super._statechanged.head != NULL) { - /* detach the top */ - struct st_h2o_evloop_socket_t *sock = loop->super._statechanged.head; - loop->super._statechanged.head = sock->_next_statechanged; - sock->_next_statechanged = sock; - /* update the state */ - if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) { - assert(sock->fd == -1); - free(sock); - } else { - assert(sock->fd < loop->socks.size); - if (loop->socks.entries[sock->fd] == NULL) { - loop->socks.entries[sock->fd] = sock; - } else { - assert(loop->socks.entries[sock->fd] == sock); - } - if (h2o_socket_is_reading(&sock->super)) { - DEBUG_LOG("setting READ for fd: %d\n", sock->fd); - sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_READ; - } else { - DEBUG_LOG("clearing READ for fd: %d\n", sock->fd); - sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_READ; - } - if (h2o_socket_is_writing(&sock->super)) { - DEBUG_LOG("setting WRITE for fd: %d\n", sock->fd); - sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE; - } else { - DEBUG_LOG("clearing WRITE for fd: %d\n", sock->fd); - sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE; - } - } - } - loop->super._statechanged.tail_ref = &loop->super._statechanged.head; -} - -int evloop_do_proceed(h2o_evloop_t *_loop, int32_t max_wait) -{ - struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)_loop; - H2O_VECTOR(struct pollfd) pollfds = {NULL}; - int fd, ret; - - /* update status */ - update_socks(loop); - - /* build list of fds to be polled */ - for (fd = 0; fd != loop->socks.size; ++fd) { - struct st_h2o_evloop_socket_t *sock = loop->socks.entries[fd]; - if (sock == NULL) - continue; - assert(fd == sock->fd); - if ((sock->_flags & (H2O_SOCKET_FLAG_IS_POLLED_FOR_READ | H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE)) != 0) { - h2o_vector_reserve(NULL, &pollfds, pollfds.size + 1); - struct pollfd *slot = pollfds.entries + pollfds.size++; - slot->fd = fd; - slot->events = 0; - slot->revents = 0; - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) - slot->events |= POLLIN; - if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) - slot->events |= POLLOUT; - } - } - - /* call */ - max_wait = adjust_max_wait(&loop->super, max_wait); - ret = poll(pollfds.entries, (nfds_t)pollfds.size, max_wait); - update_now(&loop->super); - if (ret == -1) - goto Exit; - DEBUG_LOG("poll returned: %d\n", ret); - - /* update readable flags, perform writes */ - if (ret > 0) { - size_t i; - h2o_sliding_counter_start(&loop->super.exec_time_counter, loop->super._now); - for (i = 0; i != pollfds.size; ++i) { - /* set read_ready flag before calling the write cb, since app. code invoked by the latter may close the socket, clearing - * the former flag */ - if ((pollfds.entries[i].revents & POLLIN) != 0) { - struct st_h2o_evloop_socket_t *sock = loop->socks.entries[pollfds.entries[i].fd]; - assert(sock != NULL); - assert(sock->fd == pollfds.entries[i].fd); - if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) { - sock->_flags |= H2O_SOCKET_FLAG_IS_READ_READY; - link_to_pending(sock); - DEBUG_LOG("added fd %d as read_ready\n", sock->fd); - } - } - if ((pollfds.entries[i].revents & POLLOUT) != 0) { - struct st_h2o_evloop_socket_t *sock = loop->socks.entries[pollfds.entries[i].fd]; - assert(sock != NULL); - assert(sock->fd == pollfds.entries[i].fd); - if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) { - DEBUG_LOG("handling pending writes on fd %d\n", fd); - write_pending(sock); - } - } - } - ret = 0; - } - -Exit: - free(pollfds.entries); - return ret; -} - -static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock) -{ - struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)sock->loop; - - if (sock->fd >= loop->socks.size) { - h2o_vector_reserve(NULL, &loop->socks, sock->fd + 1); - memset(loop->socks.entries + loop->socks.size, 0, (sock->fd + 1 - loop->socks.size) * sizeof(loop->socks.entries[0])); - loop->socks.size = sock->fd + 1; - } - - if (loop->socks.entries[sock->fd] != NULL) - assert(loop->socks.entries[sock->fd]->_flags == H2O_SOCKET_FLAG_IS_DISPOSED); -} - -static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock) -{ - struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)sock->loop; - - if (sock->fd != -1) - loop->socks.entries[sock->fd] = NULL; -} - -static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock) -{ - struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)sock->loop; - evloop_do_on_socket_close(sock); - loop->socks.entries[sock->fd] = NULL; -} - -h2o_evloop_t *h2o_evloop_create(void) -{ - struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)create_evloop(sizeof(*loop)); - return &loop->super; -} diff --git a/web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h b/web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h deleted file mode 100644 index 44c71c166..000000000 --- a/web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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. - */ - -struct st_h2o_uv_socket_t { - h2o_socket_t super; - struct { - uv_stream_t *stream; - uv_close_cb close_cb; - } uv; - union { - uv_connect_t _creq; - uv_write_t _wreq; - }; -}; - -static void schedule_timer(h2o_timeout_t *timeout); - -static void alloc_inbuf_tcp(uv_handle_t *handle, size_t suggested_size, uv_buf_t *_buf) -{ - struct st_h2o_uv_socket_t *sock = handle->data; - - h2o_iovec_t buf = h2o_buffer_reserve(&sock->super.input, 4096); - memcpy(_buf, &buf, sizeof(buf)); -} - -static void alloc_inbuf_ssl(uv_handle_t *handle, size_t suggested_size, uv_buf_t *_buf) -{ - struct st_h2o_uv_socket_t *sock = handle->data; - - h2o_iovec_t buf = h2o_buffer_reserve(&sock->super.ssl->input.encrypted, 4096); - memcpy(_buf, &buf, sizeof(buf)); -} - -static void on_read_tcp(uv_stream_t *stream, ssize_t nread, const uv_buf_t *_unused) -{ - struct st_h2o_uv_socket_t *sock = stream->data; - - if (nread < 0) { - sock->super.bytes_read = 0; - sock->super._cb.read(&sock->super, h2o_socket_error_closed); - return; - } - - sock->super.input->size += nread; - sock->super.bytes_read = nread; - sock->super._cb.read(&sock->super, NULL); -} - -static void on_read_ssl(uv_stream_t *stream, ssize_t nread, const uv_buf_t *_unused) -{ - struct st_h2o_uv_socket_t *sock = stream->data; - size_t prev_bytes_read = sock->super.input->size; - const char *err = h2o_socket_error_io; - - if (nread > 0) { - sock->super.ssl->input.encrypted->size += nread; - if (sock->super.ssl->handshake.cb == NULL) - err = decode_ssl_input(&sock->super); - else - err = NULL; - } - sock->super.bytes_read = sock->super.input->size - prev_bytes_read; - sock->super._cb.read(&sock->super, err); -} - -static void on_do_write_complete(uv_write_t *wreq, int status) -{ - struct st_h2o_uv_socket_t *sock = H2O_STRUCT_FROM_MEMBER(struct st_h2o_uv_socket_t, _wreq, wreq); - if (sock->super._cb.write != NULL) - on_write_complete(&sock->super, status == 0 ? NULL : h2o_socket_error_io); -} - -static void free_sock(uv_handle_t *handle) -{ - struct st_h2o_uv_socket_t *sock = handle->data; - uv_close_cb cb = sock->uv.close_cb; - free(sock); - cb(handle); -} - -void do_dispose_socket(h2o_socket_t *_sock) -{ - struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock; - sock->super._cb.write = NULL; /* avoid the write callback getting called when closing the socket (#1249) */ - uv_close((uv_handle_t *)sock->uv.stream, free_sock); -} - -int h2o_socket_get_fd(h2o_socket_t *_sock) -{ - int fd, ret; - struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock; - - ret = uv_fileno((uv_handle_t *)sock->uv.stream, (uv_os_fd_t *)&fd); - if (ret) - return -1; - - return fd; -} - -void do_read_start(h2o_socket_t *_sock) -{ - struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock; - - if (sock->super.ssl == NULL) - uv_read_start(sock->uv.stream, alloc_inbuf_tcp, on_read_tcp); - else - uv_read_start(sock->uv.stream, alloc_inbuf_ssl, on_read_ssl); -} - -void do_read_stop(h2o_socket_t *_sock) -{ - struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock; - uv_read_stop(sock->uv.stream); -} - -void do_write(h2o_socket_t *_sock, h2o_iovec_t *bufs, size_t bufcnt, h2o_socket_cb cb) -{ - struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock; - - assert(sock->super._cb.write == NULL); - sock->super._cb.write = cb; - - uv_write(&sock->_wreq, sock->uv.stream, (uv_buf_t *)bufs, (int)bufcnt, on_do_write_complete); -} - -static struct st_h2o_uv_socket_t *create_socket(h2o_loop_t *loop) -{ - uv_tcp_t *tcp = h2o_mem_alloc(sizeof(*tcp)); - - if (uv_tcp_init(loop, tcp) != 0) { - free(tcp); - return NULL; - } - return (void *)h2o_uv_socket_create((void *)tcp, (uv_close_cb)free); -} - -int do_export(h2o_socket_t *_sock, h2o_socket_export_t *info) -{ - struct st_h2o_uv_socket_t *sock = (void *)_sock; - uv_os_fd_t fd; - - if (uv_fileno((uv_handle_t *)sock->uv.stream, &fd) != 0) - return -1; - /* FIXME: consider how to overcome the epoll(2) problem; man says, - * "even after a file descriptor that is part of an epoll set has been closed, - * events may be reported for that file descriptor if other file descriptors - * referring to the same underlying file description remain open" - */ - if ((info->fd = dup(fd)) == -1) - return -1; - return 0; -} - -h2o_socket_t *do_import(h2o_loop_t *loop, h2o_socket_export_t *info) -{ - struct st_h2o_uv_socket_t *sock = create_socket(loop); - - if (sock == NULL) - return NULL; - if (uv_tcp_open((uv_tcp_t *)sock->uv.stream, info->fd) != 0) { - h2o_socket_close(&sock->super); - return NULL; - } - - return &sock->super; -} - -h2o_socket_t *h2o_uv_socket_create(uv_stream_t *stream, uv_close_cb close_cb) -{ - struct st_h2o_uv_socket_t *sock = h2o_mem_alloc(sizeof(*sock)); - - memset(sock, 0, sizeof(*sock)); - h2o_buffer_init(&sock->super.input, &h2o_socket_buffer_prototype); - sock->uv.stream = stream; - sock->uv.close_cb = close_cb; - stream->data = sock; - return &sock->super; -} - -static void on_connect(uv_connect_t *conn, int status) -{ - if (status == UV_ECANCELED) - return; - struct st_h2o_uv_socket_t *sock = H2O_STRUCT_FROM_MEMBER(struct st_h2o_uv_socket_t, _creq, conn); - h2o_socket_cb cb = sock->super._cb.write; - sock->super._cb.write = NULL; - cb(&sock->super, status == 0 ? NULL : h2o_socket_error_conn_fail); -} - -h2o_loop_t *h2o_socket_get_loop(h2o_socket_t *_sock) -{ - struct st_h2o_uv_socket_t *sock = (void *)_sock; - return sock->uv.stream->loop; -} - -h2o_socket_t *h2o_socket_connect(h2o_loop_t *loop, struct sockaddr *addr, socklen_t addrlen, h2o_socket_cb cb) -{ - struct st_h2o_uv_socket_t *sock = create_socket(loop); - - if (sock == NULL) - return NULL; - if (uv_tcp_connect(&sock->_creq, (void *)sock->uv.stream, addr, on_connect) != 0) { - h2o_socket_close(&sock->super); - return NULL; - } - sock->super._cb.write = cb; - return &sock->super; -} - -socklen_t h2o_socket_getsockname(h2o_socket_t *_sock, struct sockaddr *sa) -{ - struct st_h2o_uv_socket_t *sock = (void *)_sock; - int len = sizeof(struct sockaddr_storage); - if (uv_tcp_getsockname((void *)sock->uv.stream, sa, &len) != 0) - return 0; - return (socklen_t)len; -} - -socklen_t get_peername_uncached(h2o_socket_t *_sock, struct sockaddr *sa) -{ - struct st_h2o_uv_socket_t *sock = (void *)_sock; - int len = sizeof(struct sockaddr_storage); - if (uv_tcp_getpeername((void *)sock->uv.stream, sa, &len) != 0) - return 0; - return (socklen_t)len; -} - -static void on_timeout(uv_timer_t *timer) -{ - h2o_timeout_t *timeout = H2O_STRUCT_FROM_MEMBER(h2o_timeout_t, _backend.timer, timer); - - h2o_timeout_run(timer->loop, timeout, h2o_now(timer->loop)); - if (!h2o_linklist_is_empty(&timeout->_entries)) - schedule_timer(timeout); -} - -void schedule_timer(h2o_timeout_t *timeout) -{ - h2o_timeout_entry_t *entry = H2O_STRUCT_FROM_MEMBER(h2o_timeout_entry_t, _link, timeout->_entries.next); - uv_timer_start(&timeout->_backend.timer, on_timeout, - entry->registered_at + timeout->timeout - h2o_now(timeout->_backend.timer.loop), 0); -} - -void h2o_timeout__do_init(h2o_loop_t *loop, h2o_timeout_t *timeout) -{ - uv_timer_init(loop, &timeout->_backend.timer); -} - -void h2o_timeout__do_dispose(h2o_loop_t *loop, h2o_timeout_t *timeout) -{ - uv_close((uv_handle_t *)&timeout->_backend.timer, NULL); -} - -void h2o_timeout__do_link(h2o_loop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry) -{ - /* register the timer if the entry just being added is the only entry */ - if (timeout->_entries.next == &entry->_link) - schedule_timer(timeout); -} - -void h2o_timeout__do_post_callback(h2o_loop_t *loop) -{ - /* nothing to do */ -} diff --git a/web/server/h2o/libh2o/lib/common/socketpool.c b/web/server/h2o/libh2o/lib/common/socketpool.c deleted file mode 100644 index da69933f7..000000000 --- a/web/server/h2o/libh2o/lib/common/socketpool.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c) 2014-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 -#include -#include -#include -#include -#include "h2o/hostinfo.h" -#include "h2o/linklist.h" -#include "h2o/socketpool.h" -#include "h2o/string_.h" -#include "h2o/timeout.h" - -struct pool_entry_t { - h2o_socket_export_t sockinfo; - h2o_linklist_t link; - uint64_t added_at; -}; - -struct st_h2o_socketpool_connect_request_t { - void *data; - h2o_socketpool_connect_cb cb; - h2o_socketpool_t *pool; - h2o_loop_t *loop; - h2o_hostinfo_getaddr_req_t *getaddr_req; - h2o_socket_t *sock; -}; - -static void destroy_detached(struct pool_entry_t *entry) -{ - h2o_socket_dispose_export(&entry->sockinfo); - free(entry); -} - -static void destroy_attached(struct pool_entry_t *entry) -{ - h2o_linklist_unlink(&entry->link); - destroy_detached(entry); -} - -static void destroy_expired(h2o_socketpool_t *pool) -{ - /* caller should lock the mutex */ - uint64_t expire_before = h2o_now(pool->_interval_cb.loop) - pool->timeout; - while (!h2o_linklist_is_empty(&pool->_shared.sockets)) { - struct pool_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next); - if (entry->added_at > expire_before) - break; - destroy_attached(entry); - __sync_sub_and_fetch(&pool->_shared.count, 1); - } -} - -static void on_timeout(h2o_timeout_entry_t *timeout_entry) -{ - /* FIXME decrease the frequency of this function being called; the expiration - * check can be (should be) performed in the `connect` fuction as well - */ - h2o_socketpool_t *pool = H2O_STRUCT_FROM_MEMBER(h2o_socketpool_t, _interval_cb.entry, timeout_entry); - - if (pthread_mutex_trylock(&pool->_shared.mutex) == 0) { - destroy_expired(pool); - pthread_mutex_unlock(&pool->_shared.mutex); - } - - h2o_timeout_link(pool->_interval_cb.loop, &pool->_interval_cb.timeout, &pool->_interval_cb.entry); -} - -static void common_init(h2o_socketpool_t *pool, h2o_socketpool_type_t type, h2o_iovec_t host, int is_ssl, size_t capacity) -{ - memset(pool, 0, sizeof(*pool)); - - pool->type = type; - pool->peer.host = h2o_strdup(NULL, host.base, host.len); - pool->is_ssl = is_ssl; - pool->capacity = capacity; - pool->timeout = UINT64_MAX; - - pthread_mutex_init(&pool->_shared.mutex, NULL); - h2o_linklist_init_anchor(&pool->_shared.sockets); -} - -void h2o_socketpool_init_by_address(h2o_socketpool_t *pool, struct sockaddr *sa, socklen_t salen, int is_ssl, size_t capacity) -{ - char host[NI_MAXHOST]; - size_t host_len; - - assert(salen <= sizeof(pool->peer.sockaddr.bytes)); - - if ((host_len = h2o_socket_getnumerichost(sa, salen, host)) == SIZE_MAX) { - if (sa->sa_family != AF_UNIX) - h2o_fatal("failed to convert a non-unix socket address to a numerical representation"); - /* use the sockaddr_un::sun_path as the SNI indicator (is that the right thing to do?) */ - strcpy(host, ((struct sockaddr_un *)sa)->sun_path); - host_len = strlen(host); - } - - common_init(pool, H2O_SOCKETPOOL_TYPE_SOCKADDR, h2o_iovec_init(host, host_len), is_ssl, capacity); - memcpy(&pool->peer.sockaddr.bytes, sa, salen); - pool->peer.sockaddr.len = salen; -} - -void h2o_socketpool_init_by_hostport(h2o_socketpool_t *pool, h2o_iovec_t host, uint16_t port, int is_ssl, size_t capacity) -{ - struct sockaddr_in sin; - memset(&sin, 0, sizeof(sin)); - - if (h2o_hostinfo_aton(host, &sin.sin_addr) == 0) { - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - h2o_socketpool_init_by_address(pool, (void *)&sin, sizeof(sin), is_ssl, capacity); - return; - } - - common_init(pool, H2O_SOCKETPOOL_TYPE_NAMED, host, is_ssl, capacity); - pool->peer.named_serv.base = h2o_mem_alloc(sizeof(H2O_UINT16_LONGEST_STR)); - pool->peer.named_serv.len = sprintf(pool->peer.named_serv.base, "%u", (unsigned)port); -} - -void h2o_socketpool_dispose(h2o_socketpool_t *pool) -{ - pthread_mutex_lock(&pool->_shared.mutex); - while (!h2o_linklist_is_empty(&pool->_shared.sockets)) { - struct pool_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next); - destroy_attached(entry); - __sync_sub_and_fetch(&pool->_shared.count, 1); - } - pthread_mutex_unlock(&pool->_shared.mutex); - pthread_mutex_destroy(&pool->_shared.mutex); - - if (pool->_interval_cb.loop != NULL) { - h2o_timeout_unlink(&pool->_interval_cb.entry); - h2o_timeout_dispose(pool->_interval_cb.loop, &pool->_interval_cb.timeout); - } - free(pool->peer.host.base); - switch (pool->type) { - case H2O_SOCKETPOOL_TYPE_NAMED: - free(pool->peer.named_serv.base); - break; - case H2O_SOCKETPOOL_TYPE_SOCKADDR: - break; - } -} - -void h2o_socketpool_set_timeout(h2o_socketpool_t *pool, h2o_loop_t *loop, uint64_t msec) -{ - pool->timeout = msec; - - pool->_interval_cb.loop = loop; - h2o_timeout_init(loop, &pool->_interval_cb.timeout, 1000); - pool->_interval_cb.entry.cb = on_timeout; - - h2o_timeout_link(loop, &pool->_interval_cb.timeout, &pool->_interval_cb.entry); -} - -static void call_connect_cb(h2o_socketpool_connect_request_t *req, const char *errstr) -{ - h2o_socketpool_connect_cb cb = req->cb; - h2o_socket_t *sock = req->sock; - void *data = req->data; - - free(req); - cb(sock, errstr, data); -} - -static void on_connect(h2o_socket_t *sock, const char *err) -{ - h2o_socketpool_connect_request_t *req = sock->data; - const char *errstr = NULL; - - assert(req->sock == sock); - - if (err != NULL) { - h2o_socket_close(sock); - req->sock = NULL; - errstr = "connection failed"; - } - call_connect_cb(req, errstr); -} - -static void on_close(void *data) -{ - h2o_socketpool_t *pool = data; - __sync_sub_and_fetch(&pool->_shared.count, 1); -} - -static void start_connect(h2o_socketpool_connect_request_t *req, struct sockaddr *addr, socklen_t addrlen) -{ - req->sock = h2o_socket_connect(req->loop, addr, addrlen, on_connect); - if (req->sock == NULL) { - __sync_sub_and_fetch(&req->pool->_shared.count, 1); - call_connect_cb(req, "failed to connect to host"); - return; - } - req->sock->data = req; - req->sock->on_close.cb = on_close; - req->sock->on_close.data = req->pool; -} - -static void on_getaddr(h2o_hostinfo_getaddr_req_t *getaddr_req, const char *errstr, struct addrinfo *res, void *_req) -{ - h2o_socketpool_connect_request_t *req = _req; - - assert(getaddr_req == req->getaddr_req); - req->getaddr_req = NULL; - - if (errstr != NULL) { - __sync_sub_and_fetch(&req->pool->_shared.count, 1); - call_connect_cb(req, errstr); - return; - } - - struct addrinfo *selected = h2o_hostinfo_select_one(res); - start_connect(req, selected->ai_addr, selected->ai_addrlen); -} - -void h2o_socketpool_connect(h2o_socketpool_connect_request_t **_req, h2o_socketpool_t *pool, h2o_loop_t *loop, - h2o_multithread_receiver_t *getaddr_receiver, h2o_socketpool_connect_cb cb, void *data) -{ - struct pool_entry_t *entry = NULL; - - if (_req != NULL) - *_req = NULL; - - /* fetch an entry and return it */ - pthread_mutex_lock(&pool->_shared.mutex); - destroy_expired(pool); - while (1) { - if (h2o_linklist_is_empty(&pool->_shared.sockets)) - break; - entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next); - h2o_linklist_unlink(&entry->link); - pthread_mutex_unlock(&pool->_shared.mutex); - - /* test if the connection is still alive */ - char buf[1]; - ssize_t rret = recv(entry->sockinfo.fd, buf, 1, MSG_PEEK); - if (rret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { - /* yes! return it */ - h2o_socket_t *sock = h2o_socket_import(loop, &entry->sockinfo); - free(entry); - sock->on_close.cb = on_close; - sock->on_close.data = pool; - cb(sock, NULL, data); - return; - } - - /* connection is dead, report, close, and retry */ - if (rret <= 0) { - static long counter = 0; - if (__sync_fetch_and_add(&counter, 1) == 0) - fprintf(stderr, "[WARN] detected close by upstream before the expected timeout (see issue #679)\n"); - } else { - static long counter = 0; - if (__sync_fetch_and_add(&counter, 1) == 0) - fprintf(stderr, "[WARN] unexpectedly received data to a pooled socket (see issue #679)\n"); - } - destroy_detached(entry); - pthread_mutex_lock(&pool->_shared.mutex); - } - pthread_mutex_unlock(&pool->_shared.mutex); - - /* FIXME repsect `capacity` */ - __sync_add_and_fetch(&pool->_shared.count, 1); - - /* prepare request object */ - h2o_socketpool_connect_request_t *req = h2o_mem_alloc(sizeof(*req)); - *req = (h2o_socketpool_connect_request_t){data, cb, pool, loop}; - if (_req != NULL) - *_req = req; - - switch (pool->type) { - case H2O_SOCKETPOOL_TYPE_NAMED: - /* resolve the name, and connect */ - req->getaddr_req = h2o_hostinfo_getaddr(getaddr_receiver, pool->peer.host, pool->peer.named_serv, AF_UNSPEC, SOCK_STREAM, - IPPROTO_TCP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, req); - break; - case H2O_SOCKETPOOL_TYPE_SOCKADDR: - /* connect (using sockaddr_in) */ - start_connect(req, (void *)&pool->peer.sockaddr.bytes, pool->peer.sockaddr.len); - break; - } -} - -void h2o_socketpool_cancel_connect(h2o_socketpool_connect_request_t *req) -{ - if (req->getaddr_req != NULL) { - h2o_hostinfo_getaddr_cancel(req->getaddr_req); - req->getaddr_req = NULL; - } - if (req->sock != NULL) - h2o_socket_close(req->sock); - free(req); -} - -int h2o_socketpool_return(h2o_socketpool_t *pool, h2o_socket_t *sock) -{ - struct pool_entry_t *entry; - - /* reset the on_close callback */ - assert(sock->on_close.data == pool); - sock->on_close.cb = NULL; - sock->on_close.data = NULL; - - entry = h2o_mem_alloc(sizeof(*entry)); - if (h2o_socket_export(sock, &entry->sockinfo) != 0) { - free(entry); - __sync_sub_and_fetch(&pool->_shared.count, 1); - return -1; - } - memset(&entry->link, 0, sizeof(entry->link)); - entry->added_at = h2o_now(h2o_socket_get_loop(sock)); - - pthread_mutex_lock(&pool->_shared.mutex); - destroy_expired(pool); - h2o_linklist_insert(&pool->_shared.sockets, &entry->link); - pthread_mutex_unlock(&pool->_shared.mutex); - - return 0; -} diff --git a/web/server/h2o/libh2o/lib/common/string.c b/web/server/h2o/libh2o/lib/common/string.c deleted file mode 100644 index 3c068f3ad..000000000 --- a/web/server/h2o/libh2o/lib/common/string.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Justin Zhu, 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 -#include "h2o/string_.h" - -h2o_iovec_t h2o_strdup(h2o_mem_pool_t *pool, const char *s, size_t slen) -{ - h2o_iovec_t ret; - - if (slen == SIZE_MAX) - slen = strlen(s); - - if (pool != NULL) { - ret.base = h2o_mem_alloc_pool(pool, slen + 1); - } else { - ret.base = h2o_mem_alloc(slen + 1); - } - h2o_memcpy(ret.base, s, slen); - ret.base[slen] = '\0'; - ret.len = slen; - return ret; -} - -h2o_iovec_t h2o_strdup_shared(h2o_mem_pool_t *pool, const char *s, size_t slen) -{ - h2o_iovec_t ret; - - if (slen == SIZE_MAX) - slen = strlen(s); - - ret.base = h2o_mem_alloc_shared(pool, slen + 1, NULL); - memcpy(ret.base, s, slen); - ret.base[slen] = '\0'; - ret.len = slen; - return ret; -} - -h2o_iovec_t h2o_strdup_slashed(h2o_mem_pool_t *pool, const char *src, size_t len) -{ - h2o_iovec_t ret; - - ret.len = len != SIZE_MAX ? len : strlen(src); - ret.base = pool != NULL ? h2o_mem_alloc_pool(pool, ret.len + 2) : h2o_mem_alloc(ret.len + 2); - memcpy(ret.base, src, ret.len); - if (ret.len != 0 && ret.base[ret.len - 1] != '/') - ret.base[ret.len++] = '/'; - ret.base[ret.len] = '\0'; - - return ret; -} - -int h2o__lcstris_core(const char *target, const char *test, size_t test_len) -{ - for (; test_len != 0; --test_len) - if (h2o_tolower(*target++) != *test++) - return 0; - return 1; -} - -size_t h2o_strtosize(const char *s, size_t len) -{ - uint64_t v = 0, m = 1; - const char *p = s + len; - - if (len == 0) - goto Error; - - while (1) { - int ch = *--p; - if (!('0' <= ch && ch <= '9')) - goto Error; - v += (ch - '0') * m; - if (p == s) - break; - m *= 10; - /* do not even try to overflow */ - if (m == 10000000000000000000ULL) - goto Error; - } - - if (v >= SIZE_MAX) - goto Error; - return v; - -Error: - return SIZE_MAX; -} - -size_t h2o_strtosizefwd(char **s, size_t len) -{ - uint64_t v, c; - char *p = *s, *p_end = *s + len; - - if (len == 0) - goto Error; - - int ch = *p++; - if (!('0' <= ch && ch <= '9')) - goto Error; - v = ch - '0'; - c = 1; - - while (1) { - ch = *p; - if (!('0' <= ch && ch <= '9')) - break; - v *= 10; - v += ch - '0'; - p++; - c++; - if (p == p_end) - break; - /* similar as above, do not even try to overflow */ - if (c == 20) - goto Error; - } - - if (v >= SIZE_MAX) - goto Error; - *s = p; - return v; - -Error: - return SIZE_MAX; -} - -static uint32_t decode_base64url_quad(const char *src) -{ - const char *src_end = src + 4; - uint32_t decoded = 0; - - while (1) { - if ('A' <= *src && *src <= 'Z') { - decoded |= *src - 'A'; - } else if ('a' <= *src && *src <= 'z') { - decoded |= *src - 'a' + 26; - } else if ('0' <= *src && *src <= '9') { - decoded |= *src - '0' + 52; - } else if (*src == '-') { - decoded |= 62; - } else if (*src == '_') { - decoded |= 63; -#if 1 /* curl uses normal base64 */ - } else if (*src == '+') { - decoded |= 62; - } else if (*src == '/') { - decoded |= 63; -#endif - } else { - return UINT32_MAX; - } - if (++src == src_end) - break; - decoded <<= 6; - } - - return decoded; -} - -h2o_iovec_t h2o_decode_base64url(h2o_mem_pool_t *pool, const char *src, size_t len) -{ - h2o_iovec_t decoded; - uint32_t t; - uint8_t *dst; - char remaining_input[4]; - - decoded.len = len * 3 / 4; - decoded.base = pool != NULL ? h2o_mem_alloc_pool(pool, decoded.len + 1) : h2o_mem_alloc(decoded.len + 1); - dst = (uint8_t *)decoded.base; - - while (len >= 4) { - if ((t = decode_base64url_quad(src)) == UINT32_MAX) - goto Error; - *dst++ = t >> 16; - *dst++ = t >> 8; - *dst++ = t; - src += 4; - len -= 4; - } - switch (len) { - case 0: - break; - case 1: - goto Error; - case 2: - remaining_input[0] = *src++; - remaining_input[1] = *src++; - remaining_input[2] = 'A'; - remaining_input[3] = 'A'; - if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX) - goto Error; - *dst++ = t >> 16; - break; - case 3: - remaining_input[0] = *src++; - remaining_input[1] = *src++; - remaining_input[2] = *src++; - remaining_input[3] = 'A'; - if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX) - goto Error; - *dst++ = t >> 16; - *dst++ = t >> 8; - break; - } - - assert((char *)dst - decoded.base == decoded.len); - decoded.base[decoded.len] = '\0'; - - return decoded; - -Error: - if (pool == NULL) - free(decoded.base); - return h2o_iovec_init(NULL, 0); -} - -size_t h2o_base64_encode(char *_dst, const void *_src, size_t len, int url_encoded) -{ - static const char *MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - static const char *MAP_URL_ENCODED = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789-_"; - - char *dst = _dst; - const uint8_t *src = _src; - const char *map = url_encoded ? MAP_URL_ENCODED : MAP; - uint32_t quad; - - for (; len >= 3; src += 3, len -= 3) { - quad = ((uint32_t)src[0] << 16) | ((uint32_t)src[1] << 8) | src[2]; - *dst++ = map[quad >> 18]; - *dst++ = map[(quad >> 12) & 63]; - *dst++ = map[(quad >> 6) & 63]; - *dst++ = map[quad & 63]; - } - if (len != 0) { - quad = (uint32_t)src[0] << 16; - *dst++ = map[quad >> 18]; - if (len == 2) { - quad |= (uint32_t)src[1] << 8; - *dst++ = map[(quad >> 12) & 63]; - *dst++ = map[(quad >> 6) & 63]; - if (!url_encoded) - *dst++ = '='; - } else { - *dst++ = map[(quad >> 12) & 63]; - if (!url_encoded) { - *dst++ = '='; - *dst++ = '='; - } - } - } - - *dst = '\0'; - return dst - _dst; -} - -static int decode_hex(int ch) -{ - if ('0' <= ch && ch <= '9') - return ch - '0'; - if ('A' <= ch && ch <= 'F') - return ch - 'A' + 0xa; - if ('a' <= ch && ch <= 'f') - return ch - 'a' + 0xa; - return -1; -} - -int h2o_hex_decode(void *_dst, const char *src, size_t src_len) -{ - unsigned char *dst = _dst; - - if (src_len % 2 != 0) - return -1; - for (; src_len != 0; src_len -= 2) { - int hi, lo; - if ((hi = decode_hex(*src++)) == -1 || (lo = decode_hex(*src++)) == -1) - return -1; - *dst++ = (hi << 4) | lo; - } - return 0; -} - -void h2o_hex_encode(char *dst, const void *_src, size_t src_len) -{ - const unsigned char *src = _src, *src_end = src + src_len; - for (; src != src_end; ++src) { - *dst++ = "0123456789abcdef"[*src >> 4]; - *dst++ = "0123456789abcdef"[*src & 0xf]; - } - *dst = '\0'; -} - -h2o_iovec_t h2o_uri_escape(h2o_mem_pool_t *pool, const char *s, size_t l, const char *preserve_chars) -{ - h2o_iovec_t encoded; - size_t i, capacity = l * 3 + 1; - - encoded.base = pool != NULL ? h2o_mem_alloc_pool(pool, capacity) : h2o_mem_alloc(capacity); - encoded.len = 0; - - /* RFC 3986: - path-noscheme = segment-nz-nc *( "/" segment ) - segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) - unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - sub-delims = "!" / "$" / "&" / "'" / "(" / ")" - / "*" / "+" / "," / ";" / "=" - */ - for (i = 0; i != l; ++i) { - int ch = s[i]; - if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ('0' <= ch && ch <= '9') || ch == '-' || ch == '.' || - ch == '_' || ch == '~' || ch == '!' || ch == '$' || ch == '&' || ch == '\'' || ch == '(' || ch == ')' || ch == '*' || - ch == '+' || ch == ',' || ch == ';' || ch == '=' || - (ch != '\0' && preserve_chars != NULL && strchr(preserve_chars, ch) != NULL)) { - encoded.base[encoded.len++] = ch; - } else { - encoded.base[encoded.len++] = '%'; - encoded.base[encoded.len++] = "0123456789ABCDEF"[(ch >> 4) & 0xf]; - encoded.base[encoded.len++] = "0123456789ABCDEF"[ch & 0xf]; - } - } - encoded.base[encoded.len] = '\0'; - - return encoded; -} - -h2o_iovec_t h2o_get_filext(const char *path, size_t len) -{ - const char *end = path + len, *p = end; - - while (--p != path) { - if (*p == '.') { - return h2o_iovec_init(p + 1, end - (p + 1)); - } else if (*p == '/') { - break; - } - } - return h2o_iovec_init(NULL, 0); -} - -static int is_ws(int ch) -{ - return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; -} - -h2o_iovec_t h2o_str_stripws(const char *s, size_t len) -{ - const char *end = s + len; - - while (s != end) { - if (!is_ws(*s)) - break; - ++s; - } - while (s != end) { - if (!is_ws(end[-1])) - break; - --end; - } - return h2o_iovec_init(s, end - s); -} - -size_t h2o_strstr(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len) -{ - /* TODO optimize */ - if (haysack_len >= needle_len) { - size_t off, max = haysack_len - needle_len + 1; - if (needle_len == 0) - return 0; - for (off = 0; off != max; ++off) - if (haysack[off] == needle[0] && memcmp(haysack + off + 1, needle + 1, needle_len - 1) == 0) - return off; - } - return SIZE_MAX; -} - -/* note: returns a zero-width match as well */ -const char *h2o_next_token(h2o_iovec_t *iter, int separator, size_t *element_len, h2o_iovec_t *value) -{ - const char *cur = iter->base, *end = iter->base + iter->len, *token_start, *token_end; - - /* find start */ - for (;; ++cur) { - if (cur == end) - return NULL; - if (!(*cur == ' ' || *cur == '\t')) - break; - } - token_start = cur; - token_end = cur; - - /* find last */ - for (;; ++cur) { - if (cur == end) - break; - if (*cur == separator) { - ++cur; - break; - } - if (*cur == ',') { - if (token_start == cur) { - ++cur; - token_end = cur; - } - break; - } - if (value != NULL && *cur == '=') { - ++cur; - goto FindValue; - } - if (!(*cur == ' ' || *cur == '\t')) - token_end = cur + 1; - } - - /* found */ - *iter = h2o_iovec_init(cur, end - cur); - *element_len = token_end - token_start; - if (value != NULL) - *value = (h2o_iovec_t){NULL}; - return token_start; - -FindValue: - *iter = h2o_iovec_init(cur, end - cur); - *element_len = token_end - token_start; - if ((value->base = (char *)h2o_next_token(iter, separator, &value->len, NULL)) == NULL) { - *value = (h2o_iovec_t){"", 0}; - } else if (h2o_memis(value->base, value->len, H2O_STRLIT(","))) { - *value = (h2o_iovec_t){"", 0}; - iter->base -= 1; - iter->len += 1; - } - return token_start; -} - -int h2o_contains_token(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len, int separator) -{ - h2o_iovec_t iter = h2o_iovec_init(haysack, haysack_len); - const char *token = NULL; - size_t token_len = 0; - - while ((token = h2o_next_token(&iter, separator, &token_len, NULL)) != NULL) { - if (h2o_lcstris(token, token_len, needle, needle_len)) { - return 1; - } - } - return 0; -} - -h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len) -{ - const char *s, *end = src + len; - size_t add_size = 0; - -#define ENTITY_MAP() \ - ENTITY('"', """); \ - ENTITY('&', "&"); \ - ENTITY('\'', "'"); \ - ENTITY('<', "<"); \ - ENTITY('>', ">"); - - for (s = src; s != end; ++s) { - if ((unsigned)(unsigned char)*s - '"' <= '>' - '"') { - switch (*s) { -#define ENTITY(code, quoted) \ - case code: \ - add_size += sizeof(quoted) - 2; \ - break - ENTITY_MAP() -#undef ENTITY - } - } - } - - /* escape and return the result if necessary */ - if (add_size != 0) { - /* allocate buffer and fill in the chars that are known not to require escaping */ - h2o_iovec_t escaped = {h2o_mem_alloc_pool(pool, len + add_size + 1), 0}; - /* fill-in the rest */ - for (s = src; s != end; ++s) { - switch (*s) { -#define ENTITY(code, quoted) \ - case code: \ - memcpy(escaped.base + escaped.len, quoted, sizeof(quoted) - 1); \ - escaped.len += sizeof(quoted) - 1; \ - break - ENTITY_MAP() -#undef ENTITY - default: - escaped.base[escaped.len++] = *s; - break; - } - } - assert(escaped.len == len + add_size); - escaped.base[escaped.len] = '\0'; - - return escaped; - } - -#undef ENTITY_MAP - - /* no need not escape; return the original */ - return h2o_iovec_init(src, len); -} - -h2o_iovec_t h2o_concat_list(h2o_mem_pool_t *pool, h2o_iovec_t *list, size_t count) -{ - h2o_iovec_t ret = {NULL, 0}; - size_t i; - - /* calc the length */ - for (i = 0; i != count; ++i) { - ret.len += list[i].len; - } - - /* allocate memory */ - if (pool != NULL) - ret.base = h2o_mem_alloc_pool(pool, ret.len + 1); - else - ret.base = h2o_mem_alloc(ret.len + 1); - - /* concatenate */ - ret.len = 0; - for (i = 0; i != count; ++i) { - h2o_memcpy(ret.base + ret.len, list[i].base, list[i].len); - ret.len += list[i].len; - } - ret.base[ret.len] = '\0'; - - return ret; -} - -int h2o_str_at_position(char *buf, const char *src, size_t src_len, int lineno, int column) -{ - const char *src_end = src + src_len; - int i; - - /* find the line */ - if (lineno <= 0 || column <= 0) - return -1; - for (--lineno; lineno != 0; --lineno) { - do { - if (src == src_end) - return -1; - } while (*src++ != '\n'); - } - - /* adjust the starting column */ - while (column > 40) { - if (src != src_end) - ++src; - --column; - } - - /* emit */ - for (i = 1; i <= 76; ++i) { - if (src == src_end || *src == '\n') - break; - *buf++ = *src++; - } - if (i < column) - column = i; - *buf++ = '\n'; - for (i = 1; i < column; ++i) - *buf++ = ' '; - *buf++ = '^'; - *buf++ = '\n'; - *buf = '\0'; - return 0; -} diff --git a/web/server/h2o/libh2o/lib/common/time.c b/web/server/h2o/libh2o/lib/common/time.c deleted file mode 100644 index 368143e78..000000000 --- a/web/server/h2o/libh2o/lib/common/time.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 -#include -#include -#include "h2o/time_.h" - -static char *emit_wday(char *dst, int wday) -{ - memcpy(dst, ("SunMonTueWedThuFriSat") + wday * 3, 3); - return dst + 3; -} - -static char *emit_mon(char *dst, int mon) -{ - memcpy(dst, ("JanFebMarAprMayJunJulAugSepOctNovDec") + mon * 3, 3); - return dst + 3; -} - -static char *emit_digits(char *dst, int n, size_t cnt) -{ - char *p = dst + cnt; - - /* emit digits from back */ - do { - *--p = '0' + n % 10; - n /= 10; - } while (p != dst); - - return dst + cnt; -} - -void h2o_time2str_rfc1123(char *buf, struct tm *gmt) -{ - char *p = buf; - - /* format: Fri, 19 Sep 2014 05:24:04 GMT */ - p = emit_wday(p, gmt->tm_wday); - *p++ = ','; - *p++ = ' '; - p = emit_digits(p, gmt->tm_mday, 2); - *p++ = ' '; - p = emit_mon(p, gmt->tm_mon); - *p++ = ' '; - p = emit_digits(p, gmt->tm_year + 1900, 4); - *p++ = ' '; - p = emit_digits(p, gmt->tm_hour, 2); - *p++ = ':'; - p = emit_digits(p, gmt->tm_min, 2); - *p++ = ':'; - p = emit_digits(p, gmt->tm_sec, 2); - memcpy(p, " GMT", 4); - p += 4; - *p = '\0'; - - assert(p - buf == H2O_TIMESTR_RFC1123_LEN); -} - -static int fetch_digits(const char *s, size_t n) -{ - int value = 0; - for (; n != 0; ++s, --n) { - if (!('0' <= *s && *s <= '9')) - return -1; - value = value * 10 + *s - '0'; - } - return value; -} - -int h2o_time_parse_rfc1123(const char *s, size_t len, struct tm *tm) -{ - if (len != H2O_TIMESTR_RFC1123_LEN) - return -1; - -/* 1 2 - * 01234567890123456789012345678 - * Fri, 19 Sep 2014 05:24:04 GMT - */ - -#define FETCH(dst, pos, n) \ - if ((dst = fetch_digits(s + pos, n)) == -1) \ - return -1; - FETCH(tm->tm_year, 12, 4); - tm->tm_year -= 1900; - /* month is parsed afterwards */ - FETCH(tm->tm_mday, 5, 2); - FETCH(tm->tm_hour, 17, 2); - FETCH(tm->tm_min, 20, 2); - FETCH(tm->tm_sec, 23, 2); -#undef FETCH - -#define PACK3(a, b, c) (((a)&0xff) << 16 | ((b)&0xff) << 8 | ((c)&0xff)) -#define MAP(c1, c2, c3, value) \ - case PACK3(c1, c2, c3): \ - tm->tm_mon = value; \ - break - switch (PACK3(s[8], s[9], s[10])) { - MAP('J', 'a', 'n', 0); - MAP('F', 'e', 'b', 1); - MAP('M', 'a', 'r', 2); - MAP('A', 'p', 'r', 3); - MAP('M', 'a', 'y', 4); - MAP('J', 'u', 'n', 5); - MAP('J', 'u', 'l', 6); - MAP('A', 'u', 'g', 7); - MAP('S', 'e', 'p', 8); - MAP('O', 'c', 't', 9); - MAP('N', 'o', 'v', 10); - MAP('D', 'e', 'c', 11); - default: - return -1; - } -#undef MAP -#undef PACK3 - - return 0; -} - -static int calc_gmt_offset(time_t t, struct tm *local) -{ - struct tm gmt; - int delta; - - gmtime_r(&t, &gmt); - delta = (local->tm_hour - gmt.tm_hour) * 60 + (local->tm_min - gmt.tm_min); - - if (local->tm_yday != gmt.tm_yday) { - int day_offset; - if (local->tm_year == gmt.tm_year) - day_offset = local->tm_yday - gmt.tm_yday; - else - day_offset = local->tm_year - gmt.tm_year; - delta += day_offset * 24 * 60; - } - return delta; -} - -void h2o_time2str_log(char *buf, time_t time) -{ - struct tm localt; - localtime_r(&time, &localt); - int gmt_off = calc_gmt_offset(time, &localt); - int gmt_sign; - - if (gmt_off >= 0) { - gmt_sign = '+'; - } else { - gmt_off = -gmt_off; - gmt_sign = '-'; - } - - int len = sprintf(buf, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d", localt.tm_mday, - ("Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0") + localt.tm_mon * 4, localt.tm_year + 1900, - localt.tm_hour, localt.tm_min, localt.tm_sec, gmt_sign, gmt_off / 60, gmt_off % 60); - assert(len == H2O_TIMESTR_LOG_LEN); -} diff --git a/web/server/h2o/libh2o/lib/common/timeout.c b/web/server/h2o/libh2o/lib/common/timeout.c deleted file mode 100644 index c50be0a3f..000000000 --- a/web/server/h2o/libh2o/lib/common/timeout.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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/timeout.h" - -void h2o_timeout_run(h2o_loop_t *loop, h2o_timeout_t *timeout, uint64_t now) -{ - uint64_t max_registered_at = now - timeout->timeout; - - while (!h2o_linklist_is_empty(&timeout->_entries)) { - h2o_timeout_entry_t *entry = H2O_STRUCT_FROM_MEMBER(h2o_timeout_entry_t, _link, timeout->_entries.next); - if (entry->registered_at > max_registered_at) { - break; - } - h2o_linklist_unlink(&entry->_link); - entry->registered_at = 0; - entry->cb(entry); - h2o_timeout__do_post_callback(loop); - } -} - -uint64_t h2o_timeout_get_wake_at(h2o_linklist_t *timeouts) -{ - h2o_linklist_t *node; - uint64_t wake_at = UINT64_MAX; - - /* change wake_at to the minimum value of the timeouts */ - for (node = timeouts->next; node != timeouts; node = node->next) { - h2o_timeout_t *timeout = H2O_STRUCT_FROM_MEMBER(h2o_timeout_t, _link, node); - if (!h2o_linklist_is_empty(&timeout->_entries)) { - h2o_timeout_entry_t *entry = H2O_STRUCT_FROM_MEMBER(h2o_timeout_entry_t, _link, timeout->_entries.next); - uint64_t entry_wake_at = entry->registered_at + timeout->timeout; - if (entry_wake_at < wake_at) - wake_at = entry_wake_at; - } - } - - return wake_at; -} - -void h2o_timeout_init(h2o_loop_t *loop, h2o_timeout_t *timeout, uint64_t millis) -{ - memset(timeout, 0, sizeof(*timeout)); - timeout->timeout = millis; - h2o_linklist_init_anchor(&timeout->_entries); - - h2o_timeout__do_init(loop, timeout); -} - -void h2o_timeout_dispose(h2o_loop_t *loop, h2o_timeout_t *timeout) -{ - assert(h2o_linklist_is_empty(&timeout->_entries)); - h2o_timeout__do_dispose(loop, timeout); -} - -void h2o_timeout_link(h2o_loop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry) -{ - /* insert at tail, so that the entries are sorted in ascending order */ - h2o_linklist_insert(&timeout->_entries, &entry->_link); - /* set data */ - entry->registered_at = h2o_now(loop); - - h2o_timeout__do_link(loop, timeout, entry); -} - -void h2o_timeout_unlink(h2o_timeout_entry_t *entry) -{ - if (h2o_linklist_is_linked(&entry->_link)) { - h2o_linklist_unlink(&entry->_link); - entry->registered_at = 0; - } -} diff --git a/web/server/h2o/libh2o/lib/common/url.c b/web/server/h2o/libh2o/lib/common/url.c deleted file mode 100644 index d65d18fb5..000000000 --- a/web/server/h2o/libh2o/lib/common/url.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (c) 2014,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 -#include -#include -#include "h2o/memory.h" -#include "h2o/string_.h" -#include "h2o/url.h" - -const h2o_url_scheme_t H2O_URL_SCHEME_HTTP = {{H2O_STRLIT("http")}, 80}; -const h2o_url_scheme_t H2O_URL_SCHEME_HTTPS = {{H2O_STRLIT("https")}, 443}; - -static int decode_hex(int ch) -{ - if ('0' <= ch && ch <= '9') - return ch - '0'; - if ('A' <= ch && ch <= 'F') - return ch - 'A' + 0xa; - if ('a' <= ch && ch <= 'f') - return ch - 'a' + 0xa; - return -1; -} - -static size_t handle_special_paths(const char *path, size_t off, size_t last_slash) -{ - size_t orig_off = off, part_size = off - last_slash; - - if (part_size == 2 && path[off - 1] == '.') { - --off; - } else if (part_size == 3 && path[off - 2] == '.' && path[off - 1] == '.') { - off -= 2; - if (off > 1) { - for (--off; path[off - 1] != '/'; --off) - ; - } - } - return orig_off - off; -} - -/* Perform path normalization and URL decoding in one pass. - * See h2o_req_t for the purpose of @norm_indexes. */ -static h2o_iovec_t rebuild_path(h2o_mem_pool_t *pool, const char *src, size_t src_len, size_t *query_at, size_t **norm_indexes) -{ - char *dst; - size_t src_off = 0, dst_off = 0, last_slash, rewind; - - { /* locate '?', and set len to the end of input path */ - const char *q = memchr(src, '?', src_len); - if (q != NULL) { - src_len = *query_at = q - src; - } else { - *query_at = SIZE_MAX; - } - } - - /* dst can be 1 byte more than src if src is missing the prefixing '/' */ - dst = h2o_mem_alloc_pool(pool, src_len + 1); - *norm_indexes = h2o_mem_alloc_pool(pool, (src_len + 1) * sizeof(*norm_indexes[0])); - - if (src[0] == '/') - src_off++; - last_slash = dst_off; - dst[dst_off] = '/'; - (*norm_indexes)[dst_off] = src_off; - dst_off++; - - /* decode %xx */ - while (src_off < src_len) { - int hi, lo; - char decoded; - - if (src[src_off] == '%' && (src_off + 2 < src_len) && (hi = decode_hex(src[src_off + 1])) != -1 && - (lo = decode_hex(src[src_off + 2])) != -1) { - decoded = (hi << 4) | lo; - src_off += 3; - } else { - decoded = src[src_off++]; - } - if (decoded == '/') { - rewind = handle_special_paths(dst, dst_off, last_slash); - if (rewind > 0) { - dst_off -= rewind; - last_slash = dst_off - 1; - continue; - } - last_slash = dst_off; - } - dst[dst_off] = decoded; - (*norm_indexes)[dst_off] = src_off; - dst_off++; - } - rewind = handle_special_paths(dst, dst_off, last_slash); - dst_off -= rewind; - - return h2o_iovec_init(dst, dst_off); -} - -h2o_iovec_t h2o_url_normalize_path(h2o_mem_pool_t *pool, const char *path, size_t len, size_t *query_at, size_t **norm_indexes) -{ - const char *p = path, *end = path + len; - h2o_iovec_t ret; - - *query_at = SIZE_MAX; - *norm_indexes = NULL; - - if (len == 0) { - ret = h2o_iovec_init("/", 1); - return ret; - } - - if (path[0] != '/') - goto Rewrite; - - for (; p + 1 < end; ++p) { - if ((p[0] == '/' && p[1] == '.') || p[0] == '%') { - /* detect false positives as well */ - goto Rewrite; - } else if (p[0] == '?') { - *query_at = p - path; - goto Return; - } - } - for (; p < end; ++p) { - if (p[0] == '?') { - *query_at = p - path; - goto Return; - } - } - -Return: - ret.base = (char *)path; - ret.len = p - path; - return ret; - -Rewrite: - ret = rebuild_path(pool, path, len, query_at, norm_indexes); - if (ret.len == 0) - goto RewriteError; - if (ret.base[0] != '/') - goto RewriteError; - if (h2o_strstr(ret.base, ret.len, H2O_STRLIT("/../")) != SIZE_MAX) - goto RewriteError; - if (ret.len >= 3 && memcmp(ret.base + ret.len - 3, "/..", 3) == 0) - goto RewriteError; - return ret; -RewriteError: - fprintf(stderr, "failed to normalize path: `%.*s` => `%.*s`\n", (int)len, path, (int)ret.len, ret.base); - ret = h2o_iovec_init("/", 1); - return ret; -} - -static const char *parse_scheme(const char *s, const char *end, const h2o_url_scheme_t **scheme) -{ - if (end - s >= 5 && memcmp(s, "http:", 5) == 0) { - *scheme = &H2O_URL_SCHEME_HTTP; - return s + 5; - } else if (end - s >= 6 && memcmp(s, "https:", 6) == 0) { - *scheme = &H2O_URL_SCHEME_HTTPS; - return s + 6; - } - return NULL; -} - -const char *h2o_url_parse_hostport(const char *s, size_t len, h2o_iovec_t *host, uint16_t *port) -{ - const char *token_start = s, *token_end, *end = s + len; - - *port = 65535; - - if (token_start == end) - return NULL; - - if (*token_start == '[') { - /* is IPv6 address */ - ++token_start; - if ((token_end = memchr(token_start, ']', end - token_start)) == NULL) - return NULL; - *host = h2o_iovec_init(token_start, token_end - token_start); - token_start = token_end + 1; - } else { - for (token_end = token_start; !(token_end == end || *token_end == '/' || *token_end == ':'); ++token_end) - ; - *host = h2o_iovec_init(token_start, token_end - token_start); - token_start = token_end; - } - - /* disallow zero-length host */ - if (host->len == 0) - return NULL; - - /* parse port */ - if (token_start != end && *token_start == ':') { - size_t p; - ++token_start; - if ((token_end = memchr(token_start, '/', end - token_start)) == NULL) - token_end = end; - if ((p = h2o_strtosize(token_start, token_end - token_start)) >= 65535) - return NULL; - *port = (uint16_t)p; - token_start = token_end; - } - - return token_start; -} - -static int parse_authority_and_path(const char *src, const char *url_end, h2o_url_t *parsed) -{ - const char *p = h2o_url_parse_hostport(src, url_end - src, &parsed->host, &parsed->_port); - if (p == NULL) - return -1; - parsed->authority = h2o_iovec_init(src, p - src); - if (p == url_end) { - parsed->path = h2o_iovec_init(H2O_STRLIT("/")); - } else { - if (*p != '/') - return -1; - parsed->path = h2o_iovec_init(p, url_end - p); - } - return 0; -} - -int h2o_url_parse(const char *url, size_t url_len, h2o_url_t *parsed) -{ - const char *url_end, *p; - - if (url_len == SIZE_MAX) - url_len = strlen(url); - url_end = url + url_len; - - /* check and skip scheme */ - if ((p = parse_scheme(url, url_end, &parsed->scheme)) == NULL) - return -1; - - /* skip "//" */ - if (!(url_end - p >= 2 && p[0] == '/' && p[1] == '/')) - return -1; - p += 2; - - return parse_authority_and_path(p, url_end, parsed); -} - -int h2o_url_parse_relative(const char *url, size_t url_len, h2o_url_t *parsed) -{ - const char *url_end, *p; - - if (url_len == SIZE_MAX) - url_len = strlen(url); - url_end = url + url_len; - - /* obtain scheme and port number */ - if ((p = parse_scheme(url, url_end, &parsed->scheme)) == NULL) { - parsed->scheme = NULL; - p = url; - } - - /* handle "//" */ - if (url_end - p >= 2 && p[0] == '/' && p[1] == '/') - return parse_authority_and_path(p + 2, url_end, parsed); - - /* reset authority, host, port, and set path */ - parsed->authority = (h2o_iovec_t){NULL}; - parsed->host = (h2o_iovec_t){NULL}; - parsed->_port = 65535; - parsed->path = h2o_iovec_init(p, url_end - p); - - return 0; -} - -h2o_iovec_t h2o_url_resolve(h2o_mem_pool_t *pool, const h2o_url_t *base, const h2o_url_t *relative, h2o_url_t *dest) -{ - h2o_iovec_t base_path, relative_path, ret; - - assert(base->path.len != 0); - assert(base->path.base[0] == '/'); - - if (relative == NULL) { - /* build URL using base copied to dest */ - *dest = *base; - base_path = base->path; - relative_path = h2o_iovec_init(NULL, 0); - goto Build; - } - - /* scheme */ - dest->scheme = relative->scheme != NULL ? relative->scheme : base->scheme; - - /* authority (and host:port) */ - if (relative->authority.base != NULL) { - assert(relative->host.base != NULL); - dest->authority = relative->authority; - dest->host = relative->host; - dest->_port = relative->_port; - } else { - assert(relative->host.base == NULL); - assert(relative->_port == 65535); - dest->authority = base->authority; - dest->host = base->host; - dest->_port = base->_port; - } - - /* path */ - base_path = base->path; - if (relative->path.base != NULL) { - relative_path = relative->path; - h2o_url_resolve_path(&base_path, &relative_path); - } else { - assert(relative->path.len == 0); - relative_path = (h2o_iovec_t){NULL}; - } - -Build: - /* build the output */ - ret = h2o_concat(pool, dest->scheme->name, h2o_iovec_init(H2O_STRLIT("://")), dest->authority, base_path, relative_path); - /* adjust dest */ - dest->authority.base = ret.base + dest->scheme->name.len + 3; - dest->host.base = dest->authority.base; - if (dest->authority.len != 0 && dest->authority.base[0] == '[') - ++dest->host.base; - dest->path.base = dest->authority.base + dest->authority.len; - dest->path.len = ret.base + ret.len - dest->path.base; - - return ret; -} - -void h2o_url_resolve_path(h2o_iovec_t *base, h2o_iovec_t *relative) -{ - size_t base_path_len = base->len, rel_path_offset = 0; - - if (relative->len != 0 && relative->base[0] == '/') { - base_path_len = 0; - } else { - /* relative path */ - while (base->base[--base_path_len] != '/') - ; - while (rel_path_offset != relative->len) { - if (relative->base[rel_path_offset] == '.') { - if (relative->len - rel_path_offset >= 2 && relative->base[rel_path_offset + 1] == '.' && - (relative->len - rel_path_offset == 2 || relative->base[rel_path_offset + 2] == '/')) { - if (base_path_len != 0) { - while (base->base[--base_path_len] != '/') - ; - } - rel_path_offset += relative->len - rel_path_offset == 2 ? 2 : 3; - continue; - } - if (relative->len - rel_path_offset == 1) { - rel_path_offset += 1; - continue; - } else if (relative->base[rel_path_offset + 1] == '/') { - rel_path_offset += 2; - continue; - } - } - break; - } - base_path_len += 1; - } - - base->len = base_path_len; - *relative = h2o_iovec_init(relative->base + rel_path_offset, relative->len - rel_path_offset); -} - -void h2o_url_copy(h2o_mem_pool_t *pool, h2o_url_t *dest, const h2o_url_t *src) -{ - dest->scheme = src->scheme; - dest->authority = h2o_strdup(pool, src->authority.base, src->authority.len); - dest->host = h2o_strdup(pool, src->host.base, src->host.len); - dest->path = h2o_strdup(pool, src->path.base, src->path.len); - dest->_port = src->_port; -} - -const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa) -{ -#define PREFIX "unix:" - - if (host.len < sizeof(PREFIX) - 1 || memcmp(host.base, PREFIX, sizeof(PREFIX) - 1) != 0) - return h2o_url_host_to_sun_err_is_not_unix_socket; - - if (host.len - sizeof(PREFIX) - 1 >= sizeof(sa->sun_path)) - return "unix-domain socket path is too long"; - - memset(sa, 0, sizeof(*sa)); - sa->sun_family = AF_UNIX; - memcpy(sa->sun_path, host.base + sizeof(PREFIX) - 1, host.len - (sizeof(PREFIX) - 1)); - return NULL; - -#undef PREFIX -} - -const char *h2o_url_host_to_sun_err_is_not_unix_socket = "supplied name does not look like an unix-domain socket"; diff --git a/web/server/h2o/libh2o/lib/core/config.c b/web/server/h2o/libh2o/lib/core/config.c deleted file mode 100644 index ce1d32018..000000000 --- a/web/server/h2o/libh2o/lib/core/config.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2014-2016 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 -#include -#include -#include -#include -#include -#include "h2o.h" -#include "h2o/configurator.h" -#include "h2o/http1.h" -#include "h2o/http2.h" - -static h2o_hostconf_t *create_hostconf(h2o_globalconf_t *globalconf) -{ - h2o_hostconf_t *hostconf = h2o_mem_alloc(sizeof(*hostconf)); - *hostconf = (h2o_hostconf_t){globalconf}; - hostconf->http2.push_preload = 1; /* enabled by default */ - h2o_config_init_pathconf(&hostconf->fallback_path, globalconf, NULL, globalconf->mimemap); - hostconf->mimemap = globalconf->mimemap; - h2o_mem_addref_shared(hostconf->mimemap); - return hostconf; -} - -static void destroy_hostconf(h2o_hostconf_t *hostconf) -{ - size_t i; - - if (hostconf->authority.hostport.base != hostconf->authority.host.base) - free(hostconf->authority.hostport.base); - free(hostconf->authority.host.base); - for (i = 0; i != hostconf->paths.size; ++i) { - h2o_pathconf_t *pathconf = hostconf->paths.entries + i; - h2o_config_dispose_pathconf(pathconf); - } - free(hostconf->paths.entries); - h2o_config_dispose_pathconf(&hostconf->fallback_path); - h2o_mem_release_shared(hostconf->mimemap); - - free(hostconf); -} - -static void on_dispose_envconf(void *_envconf) -{ - h2o_envconf_t *envconf = _envconf; - size_t i; - - if (envconf->parent != NULL) - h2o_mem_release_shared(envconf->parent); - - for (i = 0; i != envconf->unsets.size; ++i) - h2o_mem_release_shared(envconf->unsets.entries[i].base); - free(envconf->unsets.entries); - for (i = 0; i != envconf->sets.size; ++i) - h2o_mem_release_shared(envconf->sets.entries[i].base); - free(envconf->sets.entries); -} - -h2o_envconf_t *h2o_config_create_envconf(h2o_envconf_t *parent) -{ - h2o_envconf_t *envconf = h2o_mem_alloc_shared(NULL, sizeof(*envconf), on_dispose_envconf); - *envconf = (h2o_envconf_t){NULL}; - - if (parent != NULL) { - envconf->parent = parent; - h2o_mem_addref_shared(parent); - } - return envconf; -} - -void h2o_config_setenv(h2o_envconf_t *envconf, const char *name, const char *value) -{ - size_t name_len = strlen(name), i; - h2o_iovec_t *value_slot; - - /* remove from the list of unsets */ - for (i = 0; i != envconf->unsets.size; ++i) { - if (h2o_memis(envconf->unsets.entries[i].base, envconf->unsets.entries[i].len, name, name_len)) { - h2o_mem_release_shared(envconf->unsets.entries[i].base); - h2o_vector_erase(&envconf->unsets, i); - break; - } - } - /* find the slot */ - for (i = 0; i != envconf->sets.size; i += 2) { - if (h2o_memis(envconf->sets.entries[i].base, envconf->sets.entries[i].len, name, name_len)) { - value_slot = envconf->sets.entries + i + 1; - h2o_mem_release_shared(value_slot->base); - goto SetValue; - } - } - /* name not found in existing sets */ - h2o_vector_reserve(NULL, &envconf->sets, envconf->sets.size + 2); - envconf->sets.entries[envconf->sets.size++] = h2o_strdup_shared(NULL, name, name_len); - value_slot = envconf->sets.entries + envconf->sets.size++; -SetValue: - *value_slot = h2o_strdup_shared(NULL, value, SIZE_MAX); -} - -void h2o_config_unsetenv(h2o_envconf_t *envconf, const char *name) -{ - size_t i, name_len = strlen(name); - - /* do nothing if already set */ - for (i = 0; i != envconf->unsets.size; ++i) - if (h2o_memis(envconf->unsets.entries[i].base, envconf->unsets.entries[i].len, name, name_len)) - return; - /* register */ - h2o_vector_reserve(NULL, &envconf->unsets, envconf->unsets.size + 1); - envconf->unsets.entries[envconf->unsets.size++] = h2o_strdup_shared(NULL, name, name_len); -} - -void h2o_config_init_pathconf(h2o_pathconf_t *pathconf, h2o_globalconf_t *globalconf, const char *path, h2o_mimemap_t *mimemap) -{ - memset(pathconf, 0, sizeof(*pathconf)); - pathconf->global = globalconf; - h2o_chunked_register(pathconf); - if (path != NULL) - pathconf->path = h2o_strdup(NULL, path, SIZE_MAX); - h2o_mem_addref_shared(mimemap); - pathconf->mimemap = mimemap; - pathconf->error_log.emit_request_errors = 1; -} - -void h2o_config_dispose_pathconf(h2o_pathconf_t *pathconf) -{ -#define DESTROY_LIST(type, list) \ - do { \ - size_t i; \ - for (i = 0; i != list.size; ++i) { \ - type *e = list.entries[i]; \ - if (e->dispose != NULL) \ - e->dispose(e); \ - free(e); \ - } \ - free(list.entries); \ - } while (0) - DESTROY_LIST(h2o_handler_t, pathconf->handlers); - DESTROY_LIST(h2o_filter_t, pathconf->filters); - DESTROY_LIST(h2o_logger_t, pathconf->loggers); -#undef DESTROY_LIST - - free(pathconf->path.base); - if (pathconf->mimemap != NULL) - h2o_mem_release_shared(pathconf->mimemap); - if (pathconf->env != NULL) - h2o_mem_release_shared(pathconf->env); -} - -void h2o_config_init(h2o_globalconf_t *config) -{ - memset(config, 0, sizeof(*config)); - config->hosts = h2o_mem_alloc(sizeof(config->hosts[0])); - config->hosts[0] = NULL; - h2o_linklist_init_anchor(&config->configurators); - config->server_name = h2o_iovec_init(H2O_STRLIT("h2o/" H2O_VERSION)); - config->max_request_entity_size = H2O_DEFAULT_MAX_REQUEST_ENTITY_SIZE; - config->max_delegations = H2O_DEFAULT_MAX_DELEGATIONS; - config->handshake_timeout = H2O_DEFAULT_HANDSHAKE_TIMEOUT; - config->http1.req_timeout = H2O_DEFAULT_HTTP1_REQ_TIMEOUT; - config->http1.upgrade_to_http2 = H2O_DEFAULT_HTTP1_UPGRADE_TO_HTTP2; - config->http1.callbacks = H2O_HTTP1_CALLBACKS; - config->http2.idle_timeout = H2O_DEFAULT_HTTP2_IDLE_TIMEOUT; - config->http2.graceful_shutdown_timeout = H2O_DEFAULT_HTTP2_GRACEFUL_SHUTDOWN_TIMEOUT; - config->proxy.io_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT; - config->proxy.emit_x_forwarded_headers = 1; - config->proxy.emit_via_header = 1; - config->http2.max_concurrent_requests_per_connection = H2O_HTTP2_SETTINGS_HOST.max_concurrent_streams; - config->http2.max_streams_for_priority = 16; - config->http2.latency_optimization.min_rtt = 50; // milliseconds - config->http2.latency_optimization.max_additional_delay = 10; - config->http2.latency_optimization.max_cwnd = 65535; - config->http2.callbacks = H2O_HTTP2_CALLBACKS; - config->mimemap = h2o_mimemap_create(); - - h2o_configurator__init_core(config); -} - -h2o_pathconf_t *h2o_config_register_path(h2o_hostconf_t *hostconf, const char *path, int flags) -{ - h2o_pathconf_t *pathconf; - - h2o_vector_reserve(NULL, &hostconf->paths, hostconf->paths.size + 1); - pathconf = hostconf->paths.entries + hostconf->paths.size++; - - h2o_config_init_pathconf(pathconf, hostconf->global, path, hostconf->mimemap); - - return pathconf; -} - -void h2o_config_register_status_handler(h2o_globalconf_t *config, h2o_status_handler_t status_handler) -{ - h2o_vector_reserve(NULL, &config->statuses, config->statuses.size + 1); - config->statuses.entries[config->statuses.size++] = status_handler; -} - -void h2o_config_register_simple_status_handler(h2o_globalconf_t *config, h2o_iovec_t name, final_status_handler_cb status_handler) -{ - h2o_status_handler_t *sh; - - h2o_vector_reserve(NULL, &config->statuses, config->statuses.size + 1); - sh = &config->statuses.entries[config->statuses.size++]; - memset(sh, 0, sizeof(*sh)); - sh->name = h2o_strdup(NULL, name.base, name.len); - sh->final = status_handler; -} - -h2o_hostconf_t *h2o_config_register_host(h2o_globalconf_t *config, h2o_iovec_t host, uint16_t port) -{ - h2o_hostconf_t *hostconf = NULL; - h2o_iovec_t host_lc; - - assert(host.len != 0); - - /* convert hostname to lowercase */ - host_lc = h2o_strdup(NULL, host.base, host.len); - h2o_strtolower(host_lc.base, host_lc.len); - - { /* return NULL if given authority is already registered */ - h2o_hostconf_t **p; - for (p = config->hosts; *p != NULL; ++p) - if (h2o_memis((*p)->authority.host.base, (*p)->authority.host.len, host_lc.base, host_lc.len) && - (*p)->authority.port == port) - goto Exit; - } - - /* create hostconf */ - hostconf = create_hostconf(config); - hostconf->authority.host = host_lc; - host_lc = (h2o_iovec_t){NULL}; - hostconf->authority.port = port; - if (hostconf->authority.port == 65535) { - hostconf->authority.hostport = hostconf->authority.host; - } else { - hostconf->authority.hostport.base = h2o_mem_alloc(hostconf->authority.host.len + sizeof("[]:" H2O_UINT16_LONGEST_STR)); - if (strchr(hostconf->authority.host.base, ':') != NULL) { - hostconf->authority.hostport.len = - sprintf(hostconf->authority.hostport.base, "[%s]:%" PRIu16, hostconf->authority.host.base, port); - } else { - hostconf->authority.hostport.len = - sprintf(hostconf->authority.hostport.base, "%s:%" PRIu16, hostconf->authority.host.base, port); - } - } - - /* append to the list */ - h2o_append_to_null_terminated_list((void *)&config->hosts, hostconf); - -Exit: - free(host_lc.base); - return hostconf; -} - -void h2o_config_dispose(h2o_globalconf_t *config) -{ - size_t i; - - for (i = 0; config->hosts[i] != NULL; ++i) { - h2o_hostconf_t *hostconf = config->hosts[i]; - destroy_hostconf(hostconf); - } - free(config->hosts); - - h2o_mem_release_shared(config->mimemap); - h2o_configurator__dispose_configurators(config); -} - -h2o_handler_t *h2o_create_handler(h2o_pathconf_t *conf, size_t sz) -{ - h2o_handler_t *handler = h2o_mem_alloc(sz); - - memset(handler, 0, sz); - handler->_config_slot = conf->global->_num_config_slots++; - - h2o_vector_reserve(NULL, &conf->handlers, conf->handlers.size + 1); - conf->handlers.entries[conf->handlers.size++] = handler; - - return handler; -} - -h2o_filter_t *h2o_create_filter(h2o_pathconf_t *conf, size_t sz) -{ - h2o_filter_t *filter = h2o_mem_alloc(sz); - - memset(filter, 0, sz); - filter->_config_slot = conf->global->_num_config_slots++; - - h2o_vector_reserve(NULL, &conf->filters, conf->filters.size + 1); - memmove(conf->filters.entries + 1, conf->filters.entries, conf->filters.size * sizeof(conf->filters.entries[0])); - conf->filters.entries[0] = filter; - ++conf->filters.size; - - return filter; -} - -h2o_logger_t *h2o_create_logger(h2o_pathconf_t *conf, size_t sz) -{ - h2o_logger_t *logger = h2o_mem_alloc(sz); - - memset(logger, 0, sz); - logger->_config_slot = conf->global->_num_config_slots++; - - h2o_vector_reserve(NULL, &conf->loggers, conf->loggers.size + 1); - conf->loggers.entries[conf->loggers.size++] = logger; - - return logger; -} diff --git a/web/server/h2o/libh2o/lib/core/configurator.c b/web/server/h2o/libh2o/lib/core/configurator.c deleted file mode 100644 index 891770cc2..000000000 --- a/web/server/h2o/libh2o/lib/core/configurator.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * 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/configurator.h" - -struct st_core_config_vars_t { - struct { - unsigned reprioritize_blocking_assets : 1; - unsigned push_preload : 1; - h2o_casper_conf_t casper; - } http2; - struct { - unsigned emit_request_errors : 1; - } error_log; -}; - -struct st_core_configurator_t { - h2o_configurator_t super; - struct st_core_config_vars_t *vars, _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static h2o_configurator_context_t *create_context(h2o_configurator_context_t *parent, int is_custom_handler) -{ - h2o_configurator_context_t *ctx = h2o_mem_alloc(sizeof(*ctx)); - if (parent == NULL) { - *ctx = (h2o_configurator_context_t){NULL}; - return ctx; - } - *ctx = *parent; - if (ctx->env != NULL) - h2o_mem_addref_shared(ctx->env); - ctx->parent = parent; - return ctx; -} - -static void destroy_context(h2o_configurator_context_t *ctx) -{ - if (ctx->env != NULL) { - if (ctx->pathconf != NULL) - ctx->pathconf->env = ctx->env; - else - h2o_mem_release_shared(ctx->env); - } - free(ctx); -} - -static int on_core_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)_self; - - ++self->vars; - self->vars[0] = self->vars[-1]; - return 0; -} - -static int on_core_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)_self; - - if (ctx->hostconf != NULL && ctx->pathconf == NULL) { - /* exitting from host-level configuration */ - ctx->hostconf->http2.reprioritize_blocking_assets = self->vars->http2.reprioritize_blocking_assets; - ctx->hostconf->http2.push_preload = self->vars->http2.push_preload; - ctx->hostconf->http2.casper = self->vars->http2.casper; - } else if (ctx->pathconf != NULL) { - /* exitting from path or extension-level configuration */ - ctx->pathconf->error_log.emit_request_errors = self->vars->error_log.emit_request_errors; - } - - --self->vars; - return 0; -} - -static void destroy_configurator(h2o_configurator_t *configurator) -{ - if (configurator->dispose != NULL) - configurator->dispose(configurator); - free(configurator->commands.entries); - free(configurator); -} - -static int setup_configurators(h2o_configurator_context_t *ctx, int is_enter, yoml_t *node) -{ - h2o_linklist_t *n; - - for (n = ctx->globalconf->configurators.next; n != &ctx->globalconf->configurators; n = n->next) { - h2o_configurator_t *c = H2O_STRUCT_FROM_MEMBER(h2o_configurator_t, _link, n); - if (is_enter) { - if (c->enter != NULL && c->enter(c, ctx, node) != 0) - return -1; - } else { - if (c->exit != NULL && c->exit(c, ctx, node) != 0) - return -1; - } - } - - return 0; -} - -static int config_timeout(h2o_configurator_command_t *cmd, yoml_t *node, uint64_t *slot) -{ - uint64_t timeout_in_secs; - - if (h2o_configurator_scanf(cmd, node, "%" SCNu64, &timeout_in_secs) != 0) - return -1; - - *slot = timeout_in_secs * 1000; - return 0; -} - -int h2o_configurator_apply_commands(h2o_configurator_context_t *ctx, yoml_t *node, int flags_mask, const char **ignore_commands) -{ - struct st_cmd_value_t { - h2o_configurator_command_t *cmd; - yoml_t *value; - }; - H2O_VECTOR(struct st_cmd_value_t) deferred = {NULL}, semi_deferred = {NULL}; - int ret = -1; - - if (node != NULL && node->type != YOML_TYPE_MAPPING) { - h2o_configurator_errprintf(NULL, node, "node must be a MAPPING"); - goto Exit; - } - - /* call on_enter of every configurator */ - if (setup_configurators(ctx, 1, node) != 0) - goto Exit; - - /* handle the configuration commands */ - if (node != NULL) { - size_t i; - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key, *value = node->data.mapping.elements[i].value; - h2o_configurator_command_t *cmd; - /* obtain the target command */ - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(NULL, key, "command must be a string"); - goto Exit; - } - if (ignore_commands != NULL) { - size_t i; - for (i = 0; ignore_commands[i] != NULL; ++i) - if (strcmp(ignore_commands[i], key->data.scalar) == 0) - goto SkipCommand; - } - if ((cmd = h2o_configurator_get_command(ctx->globalconf, key->data.scalar)) == NULL) { - h2o_configurator_errprintf(NULL, key, "unknown command: %s", key->data.scalar); - goto Exit; - } - if ((cmd->flags & flags_mask) == 0) { - h2o_configurator_errprintf(cmd, key, "the command cannot be used at this level"); - goto Exit; - } - /* check value type */ - if ((cmd->flags & (H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE | - H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING)) != 0) { - switch (value->type) { - case YOML_TYPE_SCALAR: - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR) == 0) { - h2o_configurator_errprintf(cmd, value, "argument cannot be a scalar"); - goto Exit; - } - break; - case YOML_TYPE_SEQUENCE: - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE) == 0) { - h2o_configurator_errprintf(cmd, value, "argument cannot be a sequence"); - goto Exit; - } - break; - case YOML_TYPE_MAPPING: - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING) == 0) { - h2o_configurator_errprintf(cmd, value, "argument cannot be a mapping"); - goto Exit; - } - break; - default: - assert(!"unreachable"); - break; - } - } - /* handle the command (or keep it for later execution) */ - if ((cmd->flags & H2O_CONFIGURATOR_FLAG_SEMI_DEFERRED) != 0) { - h2o_vector_reserve(NULL, &semi_deferred, semi_deferred.size + 1); - semi_deferred.entries[semi_deferred.size++] = (struct st_cmd_value_t){cmd, value}; - } else if ((cmd->flags & H2O_CONFIGURATOR_FLAG_DEFERRED) != 0) { - h2o_vector_reserve(NULL, &deferred, deferred.size + 1); - deferred.entries[deferred.size++] = (struct st_cmd_value_t){cmd, value}; - } else { - if (cmd->cb(cmd, ctx, value) != 0) - goto Exit; - } - SkipCommand:; - } - for (i = 0; i != semi_deferred.size; ++i) { - struct st_cmd_value_t *pair = semi_deferred.entries + i; - if (pair->cmd->cb(pair->cmd, ctx, pair->value) != 0) - goto Exit; - } - for (i = 0; i != deferred.size; ++i) { - struct st_cmd_value_t *pair = deferred.entries + i; - if (pair->cmd->cb(pair->cmd, ctx, pair->value) != 0) - goto Exit; - } - } - - /* call on_exit of every configurator */ - if (setup_configurators(ctx, 0, node) != 0) - goto Exit; - - ret = 0; -Exit: - free(deferred.entries); - free(semi_deferred.entries); - return ret; -} - -static int sort_from_longer_paths(const yoml_mapping_element_t *x, const yoml_mapping_element_t *y) -{ - size_t xlen = strlen(x->key->data.scalar), ylen = strlen(y->key->data.scalar); - if (xlen < ylen) - return 1; - else if (xlen > ylen) - return -1; - /* apply strcmp for stable sort */ - return strcmp(x->key->data.scalar, y->key->data.scalar); -} - -static yoml_t *convert_path_config_node(h2o_configurator_command_t *cmd, yoml_t *node) -{ - size_t i, j; - - switch (node->type) { - case YOML_TYPE_MAPPING: - break; - case YOML_TYPE_SEQUENCE: { - /* convert to mapping */ - yoml_t *map = h2o_mem_alloc(sizeof(yoml_t)); - *map = (yoml_t){YOML_TYPE_MAPPING}; - if (node->filename != NULL) - map->filename = h2o_strdup(NULL, node->filename, SIZE_MAX).base; - map->line = node->line; - map->column = node->column; - if (node->anchor != NULL) - map->anchor = h2o_strdup(NULL, node->anchor, SIZE_MAX).base; - map->_refcnt = 1; - - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *elem = node->data.sequence.elements[i]; - if (elem->type != YOML_TYPE_MAPPING) { - yoml_free(map, NULL); - goto Error; - } - for (j = 0; j != elem->data.mapping.size; ++j) { - yoml_t *elemkey = elem->data.mapping.elements[j].key; - yoml_t *elemvalue = elem->data.mapping.elements[j].value; - map = h2o_mem_realloc(map, offsetof(yoml_t, data.mapping.elements) + - sizeof(yoml_mapping_element_t) * (map->data.mapping.size + 1)); - map->data.mapping.elements[map->data.mapping.size].key = elemkey; - map->data.mapping.elements[map->data.mapping.size].value = elemvalue; - ++map->data.mapping.size; - ++elemkey->_refcnt; - ++elemvalue->_refcnt; - } - } - return map; - } break; - default: - Error: - h2o_configurator_errprintf(cmd, node, "value must be a mapping or sequence of mapping"); - return NULL; - } - - ++node->_refcnt; - return node; -} - -static int config_path(h2o_configurator_context_t *parent_ctx, h2o_pathconf_t *pathconf, yoml_t *node) -{ - h2o_configurator_context_t *path_ctx = create_context(parent_ctx, 0); - path_ctx->pathconf = pathconf; - path_ctx->mimemap = &pathconf->mimemap; - - int ret = h2o_configurator_apply_commands(path_ctx, node, H2O_CONFIGURATOR_FLAG_PATH, NULL); - - destroy_context(path_ctx); - return ret; -} - -static int on_config_paths(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - /* sort by the length of the path (descending) */ - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, key, "key (representing the virtual path) must be a string"); - return -1; - } - } - qsort(node->data.mapping.elements, node->data.mapping.size, sizeof(node->data.mapping.elements[0]), - (int (*)(const void *, const void *))sort_from_longer_paths); - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key, *value; - if ((value = convert_path_config_node(cmd, node->data.mapping.elements[i].value)) == NULL) - return -1; - h2o_pathconf_t *pathconf = h2o_config_register_path(ctx->hostconf, key->data.scalar, 0); - int cmd_ret = config_path(ctx, pathconf, value); - yoml_free(value, NULL); - if (cmd_ret != 0) - return cmd_ret; - } - - /* configure fallback path along with ordinary paths */ - return config_path(ctx, &ctx->hostconf->fallback_path, NULL); -} - -static int on_config_hosts(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - if (node->data.mapping.size == 0) { - h2o_configurator_errprintf(cmd, node, "the mapping cannot be empty"); - return -1; - } - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - yoml_t *value = node->data.mapping.elements[i].value; - h2o_iovec_t hostname; - uint16_t port; - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, key, "key (representing the hostname) must be a string"); - return -1; - } - if (h2o_url_parse_hostport(key->data.scalar, strlen(key->data.scalar), &hostname, &port) == NULL) { - h2o_configurator_errprintf(cmd, key, "invalid key (must be either `host` or `host:port`)"); - return -1; - } - assert(hostname.len != 0); - if ((hostname.base[0] == '*' && !(hostname.len == 1 || hostname.base[1] == '.')) || - memchr(hostname.base + 1, '*', hostname.len - 1) != NULL) { - h2o_configurator_errprintf(cmd, key, "wildcard (*) can only be used at the start of the hostname"); - return -1; - } - h2o_configurator_context_t *host_ctx = create_context(ctx, 0); - if ((host_ctx->hostconf = h2o_config_register_host(host_ctx->globalconf, hostname, port)) == NULL) { - h2o_configurator_errprintf(cmd, key, "duplicate host entry"); - destroy_context(host_ctx); - return -1; - } - host_ctx->mimemap = &host_ctx->hostconf->mimemap; - int cmd_ret = h2o_configurator_apply_commands(host_ctx, value, H2O_CONFIGURATOR_FLAG_HOST, NULL); - destroy_context(host_ctx); - if (cmd_ret != 0) - return -1; - if (yoml_get(value, "paths") == NULL) { - h2o_configurator_errprintf(NULL, value, "mandatory configuration directive `paths` is missing"); - return -1; - } - } - - return 0; -} - -static int on_config_limit_request_body(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%zu", &ctx->globalconf->max_request_entity_size); -} - -static int on_config_max_delegations(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->max_delegations); -} - -static int on_config_handshake_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->handshake_timeout); -} - -static int on_config_http1_request_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->http1.req_timeout); -} - -static int on_config_http1_upgrade_to_http2(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - ctx->globalconf->http1.upgrade_to_http2 = (int)ret; - return 0; -} - -static int on_config_http2_idle_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->http2.idle_timeout); -} - -static int on_config_http2_graceful_shutdown_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - return config_timeout(cmd, node, &ctx->globalconf->http2.graceful_shutdown_timeout); -} - -static int on_config_http2_max_concurrent_requests_per_connection(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%zu", &ctx->globalconf->http2.max_concurrent_requests_per_connection); -} - -static int on_config_http2_latency_optimization_min_rtt(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->http2.latency_optimization.min_rtt); -} - -static int on_config_http2_latency_optimization_max_additional_delay(h2o_configurator_command_t *cmd, - h2o_configurator_context_t *ctx, yoml_t *node) -{ - double ratio; - if (h2o_configurator_scanf(cmd, node, "%lf", &ratio) != 0) - return -1; - if (!(0.0 < ratio)) { - h2o_configurator_errprintf(cmd, node, "ratio must be a positive number"); - return -1; - } - ctx->globalconf->http2.latency_optimization.max_additional_delay = 100 * ratio; - return 0; -} - -static int on_config_http2_latency_optimization_max_cwnd(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->http2.latency_optimization.max_cwnd); -} - -static int on_config_http2_reprioritize_blocking_assets(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)cmd->configurator; - ssize_t on; - - if ((on = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - self->vars->http2.reprioritize_blocking_assets = (int)on; - - return 0; -} - -static int on_config_http2_push_preload(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)cmd->configurator; - ssize_t on; - - if ((on = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - self->vars->http2.push_preload = (int)on; - - return 0; -} - -static int on_config_http2_casper(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - static const h2o_casper_conf_t defaults = { - 13, /* casper_bits: default (2^13 ~= 100 assets * 1/0.01 collision probability) */ - 0 /* track blocking assets only */ - }; - - struct st_core_configurator_t *self = (void *)cmd->configurator; - - switch (node->type) { - case YOML_TYPE_SCALAR: - if (strcasecmp(node->data.scalar, "OFF") == 0) { - self->vars->http2.casper = (h2o_casper_conf_t){0}; - } else if (strcasecmp(node->data.scalar, "ON") == 0) { - self->vars->http2.casper = defaults; - } - break; - case YOML_TYPE_MAPPING: { - /* set to default */ - self->vars->http2.casper = defaults; - /* override the attributes defined */ - yoml_t *t; - if ((t = yoml_get(node, "capacity-bits")) != NULL) { - if (!(t->type == YOML_TYPE_SCALAR && sscanf(t->data.scalar, "%u", &self->vars->http2.casper.capacity_bits) == 1 && - self->vars->http2.casper.capacity_bits < 16)) { - h2o_configurator_errprintf(cmd, t, "value of `capacity-bits` must be an integer between 0 to 15"); - return -1; - } - } - if ((t = yoml_get(node, "tracking-types")) != NULL) { - if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "blocking-assets") == 0) { - self->vars->http2.casper.track_all_types = 0; - } else if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "all") == 0) { - self->vars->http2.casper.track_all_types = 1; - } else { - h2o_configurator_errprintf(cmd, t, "value of `tracking-types` must be either of: `blocking-assets` or `all`"); - return -1; - } - } - } break; - default: - h2o_configurator_errprintf(cmd, node, "value must be `OFF`,`ON` or a mapping containing the necessary attributes"); - return -1; - } - - return 0; -} - -static int assert_is_mimetype(h2o_configurator_command_t *cmd, yoml_t *node) -{ - if (node->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, node, "expected a scalar (mime-type)"); - return -1; - } - if (strchr(node->data.scalar, '/') == NULL) { - h2o_configurator_errprintf(cmd, node, "the string \"%s\" does not look like a mime-type", node->data.scalar); - return -1; - } - return 0; -} - -static int assert_is_extension(h2o_configurator_command_t *cmd, yoml_t *node) -{ - if (node->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, node, "expected a scalar (extension)"); - return -1; - } - if (node->data.scalar[0] != '.') { - h2o_configurator_errprintf(cmd, node, "given extension \"%s\" does not start with a \".\"", node->data.scalar); - return -1; - } - return 0; -} - -static int set_mimetypes(h2o_configurator_command_t *cmd, h2o_mimemap_t *mimemap, yoml_t *node) -{ - size_t i, j; - - assert(node->type == YOML_TYPE_MAPPING); - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - yoml_t *value = node->data.mapping.elements[i].value; - if (assert_is_mimetype(cmd, key) != 0) - return -1; - switch (value->type) { - case YOML_TYPE_SCALAR: - if (assert_is_extension(cmd, value) != 0) - return -1; - h2o_mimemap_define_mimetype(mimemap, value->data.scalar + 1, key->data.scalar, NULL); - break; - case YOML_TYPE_SEQUENCE: - for (j = 0; j != value->data.sequence.size; ++j) { - yoml_t *ext_node = value->data.sequence.elements[j]; - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - h2o_mimemap_define_mimetype(mimemap, ext_node->data.scalar + 1, key->data.scalar, NULL); - } - break; - case YOML_TYPE_MAPPING: { - yoml_t *t; - h2o_mime_attributes_t attr; - h2o_mimemap_get_default_attributes(key->data.scalar, &attr); - if ((t = yoml_get(value, "is_compressible")) != NULL) { - if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "YES") == 0) { - attr.is_compressible = 1; - } else if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "NO") == 0) { - attr.is_compressible = 0; - } else { - h2o_configurator_errprintf(cmd, t, "`is_compressible` attribute must be either of: `YES` or `NO`"); - return -1; - } - } - if ((t = yoml_get(value, "priority")) != NULL) { - if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "normal") == 0) { - attr.priority = H2O_MIME_ATTRIBUTE_PRIORITY_NORMAL; - } else if (t->type == YOML_TYPE_SCALAR && strcasecmp(t->data.scalar, "highest") == 0) { - attr.priority = H2O_MIME_ATTRIBUTE_PRIORITY_HIGHEST; - } else { - h2o_configurator_errprintf(cmd, t, "`priority` attribute must be either of: `normal` or `highest`"); - return -1; - } - } - if ((t = yoml_get(value, "extensions")) == NULL) { - h2o_configurator_errprintf(cmd, value, "cannot find mandatory attribute `extensions`"); - return -1; - } - if (t->type != YOML_TYPE_SEQUENCE) { - h2o_configurator_errprintf(cmd, t, "`extensions` attribute must be a sequence of scalars"); - return -1; - } - for (j = 0; j != t->data.sequence.size; ++j) { - yoml_t *ext_node = t->data.sequence.elements[j]; - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - h2o_mimemap_define_mimetype(mimemap, ext_node->data.scalar + 1, key->data.scalar, &attr); - } - } break; - default: - fprintf(stderr, "logic flaw at %s:%d\n", __FILE__, __LINE__); - abort(); - } - } - - return 0; -} - -static int on_config_mime_settypes(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - h2o_mimemap_t *newmap = h2o_mimemap_create(); - h2o_mimemap_clear_types(newmap); - h2o_mimemap_set_default_type(newmap, h2o_mimemap_get_default_type(*ctx->mimemap)->data.mimetype.base, NULL); - if (set_mimetypes(cmd, newmap, node) != 0) { - h2o_mem_release_shared(newmap); - return -1; - } - - h2o_mem_release_shared(*ctx->mimemap); - *ctx->mimemap = newmap; - return 0; -} - -static void clone_mimemap_if_clean(h2o_configurator_context_t *ctx) -{ - if (ctx->parent == NULL) - return; - if (*ctx->mimemap != *ctx->parent->mimemap) - return; - h2o_mem_release_shared(*ctx->mimemap); - /* even after release, ctx->mimemap is still retained by the parent and therefore we can use it as the argument to clone */ - *ctx->mimemap = h2o_mimemap_clone(*ctx->mimemap); -} - -static int on_config_mime_addtypes(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - clone_mimemap_if_clean(ctx); - return set_mimetypes(cmd, *ctx->mimemap, node); -} - -static int on_config_mime_removetypes(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - clone_mimemap_if_clean(ctx); - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *ext_node = node->data.sequence.elements[i]; - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - h2o_mimemap_remove_type(*ctx->mimemap, ext_node->data.scalar + 1); - } - - return 0; -} - -static int on_config_mime_setdefaulttype(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - if (assert_is_mimetype(cmd, node) != 0) - return -1; - - clone_mimemap_if_clean(ctx); - h2o_mimemap_set_default_type(*ctx->mimemap, node->data.scalar, NULL); - - return 0; -} - -static int on_config_custom_handler(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - static const char *ignore_commands[] = {"extension", NULL}; - yoml_t *ext_node; - const char **exts; - h2o_mimemap_type_t *type = NULL; - - if (node->type != YOML_TYPE_MAPPING) { - h2o_configurator_errprintf(cmd, node, "argument must be a MAPPING"); - return -1; - } - if ((ext_node = yoml_get(node, "extension")) == NULL) { - h2o_configurator_errprintf(cmd, node, "mandatory key `extension` is missing"); - return -1; - } - - /* create dynamic type */ - switch (ext_node->type) { - case YOML_TYPE_SCALAR: - if (assert_is_extension(cmd, ext_node) != 0) - return -1; - exts = alloca(2 * sizeof(*exts)); - exts[0] = ext_node->data.scalar + 1; - exts[1] = NULL; - break; - case YOML_TYPE_SEQUENCE: { - exts = alloca((ext_node->data.sequence.size + 1) * sizeof(*exts)); - size_t i; - for (i = 0; i != ext_node->data.sequence.size; ++i) { - yoml_t *n = ext_node->data.sequence.elements[i]; - if (assert_is_extension(cmd, n) != 0) - return -1; - exts[i] = n->data.scalar + 1; - } - exts[i] = NULL; - } break; - default: - h2o_configurator_errprintf(cmd, ext_node, "`extensions` must be a scalar or sequence of scalar"); - return -1; - } - clone_mimemap_if_clean(ctx); - type = h2o_mimemap_define_dynamic(*ctx->mimemap, exts, ctx->globalconf); - - /* apply the configuration commands */ - h2o_configurator_context_t *ext_ctx = create_context(ctx, 1); - ext_ctx->pathconf = &type->data.dynamic.pathconf; - ext_ctx->mimemap = NULL; - int cmd_ret = h2o_configurator_apply_commands(ext_ctx, node, H2O_CONFIGURATOR_FLAG_EXTENSION, ignore_commands); - destroy_context(ext_ctx); - if (cmd_ret != 0) - return cmd_ret; - switch (type->data.dynamic.pathconf.handlers.size) { - case 1: - break; - case 0: - h2o_configurator_errprintf(cmd, node, "no handler declared for given extension"); - return -1; - default: - h2o_configurator_errprintf(cmd, node, "cannot assign more than one handler for given extension"); - return -1; - } - - return 0; -} - -static void inherit_env_if_necessary(h2o_configurator_context_t *ctx) -{ - if (ctx->env == (ctx->parent != NULL ? ctx->parent->env : NULL)) - ctx->env = h2o_config_create_envconf(ctx->env); -} - -static int on_config_setenv(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - size_t i; - - inherit_env_if_necessary(ctx); - - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key, *value = node->data.mapping.elements[i].value; - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, key, "key must be a scalar"); - return -1; - } - if (value->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, value, "value must be a scalar"); - return -1; - } - h2o_config_setenv(ctx->env, key->data.scalar, value->data.scalar); - } - - return 0; -} - -static int on_config_unsetenv(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - inherit_env_if_necessary(ctx); - - switch (node->type) { - case YOML_TYPE_SCALAR: - h2o_config_unsetenv(ctx->env, node->data.scalar); - break; - case YOML_TYPE_SEQUENCE: { - size_t i; - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *element = node->data.sequence.elements[i]; - if (element->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, element, "element of a sequence passed to unsetenv must be a scalar"); - return -1; - } - h2o_config_unsetenv(ctx->env, element->data.scalar); - } - } break; - default: - h2o_configurator_errprintf(cmd, node, "argument to unsetenv must be either a scalar or a sequence"); - return -1; - } - - return 0; -} - -static int on_config_server_name(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - ctx->globalconf->server_name = h2o_strdup(NULL, node->data.scalar, SIZE_MAX); - return 0; -} - -static int on_config_send_server_name(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - switch(h2o_configurator_get_one_of(cmd, node, "OFF,ON,preserve")) { - case 0: /* off */ - ctx->globalconf->server_name = h2o_iovec_init(H2O_STRLIT("")); - break; - case 1: /* on */ - break; - case 2: /* preserve */ - ctx->globalconf->server_name = h2o_iovec_init(H2O_STRLIT("")); - ctx->globalconf->proxy.preserve_server_header = 1; - break; - default: - return -1; - } - return 0; -} - -static int on_config_error_log_emit_request_errors(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_core_configurator_t *self = (void *)cmd->configurator; - ssize_t on; - - if ((on = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - - self->vars->error_log.emit_request_errors = (int)on; - return 0; -} - -void h2o_configurator__init_core(h2o_globalconf_t *conf) -{ - /* check if already initialized */ - if (h2o_configurator_get_command(conf, "files") != NULL) - return; - - { /* `hosts` and `paths` */ - h2o_configurator_t *c = h2o_configurator_create(conf, sizeof(*c)); - h2o_configurator_define_command(c, "hosts", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_hosts); - h2o_configurator_define_command(c, "paths", H2O_CONFIGURATOR_FLAG_HOST | H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_paths); - }; - - { /* setup global configurators */ - struct st_core_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - c->super.enter = on_core_enter; - c->super.exit = on_core_exit; - c->vars = c->_vars_stack; - c->vars->http2.reprioritize_blocking_assets = 1; /* defaults to ON */ - c->vars->http2.push_preload = 1; /* defaults to ON */ - c->vars->error_log.emit_request_errors = 1; /* defaults to ON */ - h2o_configurator_define_command(&c->super, "limit-request-body", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_limit_request_body); - h2o_configurator_define_command(&c->super, "max-delegations", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_max_delegations); - h2o_configurator_define_command(&c->super, "handshake-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_handshake_timeout); - h2o_configurator_define_command(&c->super, "http1-request-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http1_request_timeout); - h2o_configurator_define_command(&c->super, "http1-upgrade-to-http2", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http1_upgrade_to_http2); - h2o_configurator_define_command(&c->super, "http2-idle-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_idle_timeout); - h2o_configurator_define_command(&c->super, "http2-graceful-shutdown-timeout", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_graceful_shutdown_timeout); - h2o_configurator_define_command(&c->super, "http2-max-concurrent-requests-per-connection", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_max_concurrent_requests_per_connection); - h2o_configurator_define_command(&c->super, "http2-latency-optimization-min-rtt", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_latency_optimization_min_rtt); - h2o_configurator_define_command(&c->super, "http2-latency-optimization-max-additional-delay", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_latency_optimization_max_additional_delay); - h2o_configurator_define_command(&c->super, "http2-latency-optimization-max-cwnd", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_latency_optimization_max_cwnd); - h2o_configurator_define_command(&c->super, "http2-reprioritize-blocking-assets", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_reprioritize_blocking_assets); - h2o_configurator_define_command(&c->super, "http2-push-preload", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_http2_push_preload); - h2o_configurator_define_command(&c->super, "http2-casper", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST, - on_config_http2_casper); - h2o_configurator_define_command(&c->super, "file.mime.settypes", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING, - on_config_mime_settypes); - h2o_configurator_define_command(&c->super, "file.mime.addtypes", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING, - on_config_mime_addtypes); - h2o_configurator_define_command(&c->super, "file.mime.removetypes", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE, - on_config_mime_removetypes); - h2o_configurator_define_command(&c->super, "file.mime.setdefaulttype", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_mime_setdefaulttype); - h2o_configurator_define_command(&c->super, "file.custom-handler", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_SEMI_DEFERRED, - on_config_custom_handler); - h2o_configurator_define_command(&c->super, "setenv", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING, on_config_setenv); - h2o_configurator_define_command(&c->super, "unsetenv", H2O_CONFIGURATOR_FLAG_ALL_LEVELS, on_config_unsetenv); - h2o_configurator_define_command(&c->super, "server-name", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_server_name); - h2o_configurator_define_command(&c->super, "send-server-name", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_send_server_name); - h2o_configurator_define_command(&c->super, "error-log.emit-request-errors", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_error_log_emit_request_errors); - } -} - -void h2o_configurator__dispose_configurators(h2o_globalconf_t *conf) -{ - while (!h2o_linklist_is_empty(&conf->configurators)) { - h2o_configurator_t *c = H2O_STRUCT_FROM_MEMBER(h2o_configurator_t, _link, conf->configurators.next); - h2o_linklist_unlink(&c->_link); - if (c->dispose != NULL) - c->dispose(c); - destroy_configurator(c); - } -} - -h2o_configurator_t *h2o_configurator_create(h2o_globalconf_t *conf, size_t sz) -{ - h2o_configurator_t *c; - - assert(sz >= sizeof(*c)); - - c = h2o_mem_alloc(sz); - memset(c, 0, sz); - h2o_linklist_insert(&conf->configurators, &c->_link); - - return c; -} - -void h2o_configurator_define_command(h2o_configurator_t *configurator, const char *name, int flags, h2o_configurator_command_cb cb) -{ - h2o_configurator_command_t *cmd; - - h2o_vector_reserve(NULL, &configurator->commands, configurator->commands.size + 1); - cmd = configurator->commands.entries + configurator->commands.size++; - cmd->configurator = configurator; - cmd->flags = flags; - cmd->name = name; - cmd->cb = cb; -} - -h2o_configurator_command_t *h2o_configurator_get_command(h2o_globalconf_t *conf, const char *name) -{ - h2o_linklist_t *node; - size_t i; - - for (node = conf->configurators.next; node != &conf->configurators; node = node->next) { - h2o_configurator_t *configurator = H2O_STRUCT_FROM_MEMBER(h2o_configurator_t, _link, node); - for (i = 0; i != configurator->commands.size; ++i) { - h2o_configurator_command_t *cmd = configurator->commands.entries + i; - if (strcmp(cmd->name, name) == 0) { - return cmd; - } - } - } - - return NULL; -} - -int h2o_configurator_apply(h2o_globalconf_t *config, yoml_t *node, int dry_run) -{ - h2o_configurator_context_t *ctx = create_context(NULL, 0); - ctx->globalconf = config; - ctx->mimemap = &ctx->globalconf->mimemap; - ctx->dry_run = dry_run; - int cmd_ret = h2o_configurator_apply_commands(ctx, node, H2O_CONFIGURATOR_FLAG_GLOBAL, NULL); - destroy_context(ctx); - - if (cmd_ret != 0) - return cmd_ret; - if (config->hosts[0] == NULL) { - h2o_configurator_errprintf(NULL, node, "mandatory configuration directive `hosts` is missing"); - return -1; - } - return 0; -} - -void h2o_configurator_errprintf(h2o_configurator_command_t *cmd, yoml_t *node, const char *reason, ...) -{ - va_list args; - - fprintf(stderr, "[%s:%zu] ", node->filename ? node->filename : "-", node->line + 1); - if (cmd != NULL) - fprintf(stderr, "in command %s, ", cmd->name); - va_start(args, reason); - vfprintf(stderr, reason, args); - va_end(args); - fputc('\n', stderr); -} - -int h2o_configurator_scanf(h2o_configurator_command_t *cmd, yoml_t *node, const char *fmt, ...) -{ - va_list args; - int sscan_ret; - - if (node->type != YOML_TYPE_SCALAR) - goto Error; - va_start(args, fmt); - sscan_ret = vsscanf(node->data.scalar, fmt, args); - va_end(args); - if (sscan_ret != 1) - goto Error; - - return 0; -Error: - h2o_configurator_errprintf(cmd, node, "argument must match the format: %s", fmt); - return -1; -} - -ssize_t h2o_configurator_get_one_of(h2o_configurator_command_t *cmd, yoml_t *node, const char *candidates) -{ - const char *config_str, *cand_str; - ssize_t config_str_len, cand_index; - - if (node->type != YOML_TYPE_SCALAR) - goto Error; - - config_str = node->data.scalar; - config_str_len = strlen(config_str); - - cand_str = candidates; - for (cand_index = 0;; ++cand_index) { - if (strncasecmp(cand_str, config_str, config_str_len) == 0 && - (cand_str[config_str_len] == '\0' || cand_str[config_str_len] == ',')) { - /* found */ - return cand_index; - } - cand_str = strchr(cand_str, ','); - if (cand_str == NULL) - goto Error; - cand_str += 1; /* skip ',' */ - } -/* not reached */ - -Error: - h2o_configurator_errprintf(cmd, node, "argument must be one of: %s", candidates); - return -1; -} - -char *h2o_configurator_get_cmd_path(const char *cmd) -{ - char *root, *cmd_fullpath; - - /* just return the cmd (being strdup'ed) in case we do not need to prefix the value */ - if (cmd[0] == '/' || strchr(cmd, '/') == NULL) - goto ReturnOrig; - - /* obtain root */ - if ((root = getenv("H2O_ROOT")) == NULL) { - root = H2O_TO_STR(H2O_ROOT); - } - - /* build full-path and return */ - cmd_fullpath = h2o_mem_alloc(strlen(root) + strlen(cmd) + 2); - sprintf(cmd_fullpath, "%s/%s", root, cmd); - return cmd_fullpath; - -ReturnOrig: - return h2o_strdup(NULL, cmd, SIZE_MAX).base; -} diff --git a/web/server/h2o/libh2o/lib/core/context.c b/web/server/h2o/libh2o/lib/core/context.c deleted file mode 100644 index 8d1101381..000000000 --- a/web/server/h2o/libh2o/lib/core/context.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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 -#include -#include -#include "h2o.h" -#include "h2o/memcached.h" - -void h2o_context_init_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf) -{ - /* add pathconf to the inited list (or return if already inited) */ - size_t i; - for (i = 0; i != ctx->_pathconfs_inited.size; ++i) - if (ctx->_pathconfs_inited.entries[i] == pathconf) - return; - h2o_vector_reserve(NULL, &ctx->_pathconfs_inited, ctx->_pathconfs_inited.size + 1); - ctx->_pathconfs_inited.entries[ctx->_pathconfs_inited.size++] = pathconf; - -#define DOIT(type, list) \ - do { \ - size_t i; \ - for (i = 0; i != pathconf->list.size; ++i) { \ - type *o = pathconf->list.entries[i]; \ - if (o->on_context_init != NULL) \ - o->on_context_init(o, ctx); \ - } \ - } while (0) - - DOIT(h2o_handler_t, handlers); - DOIT(h2o_filter_t, filters); - DOIT(h2o_logger_t, loggers); - -#undef DOIT -} - -void h2o_context_dispose_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf) -{ - /* nullify pathconf in the inited list (or return if already disposed) */ - size_t i; - for (i = 0; i != ctx->_pathconfs_inited.size; ++i) - if (ctx->_pathconfs_inited.entries[i] == pathconf) - break; - if (i == ctx->_pathconfs_inited.size) - return; - ctx->_pathconfs_inited.entries[i] = NULL; - -#define DOIT(type, list) \ - do { \ - size_t i; \ - for (i = 0; i != pathconf->list.size; ++i) { \ - type *o = pathconf->list.entries[i]; \ - if (o->on_context_dispose != NULL) \ - o->on_context_dispose(o, ctx); \ - } \ - } while (0) - - DOIT(h2o_handler_t, handlers); - DOIT(h2o_filter_t, filters); - DOIT(h2o_logger_t, loggers); - -#undef DOIT -} - -void h2o_context_init(h2o_context_t *ctx, h2o_loop_t *loop, h2o_globalconf_t *config) -{ - size_t i, j; - - assert(config->hosts[0] != NULL); - - memset(ctx, 0, sizeof(*ctx)); - ctx->loop = loop; - ctx->globalconf = config; - h2o_timeout_init(ctx->loop, &ctx->zero_timeout, 0); - h2o_timeout_init(ctx->loop, &ctx->one_sec_timeout, 1000); - h2o_timeout_init(ctx->loop, &ctx->hundred_ms_timeout, 100); - ctx->queue = h2o_multithread_create_queue(loop); - h2o_multithread_register_receiver(ctx->queue, &ctx->receivers.hostinfo_getaddr, h2o_hostinfo_getaddr_receiver); - ctx->filecache = h2o_filecache_create(config->filecache.capacity); - - h2o_timeout_init(ctx->loop, &ctx->handshake_timeout, config->handshake_timeout); - h2o_timeout_init(ctx->loop, &ctx->http1.req_timeout, config->http1.req_timeout); - h2o_linklist_init_anchor(&ctx->http1._conns); - h2o_timeout_init(ctx->loop, &ctx->http2.idle_timeout, config->http2.idle_timeout); - h2o_timeout_init(ctx->loop, &ctx->http2.graceful_shutdown_timeout, config->http2.graceful_shutdown_timeout); - h2o_linklist_init_anchor(&ctx->http2._conns); - ctx->proxy.client_ctx.loop = loop; - h2o_timeout_init(ctx->loop, &ctx->proxy.io_timeout, config->proxy.io_timeout); - ctx->proxy.client_ctx.getaddr_receiver = &ctx->receivers.hostinfo_getaddr; - ctx->proxy.client_ctx.io_timeout = &ctx->proxy.io_timeout; - ctx->proxy.client_ctx.ssl_ctx = config->proxy.ssl_ctx; - - ctx->_module_configs = h2o_mem_alloc(sizeof(*ctx->_module_configs) * config->_num_config_slots); - memset(ctx->_module_configs, 0, sizeof(*ctx->_module_configs) * config->_num_config_slots); - - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&mutex); - for (i = 0; config->hosts[i] != NULL; ++i) { - h2o_hostconf_t *hostconf = config->hosts[i]; - for (j = 0; j != hostconf->paths.size; ++j) { - h2o_pathconf_t *pathconf = hostconf->paths.entries + j; - h2o_context_init_pathconf_context(ctx, pathconf); - } - h2o_context_init_pathconf_context(ctx, &hostconf->fallback_path); - } - pthread_mutex_unlock(&mutex); -} - -void h2o_context_dispose(h2o_context_t *ctx) -{ - h2o_globalconf_t *config = ctx->globalconf; - size_t i, j; - - for (i = 0; config->hosts[i] != NULL; ++i) { - h2o_hostconf_t *hostconf = config->hosts[i]; - for (j = 0; j != hostconf->paths.size; ++j) { - h2o_pathconf_t *pathconf = hostconf->paths.entries + j; - h2o_context_dispose_pathconf_context(ctx, pathconf); - } - h2o_context_dispose_pathconf_context(ctx, &hostconf->fallback_path); - } - free(ctx->_pathconfs_inited.entries); - free(ctx->_module_configs); - h2o_timeout_dispose(ctx->loop, &ctx->zero_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->one_sec_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->hundred_ms_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->handshake_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http1.req_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http2.idle_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http2.graceful_shutdown_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->proxy.io_timeout); - /* what should we do here? assert(!h2o_linklist_is_empty(&ctx->http2._conns); */ - - h2o_filecache_destroy(ctx->filecache); - ctx->filecache = NULL; - - /* clear storage */ - for (i = 0; i != ctx->storage.size; ++i) { - h2o_context_storage_item_t *item = ctx->storage.entries + i; - if (item->dispose != NULL) { - item->dispose(item->data); - } - } - free(ctx->storage.entries); - - /* TODO assert that the all the getaddrinfo threads are idle */ - h2o_multithread_unregister_receiver(ctx->queue, &ctx->receivers.hostinfo_getaddr); - h2o_multithread_destroy_queue(ctx->queue); - - if (ctx->_timestamp_cache.value != NULL) - h2o_mem_release_shared(ctx->_timestamp_cache.value); - -#if H2O_USE_LIBUV - /* make sure the handles released by h2o_timeout_dispose get freed */ - uv_run(ctx->loop, UV_RUN_NOWAIT); -#endif -} - -void h2o_context_request_shutdown(h2o_context_t *ctx) -{ - ctx->shutdown_requested = 1; - if (ctx->globalconf->http1.callbacks.request_shutdown != NULL) - ctx->globalconf->http1.callbacks.request_shutdown(ctx); - if (ctx->globalconf->http2.callbacks.request_shutdown != NULL) - ctx->globalconf->http2.callbacks.request_shutdown(ctx); -} - -void h2o_context_update_timestamp_cache(h2o_context_t *ctx) -{ - time_t prev_sec = ctx->_timestamp_cache.tv_at.tv_sec; - ctx->_timestamp_cache.uv_now_at = h2o_now(ctx->loop); - gettimeofday(&ctx->_timestamp_cache.tv_at, NULL); - if (ctx->_timestamp_cache.tv_at.tv_sec != prev_sec) { - struct tm gmt; - /* update the string cache */ - if (ctx->_timestamp_cache.value != NULL) - h2o_mem_release_shared(ctx->_timestamp_cache.value); - ctx->_timestamp_cache.value = h2o_mem_alloc_shared(NULL, sizeof(h2o_timestamp_string_t), NULL); - gmtime_r(&ctx->_timestamp_cache.tv_at.tv_sec, &gmt); - h2o_time2str_rfc1123(ctx->_timestamp_cache.value->rfc1123, &gmt); - h2o_time2str_log(ctx->_timestamp_cache.value->log, ctx->_timestamp_cache.tv_at.tv_sec); - } -} diff --git a/web/server/h2o/libh2o/lib/core/headers.c b/web/server/h2o/libh2o/lib/core/headers.c deleted file mode 100644 index d31183623..000000000 --- a/web/server/h2o/libh2o/lib/core/headers.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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 -#include -#include "h2o.h" - -static void add_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, h2o_iovec_t *name, const char *orig_name, const char *value, - size_t value_len) -{ - h2o_header_t *slot; - - h2o_vector_reserve(pool, headers, headers->size + 1); - slot = headers->entries + headers->size++; - - slot->name = name; - slot->value.base = (char *)value; - slot->value.len = value_len; - slot->orig_name = orig_name ? h2o_strdup(pool, orig_name, name->len).base : NULL; -} - -ssize_t h2o_find_header(const h2o_headers_t *headers, const h2o_token_t *token, ssize_t cursor) -{ - for (++cursor; cursor < headers->size; ++cursor) { - if (headers->entries[cursor].name == &token->buf) { - return cursor; - } - } - return -1; -} - -ssize_t h2o_find_header_by_str(const h2o_headers_t *headers, const char *name, size_t name_len, ssize_t cursor) -{ - for (++cursor; cursor < headers->size; ++cursor) { - h2o_header_t *t = headers->entries + cursor; - if (h2o_memis(t->name->base, t->name->len, name, name_len)) { - return cursor; - } - } - return -1; -} - -void h2o_add_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *orig_name, - const char *value, size_t value_len) -{ - add_header(pool, headers, (h2o_iovec_t *)&token->buf, orig_name, value, value_len); -} - -void h2o_add_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, - const char *orig_name, const char *value, size_t value_len) -{ - h2o_iovec_t *name_buf; - - if (maybe_token) { - const h2o_token_t *token = h2o_lookup_token(name, name_len); - if (token != NULL) { - add_header(pool, headers, (h2o_iovec_t *)token, orig_name, value, value_len); - return; - } - } - name_buf = h2o_mem_alloc_pool(pool, sizeof(h2o_iovec_t)); - name_buf->base = (char *)name; - name_buf->len = name_len; - add_header(pool, headers, name_buf, orig_name, value, value_len); -} - -void h2o_set_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *value, size_t value_len, - int overwrite_if_exists) -{ - ssize_t cursor = h2o_find_header(headers, token, -1); - if (cursor != -1) { - if (overwrite_if_exists) { - h2o_iovec_t *slot = &headers->entries[cursor].value; - slot->base = (char *)value; - slot->len = value_len; - } - } else { - h2o_add_header(pool, headers, token, NULL, value, value_len); - } -} - -void h2o_set_header_by_str(h2o_mem_pool_t *pool, h2o_headers_t *headers, const char *name, size_t name_len, int maybe_token, - const char *value, size_t value_len, int overwrite_if_exists) -{ - ssize_t cursor; - - if (maybe_token) { - const h2o_token_t *token = h2o_lookup_token(name, name_len); - if (token != NULL) { - h2o_set_header(pool, headers, token, value, value_len, overwrite_if_exists); - return; - } - } - - cursor = h2o_find_header_by_str(headers, name, name_len, -1); - if (cursor != -1) { - if (overwrite_if_exists) { - h2o_iovec_t *slot = &headers->entries[cursor].value; - slot->base = (char *)value; - slot->len = value_len; - } - } else { - h2o_iovec_t *name_buf = h2o_mem_alloc_pool(pool, sizeof(h2o_iovec_t)); - name_buf->base = (char *)name; - name_buf->len = name_len; - add_header(pool, headers, name_buf, NULL, value, value_len); - } -} - -void h2o_set_header_token(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_token_t *token, const char *value, - size_t value_len) -{ - h2o_header_t *dest = NULL; - size_t i; - for (i = 0; i != headers->size; ++i) { - if (headers->entries[i].name == &token->buf) { - if (h2o_contains_token(headers->entries[i].value.base, headers->entries[i].value.len, value, value_len, ',')) - return; - dest = headers->entries + i; - } - } - if (dest != NULL) { - dest->value = h2o_concat(pool, dest->value, h2o_iovec_init(H2O_STRLIT(", ")), h2o_iovec_init(value, value_len)); - } else { - h2o_add_header(pool, headers, token, NULL, value, value_len); - } -} - -ssize_t h2o_delete_header(h2o_headers_t *headers, ssize_t cursor) -{ - assert(cursor != -1); - - --headers->size; - memmove(headers->entries + cursor, headers->entries + cursor + 1, sizeof(h2o_header_t) * (headers->size - cursor)); - - return cursor; -} diff --git a/web/server/h2o/libh2o/lib/core/logconf.c b/web/server/h2o/libh2o/lib/core/logconf.c deleted file mode 100644 index 4d79736cc..000000000 --- a/web/server/h2o/libh2o/lib/core/logconf.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright (c) 2014-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 "h2o.h" - -enum { - ELEMENT_TYPE_EMPTY, /* empty element (with suffix only) */ - ELEMENT_TYPE_LOCAL_ADDR, /* %A */ - ELEMENT_TYPE_BYTES_SENT, /* %b */ - ELEMENT_TYPE_PROTOCOL, /* %H */ - ELEMENT_TYPE_REMOTE_ADDR, /* %h */ - ELEMENT_TYPE_LOGNAME, /* %l */ - ELEMENT_TYPE_METHOD, /* %m */ - ELEMENT_TYPE_LOCAL_PORT, /* %p, %{local}p */ - ELEMENT_TYPE_REMOTE_PORT, /* %{remote}p */ - ELEMENT_TYPE_ENV_VAR, /* %{..}e */ - ELEMENT_TYPE_QUERY, /* %q */ - ELEMENT_TYPE_REQUEST_LINE, /* %r */ - ELEMENT_TYPE_STATUS, /* %s */ - ELEMENT_TYPE_TIMESTAMP, /* %t */ - ELEMENT_TYPE_TIMESTAMP_STRFTIME, /* %{...}t */ - ELEMENT_TYPE_TIMESTAMP_SEC_SINCE_EPOCH, /* %{sec}t */ - ELEMENT_TYPE_TIMESTAMP_MSEC_SINCE_EPOCH, /* %{msec}t */ - ELEMENT_TYPE_TIMESTAMP_USEC_SINCE_EPOCH, /* %{usec}t */ - ELEMENT_TYPE_TIMESTAMP_MSEC_FRAC, /* %{msec_frac}t */ - ELEMENT_TYPE_TIMESTAMP_USEC_FRAC, /* %{usec_frac}t */ - ELEMENT_TYPE_URL_PATH, /* %U */ - ELEMENT_TYPE_REMOTE_USER, /* %u */ - ELEMENT_TYPE_AUTHORITY, /* %V */ - ELEMENT_TYPE_HOSTCONF, /* %v */ - ELEMENT_TYPE_IN_HEADER_TOKEN, /* %{data.header_token}i */ - ELEMENT_TYPE_IN_HEADER_STRING, /* %{data.name}i */ - ELEMENT_TYPE_OUT_HEADER_TOKEN, /* %{data.header_token}o */ - ELEMENT_TYPE_OUT_HEADER_STRING, /* %{data.name}o */ - ELEMENT_TYPE_OUT_HEADER_TOKEN_CONCATENATED, /* %{data.header_token}o */ - ELEMENT_TYPE_EXTENDED_VAR, /* %{data.name}x */ - ELEMENT_TYPE_CONNECTION_ID, /* %{connection-id}x */ - ELEMENT_TYPE_CONNECT_TIME, /* %{connect-time}x */ - ELEMENT_TYPE_REQUEST_HEADER_TIME, /* %{request-header-time}x */ - ELEMENT_TYPE_REQUEST_BODY_TIME, /* %{request-body-time}x */ - ELEMENT_TYPE_REQUEST_TOTAL_TIME, /* %{request-total-time}x */ - ELEMENT_TYPE_PROCESS_TIME, /* %{process-time}x */ - ELEMENT_TYPE_RESPONSE_TIME, /* %{response-total-time}x */ - ELEMENT_TYPE_DURATION, /* %{duration}x */ - ELEMENT_TYPE_ERROR, /* %{error}x */ - ELEMENT_TYPE_PROTOCOL_SPECIFIC, /* %{protocol-specific...}x */ - NUM_ELEMENT_TYPES -}; - -struct log_element_t { - unsigned type; - h2o_iovec_t suffix; - union { - const h2o_token_t *header_token; - h2o_iovec_t name; - size_t protocol_specific_callback_index; - } data; - unsigned magically_quoted_json : 1; /* whether to omit surrounding doublequotes when the output is null */ - unsigned original_response : 1; -}; - -struct st_h2o_logconf_t { - H2O_VECTOR(struct log_element_t) elements; - int escape; -}; - -static h2o_iovec_t strdup_lowercased(const char *s, size_t len) -{ - h2o_iovec_t v = h2o_strdup(NULL, s, len); - h2o_strtolower(v.base, v.len); - return v; -} - -static int determine_magicquote_nodes(h2o_logconf_t *logconf, char *errbuf) -{ - size_t element_index; - int quote_char = '\0'; /* the quote char being used if the state machine is within a string literal */ - int just_in = 0; /* if we just went into the string literal */ - - for (element_index = 0; element_index < logconf->elements.size; ++element_index) { - h2o_iovec_t suffix = logconf->elements.entries[element_index].suffix; - logconf->elements.entries[element_index].magically_quoted_json = just_in && suffix.len != 0 && suffix.base[0] == quote_char; - - just_in = 0; - - size_t i; - for (i = 0; i < suffix.len; ++i) { - just_in = 0; - if (quote_char != '\0') { - if (quote_char == suffix.base[i]) { - /* out of quote? */ - size_t j, num_bs = 0; - for (j = i; j != 0; ++num_bs) - if (suffix.base[--j] != '\\') - break; - if (num_bs % 2 == 0) - quote_char = '\0'; - } - } else { - if (suffix.base[i] == '"' || suffix.base[i] == '\'') { - quote_char = suffix.base[i]; - just_in = 1; - } - } - } - } - - return 1; -} - -h2o_logconf_t *h2o_logconf_compile(const char *fmt, int escape, char *errbuf) -{ - h2o_logconf_t *logconf = h2o_mem_alloc(sizeof(*logconf)); - const char *pt = fmt; - size_t fmt_len = strlen(fmt); - - *logconf = (h2o_logconf_t){{NULL}, escape}; - -#define LAST_ELEMENT() (logconf->elements.entries + logconf->elements.size - 1) -/* suffix buffer is always guaranteed to be larger than the fmt + (sizeof('\n') - 1) (so that they would be no buffer overruns) */ -#define NEW_ELEMENT(ty) \ - do { \ - h2o_vector_reserve(NULL, &logconf->elements, logconf->elements.size + 1); \ - logconf->elements.size++; \ - *LAST_ELEMENT() = (struct log_element_t){0}; \ - LAST_ELEMENT()->type = ty; \ - LAST_ELEMENT()->suffix.base = h2o_mem_alloc(fmt_len + 1); \ - } while (0) - - while (*pt != '\0') { - if (memcmp(pt, "%%", 2) == 0) { - ++pt; /* emit % */ - } else if (*pt == '%') { - ++pt; - /* handle < and > */ - int log_original = 0; - for (;; ++pt) { - if (*pt == '<') { - log_original = 1; - } else if (*pt == '>') { - log_original = 0; - } else { - break; - } - } - /* handle {...}n */ - if (*pt == '{') { - const h2o_token_t *token; - const char *quote_end = strchr(++pt, '}'); - if (quote_end == NULL) { - sprintf(errbuf, "failed to compile log format: unterminated header name starting at: \"%16s\"", pt); - goto Error; - } - const char modifier = quote_end[1]; - switch (modifier) { - case 'i': - case 'o': { - h2o_iovec_t name = strdup_lowercased(pt, quote_end - pt); - token = h2o_lookup_token(name.base, name.len); - if (token != NULL) { - free(name.base); - if (modifier == 'o' && token == H2O_TOKEN_SET_COOKIE) { - NEW_ELEMENT(ELEMENT_TYPE_OUT_HEADER_TOKEN_CONCATENATED); - LAST_ELEMENT()->data.header_token = token; - } else { - NEW_ELEMENT(modifier == 'i' ? ELEMENT_TYPE_IN_HEADER_TOKEN : ELEMENT_TYPE_OUT_HEADER_TOKEN); - LAST_ELEMENT()->data.header_token = token; - } - } else { - NEW_ELEMENT(modifier == 'i' ? ELEMENT_TYPE_IN_HEADER_STRING : ELEMENT_TYPE_OUT_HEADER_STRING); - LAST_ELEMENT()->data.name = name; - } - LAST_ELEMENT()->original_response = log_original; - } break; - case 'p': - if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("local"))) { - NEW_ELEMENT(ELEMENT_TYPE_LOCAL_PORT); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("remote"))) { - NEW_ELEMENT(ELEMENT_TYPE_REMOTE_PORT); - } else { - sprintf(errbuf, "failed to compile log format: unknown specifier for %%{...}p"); - goto Error; - } - break; - case 'e': - { - h2o_iovec_t name = h2o_strdup(NULL, pt, quote_end - pt); - NEW_ELEMENT(ELEMENT_TYPE_ENV_VAR); - LAST_ELEMENT()->data.name = name; - } - break; - case 't': - if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("sec"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_SEC_SINCE_EPOCH); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("msec"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_MSEC_SINCE_EPOCH); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("usec"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_USEC_SINCE_EPOCH); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("msec_frac"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_MSEC_FRAC); - } else if (h2o_memis(pt, quote_end - pt, H2O_STRLIT("usec_frac"))) { - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_USEC_FRAC); - } else { - h2o_iovec_t name = h2o_strdup(NULL, pt, quote_end - pt); - NEW_ELEMENT(ELEMENT_TYPE_TIMESTAMP_STRFTIME); - LAST_ELEMENT()->data.name = name; - } - break; - case 'x': -#define MAP_EXT_TO_TYPE(name, id) \ - if (h2o_lcstris(pt, quote_end - pt, H2O_STRLIT(name))) { \ - NEW_ELEMENT(id); \ - goto MAP_EXT_Found; \ - } -#define MAP_EXT_TO_PROTO(name, cb) \ - if (h2o_lcstris(pt, quote_end - pt, H2O_STRLIT(name))) { \ - h2o_conn_callbacks_t dummy_; \ - NEW_ELEMENT(ELEMENT_TYPE_PROTOCOL_SPECIFIC); \ - LAST_ELEMENT()->data.protocol_specific_callback_index = \ - &dummy_.log_.cb - dummy_.log_.callbacks; \ - goto MAP_EXT_Found; \ - } - MAP_EXT_TO_TYPE("connection-id", ELEMENT_TYPE_CONNECTION_ID); - MAP_EXT_TO_TYPE("connect-time", ELEMENT_TYPE_CONNECT_TIME); - MAP_EXT_TO_TYPE("request-total-time", ELEMENT_TYPE_REQUEST_TOTAL_TIME); - MAP_EXT_TO_TYPE("request-header-time", ELEMENT_TYPE_REQUEST_HEADER_TIME); - MAP_EXT_TO_TYPE("request-body-time", ELEMENT_TYPE_REQUEST_BODY_TIME); - MAP_EXT_TO_TYPE("process-time", ELEMENT_TYPE_PROCESS_TIME); - MAP_EXT_TO_TYPE("response-time", ELEMENT_TYPE_RESPONSE_TIME); - MAP_EXT_TO_TYPE("duration", ELEMENT_TYPE_DURATION); - MAP_EXT_TO_TYPE("error", ELEMENT_TYPE_ERROR); - MAP_EXT_TO_PROTO("http1.request-index", http1.request_index); - MAP_EXT_TO_PROTO("http2.stream-id", http2.stream_id); - MAP_EXT_TO_PROTO("http2.priority.received", http2.priority_received); - MAP_EXT_TO_PROTO("http2.priority.received.exclusive", http2.priority_received_exclusive); - MAP_EXT_TO_PROTO("http2.priority.received.parent", http2.priority_received_parent); - MAP_EXT_TO_PROTO("http2.priority.received.weight", http2.priority_received_weight); - MAP_EXT_TO_PROTO("http2.priority.actual", http2.priority_actual); - MAP_EXT_TO_PROTO("http2.priority.actual.parent", http2.priority_actual_parent); - MAP_EXT_TO_PROTO("http2.priority.actual.weight", http2.priority_actual_weight); - MAP_EXT_TO_PROTO("ssl.protocol-version", ssl.protocol_version); - MAP_EXT_TO_PROTO("ssl.session-reused", ssl.session_reused); - MAP_EXT_TO_PROTO("ssl.cipher", ssl.cipher); - MAP_EXT_TO_PROTO("ssl.cipher-bits", ssl.cipher_bits); - MAP_EXT_TO_PROTO("ssl.session-id", ssl.session_id); - { /* not found */ - h2o_iovec_t name = strdup_lowercased(pt, quote_end - pt); - NEW_ELEMENT(ELEMENT_TYPE_EXTENDED_VAR); - LAST_ELEMENT()->data.name = name; - } - MAP_EXT_Found: -#undef MAP_EXT_TO_TYPE -#undef MAP_EXT_TO_PROTO - break; - default: - sprintf(errbuf, "failed to compile log format: header name is not followed by either `i`, `o`, `x`, `e`"); - goto Error; - } - pt = quote_end + 2; - continue; - } else { - unsigned type = NUM_ELEMENT_TYPES; - switch (*pt++) { -#define TYPE_MAP(ch, ty) \ - case ch: \ - type = ty; \ - break - TYPE_MAP('A', ELEMENT_TYPE_LOCAL_ADDR); - TYPE_MAP('b', ELEMENT_TYPE_BYTES_SENT); - TYPE_MAP('H', ELEMENT_TYPE_PROTOCOL); - TYPE_MAP('h', ELEMENT_TYPE_REMOTE_ADDR); - TYPE_MAP('l', ELEMENT_TYPE_LOGNAME); - TYPE_MAP('m', ELEMENT_TYPE_METHOD); - TYPE_MAP('p', ELEMENT_TYPE_LOCAL_PORT); - TYPE_MAP('e', ELEMENT_TYPE_ENV_VAR); - TYPE_MAP('q', ELEMENT_TYPE_QUERY); - TYPE_MAP('r', ELEMENT_TYPE_REQUEST_LINE); - TYPE_MAP('s', ELEMENT_TYPE_STATUS); - TYPE_MAP('t', ELEMENT_TYPE_TIMESTAMP); - TYPE_MAP('U', ELEMENT_TYPE_URL_PATH); - TYPE_MAP('u', ELEMENT_TYPE_REMOTE_USER); - TYPE_MAP('V', ELEMENT_TYPE_AUTHORITY); - TYPE_MAP('v', ELEMENT_TYPE_HOSTCONF); -#undef TYPE_MAP - default: - sprintf(errbuf, "failed to compile log format: unknown escape sequence: %%%c", pt[-1]); - goto Error; - } - NEW_ELEMENT(type); - LAST_ELEMENT()->original_response = log_original; - continue; - } - } - /* emit current char */ - if (logconf->elements.size == 0) - NEW_ELEMENT(ELEMENT_TYPE_EMPTY); - LAST_ELEMENT()->suffix.base[LAST_ELEMENT()->suffix.len++] = *pt++; - } - - /* emit end-of-line */ - if (logconf->elements.size == 0) - NEW_ELEMENT(ELEMENT_TYPE_EMPTY); - LAST_ELEMENT()->suffix.base[LAST_ELEMENT()->suffix.len++] = '\n'; - -#undef NEW_ELEMENT -#undef LAST_ELEMENT - - if (escape == H2O_LOGCONF_ESCAPE_JSON) { - if (!determine_magicquote_nodes(logconf, errbuf)) - goto Error; - } - - return logconf; - -Error: - h2o_logconf_dispose(logconf); - return NULL; -} - -void h2o_logconf_dispose(h2o_logconf_t *logconf) -{ - size_t i; - - for (i = 0; i != logconf->elements.size; ++i) { - free(logconf->elements.entries[i].suffix.base); - switch (logconf->elements.entries[i].type) { - case ELEMENT_TYPE_EXTENDED_VAR: - case ELEMENT_TYPE_IN_HEADER_STRING: - case ELEMENT_TYPE_OUT_HEADER_STRING: - case ELEMENT_TYPE_TIMESTAMP_STRFTIME: - free(logconf->elements.entries[i].data.name.base); - break; - default: - break; - } - } - free(logconf->elements.entries); - free(logconf); -} - -static inline char *append_safe_string(char *pos, const char *src, size_t len) -{ - memcpy(pos, src, len); - return pos + len; -} - -static char *append_unsafe_string_apache(char *pos, const char *src, size_t len) -{ - const char *src_end = src + len; - - for (; src != src_end; ++src) { - if (' ' <= *src && *src < 0x7d && *src != '"') { - *pos++ = *src; - } else { - *pos++ = '\\'; - *pos++ = 'x'; - *pos++ = ("0123456789abcdef")[(*src >> 4) & 0xf]; - *pos++ = ("0123456789abcdef")[*src & 0xf]; - } - } - - return pos; -} - -static char *append_unsafe_string_json(char *pos, const char *src, size_t len) -{ - const char *src_end = src + len; - - for (; src != src_end; ++src) { - if (' ' <= *src && *src < 0x7e) { - if (*src == '"' || *src == '\\') - *pos++ = '\\'; - *pos++ = *src; - } else { - *pos++ = '\\'; - *pos++ = 'u'; - *pos++ = '0'; - *pos++ = '0'; - *pos++ = ("0123456789abcdef")[(*src >> 4) & 0xf]; - *pos++ = ("0123456789abcdef")[*src & 0xf]; - } - } - - return pos; -} - -static char *append_addr(char *pos, socklen_t (*cb)(h2o_conn_t *conn, struct sockaddr *sa), h2o_conn_t *conn, h2o_iovec_t nullexpr) -{ - struct sockaddr_storage ss; - socklen_t sslen; - - if ((sslen = cb(conn, (void *)&ss)) == 0) - goto Fail; - size_t l = h2o_socket_getnumerichost((void *)&ss, sslen, pos); - if (l == SIZE_MAX) - goto Fail; - pos += l; - return pos; - -Fail: - memcpy(pos, nullexpr.base, nullexpr.len); - pos += nullexpr.len; - return pos; -} - -static char *append_port(char *pos, socklen_t (*cb)(h2o_conn_t *conn, struct sockaddr *sa), h2o_conn_t *conn, h2o_iovec_t nullexpr) -{ - struct sockaddr_storage ss; - socklen_t sslen; - - if ((sslen = cb(conn, (void *)&ss)) == 0) - goto Fail; - int32_t port = h2o_socket_getport((void *)&ss); - if (port == -1) - goto Fail; - pos += sprintf(pos, "%" PRIu16, (uint16_t)port); - return pos; - -Fail: - memcpy(pos, nullexpr.base, nullexpr.len); - pos += nullexpr.len; - return pos; -} - -#define APPEND_DURATION(pos, name) \ - do { \ - int64_t delta_usec; \ - if (!h2o_time_compute_##name(req, &delta_usec)) \ - goto EmitNull; \ - int32_t delta_sec = (int32_t)(delta_usec / (1000 * 1000)); \ - delta_usec -= ((int64_t)delta_sec * (1000 * 1000)); \ - RESERVE(sizeof(H2O_INT32_LONGEST_STR ".999999") - 1); \ - pos += sprintf(pos, "%" PRId32, delta_sec); \ - if (delta_usec != 0) { \ - int i; \ - *pos++ = '.'; \ - for (i = 5; i >= 0; --i) { \ - pos[i] = '0' + delta_usec % 10; \ - delta_usec /= 10; \ - } \ - pos += 6; \ - } \ - } while (0); - -static char *expand_line_buf(char *line, size_t *cur_size, size_t required, int should_realloc) -{ - size_t new_size = *cur_size; - - /* determine the new size */ - do { - new_size *= 2; - } while (new_size < required); - - /* reallocate */ - if (!should_realloc) { - char *newpt = h2o_mem_alloc(new_size); - memcpy(newpt, line, *cur_size); - line = newpt; - } else { - line = h2o_mem_realloc(line, new_size); - } - *cur_size = new_size; - - return line; -} - -char *h2o_log_request(h2o_logconf_t *logconf, h2o_req_t *req, size_t *len, char *buf) -{ - char *line = buf, *pos = line, *line_end = line + *len; - h2o_iovec_t nullexpr; - char *(*append_unsafe_string)(char *pos, const char *src, size_t len); - size_t element_index, unsafe_factor; - struct tm localt = {0}; - int should_realloc_on_expand = 0; - - switch (logconf->escape) { - case H2O_LOGCONF_ESCAPE_APACHE: - nullexpr = h2o_iovec_init(H2O_STRLIT("-")); - append_unsafe_string = append_unsafe_string_apache; - unsafe_factor = 4; - break; - case H2O_LOGCONF_ESCAPE_JSON: - nullexpr = h2o_iovec_init(H2O_STRLIT("null")); - append_unsafe_string = append_unsafe_string_json; - unsafe_factor = 6; - break; - default: - h2o_fatal("unexpected escape mode"); - break; - } - - for (element_index = 0; element_index != logconf->elements.size; ++element_index) { - struct log_element_t *element = logconf->elements.entries + element_index; - -/* reserve capacity + suffix.len */ -#define RESERVE(capacity) \ - do { \ - if ((capacity) + element->suffix.len > line_end - pos) { \ - size_t off = pos - line; \ - size_t size = line_end - line; \ - line = expand_line_buf(line, &size, off + (capacity) + element->suffix.len, should_realloc_on_expand); \ - pos = line + off; \ - line_end = line + size; \ - should_realloc_on_expand = 1; \ - } \ - } while (0) - - switch (element->type) { - case ELEMENT_TYPE_EMPTY: - RESERVE(0); - break; - case ELEMENT_TYPE_LOCAL_ADDR: /* %A */ - RESERVE(NI_MAXHOST); - pos = append_addr(pos, req->conn->callbacks->get_sockname, req->conn, nullexpr); - break; - case ELEMENT_TYPE_BYTES_SENT: /* %b */ - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu64, (uint64_t)req->bytes_sent); - break; - case ELEMENT_TYPE_PROTOCOL: /* %H */ - RESERVE(sizeof("HTTP/1.1")); - pos += h2o_stringify_protocol_version(pos, req->version); - break; - case ELEMENT_TYPE_REMOTE_ADDR: /* %h */ - RESERVE(NI_MAXHOST); - pos = append_addr(pos, req->conn->callbacks->get_peername, req->conn, nullexpr); - break; - case ELEMENT_TYPE_METHOD: /* %m */ - RESERVE(req->input.method.len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.method.base, req->input.method.len); - break; - case ELEMENT_TYPE_LOCAL_PORT: /* %p */ - RESERVE(sizeof(H2O_UINT16_LONGEST_STR) - 1); - pos = append_port(pos, req->conn->callbacks->get_sockname, req->conn, nullexpr); - break; - case ELEMENT_TYPE_REMOTE_PORT: /* %{remote}p */ - RESERVE(sizeof(H2O_UINT16_LONGEST_STR) - 1); - pos = append_port(pos, req->conn->callbacks->get_peername, req->conn, nullexpr); - break; - case ELEMENT_TYPE_ENV_VAR: /* %{..}e */ { - h2o_iovec_t *env_var = h2o_req_getenv(req, element->data.name.base, element->data.name.len, 0); - if (env_var == NULL) - goto EmitNull; - RESERVE(env_var->len * unsafe_factor); - pos = append_safe_string(pos, env_var->base, env_var->len); - } break; - case ELEMENT_TYPE_QUERY: /* %q */ - if (req->input.query_at != SIZE_MAX) { - size_t len = req->input.path.len - req->input.query_at; - RESERVE(len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.path.base + req->input.query_at, len); - } - break; - case ELEMENT_TYPE_REQUEST_LINE: /* %r */ - RESERVE((req->input.method.len + req->input.path.len) * unsafe_factor + sizeof(" HTTP/1.1")); - pos = append_unsafe_string(pos, req->input.method.base, req->input.method.len); - *pos++ = ' '; - pos = append_unsafe_string(pos, req->input.path.base, req->input.path.len); - *pos++ = ' '; - pos += h2o_stringify_protocol_version(pos, req->version); - break; - case ELEMENT_TYPE_STATUS: /* %s */ - RESERVE(sizeof(H2O_INT32_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRId32, (int32_t)(element->original_response ? req->res.original.status : req->res.status)); - break; - case ELEMENT_TYPE_TIMESTAMP: /* %t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(H2O_TIMESTR_LOG_LEN + 2); - *pos++ = '['; - pos = append_safe_string(pos, req->processed_at.str->log, H2O_TIMESTR_LOG_LEN); - *pos++ = ']'; - break; - case ELEMENT_TYPE_TIMESTAMP_STRFTIME: /* %{...}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - { - size_t bufsz, len; - if (localt.tm_year == 0) - localtime_r(&req->processed_at.at.tv_sec, &localt); - for (bufsz = 128;; bufsz *= 2) { - RESERVE(bufsz); - if ((len = strftime(pos, bufsz, element->data.name.base, &localt)) != 0) - break; - } - pos += len; - } - break; - case ELEMENT_TYPE_TIMESTAMP_SEC_SINCE_EPOCH: /* %{sec}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(sizeof(H2O_UINT32_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu32, (uint32_t)req->processed_at.at.tv_sec); - break; - case ELEMENT_TYPE_TIMESTAMP_MSEC_SINCE_EPOCH: /* %{msec}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu64, - (uint64_t)req->processed_at.at.tv_sec * 1000 + (uint64_t)req->processed_at.at.tv_usec / 1000); - break; - case ELEMENT_TYPE_TIMESTAMP_USEC_SINCE_EPOCH: /* %{usec}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += - sprintf(pos, "%" PRIu64, (uint64_t)req->processed_at.at.tv_sec * 1000000 + (uint64_t)req->processed_at.at.tv_usec); - break; - case ELEMENT_TYPE_TIMESTAMP_MSEC_FRAC: /* %{msec_frac}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(3); - pos += sprintf(pos, "%03u", (unsigned)(req->processed_at.at.tv_usec / 1000)); - break; - case ELEMENT_TYPE_TIMESTAMP_USEC_FRAC: /* %{usec_frac}t */ - if (h2o_timeval_is_null(&req->processed_at.at)) - goto EmitNull; - RESERVE(6); - pos += sprintf(pos, "%06u", (unsigned)req->processed_at.at.tv_usec); - break; - case ELEMENT_TYPE_URL_PATH: /* %U */ { - size_t path_len = req->input.query_at == SIZE_MAX ? req->input.path.len : req->input.query_at; - RESERVE(path_len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.path.base, path_len); - } break; - case ELEMENT_TYPE_REMOTE_USER: /* %u */ { - h2o_iovec_t *remote_user = h2o_req_getenv(req, H2O_STRLIT("REMOTE_USER"), 0); - if (remote_user == NULL) - goto EmitNull; - RESERVE(remote_user->len * unsafe_factor); - pos = append_unsafe_string(pos, remote_user->base, remote_user->len); - } break; - case ELEMENT_TYPE_AUTHORITY: /* %V */ - RESERVE(req->input.authority.len * unsafe_factor); - pos = append_unsafe_string(pos, req->input.authority.base, req->input.authority.len); - break; - case ELEMENT_TYPE_HOSTCONF: /* %v */ - RESERVE(req->hostconf->authority.hostport.len * unsafe_factor); - pos = append_unsafe_string(pos, req->hostconf->authority.hostport.base, req->hostconf->authority.hostport.len); - break; - -#define EMIT_HEADER(__headers, concat, findfunc, ...) \ - do { \ - h2o_headers_t *headers = (__headers); \ - ssize_t index = -1; \ - int found = 0; \ - while ((index = (findfunc)(headers, __VA_ARGS__, index)) != -1) { \ - if (found) { \ - RESERVE(2); \ - *pos++ = ','; \ - *pos++ = ' '; \ - } else { \ - found = 1; \ - } \ - const h2o_header_t *header = headers->entries + index; \ - RESERVE(header->value.len *unsafe_factor); \ - pos = append_unsafe_string(pos, header->value.base, header->value.len); \ - if (!concat) \ - break; \ - } \ - if (!found) \ - goto EmitNull; \ - } while (0) - - case ELEMENT_TYPE_IN_HEADER_TOKEN: - EMIT_HEADER(&req->headers, 0, h2o_find_header, element->data.header_token); - break; - case ELEMENT_TYPE_IN_HEADER_STRING: - EMIT_HEADER(&req->headers, 0, h2o_find_header_by_str, element->data.name.base, element->data.name.len); - break; - case ELEMENT_TYPE_OUT_HEADER_TOKEN: - EMIT_HEADER(element->original_response ? &req->res.original.headers : &req->res.headers, 0, h2o_find_header, - element->data.header_token); - break; - case ELEMENT_TYPE_OUT_HEADER_STRING: - EMIT_HEADER(element->original_response ? &req->res.original.headers : &req->res.headers, 0, h2o_find_header_by_str, - element->data.name.base, element->data.name.len); - break; - case ELEMENT_TYPE_OUT_HEADER_TOKEN_CONCATENATED: - EMIT_HEADER(element->original_response ? &req->res.original.headers : &req->res.headers, 1, h2o_find_header, - element->data.header_token); - break; - -#undef EMIT_HEADER - - case ELEMENT_TYPE_CONNECTION_ID: - RESERVE(sizeof(H2O_UINT64_LONGEST_STR) - 1); - pos += sprintf(pos, "%" PRIu64, req->conn->id); - break; - - case ELEMENT_TYPE_CONNECT_TIME: - APPEND_DURATION(pos, connect_time); - break; - - case ELEMENT_TYPE_REQUEST_HEADER_TIME: - APPEND_DURATION(pos, header_time); - break; - - case ELEMENT_TYPE_REQUEST_BODY_TIME: - APPEND_DURATION(pos, body_time); - break; - - case ELEMENT_TYPE_REQUEST_TOTAL_TIME: - APPEND_DURATION(pos, request_total_time); - break; - - case ELEMENT_TYPE_PROCESS_TIME: - APPEND_DURATION(pos, process_time); - break; - - case ELEMENT_TYPE_RESPONSE_TIME: - APPEND_DURATION(pos, response_time); - break; - - case ELEMENT_TYPE_DURATION: - APPEND_DURATION(pos, duration); - break; - - case ELEMENT_TYPE_ERROR: { - size_t i; - for (i = 0; i != req->error_logs.size; ++i) { - h2o_req_error_log_t *log = req->error_logs.entries + i; - size_t module_len = strlen(log->module); - RESERVE(sizeof("[] ") - 1 + module_len + log->msg.len * unsafe_factor); - *pos++ = '['; - pos = append_safe_string(pos, log->module, module_len); - *pos++ = ']'; - *pos++ = ' '; - pos = append_unsafe_string(pos, log->msg.base, log->msg.len); - } - } break; - - case ELEMENT_TYPE_PROTOCOL_SPECIFIC: { - h2o_iovec_t (*cb)(h2o_req_t *) = req->conn->callbacks->log_.callbacks[element->data.protocol_specific_callback_index]; - if (cb != NULL) { - h2o_iovec_t s = cb(req); - if (s.base == NULL) - goto EmitNull; - RESERVE(s.len); - pos = append_safe_string(pos, s.base, s.len); - } else { - goto EmitNull; - } - } break; - - case ELEMENT_TYPE_LOGNAME: /* %l */ - case ELEMENT_TYPE_EXTENDED_VAR: /* %{...}x */ - EmitNull: - RESERVE(nullexpr.len); - /* special case that trims surrounding quotes */ - if (element->magically_quoted_json) { - --pos; - pos = append_safe_string(pos, nullexpr.base, nullexpr.len); - pos = append_safe_string(pos, element->suffix.base + 1, element->suffix.len - 1); - continue; - } - pos = append_safe_string(pos, nullexpr.base, nullexpr.len); - break; - - default: - assert(!"unknown type"); - break; - } - -#undef RESERVE - - pos = append_safe_string(pos, element->suffix.base, element->suffix.len); - } - - *len = pos - line; - return line; -} diff --git a/web/server/h2o/libh2o/lib/core/proxy.c b/web/server/h2o/libh2o/lib/core/proxy.c deleted file mode 100644 index edb4baf9d..000000000 --- a/web/server/h2o/libh2o/lib/core/proxy.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Masahiro Nagano - * - * 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 "picohttpparser.h" -#include "h2o.h" -#include "h2o/http1.h" -#include "h2o/http1client.h" -#include "h2o/tunnel.h" - -struct rp_generator_t { - h2o_generator_t super; - h2o_req_t *src_req; - h2o_http1client_t *client; - struct { - h2o_iovec_t bufs[2]; /* first buf is the request line and headers, the second is the POST content */ - int is_head; - } up_req; - h2o_buffer_t *last_content_before_send; - h2o_doublebuffer_t sending; - int is_websocket_handshake; - int had_body_error; /* set if an error happened while fetching the body so that we can propagate the error */ -}; - -struct rp_ws_upgrade_info_t { - h2o_context_t *ctx; - h2o_timeout_t *timeout; - h2o_socket_t *upstream_sock; -}; - -static h2o_http1client_ctx_t *get_client_ctx(h2o_req_t *req) -{ - h2o_req_overrides_t *overrides = req->overrides; - if (overrides != NULL && overrides->client_ctx != NULL) - return overrides->client_ctx; - return &req->conn->ctx->proxy.client_ctx; -} - -static h2o_iovec_t rewrite_location(h2o_mem_pool_t *pool, const char *location, size_t location_len, h2o_url_t *match, - const h2o_url_scheme_t *req_scheme, h2o_iovec_t req_authority, h2o_iovec_t req_basepath) -{ - h2o_url_t loc_parsed; - - if (h2o_url_parse(location, location_len, &loc_parsed) != 0) - goto NoRewrite; - if (loc_parsed.scheme != &H2O_URL_SCHEME_HTTP) - goto NoRewrite; - if (!h2o_url_hosts_are_equal(&loc_parsed, match)) - goto NoRewrite; - if (h2o_url_get_port(&loc_parsed) != h2o_url_get_port(match)) - goto NoRewrite; - if (loc_parsed.path.len < match->path.len) - goto NoRewrite; - if (memcmp(loc_parsed.path.base, match->path.base, match->path.len) != 0) - goto NoRewrite; - - return h2o_concat(pool, req_scheme->name, h2o_iovec_init(H2O_STRLIT("://")), req_authority, req_basepath, - h2o_iovec_init(loc_parsed.path.base + match->path.len, loc_parsed.path.len - match->path.len)); - -NoRewrite: - return (h2o_iovec_t){NULL}; -} - -static h2o_iovec_t build_request_merge_headers(h2o_mem_pool_t *pool, h2o_iovec_t merged, h2o_iovec_t added, int seperator) -{ - if (added.len == 0) - return merged; - if (merged.len == 0) - return added; - - size_t newlen = merged.len + 2 + added.len; - char *buf = h2o_mem_alloc_pool(pool, newlen); - memcpy(buf, merged.base, merged.len); - buf[merged.len] = seperator; - buf[merged.len + 1] = ' '; - memcpy(buf + merged.len + 2, added.base, added.len); - merged.base = buf; - merged.len = newlen; - return merged; -} - -/* - * A request without neither Content-Length or Transfer-Encoding header implies a zero-length request body (see 6th rule of RFC 7230 - * 3.3.3). - * OTOH, section 3.3.3 states: - * - * A user agent SHOULD send a Content-Length in a request message when - * no Transfer-Encoding is sent and the request method defines a meaning - * for an enclosed payload body. For example, a Content-Length header - * field is normally sent in a POST request even when the value is 0 - * (indicating an empty payload body). A user agent SHOULD NOT send a - * Content-Length header field when the request message does not contain - * a payload body and the method semantics do not anticipate such a - * body. - * - * PUT and POST define a meaning for the payload body, let's emit a - * Content-Length header if it doesn't exist already, since the server - * might send a '411 Length Required' response. - * - * see also: ML thread starting at https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0580.html - */ -static int req_requires_content_length(h2o_req_t *req) -{ - int is_put_or_post = - (req->method.len >= 1 && req->method.base[0] == 'P' && (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST")) || - h2o_memis(req->method.base, req->method.len, H2O_STRLIT("PUT")))); - - return is_put_or_post && h2o_find_header(&req->res.headers, H2O_TOKEN_TRANSFER_ENCODING, -1) == -1; -} - -static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket_handshake, int use_proxy_protocol) -{ - h2o_iovec_t buf; - size_t offset = 0, remote_addr_len = SIZE_MAX; - char remote_addr[NI_MAXHOST]; - struct sockaddr_storage ss; - socklen_t sslen; - h2o_iovec_t cookie_buf = {NULL}, xff_buf = {NULL}, via_buf = {NULL}; - int preserve_x_forwarded_proto = req->conn->ctx->globalconf->proxy.preserve_x_forwarded_proto; - int emit_x_forwarded_headers = req->conn->ctx->globalconf->proxy.emit_x_forwarded_headers; - int emit_via_header = req->conn->ctx->globalconf->proxy.emit_via_header; - - /* for x-f-f */ - if ((sslen = req->conn->callbacks->get_peername(req->conn, (void *)&ss)) != 0) - remote_addr_len = h2o_socket_getnumerichost((void *)&ss, sslen, remote_addr); - - /* build response */ - buf.len = req->method.len + req->path.len + req->authority.len + 512; - if (use_proxy_protocol) - buf.len += H2O_PROXY_HEADER_MAX_LENGTH; - buf.base = h2o_mem_alloc_pool(&req->pool, buf.len); - -#define RESERVE(sz) \ - do { \ - size_t required = offset + sz + 4 /* for "\r\n\r\n" */; \ - if (required > buf.len) { \ - do { \ - buf.len *= 2; \ - } while (required > buf.len); \ - char *newp = h2o_mem_alloc_pool(&req->pool, buf.len); \ - memcpy(newp, buf.base, offset); \ - buf.base = newp; \ - } \ - } while (0) -#define APPEND(s, l) \ - do { \ - memcpy(buf.base + offset, (s), (l)); \ - offset += (l); \ - } while (0) -#define APPEND_STRLIT(lit) APPEND((lit), sizeof(lit) - 1) -#define FLATTEN_PREFIXED_VALUE(prefix, value, add_size) \ - do { \ - RESERVE(sizeof(prefix) - 1 + value.len + 2 + add_size); \ - APPEND_STRLIT(prefix); \ - if (value.len != 0) { \ - APPEND(value.base, value.len); \ - if (add_size != 0) { \ - buf.base[offset++] = ','; \ - buf.base[offset++] = ' '; \ - } \ - } \ - } while (0) - - if (use_proxy_protocol) - offset += h2o_stringify_proxy_header(req->conn, buf.base + offset); - - APPEND(req->method.base, req->method.len); - buf.base[offset++] = ' '; - APPEND(req->path.base, req->path.len); - APPEND_STRLIT(" HTTP/1.1\r\nconnection: "); - if (is_websocket_handshake) { - APPEND_STRLIT("upgrade\r\nupgrade: websocket\r\nhost: "); - } else if (keepalive) { - APPEND_STRLIT("keep-alive\r\nhost: "); - } else { - APPEND_STRLIT("close\r\nhost: "); - } - APPEND(req->authority.base, req->authority.len); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - assert(offset <= buf.len); - if (req->entity.base != NULL || req_requires_content_length(req)) { - RESERVE(sizeof("content-length: " H2O_UINT64_LONGEST_STR) - 1); - offset += sprintf(buf.base + offset, "content-length: %zu\r\n", req->entity.len); - } - - /* rewrite headers if necessary */ - h2o_headers_t req_headers = req->headers; - if (req->overrides != NULL && req->overrides->headers_cmds != NULL) { - req_headers.entries = NULL; - req_headers.size = 0; - req_headers.capacity = 0; - h2o_headers_command_t *cmd; - h2o_vector_reserve(&req->pool, &req_headers, req->headers.capacity); - memcpy(req_headers.entries, req->headers.entries, sizeof(req->headers.entries[0]) * req->headers.size); - req_headers.size = req->headers.size; - for (cmd = req->overrides->headers_cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd) - h2o_rewrite_headers(&req->pool, &req_headers, cmd); - } - - { - const h2o_header_t *h, *h_end; - for (h = req_headers.entries, h_end = h + req_headers.size; h != h_end; ++h) { - if (h2o_iovec_is_token(h->name)) { - const h2o_token_t *token = (void *)h->name; - if (token->proxy_should_drop_for_req) { - continue; - } else if (token == H2O_TOKEN_COOKIE) { - /* merge the cookie headers; see HTTP/2 8.1.2.5 and HTTP/1 (RFC6265 5.4) */ - /* FIXME current algorithm is O(n^2) against the number of cookie headers */ - cookie_buf = build_request_merge_headers(&req->pool, cookie_buf, h->value, ';'); - continue; - } else if (token == H2O_TOKEN_VIA) { - if (!emit_via_header) { - goto AddHeader; - } - via_buf = build_request_merge_headers(&req->pool, via_buf, h->value, ','); - continue; - } else if (token == H2O_TOKEN_X_FORWARDED_FOR) { - if (!emit_x_forwarded_headers) { - goto AddHeader; - } - xff_buf = build_request_merge_headers(&req->pool, xff_buf, h->value, ','); - continue; - } - } - if (!preserve_x_forwarded_proto && h2o_lcstris(h->name->base, h->name->len, H2O_STRLIT("x-forwarded-proto"))) - continue; - AddHeader: - RESERVE(h->name->len + h->value.len + 2); - APPEND(h->orig_name ? h->orig_name : h->name->base, h->name->len); - buf.base[offset++] = ':'; - buf.base[offset++] = ' '; - APPEND(h->value.base, h->value.len); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - } - if (cookie_buf.len != 0) { - FLATTEN_PREFIXED_VALUE("cookie: ", cookie_buf, 0); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - if (emit_x_forwarded_headers) { - if (!preserve_x_forwarded_proto) { - FLATTEN_PREFIXED_VALUE("x-forwarded-proto: ", req->input.scheme->name, 0); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - if (remote_addr_len != SIZE_MAX) { - FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, remote_addr_len); - APPEND(remote_addr, remote_addr_len); - } else { - FLATTEN_PREFIXED_VALUE("x-forwarded-for: ", xff_buf, 0); - } - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - if (emit_via_header) { - FLATTEN_PREFIXED_VALUE("via: ", via_buf, sizeof("1.1 ") - 1 + req->input.authority.len); - if (req->version < 0x200) { - buf.base[offset++] = '1'; - buf.base[offset++] = '.'; - buf.base[offset++] = '0' + (0x100 <= req->version && req->version <= 0x109 ? req->version - 0x100 : 0); - } else { - buf.base[offset++] = '2'; - } - buf.base[offset++] = ' '; - APPEND(req->input.authority.base, req->input.authority.len); - buf.base[offset++] = '\r'; - buf.base[offset++] = '\n'; - } - APPEND_STRLIT("\r\n"); - -#undef RESERVE -#undef APPEND -#undef APPEND_STRLIT -#undef FLATTEN_PREFIXED_VALUE - - /* set the length */ - assert(offset <= buf.len); - buf.len = offset; - - return buf; -} - -static void do_close(h2o_generator_t *generator, h2o_req_t *req) -{ - struct rp_generator_t *self = (void *)generator; - - if (self->client != NULL) { - h2o_http1client_cancel(self->client); - self->client = NULL; - } -} - -static void do_send(struct rp_generator_t *self) -{ - h2o_iovec_t vecs[1]; - size_t veccnt; - h2o_send_state_t ststate; - - assert(self->sending.bytes_inflight == 0); - - vecs[0] = h2o_doublebuffer_prepare(&self->sending, - self->client != NULL ? &self->client->sock->input : &self->last_content_before_send, - self->src_req->preferred_chunk_size); - - if (self->client == NULL && vecs[0].len == self->sending.buf->size && self->last_content_before_send->size == 0) { - veccnt = vecs[0].len != 0 ? 1 : 0; - ststate = H2O_SEND_STATE_FINAL; - } else { - if (vecs[0].len == 0) - return; - veccnt = 1; - ststate = H2O_SEND_STATE_IN_PROGRESS; - } - - if (self->had_body_error) - ststate = H2O_SEND_STATE_ERROR; - - h2o_send(self->src_req, vecs, veccnt, ststate); -} - -static void do_proceed(h2o_generator_t *generator, h2o_req_t *req) -{ - struct rp_generator_t *self = (void *)generator; - - h2o_doublebuffer_consume(&self->sending); - do_send(self); -} - -static void on_websocket_upgrade_complete(void *_info, h2o_socket_t *sock, size_t reqsize) -{ - struct rp_ws_upgrade_info_t *info = _info; - - if (sock != NULL) { - h2o_buffer_consume(&sock->input, reqsize);//It is detached from conn. Let's trash unused data. - h2o_tunnel_establish(info->ctx, sock, info->upstream_sock, info->timeout); - } else { - h2o_socket_close(info->upstream_sock); - } - free(info); -} - -static inline void on_websocket_upgrade(struct rp_generator_t *self, h2o_timeout_t *timeout, int rlen) -{ - h2o_req_t *req = self->src_req; - h2o_socket_t *sock = h2o_http1client_steal_socket(self->client); - h2o_buffer_consume(&sock->input, rlen);//trash data after stealing sock. - struct rp_ws_upgrade_info_t *info = h2o_mem_alloc(sizeof(*info)); - info->upstream_sock = sock; - info->timeout = timeout; - info->ctx = req->conn->ctx; - h2o_http1_upgrade(req, NULL, 0, on_websocket_upgrade_complete, info); -} - -static int on_body(h2o_http1client_t *client, const char *errstr) -{ - struct rp_generator_t *self = client->data; - - if (errstr != NULL) { - /* detach the content */ - self->last_content_before_send = self->client->sock->input; - h2o_buffer_init(&self->client->sock->input, &h2o_socket_buffer_prototype); - self->client = NULL; - if (errstr != h2o_http1client_error_is_eos) { - h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr); - self->had_body_error = 1; - } - } - if (self->sending.bytes_inflight == 0) - do_send(self); - - return 0; -} - -static char compress_hint_to_enum(const char *val, size_t len) -{ - if (h2o_lcstris(val, len, H2O_STRLIT("on"))) { - return H2O_COMPRESS_HINT_ENABLE; - } - if (h2o_lcstris(val, len, H2O_STRLIT("off"))) { - return H2O_COMPRESS_HINT_DISABLE; - } - return H2O_COMPRESS_HINT_AUTO; -} - -static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, - h2o_iovec_t msg, h2o_header_t *headers, size_t num_headers, int rlen) -{ - struct rp_generator_t *self = client->data; - h2o_req_t *req = self->src_req; - size_t i; - - if (errstr != NULL && errstr != h2o_http1client_error_is_eos) { - self->client = NULL; - h2o_req_log_error(req, "lib/core/proxy.c", "%s", errstr); - h2o_send_error_502(req, "Gateway Error", errstr, 0); - return NULL; - } - - /* copy the response (note: all the headers must be copied; http1client discards the input once we return from this callback) */ - req->res.status = status; - req->res.reason = h2o_strdup(&req->pool, msg.base, msg.len).base; - for (i = 0; i != num_headers; ++i) { - if (h2o_iovec_is_token(headers[i].name)) { - const h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, headers[i].name); - h2o_iovec_t value; - if (token->proxy_should_drop_for_res) { - goto Skip; - } - if (token == H2O_TOKEN_CONTENT_LENGTH) { - if (req->res.content_length != SIZE_MAX || - (req->res.content_length = h2o_strtosize(headers[i].value.base, headers[i].value.len)) == SIZE_MAX) { - self->client = NULL; - h2o_req_log_error(req, "lib/core/proxy.c", "%s", "invalid response from upstream (malformed content-length)"); - h2o_send_error_502(req, "Gateway Error", "invalid response from upstream", 0); - return NULL; - } - goto Skip; - } else if (token == H2O_TOKEN_LOCATION) { - if (req->res_is_delegated && (300 <= status && status <= 399) && status != 304) { - self->client = NULL; - h2o_iovec_t method = h2o_get_redirect_method(req->method, status); - h2o_send_redirect_internal(req, method, headers[i].value.base, headers[i].value.len, 1); - return NULL; - } - if (req->overrides != NULL && req->overrides->location_rewrite.match != NULL) { - value = rewrite_location(&req->pool, headers[i].value.base, headers[i].value.len, - req->overrides->location_rewrite.match, req->input.scheme, req->input.authority, - req->overrides->location_rewrite.path_prefix); - if (value.base != NULL) - goto AddHeader; - } - goto AddHeaderDuped; - } else if (token == H2O_TOKEN_LINK) { - h2o_iovec_t new_value; - new_value = h2o_push_path_in_link_header(req, headers[i].value.base, headers[i].value.len); - if (!new_value.len) - goto Skip; - headers[i].value.base = new_value.base; - headers[i].value.len = new_value.len; - } else if (token == H2O_TOKEN_SERVER) { - if (!req->conn->ctx->globalconf->proxy.preserve_server_header) - goto Skip; - } else if (token == H2O_TOKEN_X_COMPRESS_HINT) { - req->compress_hint = compress_hint_to_enum(headers[i].value.base, headers[i].value.len); - goto Skip; - } - /* default behaviour, transfer the header downstream */ - AddHeaderDuped: - value = h2o_strdup(&req->pool, headers[i].value.base, headers[i].value.len); - AddHeader: - h2o_add_header(&req->pool, &req->res.headers, token, headers[i].orig_name, value.base, value.len); - Skip:; - } else { - h2o_iovec_t name = h2o_strdup(&req->pool, headers[i].name->base, headers[i].name->len); - h2o_iovec_t value = h2o_strdup(&req->pool, headers[i].value.base, headers[i].value.len); - h2o_add_header_by_str(&req->pool, &req->res.headers, name.base, name.len, 0, headers[i].orig_name, value.base, - value.len); - } - } - - if (self->is_websocket_handshake && req->res.status == 101) { - h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); - assert(client_ctx->websocket_timeout != NULL); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_UPGRADE, NULL, H2O_STRLIT("websocket")); - on_websocket_upgrade(self, client_ctx->websocket_timeout, rlen); - self->client = NULL; - return NULL; - } - /* declare the start of the response */ - h2o_start_response(req, &self->super); - - if (errstr == h2o_http1client_error_is_eos) { - self->client = NULL; - h2o_send(req, NULL, 0, H2O_SEND_STATE_FINAL); - return NULL; - } - - return on_body; -} - -static int on_1xx(h2o_http1client_t *client, int minor_version, int status, h2o_iovec_t msg, h2o_header_t *headers, - size_t num_headers) -{ - struct rp_generator_t *self = client->data; - size_t i; - - for (i = 0; i != num_headers; ++i) { - if (headers[i].name == &H2O_TOKEN_LINK->buf) - h2o_push_path_in_link_header(self->src_req, headers[i].value.base, headers[i].value.len); - } - - return 0; -} - -static h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr, h2o_iovec_t **reqbufs, size_t *reqbufcnt, - int *method_is_head) -{ - struct rp_generator_t *self = client->data; - - if (errstr != NULL) { - self->client = NULL; - h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr); - h2o_send_error_502(self->src_req, "Gateway Error", errstr, 0); - return NULL; - } - - *reqbufs = self->up_req.bufs; - *reqbufcnt = self->up_req.bufs[1].base != NULL ? 2 : 1; - *method_is_head = self->up_req.is_head; - self->client->informational_cb = on_1xx; - return on_head; -} - -static void on_generator_dispose(void *_self) -{ - struct rp_generator_t *self = _self; - - if (self->client != NULL) { - h2o_http1client_cancel(self->client); - self->client = NULL; - } - h2o_buffer_dispose(&self->last_content_before_send); - h2o_doublebuffer_dispose(&self->sending); -} - -static struct rp_generator_t *proxy_send_prepare(h2o_req_t *req, int keepalive, int use_proxy_protocol) -{ - struct rp_generator_t *self = h2o_mem_alloc_shared(&req->pool, sizeof(*self), on_generator_dispose); - h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); - - self->super.proceed = do_proceed; - self->super.stop = do_close; - self->src_req = req; - if (client_ctx->websocket_timeout != NULL && h2o_lcstris(req->upgrade.base, req->upgrade.len, H2O_STRLIT("websocket"))) { - self->is_websocket_handshake = 1; - } else { - self->is_websocket_handshake = 0; - } - self->had_body_error = 0; - self->up_req.bufs[0] = build_request(req, keepalive, self->is_websocket_handshake, use_proxy_protocol); - self->up_req.bufs[1] = req->entity; - self->up_req.is_head = h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD")); - h2o_buffer_init(&self->last_content_before_send, &h2o_socket_buffer_prototype); - h2o_doublebuffer_init(&self->sending, &h2o_socket_buffer_prototype); - - return self; -} - -void h2o__proxy_process_request(h2o_req_t *req) -{ - h2o_req_overrides_t *overrides = req->overrides; - h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); - struct rp_generator_t *self; - - if (overrides != NULL) { - if (overrides->socketpool != NULL) { - if (overrides->use_proxy_protocol) - assert(!"proxy protocol cannot be used for a persistent upstream connection"); - self = proxy_send_prepare(req, 1, 0); - h2o_http1client_connect_with_pool(&self->client, self, client_ctx, overrides->socketpool, on_connect); - return; - } else if (overrides->hostport.host.base != NULL) { - self = proxy_send_prepare(req, 0, overrides->use_proxy_protocol); - h2o_http1client_connect(&self->client, self, client_ctx, req->overrides->hostport.host, req->overrides->hostport.port, - 0, on_connect); - return; - } - } - { /* default logic */ - h2o_iovec_t host; - uint16_t port; - if (h2o_url_parse_hostport(req->authority.base, req->authority.len, &host, &port) == NULL) { - h2o_req_log_error(req, "lib/core/proxy.c", "invalid URL supplied for internal redirection:%s://%.*s%.*s", - req->scheme->name.base, (int)req->authority.len, req->authority.base, (int)req->path.len, - req->path.base); - h2o_send_error_502(req, "Gateway Error", "internal error", 0); - return; - } - if (port == 65535) - port = req->scheme->default_port; - self = proxy_send_prepare(req, 0, overrides != NULL && overrides->use_proxy_protocol); - h2o_http1client_connect(&self->client, self, client_ctx, host, port, req->scheme == &H2O_URL_SCHEME_HTTPS, on_connect); - return; - } -} diff --git a/web/server/h2o/libh2o/lib/core/request.c b/web/server/h2o/libh2o/lib/core/request.c deleted file mode 100644 index 96aabb22d..000000000 --- a/web/server/h2o/libh2o/lib/core/request.c +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Tatsuhiro Tsujikawa - * - * 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" - -#ifndef IOV_MAX -#define IOV_MAX UIO_MAXIOV -#endif - -#define INITIAL_INBUFSZ 8192 - -struct st_deferred_request_action_t { - h2o_timeout_entry_t timeout; - h2o_req_t *req; -}; - -struct st_delegate_request_deferred_t { - struct st_deferred_request_action_t super; - h2o_handler_t *current_handler; -}; - -struct st_reprocess_request_deferred_t { - struct st_deferred_request_action_t super; - h2o_iovec_t method; - const h2o_url_scheme_t *scheme; - h2o_iovec_t authority; - h2o_iovec_t path; - h2o_req_overrides_t *overrides; - int is_delegated; -}; - -struct st_send_error_deferred_t { - h2o_req_t *req; - int status; - const char *reason; - const char *body; - int flags; - h2o_timeout_entry_t _timeout; -}; - -static void on_deferred_action_dispose(void *_action) -{ - struct st_deferred_request_action_t *action = _action; - if (h2o_timeout_is_linked(&action->timeout)) - h2o_timeout_unlink(&action->timeout); -} - -static struct st_deferred_request_action_t *create_deferred_action(h2o_req_t *req, size_t sz, h2o_timeout_cb cb) -{ - struct st_deferred_request_action_t *action = h2o_mem_alloc_shared(&req->pool, sz, on_deferred_action_dispose); - *action = (struct st_deferred_request_action_t){{0, cb}, req}; - h2o_timeout_link(req->conn->ctx->loop, &req->conn->ctx->zero_timeout, &action->timeout); - return action; -} - -static h2o_hostconf_t *find_hostconf(h2o_hostconf_t **hostconfs, h2o_iovec_t authority, uint16_t default_port) -{ - h2o_iovec_t hostname; - uint16_t port; - char *hostname_lc; - - /* safe-guard for alloca */ - if (authority.len >= 65536) - return NULL; - - /* extract the specified hostname and port */ - if (h2o_url_parse_hostport(authority.base, authority.len, &hostname, &port) == NULL) - return NULL; - if (port == 65535) - port = default_port; - - /* convert supplied hostname to lower-case */ - hostname_lc = alloca(hostname.len); - memcpy(hostname_lc, hostname.base, hostname.len); - h2o_strtolower(hostname_lc, hostname.len); - - do { - h2o_hostconf_t *hostconf = *hostconfs; - if (hostconf->authority.port == port || (hostconf->authority.port == 65535 && port == default_port)) { - if (hostconf->authority.host.base[0] == '*') { - /* matching against "*.foo.bar" */ - size_t cmplen = hostconf->authority.host.len - 1; - if (cmplen < hostname.len && - memcmp(hostconf->authority.host.base + 1, hostname_lc + hostname.len - cmplen, cmplen) == 0) - return hostconf; - } else { - /* exact match */ - if (h2o_memis(hostconf->authority.host.base, hostconf->authority.host.len, hostname_lc, hostname.len)) - return hostconf; - } - } - } while (*++hostconfs != NULL); - - return NULL; -} - -static h2o_hostconf_t *setup_before_processing(h2o_req_t *req) -{ - h2o_context_t *ctx = req->conn->ctx; - h2o_hostconf_t *hostconf; - - h2o_get_timestamp(ctx, &req->pool, &req->processed_at); - - /* find the host context */ - if (req->input.authority.base != NULL) { - if (req->conn->hosts[1] == NULL || - (hostconf = find_hostconf(req->conn->hosts, req->input.authority, req->input.scheme->default_port)) == NULL) - hostconf = *req->conn->hosts; - } else { - /* set the authority name to the default one */ - hostconf = *req->conn->hosts; - req->input.authority = hostconf->authority.hostport; - } - - req->scheme = req->input.scheme; - req->method = req->input.method; - req->authority = req->input.authority; - req->path = req->input.path; - req->path_normalized = - h2o_url_normalize_path(&req->pool, req->input.path.base, req->input.path.len, &req->query_at, &req->norm_indexes); - req->input.query_at = req->query_at; /* we can do this since input.path == path */ - - return hostconf; -} - -static void call_handlers(h2o_req_t *req, h2o_handler_t **handler) -{ - h2o_handler_t **end = req->pathconf->handlers.entries + req->pathconf->handlers.size; - - for (; handler != end; ++handler) - if ((*handler)->on_req(*handler, req) == 0) - return; - - h2o_send_error_404(req, "File Not Found", "not found", 0); -} - -static void process_hosted_request(h2o_req_t *req, h2o_hostconf_t *hostconf) -{ - h2o_pathconf_t *selected_pathconf = &hostconf->fallback_path; - size_t i; - - /* setup pathconf, or redirect to "path/" */ - for (i = 0; i != hostconf->paths.size; ++i) { - h2o_pathconf_t *candidate = hostconf->paths.entries + i; - if (req->path_normalized.len >= candidate->path.len && - memcmp(req->path_normalized.base, candidate->path.base, candidate->path.len) == 0 && - (candidate->path.base[candidate->path.len - 1] == '/' || req->path_normalized.len == candidate->path.len || - req->path_normalized.base[candidate->path.len] == '/')) { - selected_pathconf = candidate; - break; - } - } - h2o_req_bind_conf(req, hostconf, selected_pathconf); - - call_handlers(req, req->pathconf->handlers.entries); -} - -static void deferred_proceed_cb(h2o_timeout_entry_t *entry) -{ - h2o_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_req_t, _timeout_entry, entry); - h2o_proceed_response(req); -} - -static void close_generator_and_filters(h2o_req_t *req) -{ - /* close the generator if it is still open */ - if (req->_generator != NULL) { - /* close generator */ - if (req->_generator->stop != NULL) - req->_generator->stop(req->_generator, req); - req->_generator = NULL; - } - /* close the ostreams still open */ - while (req->_ostr_top->next != NULL) { - if (req->_ostr_top->stop != NULL) - req->_ostr_top->stop(req->_ostr_top, req); - req->_ostr_top = req->_ostr_top->next; - } -} - -static void reset_response(h2o_req_t *req) -{ - req->res = (h2o_res_t){0, NULL, SIZE_MAX}; - req->res.reason = "OK"; - req->_next_filter_index = 0; - req->bytes_sent = 0; -} - -static void retain_original_response(h2o_req_t *req) -{ - if (req->res.original.status != 0) - return; - - req->res.original.status = req->res.status; - h2o_vector_reserve(&req->pool, &req->res.original.headers, req->res.headers.size); - h2o_memcpy(req->res.original.headers.entries, req->res.headers.entries, - sizeof(req->res.headers.entries[0]) * req->res.headers.size); - req->res.original.headers.size = req->res.headers.size; -} - -void h2o_init_request(h2o_req_t *req, h2o_conn_t *conn, h2o_req_t *src) -{ - /* clear all memory (expect memory pool, since it is large) */ - memset(req, 0, offsetof(h2o_req_t, pool)); - - /* init memory pool (before others, since it may be used) */ - h2o_mem_init_pool(&req->pool); - - /* init properties that should be initialized to non-zero */ - req->conn = conn; - req->_timeout_entry.cb = deferred_proceed_cb; - req->res.reason = "OK"; /* default to "OK" regardless of the status value, it's not important after all (never sent in HTTP2) */ - req->res.content_length = SIZE_MAX; - req->preferred_chunk_size = SIZE_MAX; - - if (src != NULL) { - size_t i; -#define COPY(buf) \ - do { \ - req->buf.base = h2o_mem_alloc_pool(&req->pool, src->buf.len); \ - memcpy(req->buf.base, src->buf.base, src->buf.len); \ - req->buf.len = src->buf.len; \ - } while (0) - COPY(input.authority); - COPY(input.method); - COPY(input.path); - req->input.scheme = src->input.scheme; - req->version = src->version; - req->entity = src->entity; - req->http1_is_persistent = src->http1_is_persistent; - req->timestamps = src->timestamps; - if (src->upgrade.base != NULL) { - COPY(upgrade); - } else { - req->upgrade.base = NULL; - req->upgrade.len = 0; - } -#undef COPY - h2o_vector_reserve(&req->pool, &req->headers, src->headers.size); - req->headers.size = src->headers.size; - for (i = 0; i != src->headers.size; ++i) { - h2o_header_t *dst_header = req->headers.entries + i, *src_header = src->headers.entries + i; - if (h2o_iovec_is_token(src_header->name)) { - dst_header->name = src_header->name; - } else { - dst_header->name = h2o_mem_alloc_pool(&req->pool, sizeof(*dst_header->name)); - *dst_header->name = h2o_strdup(&req->pool, src_header->name->base, src_header->name->len); - } - dst_header->value = h2o_strdup(&req->pool, src_header->value.base, src_header->value.len); - if (!src_header->orig_name) - dst_header->orig_name = NULL; - else - dst_header->orig_name = h2o_strdup(&req->pool, src_header->orig_name, src_header->name->len).base; - } - if (src->env.size != 0) { - h2o_vector_reserve(&req->pool, &req->env, src->env.size); - req->env.size = src->env.size; - for (i = 0; i != req->env.size; ++i) - req->env.entries[i] = h2o_strdup(&req->pool, src->env.entries[i].base, src->env.entries[i].len); - } - } -} - -void h2o_dispose_request(h2o_req_t *req) -{ - close_generator_and_filters(req); - - h2o_timeout_unlink(&req->_timeout_entry); - - if (req->version != 0 && req->pathconf != NULL) { - h2o_logger_t **logger = req->pathconf->loggers.entries, **end = logger + req->pathconf->loggers.size; - for (; logger != end; ++logger) { - (*logger)->log_access((*logger), req); - } - } - - h2o_mem_clear_pool(&req->pool); -} - -void h2o_process_request(h2o_req_t *req) -{ - h2o_hostconf_t *hostconf = setup_before_processing(req); - process_hosted_request(req, hostconf); -} - -void h2o_delegate_request(h2o_req_t *req, h2o_handler_t *current_handler) -{ - h2o_handler_t **handler = req->pathconf->handlers.entries, **end = handler + req->pathconf->handlers.size; - - for (; handler != end; ++handler) { - if (*handler == current_handler) { - ++handler; - break; - } - } - call_handlers(req, handler); -} - -static void on_delegate_request_cb(h2o_timeout_entry_t *entry) -{ - struct st_delegate_request_deferred_t *args = - H2O_STRUCT_FROM_MEMBER(struct st_delegate_request_deferred_t, super.timeout, entry); - h2o_delegate_request(args->super.req, args->current_handler); -} - -void h2o_delegate_request_deferred(h2o_req_t *req, h2o_handler_t *current_handler) -{ - struct st_delegate_request_deferred_t *args = - (struct st_delegate_request_deferred_t *)create_deferred_action(req, sizeof(*args), on_delegate_request_cb); - args->current_handler = current_handler; -} - -void h2o_reprocess_request(h2o_req_t *req, h2o_iovec_t method, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, - h2o_iovec_t path, h2o_req_overrides_t *overrides, int is_delegated) -{ - h2o_hostconf_t *hostconf; - - retain_original_response(req); - - /* close generators and filters that are already running */ - close_generator_and_filters(req); - - /* setup the request/response parameters */ - req->method = method; - req->scheme = scheme; - req->authority = authority; - req->path = path; - req->path_normalized = h2o_url_normalize_path(&req->pool, req->path.base, req->path.len, &req->query_at, &req->norm_indexes); - req->overrides = overrides; - req->res_is_delegated |= is_delegated; - reset_response(req); - - /* check the delegation (or reprocess) counter */ - if (req->res_is_delegated) { - if (req->num_delegated == req->conn->ctx->globalconf->max_delegations) { - /* TODO log */ - h2o_send_error_502(req, "Gateway Error", "too many internal delegations", 0); - return; - } - ++req->num_delegated; - } else { - if (req->num_reprocessed >= 5) { - /* TODO log */ - h2o_send_error_502(req, "Gateway Error", "too many internal reprocesses", 0); - return; - } - ++req->num_reprocessed; - } - - /* handle the response using the handlers, if hostconf exists */ - h2o_hostconf_t **hosts = is_delegated ? req->conn->ctx->globalconf->hosts : req->conn->hosts; - if (req->overrides == NULL && (hostconf = find_hostconf(hosts, req->authority, req->scheme->default_port)) != NULL) { - req->pathconf = NULL; - process_hosted_request(req, hostconf); - return; - } - - /* uses the current pathconf, in other words, proxy uses the previous pathconf for building filters */ - h2o__proxy_process_request(req); -} - -static void on_reprocess_request_cb(h2o_timeout_entry_t *entry) -{ - struct st_reprocess_request_deferred_t *args = - H2O_STRUCT_FROM_MEMBER(struct st_reprocess_request_deferred_t, super.timeout, entry); - h2o_reprocess_request(args->super.req, args->method, args->scheme, args->authority, args->path, args->overrides, - args->is_delegated); -} - -void h2o_reprocess_request_deferred(h2o_req_t *req, h2o_iovec_t method, const h2o_url_scheme_t *scheme, h2o_iovec_t authority, - h2o_iovec_t path, h2o_req_overrides_t *overrides, int is_delegated) -{ - struct st_reprocess_request_deferred_t *args = - (struct st_reprocess_request_deferred_t *)create_deferred_action(req, sizeof(*args), on_reprocess_request_cb); - args->method = method; - args->scheme = scheme; - args->authority = authority; - args->path = path; - args->overrides = overrides; - args->is_delegated = is_delegated; -} - -void h2o_start_response(h2o_req_t *req, h2o_generator_t *generator) -{ - retain_original_response(req); - - /* set generator */ - assert(req->_generator == NULL); - req->_generator = generator; - - /* setup response filters */ - if (req->prefilters != NULL) { - req->prefilters->on_setup_ostream(req->prefilters, req, &req->_ostr_top); - } else { - h2o_setup_next_ostream(req, &req->_ostr_top); - } -} - -void h2o_send(h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state) -{ - assert(req->_generator != NULL); - - if (!h2o_send_state_is_in_progress(state)) - req->_generator = NULL; - - req->_ostr_top->do_send(req->_ostr_top, req, bufs, bufcnt, state); -} - -h2o_req_prefilter_t *h2o_add_prefilter(h2o_req_t *req, size_t sz) -{ - h2o_req_prefilter_t *prefilter = h2o_mem_alloc_pool(&req->pool, sz); - prefilter->next = req->prefilters; - req->prefilters = prefilter; - return prefilter; -} - -h2o_ostream_t *h2o_add_ostream(h2o_req_t *req, size_t sz, h2o_ostream_t **slot) -{ - h2o_ostream_t *ostr = h2o_mem_alloc_pool(&req->pool, sz); - ostr->next = *slot; - ostr->do_send = NULL; - ostr->stop = NULL; - ostr->start_pull = NULL; - - *slot = ostr; - - return ostr; -} - -static void apply_env(h2o_req_t *req, h2o_envconf_t *env) -{ - size_t i; - - if (env->parent != NULL) - apply_env(req, env->parent); - for (i = 0; i != env->unsets.size; ++i) - h2o_req_unsetenv(req, env->unsets.entries[i].base, env->unsets.entries[i].len); - for (i = 0; i != env->sets.size; i += 2) - *h2o_req_getenv(req, env->sets.entries[i].base, env->sets.entries[i].len, 1) = env->sets.entries[i + 1]; -} - -void h2o_req_bind_conf(h2o_req_t *req, h2o_hostconf_t *hostconf, h2o_pathconf_t *pathconf) -{ - req->hostconf = hostconf; - req->pathconf = pathconf; - if (pathconf->env != NULL) - apply_env(req, pathconf->env); -} - -void h2o_ostream_send_next(h2o_ostream_t *ostream, h2o_req_t *req, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t state) -{ - if (!h2o_send_state_is_in_progress(state)) { - assert(req->_ostr_top == ostream); - req->_ostr_top = ostream->next; - } else if (bufcnt == 0) { - h2o_timeout_link(req->conn->ctx->loop, &req->conn->ctx->zero_timeout, &req->_timeout_entry); - return; - } - ostream->next->do_send(ostream->next, req, bufs, bufcnt, state); -} - -void h2o_req_fill_mime_attributes(h2o_req_t *req) -{ - ssize_t content_type_index; - h2o_mimemap_type_t *mime; - - if (req->res.mime_attr != NULL) - return; - - if ((content_type_index = h2o_find_header(&req->res.headers, H2O_TOKEN_CONTENT_TYPE, -1)) != -1 && - (mime = h2o_mimemap_get_type_by_mimetype(req->pathconf->mimemap, req->res.headers.entries[content_type_index].value, 0)) != - NULL) - req->res.mime_attr = &mime->data.attr; - else - req->res.mime_attr = &h2o_mime_attributes_as_is; -} - -void h2o_send_inline(h2o_req_t *req, const char *body, size_t len) -{ - static h2o_generator_t generator = {NULL, NULL}; - - h2o_iovec_t buf = h2o_strdup(&req->pool, body, len); - /* the function intentionally does not set the content length, since it may be used for generating 304 response, etc. */ - /* req->res.content_length = buf.len; */ - - h2o_start_response(req, &generator); - - if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD"))) - h2o_send(req, NULL, 0, H2O_SEND_STATE_FINAL); - else - h2o_send(req, &buf, 1, H2O_SEND_STATE_FINAL); -} - -void h2o_send_error_generic(h2o_req_t *req, int status, const char *reason, const char *body, int flags) -{ - if (req->pathconf == NULL) { - h2o_hostconf_t *hostconf = setup_before_processing(req); - h2o_req_bind_conf(req, hostconf, &hostconf->fallback_path); - } - - if ((flags & H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION) != 0) - req->http1_is_persistent = 0; - - req->res.status = status; - req->res.reason = reason; - req->res.content_length = strlen(body); - - if ((flags & H2O_SEND_ERROR_KEEP_HEADERS) == 0) - memset(&req->res.headers, 0, sizeof(req->res.headers)); - - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/plain; charset=utf-8")); - - h2o_send_inline(req, body, SIZE_MAX); -} - -#define DECL_SEND_ERROR_DEFERRED(status_) \ - static void send_error_deferred_cb_##status_(h2o_timeout_entry_t *entry) \ - { \ - struct st_send_error_deferred_t *args = H2O_STRUCT_FROM_MEMBER(struct st_send_error_deferred_t, _timeout, entry); \ - reset_response(args->req); \ - args->req->conn->ctx->emitted_error_status[H2O_STATUS_ERROR_##status_]++; \ - h2o_send_error_generic(args->req, args->status, args->reason, args->body, args->flags); \ - } \ - \ - static void h2o_send_error_deferred_##status_(h2o_req_t *req, const char *reason, const char *body, int flags) \ - { \ - struct st_send_error_deferred_t *args = h2o_mem_alloc_pool(&req->pool, sizeof(*args)); \ - *args = (struct st_send_error_deferred_t){req, status_, reason, body, flags}; \ - args->_timeout.cb = send_error_deferred_cb_##status_; \ - h2o_timeout_link(req->conn->ctx->loop, &req->conn->ctx->zero_timeout, &args->_timeout); \ - } - -DECL_SEND_ERROR_DEFERRED(502) - -#undef DECL_SEND_ERROR_DEFERRED - -void h2o_req_log_error(h2o_req_t *req, const char *module, const char *fmt, ...) -{ -#define INITIAL_BUF_SIZE 256 - - char *errbuf = h2o_mem_alloc_pool(&req->pool, INITIAL_BUF_SIZE); - int errlen; - va_list args; - - va_start(args, fmt); - errlen = vsnprintf(errbuf, INITIAL_BUF_SIZE, fmt, args); - va_end(args); - - if (errlen >= INITIAL_BUF_SIZE) { - errbuf = h2o_mem_alloc_pool(&req->pool, errlen + 1); - va_start(args, fmt); - errlen = vsnprintf(errbuf, errlen + 1, fmt, args); - va_end(args); - } - -#undef INITIAL_BUF_SIZE - - /* save the log */ - h2o_vector_reserve(&req->pool, &req->error_logs, req->error_logs.size + 1); - req->error_logs.entries[req->error_logs.size++] = (h2o_req_error_log_t){module, h2o_iovec_init(errbuf, errlen)}; - - if (req->pathconf->error_log.emit_request_errors) { - /* build prefix */ - char *prefix = alloca(sizeof("[] in request::") + 32 + strlen(module)), *p = prefix; - p += sprintf(p, "[%s] in request:", module); - if (req->path.len < 32) { - memcpy(p, req->path.base, req->path.len); - p += req->path.len; - } else { - memcpy(p, req->path.base, 29); - p += 29; - memcpy(p, "...", 3); - p += 3; - } - *p++ = ':'; - /* use writev(2) to emit error atomically */ - struct iovec vecs[] = {{prefix, p - prefix}, {errbuf, errlen}, {"\n", 1}}; - H2O_BUILD_ASSERT(sizeof(vecs) / sizeof(vecs[0]) < IOV_MAX); - writev(2, vecs, sizeof(vecs) / sizeof(vecs[0])); - } -} - -void h2o_send_redirect(h2o_req_t *req, int status, const char *reason, const char *url, size_t url_len) -{ - if (req->res_is_delegated) { - h2o_iovec_t method = h2o_get_redirect_method(req->method, status); - h2o_send_redirect_internal(req, method, url, url_len, 0); - return; - } - - static h2o_generator_t generator = {NULL, NULL}; - static const h2o_iovec_t body_prefix = {H2O_STRLIT("Moved

The document has moved here")}; - - /* build and send response */ - h2o_iovec_t bufs[3]; - size_t bufcnt; - if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD"))) { - req->res.content_length = SIZE_MAX; - bufcnt = 0; - } else { - bufs[0] = body_prefix; - bufs[1] = h2o_htmlescape(&req->pool, url, url_len); - bufs[2] = body_suffix; - bufcnt = 3; - req->res.content_length = body_prefix.len + bufs[1].len + body_suffix.len; - } - req->res.status = status; - req->res.reason = reason; - req->res.headers = (h2o_headers_t){NULL}; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_LOCATION, NULL, url, url_len); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/html; charset=utf-8")); - h2o_start_response(req, &generator); - h2o_send(req, bufs, bufcnt, H2O_SEND_STATE_FINAL); -} - -void h2o_send_redirect_internal(h2o_req_t *req, h2o_iovec_t method, const char *url_str, size_t url_len, int preserve_overrides) -{ - h2o_url_t url; - - /* parse the location URL */ - if (h2o_url_parse_relative(url_str, url_len, &url) != 0) { - /* TODO log fprintf(stderr, "[proxy] cannot handle location header: %.*s\n", (int)url_len, url); */ - h2o_send_error_deferred_502(req, "Gateway Error", "internal error", 0); - return; - } - /* convert the location to absolute (while creating copies of the values passed to the deferred call) */ - if (url.scheme == NULL) - url.scheme = req->scheme; - if (url.authority.base == NULL) { - if (req->hostconf != NULL) - url.authority = req->hostconf->authority.hostport; - else - url.authority = req->authority; - } else { - if (h2o_lcstris(url.authority.base, url.authority.len, req->authority.base, req->authority.len)) { - url.authority = req->authority; - } else { - url.authority = h2o_strdup(&req->pool, url.authority.base, url.authority.len); - preserve_overrides = 0; - } - } - h2o_iovec_t base_path = req->path; - h2o_url_resolve_path(&base_path, &url.path); - url.path = h2o_concat(&req->pool, base_path, url.path); - - h2o_reprocess_request_deferred(req, method, url.scheme, url.authority, url.path, preserve_overrides ? req->overrides : NULL, 1); -} - -h2o_iovec_t h2o_get_redirect_method(h2o_iovec_t method, int status) -{ - if (h2o_memis(method.base, method.len, H2O_STRLIT("POST")) && !(status == 307 || status == 308)) - method = h2o_iovec_init(H2O_STRLIT("GET")); - return method; -} - -h2o_iovec_t h2o_push_path_in_link_header(h2o_req_t *req, const char *value, size_t value_len) -{ - int i; - h2o_iovec_t ret = h2o_iovec_init(value, value_len); - if (req->conn->callbacks->push_path == NULL) - return ret; - - h2o_iovec_vector_t paths = h2o_extract_push_path_from_link_header( - &req->pool, value, value_len, req->path_normalized, req->input.scheme, req->input.authority, - req->res_is_delegated ? req->scheme : NULL, req->res_is_delegated ? &req->authority : NULL, &ret); - if (paths.size == 0) - return ret; - - for (i = 0; i < paths.size; i++) { - req->conn->callbacks->push_path(req, paths.entries[i].base, paths.entries[i].len); - } - return ret; -} diff --git a/web/server/h2o/libh2o/lib/core/token.c b/web/server/h2o/libh2o/lib/core/token.c deleted file mode 100644 index e21ce2383..000000000 --- a/web/server/h2o/libh2o/lib/core/token.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 "token_table.h" - -int h2o_iovec_is_token(const h2o_iovec_t *buf) -{ - return &h2o__tokens[0].buf <= buf && buf <= &h2o__tokens[H2O_MAX_TOKENS - 1].buf; -} diff --git a/web/server/h2o/libh2o/lib/core/token_table.h b/web/server/h2o/libh2o/lib/core/token_table.h deleted file mode 100644 index ae26aa6c4..000000000 --- a/web/server/h2o/libh2o/lib/core/token_table.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - * 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. - */ - -/* DO NOT EDIT! generated by tokens.pl */ -h2o_token_t h2o__tokens[] = {{{H2O_STRLIT(":authority")}, 1, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":method")}, 2, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":path")}, 4, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":scheme")}, 6, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT(":status")}, 8, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("accept")}, 19, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-charset")}, 15, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-encoding")}, 16, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-language")}, 17, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("accept-ranges")}, 18, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("access-control-allow-origin")}, 20, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("age")}, 21, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("allow")}, 22, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("authorization")}, 23, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("cache-control")}, 24, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("cache-digest")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("connection")}, 0, 1, 1, 0, 1, 0, 0}, - {{H2O_STRLIT("content-disposition")}, 25, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-encoding")}, 26, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-language")}, 27, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-length")}, 28, 0, 0, 1, 0, 0, 0}, - {{H2O_STRLIT("content-location")}, 29, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-range")}, 30, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("content-type")}, 31, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("cookie")}, 32, 0, 0, 0, 0, 0, 1}, - {{H2O_STRLIT("date")}, 33, 0, 1, 0, 0, 0, 0}, - {{H2O_STRLIT("etag")}, 34, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("expect")}, 35, 0, 0, 1, 0, 0, 0}, - {{H2O_STRLIT("expires")}, 36, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("from")}, 37, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("host")}, 38, 0, 0, 1, 1, 0, 0}, - {{H2O_STRLIT("http2-settings")}, 0, 1, 0, 0, 1, 0, 0}, - {{H2O_STRLIT("if-match")}, 39, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-modified-since")}, 40, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-none-match")}, 41, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-range")}, 42, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("if-unmodified-since")}, 43, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("keep-alive")}, 0, 1, 1, 0, 0, 0, 0}, - {{H2O_STRLIT("last-modified")}, 44, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("link")}, 45, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("location")}, 46, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("max-forwards")}, 47, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("proxy-authenticate")}, 48, 1, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("proxy-authorization")}, 49, 1, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("range")}, 50, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("referer")}, 51, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("refresh")}, 52, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("retry-after")}, 53, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("server")}, 54, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("set-cookie")}, 55, 0, 0, 0, 0, 0, 1}, - {{H2O_STRLIT("strict-transport-security")}, 56, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("te")}, 0, 1, 0, 0, 1, 0, 0}, - {{H2O_STRLIT("transfer-encoding")}, 57, 1, 1, 1, 1, 0, 0}, - {{H2O_STRLIT("upgrade")}, 0, 1, 1, 1, 1, 0, 0}, - {{H2O_STRLIT("user-agent")}, 58, 0, 0, 0, 0, 1, 0}, - {{H2O_STRLIT("vary")}, 59, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("via")}, 60, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("www-authenticate")}, 61, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-compress-hint")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-forwarded-for")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-reproxy-url")}, 0, 0, 0, 0, 0, 0, 0}, - {{H2O_STRLIT("x-traffic")}, 0, 0, 0, 0, 0, 0, 0}}; -size_t h2o__num_tokens = 62; - -const h2o_token_t *h2o_lookup_token(const char *name, size_t len) -{ - switch (len) { - case 2: - switch (name[1]) { - case 'e': - if (memcmp(name, "t", 1) == 0) - return H2O_TOKEN_TE; - break; - } - break; - case 3: - switch (name[2]) { - case 'a': - if (memcmp(name, "vi", 2) == 0) - return H2O_TOKEN_VIA; - break; - case 'e': - if (memcmp(name, "ag", 2) == 0) - return H2O_TOKEN_AGE; - break; - } - break; - case 4: - switch (name[3]) { - case 'e': - if (memcmp(name, "dat", 3) == 0) - return H2O_TOKEN_DATE; - break; - case 'g': - if (memcmp(name, "eta", 3) == 0) - return H2O_TOKEN_ETAG; - break; - case 'k': - if (memcmp(name, "lin", 3) == 0) - return H2O_TOKEN_LINK; - break; - case 'm': - if (memcmp(name, "fro", 3) == 0) - return H2O_TOKEN_FROM; - break; - case 't': - if (memcmp(name, "hos", 3) == 0) - return H2O_TOKEN_HOST; - break; - case 'y': - if (memcmp(name, "var", 3) == 0) - return H2O_TOKEN_VARY; - break; - } - break; - case 5: - switch (name[4]) { - case 'e': - if (memcmp(name, "rang", 4) == 0) - return H2O_TOKEN_RANGE; - break; - case 'h': - if (memcmp(name, ":pat", 4) == 0) - return H2O_TOKEN_PATH; - break; - case 'w': - if (memcmp(name, "allo", 4) == 0) - return H2O_TOKEN_ALLOW; - break; - } - break; - case 6: - switch (name[5]) { - case 'e': - if (memcmp(name, "cooki", 5) == 0) - return H2O_TOKEN_COOKIE; - break; - case 'r': - if (memcmp(name, "serve", 5) == 0) - return H2O_TOKEN_SERVER; - break; - case 't': - if (memcmp(name, "accep", 5) == 0) - return H2O_TOKEN_ACCEPT; - if (memcmp(name, "expec", 5) == 0) - return H2O_TOKEN_EXPECT; - break; - } - break; - case 7: - switch (name[6]) { - case 'd': - if (memcmp(name, ":metho", 6) == 0) - return H2O_TOKEN_METHOD; - break; - case 'e': - if (memcmp(name, ":schem", 6) == 0) - return H2O_TOKEN_SCHEME; - if (memcmp(name, "upgrad", 6) == 0) - return H2O_TOKEN_UPGRADE; - break; - case 'h': - if (memcmp(name, "refres", 6) == 0) - return H2O_TOKEN_REFRESH; - break; - case 'r': - if (memcmp(name, "refere", 6) == 0) - return H2O_TOKEN_REFERER; - break; - case 's': - if (memcmp(name, ":statu", 6) == 0) - return H2O_TOKEN_STATUS; - if (memcmp(name, "expire", 6) == 0) - return H2O_TOKEN_EXPIRES; - break; - } - break; - case 8: - switch (name[7]) { - case 'e': - if (memcmp(name, "if-rang", 7) == 0) - return H2O_TOKEN_IF_RANGE; - break; - case 'h': - if (memcmp(name, "if-matc", 7) == 0) - return H2O_TOKEN_IF_MATCH; - break; - case 'n': - if (memcmp(name, "locatio", 7) == 0) - return H2O_TOKEN_LOCATION; - break; - } - break; - case 9: - switch (name[8]) { - case 'c': - if (memcmp(name, "x-traffi", 8) == 0) - return H2O_TOKEN_X_TRAFFIC; - break; - } - break; - case 10: - switch (name[9]) { - case 'e': - if (memcmp(name, "keep-aliv", 9) == 0) - return H2O_TOKEN_KEEP_ALIVE; - if (memcmp(name, "set-cooki", 9) == 0) - return H2O_TOKEN_SET_COOKIE; - break; - case 'n': - if (memcmp(name, "connectio", 9) == 0) - return H2O_TOKEN_CONNECTION; - break; - case 't': - if (memcmp(name, "user-agen", 9) == 0) - return H2O_TOKEN_USER_AGENT; - break; - case 'y': - if (memcmp(name, ":authorit", 9) == 0) - return H2O_TOKEN_AUTHORITY; - break; - } - break; - case 11: - switch (name[10]) { - case 'r': - if (memcmp(name, "retry-afte", 10) == 0) - return H2O_TOKEN_RETRY_AFTER; - break; - } - break; - case 12: - switch (name[11]) { - case 'e': - if (memcmp(name, "content-typ", 11) == 0) - return H2O_TOKEN_CONTENT_TYPE; - break; - case 's': - if (memcmp(name, "max-forward", 11) == 0) - return H2O_TOKEN_MAX_FORWARDS; - break; - case 't': - if (memcmp(name, "cache-diges", 11) == 0) - return H2O_TOKEN_CACHE_DIGEST; - break; - } - break; - case 13: - switch (name[12]) { - case 'd': - if (memcmp(name, "last-modifie", 12) == 0) - return H2O_TOKEN_LAST_MODIFIED; - break; - case 'e': - if (memcmp(name, "content-rang", 12) == 0) - return H2O_TOKEN_CONTENT_RANGE; - break; - case 'h': - if (memcmp(name, "if-none-matc", 12) == 0) - return H2O_TOKEN_IF_NONE_MATCH; - break; - case 'l': - if (memcmp(name, "cache-contro", 12) == 0) - return H2O_TOKEN_CACHE_CONTROL; - if (memcmp(name, "x-reproxy-ur", 12) == 0) - return H2O_TOKEN_X_REPROXY_URL; - break; - case 'n': - if (memcmp(name, "authorizatio", 12) == 0) - return H2O_TOKEN_AUTHORIZATION; - break; - case 's': - if (memcmp(name, "accept-range", 12) == 0) - return H2O_TOKEN_ACCEPT_RANGES; - break; - } - break; - case 14: - switch (name[13]) { - case 'h': - if (memcmp(name, "content-lengt", 13) == 0) - return H2O_TOKEN_CONTENT_LENGTH; - break; - case 's': - if (memcmp(name, "http2-setting", 13) == 0) - return H2O_TOKEN_HTTP2_SETTINGS; - break; - case 't': - if (memcmp(name, "accept-charse", 13) == 0) - return H2O_TOKEN_ACCEPT_CHARSET; - break; - } - break; - case 15: - switch (name[14]) { - case 'e': - if (memcmp(name, "accept-languag", 14) == 0) - return H2O_TOKEN_ACCEPT_LANGUAGE; - break; - case 'g': - if (memcmp(name, "accept-encodin", 14) == 0) - return H2O_TOKEN_ACCEPT_ENCODING; - break; - case 'r': - if (memcmp(name, "x-forwarded-fo", 14) == 0) - return H2O_TOKEN_X_FORWARDED_FOR; - break; - case 't': - if (memcmp(name, "x-compress-hin", 14) == 0) - return H2O_TOKEN_X_COMPRESS_HINT; - break; - } - break; - case 16: - switch (name[15]) { - case 'e': - if (memcmp(name, "content-languag", 15) == 0) - return H2O_TOKEN_CONTENT_LANGUAGE; - if (memcmp(name, "www-authenticat", 15) == 0) - return H2O_TOKEN_WWW_AUTHENTICATE; - break; - case 'g': - if (memcmp(name, "content-encodin", 15) == 0) - return H2O_TOKEN_CONTENT_ENCODING; - break; - case 'n': - if (memcmp(name, "content-locatio", 15) == 0) - return H2O_TOKEN_CONTENT_LOCATION; - break; - } - break; - case 17: - switch (name[16]) { - case 'e': - if (memcmp(name, "if-modified-sinc", 16) == 0) - return H2O_TOKEN_IF_MODIFIED_SINCE; - break; - case 'g': - if (memcmp(name, "transfer-encodin", 16) == 0) - return H2O_TOKEN_TRANSFER_ENCODING; - break; - } - break; - case 18: - switch (name[17]) { - case 'e': - if (memcmp(name, "proxy-authenticat", 17) == 0) - return H2O_TOKEN_PROXY_AUTHENTICATE; - break; - } - break; - case 19: - switch (name[18]) { - case 'e': - if (memcmp(name, "if-unmodified-sinc", 18) == 0) - return H2O_TOKEN_IF_UNMODIFIED_SINCE; - break; - case 'n': - if (memcmp(name, "content-dispositio", 18) == 0) - return H2O_TOKEN_CONTENT_DISPOSITION; - if (memcmp(name, "proxy-authorizatio", 18) == 0) - return H2O_TOKEN_PROXY_AUTHORIZATION; - break; - } - break; - case 25: - switch (name[24]) { - case 'y': - if (memcmp(name, "strict-transport-securit", 24) == 0) - return H2O_TOKEN_STRICT_TRANSPORT_SECURITY; - break; - } - break; - case 27: - switch (name[26]) { - case 'n': - if (memcmp(name, "access-control-allow-origi", 26) == 0) - return H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN; - break; - } - break; - } - - return NULL; -} diff --git a/web/server/h2o/libh2o/lib/core/util.c b/web/server/h2o/libh2o/lib/core/util.c deleted file mode 100644 index 50d2b2493..000000000 --- a/web/server/h2o/libh2o/lib/core/util.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Satoh Hiroh - * - * 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 -#include -#include -#include "h2o.h" -#include "h2o/http1.h" -#include "h2o/http2.h" - -struct st_h2o_accept_data_t { - h2o_accept_ctx_t *ctx; - h2o_socket_t *sock; - h2o_timeout_entry_t timeout; - h2o_memcached_req_t *async_resumption_get_req; - struct timeval connected_at; -}; - -static void on_accept_timeout(h2o_timeout_entry_t *entry); - -static struct st_h2o_accept_data_t *create_accept_data(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at) -{ - struct st_h2o_accept_data_t *data = h2o_mem_alloc(sizeof(*data)); - - data->ctx = ctx; - data->sock = sock; - data->timeout = (h2o_timeout_entry_t){0}; - data->timeout.cb = on_accept_timeout; - h2o_timeout_link(ctx->ctx->loop, &ctx->ctx->handshake_timeout, &data->timeout); - data->async_resumption_get_req = NULL; - data->connected_at = connected_at; - - sock->data = data; - return data; -} - -static void free_accept_data(struct st_h2o_accept_data_t *data) -{ - assert(data->async_resumption_get_req == NULL); - h2o_timeout_unlink(&data->timeout); - free(data); -} - -static struct { - h2o_memcached_context_t *memc; - unsigned expiration; -} async_resumption_context; - -static void async_resumption_on_get(h2o_iovec_t session_data, void *_accept_data) -{ - struct st_h2o_accept_data_t *accept_data = _accept_data; - accept_data->async_resumption_get_req = NULL; - h2o_socket_ssl_resume_server_handshake(accept_data->sock, session_data); -} - -static void async_resumption_get(h2o_socket_t *sock, h2o_iovec_t session_id) -{ - struct st_h2o_accept_data_t *data = sock->data; - - data->async_resumption_get_req = - h2o_memcached_get(async_resumption_context.memc, data->ctx->libmemcached_receiver, session_id, async_resumption_on_get, - data, H2O_MEMCACHED_ENCODE_KEY | H2O_MEMCACHED_ENCODE_VALUE); -} - -static void async_resumption_new(h2o_iovec_t session_id, h2o_iovec_t session_data) -{ - h2o_memcached_set(async_resumption_context.memc, session_id, session_data, - (uint32_t)time(NULL) + async_resumption_context.expiration, - H2O_MEMCACHED_ENCODE_KEY | H2O_MEMCACHED_ENCODE_VALUE); -} - -void h2o_accept_setup_async_ssl_resumption(h2o_memcached_context_t *memc, unsigned expiration) -{ - async_resumption_context.memc = memc; - async_resumption_context.expiration = expiration; - h2o_socket_ssl_async_resumption_init(async_resumption_get, async_resumption_new); -} - -void on_accept_timeout(h2o_timeout_entry_t *entry) -{ - /* TODO log */ - struct st_h2o_accept_data_t *data = H2O_STRUCT_FROM_MEMBER(struct st_h2o_accept_data_t, timeout, entry); - if (data->async_resumption_get_req != NULL) { - h2o_memcached_cancel_get(async_resumption_context.memc, data->async_resumption_get_req); - data->async_resumption_get_req = NULL; - } - h2o_socket_t *sock = data->sock; - free_accept_data(data); - h2o_socket_close(sock); -} - -static void on_ssl_handshake_complete(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_accept_data_t *data = sock->data; - sock->data = NULL; - - if (err != NULL) { - h2o_socket_close(sock); - goto Exit; - } - - h2o_iovec_t proto = h2o_socket_ssl_get_selected_protocol(sock); - const h2o_iovec_t *ident; - for (ident = h2o_http2_alpn_protocols; ident->len != 0; ++ident) { - if (proto.len == ident->len && memcmp(proto.base, ident->base, proto.len) == 0) { - /* connect as http2 */ - h2o_http2_accept(data->ctx, sock, data->connected_at); - goto Exit; - } - } - /* connect as http1 */ - h2o_http1_accept(data->ctx, sock, data->connected_at); - -Exit: - free_accept_data(data); -} - -static ssize_t parse_proxy_line(char *src, size_t len, struct sockaddr *sa, socklen_t *salen) -{ -#define CHECK_EOF() \ - if (p == end) \ - return -2 -#define EXPECT_CHAR(ch) \ - do { \ - CHECK_EOF(); \ - if (*p++ != ch) \ - return -1; \ - } while (0) -#define SKIP_TO_WS() \ - do { \ - do { \ - CHECK_EOF(); \ - } while (*p++ != ' '); \ - --p; \ - } while (0) - - char *p = src, *end = p + len; - void *addr; - in_port_t *port; - - /* "PROXY "*/ - EXPECT_CHAR('P'); - EXPECT_CHAR('R'); - EXPECT_CHAR('O'); - EXPECT_CHAR('X'); - EXPECT_CHAR('Y'); - EXPECT_CHAR(' '); - - /* "TCP[46] " */ - CHECK_EOF(); - if (*p++ != 'T') { - *salen = 0; /* indicate that no data has been obtained */ - goto SkipToEOL; - } - EXPECT_CHAR('C'); - EXPECT_CHAR('P'); - CHECK_EOF(); - switch (*p++) { - case '4': - *salen = sizeof(struct sockaddr_in); - memset(sa, 0, sizeof(struct sockaddr_in)); - sa->sa_family = AF_INET; - addr = &((struct sockaddr_in *)sa)->sin_addr; - port = &((struct sockaddr_in *)sa)->sin_port; - break; - case '6': - *salen = sizeof(struct sockaddr_in6); - memset(sa, 0, sizeof(struct sockaddr_in6)); - sa->sa_family = AF_INET6; - addr = &((struct sockaddr_in6 *)sa)->sin6_addr; - port = &((struct sockaddr_in6 *)sa)->sin6_port; - break; - default: - return -1; - } - EXPECT_CHAR(' '); - - /* parse peer address */ - char *addr_start = p; - SKIP_TO_WS(); - *p = '\0'; - if (inet_pton(sa->sa_family, addr_start, addr) != 1) - return -1; - *p++ = ' '; - - /* skip local address */ - SKIP_TO_WS(); - ++p; - - /* parse peer port */ - char *port_start = p; - SKIP_TO_WS(); - *p = '\0'; - unsigned short usval; - if (sscanf(port_start, "%hu", &usval) != 1) - return -1; - *port = htons(usval); - *p++ = ' '; - -SkipToEOL: - do { - CHECK_EOF(); - } while (*p++ != '\r'); - CHECK_EOF(); - if (*p++ != '\n') - return -2; - return p - src; - -#undef CHECK_EOF -#undef EXPECT_CHAR -#undef SKIP_TO_WS -} - -static void on_read_proxy_line(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_accept_data_t *data = sock->data; - - if (err != NULL) { - free_accept_data(data); - h2o_socket_close(sock); - return; - } - - struct sockaddr_storage addr; - socklen_t addrlen; - ssize_t r = parse_proxy_line(sock->input->bytes, sock->input->size, (void *)&addr, &addrlen); - switch (r) { - case -1: /* error, just pass the input to the next handler */ - break; - case -2: /* incomplete */ - return; - default: - h2o_buffer_consume(&sock->input, r); - if (addrlen != 0) - h2o_socket_setpeername(sock, (void *)&addr, addrlen); - break; - } - - if (data->ctx->ssl_ctx != NULL) { - h2o_socket_ssl_handshake(sock, data->ctx->ssl_ctx, NULL, on_ssl_handshake_complete); - } else { - struct st_h2o_accept_data_t *data = sock->data; - sock->data = NULL; - h2o_http1_accept(data->ctx, sock, data->connected_at); - free_accept_data(data); - } -} - -void h2o_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock) -{ - struct timeval connected_at = *h2o_get_timestamp(ctx->ctx, NULL, NULL); - - if (ctx->expect_proxy_line || ctx->ssl_ctx != NULL) { - create_accept_data(ctx, sock, connected_at); - if (ctx->expect_proxy_line) { - h2o_socket_read_start(sock, on_read_proxy_line); - } else { - h2o_socket_ssl_handshake(sock, ctx->ssl_ctx, NULL, on_ssl_handshake_complete); - } - } else { - h2o_http1_accept(ctx, sock, connected_at); - } -} - -size_t h2o_stringify_protocol_version(char *dst, int version) -{ - char *p = dst; - - if (version < 0x200) { - assert(version <= 0x109); -#define PREFIX "HTTP/1." - memcpy(p, PREFIX, sizeof(PREFIX) - 1); - p += sizeof(PREFIX) - 1; -#undef PREFIX - *p++ = '0' + (version & 0xff); - } else { -#define PROTO "HTTP/2" - memcpy(p, PROTO, sizeof(PROTO) - 1); - p += sizeof(PROTO) - 1; -#undef PROTO - } - - *p = '\0'; - return p - dst; -} - -size_t h2o_stringify_proxy_header(h2o_conn_t *conn, char *buf) -{ - struct sockaddr_storage ss; - socklen_t sslen; - size_t strlen; - uint16_t peerport; - char *dst = buf; - - if ((sslen = conn->callbacks->get_peername(conn, (void *)&ss)) == 0) - goto Unknown; - switch (ss.ss_family) { - case AF_INET: - memcpy(dst, "PROXY TCP4 ", 11); - dst += 11; - break; - case AF_INET6: - memcpy(dst, "PROXY TCP6 ", 11); - dst += 11; - break; - default: - goto Unknown; - } - if ((strlen = h2o_socket_getnumerichost((void *)&ss, sslen, dst)) == SIZE_MAX) - goto Unknown; - dst += strlen; - *dst++ = ' '; - - peerport = h2o_socket_getport((void *)&ss); - - if ((sslen = conn->callbacks->get_sockname(conn, (void *)&ss)) == 0) - goto Unknown; - if ((strlen = h2o_socket_getnumerichost((void *)&ss, sslen, dst)) == SIZE_MAX) - goto Unknown; - dst += strlen; - *dst++ = ' '; - - dst += sprintf(dst, "%" PRIu16 " %" PRIu16 "\r\n", peerport, (uint16_t)h2o_socket_getport((void *)&ss)); - - return dst - buf; - -Unknown: - memcpy(buf, "PROXY UNKNOWN\r\n", 15); - return 15; -} - -static void push_one_path(h2o_mem_pool_t *pool, h2o_iovec_vector_t *paths_to_push, h2o_iovec_t url, h2o_iovec_t base_path, - const h2o_url_scheme_t *input_scheme, h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, - h2o_iovec_t *base_authority) -{ - h2o_url_t parsed, resolved; - - /* check the authority, and extract absolute path */ - if (h2o_url_parse_relative(url.base, url.len, &parsed) != 0) - return; - - /* fast-path for abspath form */ - if (base_scheme == NULL && parsed.scheme == NULL && parsed.authority.base == NULL && url.len != 0 && url.base[0] == '/') { - h2o_vector_reserve(pool, paths_to_push, paths_to_push->size + 1); - paths_to_push->entries[paths_to_push->size++] = h2o_strdup(pool, url.base, url.len); - return; - } - - /* check scheme and authority if given URL contains either of the two, or if base is specified */ - h2o_url_t base = {input_scheme, input_authority, {NULL}, base_path, 65535}; - if (base_scheme != NULL) { - base.scheme = base_scheme; - base.authority = *base_authority; - } - h2o_url_resolve(pool, &base, &parsed, &resolved); - if (input_scheme != resolved.scheme) - return; - if (!h2o_lcstris(input_authority.base, input_authority.len, resolved.authority.base, resolved.authority.len)) - return; - - h2o_vector_reserve(pool, paths_to_push, paths_to_push->size + 1); - paths_to_push->entries[paths_to_push->size++] = resolved.path; -} - -h2o_iovec_vector_t h2o_extract_push_path_from_link_header(h2o_mem_pool_t *pool, const char *value, size_t value_len, - h2o_iovec_t base_path, const h2o_url_scheme_t *input_scheme, - h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, - h2o_iovec_t *base_authority, h2o_iovec_t *filtered_value) -{ - h2o_iovec_vector_t paths_to_push = {NULL}; - h2o_iovec_t iter = h2o_iovec_init(value, value_len), token_value; - const char *token; - size_t token_len; - *filtered_value = h2o_iovec_init(NULL, 0); - -#define PUSH_FILTERED_VALUE(s, e) \ - do { \ - if (filtered_value->len != 0) { \ - memcpy(filtered_value->base + filtered_value->len, ", ", 2); \ - filtered_value->len += 2; \ - } \ - memcpy(filtered_value->base + filtered_value->len, (s), (e) - (s)); \ - filtered_value->len += (e) - (s); \ - } while (0) - - /* extract URL values from Link: ; rel=preload */ - do { - if ((token = h2o_next_token(&iter, ';', &token_len, NULL)) == NULL) - break; - /* first element should be */ - if (!(token_len >= 2 && token[0] == '<' && token[token_len - 1] == '>')) - break; - h2o_iovec_t url_with_brackets = h2o_iovec_init(token, token_len); - /* find rel=preload */ - int preload = 0, nopush = 0, push_only = 0; - 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("rel")) && - h2o_lcstris(token_value.base, token_value.len, H2O_STRLIT("preload"))) { - preload++; - } else if (h2o_lcstris(token, token_len, H2O_STRLIT("nopush"))) { - nopush++; - } else if (h2o_lcstris(token, token_len, H2O_STRLIT("x-http2-push-only"))) { - push_only++; - } - } - /* push the path */ - if (!nopush && preload) - push_one_path(pool, &paths_to_push, h2o_iovec_init(url_with_brackets.base + 1, url_with_brackets.len - 2), base_path, - input_scheme, input_authority, base_scheme, base_authority); - /* store the elements that needs to be preserved to filtered_value */ - if (push_only) { - if (filtered_value->base == NULL) { - /* the max. size of filtered_value would be x2 in the worst case, when "," is converted to ", " */ - filtered_value->base = h2o_mem_alloc_pool(pool, value_len * 2); - const char *prev_comma = h2o_memrchr(value, ',', url_with_brackets.base - value); - if (prev_comma != NULL) - PUSH_FILTERED_VALUE(value, prev_comma); - } - } else if (filtered_value->base != NULL) { - PUSH_FILTERED_VALUE(url_with_brackets.base, token != NULL ? token : value + value_len); - } - } while (token != NULL); - - if (filtered_value->base != NULL) { - if (token != NULL) - PUSH_FILTERED_VALUE(token, value + value_len); - } else { - *filtered_value = h2o_iovec_init(value, value_len); - } - - return paths_to_push; - -#undef PUSH_FILTERED_VALUE -} - -int h2o_get_compressible_types(const h2o_headers_t *headers) -{ - size_t header_index; - int compressible_types = 0; - - for (header_index = 0; header_index != headers->size; ++header_index) { - const h2o_header_t *header = headers->entries + header_index; - if (H2O_UNLIKELY(header->name == &H2O_TOKEN_ACCEPT_ENCODING->buf)) { - h2o_iovec_t iter = h2o_iovec_init(header->value.base, header->value.len); - const char *token = NULL; - size_t token_len = 0; - while ((token = h2o_next_token(&iter, ',', &token_len, NULL)) != NULL) { - if (h2o_lcstris(token, token_len, H2O_STRLIT("gzip"))) - compressible_types |= H2O_COMPRESSIBLE_GZIP; - else if (h2o_lcstris(token, token_len, H2O_STRLIT("br"))) - compressible_types |= H2O_COMPRESSIBLE_BROTLI; - } - } - } - - return compressible_types; -} - -h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t prefix_len, int use_path_normalized) -{ - h2o_iovec_t parts[4]; - size_t num_parts = 0; - int conf_ends_with_slash = req->pathconf->path.base[req->pathconf->path.len - 1] == '/'; - int prefix_ends_with_slash = prefix[prefix_len - 1] == '/'; - - /* destination starts with given prefix */ - parts[num_parts++] = h2o_iovec_init(prefix, prefix_len); - - /* make adjustments depending on the trailing slashes */ - if (conf_ends_with_slash != prefix_ends_with_slash) { - if (conf_ends_with_slash) { - parts[num_parts++] = h2o_iovec_init(H2O_STRLIT("/")); - } else { - if (req->path_normalized.len != req->pathconf->path.len) - parts[num_parts - 1].len -= 1; - } - } - - /* append suffix path and query */ - - if (use_path_normalized) { - parts[num_parts++] = h2o_uri_escape(&req->pool, req->path_normalized.base + req->pathconf->path.len, - req->path_normalized.len - req->pathconf->path.len, "/@:"); - if (req->query_at != SIZE_MAX) { - parts[num_parts++] = h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at); - } - } else { - if (req->path.len > 1) { - /* - * When proxying, we want to modify the input URL as little - * as possible. We use norm_indexes to find the start of - * the path we want to forward. - */ - size_t next_unnormalized; - if (req->norm_indexes && req->pathconf->path.len > 1) { - next_unnormalized = req->norm_indexes[req->pathconf->path.len - 1]; - } else { - next_unnormalized = req->pathconf->path.len; - } - - /* - * Special case: the input path didn't have any '/' including the first, - * so the first character is actually found at '0' - */ - if (req->path.base[0] != '/' && next_unnormalized == 1) { - next_unnormalized = 0; - } - parts[num_parts++] = (h2o_iovec_t){req->path.base + next_unnormalized, req->path.len - next_unnormalized}; - } - } - - return h2o_concat_list(&req->pool, parts, num_parts); -} - -/* h2-14 and h2-16 are kept for backwards compatibility, as they are often used */ -#define ALPN_ENTRY(s) \ - { \ - H2O_STRLIT(s) \ - } -#define ALPN_PROTOCOLS_CORE ALPN_ENTRY("h2"), ALPN_ENTRY("h2-16"), ALPN_ENTRY("h2-14") -#define NPN_PROTOCOLS_CORE \ - "\x02" \ - "h2" \ - "\x05" \ - "h2-16" \ - "\x05" \ - "h2-14" - -static const h2o_iovec_t http2_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {NULL}}; -const h2o_iovec_t *h2o_http2_alpn_protocols = http2_alpn_protocols; - -static const h2o_iovec_t alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {H2O_STRLIT("http/1.1")}, {NULL}}; -const h2o_iovec_t *h2o_alpn_protocols = alpn_protocols; - -const char *h2o_http2_npn_protocols = NPN_PROTOCOLS_CORE; -const char *h2o_npn_protocols = NPN_PROTOCOLS_CORE "\x08" - "http/1.1"; - -uint64_t h2o_connection_id = 0; diff --git a/web/server/h2o/libh2o/lib/handler/access_log.c b/web/server/h2o/libh2o/lib/handler/access_log.c deleted file mode 100644 index 4a7704174..000000000 --- a/web/server/h2o/libh2o/lib/handler/access_log.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2014-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 -#include -#include -#include -#include -#include -#include -#include "h2o.h" -#include "h2o/serverutil.h" - -struct st_h2o_access_log_filehandle_t { - h2o_logconf_t *logconf; - int fd; -}; - -struct st_h2o_access_logger_t { - h2o_logger_t super; - h2o_access_log_filehandle_t *fh; -}; - -static void log_access(h2o_logger_t *_self, h2o_req_t *req) -{ - struct st_h2o_access_logger_t *self = (struct st_h2o_access_logger_t *)_self; - h2o_access_log_filehandle_t *fh = self->fh; - char *logline, buf[4096]; - size_t len; - - /* stringify */ - len = sizeof(buf); - logline = h2o_log_request(fh->logconf, req, &len, buf); - - /* emit */ - write(fh->fd, logline, len); - - /* free memory */ - if (logline != buf) - free(logline); -} - -static void on_dispose_handle(void *_fh) -{ - h2o_access_log_filehandle_t *fh = _fh; - - h2o_logconf_dispose(fh->logconf); - close(fh->fd); -} - -int h2o_access_log_open_log(const char *path) -{ - int fd; - - if (path[0] == '|') { - int pipefds[2]; - pid_t pid; - char *argv[4] = {"/bin/sh", "-c", (char *)(path + 1), NULL}; - /* create pipe */ - if (pipe(pipefds) != 0) { - perror("pipe failed"); - return -1; - } - if (fcntl(pipefds[1], F_SETFD, FD_CLOEXEC) == -1) { - perror("failed to set FD_CLOEXEC on pipefds[1]"); - return -1; - } - /* spawn the logger */ - int mapped_fds[] = {pipefds[0], 0, /* map pipefds[0] to stdin */ - -1}; - if ((pid = h2o_spawnp(argv[0], argv, mapped_fds, 0)) == -1) { - fprintf(stderr, "failed to open logger: %s:%s\n", path + 1, strerror(errno)); - return -1; - } - /* close the read side of the pipefds and return the write side */ - close(pipefds[0]); - fd = pipefds[1]; - } else { - if ((fd = open(path, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0644)) == -1) { - fprintf(stderr, "failed to open log file:%s:%s\n", path, strerror(errno)); - return -1; - } - } - - return fd; -} - -h2o_access_log_filehandle_t *h2o_access_log_open_handle(const char *path, const char *fmt, int escape) -{ - h2o_logconf_t *logconf; - int fd; - h2o_access_log_filehandle_t *fh; - char errbuf[256]; - - /* default to combined log format */ - if (fmt == NULL) - fmt = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""; - if ((logconf = h2o_logconf_compile(fmt, escape, errbuf)) == NULL) { - fprintf(stderr, "%s\n", errbuf); - return NULL; - } - - /* open log file */ - if ((fd = h2o_access_log_open_log(path)) == -1) { - h2o_logconf_dispose(logconf); - return NULL; - } - - fh = h2o_mem_alloc_shared(NULL, sizeof(*fh), on_dispose_handle); - fh->logconf = logconf; - fh->fd = fd; - return fh; -} - -static void dispose(h2o_logger_t *_self) -{ - struct st_h2o_access_logger_t *self = (void *)_self; - - h2o_mem_release_shared(self->fh); -} - -h2o_logger_t *h2o_access_log_register(h2o_pathconf_t *pathconf, h2o_access_log_filehandle_t *fh) -{ - struct st_h2o_access_logger_t *self = (void *)h2o_create_logger(pathconf, sizeof(*self)); - - self->super.dispose = dispose; - self->super.log_access = log_access; - self->fh = fh; - h2o_mem_addref_shared(fh); - - return &self->super; -} diff --git a/web/server/h2o/libh2o/lib/handler/chunked.c b/web/server/h2o/libh2o/lib/handler/chunked.c deleted file mode 100644 index b6ad4346b..000000000 --- a/web/server/h2o/libh2o/lib/handler/chunked.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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 -#include -#include -#include "h2o.h" - -typedef struct st_chunked_encoder_t { - h2o_ostream_t super; - char buf[64]; -} chunked_encoder_t; - -static void send_chunk(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state) -{ - chunked_encoder_t *self = (void *)_self; - h2o_iovec_t *outbufs = alloca(sizeof(h2o_iovec_t) * (inbufcnt + 2)); - size_t chunk_size, outbufcnt = 0, i; - - /* calc chunk size */ - chunk_size = 0; - for (i = 0; i != inbufcnt; ++i) - chunk_size += inbufs[i].len; - req->bytes_sent += chunk_size; - - /* create chunk header and output data */ - if (chunk_size != 0) { - outbufs[outbufcnt].base = self->buf; - outbufs[outbufcnt].len = sprintf(self->buf, "%zx\r\n", chunk_size); - assert(outbufs[outbufcnt].len < sizeof(self->buf)); - outbufcnt++; - memcpy(outbufs + outbufcnt, inbufs, sizeof(h2o_iovec_t) * inbufcnt); - outbufcnt += inbufcnt; - if (state != H2O_SEND_STATE_ERROR) { - outbufs[outbufcnt].base = "\r\n0\r\n\r\n"; - outbufs[outbufcnt].len = state == H2O_SEND_STATE_FINAL ? 7 : 2; - outbufcnt++; - } - } else if (state == H2O_SEND_STATE_FINAL) { - outbufs[outbufcnt].base = "0\r\n\r\n"; - outbufs[outbufcnt].len = 5; - outbufcnt++; - } - - /* if state is error, send a broken chunk to pass the error down to the browser */ - if (state == H2O_SEND_STATE_ERROR) { - outbufs[outbufcnt].base = "\r\n1\r\n"; - outbufs[outbufcnt].len = 5; - outbufcnt++; - } - - h2o_ostream_send_next(&self->super, req, outbufs, outbufcnt, state); -} - -static void on_setup_ostream(h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t **slot) -{ - chunked_encoder_t *encoder; - - /* do nothing if not HTTP/1.1 or content-length is known */ - if (req->res.content_length != SIZE_MAX || req->version != 0x101) - goto Next; - /* RFC 2616 4.4 states that the following status codes (and response to a HEAD method) should not include message body */ - if ((100 <= req->res.status && req->res.status <= 199) || req->res.status == 204 || req->res.status == 304) - goto Next; - else if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD"))) - goto Next; - /* we cannot handle certain responses (like 101 switching protocols) */ - if (req->res.status != 200) { - req->http1_is_persistent = 0; - goto Next; - } - /* skip if content-encoding header is being set */ - if (h2o_find_header(&req->res.headers, H2O_TOKEN_TRANSFER_ENCODING, -1) != -1) - goto Next; - - /* set content-encoding header */ - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_TRANSFER_ENCODING, NULL, H2O_STRLIT("chunked")); - - /* set the flag that tells finalostream that req->bytes_sent is already counted */ - req->bytes_counted_by_ostream = 1; - - /* setup filter */ - encoder = (void *)h2o_add_ostream(req, sizeof(chunked_encoder_t), slot); - encoder->super.do_send = send_chunk; - slot = &encoder->super.next; - -Next: - h2o_setup_next_ostream(req, slot); -} - -void h2o_chunked_register(h2o_pathconf_t *pathconf) -{ - h2o_filter_t *self = h2o_create_filter(pathconf, sizeof(*self)); - self->on_setup_ostream = on_setup_ostream; -} diff --git a/web/server/h2o/libh2o/lib/handler/compress.c b/web/server/h2o/libh2o/lib/handler/compress.c deleted file mode 100644 index 615977131..000000000 --- a/web/server/h2o/libh2o/lib/handler/compress.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2015,2016 Justin Zhu, 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 "h2o.h" - -#ifndef BUF_SIZE -#define BUF_SIZE 8192 -#endif - -struct st_compress_filter_t { - h2o_filter_t super; - h2o_compress_args_t args; -}; - -struct st_compress_encoder_t { - h2o_ostream_t super; - h2o_compress_context_t *compressor; -}; - -static void do_send(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state) -{ - struct st_compress_encoder_t *self = (void *)_self; - h2o_iovec_t *outbufs; - size_t outbufcnt; - - self->compressor->transform(self->compressor, inbufs, inbufcnt, state, &outbufs, &outbufcnt); - h2o_ostream_send_next(&self->super, req, outbufs, outbufcnt, state); -} - -static void on_setup_ostream(h2o_filter_t *_self, h2o_req_t *req, h2o_ostream_t **slot) -{ - struct st_compress_filter_t *self = (void *)_self; - struct st_compress_encoder_t *encoder; - int compressible_types; - h2o_compress_context_t *compressor; - ssize_t i; - - if (req->version < 0x101) - goto Next; - if (req->res.status != 200) - goto Next; - if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD"))) - goto Next; - - switch (req->compress_hint) { - case H2O_COMPRESS_HINT_DISABLE: - /* compression was explicitely disabled, skip */ - goto Next; - case H2O_COMPRESS_HINT_ENABLE: - /* compression was explicitely enabled */ - break; - case H2O_COMPRESS_HINT_AUTO: - default: - /* no hint from the producer, decide whether to compress based - on the configuration */ - if (req->res.mime_attr == NULL) - h2o_req_fill_mime_attributes(req); - if (!req->res.mime_attr->is_compressible) - goto Next; - if (req->res.content_length < self->args.min_size) - goto Next; - } - - /* skip if failed to gather the list of compressible types */ - if ((compressible_types = h2o_get_compressible_types(&req->headers)) == 0) - goto Next; - - /* skip if content-encoding header is being set (as well as obtain the location of accept-ranges) */ - size_t content_encoding_header_index = -1, accept_ranges_header_index = -1; - for (i = 0; i != req->res.headers.size; ++i) { - if (req->res.headers.entries[i].name == &H2O_TOKEN_CONTENT_ENCODING->buf) - content_encoding_header_index = i; - else if (req->res.headers.entries[i].name == &H2O_TOKEN_ACCEPT_RANGES->buf) - accept_ranges_header_index = i; - else - continue; - } - if (content_encoding_header_index != -1) - goto Next; - -/* open the compressor */ -#if H2O_USE_BROTLI - if (self->args.brotli.quality != -1 && (compressible_types & H2O_COMPRESSIBLE_BROTLI) != 0) { - compressor = h2o_compress_brotli_open(&req->pool, self->args.brotli.quality, req->res.content_length); - } else -#endif - if (self->args.gzip.quality != -1 && (compressible_types & H2O_COMPRESSIBLE_GZIP) != 0) { - compressor = h2o_compress_gzip_open(&req->pool, self->args.gzip.quality); - } else { - /* let proxies know that we looked at accept-encoding when deciding not to compress */ - h2o_set_header_token(&req->pool, &req->res.headers, H2O_TOKEN_VARY, H2O_STRLIT("accept-encoding")); - goto Next; - } - - /* adjust the response headers */ - req->res.content_length = SIZE_MAX; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_ENCODING, NULL, compressor->name.base, compressor->name.len); - h2o_set_header_token(&req->pool, &req->res.headers, H2O_TOKEN_VARY, H2O_STRLIT("accept-encoding")); - if (accept_ranges_header_index != -1) { - req->res.headers.entries[accept_ranges_header_index].value = h2o_iovec_init(H2O_STRLIT("none")); - } else { - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_ACCEPT_RANGES, NULL, H2O_STRLIT("none")); - } - - /* setup filter */ - encoder = (void *)h2o_add_ostream(req, sizeof(*encoder), slot); - encoder->super.do_send = do_send; - slot = &encoder->super.next; - encoder->compressor = compressor; - - /* adjust preferred chunk size (compress by 8192 bytes) */ - if (req->preferred_chunk_size > BUF_SIZE) - req->preferred_chunk_size = BUF_SIZE; - -Next: - h2o_setup_next_ostream(req, slot); -} - -void h2o_compress_register(h2o_pathconf_t *pathconf, h2o_compress_args_t *args) -{ - struct st_compress_filter_t *self = (void *)h2o_create_filter(pathconf, sizeof(*self)); - self->super.on_setup_ostream = on_setup_ostream; - self->args = *args; -} diff --git a/web/server/h2o/libh2o/lib/handler/compress/brotli.cc b/web/server/h2o/libh2o/lib/handler/compress/brotli.cc deleted file mode 100644 index d4d06e9c4..000000000 --- a/web/server/h2o/libh2o/lib/handler/compress/brotli.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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 -#include "h2o.h" -#include "encode.h" - -namespace { - class brotli_context : public h2o_compress_context_t { - protected: - brotli::BrotliCompressor *brotli_; - brotli::BrotliParams params_; - std::vector bufs_; // all bufs_[nnn].base must be free(3)ed - public: - brotli_context(int quality, size_t estimated_content_length) : brotli_(NULL) { - name = h2o_iovec_init(H2O_STRLIT("br")); - transform = _compress; - params_.quality = quality; - if (estimated_content_length != std::numeric_limits::max()) - _update_lgwin(params_, estimated_content_length); - } - ~brotli_context() { - _clear_bufs(); - delete brotli_; - } - static void dispose(void *_self) { - brotli_context *self = static_cast(_self); - self->~brotli_context(); - } - private: - void _clear_bufs(); - void _emit(bool is_last, bool force_flush); - void _compress(h2o_iovec_t *inbufs, size_t inbufcnt, int is_final, h2o_iovec_t **outbufs, size_t *outbufcnt); - static void _compress(h2o_compress_context_t *self, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state, - h2o_iovec_t **outbufs, size_t *outbufcnt) { - static_cast(self)->_compress(inbufs, inbufcnt, !h2o_send_state_is_in_progress(state), outbufs, outbufcnt); - } - static void _update_lgwin(brotli::BrotliParams ¶ms, size_t estimated_content_length); - }; -} - -void brotli_context::_clear_bufs() -{ - for (std::vector::iterator i = bufs_.begin(); i != bufs_.end(); ++i) - free(i->base); - bufs_.clear(); -} - -void brotli_context::_emit(bool is_last, bool force_flush) -{ - uint8_t *output; - size_t out_size; - bool ret = brotli_->WriteBrotliData(is_last, force_flush, &out_size, &output); - assert(ret); - (void)ret; - if (out_size != 0) - bufs_.push_back(h2o_strdup(NULL, reinterpret_cast(output), out_size)); -} - -void brotli_context::_compress(h2o_iovec_t *inbufs, size_t inbufcnt, int is_final, h2o_iovec_t **outbufs, size_t *outbufcnt) -{ - if (brotli_ == NULL) { - if (is_final) { - uint64_t len = 0; - for (size_t i = 0; i != inbufcnt; ++i) - len += inbufs[i].len; - if (len < std::numeric_limits::max()) - _update_lgwin(params_, len); - } - brotli_ = new brotli::BrotliCompressor(params_); - } - - _clear_bufs(); - - if (inbufcnt != 0) { - size_t inbufindex = 0, offset = 0, block_space = brotli_->input_block_size(); - while (inbufindex != inbufcnt) { - size_t copy_len = std::min(block_space, inbufs[inbufindex].len - offset); - brotli_->CopyInputToRingBuffer(copy_len, reinterpret_cast(inbufs[inbufindex].base) + offset); - offset += copy_len; - if (inbufs[inbufindex].len == offset) { - if (++inbufindex == inbufcnt) - break; - offset = 0; - } - if (block_space == 0) { - _emit(false, false); - block_space = brotli_->input_block_size(); - } - } - _emit(is_final, !is_final); - } else { - if (is_final) - _emit(true, false); - } - - if (is_final) { - delete brotli_; - brotli_ = NULL; - } - - *outbufs = &bufs_.front(); - *outbufcnt = bufs_.size(); -} - -void brotli_context::_update_lgwin(brotli::BrotliParams ¶ms, size_t estimated_content_length) -{ - int bits = estimated_content_length > 1 ? sizeof(unsigned long long) * 8 - __builtin_clzll(estimated_content_length - 1) : 1; - if (bits < params.lgwin) - params.lgwin = std::max(bits, brotli::kMinWindowBits); -} - -h2o_compress_context_t *h2o_compress_brotli_open(h2o_mem_pool_t *pool, int quality, size_t estimated_content_length) -{ - brotli_context *ctx = static_cast(h2o_mem_alloc_shared(pool, sizeof(*ctx), brotli_context::dispose)); - return new (ctx) brotli_context(quality, estimated_content_length); -} diff --git a/web/server/h2o/libh2o/lib/handler/compress/gzip.c b/web/server/h2o/libh2o/lib/handler/compress/gzip.c deleted file mode 100644 index c12260df3..000000000 --- a/web/server/h2o/libh2o/lib/handler/compress/gzip.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * 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 "h2o.h" - -#define WINDOW_BITS 31 -#ifndef BUF_SIZE /* is altered by unit test */ -#define BUF_SIZE 8192 -#endif - -typedef H2O_VECTOR(h2o_iovec_t) iovec_vector_t; - -struct st_gzip_context_t { - h2o_compress_context_t super; - z_stream zs; - int zs_is_open; - iovec_vector_t bufs; -}; - -static void do_compress(h2o_compress_context_t *_self, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state, - h2o_iovec_t **outbufs, size_t *outbufcnt); -static void do_decompress(h2o_compress_context_t *_self, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state, - h2o_iovec_t **outbufs, size_t *outbufcnt); - -static void *alloc_cb(void *_unused, unsigned int cnt, unsigned int sz) -{ - return h2o_mem_alloc(cnt * (size_t)sz); -} - -static void free_cb(void *_unused, void *p) -{ - free(p); -} - -static void expand_buf(iovec_vector_t *bufs) -{ - h2o_vector_reserve(NULL, bufs, bufs->size + 1); - bufs->entries[bufs->size++] = h2o_iovec_init(h2o_mem_alloc(BUF_SIZE), 0); -} - -typedef int (*processor)(z_streamp strm, int flush); - -static size_t process_chunk(struct st_gzip_context_t *self, const void *src, size_t len, int flush, size_t bufindex, processor proc) -{ - int ret; - - self->zs.next_in = (void *)src; - self->zs.avail_in = (unsigned)len; - - /* man says: If inflate/deflate returns with avail_out == 0, this function must be called again with the same value of the flush - * parameter and more output space (updated avail_out), until the flush is complete (function returns with non-zero avail_out). - */ - do { - /* expand buffer (note: in case of Z_SYNC_FLUSH we need to supply at least 6 bytes of output buffer) */ - if (self->bufs.entries[bufindex].len + 32 > BUF_SIZE) { - ++bufindex; - if (bufindex == self->bufs.size) - expand_buf(&self->bufs); - self->bufs.entries[bufindex].len = 0; - } - self->zs.next_out = (void *)(self->bufs.entries[bufindex].base + self->bufs.entries[bufindex].len); - self->zs.avail_out = (unsigned)(BUF_SIZE - self->bufs.entries[bufindex].len); - ret = proc(&self->zs, flush); - /* inflate() returns Z_BUF_ERROR if flush is set to Z_FINISH at the middle of the compressed data */ - assert(ret == Z_OK || ret == Z_STREAM_END || ret == Z_BUF_ERROR); - self->bufs.entries[bufindex].len = BUF_SIZE - self->zs.avail_out; - } while (self->zs.avail_out == 0 && ret != Z_STREAM_END); - - return bufindex; -} - -static void do_process(h2o_compress_context_t *_self, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state, - h2o_iovec_t **outbufs, size_t *outbufcnt, processor proc) -{ - struct st_gzip_context_t *self = (void *)_self; - size_t outbufindex; - h2o_iovec_t last_buf; - - outbufindex = 0; - self->bufs.entries[0].len = 0; - - if (inbufcnt != 0) { - size_t i; - for (i = 0; i != inbufcnt - 1; ++i) - outbufindex = process_chunk(self, inbufs[i].base, inbufs[i].len, Z_NO_FLUSH, outbufindex, proc); - last_buf = inbufs[i]; - } else { - last_buf = h2o_iovec_init(NULL, 0); - } - outbufindex = process_chunk(self, last_buf.base, last_buf.len, h2o_send_state_is_in_progress(state) ? Z_SYNC_FLUSH : Z_FINISH, - outbufindex, proc); - - *outbufs = self->bufs.entries; - *outbufcnt = outbufindex + 1; - - if (!h2o_send_state_is_in_progress(state)) { - if (self->super.transform == do_compress) { - deflateEnd(&self->zs); - } else { - inflateEnd(&self->zs); - } - self->zs_is_open = 0; - } -} - -static void do_compress(h2o_compress_context_t *_self, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state, - h2o_iovec_t **outbufs, size_t *outbufcnt) -{ - do_process(_self, inbufs, inbufcnt, state, outbufs, outbufcnt, (processor)deflate); -} - -static void do_decompress(h2o_compress_context_t *_self, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state, - h2o_iovec_t **outbufs, size_t *outbufcnt) -{ - do_process(_self, inbufs, inbufcnt, state, outbufs, outbufcnt, (processor)inflate); -} - -static void do_free(void *_self) -{ - struct st_gzip_context_t *self = _self; - size_t i; - - if (self->zs_is_open) { - if (self->super.transform == do_compress) { - deflateEnd(&self->zs); - } else { - inflateEnd(&self->zs); - } - } - - for (i = 0; i != self->bufs.size; ++i) - free(self->bufs.entries[i].base); - free(self->bufs.entries); -} - -static struct st_gzip_context_t *gzip_open(h2o_mem_pool_t *pool) -{ - struct st_gzip_context_t *self = h2o_mem_alloc_shared(pool, sizeof(*self), do_free); - - self->super.name = h2o_iovec_init(H2O_STRLIT("gzip")); - self->super.transform = NULL; - self->zs.zalloc = alloc_cb; - self->zs.zfree = free_cb; - self->zs.opaque = NULL; - self->zs_is_open = 1; - self->bufs = (iovec_vector_t){NULL}; - expand_buf(&self->bufs); - - return self; -} - -h2o_compress_context_t *h2o_compress_gzip_open(h2o_mem_pool_t *pool, int quality) -{ - struct st_gzip_context_t *self = gzip_open(pool); - self->super.transform = do_compress; - /* Z_BEST_SPEED for on-the-fly compression, memlevel set to 8 as suggested by the manual */ - deflateInit2(&self->zs, quality, Z_DEFLATED, WINDOW_BITS, 8, Z_DEFAULT_STRATEGY); - - return &self->super; -} - -h2o_compress_context_t *h2o_compress_gunzip_open(h2o_mem_pool_t *pool) -{ - struct st_gzip_context_t *self = gzip_open(pool); - self->super.transform = do_decompress; - inflateInit2(&self->zs, WINDOW_BITS); - - return &self->super; -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/access_log.c b/web/server/h2o/libh2o/lib/handler/configurator/access_log.c deleted file mode 100644 index de6380882..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/access_log.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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/configurator.h" - -typedef H2O_VECTOR(h2o_access_log_filehandle_t *) st_h2o_access_log_filehandle_vector_t; - -struct st_h2o_access_log_configurator_t { - h2o_configurator_t super; - st_h2o_access_log_filehandle_vector_t *handles; - st_h2o_access_log_filehandle_vector_t _handles_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_access_log_configurator_t *self = (void *)cmd->configurator; - const char *path, *fmt = NULL; - int escape = H2O_LOGCONF_ESCAPE_APACHE; - h2o_access_log_filehandle_t *fh; - - switch (node->type) { - case YOML_TYPE_SCALAR: - path = node->data.scalar; - break; - case YOML_TYPE_MAPPING: { - yoml_t *t; - /* get path */ - if ((t = yoml_get(node, "path")) == NULL) { - h2o_configurator_errprintf(cmd, node, "could not find mandatory key `path`"); - return -1; - } - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, t, "`path` must be scalar"); - return -1; - } - path = t->data.scalar; - /* get format */ - if ((t = yoml_get(node, "format")) != NULL) { - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, t, "`format` must be a scalar"); - return -1; - } - fmt = t->data.scalar; - } - /* get escape */ - if ((t = yoml_get(node, "escape")) != NULL) { - switch (h2o_configurator_get_one_of(cmd, t, "apache,json")) { - case 0: - escape = H2O_LOGCONF_ESCAPE_APACHE; - break; - case 1: - escape = H2O_LOGCONF_ESCAPE_JSON; - break; - default: - return -1; - } - } - } break; - default: - h2o_configurator_errprintf(cmd, node, "node must be a scalar or a mapping"); - return -1; - } - - if (!ctx->dry_run) { - if ((fh = h2o_access_log_open_handle(path, fmt, escape)) == NULL) - return -1; - h2o_vector_reserve(NULL, self->handles, self->handles->size + 1); - self->handles->entries[self->handles->size++] = fh; - } - - return 0; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_access_log_configurator_t *self = (void *)_self; - size_t i; - - /* push the stack pointer */ - ++self->handles; - - /* link the handles */ - memset(self->handles, 0, sizeof(*self->handles)); - h2o_vector_reserve(NULL, self->handles, self->handles[-1].size + 1); - for (i = 0; i != self->handles[-1].size; ++i) { - h2o_access_log_filehandle_t *fh = self->handles[-1].entries[i]; - self->handles[0].entries[self->handles[0].size++] = fh; - h2o_mem_addref_shared(fh); - } - - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_access_log_configurator_t *self = (void *)_self; - size_t i; - - /* register all handles, and decref them */ - for (i = 0; i != self->handles->size; ++i) { - h2o_access_log_filehandle_t *fh = self->handles->entries[i]; - if (ctx->pathconf != NULL) - h2o_access_log_register(ctx->pathconf, fh); - h2o_mem_release_shared(fh); - } - /* free the vector */ - free(self->handles->entries); - - /* pop the stack pointer */ - --self->handles; - - return 0; -} - -void h2o_access_log_register_configurator(h2o_globalconf_t *conf) -{ - struct st_h2o_access_log_configurator_t *self = (void *)h2o_configurator_create(conf, sizeof(*self)); - - self->super.enter = on_config_enter; - self->super.exit = on_config_exit; - self->handles = self->_handles_stack; - - h2o_configurator_define_command(&self->super, "access-log", H2O_CONFIGURATOR_FLAG_ALL_LEVELS, on_config); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/compress.c b/web/server/h2o/libh2o/lib/handler/configurator/compress.c deleted file mode 100644 index c023dd5cf..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/compress.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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 "h2o.h" -#include "h2o/configurator.h" - -#define DEFAULT_GZIP_QUALITY 1 -#define DEFAULT_BROTLI_QUALITY 1 - -struct compress_configurator_t { - h2o_configurator_t super; - h2o_compress_args_t *vars, _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static const h2o_compress_args_t all_off = {0, {-1}, {-1}}, all_on = {100, {DEFAULT_GZIP_QUALITY}, {DEFAULT_BROTLI_QUALITY}}; - -static int on_config_gzip(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct compress_configurator_t *self = (void *)cmd->configurator; - int mode; - - if ((mode = (int)h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - - *self->vars = all_off; - if (mode != 0) - self->vars->gzip.quality = DEFAULT_GZIP_QUALITY; - - return 0; -} - -static int obtain_quality(yoml_t *node, int min_quality, int max_quality, int default_quality, int *slot) -{ - int tmp; - if (node->type != YOML_TYPE_SCALAR) - return -1; - if (strcasecmp(node->data.scalar, "OFF") == 0) { - *slot = -1; - return 0; - } - if (strcasecmp(node->data.scalar, "ON") == 0) { - *slot = default_quality; - return 0; - } - if (sscanf(node->data.scalar, "%d", &tmp) == 1 && (min_quality <= tmp && tmp <= max_quality)) { - *slot = tmp; - return 0; - } - return -1; -} - -static int on_config_compress_min_size(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct compress_configurator_t *self = (void *)cmd->configurator; - return h2o_configurator_scanf(cmd, node, "%zu", &self->vars->min_size); -} - -static int on_config_compress(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct compress_configurator_t *self = (void *)cmd->configurator; - size_t i; - - switch (node->type) { - case YOML_TYPE_SCALAR: - if (strcasecmp(node->data.scalar, "OFF") == 0) { - *self->vars = all_off; - } else if (strcasecmp(node->data.scalar, "ON") == 0) { - *self->vars = all_on; - } else { - h2o_configurator_errprintf(cmd, node, "scalar argument must be either of: `OFF`, `ON`"); - return -1; - } - break; - case YOML_TYPE_SEQUENCE: - *self->vars = all_off; - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *element = node->data.sequence.elements[i]; - if (element->type == YOML_TYPE_SCALAR && strcasecmp(element->data.scalar, "gzip") == 0) { - self->vars->gzip.quality = DEFAULT_GZIP_QUALITY; - } else if (element->type == YOML_TYPE_SCALAR && strcasecmp(element->data.scalar, "br") == 0) { - self->vars->brotli.quality = DEFAULT_BROTLI_QUALITY; - } else { - h2o_configurator_errprintf(cmd, element, "element of the sequence must be either of: `gzip`, `br`"); - return -1; - } - } - break; - case YOML_TYPE_MAPPING: - *self->vars = all_off; - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - yoml_t *value = node->data.mapping.elements[i].value; - if (key->type == YOML_TYPE_SCALAR && strcasecmp(key->data.scalar, "gzip") == 0) { - if (obtain_quality(value, 1, 9, DEFAULT_GZIP_QUALITY, &self->vars->gzip.quality) != 0) { - h2o_configurator_errprintf( - cmd, value, "value of gzip attribute must be either of `OFF`, `ON` or an integer value between 1 and 9"); - return -1; - } - } else if (key->type == YOML_TYPE_SCALAR && strcasecmp(key->data.scalar, "br") == 0) { - if (obtain_quality(value, 0, 11, DEFAULT_BROTLI_QUALITY, &self->vars->brotli.quality) != 0) { - h2o_configurator_errprintf( - cmd, value, "value of br attribute must be either of `OFF`, `ON` or an integer between 0 and 11"); - return -1; - } - } else { - h2o_configurator_errprintf(cmd, key, "key must be either of: `gzip`, `br`"); - return -1; - } - } - break; - default: - h2o_fatal("unexpected node type"); - break; - } - - return 0; -} - -static int on_config_enter(h2o_configurator_t *configurator, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct compress_configurator_t *self = (void *)configurator; - - ++self->vars; - self->vars[0] = self->vars[-1]; - return 0; -} - -static int on_config_exit(h2o_configurator_t *configurator, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct compress_configurator_t *self = (void *)configurator; - - if (ctx->pathconf != NULL && (self->vars->gzip.quality != -1 || self->vars->brotli.quality != -1)) - h2o_compress_register(ctx->pathconf, self->vars); - - --self->vars; - return 0; -} - -void h2o_compress_register_configurator(h2o_globalconf_t *conf) -{ - struct compress_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - h2o_configurator_define_command(&c->super, "compress", H2O_CONFIGURATOR_FLAG_ALL_LEVELS, on_config_compress); - h2o_configurator_define_command(&c->super, "compress-minimum-size", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_compress_min_size); - h2o_configurator_define_command(&c->super, "gzip", H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_gzip); - c->vars = c->_vars_stack; - c->vars->gzip.quality = -1; - c->vars->brotli.quality = -1; -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/errordoc.c b/web/server/h2o/libh2o/lib/handler/configurator/errordoc.c deleted file mode 100644 index ab24923ee..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/errordoc.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2015-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 "h2o.h" -#include "h2o/configurator.h" - -struct errordoc_configurator_t { - h2o_configurator_t super; - h2o_mem_pool_t pool; - H2O_VECTOR(h2o_errordoc_t) * vars, _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int scan_and_check_status(h2o_configurator_command_t *cmd, yoml_t *value, int *slot) -{ - if (value->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, value, "status must be must be either of: scalar, sequence of scalar"); - return -1; - } - if (h2o_configurator_scanf(cmd, value, "%d", slot) != 0) - return -1; - if (!(400 <= *slot && *slot <= 599)) { - h2o_configurator_errprintf(cmd, value, "status must be within range of 400 to 599"); - return -1; - } - return 0; -} - -static int register_errordoc(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *hash) -{ - struct errordoc_configurator_t *self = (void *)cmd->configurator; - int status[200]; - size_t status_len = 0; - int parsed; - const char *url = NULL; - size_t i, j, k; - yoml_t *key, *value; - - for (i = 0; i != hash->data.mapping.size; ++i) { - key = hash->data.mapping.elements[i].key; - value = hash->data.mapping.elements[i].value; - if (key->type != YOML_TYPE_SCALAR) - goto UnknownKeyError; - if (strcmp(key->data.scalar, "status") == 0) { - if (status_len != 0) - goto KeyAlreadyDefinedError; - - if (value->type == YOML_TYPE_SEQUENCE) { - if (value->data.sequence.size == 0) { - h2o_configurator_errprintf(cmd, value, "status sequence must not be empty"); - return -1; - } - for (j = 0; j != value->data.sequence.size; ++j) { - if (scan_and_check_status(cmd, value->data.sequence.elements[j], &parsed) != 0) - return -1; - /* check the scanned status hasn't already appeared */ - for (k = 0; k != status_len; ++k) { - if (status[k] == parsed) { - h2o_configurator_errprintf(cmd, value, "status %d appears multiple times", status[k]); - return -1; - } - } - status[status_len++] = parsed; - } - } else { - if (scan_and_check_status(cmd, value, &parsed) != 0) - return -1; - status[status_len++] = parsed; - } - - } else if (strcmp(key->data.scalar, "url") == 0) { - if (url != NULL) - goto KeyAlreadyDefinedError; - if (value->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, value, "URL must be a scalar"); - return -1; - } - url = value->data.scalar; - } else { - goto UnknownKeyError; - } - } - - if (status_len == 0) { - h2o_configurator_errprintf(cmd, hash, "mandatory key `status` is not defined"); - return -1; - } - if (url == NULL) { - h2o_configurator_errprintf(cmd, hash, "mandatory key `url` is not defined"); - return -1; - } - - h2o_iovec_t _url = h2o_strdup(&self->pool, url, SIZE_MAX); - for (i = 0; i != status_len; ++i){ - /* register */ - h2o_vector_reserve(&self->pool, self->vars, self->vars->size + 1); - h2o_errordoc_t *errordoc = self->vars->entries + self->vars->size++; - errordoc->status = status[i]; - errordoc->url = _url; - } - - return 0; - -UnknownKeyError: - h2o_configurator_errprintf(cmd, key, "key must be either of: `status`, `url`"); - return -1; -KeyAlreadyDefinedError: - h2o_configurator_errprintf(cmd, key, "the key cannot be defined more than once"); - return -1; -} - -static int on_config_errordoc(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - switch (node->type) { - case YOML_TYPE_SEQUENCE: { - size_t i; - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *e = node->data.sequence.elements[i]; - if (e->type != YOML_TYPE_MAPPING) { - h2o_configurator_errprintf(cmd, e, "element must be a mapping"); - return -1; - } - if (register_errordoc(cmd, ctx, e) != 0) - return -1; - } - return 0; - } - case YOML_TYPE_MAPPING: - return register_errordoc(cmd, ctx, node); - default: - break; - } - - h2o_configurator_errprintf(cmd, node, "argument must be either of: sequence, mapping"); - return -1; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct errordoc_configurator_t *self = (void *)_self; - - if (self->vars == self->_vars_stack) { - /* entering global level */ - h2o_mem_init_pool(&self->pool); - } - - /* copy vars */ - memset(&self->vars[1], 0, sizeof(self->vars[1])); - h2o_vector_reserve(&self->pool, &self->vars[1], self->vars[0].size); - h2o_memcpy(self->vars[1].entries, self->vars[0].entries, sizeof(self->vars[0].entries[0]) * self->vars[0].size); - self->vars[1].size = self->vars[0].size; - - ++self->vars; - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct errordoc_configurator_t *self = (void *)_self; - - if (ctx->pathconf != NULL && self->vars->size != 0) - h2o_errordoc_register(ctx->pathconf, self->vars->entries, self->vars->size); - - --self->vars; - if (self->vars == self->_vars_stack) { - /* exitting global level */ - h2o_mem_clear_pool(&self->pool); - } - - return 0; -} - -void h2o_errordoc_register_configurator(h2o_globalconf_t *conf) -{ - struct errordoc_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - /* set default vars */ - c->vars = c->_vars_stack; - - /* setup handlers */ - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - - /* reproxy: ON | OFF */ - h2o_configurator_define_command(&c->super, "error-doc", H2O_CONFIGURATOR_FLAG_ALL_LEVELS, on_config_errordoc); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/expires.c b/web/server/h2o/libh2o/lib/handler/configurator/expires.c deleted file mode 100644 index 01d404dd5..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/expires.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 -#include -#include -#include "h2o.h" -#include "h2o/configurator.h" - -struct expires_configurator_t { - h2o_configurator_t super; - h2o_expires_args_t **args; - h2o_expires_args_t *_args_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config_expires(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct expires_configurator_t *self = (void *)cmd->configurator; - uint64_t value; - char unit[32]; - - if (strcasecmp(node->data.scalar, "OFF") == 0) { - free(*self->args); - *self->args = NULL; - } else if (sscanf(node->data.scalar, "%" SCNu64 " %31s", &value, unit) == 2) { - /* convert value to seconds depending on the unit */ - if (strncasecmp(unit, H2O_STRLIT("second")) == 0) { - /* ok */ - } else if (strncasecmp(unit, H2O_STRLIT("minute")) == 0) { - value *= 60; - } else if (strncasecmp(unit, H2O_STRLIT("hour")) == 0) { - value *= 60 * 60; - } else if (strncasecmp(unit, H2O_STRLIT("day")) == 0) { - value *= 24 * 60 * 60; - } else if (strncasecmp(unit, H2O_STRLIT("month")) == 0) { - value *= 30 * 24 * 60 * 60; - } else if (strncasecmp(unit, H2O_STRLIT("year")) == 0) { - value *= 365 * 30 * 24 * 60 * 60; - } else { - /* TODO add support for H2O_EXPIRES_MODE_MAX_ABSOLUTE that sets the Expires header? */ - h2o_configurator_errprintf(cmd, node, "unknown unit:`%s` (see --help)", unit); - return -1; - } - /* save the value */ - if (*self->args == NULL) - *self->args = h2o_mem_alloc(sizeof(**self->args)); - (*self->args)->mode = H2O_EXPIRES_MODE_MAX_AGE; - (*self->args)->data.max_age = value; - } else { - h2o_configurator_errprintf(cmd, node, - "failed to parse the value, should be in form of: ` ` or `OFF` (see --help)"); - return -1; - } - - return 0; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct expires_configurator_t *self = (void *)_self; - - if (self->args[0] != NULL) { - /* duplicate */ - assert(self->args[0]->mode == H2O_EXPIRES_MODE_MAX_AGE); - self->args[1] = h2o_mem_alloc(sizeof(**self->args)); - *self->args[1] = *self->args[0]; - } else { - self->args[1] = NULL; - } - ++self->args; - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct expires_configurator_t *self = (void *)_self; - - if (*self->args != NULL) { - /* setup */ - if (ctx->pathconf != NULL) { - h2o_expires_register(ctx->pathconf, *self->args); - } - /* destruct */ - assert((*self->args)->mode == H2O_EXPIRES_MODE_MAX_AGE); - free(*self->args); - *self->args = NULL; - } - - --self->args; - return 0; -} - -void h2o_expires_register_configurator(h2o_globalconf_t *conf) -{ - struct expires_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - /* set default vars */ - c->args = c->_args_stack; - - /* setup handlers */ - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - h2o_configurator_define_command(&c->super, "expires", H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_expires); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/fastcgi.c b/web/server/h2o/libh2o/lib/handler/configurator/fastcgi.c deleted file mode 100644 index bf89b7b26..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/fastcgi.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "h2o.h" -#include "h2o/configurator.h" -#include "h2o/serverutil.h" - -struct fastcgi_configurator_t { - h2o_configurator_t super; - h2o_fastcgi_config_vars_t *vars; - h2o_fastcgi_config_vars_t _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config_timeout_io(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)cmd->configurator; - return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->io_timeout); -} - -static int on_config_timeout_keepalive(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)cmd->configurator; - return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->keepalive_timeout); -} - -static int on_config_document_root(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)cmd->configurator; - - if (node->data.scalar[0] == '\0') { - /* unset */ - self->vars->document_root = h2o_iovec_init(NULL, 0); - } else if (node->data.scalar[0] == '/') { - /* set */ - self->vars->document_root = h2o_iovec_init(node->data.scalar, strlen(node->data.scalar)); - } else { - h2o_configurator_errprintf(cmd, node, "value does not start from `/`"); - return -1; - } - return 0; -} - -static int on_config_send_delegated_uri(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)cmd->configurator; - ssize_t v; - - if ((v = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - self->vars->send_delegated_uri = (int)v; - return 0; -} - -static int on_config_connect(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)cmd->configurator; - const char *hostname = "127.0.0.1", *servname = NULL, *type = "tcp"; - - /* fetch servname (and hostname) */ - switch (node->type) { - case YOML_TYPE_SCALAR: - servname = node->data.scalar; - break; - case YOML_TYPE_MAPPING: { - yoml_t *t; - if ((t = yoml_get(node, "host")) != NULL) { - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, t, "`host` is not a string"); - return -1; - } - hostname = t->data.scalar; - } - if ((t = yoml_get(node, "port")) == NULL) { - h2o_configurator_errprintf(cmd, node, "cannot find mandatory property `port`"); - return -1; - } - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, node, "`port` is not a string"); - return -1; - } - servname = t->data.scalar; - if ((t = yoml_get(node, "type")) != NULL) { - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, t, "`type` is not a string"); - return -1; - } - type = t->data.scalar; - } - } break; - default: - h2o_configurator_errprintf(cmd, node, - "value must be a string or a mapping (with keys: `port` and optionally `host` and `type`)"); - return -1; - } - - if (strcmp(type, "unix") == 0) { - /* unix socket */ - struct sockaddr_un sa; - memset(&sa, 0, sizeof(sa)); - if (strlen(servname) >= sizeof(sa.sun_path)) { - h2o_configurator_errprintf(cmd, node, "path:%s is too long as a unix socket name", servname); - return -1; - } - sa.sun_family = AF_UNIX; - strcpy(sa.sun_path, servname); - h2o_fastcgi_register_by_address(ctx->pathconf, (void *)&sa, sizeof(sa), self->vars); - } else if (strcmp(type, "tcp") == 0) { - /* tcp socket */ - uint16_t port; - if (sscanf(servname, "%" SCNu16, &port) != 1) { - h2o_configurator_errprintf(cmd, node, "invalid port number:%s", servname); - return -1; - } - h2o_fastcgi_register_by_hostport(ctx->pathconf, hostname, port, self->vars); - } else { - h2o_configurator_errprintf(cmd, node, "unknown listen type: %s", type); - return -1; - } - - return 0; -} - -static int create_spawnproc(h2o_configurator_command_t *cmd, yoml_t *node, const char *dirname, char *const *argv, - struct sockaddr_un *sa, struct passwd *pw) -{ - int ret, listen_fd = -1, pipe_fds[2] = {-1, -1}; - - /* build socket path */ - sa->sun_family = AF_UNIX; - ret = snprintf(sa->sun_path, sizeof(sa->sun_path), "%s/_", dirname); - if (ret < 0 || ret >= sizeof(sa->sun_path)) { - h2o_configurator_errprintf(cmd, node, "unix socket path too long: %s", dirname); - goto Error; - } - - /* create socket */ - if ((listen_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - h2o_configurator_errprintf(cmd, node, "socket(2) failed: %s", strerror(errno)); - goto Error; - } - if (bind(listen_fd, (void *)sa, sizeof(*sa)) != 0) { - h2o_configurator_errprintf(cmd, node, "bind(2) failed: %s", strerror(errno)); - goto Error; - } - if (listen(listen_fd, H2O_SOMAXCONN) != 0) { - h2o_configurator_errprintf(cmd, node, "listen(2) failed: %s", strerror(errno)); - goto Error; - } - /* change ownership of socket */ - if (pw != NULL && chown(sa->sun_path, pw->pw_uid, pw->pw_gid) != 0) { - h2o_configurator_errprintf(cmd, node, "chown(2) failed to change ownership of socket:%s:%s", sa->sun_path, strerror(errno)); - goto Error; - } - - /* create pipe which is used to notify the termination of the server */ - if (pipe(pipe_fds) != 0) { - h2o_configurator_errprintf(cmd, node, "pipe(2) failed: %s", strerror(errno)); - pipe_fds[0] = -1; - pipe_fds[1] = -1; - goto Error; - } - if (fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) - goto Error; - - /* spawn */ - int mapped_fds[] = {listen_fd, 0, /* listen_fd to 0 */ - pipe_fds[0], 5, /* pipe_fds[0] to 5 */ - -1}; - pid_t pid = h2o_spawnp(argv[0], argv, mapped_fds, 0); - if (pid == -1) { - fprintf(stderr, "[lib/handler/fastcgi.c] failed to launch helper program %s:%s\n", argv[0], strerror(errno)); - goto Error; - } - - close(listen_fd); - listen_fd = -1; - close(pipe_fds[0]); - pipe_fds[0] = -1; - - return pipe_fds[1]; - -Error: - if (pipe_fds[0] != -1) - close(pipe_fds[0]); - if (pipe_fds[1]) - close(pipe_fds[1]); - if (listen_fd != -1) - close(listen_fd); - unlink(sa->sun_path); - return -1; -} - -static void spawnproc_on_dispose(h2o_fastcgi_handler_t *handler, void *data) -{ - int pipe_fd = (int)((char *)data - (char *)NULL); - close(pipe_fd); -} - -static int on_config_spawn(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)cmd->configurator; - char *spawn_user = NULL, *spawn_cmd; - char *kill_on_close_cmd_path = NULL, *setuidgid_cmd_path = NULL; - char dirname[] = "/tmp/h2o.fcgisock.XXXXXX"; - char *argv[10]; - int spawner_fd; - struct sockaddr_un sa; - h2o_fastcgi_config_vars_t config_vars; - int ret = -1; - struct passwd h2o_user_pwbuf, *h2o_user_pw; - char h2o_user_buf[65536]; - - memset(&sa, 0, sizeof(sa)); - - switch (node->type) { - case YOML_TYPE_SCALAR: - spawn_user = ctx->globalconf->user; - spawn_cmd = node->data.scalar; - break; - case YOML_TYPE_MAPPING: { - yoml_t *t; - if ((t = yoml_get(node, "command")) == NULL) { - h2o_configurator_errprintf(cmd, node, "mandatory attribute `command` does not exist"); - return -1; - } - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, node, "attribute `command` must be scalar"); - return -1; - } - spawn_cmd = t->data.scalar; - spawn_user = ctx->globalconf->user; - if ((t = yoml_get(node, "user")) != NULL) { - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, node, "attribute `user` must be scalar"); - return -1; - } - spawn_user = t->data.scalar; - } - } break; - default: - h2o_configurator_errprintf(cmd, node, "argument must be scalar or mapping"); - return -1; - } - - /* obtain uid & gid of the client that connects to the FastCGI daemon (i.e. H2O after dropping privileges) */ - if (ctx->globalconf->user != NULL) { - /* change ownership of temporary directory */ - if (getpwnam_r(ctx->globalconf->user, &h2o_user_pwbuf, h2o_user_buf, sizeof(h2o_user_buf), &h2o_user_pw) != 0 || - h2o_user_pw == NULL) { - h2o_configurator_errprintf(cmd, node, "getpwnam_r(3) failed to obtain uid of user:%s", ctx->globalconf->user); - goto Exit; - } - } else { - h2o_user_pw = NULL; - } - - { /* build args */ - size_t i = 0; - argv[i++] = kill_on_close_cmd_path = h2o_configurator_get_cmd_path("share/h2o/kill-on-close"); - argv[i++] = "--rm"; - argv[i++] = dirname; - argv[i++] = "--"; - if (spawn_user != NULL) { - argv[i++] = setuidgid_cmd_path = h2o_configurator_get_cmd_path("share/h2o/setuidgid"); - argv[i++] = spawn_user; - } - argv[i++] = "/bin/sh"; - argv[i++] = "-c"; - argv[i++] = spawn_cmd; - argv[i++] = NULL; - assert(i <= sizeof(argv) / sizeof(argv[0])); - } - - if (ctx->dry_run) { - dirname[0] = '\0'; - spawner_fd = -1; - sa.sun_family = AF_UNIX; - strcpy(sa.sun_path, "/dry-run.nonexistent"); - } else { - /* create temporary directory */ - if (mkdtemp(dirname) == NULL) { - h2o_configurator_errprintf(cmd, node, "mkdtemp(3) failed to create temporary directory:%s:%s", dirname, - strerror(errno)); - dirname[0] = '\0'; - goto Exit; - } - /* change ownership of temporary directory */ - if (h2o_user_pw != NULL && chown(dirname, h2o_user_pw->pw_uid, h2o_user_pw->pw_gid) != 0) { - h2o_configurator_errprintf(cmd, node, "chown(2) failed to change ownership of temporary directory:%s:%s", dirname, - strerror(errno)); - goto Exit; - } - /* launch spawnfcgi command */ - if ((spawner_fd = create_spawnproc(cmd, node, dirname, argv, &sa, h2o_user_pw)) == -1) { - goto Exit; - } - } - - config_vars = *self->vars; - config_vars.callbacks.dispose = spawnproc_on_dispose; - config_vars.callbacks.data = (char *)NULL + spawner_fd; - h2o_fastcgi_register_by_address(ctx->pathconf, (void *)&sa, sizeof(sa), &config_vars); - - ret = 0; -Exit: - if (dirname[0] != '\0') - unlink(dirname); - free(kill_on_close_cmd_path); - free(setuidgid_cmd_path); - return ret; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)_self; - - memcpy(self->vars + 1, self->vars, sizeof(*self->vars)); - ++self->vars; - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct fastcgi_configurator_t *self = (void *)_self; - - --self->vars; - return 0; -} - -void h2o_fastcgi_register_configurator(h2o_globalconf_t *conf) -{ - struct fastcgi_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - /* set default vars */ - c->vars = c->_vars_stack; - c->vars->io_timeout = H2O_DEFAULT_FASTCGI_IO_TIMEOUT; - c->vars->keepalive_timeout = 0; - - /* setup handlers */ - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - - h2o_configurator_define_command(&c->super, "fastcgi.connect", - H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXTENSION | H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_connect); - h2o_configurator_define_command(&c->super, "fastcgi.spawn", - H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXTENSION | H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_spawn); - h2o_configurator_define_command(&c->super, "fastcgi.timeout.io", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_timeout_io); - h2o_configurator_define_command(&c->super, "fastcgi.timeout.keepalive", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_timeout_keepalive); - h2o_configurator_define_command(&c->super, "fastcgi.document_root", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_document_root); - h2o_configurator_define_command(&c->super, "fastcgi.send-delegated-uri", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_send_delegated_uri); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/file.c b/web/server/h2o/libh2o/lib/handler/configurator/file.c deleted file mode 100644 index c1c779c68..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/file.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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/configurator.h" - -struct st_h2o_file_config_vars_t { - const char **index_files; - int flags; -}; - -struct st_h2o_file_configurator_t { - h2o_configurator_t super; - struct st_h2o_file_config_vars_t *vars; - struct st_h2o_file_config_vars_t _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config_dir(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)cmd->configurator; - - h2o_file_register(ctx->pathconf, node->data.scalar, self->vars->index_files, *ctx->mimemap, self->vars->flags); - return 0; -} - -static int on_config_file(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)cmd->configurator; - h2o_mimemap_type_t *mime_type = - h2o_mimemap_get_type_by_extension(*ctx->mimemap, h2o_get_filext(node->data.scalar, strlen(node->data.scalar))); - h2o_file_register_file(ctx->pathconf, node->data.scalar, mime_type, self->vars->flags); - return 0; -} - -static int on_config_index(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)cmd->configurator; - size_t i; - - free(self->vars->index_files); - self->vars->index_files = h2o_mem_alloc(sizeof(self->vars->index_files[0]) * (node->data.sequence.size + 1)); - for (i = 0; i != node->data.sequence.size; ++i) { - yoml_t *element = node->data.sequence.elements[i]; - if (element->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, element, "argument must be a sequence of scalars"); - return -1; - } - self->vars->index_files[i] = element->data.scalar; - } - self->vars->index_files[i] = NULL; - - return 0; -} - -static int on_config_etag(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)cmd->configurator; - - switch (h2o_configurator_get_one_of(cmd, node, "OFF,ON")) { - case 0: /* off */ - self->vars->flags |= H2O_FILE_FLAG_NO_ETAG; - break; - case 1: /* on */ - self->vars->flags &= ~H2O_FILE_FLAG_NO_ETAG; - break; - default: /* error */ - return -1; - } - - return 0; -} - -static int on_config_send_compressed(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)cmd->configurator; - - switch (h2o_configurator_get_one_of(cmd, node, "OFF,ON,gunzip")) { - case 0: /* off */ - self->vars->flags &= ~H2O_FILE_FLAG_SEND_COMPRESSED; - break; - case 1: /* on */ - self->vars->flags |= H2O_FILE_FLAG_SEND_COMPRESSED; - break; - case 2: /* gunzip */ - self->vars->flags |= (H2O_FILE_FLAG_SEND_COMPRESSED | H2O_FILE_FLAG_GUNZIP); - break; - default: /* error */ - return -1; - } - - return 0; -} - -static int on_config_dir_listing(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)cmd->configurator; - - switch (h2o_configurator_get_one_of(cmd, node, "OFF,ON")) { - case 0: /* off */ - self->vars->flags &= ~H2O_FILE_FLAG_DIR_LISTING; - break; - case 1: /* on */ - self->vars->flags |= H2O_FILE_FLAG_DIR_LISTING; - break; - default: /* error */ - return -1; - } - - return 0; -} - -static const char **dup_strlist(const char **s) -{ - size_t i; - const char **ret; - - for (i = 0; s[i] != NULL; ++i) - ; - ret = h2o_mem_alloc(sizeof(*ret) * (i + 1)); - for (i = 0; s[i] != NULL; ++i) - ret[i] = s[i]; - ret[i] = NULL; - - return ret; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)_self; - ++self->vars; - self->vars[0].index_files = dup_strlist(self->vars[-1].index_files); - self->vars[0].flags = self->vars[-1].flags; - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_h2o_file_configurator_t *self = (void *)_self; - free(self->vars->index_files); - --self->vars; - return 0; -} - -void h2o_file_register_configurator(h2o_globalconf_t *globalconf) -{ - struct st_h2o_file_configurator_t *self = (void *)h2o_configurator_create(globalconf, sizeof(*self)); - - self->super.enter = on_config_enter; - self->super.exit = on_config_exit; - self->vars = self->_vars_stack; - self->vars->index_files = h2o_file_default_index_files; - - h2o_configurator_define_command(&self->super, "file.dir", H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_dir); - h2o_configurator_define_command(&self->super, "file.file", H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | - H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_file); - h2o_configurator_define_command(&self->super, "file.index", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE, - on_config_index); - h2o_configurator_define_command(&self->super, "file.etag", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_etag); - h2o_configurator_define_command(&self->super, "file.send-compressed", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_send_compressed); - h2o_configurator_define_command(&self->super, "file.send-gzip", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_send_compressed); - h2o_configurator_define_command(&self->super, "file.dirlisting", - (H2O_CONFIGURATOR_FLAG_ALL_LEVELS & ~H2O_CONFIGURATOR_FLAG_EXTENSION) | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_dir_listing); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/headers.c b/web/server/h2o/libh2o/lib/handler/configurator/headers.c deleted file mode 100644 index 68536c052..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/headers.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 "h2o.h" -#include "h2o/configurator.h" - -struct headers_configurator_t { - h2o_configurator_t super; - h2o_headers_command_t **cmds, *_cmd_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct headers_configurator_t *self = (void *)_self; - - self->cmds[1] = self->cmds[0]; - if (self->cmds[1] != NULL) - h2o_mem_addref_shared(self->cmds[1]); - - ++self->cmds; - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct headers_configurator_t *self = (void *)_self; - - if (ctx->pathconf != NULL && *self->cmds != NULL) { - if (*self->cmds != NULL) - h2o_mem_addref_shared(*self->cmds); - h2o_headers_register(ctx->pathconf, *self->cmds); - } - - if (*self->cmds != NULL) - h2o_mem_release_shared(*self->cmds); - --self->cmds; - return 0; -} - -static h2o_headers_command_t **get_headers_commands(h2o_configurator_t *_self) -{ - struct headers_configurator_t *self = (void *)_self; - return self->cmds; -} - -void h2o_headers_register_configurator(h2o_globalconf_t *conf) -{ - struct headers_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - - h2o_configurator_define_headers_commands(conf, &c->super, "header", get_headers_commands); - c->cmds = c->_cmd_stack; -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/headers_util.c b/web/server/h2o/libh2o/lib/handler/configurator/headers_util.c deleted file mode 100644 index c05b9b7c2..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/headers_util.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "h2o.h" -#include "h2o/configurator.h" - -struct headers_util_configurator_t { - h2o_configurator_t super; - h2o_configurator_t *child; - h2o_configurator_get_headers_commands_cb get_commands; -}; - -static int extract_name(const char *src, size_t len, h2o_iovec_t **_name) -{ - h2o_iovec_t name; - const h2o_token_t *name_token; - - name = h2o_str_stripws(src, len); - if (name.len == 0) - return -1; - - name = h2o_strdup(NULL, name.base, name.len); - h2o_strtolower(name.base, name.len); - - if ((name_token = h2o_lookup_token(name.base, name.len)) != NULL) { - *_name = (h2o_iovec_t *)&name_token->buf; - free(name.base); - } else { - *_name = h2o_mem_alloc(sizeof(**_name)); - **_name = name; - } - - return 0; -} - -static int extract_name_value(const char *src, h2o_iovec_t **name, h2o_iovec_t *value) -{ - const char *colon = strchr(src, ':'); - - if (colon == NULL) - return -1; - - if (extract_name(src, colon - src, name) != 0) - return -1; - *value = h2o_str_stripws(colon + 1, strlen(colon + 1)); - *value = h2o_strdup(NULL, value->base, value->len); - - return 0; -} - -static int add_cmd(h2o_configurator_command_t *cmd, yoml_t *node, int cmd_id, h2o_iovec_t *name, h2o_iovec_t value, - h2o_headers_command_t **cmds) -{ - if (h2o_iovec_is_token(name)) { - const h2o_token_t *token = (void *)name; - if (h2o_headers_is_prohibited_name(token)) { - h2o_configurator_errprintf(cmd, node, "the named header cannot be rewritten"); - return -1; - } - } - - h2o_headers_append_command(cmds, cmd_id, name, value); - return 0; -} - -static int on_config_header_2arg(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, int cmd_id, yoml_t *node, - h2o_headers_command_t **headers_cmds) -{ - h2o_iovec_t *name, value; - - if (extract_name_value(node->data.scalar, &name, &value) != 0) { - h2o_configurator_errprintf(cmd, node, "failed to parse the value; should be in form of `name: value`"); - return -1; - } - if (add_cmd(cmd, node, cmd_id, name, value, headers_cmds) != 0) { - if (!h2o_iovec_is_token(name)) - free(name->base); - free(value.base); - return -1; - } - return 0; -} - -static int on_config_header_unset(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - h2o_iovec_t *name; - struct headers_util_configurator_t *self = (void *)cmd->configurator; - - if (extract_name(node->data.scalar, strlen(node->data.scalar), &name) != 0) { - h2o_configurator_errprintf(cmd, node, "invalid header name"); - return -1; - } - if (add_cmd(cmd, node, H2O_HEADERS_CMD_UNSET, name, (h2o_iovec_t){NULL}, self->get_commands(self->child)) != 0) { - if (!h2o_iovec_is_token(name)) - free(name->base); - return -1; - } - return 0; -} - -#define DEFINE_2ARG(fn, cmd_id) \ - static int fn(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) \ - { \ - struct headers_util_configurator_t *self = (void *)cmd->configurator; \ - return on_config_header_2arg(cmd, ctx, cmd_id, node, self->get_commands(self->child)); \ - } - -DEFINE_2ARG(on_config_header_add, H2O_HEADERS_CMD_ADD) -DEFINE_2ARG(on_config_header_append, H2O_HEADERS_CMD_APPEND) -DEFINE_2ARG(on_config_header_merge, H2O_HEADERS_CMD_MERGE) -DEFINE_2ARG(on_config_header_set, H2O_HEADERS_CMD_SET) -DEFINE_2ARG(on_config_header_setifempty, H2O_HEADERS_CMD_SETIFEMPTY) - -#undef DEFINE_2ARG - -void h2o_configurator_define_headers_commands(h2o_globalconf_t *global_conf, h2o_configurator_t *conf, const char *prefix, - h2o_configurator_get_headers_commands_cb get_commands) -{ - struct headers_util_configurator_t *c = (void *)h2o_configurator_create(global_conf, sizeof(*c)); - c->child = conf; - c->get_commands = get_commands; - size_t prefix_len = strlen(prefix); - -#define DEFINE_CMD_NAME(name, suffix) \ - char *name = h2o_mem_alloc(prefix_len + sizeof(suffix)); \ - memcpy(name, prefix, prefix_len); \ - memcpy(name + prefix_len, suffix, sizeof(suffix)) - - DEFINE_CMD_NAME(add_directive, ".add"); - DEFINE_CMD_NAME(append_directive, ".append"); - DEFINE_CMD_NAME(merge_directive, ".merge"); - DEFINE_CMD_NAME(set_directive, ".set"); - DEFINE_CMD_NAME(setifempty_directive, ".setifempty"); - DEFINE_CMD_NAME(unset_directive, ".unset"); -#undef DEFINE_CMD_NAME - -#define DEFINE_CMD(name, cb) \ - h2o_configurator_define_command(&c->super, name, H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, cb) - DEFINE_CMD(add_directive, on_config_header_add); - DEFINE_CMD(append_directive, on_config_header_append); - DEFINE_CMD(merge_directive, on_config_header_merge); - DEFINE_CMD(set_directive, on_config_header_set); - DEFINE_CMD(setifempty_directive, on_config_header_setifempty); - DEFINE_CMD(unset_directive, on_config_header_unset); -#undef DEFINE_CMD -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/http2_debug_state.c b/web/server/h2o/libh2o/lib/handler/configurator/http2_debug_state.c deleted file mode 100644 index 419da9de8..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/http2_debug_state.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 "h2o.h" -#include "h2o/configurator.h" - -static int on_config_debug_state(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - switch (h2o_configurator_get_one_of(cmd, node, "minimum,hpack")) { - case 0: /* minimum */ - h2o_http2_debug_state_register(ctx->hostconf, 0); - return 0; - case 1: /* with hpack state*/ - h2o_http2_debug_state_register(ctx->hostconf, 1); - return 0; - default: /* error */ - return -1; - } -} - -void h2o_http2_debug_state_register_configurator(h2o_globalconf_t *conf) -{ - struct st_h2o_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - h2o_configurator_define_command(c, "http2-debug-state", H2O_CONFIGURATOR_FLAG_HOST | H2O_CONFIGURATOR_FLAG_DEFERRED | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_debug_state); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/mruby.c b/web/server/h2o/libh2o/lib/handler/configurator/mruby.c deleted file mode 100644 index 1cef8f499..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/mruby.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku, Ryosuke Matsumoto - * - * 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/configurator.h" -#include "h2o/mruby_.h" - -struct mruby_configurator_t { - h2o_configurator_t super; - h2o_mruby_config_vars_t *vars; - h2o_mruby_config_vars_t _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; - mrb_state *mrb; /* will be lazily initialized */ -}; - -static int compile_test(mrb_state *mrb, h2o_mruby_config_vars_t *config, char *errbuf) -{ - mrb_value result = h2o_mruby_compile_code(mrb, config, errbuf); - int ok = !mrb_nil_p(result); - return ok; -} - -static mrb_state *get_mrb(struct mruby_configurator_t *self) -{ - if (self->mrb == NULL) { - self->mrb = mrb_open(); - if (self->mrb == NULL) { - fprintf(stderr, "%s: no memory\n", H2O_MRUBY_MODULE_NAME); - abort(); - } - h2o_mruby_setup_globals(self->mrb); - } - return self->mrb; -} - -static int on_config_mruby_handler(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct mruby_configurator_t *self = (void *)cmd->configurator; - - /* set source */ - self->vars->source = h2o_strdup(NULL, node->data.scalar, SIZE_MAX); - self->vars->path = node->filename; - self->vars->lineno = (int)node->line + 1; - - /* check if there is any error in source */ - char errbuf[1024]; - if (!compile_test(get_mrb(self), self->vars, errbuf)) { - h2o_configurator_errprintf(cmd, node, "ruby compile error:%s", errbuf); - return -1; - } - - /* register */ - h2o_mruby_register(ctx->pathconf, self->vars); - - return 0; -} - -static int on_config_mruby_handler_file(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct mruby_configurator_t *self = (void *)cmd->configurator; - FILE *fp = NULL; - h2o_iovec_t buf = {NULL}; - int ret = -1; - - /* open and read file */ - if ((fp = fopen(node->data.scalar, "rt")) == NULL) { - h2o_configurator_errprintf(cmd, node, "failed to open file: %s:%s", node->data.scalar, strerror(errno)); - goto Exit; - } - while (!feof(fp)) { - buf.base = h2o_mem_realloc(buf.base, buf.len + 65536); - buf.len += fread(buf.base + buf.len, 1, 65536, fp); - if (ferror(fp)) { - h2o_configurator_errprintf(cmd, node, "I/O error occurred while reading file:%s:%s", node->data.scalar, - strerror(errno)); - goto Exit; - } - } - - /* set source */ - self->vars->source = buf; - buf.base = NULL; - self->vars->path = node->data.scalar; /* the value is retained until the end of the configuration phase */ - self->vars->lineno = 0; - - /* check if there is any error in source */ - char errbuf[1024]; - if (!compile_test(get_mrb(self), self->vars, errbuf)) { - h2o_configurator_errprintf(cmd, node, "failed to compile file:%s:%s", node->data.scalar, errbuf); - goto Exit; - } - - /* register */ - h2o_mruby_register(ctx->pathconf, self->vars); - - ret = 0; - -Exit: - if (fp != NULL) - fclose(fp); - if (buf.base != NULL) - free(buf.base); - return ret; -} - -static int on_config_mruby_handler_path(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - h2o_configurator_errprintf(cmd, node, "the command has been removed; see https://github.com/h2o/h2o/pull/467"); - return -1; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct mruby_configurator_t *self = (void *)_self; - - memcpy(self->vars + 1, self->vars, sizeof(*self->vars)); - ++self->vars; - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct mruby_configurator_t *self = (void *)_self; - - /* free if the to-be-exitted frame level contains a different source */ - if (self->vars[-1].source.base != self->vars[0].source.base) - free(self->vars->source.base); - - --self->vars; - - /* release mrb only when global configuration exited */ - if (self->mrb != NULL && ctx->parent == NULL) { - mrb_close(self->mrb); - self->mrb = NULL; - } - - return 0; -} - -void h2o_mruby_register_configurator(h2o_globalconf_t *conf) -{ - struct mruby_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - c->vars = c->_vars_stack; - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - - h2o_configurator_define_command(&c->super, "mruby.handler", H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_DEFERRED | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_mruby_handler); - h2o_configurator_define_command(&c->super, "mruby.handler-file", H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_DEFERRED | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_mruby_handler_file); - h2o_configurator_define_command(&c->super, "mruby.handler_path", H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_DEFERRED, - on_config_mruby_handler_path); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/proxy.c b/web/server/h2o/libh2o/lib/handler/configurator/proxy.c deleted file mode 100644 index cfc9cbf40..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/proxy.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include "h2o.h" -#include "h2o/configurator.h" - -struct proxy_configurator_t { - h2o_configurator_t super; - h2o_proxy_config_vars_t *vars; - h2o_proxy_config_vars_t _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config_timeout_io(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->io_timeout); -} - -static int on_config_timeout_keepalive(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->keepalive_timeout); -} - -static int on_config_preserve_host(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - self->vars->preserve_host = (int)ret; - return 0; -} - -static int on_config_proxy_protocol(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - self->vars->use_proxy_protocol = (int)ret; - return 0; -} - -static int on_config_websocket_timeout(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->websocket.timeout); -} - -static int on_config_websocket(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - self->vars->websocket.enabled = (int)ret; - return 0; -} - -static SSL_CTX *create_ssl_ctx(void) -{ - SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method()); - SSL_CTX_set_options(ctx, SSL_CTX_get_options(ctx) | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - return ctx; -} - -static h2o_cache_t *create_ssl_session_cache(size_t capacity, uint64_t duration) -{ - return h2o_cache_create(H2O_CACHE_FLAG_MULTITHREADED, capacity, duration, h2o_socket_ssl_destroy_session_cache_entry); -} - -static void update_ssl_ctx(SSL_CTX **ctx, X509_STORE *cert_store, int verify_mode, h2o_cache_t **session_cache) -{ - assert(*ctx != NULL); - - /* inherit the properties that weren't specified */ - if (cert_store == NULL) - cert_store = SSL_CTX_get_cert_store(*ctx); - X509_STORE_up_ref(cert_store); - if (verify_mode == -1) - verify_mode = SSL_CTX_get_verify_mode(*ctx); - h2o_cache_t *new_session_cache; - if (session_cache == NULL) { - h2o_cache_t *current = h2o_socket_ssl_get_session_cache(*ctx); - new_session_cache = - current == NULL ? NULL : create_ssl_session_cache(h2o_cache_get_capacity(current), h2o_cache_get_duration(current)); - } else { - new_session_cache = *session_cache; - } - - /* free the existing context */ - if (*ctx != NULL) - SSL_CTX_free(*ctx); - - /* create new ctx */ - *ctx = create_ssl_ctx(); - SSL_CTX_set_cert_store(*ctx, cert_store); - SSL_CTX_set_verify(*ctx, verify_mode, NULL); - if (new_session_cache != NULL) - h2o_socket_ssl_set_session_cache(*ctx, new_session_cache); -} - -static int on_config_ssl_verify_peer(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - - update_ssl_ctx(&self->vars->ssl_ctx, NULL, ret != 0 ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, - NULL); - - return 0; -} - -static int on_config_ssl_cafile(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - X509_STORE *store = X509_STORE_new(); - int ret = -1; - - if (X509_STORE_load_locations(store, node->data.scalar, NULL) == 1) { - update_ssl_ctx(&self->vars->ssl_ctx, store, -1, NULL); - ret = 0; - } else { - h2o_configurator_errprintf(cmd, node, "failed to load certificates file:%s", node->data.scalar); - ERR_print_errors_fp(stderr); - } - - X509_STORE_free(store); - return ret; -} - -static int on_config_ssl_session_cache(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - size_t capacity = 0; - uint64_t duration = 0; - h2o_cache_t *current_cache = h2o_socket_ssl_get_session_cache(self->vars->ssl_ctx); - - switch (node->type) { - case YOML_TYPE_SCALAR: - if (strcasecmp(node->data.scalar, "OFF") == 0) { - if (current_cache != NULL) { - /* set the cache NULL */ - h2o_cache_t *empty_cache = NULL; - update_ssl_ctx(&self->vars->ssl_ctx, NULL, -1, &empty_cache); - } - return 0; - } else if (strcasecmp(node->data.scalar, "ON") == 0) { - /* use default values */ - capacity = H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_CAPACITY; - duration = H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_DURATION; - } else { - h2o_configurator_errprintf(cmd, node, "scalar argument must be either of: `OFF`, `ON`"); - return -1; - } - break; - case YOML_TYPE_MAPPING: { - size_t i; - for (i = 0; i != node->data.mapping.size; ++i) { - yoml_t *key = node->data.mapping.elements[i].key; - yoml_t *value = node->data.mapping.elements[i].value; - if (key->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, key, "key must be a scalar"); - return -1; - } - if (strcasecmp(key->data.scalar, "capacity") == 0) { - if (h2o_configurator_scanf(cmd, value, "%zu", &capacity) != 0) - return -1; - if (capacity == 0) { - h2o_configurator_errprintf(cmd, key, "capacity must be greater than zero"); - return -1; - } - } else if (strcasecmp(key->data.scalar, "lifetime") == 0) { - unsigned lifetime = 0; - if (h2o_configurator_scanf(cmd, value, "%u", &lifetime) != 0) - return -1; - if (lifetime == 0) { - h2o_configurator_errprintf(cmd, key, "lifetime must be greater than zero"); - return -1; - } - duration = (uint64_t)lifetime * 1000; - } else { - h2o_configurator_errprintf(cmd, key, "key must be either of: `capacity`, `lifetime`"); - return -1; - } - } - if (capacity == 0 || duration == 0) { - h2o_configurator_errprintf(cmd, node, "`capacity` and `lifetime` are required"); - return -1; - } - } break; - default: - h2o_configurator_errprintf(cmd, node, "node must be a scalar or a mapping"); - return -1; - } - - if (current_cache != NULL) { - size_t current_capacity = h2o_cache_get_capacity(current_cache); - uint64_t current_duration = h2o_cache_get_duration(current_cache); - if (capacity == current_capacity && duration == current_duration) { - /* parameters aren't changed, so reuse it */ - return 0; - } - } - - h2o_cache_t *new_cache = create_ssl_session_cache(capacity, duration); - update_ssl_ctx(&self->vars->ssl_ctx, NULL, -1, &new_cache); - return 0; -} - -static int on_config_reverse_url(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)cmd->configurator; - h2o_url_t parsed; - - if (h2o_url_parse(node->data.scalar, SIZE_MAX, &parsed) != 0) { - h2o_configurator_errprintf(cmd, node, "failed to parse URL: %s\n", node->data.scalar); - return -1; - } - if (self->vars->keepalive_timeout != 0 && self->vars->use_proxy_protocol) { - h2o_configurator_errprintf(cmd, node, "please either set `proxy.use-proxy-protocol` to `OFF` or disable keep-alive by " - "setting `proxy.timeout.keepalive` to zero; the features are mutually exclusive"); - return -1; - } - - if (self->vars->headers_cmds != NULL) - h2o_mem_addref_shared(self->vars->headers_cmds); - - /* register */ - h2o_proxy_register_reverse_proxy(ctx->pathconf, &parsed, self->vars); - - return 0; -} - -static int on_config_emit_x_forwarded_headers(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - ctx->globalconf->proxy.emit_x_forwarded_headers = (int)ret; - return 0; -} - -static int on_config_emit_via_header(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - ctx->globalconf->proxy.emit_via_header = (int)ret; - return 0; -} - -static int on_config_preserve_x_forwarded_proto(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - ctx->globalconf->proxy.preserve_x_forwarded_proto = (int)ret; - return 0; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)_self; - - memcpy(self->vars + 1, self->vars, sizeof(*self->vars)); - if (self->vars[1].headers_cmds != NULL) - h2o_mem_addref_shared(self->vars[1].headers_cmds); - ++self->vars; - - if (ctx->pathconf == NULL && ctx->hostconf == NULL) { - /* is global conf, setup the default SSL context */ - self->vars->ssl_ctx = create_ssl_ctx(); - char *ca_bundle = h2o_configurator_get_cmd_path("share/h2o/ca-bundle.crt"); - if (SSL_CTX_load_verify_locations(self->vars->ssl_ctx, ca_bundle, NULL) != 1) - fprintf(stderr, "Warning: failed to load the default certificates file at %s. Proxying to HTTPS servers may fail.\n", - ca_bundle); - free(ca_bundle); - SSL_CTX_set_verify(self->vars->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); - h2o_cache_t *ssl_session_cache = - create_ssl_session_cache(H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_CAPACITY, H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_DURATION); - h2o_socket_ssl_set_session_cache(self->vars->ssl_ctx, ssl_session_cache); - } else { - SSL_CTX_up_ref(self->vars->ssl_ctx); - } - - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct proxy_configurator_t *self = (void *)_self; - - if (ctx->pathconf == NULL && ctx->hostconf == NULL) { - /* is global conf */ - ctx->globalconf->proxy.io_timeout = self->vars->io_timeout; - ctx->globalconf->proxy.ssl_ctx = self->vars->ssl_ctx; - } else { - SSL_CTX_free(self->vars->ssl_ctx); - } - - if (self->vars->headers_cmds != NULL) - h2o_mem_release_shared(self->vars->headers_cmds); - - --self->vars; - return 0; -} - -static h2o_headers_command_t **get_headers_commands(h2o_configurator_t *_self) -{ - struct proxy_configurator_t *self = (void *)_self; - return &self->vars->headers_cmds; -} - -void h2o_proxy_register_configurator(h2o_globalconf_t *conf) -{ - struct proxy_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - /* set default vars */ - c->vars = c->_vars_stack; - c->vars->io_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT; - c->vars->keepalive_timeout = 2000; - c->vars->websocket.enabled = 0; /* have websocket proxying disabled by default; until it becomes non-experimental */ - c->vars->websocket.timeout = H2O_DEFAULT_PROXY_WEBSOCKET_TIMEOUT; - - /* setup handlers */ - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - h2o_configurator_define_command( - &c->super, "proxy.reverse.url", - H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | H2O_CONFIGURATOR_FLAG_DEFERRED, on_config_reverse_url); - h2o_configurator_define_command(&c->super, "proxy.preserve-host", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_preserve_host); - h2o_configurator_define_command(&c->super, "proxy.proxy-protocol", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_proxy_protocol); - h2o_configurator_define_command(&c->super, "proxy.timeout.io", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_timeout_io); - h2o_configurator_define_command(&c->super, "proxy.timeout.keepalive", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_timeout_keepalive); - h2o_configurator_define_command(&c->super, "proxy.websocket", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_websocket); - h2o_configurator_define_command(&c->super, "proxy.websocket.timeout", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_websocket_timeout); - h2o_configurator_define_command(&c->super, "proxy.ssl.verify-peer", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_ssl_verify_peer); - h2o_configurator_define_command(&c->super, "proxy.ssl.cafile", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_ssl_cafile); - h2o_configurator_define_command(&c->super, "proxy.ssl.session-cache", H2O_CONFIGURATOR_FLAG_ALL_LEVELS, - on_config_ssl_session_cache); - h2o_configurator_define_command(&c->super, "proxy.preserve-x-forwarded-proto", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_preserve_x_forwarded_proto); - h2o_configurator_define_command(&c->super, "proxy.emit-x-forwarded-headers", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_emit_x_forwarded_headers); - h2o_configurator_define_command(&c->super, "proxy.emit-via-header", - H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_emit_via_header); - h2o_configurator_define_headers_commands(conf, &c->super, "proxy.header", get_headers_commands); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/redirect.c b/web/server/h2o/libh2o/lib/handler/configurator/redirect.c deleted file mode 100644 index 4ebbb99c0..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/redirect.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 "h2o.h" -#include "h2o/configurator.h" - -static int on_config(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - const char *dest; - int status = 302; /* default is temporary redirect */ - int internal = 0; /* default is external redirect */ - yoml_t *t; - - switch (node->type) { - case YOML_TYPE_SCALAR: - dest = node->data.scalar; - break; - case YOML_TYPE_MAPPING: - if ((t = yoml_get(node, "url")) == NULL) { - h2o_configurator_errprintf(cmd, node, "mandatory property `url` is missing"); - return -1; - } - if (t->type != YOML_TYPE_SCALAR) { - h2o_configurator_errprintf(cmd, t, "property `url` must be a string"); - return -1; - } - dest = t->data.scalar; - if ((t = yoml_get(node, "status")) == NULL) { - h2o_configurator_errprintf(cmd, node, "mandatory property `status` is missing"); - return -1; - } - if (h2o_configurator_scanf(cmd, t, "%d", &status) != 0) - return -1; - if (!(300 <= status && status <= 399)) { - h2o_configurator_errprintf(cmd, t, "value of property `status` should be within 300 to 399"); - return -1; - } - if ((t = yoml_get(node, "internal")) != NULL) { - if ((internal = (int)h2o_configurator_get_one_of(cmd, t, "NO,YES")) == -1) - return -1; - } - break; - default: - h2o_configurator_errprintf(cmd, node, "value must be a string or a mapping"); - return -1; - } - - h2o_redirect_register(ctx->pathconf, internal, status, dest); - - return 0; -} - -void h2o_redirect_register_configurator(h2o_globalconf_t *conf) -{ - h2o_configurator_t *c = h2o_configurator_create(conf, sizeof(*c)); - - h2o_configurator_define_command(c, "redirect", H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_DEFERRED, on_config); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/reproxy.c b/web/server/h2o/libh2o/lib/handler/configurator/reproxy.c deleted file mode 100644 index 21650e4fb..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/reproxy.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015 Daisuke Maki, 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 "h2o.h" -#include "h2o/configurator.h" - -struct config_t { - int enabled; -}; - -struct reproxy_configurator_t { - h2o_configurator_t super; - struct config_t *vars, _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config_reproxy(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct reproxy_configurator_t *self = (void *)cmd->configurator; - - ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); - if (ret == -1) - return -1; - self->vars->enabled = (int)ret; - - return 0; -} - -static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct reproxy_configurator_t *self = (void *)_self; - - self->vars[1] = self->vars[0]; - ++self->vars; - return 0; -} - -static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct reproxy_configurator_t *self = (void *)_self; - - if (ctx->pathconf != NULL && self->vars->enabled != 0) - h2o_reproxy_register(ctx->pathconf); - - --self->vars; - return 0; -} - -void h2o_reproxy_register_configurator(h2o_globalconf_t *conf) -{ - struct reproxy_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - /* set default vars */ - c->vars = c->_vars_stack; - - /* setup handlers */ - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - - /* reproxy: ON | OFF */ - h2o_configurator_define_command(&c->super, "reproxy", H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_reproxy); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/status.c b/web/server/h2o/libh2o/lib/handler/configurator/status.c deleted file mode 100644 index 8645aa33d..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/status.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 "h2o.h" -#include "h2o/configurator.h" - -static int on_config_status(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - switch (h2o_configurator_get_one_of(cmd, node, "OFF,ON")) { - case 0: /* OFF */ - return 0; - case 1: /* ON */ - h2o_status_register(ctx->pathconf); - return 0; - default: /* error */ - return -1; - } -} - -struct st_status_configurator { - h2o_configurator_t super; - int stack; - int duration_stats; -}; - -static int on_config_duration_stats(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_status_configurator *c = (void *)cmd->configurator; - ssize_t ret; - switch (ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON")) { - case 0: /* OFF */ - case 1: /* ON */ - c->duration_stats = (int)ret; - return 0; - default: /* error */ - return -1; - } -} - -int on_enter_status(h2o_configurator_t *_conf, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_status_configurator *c = (void *)_conf; - c->stack++; - return 0; -} - -int on_exit_status(h2o_configurator_t *_conf, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct st_status_configurator *c = (void *)_conf; - c->stack--; - if (!c->stack && c->duration_stats) { - h2o_duration_stats_register(ctx->globalconf); - } - return 0; -} - -void h2o_status_register_configurator(h2o_globalconf_t *conf) -{ - struct st_status_configurator *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - c->super.enter = on_enter_status; - c->super.exit = on_exit_status; - - h2o_configurator_define_command(&c->super, "status", H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_DEFERRED | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_status); - - h2o_configurator_define_command(&c->super, "duration-stats", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_duration_stats); -} diff --git a/web/server/h2o/libh2o/lib/handler/configurator/throttle_resp.c b/web/server/h2o/libh2o/lib/handler/configurator/throttle_resp.c deleted file mode 100644 index 61431f756..000000000 --- a/web/server/h2o/libh2o/lib/handler/configurator/throttle_resp.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2016 Justin Zhu - * - * 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/configurator.h" - -struct throttle_resp_config_vars_t { - int on; -}; - -struct throttle_resp_configurator_t { - h2o_configurator_t super; - struct throttle_resp_config_vars_t *vars, _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; -}; - -static int on_config_throttle_resp(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct throttle_resp_configurator_t *self = (void *)cmd->configurator; - - if ((self->vars->on = (int)h2o_configurator_get_one_of(cmd, node, "OFF,ON")) == -1) - return -1; - return 0; -} - -static int on_config_enter(h2o_configurator_t *configurator, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct throttle_resp_configurator_t *self = (void *)configurator; - - ++self->vars; - self->vars[0] = self->vars[-1]; - return 0; -} - -static int on_config_exit(h2o_configurator_t *configurator, h2o_configurator_context_t *ctx, yoml_t *node) -{ - struct throttle_resp_configurator_t *self = (void *)configurator; - - if (ctx->pathconf != NULL && self->vars->on) - h2o_throttle_resp_register(ctx->pathconf); - - --self->vars; - return 0; -} - -void h2o_throttle_resp_register_configurator(h2o_globalconf_t *conf) -{ - struct throttle_resp_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); - - c->super.enter = on_config_enter; - c->super.exit = on_config_exit; - h2o_configurator_define_command(&c->super, "throttle-response", - H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, - on_config_throttle_resp); - c->vars = c->_vars_stack; -} diff --git a/web/server/h2o/libh2o/lib/handler/errordoc.c b/web/server/h2o/libh2o/lib/handler/errordoc.c deleted file mode 100644 index 72744f358..000000000 --- a/web/server/h2o/libh2o/lib/handler/errordoc.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 "h2o.h" - -/* used to rewrite status code to the original code */ -struct st_errordoc_prefilter_t { - h2o_req_prefilter_t super; - h2o_headers_t req_headers; - int status; - const char *reason; - h2o_headers_t res_headers; -}; - -/* used to capture an error response */ -struct st_errordoc_filter_t { - h2o_filter_t super; - H2O_VECTOR(h2o_errordoc_t) errordocs; -}; - -static void add_header(h2o_mem_pool_t *pool, h2o_headers_t *headers, const h2o_header_t *header) -{ - h2o_vector_reserve(pool, headers, headers->size + 1); - headers->entries[headers->size++] = *header; -} - -static void on_prefilter_setup_stream(h2o_req_prefilter_t *_self, h2o_req_t *req, h2o_ostream_t **slot) -{ - struct st_errordoc_prefilter_t *self = (void *)_self; - h2o_headers_t headers_merged = {NULL}; - size_t i; - - /* restore request headers (for logging) and response status */ - req->headers = self->req_headers; - req->res.status = self->status; - req->res.reason = self->reason; - - /* generate response headers (by merging the preserved and given) */ - for (i = 0; i != self->res_headers.size; ++i) - add_header(&req->pool, &headers_merged, self->res_headers.entries + i); - for (i = 0; i != req->res.headers.size; ++i) { - const h2o_header_t *header = req->res.headers.entries + i; - if (header->name == &H2O_TOKEN_CONTENT_TYPE->buf || header->name == &H2O_TOKEN_CONTENT_LANGUAGE->buf || - header->name == &H2O_TOKEN_SET_COOKIE->buf) - add_header(&req->pool, &headers_merged, header); - } - req->res.headers = headers_merged; - - h2o_setup_next_prefilter(&self->super, req, slot); -} - -static void on_ostream_send(h2o_ostream_t *self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state) -{ - /* nothing to do */ -} - -static int prefilter_is_registered(h2o_req_t *req) -{ - h2o_req_prefilter_t *prefilter; - for (prefilter = req->prefilters; prefilter != NULL; prefilter = prefilter->next) - if (prefilter->on_setup_ostream == on_prefilter_setup_stream) - return 1; - return 0; -} - -static void on_filter_setup_ostream(h2o_filter_t *_self, h2o_req_t *req, h2o_ostream_t **slot) -{ - struct st_errordoc_filter_t *self = (void *)_self; - h2o_errordoc_t *errordoc; - struct st_errordoc_prefilter_t *prefilter; - h2o_iovec_t method; - h2o_ostream_t *ostream; - size_t i; - - if (req->res.status >= 400 && !prefilter_is_registered(req)) { - size_t i; - for (i = 0; i != self->errordocs.size; ++i) { - errordoc = self->errordocs.entries + i; - if (errordoc->status == req->res.status) - goto Found; - } - } - - /* bypass to the next filter */ - h2o_setup_next_ostream(req, slot); - return; - -Found: - /* register prefilter that rewrites the status code after the internal redirect is processed */ - prefilter = (void *)h2o_add_prefilter(req, sizeof(*prefilter)); - prefilter->super.on_setup_ostream = on_prefilter_setup_stream; - prefilter->req_headers = req->headers; - prefilter->status = req->res.status; - prefilter->reason = req->res.reason; - prefilter->res_headers = (h2o_headers_t){NULL}; - for (i = 0; i != req->res.headers.size; ++i) { - const h2o_header_t *header = req->res.headers.entries + i; - if (!(header->name == &H2O_TOKEN_CONTENT_TYPE->buf || header->name == &H2O_TOKEN_CONTENT_LANGUAGE->buf)) - add_header(&req->pool, &prefilter->res_headers, header); - } - /* redirect internally to the error document */ - method = req->method; - if (h2o_memis(method.base, method.len, H2O_STRLIT("POST"))) - method = h2o_iovec_init(H2O_STRLIT("GET")); - req->headers = (h2o_headers_t){NULL}; - req->res.headers = (h2o_headers_t){NULL}; - h2o_send_redirect_internal(req, method, errordoc->url.base, errordoc->url.len, 0); - /* create fake ostream that swallows the contents emitted by the generator */ - ostream = h2o_add_ostream(req, sizeof(*ostream), slot); - ostream->do_send = on_ostream_send; -} - -void h2o_errordoc_register(h2o_pathconf_t *pathconf, h2o_errordoc_t *errdocs, size_t cnt) -{ - struct st_errordoc_filter_t *self = (void *)h2o_create_filter(pathconf, sizeof(*self)); - size_t i; - - self->super.on_setup_ostream = on_filter_setup_ostream; - h2o_vector_reserve(NULL, &self->errordocs, cnt); - self->errordocs.size = cnt; - for (i = 0; i != cnt; ++i) { - const h2o_errordoc_t *src = errdocs + i; - h2o_errordoc_t *dst = self->errordocs.entries + i; - dst->status = src->status; - dst->url = h2o_strdup(NULL, src->url.base, src->url.len); - } -} diff --git a/web/server/h2o/libh2o/lib/handler/expires.c b/web/server/h2o/libh2o/lib/handler/expires.c deleted file mode 100644 index c77225649..000000000 --- a/web/server/h2o/libh2o/lib/handler/expires.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 -#include -#include -#include -#include "h2o.h" - -struct st_expires_t { - h2o_filter_t super; - int mode; - h2o_iovec_t value; -}; - -static void on_setup_ostream(h2o_filter_t *_self, h2o_req_t *req, h2o_ostream_t **slot) -{ - struct st_expires_t *self = (void *)_self; - - switch (req->res.status) { - case 200: - case 201: - case 204: - case 206: - case 301: - case 302: - case 303: - case 304: - case 307: - switch (self->mode) { - case H2O_EXPIRES_MODE_ABSOLUTE: - h2o_set_header(&req->pool, &req->res.headers, H2O_TOKEN_EXPIRES, self->value.base, self->value.len, 0); - break; - case H2O_EXPIRES_MODE_MAX_AGE: - h2o_set_header_token(&req->pool, &req->res.headers, H2O_TOKEN_CACHE_CONTROL, self->value.base, self->value.len); - break; - default: - assert(0); - break; - } - break; - default: - break; - } - - h2o_setup_next_ostream(req, slot); -} - -void h2o_expires_register(h2o_pathconf_t *pathconf, h2o_expires_args_t *args) -{ - struct st_expires_t *self = (void *)h2o_create_filter(pathconf, sizeof(*self)); - self->super.on_setup_ostream = on_setup_ostream; - self->mode = args->mode; - switch (args->mode) { - case H2O_EXPIRES_MODE_ABSOLUTE: - self->value = h2o_strdup(NULL, args->data.absolute, SIZE_MAX); - break; - case H2O_EXPIRES_MODE_MAX_AGE: - self->value.base = h2o_mem_alloc(128); - self->value.len = sprintf(self->value.base, "max-age=%" PRIu64, args->data.max_age); - break; - default: - assert(0); - break; - } -} diff --git a/web/server/h2o/libh2o/lib/handler/fastcgi.c b/web/server/h2o/libh2o/lib/handler/fastcgi.c deleted file mode 100644 index d6bcf9ede..000000000 --- a/web/server/h2o/libh2o/lib/handler/fastcgi.c +++ /dev/null @@ -1,856 +0,0 @@ -/* - * Copyright (c) 2015-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 "picohttpparser.h" -#include "h2o.h" - -#define FCGI_VERSION_1 1 - -#define FCGI_RESPONDER 1 -#define FCGI_KEEP_CONN 1 - -#define FCGI_BEGIN_REQUEST 1 -#define FCGI_END_REQUEST 3 -#define FCGI_PARAMS 4 -#define FCGI_STDIN 5 -#define FCGI_STDOUT 6 -#define FCGI_STDERR 7 -#define FCGI_DATA 8 - -#define FCGI_RECORD_HEADER_SIZE (sizeof(struct st_fcgi_record_header_t)) -#define FCGI_BEGIN_REQUEST_BODY_SIZE 8 - -#define MODULE_NAME "lib/handler/fastcgi.c" - -#define APPEND_BLOCKSIZE 512 /* the size should be small enough to be allocated within the buffer of the memory pool */ - -struct st_fcgi_record_header_t { - uint8_t version; - uint8_t type; - uint16_t requestId; - uint16_t contentLength; - uint8_t paddingLength; - uint8_t reserved; -}; - -struct st_fcgi_begin_request_body_t { - uint16_t role; - uint8_t flags; - uint8_t reserved[5]; -}; - -typedef H2O_VECTOR(h2o_iovec_t) iovec_vector_t; - -struct st_fcgi_context_t { - h2o_fastcgi_handler_t *handler; - h2o_timeout_t io_timeout; -}; - -struct st_fcgi_generator_t { - h2o_generator_t super; - struct st_fcgi_context_t *ctx; - h2o_req_t *req; - h2o_socketpool_connect_request_t *connect_req; - h2o_socket_t *sock; - int sent_headers; - size_t leftsize; /* remaining amount of the content to receive (or SIZE_MAX if unknown) */ - struct { - h2o_doublebuffer_t sending; - h2o_buffer_t *receiving; - } resp; - h2o_timeout_entry_t timeout; -}; - -struct st_h2o_fastcgi_handler_t { - h2o_handler_t super; - h2o_socketpool_t sockpool; - h2o_fastcgi_config_vars_t config; -}; - -static void encode_uint16(void *_p, unsigned v) -{ - unsigned char *p = _p; - p[0] = (unsigned char)(v >> 8); - p[1] = (unsigned char)v; -} - -static void encode_record_header(void *p, uint8_t type, uint16_t reqId, uint16_t sz) -{ - struct st_fcgi_record_header_t *header = p; - header->version = FCGI_VERSION_1; - header->type = type; - encode_uint16(&header->requestId, reqId); - encode_uint16(&header->contentLength, sz); - header->paddingLength = 0; - header->reserved = 0; -} - -static void encode_begin_request(void *p, uint16_t reqId, uint16_t role, uint8_t flags) -{ - encode_record_header(p, FCGI_BEGIN_REQUEST, reqId, FCGI_BEGIN_REQUEST_BODY_SIZE); - struct st_fcgi_begin_request_body_t *body = (void *)((char *)p + FCGI_RECORD_HEADER_SIZE); - encode_uint16(&body->role, role); - body->flags = flags; - memset(body->reserved, 0, sizeof(body->reserved)); -} - -static h2o_iovec_t create_begin_request(h2o_mem_pool_t *pool, uint16_t reqId, uint16_t role, uint8_t flags) -{ - h2o_iovec_t rec = h2o_iovec_init(h2o_mem_alloc_pool(pool, FCGI_RECORD_HEADER_SIZE + FCGI_BEGIN_REQUEST_BODY_SIZE), - FCGI_RECORD_HEADER_SIZE + FCGI_BEGIN_REQUEST_BODY_SIZE); - encode_begin_request(rec.base, reqId, role, flags); - return rec; -} - -static h2o_iovec_t create_header(h2o_mem_pool_t *pool, uint8_t type, uint16_t reqId, uint16_t sz) -{ - h2o_iovec_t rec = h2o_iovec_init(h2o_mem_alloc_pool(pool, FCGI_RECORD_HEADER_SIZE), FCGI_RECORD_HEADER_SIZE); - encode_record_header(rec.base, type, reqId, sz); - return rec; -} - -static void decode_header(struct st_fcgi_record_header_t *decoded, const void *s) -{ - memcpy(decoded, s, sizeof(*decoded)); - decoded->requestId = htons(decoded->requestId); - decoded->contentLength = htons(decoded->contentLength); -} - -static void *append(h2o_mem_pool_t *pool, iovec_vector_t *blocks, const void *s, size_t len) -{ - h2o_iovec_t *slot; - - if (blocks->entries[blocks->size - 1].len + len > APPEND_BLOCKSIZE) { - h2o_vector_reserve(pool, blocks, blocks->size + 1); - slot = blocks->entries + blocks->size++; - slot->base = h2o_mem_alloc_pool(pool, len < APPEND_BLOCKSIZE ? APPEND_BLOCKSIZE : len); - slot->len = 0; - } else { - slot = blocks->entries + blocks->size - 1; - } - - if (s != NULL) - memcpy(slot->base + slot->len, s, len); - slot->len += len; - - return slot->base + slot->len - len; -} - -static char *encode_length_of_pair(char *p, size_t len) -{ - if (len < 127) { - *p++ = (char)len; - } else { - *p++ = (unsigned char)(len >> 24) | 0x80; - *p++ = (unsigned char)(len >> 16); - *p++ = (unsigned char)(len >> 8); - *p++ = (unsigned char)len; - } - return p; -} - -static void *append_pair(h2o_mem_pool_t *pool, iovec_vector_t *blocks, const char *name, size_t namelen, const char *value, - size_t valuelen) -{ - char lenbuf[8]; - void *name_buf; - - append(pool, blocks, lenbuf, encode_length_of_pair(encode_length_of_pair(lenbuf, namelen), valuelen) - lenbuf); - name_buf = append(pool, blocks, name, namelen); - if (valuelen != 0) - append(pool, blocks, value, valuelen); - - return name_buf; -} - -static void append_address_info(h2o_req_t *req, iovec_vector_t *vecs, const char *addrlabel, size_t addrlabel_len, - const char *portlabel, size_t portlabel_len, socklen_t (*cb)(h2o_conn_t *conn, struct sockaddr *)) -{ - struct sockaddr_storage ss; - socklen_t sslen; - char buf[NI_MAXHOST]; - - if ((sslen = cb(req->conn, (void *)&ss)) == 0) - return; - - size_t l = h2o_socket_getnumerichost((void *)&ss, sslen, buf); - if (l != SIZE_MAX) - append_pair(&req->pool, vecs, addrlabel, addrlabel_len, buf, l); - int32_t port = h2o_socket_getport((void *)&ss); - if (port != -1) { - char buf[6]; - int l = sprintf(buf, "%" PRIu16, (uint16_t)port); - append_pair(&req->pool, vecs, portlabel, portlabel_len, buf, (size_t)l); - } -} - -static int envname_is_headername(const h2o_iovec_t *env, const h2o_iovec_t *header) -{ - const char *ep, *hp, *hend; - - if (env->len != 5 + header->len) - return 0; - if (memcmp(env->base, "HTTP_", 5) != 0) - return 0; - for (ep = env->base + 5, hp = header->base, hend = hp + header->len; hp < hend; ++ep, ++hp) - if (*ep != h2o_toupper(*hp)) - return 0; - return 1; -} - -static void append_params(h2o_req_t *req, iovec_vector_t *vecs, h2o_fastcgi_config_vars_t *config) -{ - h2o_iovec_t path_info = {NULL}; - - /* CONTENT_LENGTH */ - if (req->entity.base != NULL) { - char buf[32]; - int l = sprintf(buf, "%zu", req->entity.len); - append_pair(&req->pool, vecs, H2O_STRLIT("CONTENT_LENGTH"), buf, (size_t)l); - } - /* SCRIPT_FILENAME, SCRIPT_NAME, PATH_INFO */ - if (req->filereq != NULL) { - h2o_filereq_t *filereq = req->filereq; - append_pair(&req->pool, vecs, H2O_STRLIT("SCRIPT_FILENAME"), filereq->local_path.base, filereq->local_path.len); - append_pair(&req->pool, vecs, H2O_STRLIT("SCRIPT_NAME"), filereq->script_name.base, filereq->script_name.len); - path_info = filereq->path_info; - } else { - append_pair(&req->pool, vecs, H2O_STRLIT("SCRIPT_NAME"), NULL, 0); - path_info = req->path_normalized; - } - if (path_info.base != NULL) - append_pair(&req->pool, vecs, H2O_STRLIT("PATH_INFO"), path_info.base, path_info.len); - /* DOCUMENT_ROOT and PATH_TRANSLATED */ - if (config->document_root.base != NULL) { - append_pair(&req->pool, vecs, H2O_STRLIT("DOCUMENT_ROOT"), config->document_root.base, config->document_root.len); - if (path_info.base != NULL) { - append_pair(&req->pool, vecs, H2O_STRLIT("PATH_TRANSLATED"), NULL, config->document_root.len + path_info.len); - char *dst_end = vecs->entries[vecs->size - 1].base + vecs->entries[vecs->size - 1].len; - memcpy(dst_end - path_info.len, path_info.base, path_info.len); - memcpy(dst_end - path_info.len - config->document_root.len, config->document_root.base, config->document_root.len); - } - } - /* QUERY_STRING (and adjust PATH_INFO) */ - if (req->query_at != SIZE_MAX) { - append_pair(&req->pool, vecs, H2O_STRLIT("QUERY_STRING"), req->path.base + req->query_at + 1, - req->path.len - (req->query_at + 1)); - } else { - append_pair(&req->pool, vecs, H2O_STRLIT("QUERY_STRING"), NULL, 0); - } - /* REMOTE_ADDR & REMOTE_PORT */ - append_address_info(req, vecs, H2O_STRLIT("REMOTE_ADDR"), H2O_STRLIT("REMOTE_PORT"), req->conn->callbacks->get_peername); - { /* environment variables (REMOTE_USER, etc.) */ - size_t i; - for (i = 0; i != req->env.size; i += 2) { - h2o_iovec_t *name = req->env.entries + i, *value = name + 1; - append_pair(&req->pool, vecs, name->base, name->len, value->base, value->len); - } - } - /* REQUEST_METHOD */ - append_pair(&req->pool, vecs, H2O_STRLIT("REQUEST_METHOD"), req->method.base, req->method.len); - /* HTTP_HOST & REQUEST_URI */ - if (config->send_delegated_uri) { - append_pair(&req->pool, vecs, H2O_STRLIT("HTTP_HOST"), req->authority.base, req->authority.len); - append_pair(&req->pool, vecs, H2O_STRLIT("REQUEST_URI"), req->path.base, req->path.len); - } else { - append_pair(&req->pool, vecs, H2O_STRLIT("HTTP_HOST"), req->input.authority.base, req->input.authority.len); - append_pair(&req->pool, vecs, H2O_STRLIT("REQUEST_URI"), req->input.path.base, req->input.path.len); - } - /* SERVER_ADDR & SERVER_PORT */ - append_address_info(req, vecs, H2O_STRLIT("SERVER_ADDR"), H2O_STRLIT("SERVER_PORT"), req->conn->callbacks->get_sockname); - /* SERVER_NAME */ - append_pair(&req->pool, vecs, H2O_STRLIT("SERVER_NAME"), req->hostconf->authority.host.base, req->hostconf->authority.host.len); - { /* SERVER_PROTOCOL */ - char buf[sizeof("HTTP/1.1")]; - size_t l = h2o_stringify_protocol_version(buf, req->version); - append_pair(&req->pool, vecs, H2O_STRLIT("SERVER_PROTOCOL"), buf, l); - } - /* SERVER_SOFTWARE */ - append_pair(&req->pool, vecs, H2O_STRLIT("SERVER_SOFTWARE"), req->conn->ctx->globalconf->server_name.base, - req->conn->ctx->globalconf->server_name.len); - /* set HTTPS: on if necessary */ - if (req->scheme == &H2O_URL_SCHEME_HTTPS) - append_pair(&req->pool, vecs, H2O_STRLIT("HTTPS"), H2O_STRLIT("on")); - { /* headers */ - const h2o_header_t *h = req->headers.entries, *h_end = h + req->headers.size; - size_t cookie_length = 0; - for (; h != h_end; ++h) { - if (h->name == &H2O_TOKEN_CONTENT_TYPE->buf) { - append_pair(&req->pool, vecs, H2O_STRLIT("CONTENT_TYPE"), h->value.base, h->value.len); - } else if (h->name == &H2O_TOKEN_COOKIE->buf) { - /* accumulate the length of the cookie, together with the separator */ - cookie_length += h->value.len + 1; - } else { - size_t i; - for (i = 0; i != req->env.size; i += 2) { - h2o_iovec_t *envname = req->env.entries + i; - if (envname_is_headername(envname, h->name)) - goto NextHeader; - } - char *dst = append_pair(&req->pool, vecs, NULL, h->name->len + sizeof("HTTP_") - 1, h->value.base, h->value.len); - const char *src = h->name->base, *src_end = src + h->name->len; - *dst++ = 'H'; - *dst++ = 'T'; - *dst++ = 'T'; - *dst++ = 'P'; - *dst++ = '_'; - for (; src != src_end; ++src) - *dst++ = *src == '-' ? '_' : h2o_toupper(*src); - } - NextHeader:; - } - if (cookie_length != 0) { - /* emit the cookie merged */ - cookie_length -= 1; - append_pair(&req->pool, vecs, H2O_STRLIT("HTTP_COOKIE"), NULL, cookie_length); - char *dst = vecs->entries[vecs->size - 1].base + vecs->entries[vecs->size - 1].len - cookie_length; - for (h = req->headers.entries;; ++h) { - if (h->name == &H2O_TOKEN_COOKIE->buf) { - if (cookie_length == h->value.len) - break; - memcpy(dst, h->value.base, h->value.len); - dst += h->value.len; - *dst++ = ';'; - cookie_length -= h->value.len + 1; - } - } - memcpy(dst, h->value.base, h->value.len); - } - } -} - -static void annotate_params(h2o_mem_pool_t *pool, iovec_vector_t *vecs, unsigned request_id, size_t max_record_size) -{ - size_t index = 2, recsize = 0, header_slot = 1; - - while (index != vecs->size) { - if (recsize + vecs->entries[index].len < max_record_size) { - recsize += vecs->entries[index].len; - ++index; - } else { - vecs->entries[header_slot] = create_header(pool, FCGI_PARAMS, request_id, max_record_size); - if (recsize + vecs->entries[index].len == max_record_size) { - h2o_vector_reserve(pool, vecs, vecs->size + 1); - memmove(vecs->entries + index + 2, vecs->entries + index + 1, - (vecs->size - (index + 1)) * sizeof(vecs->entries[0])); - ++vecs->size; - } else { - h2o_vector_reserve(pool, vecs, vecs->size + 2); - memmove(vecs->entries + index + 2, vecs->entries + index, (vecs->size - index) * sizeof(vecs->entries[0])); - vecs->size += 2; - size_t lastsz = max_record_size - recsize; - vecs->entries[index].len = lastsz; - vecs->entries[index + 2].base += lastsz; - vecs->entries[index + 2].len -= lastsz; - } - header_slot = index + 1; - index += 2; - recsize = 0; - } - } - - vecs->entries[header_slot] = create_header(pool, FCGI_PARAMS, request_id, recsize); - if (recsize != 0) { - h2o_vector_reserve(pool, vecs, vecs->size + 1); - vecs->entries[vecs->size++] = create_header(pool, FCGI_PARAMS, request_id, 0); - } -} - -static void build_request(h2o_req_t *req, iovec_vector_t *vecs, unsigned request_id, size_t max_record_size, - h2o_fastcgi_config_vars_t *config) -{ - *vecs = (iovec_vector_t){NULL}; - - /* first entry is FCGI_BEGIN_REQUEST */ - h2o_vector_reserve(&req->pool, vecs, 5 /* we send at least 5 iovecs */); - vecs->entries[0] = - create_begin_request(&req->pool, request_id, FCGI_RESPONDER, config->keepalive_timeout != 0 ? FCGI_KEEP_CONN : 0); - /* second entry is reserved for FCGI_PARAMS header */ - vecs->entries[1] = h2o_iovec_init(NULL, APPEND_BLOCKSIZE); /* dummy value set to prevent params being appended to the entry */ - vecs->size = 2; - /* accumulate the params data, and annotate them with FCGI_PARAM headers */ - append_params(req, vecs, config); - annotate_params(&req->pool, vecs, request_id, max_record_size); - /* setup FCGI_STDIN headers */ - if (req->entity.len != 0) { - size_t off = 0; - for (; off + max_record_size < req->entity.len; off += max_record_size) { - h2o_vector_reserve(&req->pool, vecs, vecs->size + 2); - vecs->entries[vecs->size++] = create_header(&req->pool, FCGI_STDIN, request_id, max_record_size); - vecs->entries[vecs->size++] = h2o_iovec_init(req->entity.base + off, max_record_size); - } - if (off != req->entity.len) { - h2o_vector_reserve(&req->pool, vecs, vecs->size + 2); - vecs->entries[vecs->size++] = create_header(&req->pool, FCGI_STDIN, request_id, req->entity.len - off); - vecs->entries[vecs->size++] = h2o_iovec_init(req->entity.base + off, req->entity.len - off); - } - } - h2o_vector_reserve(&req->pool, vecs, vecs->size + 1); - vecs->entries[vecs->size++] = create_header(&req->pool, FCGI_STDIN, request_id, 0); -} - -static void set_timeout(struct st_fcgi_generator_t *generator, h2o_timeout_t *timeout, h2o_timeout_cb cb) -{ - if (h2o_timeout_is_linked(&generator->timeout)) - h2o_timeout_unlink(&generator->timeout); - - generator->timeout.cb = cb; - h2o_timeout_link(generator->req->conn->ctx->loop, timeout, &generator->timeout); -} - -static void close_generator(struct st_fcgi_generator_t *generator) -{ - /* can be called more than once */ - - if (h2o_timeout_is_linked(&generator->timeout)) - h2o_timeout_unlink(&generator->timeout); - if (generator->connect_req != NULL) { - h2o_socketpool_cancel_connect(generator->connect_req); - generator->connect_req = NULL; - } - if (generator->sock != NULL) { - h2o_socket_close(generator->sock); - generator->sock = NULL; - } - if (generator->resp.sending.buf != NULL) - h2o_doublebuffer_dispose(&generator->resp.sending); - if (generator->resp.receiving != NULL) - h2o_buffer_dispose(&generator->resp.receiving); -} - -static void do_send(struct st_fcgi_generator_t *generator) -{ - h2o_iovec_t vecs[1]; - size_t veccnt; - int is_final; - - vecs[0] = h2o_doublebuffer_prepare(&generator->resp.sending, &generator->resp.receiving, generator->req->preferred_chunk_size); - veccnt = vecs[0].len != 0 ? 1 : 0; - if (generator->sock == NULL && vecs[0].len == generator->resp.sending.buf->size && generator->resp.receiving->size == 0) { - is_final = 1; - if (!(generator->leftsize == 0 || generator->leftsize == SIZE_MAX)) - generator->req->http1_is_persistent = 0; - } else { - if (veccnt == 0) - return; - is_final = 0; - } - h2o_send(generator->req, vecs, veccnt, is_final ? H2O_SEND_STATE_FINAL : H2O_SEND_STATE_IN_PROGRESS); -} - -static void send_eos_and_close(struct st_fcgi_generator_t *generator, int can_keepalive) -{ - if (generator->ctx->handler->config.keepalive_timeout != 0 && can_keepalive) - h2o_socketpool_return(&generator->ctx->handler->sockpool, generator->sock); - else - h2o_socket_close(generator->sock); - generator->sock = NULL; - - if (h2o_timeout_is_linked(&generator->timeout)) - h2o_timeout_unlink(&generator->timeout); - - if (generator->resp.sending.bytes_inflight == 0) - do_send(generator); -} - -static void errorclose(struct st_fcgi_generator_t *generator) -{ - if (generator->sent_headers) { - send_eos_and_close(generator, 0); - } else { - h2o_req_t *req = generator->req; - close_generator(generator); - h2o_send_error_503(req, "Internal Server Error", "Internal Server Error", 0); - } -} - -static int _isdigit(int ch) -{ - return '0' <= ch && ch <= '9'; -} - -static int fill_headers(h2o_req_t *req, struct phr_header *headers, size_t num_headers) -{ - size_t i; - - /* set the defaults */ - req->res.status = 200; - req->res.reason = "OK"; - req->res.content_length = SIZE_MAX; - - for (i = 0; i != num_headers; ++i) { - const h2o_token_t *token; - h2o_strtolower((char *)headers[i].name, headers[i].name_len); - if ((token = h2o_lookup_token(headers[i].name, headers[i].name_len)) != NULL) { - if (token->proxy_should_drop_for_res) { - /* skip */ - } else if (token == H2O_TOKEN_CONTENT_LENGTH) { - if (req->res.content_length != SIZE_MAX) { - h2o_req_log_error(req, MODULE_NAME, "received multiple content-length headers from fcgi"); - return -1; - } - if ((req->res.content_length = h2o_strtosize(headers[i].value, headers[i].value_len)) == SIZE_MAX) { - h2o_req_log_error(req, MODULE_NAME, "failed to parse content-length header sent from fcgi: %.*s", - (int)headers[i].value_len, headers[i].value); - return -1; - } - } else { - /* - RFC 3875 defines three headers to have special meaning: Content-Type, Status, Location. - Status is handled as below. - Content-Type does not seem to have any need to be handled specially. - RFC suggests abs-path-style Location headers should trigger an internal redirection, but is that how the web servers - work? - */ - h2o_add_header(&req->pool, &req->res.headers, token, NULL, - h2o_strdup(&req->pool, headers[i].value, headers[i].value_len).base, headers[i].value_len); - if (token == H2O_TOKEN_LINK) - h2o_push_path_in_link_header(req, headers[i].value, headers[i].value_len); - } - } else if (h2o_memis(headers[i].name, headers[i].name_len, H2O_STRLIT("status"))) { - h2o_iovec_t value = h2o_iovec_init(headers[i].value, headers[i].value_len); - if (value.len < 3 || !(_isdigit(value.base[0]) && _isdigit(value.base[1]) && _isdigit(value.base[2])) || - (value.len >= 4 && value.base[3] != ' ')) { - h2o_req_log_error(req, MODULE_NAME, "failed to parse Status header, got: %.*s", (int)value.len, value.base); - return -1; - } - req->res.status = (value.base[0] - '0') * 100 + (value.base[1] - '0') * 10 + (value.base[2] - '0'); - req->res.reason = value.len >= 5 ? h2o_strdup(&req->pool, value.base + 4, value.len - 4).base : "OK"; - } else { - h2o_iovec_t name_duped = h2o_strdup(&req->pool, headers[i].name, headers[i].name_len), - value_duped = h2o_strdup(&req->pool, headers[i].value, headers[i].value_len); - h2o_add_header_by_str(&req->pool, &req->res.headers, name_duped.base, name_duped.len, 0, NULL, value_duped.base, - value_duped.len); - } - } - - return 0; -} - -static void append_content(struct st_fcgi_generator_t *generator, const void *src, size_t len) -{ - /* do not accumulate more than content-length bytes */ - if (generator->leftsize != SIZE_MAX) { - if (generator->leftsize < len) { - len = generator->leftsize; - if (len == 0) - return; - } - generator->leftsize -= len; - } - - h2o_iovec_t reserved = h2o_buffer_reserve(&generator->resp.receiving, len); - memcpy(reserved.base, src, len); - generator->resp.receiving->size += len; -} - -static int handle_stdin_record(struct st_fcgi_generator_t *generator, struct st_fcgi_record_header_t *header) -{ - h2o_buffer_t *input = generator->sock->input; - struct phr_header headers[100]; - size_t num_headers; - int parse_result; - - if (header->contentLength == 0) - return 0; - - if (generator->sent_headers) { - /* simply accumulate the data to response buffer */ - append_content(generator, input->bytes + FCGI_RECORD_HEADER_SIZE, header->contentLength); - return 0; - } - - /* parse the headers using the input buffer (or keep it in response buffer and parse) */ - num_headers = sizeof(headers) / sizeof(headers[0]); - if (generator->resp.receiving->size == 0) { - parse_result = phr_parse_headers(input->bytes + FCGI_RECORD_HEADER_SIZE, header->contentLength, headers, &num_headers, 0); - } else { - size_t prevlen = generator->resp.receiving->size; - memcpy(h2o_buffer_reserve(&generator->resp.receiving, header->contentLength).base, input->bytes + FCGI_RECORD_HEADER_SIZE, - header->contentLength); - generator->resp.receiving->size = prevlen + header->contentLength; - parse_result = - phr_parse_headers(generator->resp.receiving->bytes, generator->resp.receiving->size, headers, &num_headers, prevlen); - } - if (parse_result < 0) { - if (parse_result == -2) { - /* incomplete */ - if (generator->resp.receiving->size == 0) { - memcpy(h2o_buffer_reserve(&generator->resp.receiving, header->contentLength).base, - input->bytes + FCGI_RECORD_HEADER_SIZE, header->contentLength); - generator->resp.receiving->size = header->contentLength; - } - return 0; - } else { - h2o_req_log_error(generator->req, MODULE_NAME, "received broken response"); - return -1; - } - } - - /* fill-in the headers, and start the response */ - if (fill_headers(generator->req, headers, num_headers) != 0) - return -1; - generator->leftsize = generator->req->res.content_length; - h2o_start_response(generator->req, &generator->super); - generator->sent_headers = 1; - - /* rest of the contents should be stored in the response buffer */ - if (generator->resp.receiving->size == 0) { - size_t leftlen = header->contentLength - parse_result; - if (leftlen != 0) { - append_content(generator, input->bytes + FCGI_RECORD_HEADER_SIZE + parse_result, leftlen); - } - } else { - h2o_buffer_consume(&generator->resp.receiving, parse_result); - } - - return 0; -} - -static void on_rw_timeout(h2o_timeout_entry_t *entry) -{ - struct st_fcgi_generator_t *generator = H2O_STRUCT_FROM_MEMBER(struct st_fcgi_generator_t, timeout, entry); - - h2o_req_log_error(generator->req, MODULE_NAME, "I/O timeout"); - errorclose(generator); -} - -static void on_read(h2o_socket_t *sock, const char *err) -{ - struct st_fcgi_generator_t *generator = sock->data; - int can_keepalive = 0; - - if (err != NULL) { - /* note: FastCGI server is allowed to close the connection any time after sending an empty FCGI_STDOUT record */ - if (!generator->sent_headers) - h2o_req_log_error(generator->req, MODULE_NAME, "fastcgi connection closed unexpectedly"); - errorclose(generator); - return; - } - - /* handle the records */ - while (1) { - struct st_fcgi_record_header_t header; - size_t recsize; - if (sock->input->size < FCGI_RECORD_HEADER_SIZE) - break; - decode_header(&header, sock->input->bytes); - recsize = FCGI_RECORD_HEADER_SIZE + header.contentLength + header.paddingLength; - if (sock->input->size < recsize) - break; - /* we have a complete record */ - switch (header.type) { - case FCGI_STDOUT: - if (handle_stdin_record(generator, &header) != 0) - goto Error; - h2o_buffer_consume(&sock->input, recsize); - break; - case FCGI_STDERR: - if (header.contentLength != 0) - h2o_req_log_error(generator->req, MODULE_NAME, "%.*s", (int)header.contentLength, - sock->input->bytes + FCGI_RECORD_HEADER_SIZE); - h2o_buffer_consume(&sock->input, recsize); - break; - case FCGI_END_REQUEST: - if (!generator->sent_headers) { - h2o_req_log_error(generator->req, MODULE_NAME, "received FCGI_END_REQUEST before end of the headers"); - goto Error; - } - h2o_buffer_consume(&sock->input, recsize); - can_keepalive = 1; - goto EOS_Received; - default: - h2o_req_log_error(generator->req, MODULE_NAME, "received unexpected record, type: %u", header.type); - h2o_buffer_consume(&sock->input, recsize); - if (!generator->sent_headers) - goto Error; - goto EOS_Received; - } - } - - /* send data if necessary */ - if (generator->sent_headers && generator->resp.sending.bytes_inflight == 0) - do_send(generator); - - set_timeout(generator, &generator->ctx->io_timeout, on_rw_timeout); - return; - -EOS_Received: - send_eos_and_close(generator, can_keepalive); - return; - -Error: - errorclose(generator); -} - -static void on_send_complete(h2o_socket_t *sock, const char *err) -{ - struct st_fcgi_generator_t *generator = sock->data; - - set_timeout(generator, &generator->ctx->io_timeout, on_rw_timeout); - /* do nothing else! all the rest is handled by the on_read */ -} - -static void on_connect(h2o_socket_t *sock, const char *errstr, void *data) -{ - struct st_fcgi_generator_t *generator = data; - iovec_vector_t vecs; - - generator->connect_req = NULL; - - if (sock == NULL) { - h2o_req_log_error(generator->req, MODULE_NAME, "connection failed:%s", errstr); - errorclose(generator); - return; - } - - generator->sock = sock; - sock->data = generator; - - build_request(generator->req, &vecs, 1, 65535, &generator->ctx->handler->config); - - /* start sending the response */ - h2o_socket_write(generator->sock, vecs.entries, vecs.size, on_send_complete); - - set_timeout(generator, &generator->ctx->io_timeout, on_rw_timeout); - - /* activate the receiver; note: FCGI spec allows the app to start sending the response before it receives FCGI_STDIN */ - h2o_socket_read_start(sock, on_read); -} - -static void do_proceed(h2o_generator_t *_generator, h2o_req_t *req) -{ - struct st_fcgi_generator_t *generator = (void *)_generator; - - h2o_doublebuffer_consume(&generator->resp.sending); - do_send(generator); -} - -static void do_stop(h2o_generator_t *_generator, h2o_req_t *req) -{ - struct st_fcgi_generator_t *generator = (void *)_generator; - close_generator(generator); -} - -static void on_connect_timeout(h2o_timeout_entry_t *entry) -{ - struct st_fcgi_generator_t *generator = H2O_STRUCT_FROM_MEMBER(struct st_fcgi_generator_t, timeout, entry); - - h2o_req_log_error(generator->req, MODULE_NAME, "connect timeout"); - errorclose(generator); -} - -static int on_req(h2o_handler_t *_handler, h2o_req_t *req) -{ - h2o_fastcgi_handler_t *handler = (void *)_handler; - struct st_fcgi_generator_t *generator; - - generator = h2o_mem_alloc_shared(&req->pool, sizeof(*generator), (void (*)(void *))close_generator); - generator->super.proceed = do_proceed; - generator->super.stop = do_stop; - generator->ctx = h2o_context_get_handler_context(req->conn->ctx, &handler->super); - generator->req = req; - generator->sock = NULL; - generator->sent_headers = 0; - h2o_doublebuffer_init(&generator->resp.sending, &h2o_socket_buffer_prototype); - h2o_buffer_init(&generator->resp.receiving, &h2o_socket_buffer_prototype); - generator->timeout = (h2o_timeout_entry_t){0}; - - set_timeout(generator, &generator->ctx->io_timeout, on_connect_timeout); - h2o_socketpool_connect(&generator->connect_req, &handler->sockpool, req->conn->ctx->loop, - &req->conn->ctx->receivers.hostinfo_getaddr, on_connect, generator); - - return 0; -} - -static void on_context_init(h2o_handler_t *_handler, h2o_context_t *ctx) -{ - h2o_fastcgi_handler_t *handler = (void *)_handler; - struct st_fcgi_context_t *handler_ctx = h2o_mem_alloc(sizeof(*handler_ctx)); - - /* use the first event loop for handling timeouts of the socket pool */ - if (handler->sockpool.timeout == UINT64_MAX) - h2o_socketpool_set_timeout(&handler->sockpool, ctx->loop, - handler->config.keepalive_timeout != 0 ? handler->config.keepalive_timeout : 60000); - - handler_ctx->handler = handler; - h2o_timeout_init(ctx->loop, &handler_ctx->io_timeout, handler->config.io_timeout); - - h2o_context_set_handler_context(ctx, &handler->super, handler_ctx); -} - -static void on_context_dispose(h2o_handler_t *_handler, h2o_context_t *ctx) -{ - h2o_fastcgi_handler_t *handler = (void *)_handler; - struct st_fcgi_context_t *handler_ctx = h2o_context_get_handler_context(ctx, &handler->super); - - if (handler_ctx == NULL) - return; - - h2o_timeout_dispose(ctx->loop, &handler_ctx->io_timeout); - free(handler_ctx); -} - -static void on_handler_dispose(h2o_handler_t *_handler) -{ - h2o_fastcgi_handler_t *handler = (void *)_handler; - - if (handler->config.callbacks.dispose != NULL) - handler->config.callbacks.dispose(handler, handler->config.callbacks.data); - - h2o_socketpool_dispose(&handler->sockpool); - free(handler->config.document_root.base); -} - -static h2o_fastcgi_handler_t *register_common(h2o_pathconf_t *pathconf, h2o_fastcgi_config_vars_t *vars) -{ - h2o_fastcgi_handler_t *handler = (void *)h2o_create_handler(pathconf, sizeof(*handler)); - - handler->super.on_context_init = on_context_init; - handler->super.on_context_dispose = on_context_dispose; - handler->super.dispose = on_handler_dispose; - handler->super.on_req = on_req; - handler->config = *vars; - if (vars->document_root.base != NULL) - handler->config.document_root = h2o_strdup(NULL, vars->document_root.base, vars->document_root.len); - - return handler; -} - -h2o_fastcgi_handler_t *h2o_fastcgi_register_by_hostport(h2o_pathconf_t *pathconf, const char *host, uint16_t port, - h2o_fastcgi_config_vars_t *vars) -{ - h2o_fastcgi_handler_t *handler = register_common(pathconf, vars); - - h2o_socketpool_init_by_hostport(&handler->sockpool, h2o_iovec_init(host, strlen(host)), port, 0, SIZE_MAX /* FIXME */); - return handler; -} - -h2o_fastcgi_handler_t *h2o_fastcgi_register_by_address(h2o_pathconf_t *pathconf, struct sockaddr *sa, socklen_t salen, - h2o_fastcgi_config_vars_t *vars) -{ - h2o_fastcgi_handler_t *handler = register_common(pathconf, vars); - - h2o_socketpool_init_by_address(&handler->sockpool, sa, salen, 0, SIZE_MAX /* FIXME */); - return handler; -} diff --git a/web/server/h2o/libh2o/lib/handler/file.c b/web/server/h2o/libh2o/lib/handler/file.c deleted file mode 100644 index 5d7c7a2a4..000000000 --- a/web/server/h2o/libh2o/lib/handler/file.c +++ /dev/null @@ -1,966 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Domingo Alvarez Duarte, - * Tatsuhiko Kubo, Nick Desaulniers, Marc Hoersken, - * Justin Zhu, Tatsuhiro Tsujikawa - * - * 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 -#include -#include -#include -#include -#include - -#include "h2o.h" - -#define MAX_BUF_SIZE 65000 -#define BOUNDARY_SIZE 20 -#define FIXED_PART_SIZE (sizeof("\r\n--") - 1 + BOUNDARY_SIZE + sizeof("\r\nContent-Range: bytes=-/\r\nContent-Type: \r\n\r\n") - 1) - -struct st_h2o_sendfile_generator_t { - h2o_generator_t super; - struct { - h2o_filecache_ref_t *ref; - off_t off; - } file; - h2o_req_t *req; - size_t bytesleft; - h2o_iovec_t content_encoding; - unsigned send_vary : 1; - unsigned send_etag : 1; - unsigned gunzip : 1; - char *buf; - struct { - size_t filesize; - size_t range_count; - size_t *range_infos; /* size_t shows in pair. first is start offset, then length */ - h2o_iovec_t boundary; /* boundary used for multipart/byteranges */ - h2o_iovec_t mimetype; /* original mimetype for multipart */ - size_t current_range; /* range that processing now */ - } ranged; - struct { - char last_modified[H2O_TIMESTR_RFC1123_LEN + 1]; - char etag[H2O_FILECACHE_ETAG_MAXLEN + 1]; - } header_bufs; -}; - -struct st_h2o_file_handler_t { - h2o_handler_t super; - h2o_iovec_t conf_path; /* has "/" appended at last */ - h2o_iovec_t real_path; /* has "/" appended at last */ - h2o_mimemap_t *mimemap; - int flags; - size_t max_index_file_len; - h2o_iovec_t index_files[1]; -}; - -struct st_h2o_specific_file_handler_t { - h2o_handler_t super; - h2o_iovec_t real_path; - h2o_mimemap_type_t *mime_type; - int flags; -}; - -struct st_gzip_decompress_t { - h2o_ostream_t super; - h2o_compress_context_t *decompressor; -}; - -static const char *default_index_files[] = {"index.html", "index.htm", "index.txt", NULL}; - -const char **h2o_file_default_index_files = default_index_files; - -#include "file/templates.c.h" - -static int tm_is_lessthan(struct tm *x, struct tm *y) -{ -#define CMP(f) \ - if (x->f < y->f) \ - return 1; \ - else if (x->f > y->f) \ - return 0; - CMP(tm_year); - CMP(tm_mon); - CMP(tm_mday); - CMP(tm_hour); - CMP(tm_min); - CMP(tm_sec); - return 0; -#undef CMP -} - -static void do_close(h2o_generator_t *_self, h2o_req_t *req) -{ - struct st_h2o_sendfile_generator_t *self = (void *)_self; - h2o_filecache_close_file(self->file.ref); -} - -static void do_proceed(h2o_generator_t *_self, h2o_req_t *req) -{ - struct st_h2o_sendfile_generator_t *self = (void *)_self; - size_t rlen; - ssize_t rret; - h2o_iovec_t vec; - h2o_send_state_t send_state; - - /* read the file */ - rlen = self->bytesleft; - if (rlen > MAX_BUF_SIZE) - rlen = MAX_BUF_SIZE; - while ((rret = pread(self->file.ref->fd, self->buf, rlen, self->file.off)) == -1 && errno == EINTR) - ; - if (rret == -1) { - h2o_send(req, NULL, 0, H2O_SEND_STATE_ERROR); - do_close(&self->super, req); - return; - } - self->file.off += rret; - self->bytesleft -= rret; - if (self->bytesleft == 0) { - send_state = H2O_SEND_STATE_FINAL; - } else { - send_state = H2O_SEND_STATE_IN_PROGRESS; - } - - /* send (and close if done) */ - vec.base = self->buf; - vec.len = rret; - h2o_send(req, &vec, 1, send_state); - if (send_state == H2O_SEND_STATE_FINAL) - do_close(&self->super, req); -} - -static void do_multirange_proceed(h2o_generator_t *_self, h2o_req_t *req) -{ - struct st_h2o_sendfile_generator_t *self = (void *)_self; - size_t rlen, used_buf = 0; - ssize_t rret, vecarrsize; - h2o_iovec_t vec[2]; - h2o_send_state_t send_state; - - if (self->bytesleft == 0) { - size_t *range_cur = self->ranged.range_infos + 2 * self->ranged.current_range; - size_t range_end = *range_cur + *(range_cur + 1) - 1; - if (H2O_LIKELY(self->ranged.current_range != 0)) - used_buf = - sprintf(self->buf, "\r\n--%s\r\nContent-Type: %s\r\nContent-Range: bytes %zd-%zd/%zd\r\n\r\n", - self->ranged.boundary.base, self->ranged.mimetype.base, *range_cur, range_end, self->ranged.filesize); - else - used_buf = - sprintf(self->buf, "--%s\r\nContent-Type: %s\r\nContent-Range: bytes %zd-%zd/%zd\r\n\r\n", - self->ranged.boundary.base, self->ranged.mimetype.base, *range_cur, range_end, self->ranged.filesize); - self->ranged.current_range++; - self->file.off = *range_cur; - self->bytesleft = *++range_cur; - } - rlen = self->bytesleft; - if (rlen + used_buf > MAX_BUF_SIZE) - rlen = MAX_BUF_SIZE - used_buf; - while ((rret = pread(self->file.ref->fd, self->buf + used_buf, rlen, self->file.off)) == -1 && errno == EINTR) - ; - if (rret == -1) - goto Error; - self->file.off += rret; - self->bytesleft -= rret; - - vec[0].base = self->buf; - vec[0].len = rret + used_buf; - if (self->ranged.current_range == self->ranged.range_count && self->bytesleft == 0) { - vec[1].base = h2o_mem_alloc_pool(&req->pool, sizeof("\r\n--") - 1 + BOUNDARY_SIZE + sizeof("--\r\n")); - vec[1].len = sprintf(vec[1].base, "\r\n--%s--\r\n", self->ranged.boundary.base); - vecarrsize = 2; - send_state = H2O_SEND_STATE_FINAL; - } else { - vecarrsize = 1; - send_state = H2O_SEND_STATE_IN_PROGRESS; - } - h2o_send(req, vec, vecarrsize, send_state); - if (send_state == H2O_SEND_STATE_FINAL) - do_close(&self->super, req); - return; - -Error: - h2o_send(req, NULL, 0, H2O_SEND_STATE_ERROR); - do_close(&self->super, req); - return; -} - -static h2o_send_state_t do_pull(h2o_generator_t *_self, h2o_req_t *req, h2o_iovec_t *buf) -{ - struct st_h2o_sendfile_generator_t *self = (void *)_self; - ssize_t rret; - - if (self->bytesleft < buf->len) - buf->len = self->bytesleft; - while ((rret = pread(self->file.ref->fd, buf->base, buf->len, self->file.off)) == -1 && errno == EINTR) - ; - if (rret <= 0) { - buf->len = 0; - self->bytesleft = 0; - do_close(&self->super, req); - return H2O_SEND_STATE_ERROR; - } else { - buf->len = rret; - self->file.off += rret; - self->bytesleft -= rret; - } - - if (self->bytesleft != 0) - return H2O_SEND_STATE_IN_PROGRESS; - do_close(&self->super, req); - return H2O_SEND_STATE_FINAL; -} - -static struct st_h2o_sendfile_generator_t *create_generator(h2o_req_t *req, const char *path, size_t path_len, int *is_dir, - int flags) -{ - struct st_h2o_sendfile_generator_t *self; - h2o_filecache_ref_t *fileref; - h2o_iovec_t content_encoding = (h2o_iovec_t){NULL}; - unsigned gunzip = 0; - - *is_dir = 0; - - if ((flags & H2O_FILE_FLAG_SEND_COMPRESSED) != 0 && req->version >= 0x101) { - int compressible_types = h2o_get_compressible_types(&req->headers); - if (compressible_types != 0) { - char *variant_path = h2o_mem_alloc_pool(&req->pool, path_len + sizeof(".gz")); - memcpy(variant_path, path, path_len); -#define TRY_VARIANT(mask, enc, ext) \ - if ((compressible_types & mask) != 0) { \ - strcpy(variant_path + path_len, ext); \ - if ((fileref = h2o_filecache_open_file(req->conn->ctx->filecache, variant_path, O_RDONLY | O_CLOEXEC)) != NULL) { \ - content_encoding = h2o_iovec_init(enc, sizeof(enc) - 1); \ - goto Opened; \ - } \ - } - TRY_VARIANT(H2O_COMPRESSIBLE_BROTLI, "br", ".br"); - TRY_VARIANT(H2O_COMPRESSIBLE_GZIP, "gzip", ".gz"); -#undef TRY_VARIANT - } - } - if ((fileref = h2o_filecache_open_file(req->conn->ctx->filecache, path, O_RDONLY | O_CLOEXEC)) != NULL) { - goto Opened; - } - if ((flags & H2O_FILE_FLAG_GUNZIP) != 0 && req->version >= 0x101) { - char *variant_path = h2o_mem_alloc_pool(&req->pool, path_len + sizeof(".gz")); - memcpy(variant_path, path, path_len); - strcpy(variant_path + path_len, ".gz"); - if ((fileref = h2o_filecache_open_file(req->conn->ctx->filecache, variant_path, O_RDONLY | O_CLOEXEC)) != NULL) { - gunzip = 1; - goto Opened; - } - } - return NULL; - -Opened: - if (S_ISDIR(fileref->st.st_mode)) { - h2o_filecache_close_file(fileref); - *is_dir = 1; - return NULL; - } - - self = h2o_mem_alloc_pool(&req->pool, sizeof(*self)); - self->super.proceed = do_proceed; - self->super.stop = do_close; - self->file.ref = fileref; - self->file.off = 0; - self->req = NULL; - self->bytesleft = self->file.ref->st.st_size; - self->ranged.range_count = 0; - self->ranged.range_infos = NULL; - self->content_encoding = content_encoding; - self->send_vary = (flags & H2O_FILE_FLAG_SEND_COMPRESSED) != 0; - self->send_etag = (flags & H2O_FILE_FLAG_NO_ETAG) == 0; - self->gunzip = gunzip; - - return self; -} - -static void add_headers_unconditional(struct st_h2o_sendfile_generator_t *self, h2o_req_t *req) -{ - /* RFC 7232 4.1: The server generating a 304 response MUST generate any of the following header fields that would have been sent - * in a 200 (OK) response to the same request: Cache-Control, Content-Location, Date, ETag, Expires, and Vary (snip) a sender - * SHOULD NOT generate representation metadata other than the above listed fields unless said metadata exists for the purpose of - * guiding cache updates. */ - if (self->send_etag) { - size_t etag_len = h2o_filecache_get_etag(self->file.ref, self->header_bufs.etag); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_ETAG, NULL, self->header_bufs.etag, etag_len); - } - if (self->send_vary) - h2o_set_header_token(&req->pool, &req->res.headers, H2O_TOKEN_VARY, H2O_STRLIT("accept-encoding")); -} - -static void send_decompressed(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state) -{ - struct st_gzip_decompress_t *self = (void *)_self; - h2o_iovec_t *outbufs; - size_t outbufcnt; - - self->decompressor->transform(self->decompressor, inbufs, inbufcnt, state, &outbufs, &outbufcnt); - h2o_ostream_send_next(&self->super, req, outbufs, outbufcnt, state); -} - -static void do_send_file(struct st_h2o_sendfile_generator_t *self, h2o_req_t *req, int status, const char *reason, - h2o_iovec_t mime_type, h2o_mime_attributes_t *mime_attr, int is_get) -{ - /* link the request */ - self->req = req; - - /* setup response */ - req->res.status = status; - req->res.reason = reason; - req->res.content_length = self->gunzip ? SIZE_MAX : self->bytesleft; - req->res.mime_attr = mime_attr; - - if (self->ranged.range_count > 1) { - mime_type.base = h2o_mem_alloc_pool(&req->pool, 52); - mime_type.len = sprintf(mime_type.base, "multipart/byteranges; boundary=%s", self->ranged.boundary.base); - } - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, mime_type.base, mime_type.len); - h2o_filecache_get_last_modified(self->file.ref, self->header_bufs.last_modified); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_LAST_MODIFIED, NULL, self->header_bufs.last_modified, - H2O_TIMESTR_RFC1123_LEN); - add_headers_unconditional(self, req); - if (self->content_encoding.base != NULL) - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_ENCODING, NULL, self->content_encoding.base, - self->content_encoding.len); - if (self->ranged.range_count == 0) - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_ACCEPT_RANGES, NULL, H2O_STRLIT("bytes")); - else if (self->ranged.range_count == 1) { - h2o_iovec_t content_range; - content_range.base = h2o_mem_alloc_pool(&req->pool, 128); - content_range.len = sprintf(content_range.base, "bytes %zd-%zd/%zd", self->ranged.range_infos[0], - self->ranged.range_infos[0] + self->ranged.range_infos[1] - 1, self->ranged.filesize); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_RANGE, NULL, content_range.base, content_range.len); - } - - /* special path for cases where we do not need to send any data */ - if (!is_get || self->bytesleft == 0) { - static h2o_generator_t generator = {NULL, NULL}; - h2o_start_response(req, &generator); - h2o_send(req, NULL, 0, H2O_SEND_STATE_FINAL); - do_close(&self->super, req); - return; - } - - /* send data */ - h2o_start_response(req, &self->super); - - /* dynamically setup gzip decompress ostream */ - if (self->gunzip) { - struct st_gzip_decompress_t *decoder = (void *)h2o_add_ostream(req, sizeof(struct st_gzip_decompress_t), &req->_ostr_top); - decoder->decompressor = h2o_compress_gunzip_open(&req->pool); - decoder->super.do_send = send_decompressed; - } - - if (self->ranged.range_count == 1) - self->file.off = self->ranged.range_infos[0]; - if (req->_ostr_top->start_pull != NULL && self->ranged.range_count < 2) { - req->_ostr_top->start_pull(req->_ostr_top, do_pull); - } else { - size_t bufsz = MAX_BUF_SIZE; - if (self->bytesleft < bufsz) - bufsz = self->bytesleft; - self->buf = h2o_mem_alloc_pool(&req->pool, bufsz); - if (self->ranged.range_count < 2) - do_proceed(&self->super, req); - else { - self->bytesleft = 0; - self->super.proceed = do_multirange_proceed; - do_multirange_proceed(&self->super, req); - } - } -} - -int h2o_file_send(h2o_req_t *req, int status, const char *reason, const char *path, h2o_iovec_t mime_type, int flags) -{ - struct st_h2o_sendfile_generator_t *self; - int is_dir; - - if ((self = create_generator(req, path, strlen(path), &is_dir, flags)) == NULL) - return -1; - /* note: is_dir is not handled */ - do_send_file(self, req, status, reason, mime_type, NULL, 1); - return 0; -} - -static int send_dir_listing(h2o_req_t *req, const char *path, size_t path_len, int is_get) -{ - static h2o_generator_t generator = {NULL, NULL}; - DIR *dp; - h2o_buffer_t *body; - h2o_iovec_t bodyvec; - - /* build html */ - if ((dp = opendir(path)) == NULL) - return -1; - body = build_dir_listing_html(&req->pool, req->path_normalized, dp); - closedir(dp); - - bodyvec = h2o_iovec_init(body->bytes, body->size); - h2o_buffer_link_to_pool(body, &req->pool); - - /* send response */ - req->res.status = 200; - req->res.reason = "OK"; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/html; charset=utf-8")); - - /* send headers */ - if (!is_get) { - h2o_send_inline(req, NULL, 0); - return 0; - } - - /* send data */ - h2o_start_response(req, &generator); - h2o_send(req, &bodyvec, 1, H2O_SEND_STATE_FINAL); - return 0; -} - -static size_t *process_range(h2o_mem_pool_t *pool, h2o_iovec_t *range_value, size_t file_size, size_t *ret) -{ -#define CHECK_EOF() \ - if (buf == buf_end) \ - return NULL; - -#define CHECK_OVERFLOW(range) \ - if (range == SIZE_MAX) \ - return NULL; - - size_t range_start = SIZE_MAX, range_count = 0; - char *buf = range_value->base, *buf_end = buf + range_value->len; - int needs_comma = 0; - H2O_VECTOR(size_t) ranges = {NULL}; - - if (range_value->len < 6 || memcmp(buf, "bytes=", 6) != 0) - return NULL; - - buf += 6; - CHECK_EOF(); - - /* most range requests contain only one range */ - do { - while (1) { - if (*buf != ',') { - if (needs_comma) - return NULL; - break; - } - needs_comma = 0; - buf++; - while (H2O_UNLIKELY(*buf == ' ') || H2O_UNLIKELY(*buf == '\t')) { - buf++; - CHECK_EOF(); - } - } - if (H2O_UNLIKELY(buf == buf_end)) - break; - if (H2O_LIKELY((range_start = h2o_strtosizefwd(&buf, buf_end - buf)) != SIZE_MAX)) { - CHECK_EOF(); - if (*buf++ != '-') - return NULL; - range_count = h2o_strtosizefwd(&buf, buf_end - buf); - if (H2O_UNLIKELY(range_start >= file_size)) { - range_start = SIZE_MAX; - } else if (H2O_LIKELY(range_count != SIZE_MAX)) { - if (H2O_UNLIKELY(range_count > file_size - 1)) - range_count = file_size - 1; - if (H2O_LIKELY(range_start <= range_count)) - range_count -= range_start - 1; - else - range_start = SIZE_MAX; - } else { - range_count = file_size - range_start; - } - } else if (H2O_LIKELY(*buf++ == '-')) { - CHECK_EOF(); - range_count = h2o_strtosizefwd(&buf, buf_end - buf); - if (H2O_UNLIKELY(range_count == SIZE_MAX)) - return NULL; - if (H2O_LIKELY(range_count != 0)) { - if (H2O_UNLIKELY(range_count > file_size)) - range_count = file_size; - range_start = file_size - range_count; - } else { - range_start = SIZE_MAX; - } - } else { - return NULL; - } - - if (H2O_LIKELY(range_start != SIZE_MAX)) { - h2o_vector_reserve(pool, &ranges, ranges.size + 2); - ranges.entries[ranges.size++] = range_start; - ranges.entries[ranges.size++] = range_count; - } - if (buf != buf_end) - while (H2O_UNLIKELY(*buf == ' ') || H2O_UNLIKELY(*buf == '\t')) { - buf++; - CHECK_EOF(); - } - needs_comma = 1; - } while (H2O_UNLIKELY(buf < buf_end)); - *ret = ranges.size / 2; - return ranges.entries; -#undef CHECK_EOF -#undef CHECK_OVERFLOW -} - -static void gen_rand_string(h2o_iovec_t *s) -{ - int i; - static const char alphanum[] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - for (i = 0; i < s->len; ++i) { - s->base[i] = alphanum[h2o_rand() % (sizeof(alphanum) - 1)]; - } - - s->base[s->len] = 0; -} - -static int delegate_dynamic_request(h2o_req_t *req, h2o_iovec_t script_name, h2o_iovec_t path_info, const char *local_path, - size_t local_path_len, h2o_mimemap_type_t *mime_type) -{ - h2o_filereq_t *filereq; - h2o_handler_t *handler; - - assert(mime_type->data.dynamic.pathconf.handlers.size == 1); - - filereq = h2o_mem_alloc_pool(&req->pool, sizeof(*filereq)); - filereq->script_name = script_name; - filereq->path_info = path_info; - filereq->local_path = h2o_strdup(&req->pool, local_path, local_path_len); - - h2o_req_bind_conf(req, req->hostconf, &mime_type->data.dynamic.pathconf); - req->filereq = filereq; - - handler = mime_type->data.dynamic.pathconf.handlers.entries[0]; - return handler->on_req(handler, req); -} - -static int try_dynamic_request(h2o_file_handler_t *self, h2o_req_t *req, char *rpath, size_t rpath_len) -{ - /* we have full local path in {rpath,rpath_len}, and need to split it into name and path_info */ - struct stat st; - size_t slash_at = self->real_path.len; - - while (1) { - /* find the next slash (or return -1 if failed) */ - for (++slash_at;; ++slash_at) { - if (slash_at >= rpath_len) - return -1; - if (rpath[slash_at] == '/') - break; - } - /* change the slash to '\0', and check if the file exists */ - rpath[slash_at] = '\0'; - if (stat(rpath, &st) != 0) - return -1; - if (!S_ISDIR(st.st_mode)) - break; - /* restore slash, and continue the search */ - rpath[slash_at] = '/'; - } - - /* file found! */ - h2o_mimemap_type_t *mime_type = h2o_mimemap_get_type_by_extension(self->mimemap, h2o_get_filext(rpath, slash_at)); - switch (mime_type->type) { - case H2O_MIMEMAP_TYPE_MIMETYPE: - return -1; - case H2O_MIMEMAP_TYPE_DYNAMIC: { - h2o_iovec_t script_name = h2o_iovec_init(req->path_normalized.base, self->conf_path.len + slash_at - self->real_path.len); - h2o_iovec_t path_info = - h2o_iovec_init(req->path_normalized.base + script_name.len, req->path_normalized.len - script_name.len); - return delegate_dynamic_request(req, script_name, path_info, rpath, slash_at, mime_type); - } - } - fprintf(stderr, "unknown h2o_miemmap_type_t::type (%d)\n", (int)mime_type->type); - abort(); -} - -static void send_method_not_allowed(h2o_req_t *req) -{ - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_ALLOW, NULL, H2O_STRLIT("GET, HEAD")); - h2o_send_error_405(req, "Method Not Allowed", "method not allowed", H2O_SEND_ERROR_KEEP_HEADERS); -} - -static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h2o_req_t *req, h2o_iovec_t resolved_path, - const char *rpath, size_t rpath_len, h2o_mimemap_type_t *mime_type) -{ - enum { METHOD_IS_GET, METHOD_IS_HEAD, METHOD_IS_OTHER } method_type; - size_t if_modified_since_header_index, if_none_match_header_index; - size_t range_header_index; - - /* determine the method */ - if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET"))) { - method_type = METHOD_IS_GET; - } else if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD"))) { - method_type = METHOD_IS_HEAD; - } else { - method_type = METHOD_IS_OTHER; - } - - /* obtain mime type */ - if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) { - do_close(&generator->super, req); - return delegate_dynamic_request(req, resolved_path, h2o_iovec_init(NULL, 0), rpath, rpath_len, mime_type); - } - assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE); - - /* if-non-match and if-modified-since */ - if ((if_none_match_header_index = h2o_find_header(&req->headers, H2O_TOKEN_IF_NONE_MATCH, SIZE_MAX)) != -1) { - h2o_iovec_t *if_none_match = &req->headers.entries[if_none_match_header_index].value; - char etag[H2O_FILECACHE_ETAG_MAXLEN + 1]; - size_t etag_len = h2o_filecache_get_etag(generator->file.ref, etag); - if (h2o_memis(if_none_match->base, if_none_match->len, etag, etag_len)) - goto NotModified; - } else if ((if_modified_since_header_index = h2o_find_header(&req->headers, H2O_TOKEN_IF_MODIFIED_SINCE, SIZE_MAX)) != -1) { - h2o_iovec_t *ims_vec = &req->headers.entries[if_modified_since_header_index].value; - struct tm ims_tm, *last_modified_tm; - if (h2o_time_parse_rfc1123(ims_vec->base, ims_vec->len, &ims_tm) == 0) { - last_modified_tm = h2o_filecache_get_last_modified(generator->file.ref, NULL); - if (!tm_is_lessthan(&ims_tm, last_modified_tm)) - goto NotModified; - } - } - - /* only allow GET or POST for static files */ - if (method_type == METHOD_IS_OTHER) { - do_close(&generator->super, req); - send_method_not_allowed(req); - return 0; - } - - /* if-range */ - if ((range_header_index = h2o_find_header(&req->headers, H2O_TOKEN_RANGE, SIZE_MAX)) != -1) { - h2o_iovec_t *range = &req->headers.entries[range_header_index].value; - size_t *range_infos, range_count; - range_infos = process_range(&req->pool, range, generator->bytesleft, &range_count); - if (range_infos == NULL) { - h2o_iovec_t content_range; - content_range.base = h2o_mem_alloc_pool(&req->pool, 32); - content_range.len = sprintf(content_range.base, "bytes */%zu", generator->bytesleft); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_RANGE, NULL, content_range.base, content_range.len); - h2o_send_error_416(req, "Request Range Not Satisfiable", "requested range not satisfiable", - H2O_SEND_ERROR_KEEP_HEADERS); - goto Close; - } - generator->ranged.range_count = range_count; - generator->ranged.range_infos = range_infos; - generator->ranged.current_range = 0; - generator->ranged.filesize = generator->bytesleft; - - /* set content-length according to range */ - if (range_count == 1) - generator->bytesleft = range_infos[1]; - else { - generator->ranged.mimetype = h2o_strdup(&req->pool, mime_type->data.mimetype.base, mime_type->data.mimetype.len); - size_t final_content_len = 0, size_tmp = 0, size_fixed_each_part, i; - generator->ranged.boundary.base = h2o_mem_alloc_pool(&req->pool, BOUNDARY_SIZE + 1); - generator->ranged.boundary.len = BOUNDARY_SIZE; - gen_rand_string(&generator->ranged.boundary); - i = generator->bytesleft; - while (i) { - i /= 10; - size_tmp++; - } - size_fixed_each_part = FIXED_PART_SIZE + mime_type->data.mimetype.len + size_tmp; - for (i = 0; i < range_count; i++) { - size_tmp = *range_infos++; - if (size_tmp == 0) - final_content_len++; - while (size_tmp) { - size_tmp /= 10; - final_content_len++; - } - - size_tmp = *(range_infos - 1); - final_content_len += *range_infos; - - size_tmp += *range_infos++ - 1; - if (size_tmp == 0) - final_content_len++; - while (size_tmp) { - size_tmp /= 10; - final_content_len++; - } - } - final_content_len += sizeof("\r\n--") - 1 + BOUNDARY_SIZE + sizeof("--\r\n") - 1 + size_fixed_each_part * range_count - - (sizeof("\r\n") - 1); - generator->bytesleft = final_content_len; - } - do_send_file(generator, req, 206, "Partial Content", mime_type->data.mimetype, &h2o_mime_attributes_as_is, - method_type == METHOD_IS_GET); - return 0; - } - - /* return file */ - do_send_file(generator, req, 200, "OK", mime_type->data.mimetype, &mime_type->data.attr, method_type == METHOD_IS_GET); - return 0; - -NotModified: - req->res.status = 304; - req->res.reason = "Not Modified"; - add_headers_unconditional(generator, req); - h2o_send_inline(req, NULL, 0); -Close: - do_close(&generator->super, req); - return 0; -} - -static int on_req(h2o_handler_t *_self, h2o_req_t *req) -{ - h2o_file_handler_t *self = (void *)_self; - char *rpath; - size_t rpath_len, req_path_prefix; - struct st_h2o_sendfile_generator_t *generator = NULL; - int is_dir; - - if (req->path_normalized.len < self->conf_path.len) { - h2o_iovec_t dest = h2o_uri_escape(&req->pool, self->conf_path.base, self->conf_path.len, "/"); - if (req->query_at != SIZE_MAX) - dest = h2o_concat(&req->pool, dest, h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at)); - h2o_send_redirect(req, 301, "Moved Permanently", dest.base, dest.len); - return 0; - } - - /* build path (still unterminated at the end of the block) */ - req_path_prefix = self->conf_path.len; - rpath = alloca(self->real_path.len + (req->path_normalized.len - req_path_prefix) + self->max_index_file_len + 1); - rpath_len = 0; - memcpy(rpath + rpath_len, self->real_path.base, self->real_path.len); - rpath_len += self->real_path.len; - memcpy(rpath + rpath_len, req->path_normalized.base + req_path_prefix, req->path_normalized.len - req_path_prefix); - rpath_len += req->path_normalized.len - req_path_prefix; - - h2o_iovec_t resolved_path = req->path_normalized; - - /* build generator (as well as terminating the rpath and its length upon success) */ - if (rpath[rpath_len - 1] == '/') { - h2o_iovec_t *index_file; - for (index_file = self->index_files; index_file->base != NULL; ++index_file) { - memcpy(rpath + rpath_len, index_file->base, index_file->len); - rpath[rpath_len + index_file->len] = '\0'; - if ((generator = create_generator(req, rpath, rpath_len + index_file->len, &is_dir, self->flags)) != NULL) { - rpath_len += index_file->len; - resolved_path = h2o_concat(&req->pool, req->path_normalized, *index_file); - goto Opened; - } - if (is_dir) { - /* note: apache redirects "path/" to "path/index.txt/" if index.txt is a dir */ - h2o_iovec_t dest = h2o_concat(&req->pool, req->path_normalized, *index_file, h2o_iovec_init(H2O_STRLIT("/"))); - dest = h2o_uri_escape(&req->pool, dest.base, dest.len, "/"); - if (req->query_at != SIZE_MAX) - dest = - h2o_concat(&req->pool, dest, h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at)); - h2o_send_redirect(req, 301, "Moved Permantently", dest.base, dest.len); - return 0; - } - if (errno != ENOENT) - break; - } - if (index_file->base == NULL && (self->flags & H2O_FILE_FLAG_DIR_LISTING) != 0) { - rpath[rpath_len] = '\0'; - int is_get = 0; - if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET"))) { - is_get = 1; - } else if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD"))) { - /* ok */ - } else { - send_method_not_allowed(req); - return 0; - } - if (send_dir_listing(req, rpath, rpath_len, is_get) == 0) - return 0; - } - } else { - rpath[rpath_len] = '\0'; - if ((generator = create_generator(req, rpath, rpath_len, &is_dir, self->flags)) != NULL) - goto Opened; - if (is_dir) { - h2o_iovec_t dest = h2o_concat(&req->pool, req->path_normalized, h2o_iovec_init(H2O_STRLIT("/"))); - dest = h2o_uri_escape(&req->pool, dest.base, dest.len, "/"); - if (req->query_at != SIZE_MAX) - dest = h2o_concat(&req->pool, dest, h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at)); - h2o_send_redirect(req, 301, "Moved Permanently", dest.base, dest.len); - return 0; - } - } - /* failed to open */ - - if (errno == ENFILE || errno == EMFILE) { - h2o_send_error_503(req, "Service Unavailable", "please try again later", 0); - } else { - if (h2o_mimemap_has_dynamic_type(self->mimemap) && try_dynamic_request(self, req, rpath, rpath_len) == 0) - return 0; - if (errno == ENOENT || errno == ENOTDIR) { - return -1; - } else { - h2o_send_error_403(req, "Access Forbidden", "access forbidden", 0); - } - } - return 0; - -Opened: - return serve_with_generator(generator, req, resolved_path, rpath, rpath_len, - h2o_mimemap_get_type_by_extension(self->mimemap, h2o_get_filext(rpath, rpath_len))); -} - -static void on_context_init(h2o_handler_t *_self, h2o_context_t *ctx) -{ - h2o_file_handler_t *self = (void *)_self; - - h2o_mimemap_on_context_init(self->mimemap, ctx); -} - -static void on_context_dispose(h2o_handler_t *_self, h2o_context_t *ctx) -{ - h2o_file_handler_t *self = (void *)_self; - - h2o_mimemap_on_context_dispose(self->mimemap, ctx); -} - -static void on_dispose(h2o_handler_t *_self) -{ - h2o_file_handler_t *self = (void *)_self; - size_t i; - - free(self->conf_path.base); - free(self->real_path.base); - h2o_mem_release_shared(self->mimemap); - for (i = 0; self->index_files[i].base != NULL; ++i) - free(self->index_files[i].base); -} - -h2o_file_handler_t *h2o_file_register(h2o_pathconf_t *pathconf, const char *real_path, const char **index_files, - h2o_mimemap_t *mimemap, int flags) -{ - h2o_file_handler_t *self; - size_t i; - - if (index_files == NULL) - index_files = default_index_files; - - /* allocate memory */ - for (i = 0; index_files[i] != NULL; ++i) - ; - self = - (void *)h2o_create_handler(pathconf, offsetof(h2o_file_handler_t, index_files[0]) + sizeof(self->index_files[0]) * (i + 1)); - - /* setup callbacks */ - self->super.on_context_init = on_context_init; - self->super.on_context_dispose = on_context_dispose; - self->super.dispose = on_dispose; - self->super.on_req = on_req; - - /* setup attributes */ - self->conf_path = h2o_strdup_slashed(NULL, pathconf->path.base, pathconf->path.len); - self->real_path = h2o_strdup_slashed(NULL, real_path, SIZE_MAX); - if (mimemap != NULL) { - h2o_mem_addref_shared(mimemap); - self->mimemap = mimemap; - } else { - self->mimemap = h2o_mimemap_create(); - } - self->flags = flags; - for (i = 0; index_files[i] != NULL; ++i) { - self->index_files[i] = h2o_strdup(NULL, index_files[i], SIZE_MAX); - if (self->max_index_file_len < self->index_files[i].len) - self->max_index_file_len = self->index_files[i].len; - } - - return self; -} - -h2o_mimemap_t *h2o_file_get_mimemap(h2o_file_handler_t *handler) -{ - return handler->mimemap; -} - -static void specific_handler_on_context_init(h2o_handler_t *_self, h2o_context_t *ctx) -{ - struct st_h2o_specific_file_handler_t *self = (void *)_self; - - if (self->mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) - h2o_context_init_pathconf_context(ctx, &self->mime_type->data.dynamic.pathconf); -} - -static void specific_handler_on_context_dispose(h2o_handler_t *_self, h2o_context_t *ctx) -{ - struct st_h2o_specific_file_handler_t *self = (void *)_self; - - if (self->mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) - h2o_context_dispose_pathconf_context(ctx, &self->mime_type->data.dynamic.pathconf); -} - -static void specific_handler_on_dispose(h2o_handler_t *_self) -{ - struct st_h2o_specific_file_handler_t *self = (void *)_self; - - free(self->real_path.base); - h2o_mem_release_shared(self->mime_type); -} - -static int specific_handler_on_req(h2o_handler_t *_self, h2o_req_t *req) -{ - struct st_h2o_specific_file_handler_t *self = (void *)_self; - struct st_h2o_sendfile_generator_t *generator; - int is_dir; - - /* open file (or send error or return -1) */ - if ((generator = create_generator(req, self->real_path.base, self->real_path.len, &is_dir, self->flags)) == NULL) { - if (is_dir) { - h2o_send_error_403(req, "Access Forbidden", "access forbidden", 0); - } else if (errno == ENOENT) { - return -1; - } else if (errno == ENFILE || errno == EMFILE) { - h2o_send_error_503(req, "Service Unavailable", "please try again later", 0); - } else { - h2o_send_error_403(req, "Access Forbidden", "access forbidden", 0); - } - return 0; - } - - return serve_with_generator(generator, req, req->path_normalized, self->real_path.base, self->real_path.len, self->mime_type); -} - -h2o_handler_t *h2o_file_register_file(h2o_pathconf_t *pathconf, const char *real_path, h2o_mimemap_type_t *mime_type, int flags) -{ - struct st_h2o_specific_file_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self)); - - self->super.on_context_init = specific_handler_on_context_init; - self->super.on_context_dispose = specific_handler_on_context_dispose; - self->super.dispose = specific_handler_on_dispose; - self->super.on_req = specific_handler_on_req; - - self->real_path = h2o_strdup(NULL, real_path, SIZE_MAX); - h2o_mem_addref_shared(mime_type); - self->mime_type = mime_type; - self->flags = flags; - - return &self->super; -} diff --git a/web/server/h2o/libh2o/lib/handler/file/_templates.c.h b/web/server/h2o/libh2o/lib/handler/file/_templates.c.h deleted file mode 100644 index 11b73577c..000000000 --- a/web/server/h2o/libh2o/lib/handler/file/_templates.c.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * - * lib/file/templates.c.h is automatically generated from lib/file/_templates.h - * with command: - * picotemplate.pl --conf=misc/picotemplate-conf.pl lib/file/_templates.c.h - */ - -#include - -static int cmpstrptr(const void *_x, const void *_y) -{ - const char *x = *(const char **)_x; - const char *y = *(const char **)_y; - return strcmp(x, y); -} - -#if !defined(NAME_MAX) || defined(__linux__) -/* readdir(3) is known to be thread-safe on Linux and should be thread-safe on a platform that does not have a predefined value for - NAME_MAX */ -#define FOREACH_DIRENT(dp, dent) \ - struct dirent *dent; \ - while ((dent = readdir(dp)) != NULL) -#else -#define FOREACH_DIRENT(dp, dent) \ - struct { \ - struct dirent d; \ - char s[NAME_MAX + 1]; \ - } dent_; \ - struct dirent *dentp, *dent = &dent_.d; \ - int ret; \ - while ((ret = readdir_r(dp, dent, &dentp)) == 0 && dentp != NULL) -#endif /* FOREACH_DIRENT */ - -static h2o_buffer_t *build_dir_listing_html(h2o_mem_pool_t *pool, h2o_iovec_t path_normalized, DIR* dp) -{ - H2O_VECTOR(char *) files = {NULL}; - - { /* build list of files */ - FOREACH_DIRENT(dp, dent) - { - if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) - continue; - h2o_vector_reserve(pool, &files, files.size + 1); - files.entries[files.size++] = h2o_strdup(pool, dent->d_name, SIZE_MAX).base; - } - if (files.size > 1) - qsort(files.entries, files.size, sizeof(files.entries[0]), cmpstrptr); - } - - h2o_buffer_t *_; - h2o_iovec_t path_normalized_escaped = h2o_htmlescape(pool, path_normalized.base, path_normalized.len); - - h2o_buffer_init(&_, &h2o_socket_buffer_prototype); - -? -?Index of <?= path_normalized_escaped ?> -?

Index of

-?
    -?
  • Parent Directory - - size_t i; - for (i = 0; i != files.size; ++i) { - h2o_iovec_t link_escaped = h2o_uri_escape(pool, files.entries[i], strlen(files.entries[i]), NULL); - link_escaped = h2o_htmlescape(pool, link_escaped.base, link_escaped.len); - h2o_iovec_t label_escaped = h2o_htmlescape(pool, files.entries[i], strlen(files.entries[i])); -?
  • - } -?
- - return _; -} diff --git a/web/server/h2o/libh2o/lib/handler/file/templates.c.h b/web/server/h2o/libh2o/lib/handler/file/templates.c.h deleted file mode 100644 index 24c12dae5..000000000 --- a/web/server/h2o/libh2o/lib/handler/file/templates.c.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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. - * - * lib/file/templates.c.h is automatically generated from lib/file/_templates.h - * with command: - * picotemplate.pl --conf=misc/picotemplate-conf.pl lib/file/_templates.c.h - */ - -#include - -static int cmpstrptr(const void *_x, const void *_y) -{ - const char *x = *(const char **)_x; - const char *y = *(const char **)_y; - return strcmp(x, y); -} - -#if !defined(NAME_MAX) || defined(__linux__) -/* readdir(3) is known to be thread-safe on Linux and should be thread-safe on a platform that does not have a predefined value for - NAME_MAX */ -#define FOREACH_DIRENT(dp, dent) \ - struct dirent *dent; \ - while ((dent = readdir(dp)) != NULL) -#else -#define FOREACH_DIRENT(dp, dent) \ - struct { \ - struct dirent d; \ - char s[NAME_MAX + 1]; \ - } dent_; \ - struct dirent *dentp, *dent = &dent_.d; \ - int ret; \ - while ((ret = readdir_r(dp, dent, &dentp)) == 0 && dentp != NULL) -#endif /* FOREACH_DIRENT */ - -static h2o_buffer_t *build_dir_listing_html(h2o_mem_pool_t *pool, h2o_iovec_t path_normalized, DIR *dp) -{ - H2O_VECTOR(char *) files = {NULL}; - - { /* build list of files */ - FOREACH_DIRENT(dp, dent) - { - if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) - continue; - h2o_vector_reserve(pool, &files, files.size + 1); - files.entries[files.size++] = h2o_strdup(pool, dent->d_name, SIZE_MAX).base; - } - if (files.size > 1) - qsort(files.entries, files.size, sizeof(files.entries[0]), cmpstrptr); - } - - h2o_buffer_t *_; - h2o_iovec_t path_normalized_escaped = h2o_htmlescape(pool, path_normalized.base, path_normalized.len); - - h2o_buffer_init(&_, &h2o_socket_buffer_prototype); - - { - h2o_iovec_t _s = (h2o_iovec_init(H2O_STRLIT("\nIndex of "))); - if (_s.len != 0 && _s.base[_s.len - 1] == '\n') - --_s.len; - h2o_buffer_reserve(&_, _s.len); - memcpy(_->bytes + _->size, _s.base, _s.len); - _->size += _s.len; - } - { - h2o_iovec_t _s = (path_normalized_escaped); - if (_s.len != 0 && _s.base[_s.len - 1] == '\n') - --_s.len; - h2o_buffer_reserve(&_, _s.len); - memcpy(_->bytes + _->size, _s.base, _s.len); - _->size += _s.len; - } - { - h2o_iovec_t _s = (h2o_iovec_init(H2O_STRLIT("\n

Index of "))); - if (_s.len != 0 && _s.base[_s.len - 1] == '\n') - --_s.len; - h2o_buffer_reserve(&_, _s.len); - memcpy(_->bytes + _->size, _s.base, _s.len); - _->size += _s.len; - } - { - h2o_iovec_t _s = (path_normalized_escaped); - if (_s.len != 0 && _s.base[_s.len - 1] == '\n') - --_s.len; - h2o_buffer_reserve(&_, _s.len); - memcpy(_->bytes + _->size, _s.base, _s.len); - _->size += _s.len; - } - { - h2o_iovec_t _s = (h2o_iovec_init(H2O_STRLIT("

\n\n"))); - if (_s.len != 0 && _s.base[_s.len - 1] == '\n') - --_s.len; - h2o_buffer_reserve(&_, _s.len); - memcpy(_->bytes + _->size, _s.base, _s.len); - _->size += _s.len; - } - - return _; -} diff --git a/web/server/h2o/libh2o/lib/handler/headers.c b/web/server/h2o/libh2o/lib/handler/headers.c deleted file mode 100644 index 973976b35..000000000 --- a/web/server/h2o/libh2o/lib/handler/headers.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 "h2o.h" - -struct st_headers_filter_t { - h2o_filter_t super; - h2o_headers_command_t *cmds; -}; - -static void on_setup_ostream(h2o_filter_t *_self, h2o_req_t *req, h2o_ostream_t **slot) -{ - struct st_headers_filter_t *self = (void *)_self; - h2o_headers_command_t *cmd; - - for (cmd = self->cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd) - h2o_rewrite_headers(&req->pool, &req->res.headers, cmd); - - h2o_setup_next_ostream(req, slot); -} - -void h2o_headers_register(h2o_pathconf_t *pathconf, h2o_headers_command_t *cmds) -{ - struct st_headers_filter_t *self = (void *)h2o_create_filter(pathconf, sizeof(*self)); - - self->super.on_setup_ostream = on_setup_ostream; - self->cmds = cmds; -} - -int h2o_headers_is_prohibited_name(const h2o_token_t *token) -{ - /* prohibit connection-specific headers */ - if (token == H2O_TOKEN_CONNECTION || token == H2O_TOKEN_CONTENT_LENGTH || token == H2O_TOKEN_TRANSFER_ENCODING) - return 1; - /* prohibit headers added at protocol layer */ - if (token == H2O_TOKEN_DATE || token == H2O_TOKEN_SERVER) - return 1; - /* all others are permitted */ - return 0; -} diff --git a/web/server/h2o/libh2o/lib/handler/headers_util.c b/web/server/h2o/libh2o/lib/handler/headers_util.c deleted file mode 100644 index 5ecacfa54..000000000 --- a/web/server/h2o/libh2o/lib/handler/headers_util.c +++ /dev/null @@ -1,114 +0,0 @@ -#include "h2o.h" - -static h2o_header_t *find_header(h2o_headers_t *headers, h2o_headers_command_t *cmd) -{ - size_t index; - - if (h2o_iovec_is_token(cmd->name)) { - index = h2o_find_header(headers, (void *)cmd->name, SIZE_MAX); - } else { - index = h2o_find_header_by_str(headers, cmd->name->base, cmd->name->len, SIZE_MAX); - } - if (index == SIZE_MAX) - return NULL; - return headers->entries + index; -} - -static void remove_header(h2o_headers_t *headers, h2o_headers_command_t *cmd) -{ - size_t src, dst = 0; - - for (src = 0; src != headers->size; ++src) { - if (h2o_iovec_is_token(cmd->name)) { - if (headers->entries[src].name == cmd->name) - continue; - } else { - if (h2o_memis(headers->entries[src].name->base, headers->entries[src].name->len, cmd->name->base, cmd->name->len)) - continue; - } - /* not matched */ - if (dst != src) - headers->entries[dst] = headers->entries[src]; - ++dst; - } - headers->size = dst; -} - -void h2o_headers_append_command(h2o_headers_command_t **cmds, int cmd, h2o_iovec_t *name, h2o_iovec_t value) -{ - h2o_headers_command_t *new_cmds; - size_t cnt; - - if (*cmds != NULL) { - for (cnt = 0; (*cmds)[cnt].cmd != H2O_HEADERS_CMD_NULL; ++cnt) - ; - } else { - cnt = 0; - } - - new_cmds = h2o_mem_alloc_shared(NULL, (cnt + 2) * sizeof(*new_cmds), NULL); - if (*cmds != NULL) - memcpy(new_cmds, *cmds, cnt * sizeof(*new_cmds)); - new_cmds[cnt] = (h2o_headers_command_t){cmd, name, value}; - new_cmds[cnt + 1] = (h2o_headers_command_t){H2O_HEADERS_CMD_NULL}; - - if (*cmds != NULL) - h2o_mem_release_shared(*cmds); - *cmds = new_cmds; -} - -void h2o_rewrite_headers(h2o_mem_pool_t *pool, h2o_headers_t *headers, h2o_headers_command_t *cmd) -{ - h2o_header_t *target; - - switch (cmd->cmd) { - case H2O_HEADERS_CMD_ADD: - goto AddHeader; - case H2O_HEADERS_CMD_APPEND: - if ((target = find_header(headers, cmd)) == NULL) - goto AddHeader; - goto AppendToken; - case H2O_HEADERS_CMD_MERGE: - if ((target = find_header(headers, cmd)) == NULL) - goto AddHeader; - if (h2o_contains_token(target->value.base, target->value.len, cmd->value.base, cmd->value.len, ',')) - return; - goto AppendToken; - case H2O_HEADERS_CMD_SET: - remove_header(headers, cmd); - goto AddHeader; - case H2O_HEADERS_CMD_SETIFEMPTY: - if (find_header(headers, cmd) != NULL) - return; - goto AddHeader; - case H2O_HEADERS_CMD_UNSET: - remove_header(headers, cmd); - return; - } - - assert(!"FIXME"); - return; - -AddHeader: - if (h2o_iovec_is_token(cmd->name)) { - h2o_add_header(pool, headers, (void *)cmd->name, NULL, cmd->value.base, cmd->value.len); - } else { - h2o_add_header_by_str(pool, headers, cmd->name->base, cmd->name->len, 0, NULL, cmd->value.base, cmd->value.len); - } - return; - -AppendToken: - if (target->value.len != 0) { - h2o_iovec_t v; - v.len = target->value.len + 2 + cmd->value.len; - v.base = h2o_mem_alloc_pool(pool, v.len); - memcpy(v.base, target->value.base, target->value.len); - v.base[target->value.len] = ','; - v.base[target->value.len + 1] = ' '; - memcpy(v.base + target->value.len + 2, cmd->value.base, cmd->value.len); - target->value = v; - } else { - target->value = cmd->value; - } - return; -} diff --git a/web/server/h2o/libh2o/lib/handler/http2_debug_state.c b/web/server/h2o/libh2o/lib/handler/http2_debug_state.c deleted file mode 100644 index 0aa0bd1b1..000000000 --- a/web/server/h2o/libh2o/lib/handler/http2_debug_state.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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" - -struct st_h2o_http2_debug_state_handler_t { - h2o_handler_t super; - int hpack_enabled; -}; - -static int on_req(h2o_handler_t *_self, h2o_req_t *req) -{ - struct st_h2o_http2_debug_state_handler_t *self = (void *)_self; - - static h2o_generator_t generator = {NULL, NULL}; - - if (req->conn->callbacks->get_debug_state == NULL) { - return -1; - } - - h2o_http2_debug_state_t *debug_state = req->conn->callbacks->get_debug_state(req, self->hpack_enabled); - - // stringify these variables to embed in Debug Header - h2o_iovec_t conn_flow_in, conn_flow_out; - conn_flow_in.base = h2o_mem_alloc_pool(&req->pool, sizeof(H2O_INT64_LONGEST_STR)); - conn_flow_in.len = sprintf(conn_flow_in.base, "%zd", debug_state->conn_flow_in); - conn_flow_out.base = h2o_mem_alloc_pool(&req->pool, sizeof(H2O_INT64_LONGEST_STR)); - conn_flow_out.len = sprintf(conn_flow_out.base, "%zd", debug_state->conn_flow_out); - - req->res.status = 200; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("application/json; charset=utf-8")); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CACHE_CONTROL, NULL, H2O_STRLIT("no-cache, no-store")); - h2o_add_header_by_str(&req->pool, &req->res.headers, H2O_STRLIT("conn-flow-in"), 0, NULL, conn_flow_in.base, conn_flow_in.len); - h2o_add_header_by_str(&req->pool, &req->res.headers, H2O_STRLIT("conn-flow-out"), 0, NULL, conn_flow_out.base, - conn_flow_out.len); - - h2o_start_response(req, &generator); - h2o_send(req, debug_state->json.entries, - h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD")) ? 0 : debug_state->json.size, - H2O_SEND_STATE_FINAL); - return 0; -} - -void h2o_http2_debug_state_register(h2o_hostconf_t *conf, int hpack_enabled) -{ - h2o_pathconf_t *pathconf = h2o_config_register_path(conf, "/.well-known/h2/state", 0); - struct st_h2o_http2_debug_state_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self)); - self->super.on_req = on_req; - self->hpack_enabled = hpack_enabled; -} diff --git a/web/server/h2o/libh2o/lib/handler/mimemap.c b/web/server/h2o/libh2o/lib/handler/mimemap.c deleted file mode 100644 index 764362da0..000000000 --- a/web/server/h2o/libh2o/lib/handler/mimemap.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * 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 -#include -#include -#include "khash.h" -#include "h2o.h" - -KHASH_MAP_INIT_STR(extmap, h2o_mimemap_type_t *) - -static inline khint_t hash_mimemap_type(h2o_mimemap_type_t *mimetype) -{ - khint_t h = 0; - size_t i; - for (i = 0; i != mimetype->data.mimetype.len; ++i) - h = (h << 5) - h + (khint_t)mimetype->data.mimetype.base[i]; - return h; -} - -static inline int mimemap_type_equals(h2o_mimemap_type_t *x, h2o_mimemap_type_t *y) -{ - return h2o_memis(x->data.mimetype.base, x->data.mimetype.len, y->data.mimetype.base, y->data.mimetype.len); -} - -KHASH_INIT(typeset, h2o_mimemap_type_t *, char, 0, hash_mimemap_type, mimemap_type_equals) - -h2o_mime_attributes_t h2o_mime_attributes_as_is; - -struct st_h2o_mimemap_t { - khash_t(extmap) * extmap; - khash_t(typeset) * typeset; /* refs point to the entries in extmap */ - h2o_mimemap_type_t *default_type; - size_t num_dynamic; -}; - -static h2o_iovec_t dupref(const char *s) -{ - h2o_iovec_t ret; - ret.len = strlen(s); - ret.base = h2o_mem_alloc_shared(NULL, ret.len + 1, NULL); - memcpy(ret.base, s, ret.len + 1); - return ret; -} - -static void on_dispose(void *_mimemap) -{ - h2o_mimemap_t *mimemap = _mimemap; - const char *ext; - h2o_mimemap_type_t *type; - - kh_destroy(typeset, mimemap->typeset); - kh_foreach(mimemap->extmap, ext, type, { - h2o_mem_release_shared((char *)ext); - h2o_mem_release_shared(type); - }); - kh_destroy(extmap, mimemap->extmap); - h2o_mem_release_shared(mimemap->default_type); -} - -static void on_unlink(h2o_mimemap_t *mimemap, h2o_mimemap_type_t *type) -{ - switch (type->type) { - case H2O_MIMEMAP_TYPE_MIMETYPE: - break; - case H2O_MIMEMAP_TYPE_DYNAMIC: - --mimemap->num_dynamic; - break; - } -} - -static void on_link(h2o_mimemap_t *mimemap, h2o_mimemap_type_t *type) -{ - switch (type->type) { - case H2O_MIMEMAP_TYPE_MIMETYPE: - break; - case H2O_MIMEMAP_TYPE_DYNAMIC: - ++mimemap->num_dynamic; - break; - } -} - -static void rebuild_typeset(h2o_mimemap_t *mimemap) -{ - kh_clear(typeset, mimemap->typeset); - - const char *ext; - h2o_mimemap_type_t *mime; - kh_foreach(mimemap->extmap, ext, mime, { - if (mime->type == H2O_MIMEMAP_TYPE_MIMETYPE) { - khiter_t iter = kh_get(typeset, mimemap->typeset, mime); - if (iter == kh_end(mimemap->typeset)) { - int r; - kh_put(typeset, mimemap->typeset, mime, &r); - } - } - }); -} - -static h2o_mimemap_type_t *create_extension_type(const char *mime, h2o_mime_attributes_t *attr) -{ - h2o_mimemap_type_t *type = h2o_mem_alloc_shared(NULL, sizeof(*type) + strlen(mime) + 1, NULL); - size_t i; - - memset(type, 0, sizeof(*type)); - - type->type = H2O_MIMEMAP_TYPE_MIMETYPE; - - /* normalize-copy type->data.mimetype */ - type->data.mimetype.base = (char *)type + sizeof(*type); - for (i = 0; mime[i] != '\0' && mime[i] != ';'; ++i) - type->data.mimetype.base[i] = h2o_tolower(mime[i]); - for (; mime[i] != '\0'; ++i) - type->data.mimetype.base[i] = mime[i]; - type->data.mimetype.base[i] = '\0'; - type->data.mimetype.len = i; - - if (attr != NULL) { - type->data.attr = *attr; - } else { - h2o_mimemap_get_default_attributes(mime, &type->data.attr); - } - - return type; -} - -static void dispose_dynamic_type(h2o_mimemap_type_t *type) -{ - h2o_config_dispose_pathconf(&type->data.dynamic.pathconf); -} - -static h2o_mimemap_type_t *create_dynamic_type(h2o_globalconf_t *globalconf, h2o_mimemap_t *mimemap) -{ - h2o_mimemap_type_t *type = h2o_mem_alloc_shared(NULL, sizeof(*type), (void (*)(void *))dispose_dynamic_type); - - type->type = H2O_MIMEMAP_TYPE_DYNAMIC; - memset(&type->data.dynamic, 0, sizeof(type->data.dynamic)); - h2o_config_init_pathconf(&type->data.dynamic.pathconf, globalconf, NULL, mimemap); - - return type; -} - -h2o_mimemap_t *h2o_mimemap_create() -{ - h2o_mimemap_t *mimemap = h2o_mem_alloc_shared(NULL, sizeof(*mimemap), on_dispose); - - mimemap->extmap = kh_init(extmap); - mimemap->typeset = kh_init(typeset); - mimemap->default_type = create_extension_type("application/octet-stream", NULL); - mimemap->num_dynamic = 0; - on_link(mimemap, mimemap->default_type); - - { /* setup the tiny default */ - static const char *default_types[] = { -#define MIMEMAP(ext, mime) ext, mime, -#include "mimemap/defaults.c.h" -#undef MIMEMAP - NULL}; - const char **p; - for (p = default_types; *p != NULL; p += 2) - h2o_mimemap_define_mimetype(mimemap, p[0], p[1], NULL); - } - rebuild_typeset(mimemap); - - return mimemap; -} - -h2o_mimemap_t *h2o_mimemap_clone(h2o_mimemap_t *src) -{ - h2o_mimemap_t *dst = h2o_mem_alloc_shared(NULL, sizeof(*dst), on_dispose); - const char *ext; - h2o_mimemap_type_t *type; - - dst->extmap = kh_init(extmap); - dst->typeset = kh_init(typeset); - kh_foreach(src->extmap, ext, type, { - int r; - khiter_t iter = kh_put(extmap, dst->extmap, ext, &r); - kh_val(dst->extmap, iter) = type; - h2o_mem_addref_shared((char *)ext); - h2o_mem_addref_shared(type); - on_link(dst, type); - }); - dst->default_type = src->default_type; - h2o_mem_addref_shared(dst->default_type); - on_link(dst, dst->default_type); - rebuild_typeset(dst); - - return dst; -} - -void h2o_mimemap_on_context_init(h2o_mimemap_t *mimemap, h2o_context_t *ctx) -{ - const char *ext; - h2o_mimemap_type_t *type; - - kh_foreach(mimemap->extmap, ext, type, { - switch (type->type) { - case H2O_MIMEMAP_TYPE_DYNAMIC: - h2o_context_init_pathconf_context(ctx, &type->data.dynamic.pathconf); - break; - case H2O_MIMEMAP_TYPE_MIMETYPE: - break; - } - }); -} - -void h2o_mimemap_on_context_dispose(h2o_mimemap_t *mimemap, h2o_context_t *ctx) -{ - const char *ext; - h2o_mimemap_type_t *type; - - kh_foreach(mimemap->extmap, ext, type, { - switch (type->type) { - case H2O_MIMEMAP_TYPE_DYNAMIC: - h2o_context_dispose_pathconf_context(ctx, &type->data.dynamic.pathconf); - break; - case H2O_MIMEMAP_TYPE_MIMETYPE: - break; - } - }); -} - -int h2o_mimemap_has_dynamic_type(h2o_mimemap_t *mimemap) -{ - return mimemap->num_dynamic != 0; -} - -void h2o_mimemap_set_default_type(h2o_mimemap_t *mimemap, const char *mime, h2o_mime_attributes_t *attr) -{ - h2o_mimemap_type_t *new_type; - - /* obtain or create new type */ - if ((new_type = h2o_mimemap_get_type_by_mimetype(mimemap, h2o_iovec_init(mime, strlen(mime)), 1)) != NULL && - (attr == NULL || memcmp(&new_type->data.attr, attr, sizeof(*attr)) == 0)) { - h2o_mem_addref_shared(new_type); - } else { - new_type = create_extension_type(mime, attr); - } - - /* unlink the old one */ - on_unlink(mimemap, mimemap->default_type); - h2o_mem_release_shared(mimemap->default_type); - - /* update */ - mimemap->default_type = new_type; - on_link(mimemap, new_type); - rebuild_typeset(mimemap); -} - -static void set_type(h2o_mimemap_t *mimemap, const char *ext, h2o_mimemap_type_t *type) -{ - /* obtain key, and remove the old value */ - khiter_t iter = kh_get(extmap, mimemap->extmap, ext); - if (iter != kh_end(mimemap->extmap)) { - h2o_mimemap_type_t *oldtype = kh_val(mimemap->extmap, iter); - on_unlink(mimemap, oldtype); - h2o_mem_release_shared(oldtype); - } else { - int ret; - iter = kh_put(extmap, mimemap->extmap, dupref(ext).base, &ret); - assert(iter != kh_end(mimemap->extmap)); - } - - /* update */ - h2o_mem_addref_shared(type); - kh_val(mimemap->extmap, iter) = type; - on_link(mimemap, type); - rebuild_typeset(mimemap); -} - -void h2o_mimemap_define_mimetype(h2o_mimemap_t *mimemap, const char *ext, const char *mime, h2o_mime_attributes_t *attr) -{ - h2o_mimemap_type_t *new_type; - - if ((new_type = h2o_mimemap_get_type_by_mimetype(mimemap, h2o_iovec_init(mime, strlen(mime)), 1)) != NULL && - (attr == NULL || memcmp(&new_type->data.attr, attr, sizeof(*attr)) == 0)) { - h2o_mem_addref_shared(new_type); - } else { - new_type = create_extension_type(mime, attr); - } - set_type(mimemap, ext, new_type); - h2o_mem_release_shared(new_type); -} - -h2o_mimemap_type_t *h2o_mimemap_define_dynamic(h2o_mimemap_t *mimemap, const char **exts, h2o_globalconf_t *globalconf) -{ - /* FIXME: fix memory leak introduced by this a cyclic link (mimemap -> new_type -> mimemap) - * note also that we may want to update the reference from the dynamic type to the mimemap as we clone the mimemap, - * but doing so naively would cause unnecessary copies of fastcgi.spawns... */ - h2o_mimemap_type_t *new_type = create_dynamic_type(globalconf, mimemap); - size_t i; - - for (i = 0; exts[i] != NULL; ++i) - set_type(mimemap, exts[i], new_type); - h2o_mem_release_shared(new_type); - return new_type; -} - -void h2o_mimemap_remove_type(h2o_mimemap_t *mimemap, const char *ext) -{ - khiter_t iter = kh_get(extmap, mimemap->extmap, ext); - if (iter != kh_end(mimemap->extmap)) { - const char *key = kh_key(mimemap->extmap, iter); - h2o_mimemap_type_t *type = kh_val(mimemap->extmap, iter); - on_unlink(mimemap, type); - h2o_mem_release_shared(type); - kh_del(extmap, mimemap->extmap, iter); - h2o_mem_release_shared((char *)key); - rebuild_typeset(mimemap); - } -} - -void h2o_mimemap_clear_types(h2o_mimemap_t *mimemap) -{ - khiter_t iter; - - for (iter = kh_begin(mimemap->extmap); iter != kh_end(mimemap->extmap); ++iter) { - if (!kh_exist(mimemap->extmap, iter)) continue; - const char *key = kh_key(mimemap->extmap, iter); - h2o_mimemap_type_t *type = kh_val(mimemap->extmap, iter); - on_unlink(mimemap, type); - h2o_mem_release_shared(type); - kh_del(extmap, mimemap->extmap, iter); - h2o_mem_release_shared((char *)key); - } - rebuild_typeset(mimemap); -} - -h2o_mimemap_type_t *h2o_mimemap_get_default_type(h2o_mimemap_t *mimemap) -{ - return mimemap->default_type; -} - -h2o_mimemap_type_t *h2o_mimemap_get_type_by_extension(h2o_mimemap_t *mimemap, h2o_iovec_t ext) -{ - char lcbuf[256]; - - if (0 < ext.len && ext.len < sizeof(lcbuf)) { - memcpy(lcbuf, ext.base, ext.len); - h2o_strtolower(lcbuf, ext.len); - lcbuf[ext.len] = '\0'; - khiter_t iter = kh_get(extmap, mimemap->extmap, lcbuf); - if (iter != kh_end(mimemap->extmap)) - return kh_val(mimemap->extmap, iter); - } - return mimemap->default_type; -} - -h2o_mimemap_type_t *h2o_mimemap_get_type_by_mimetype(h2o_mimemap_t *mimemap, h2o_iovec_t mime, int exact_match_only) -{ - h2o_mimemap_type_t key = {H2O_MIMEMAP_TYPE_MIMETYPE}; - khiter_t iter; - size_t type_end_at; - - /* exact match */ - key.data.mimetype = mime; - if ((iter = kh_get(typeset, mimemap->typeset, &key)) != kh_end(mimemap->typeset)) - return kh_key(mimemap->typeset, iter); - - if (!exact_match_only) { - /* determine the end of the type */ - for (type_end_at = 0; type_end_at != mime.len; ++type_end_at) - if (mime.base[type_end_at] == ';' || mime.base[type_end_at] == ' ') - goto HasAttributes; - } - return NULL; - -HasAttributes: - /* perform search without attributes */ - key.data.mimetype.len = type_end_at; - if ((iter = kh_get(typeset, mimemap->typeset, &key)) != kh_end(mimemap->typeset)) - return kh_key(mimemap->typeset, iter); - - return NULL; -} - -void h2o_mimemap_get_default_attributes(const char *_mime, h2o_mime_attributes_t *attr) -{ - char *mime = alloca(strlen(_mime) + 1); - strcpy(mime, _mime); - - const char *type_end_at; - - if ((type_end_at = strchr(mime, ';')) == NULL) - type_end_at = mime + strlen(mime); - - *attr = (h2o_mime_attributes_t){0}; - - if (h2o_memis(mime, type_end_at - mime, H2O_STRLIT("text/css")) || - h2o_memis(mime, type_end_at - mime, H2O_STRLIT("application/ecmascript")) || - h2o_memis(mime, type_end_at - mime, H2O_STRLIT("application/javascript")) || - h2o_memis(mime, type_end_at - mime, H2O_STRLIT("text/ecmascript")) || - h2o_memis(mime, type_end_at - mime, H2O_STRLIT("text/javascript"))) { - attr->is_compressible = 1; - attr->priority = H2O_MIME_ATTRIBUTE_PRIORITY_HIGHEST; - } else if (h2o_memis(mime, type_end_at - mime, H2O_STRLIT("application/json")) || strncmp(mime, "text/", 5) == 0 || - h2o_strstr(mime, type_end_at - mime, H2O_STRLIT("+xml")) != SIZE_MAX) { - attr->is_compressible = 1; - } -} diff --git a/web/server/h2o/libh2o/lib/handler/mimemap/defaults.c.h b/web/server/h2o/libh2o/lib/handler/mimemap/defaults.c.h deleted file mode 100644 index a395e0ccb..000000000 --- a/web/server/h2o/libh2o/lib/handler/mimemap/defaults.c.h +++ /dev/null @@ -1,109 +0,0 @@ -MIMEMAP("3gp", "video/3gpp") -MIMEMAP("3gpp", "video/3gpp") -MIMEMAP("7z", "application/x-7z-compressed") -MIMEMAP("ai", "application/postscript") -MIMEMAP("apng", "image/apng") -MIMEMAP("asf", "video/x-ms-asf") -MIMEMAP("asx", "video/x-ms-asf") -MIMEMAP("atom", "application/atom+xml") -MIMEMAP("avi", "video/x-msvideo") -MIMEMAP("bin", "application/octet-stream") -MIMEMAP("bmp", "image/x-ms-bmp") -MIMEMAP("cco", "application/x-cocoa") -MIMEMAP("crt", "application/x-x509-ca-cert") -MIMEMAP("css", "text/css") -MIMEMAP("csv", "text/csv") -MIMEMAP("deb", "application/octet-stream") -MIMEMAP("der", "application/x-x509-ca-cert") -MIMEMAP("dll", "application/octet-stream") -MIMEMAP("dmg", "application/octet-stream") -MIMEMAP("doc", "application/msword") -MIMEMAP("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document") -MIMEMAP("ear", "application/java-archive") -MIMEMAP("eot", "application/vnd.ms-fontobject") -MIMEMAP("eps", "application/postscript") -MIMEMAP("exe", "application/octet-stream") -MIMEMAP("flv", "video/x-flv") -MIMEMAP("gif", "image/gif") -MIMEMAP("hqx", "application/mac-binhex40") -MIMEMAP("htc", "text/x-component") -MIMEMAP("htm", "text/html") -MIMEMAP("html", "text/html") -MIMEMAP("ico", "image/x-icon") -MIMEMAP("img", "application/octet-stream") -MIMEMAP("iso", "application/octet-stream") -MIMEMAP("jad", "text/vnd.sun.j2me.app-descriptor") -MIMEMAP("jar", "application/java-archive") -MIMEMAP("jardiff", "application/x-java-archive-diff") -MIMEMAP("jng", "image/x-jng") -MIMEMAP("jnlp", "application/x-java-jnlp-file") -MIMEMAP("jpeg", "image/jpeg") -MIMEMAP("jpg", "image/jpeg") -MIMEMAP("jxr", "image/jxr") -MIMEMAP("js", "application/javascript") -MIMEMAP("json", "application/json") -MIMEMAP("kar", "audio/midi") -MIMEMAP("kml", "application/vnd.google-earth.kml+xml") -MIMEMAP("kmz", "application/vnd.google-earth.kmz") -MIMEMAP("m3u8", "application/vnd.apple.mpegurl") -MIMEMAP("m4a", "audio/x-m4a") -MIMEMAP("m4v", "video/x-m4v") -MIMEMAP("md", "text/markdown") -MIMEMAP("mid", "audio/midi") -MIMEMAP("midi", "audio/midi") -MIMEMAP("mml", "text/mathml") -MIMEMAP("mng", "video/x-mng") -MIMEMAP("mov", "video/quicktime") -MIMEMAP("mp3", "audio/mpeg") -MIMEMAP("mp4", "video/mp4") -MIMEMAP("mpeg", "video/mpeg") -MIMEMAP("mpg", "video/mpeg") -MIMEMAP("msi", "application/octet-stream") -MIMEMAP("msm", "application/octet-stream") -MIMEMAP("msp", "application/octet-stream") -MIMEMAP("ogg", "audio/ogg") -MIMEMAP("opus", "audio/ogg") -MIMEMAP("pdb", "application/x-pilot") -MIMEMAP("pdf", "application/pdf") -MIMEMAP("pem", "application/x-x509-ca-cert") -MIMEMAP("pl", "application/x-perl") -MIMEMAP("pm", "application/x-perl") -MIMEMAP("png", "image/png") -MIMEMAP("ppt", "application/vnd.ms-powerpoint") -MIMEMAP("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation") -MIMEMAP("prc", "application/x-pilot") -MIMEMAP("ps", "application/postscript") -MIMEMAP("ra", "audio/x-realaudio") -MIMEMAP("rar", "application/x-rar-compressed") -MIMEMAP("rpm", "application/x-redhat-package-manager") -MIMEMAP("rss", "application/rss+xml") -MIMEMAP("rtf", "application/rtf") -MIMEMAP("run", "application/x-makeself") -MIMEMAP("sea", "application/x-sea") -MIMEMAP("shtml", "text/html") -MIMEMAP("sit", "application/x-stuffit") -MIMEMAP("svg", "image/svg+xml") -MIMEMAP("svgz", "image/svg+xml") -MIMEMAP("swf", "application/x-shockwave-flash") -MIMEMAP("tcl", "application/x-tcl") -MIMEMAP("tif", "image/tiff") -MIMEMAP("tiff", "image/tiff") -MIMEMAP("tk", "application/x-tcl") -MIMEMAP("ts", "video/mp2t") -MIMEMAP("txt", "text/plain") -MIMEMAP("war", "application/java-archive") -MIMEMAP("wbmp", "image/vnd.wap.wbmp") -MIMEMAP("webm", "video/webm") -MIMEMAP("webp", "image/webp") -MIMEMAP("wml", "text/vnd.wap.wml") -MIMEMAP("wmlc", "application/vnd.wap.wmlc") -MIMEMAP("wmv", "video/x-ms-wmv") -MIMEMAP("woff", "application/font-woff") -MIMEMAP("woff2", "font/woff2") -MIMEMAP("xhtml", "application/xhtml+xml") -MIMEMAP("xls", "application/vnd.ms-excel") -MIMEMAP("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") -MIMEMAP("xml", "text/xml") -MIMEMAP("xpi", "application/x-xpinstall") -MIMEMAP("xspf", "application/xspf+xml") -MIMEMAP("zip", "application/zip") diff --git a/web/server/h2o/libh2o/lib/handler/mruby.c b/web/server/h2o/libh2o/lib/handler/mruby.c deleted file mode 100644 index af2af53fd..000000000 --- a/web/server/h2o/libh2o/lib/handler/mruby.c +++ /dev/null @@ -1,938 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Ryosuke Matsumoto, - * Masayoshi Takahashi - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "h2o.h" -#include "h2o/mruby_.h" -#include "mruby/embedded.c.h" - -#define STATUS_FALLTHRU 399 -#define FALLTHRU_SET_PREFIX "x-fallthru-set-" - -#define FREEZE_STRING(v) MRB_SET_FROZEN_FLAG(mrb_obj_ptr(v)) - -__thread h2o_mruby_generator_t *h2o_mruby_current_generator = NULL; - -void h2o_mruby__assert_failed(mrb_state *mrb, const char *file, int line) -{ - mrb_value obj = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); - struct RString *error = mrb_str_ptr(obj); - fprintf(stderr, "unexpected ruby error at file: \"%s\", line %d: %s", file, line, error->as.heap.ptr); - abort(); -} - -void h2o_mruby_setup_globals(mrb_state *mrb) -{ - const char *root = getenv("H2O_ROOT"); - if (root == NULL) - root = H2O_TO_STR(H2O_ROOT); - mrb_gv_set(mrb, mrb_intern_lit(mrb, "$H2O_ROOT"), mrb_str_new(mrb, root, strlen(root))); - - h2o_mruby_eval_expr(mrb, "$LOAD_PATH << \"#{$H2O_ROOT}/share/h2o/mruby\""); - h2o_mruby_assert(mrb); - - /* require core modules and include built-in libraries */ - h2o_mruby_eval_expr(mrb, "require \"#{$H2O_ROOT}/share/h2o/mruby/preloads.rb\""); - if (mrb->exc != NULL) { - if (mrb_obj_is_instance_of(mrb, mrb_obj_value(mrb->exc), mrb_class_get(mrb, "LoadError"))) { - fprintf(stderr, "file \"%s/%s\" not found. Did you forget to run `make install` ?", root, - "share/h2o/mruby/preloads.rb"); - } else { - mrb_value obj = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); - struct RString *error = mrb_str_ptr(obj); - fprintf(stderr, "an error occurred while loading %s/%s: %s", root, "share/h2o/mruby/preloads.rb", error->as.heap.ptr); - } - abort(); - } -} - -mrb_value h2o_mruby_to_str(mrb_state *mrb, mrb_value v) -{ - if (!mrb_string_p(v)) - H2O_MRUBY_EXEC_GUARD({ v = mrb_str_to_str(mrb, v); }); - return v; -} - -mrb_value h2o_mruby_eval_expr(mrb_state *mrb, const char *expr) -{ - return mrb_funcall(mrb, mrb_top_self(mrb), "eval", 1, mrb_str_new_cstr(mrb, expr)); -} - -void h2o_mruby_define_callback(mrb_state *mrb, const char *name, int id) -{ - mrb_value args[2]; - args[0] = mrb_str_new_cstr(mrb, name); - args[1] = mrb_fixnum_value(id); - mrb_funcall_argv(mrb, mrb_top_self(mrb), mrb_intern_lit(mrb, "_h2o_define_callback"), 2, args); - - if (mrb->exc != NULL) { - fprintf(stderr, "failed to define mruby function: %s\n", name); - h2o_mruby_assert(mrb); - } -} - -mrb_value h2o_mruby_create_data_instance(mrb_state *mrb, mrb_value class_obj, void *ptr, const mrb_data_type *type) -{ - struct RClass *klass = mrb_class_ptr(class_obj); - struct RData *data = mrb_data_object_alloc(mrb, klass, ptr, type); - return mrb_obj_value(data); -} - -mrb_value h2o_mruby_compile_code(mrb_state *mrb, h2o_mruby_config_vars_t *config, char *errbuf) -{ - mrbc_context *cxt; - struct mrb_parser_state *parser; - struct RProc *proc = NULL; - mrb_value result = mrb_nil_value(); - - /* parse */ - if ((cxt = mrbc_context_new(mrb)) == NULL) { - fprintf(stderr, "%s: no memory\n", H2O_MRUBY_MODULE_NAME); - abort(); - } - if (config->path != NULL) - mrbc_filename(mrb, cxt, config->path); - cxt->capture_errors = 1; - cxt->lineno = config->lineno; - if ((parser = mrb_parse_nstring(mrb, config->source.base, (int)config->source.len, cxt)) == NULL) { - fprintf(stderr, "%s: no memory\n", H2O_MRUBY_MODULE_NAME); - abort(); - } - /* return erro if errbuf is supplied, or abort */ - if (parser->nerr != 0) { - if (errbuf == NULL) { - fprintf(stderr, "%s: internal error (unexpected state)\n", H2O_MRUBY_MODULE_NAME); - abort(); - } - snprintf(errbuf, 256, "line %d:%s", parser->error_buffer[0].lineno, parser->error_buffer[0].message); - strcat(errbuf, "\n\n"); - if (h2o_str_at_position(errbuf + strlen(errbuf), config->source.base, config->source.len, - parser->error_buffer[0].lineno - config->lineno + 1, parser->error_buffer[0].column) != 0) { - /* remove trailing "\n\n" in case we failed to append the source code at the error location */ - errbuf[strlen(errbuf) - 2] = '\0'; - } - goto Exit; - } - /* generate code */ - if ((proc = mrb_generate_code(mrb, parser)) == NULL) { - fprintf(stderr, "%s: internal error (mrb_generate_code failed)\n", H2O_MRUBY_MODULE_NAME); - abort(); - } - - /* adjust stack length of toplevel environment (see https://github.com/h2o/h2o/issues/1464#issuecomment-337880408) */ - if (mrb->c->cibase->env) { - struct REnv *e = mrb->c->cibase->env; - if (MRB_ENV_STACK_LEN(e) < proc->body.irep->nlocals) - MRB_SET_ENV_STACK_LEN(e, proc->body.irep->nlocals); - } - - /* reset configuration context */ - h2o_mruby_eval_expr(mrb, "H2O::ConfigurationContext.reset"); - h2o_mruby_assert(mrb); - - /* run code and generate handler */ - result = mrb_run(mrb, proc, mrb_top_self(mrb)); - if (mrb->exc != NULL) { - mrb_value obj = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); - struct RString *error = mrb_str_ptr(obj); - snprintf(errbuf, 256, "%s", error->as.heap.ptr); - mrb->exc = 0; - result = mrb_nil_value(); - goto Exit; - } else if (mrb_nil_p(result)) { - snprintf(errbuf, 256, "returned value is not callable"); - goto Exit; - } - - /* call post_handler_generation hooks */ - mrb_funcall_argv(mrb, h2o_mruby_eval_expr(mrb, "H2O::ConfigurationContext.instance"), - mrb_intern_lit(mrb, "call_post_handler_generation_hooks"), 1, &result); - if (mrb->exc != NULL) { - mrb_value obj = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); - struct RString *error = mrb_str_ptr(obj); - snprintf(errbuf, 256, "%s", error->as.heap.ptr); - mrb->exc = 0; - result = mrb_nil_value(); - goto Exit; - } - -Exit: - mrb_parser_free(parser); - mrbc_context_free(mrb, cxt); - return result; -} - -static h2o_iovec_t convert_header_name_to_env(h2o_mem_pool_t *pool, const char *name, size_t len) -{ -#define KEY_PREFIX "HTTP_" -#define KEY_PREFIX_LEN (sizeof(KEY_PREFIX) - 1) - - h2o_iovec_t ret; - - ret.len = len + KEY_PREFIX_LEN; - ret.base = h2o_mem_alloc_pool(pool, ret.len); - - memcpy(ret.base, KEY_PREFIX, KEY_PREFIX_LEN); - - char *d = ret.base + KEY_PREFIX_LEN; - for (; len != 0; ++name, --len) - *d++ = *name == '-' ? '_' : h2o_toupper(*name); - - return ret; - -#undef KEY_PREFIX -#undef KEY_PREFIX_LEN -} - -static mrb_value build_constants(mrb_state *mrb, const char *server_name, size_t server_name_len) -{ - mrb_value ary = mrb_ary_new_capa(mrb, H2O_MRUBY_NUM_CONSTANTS); - mrb_int i; - - int gc_arena = mrb_gc_arena_save(mrb); - - { - h2o_mem_pool_t pool; - h2o_mem_init_pool(&pool); - for (i = 0; i != H2O_MAX_TOKENS; ++i) { - const h2o_token_t *token = h2o__tokens + i; - mrb_value lit = mrb_nil_value(); - if (token == H2O_TOKEN_CONTENT_TYPE) { - lit = mrb_str_new_lit(mrb, "CONTENT_TYPE"); - } else if (token->buf.len != 0) { - h2o_iovec_t n = convert_header_name_to_env(&pool, token->buf.base, token->buf.len); - lit = mrb_str_new(mrb, n.base, n.len); - } - if (mrb_string_p(lit)) { - FREEZE_STRING(lit); - mrb_ary_set(mrb, ary, i, lit); - } - } - h2o_mem_clear_pool(&pool); - } - -#define SET_STRING(idx, value) \ - do { \ - mrb_value lit = (value); \ - FREEZE_STRING(lit); \ - mrb_ary_set(mrb, ary, idx, lit); \ - } while (0) -#define SET_LITERAL(idx, str) SET_STRING(idx, mrb_str_new_lit(mrb, str)) - - SET_LITERAL(H2O_MRUBY_LIT_REQUEST_METHOD, "REQUEST_METHOD"); - SET_LITERAL(H2O_MRUBY_LIT_SCRIPT_NAME, "SCRIPT_NAME"); - SET_LITERAL(H2O_MRUBY_LIT_PATH_INFO, "PATH_INFO"); - SET_LITERAL(H2O_MRUBY_LIT_QUERY_STRING, "QUERY_STRING"); - SET_LITERAL(H2O_MRUBY_LIT_SERVER_NAME, "SERVER_NAME"); - SET_LITERAL(H2O_MRUBY_LIT_SERVER_ADDR, "SERVER_ADDR"); - SET_LITERAL(H2O_MRUBY_LIT_SERVER_PORT, "SERVER_PORT"); - SET_LITERAL(H2O_MRUBY_LIT_SERVER_PROTOCOL, "SERVER_PROTOCOL"); - SET_LITERAL(H2O_MRUBY_LIT_CONTENT_LENGTH, "CONTENT_LENGTH"); - SET_LITERAL(H2O_MRUBY_LIT_REMOTE_ADDR, "REMOTE_ADDR"); - SET_LITERAL(H2O_MRUBY_LIT_REMOTE_PORT, "REMOTE_PORT"); - SET_LITERAL(H2O_MRUBY_LIT_REMOTE_USER, "REMOTE_USER"); - SET_LITERAL(H2O_MRUBY_LIT_RACK_URL_SCHEME, "rack.url_scheme"); - SET_LITERAL(H2O_MRUBY_LIT_RACK_MULTITHREAD, "rack.multithread"); - SET_LITERAL(H2O_MRUBY_LIT_RACK_MULTIPROCESS, "rack.multiprocess"); - SET_LITERAL(H2O_MRUBY_LIT_RACK_RUN_ONCE, "rack.run_once"); - SET_LITERAL(H2O_MRUBY_LIT_RACK_HIJACK_, "rack.hijack?"); - SET_LITERAL(H2O_MRUBY_LIT_RACK_INPUT, "rack.input"); - SET_LITERAL(H2O_MRUBY_LIT_RACK_ERRORS, "rack.errors"); - SET_LITERAL(H2O_MRUBY_LIT_SERVER_SOFTWARE, "SERVER_SOFTWARE"); - SET_STRING(H2O_MRUBY_LIT_SERVER_SOFTWARE_VALUE, mrb_str_new(mrb, server_name, server_name_len)); - SET_LITERAL(H2O_MRUBY_LIT_SEPARATOR_COMMA, ", "); - SET_LITERAL(H2O_MRUBY_LIT_SEPARATOR_SEMICOLON, "; "); - -#undef SET_LITERAL -#undef SET_STRING - - h2o_mruby_eval_expr(mrb, H2O_MRUBY_CODE_CORE); - h2o_mruby_assert(mrb); - - mrb_ary_set(mrb, ary, H2O_MRUBY_PROC_EACH_TO_ARRAY, - mrb_funcall(mrb, mrb_obj_value(mrb->kernel_module), "_h2o_proc_each_to_array", 0)); - h2o_mruby_assert(mrb); - - /* sends exception using H2O_MRUBY_CALLBACK_ID_EXCEPTION_RAISED */ - mrb_ary_set(mrb, ary, H2O_MRUBY_PROC_APP_TO_FIBER, - mrb_funcall(mrb, mrb_obj_value(mrb->kernel_module), "_h2o_proc_app_to_fiber", 0)); - h2o_mruby_assert(mrb); - - mrb_gc_arena_restore(mrb, gc_arena); - return ary; -} - -static h2o_mruby_shared_context_t *create_shared_context(h2o_context_t *ctx) -{ - /* init mruby in every thread */ - h2o_mruby_shared_context_t *shared_ctx = h2o_mem_alloc(sizeof(*shared_ctx)); - if ((shared_ctx->mrb = mrb_open()) == NULL) { - fprintf(stderr, "%s: no memory\n", H2O_MRUBY_MODULE_NAME); - abort(); - } - h2o_mruby_setup_globals(shared_ctx->mrb); - shared_ctx->constants = build_constants(shared_ctx->mrb, ctx->globalconf->server_name.base, ctx->globalconf->server_name.len); - shared_ctx->symbols.sym_call = mrb_intern_lit(shared_ctx->mrb, "call"); - shared_ctx->symbols.sym_close = mrb_intern_lit(shared_ctx->mrb, "close"); - shared_ctx->symbols.sym_method = mrb_intern_lit(shared_ctx->mrb, "method"); - shared_ctx->symbols.sym_headers = mrb_intern_lit(shared_ctx->mrb, "headers"); - shared_ctx->symbols.sym_body = mrb_intern_lit(shared_ctx->mrb, "body"); - shared_ctx->symbols.sym_async = mrb_intern_lit(shared_ctx->mrb, "async"); - - h2o_mruby_send_chunked_init_context(shared_ctx); - h2o_mruby_http_request_init_context(shared_ctx); - - return shared_ctx; -} - -static void dispose_shared_context(void *data) -{ - if (data == NULL) - return; - h2o_mruby_shared_context_t *shared_ctx = (h2o_mruby_shared_context_t *)data; - mrb_close(shared_ctx->mrb); - free(shared_ctx); -} - -static h2o_mruby_shared_context_t *get_shared_context(h2o_context_t *ctx) -{ - static size_t key = SIZE_MAX; - void **data = h2o_context_get_storage(ctx, &key, dispose_shared_context); - if (*data == NULL) { - *data = create_shared_context(ctx); - } - return *data; -} - -static void on_context_init(h2o_handler_t *_handler, h2o_context_t *ctx) -{ - h2o_mruby_handler_t *handler = (void *)_handler; - h2o_mruby_context_t *handler_ctx = h2o_mem_alloc(sizeof(*handler_ctx)); - - handler_ctx->handler = handler; - handler_ctx->shared = get_shared_context(ctx); - - /* compile code (must be done for each thread) */ - int arena = mrb_gc_arena_save(handler_ctx->shared->mrb); - mrb_value proc = h2o_mruby_compile_code(handler_ctx->shared->mrb, &handler->config, NULL); - - handler_ctx->proc = - mrb_funcall_argv(handler_ctx->shared->mrb, mrb_ary_entry(handler_ctx->shared->constants, H2O_MRUBY_PROC_APP_TO_FIBER), - handler_ctx->shared->symbols.sym_call, 1, &proc); - h2o_mruby_assert(handler_ctx->shared->mrb); - mrb_gc_arena_restore(handler_ctx->shared->mrb, arena); - mrb_gc_protect(handler_ctx->shared->mrb, handler_ctx->proc); - - h2o_context_set_handler_context(ctx, &handler->super, handler_ctx); -} - -static void on_context_dispose(h2o_handler_t *_handler, h2o_context_t *ctx) -{ - h2o_mruby_handler_t *handler = (void *)_handler; - h2o_mruby_context_t *handler_ctx = h2o_context_get_handler_context(ctx, &handler->super); - - if (handler_ctx == NULL) - return; - - free(handler_ctx); -} - -static void on_handler_dispose(h2o_handler_t *_handler) -{ - h2o_mruby_handler_t *handler = (void *)_handler; - - free(handler->config.source.base); - free(handler->config.path); - free(handler); -} - -static void report_exception(h2o_req_t *req, mrb_state *mrb) -{ - mrb_value obj = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); - struct RString *error = mrb_str_ptr(obj); - h2o_req_log_error(req, H2O_MRUBY_MODULE_NAME, "mruby raised: %s\n", error->as.heap.ptr); - mrb->exc = NULL; -} - -static void stringify_address(h2o_conn_t *conn, socklen_t (*cb)(h2o_conn_t *conn, struct sockaddr *), mrb_state *mrb, - mrb_value *host, mrb_value *port) -{ - struct sockaddr_storage ss; - socklen_t sslen; - char buf[NI_MAXHOST]; - - *host = mrb_nil_value(); - *port = mrb_nil_value(); - - if ((sslen = cb(conn, (void *)&ss)) == 0) - return; - size_t l = h2o_socket_getnumerichost((void *)&ss, sslen, buf); - if (l != SIZE_MAX) - *host = mrb_str_new(mrb, buf, l); - int32_t p = h2o_socket_getport((void *)&ss); - if (p != -1) { - l = (int)sprintf(buf, "%" PRIu16, (uint16_t)p); - *port = mrb_str_new(mrb, buf, l); - } -} - -static void on_rack_input_free(mrb_state *mrb, const char *base, mrb_int len, void *_input_stream) -{ - /* reset ref to input_stream */ - mrb_value *input_stream = _input_stream; - *input_stream = mrb_nil_value(); -} - -static int build_env_sort_header_cb(const void *_x, const void *_y) -{ - const h2o_header_t *x = *(const h2o_header_t **)_x, *y = *(const h2o_header_t **)_y; - if (x->name->len < y->name->len) - return -1; - if (x->name->len > y->name->len) - return 1; - if (x->name->base != y->name->base) { - int r = memcmp(x->name->base, y->name->base, x->name->len); - if (r != 0) - return r; - } - assert(x != y); - /* the order of the headers having the same name needs to be retained */ - return x < y ? -1 : 1; -} - -static mrb_value build_path_info(mrb_state *mrb, h2o_req_t *req, size_t confpath_len_wo_slash) -{ - if (req->path_normalized.len == confpath_len_wo_slash) - return mrb_str_new_lit(mrb, ""); - - assert(req->path_normalized.len > confpath_len_wo_slash); - - size_t path_info_start, path_info_end = req->query_at != SIZE_MAX ? req->query_at : req->path.len; - - if (req->norm_indexes == NULL) { - path_info_start = confpath_len_wo_slash; - } else if (req->norm_indexes[0] == 0 && confpath_len_wo_slash == 0) { - /* path without leading slash */ - path_info_start = 0; - } else { - path_info_start = req->norm_indexes[confpath_len_wo_slash] - 1; - } - - return mrb_str_new(mrb, req->path.base + path_info_start, path_info_end - path_info_start); -} - -static mrb_value build_env(h2o_mruby_generator_t *generator) -{ - h2o_mruby_shared_context_t *shared = generator->ctx->shared; - mrb_state *mrb = shared->mrb; - mrb_value env = mrb_hash_new_capa(mrb, 16); - char http_version[sizeof("HTTP/1.0")]; - size_t http_version_sz; - - /* environment */ - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_REQUEST_METHOD), - mrb_str_new(mrb, generator->req->method.base, generator->req->method.len)); - - size_t confpath_len_wo_slash = generator->req->pathconf->path.len; - if (generator->req->pathconf->path.base[generator->req->pathconf->path.len - 1] == '/') - --confpath_len_wo_slash; - assert(confpath_len_wo_slash <= generator->req->path_normalized.len); - - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SCRIPT_NAME), - mrb_str_new(mrb, generator->req->pathconf->path.base, confpath_len_wo_slash)); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_PATH_INFO), build_path_info(mrb, generator->req, confpath_len_wo_slash)); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_QUERY_STRING), - generator->req->query_at != SIZE_MAX ? mrb_str_new(mrb, generator->req->path.base + generator->req->query_at + 1, - generator->req->path.len - (generator->req->query_at + 1)) - : mrb_str_new_lit(mrb, "")); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_NAME), - mrb_str_new(mrb, generator->req->hostconf->authority.host.base, generator->req->hostconf->authority.host.len)); - http_version_sz = h2o_stringify_protocol_version(http_version, generator->req->version); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_PROTOCOL), - mrb_str_new(mrb, http_version, http_version_sz)); - { - mrb_value h, p; - stringify_address(generator->req->conn, generator->req->conn->callbacks->get_sockname, mrb, &h, &p); - if (!mrb_nil_p(h)) - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_ADDR), h); - if (!mrb_nil_p(p)) - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_PORT), p); - } - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_TOKEN_HOST - h2o__tokens), - mrb_str_new(mrb, generator->req->authority.base, generator->req->authority.len)); - if (generator->req->entity.base != NULL) { - char buf[32]; - int l = sprintf(buf, "%zu", generator->req->entity.len); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_CONTENT_LENGTH), mrb_str_new(mrb, buf, l)); - generator->rack_input = mrb_input_stream_value(mrb, NULL, 0); - mrb_input_stream_set_data(mrb, generator->rack_input, generator->req->entity.base, (mrb_int)generator->req->entity.len, 0, - on_rack_input_free, &generator->rack_input); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_INPUT), generator->rack_input); - } - { - mrb_value h, p; - stringify_address(generator->req->conn, generator->req->conn->callbacks->get_peername, mrb, &h, &p); - if (!mrb_nil_p(h)) - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_REMOTE_ADDR), h); - if (!mrb_nil_p(p)) - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_REMOTE_PORT), p); - } - { - size_t i; - for (i = 0; i != generator->req->env.size; i += 2) { - h2o_iovec_t *name = generator->req->env.entries + i, *value = name + 1; - mrb_hash_set(mrb, env, mrb_str_new(mrb, name->base, name->len), mrb_str_new(mrb, value->base, value->len)); - } - } - - { /* headers */ - h2o_header_t **headers_sorted = alloca(sizeof(*headers_sorted) * generator->req->headers.size); - size_t i; - for (i = 0; i != generator->req->headers.size; ++i) - headers_sorted[i] = generator->req->headers.entries + i; - qsort(headers_sorted, generator->req->headers.size, sizeof(*headers_sorted), build_env_sort_header_cb); - for (i = 0; i != generator->req->headers.size; ++i) { - const h2o_header_t *header = headers_sorted[i]; - mrb_value n, v; - if (h2o_iovec_is_token(header->name)) { - const h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, header->name); - if (token == H2O_TOKEN_TRANSFER_ENCODING) - continue; - n = mrb_ary_entry(shared->constants, (mrb_int)(token - h2o__tokens)); - } else { - h2o_iovec_t vec = convert_header_name_to_env(&generator->req->pool, header->name->base, header->name->len); - n = mrb_str_new(mrb, vec.base, vec.len); - } - v = mrb_str_new(mrb, header->value.base, header->value.len); - while (i < generator->req->headers.size - 1) { - if (!h2o_memis(headers_sorted[i + 1]->name->base, headers_sorted[i + 1]->name->len, header->name->base, - header->name->len)) - break; - header = headers_sorted[++i]; - v = mrb_str_append(mrb, v, mrb_ary_entry(shared->constants, - header->name == &H2O_TOKEN_COOKIE->buf ? H2O_MRUBY_LIT_SEPARATOR_SEMICOLON - : H2O_MRUBY_LIT_SEPARATOR_COMMA)); - v = mrb_str_append(mrb, v, mrb_str_new(mrb, header->value.base, header->value.len)); - } - mrb_hash_set(mrb, env, n, v); - } - } - - /* rack.* */ - /* TBD rack.version? */ - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_URL_SCHEME), - mrb_str_new(mrb, generator->req->scheme->name.base, generator->req->scheme->name.len)); - /* we are using shared-none architecture, and therefore declare ourselves as multiprocess */ - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_MULTITHREAD), mrb_false_value()); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_MULTIPROCESS), mrb_true_value()); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_RUN_ONCE), mrb_false_value()); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_HIJACK_), mrb_false_value()); - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_ERRORS), - mrb_gv_get(mrb, mrb_intern_lit(mrb, "$stderr"))); - - /* server name */ - mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_SOFTWARE), - mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_SOFTWARE_VALUE)); - - return env; -} - -static int handle_response_header(h2o_mruby_context_t *handler_ctx, h2o_iovec_t name, h2o_iovec_t value, void *_req) -{ - h2o_req_t *req = _req; - const h2o_token_t *token; - static const h2o_iovec_t fallthru_set_prefix = {H2O_STRLIT(FALLTHRU_SET_PREFIX)}; - - /* convert name to lowercase */ - name = h2o_strdup(&req->pool, name.base, name.len); - h2o_strtolower(name.base, name.len); - - if ((token = h2o_lookup_token(name.base, name.len)) != NULL) { - if (token->proxy_should_drop_for_res) { - /* skip */ - } else if (token == H2O_TOKEN_CONTENT_LENGTH) { - req->res.content_length = h2o_strtosize(value.base, value.len); - } else { - value = h2o_strdup(&req->pool, value.base, value.len); - if (token == H2O_TOKEN_LINK) { - h2o_iovec_t new_value = h2o_push_path_in_link_header(req, value.base, value.len); - if (new_value.len) - h2o_add_header(&req->pool, &req->res.headers, token, NULL, new_value.base, new_value.len); - } else { - h2o_add_header(&req->pool, &req->res.headers, token, NULL, value.base, value.len); - } - } - } else if (name.len > fallthru_set_prefix.len && - h2o_memis(name.base, fallthru_set_prefix.len, fallthru_set_prefix.base, fallthru_set_prefix.len)) { - /* register environment variables (with the name converted to uppercase, and using `_`) */ - size_t i; - name.base += fallthru_set_prefix.len; - name.len -= fallthru_set_prefix.len; - for (i = 0; i != name.len; ++i) - name.base[i] = name.base[i] == '-' ? '_' : h2o_toupper(name.base[i]); - h2o_iovec_t *slot = h2o_req_getenv(req, name.base, name.len, 1); - *slot = h2o_strdup(&req->pool, value.base, value.len); - } else { - value = h2o_strdup(&req->pool, value.base, value.len); - h2o_add_header_by_str(&req->pool, &req->res.headers, name.base, name.len, 0, NULL, value.base, value.len); - } - - return 0; -} - -static void clear_rack_input(h2o_mruby_generator_t *generator) -{ - if (!mrb_nil_p(generator->rack_input)) - mrb_input_stream_set_data(generator->ctx->shared->mrb, generator->rack_input, NULL, -1, 0, NULL, NULL); -} - -static void on_generator_dispose(void *_generator) -{ - h2o_mruby_generator_t *generator = _generator; - - clear_rack_input(generator); - generator->req = NULL; - - if (generator->chunked != NULL) - h2o_mruby_send_chunked_dispose(generator); -} - -static int on_req(h2o_handler_t *_handler, h2o_req_t *req) -{ - h2o_mruby_handler_t *handler = (void *)_handler; - h2o_mruby_shared_context_t *shared = get_shared_context(req->conn->ctx); - int gc_arena = mrb_gc_arena_save(shared->mrb); - - h2o_mruby_generator_t *generator = h2o_mem_alloc_shared(&req->pool, sizeof(*generator), on_generator_dispose); - generator->super.proceed = NULL; - generator->super.stop = NULL; - generator->req = req; - generator->ctx = h2o_context_get_handler_context(req->conn->ctx, &handler->super); - generator->rack_input = mrb_nil_value(); - generator->chunked = NULL; - - mrb_value env = build_env(generator); - - int is_delegate = 0; - h2o_mruby_run_fiber(generator, generator->ctx->proc, env, &is_delegate); - - mrb_gc_arena_restore(shared->mrb, gc_arena); - if (is_delegate) - return -1; - return 0; -} - -static void send_response(h2o_mruby_generator_t *generator, mrb_int status, mrb_value resp, int *is_delegate) -{ - mrb_state *mrb = generator->ctx->shared->mrb; - mrb_value body; - h2o_iovec_t content = {NULL}; - - /* set status */ - generator->req->res.status = (int)status; - - /* set headers */ - if (h2o_mruby_iterate_headers(generator->ctx, mrb_ary_entry(resp, 1), handle_response_header, generator->req) != 0) { - assert(mrb->exc != NULL); - goto GotException; - } - - /* return without processing body, if status is fallthru */ - if (generator->req->res.status == STATUS_FALLTHRU) { - if (is_delegate != NULL) - *is_delegate = 1; - else - h2o_delegate_request_deferred(generator->req, &generator->ctx->handler->super); - return; - } - - /* obtain body */ - body = mrb_ary_entry(resp, 2); - - /* flatten body if possible */ - if (mrb_array_p(body)) { - mrb_int i, len = RARRAY_LEN(body); - /* calculate the length of the output, while at the same time converting the elements of the output array to string */ - content.len = 0; - for (i = 0; i != len; ++i) { - mrb_value e = mrb_ary_entry(body, i); - if (!mrb_string_p(e)) { - e = h2o_mruby_to_str(mrb, e); - if (mrb->exc != NULL) - goto GotException; - mrb_ary_set(mrb, body, i, e); - } - content.len += RSTRING_LEN(e); - } - /* allocate memory, and copy the response */ - char *dst = content.base = h2o_mem_alloc_pool(&generator->req->pool, content.len); - for (i = 0; i != len; ++i) { - mrb_value e = mrb_ary_entry(body, i); - assert(mrb_string_p(e)); - memcpy(dst, RSTRING_PTR(e), RSTRING_LEN(e)); - dst += RSTRING_LEN(e); - } - /* reset body to nil, now that we have read all data */ - body = mrb_nil_value(); - } - - /* use fiber in case we need to call #each */ - if (!mrb_nil_p(body)) { - h2o_start_response(generator->req, &generator->super); - mrb_value receiver = h2o_mruby_send_chunked_init(generator, body); - if (!mrb_nil_p(receiver)) - h2o_mruby_run_fiber(generator, receiver, body, 0); - return; - } - - /* send the entire response immediately */ - if (status == 101 || status == 204 || status == 304 || - h2o_memis(generator->req->input.method.base, generator->req->input.method.len, H2O_STRLIT("HEAD"))) { - h2o_start_response(generator->req, &generator->super); - h2o_send(generator->req, NULL, 0, H2O_SEND_STATE_FINAL); - } else { - if (content.len < generator->req->res.content_length) { - generator->req->res.content_length = content.len; - } else { - content.len = generator->req->res.content_length; - } - h2o_start_response(generator->req, &generator->super); - h2o_send(generator->req, &content, 1, H2O_SEND_STATE_FINAL); - } - return; - -GotException: - report_exception(generator->req, mrb); - h2o_send_error_500(generator->req, "Internal Server Error", "Internal Server Error", 0); -} - -void h2o_mruby_run_fiber(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value input, int *is_delegate) -{ - mrb_state *mrb = generator->ctx->shared->mrb; - mrb_value output; - mrb_int status; - - if (!mrb_obj_eq(mrb, generator->ctx->proc, receiver)) { - mrb_gc_unregister(mrb, receiver); - mrb_gc_protect(mrb, receiver); - } - - h2o_mruby_current_generator = generator; - - while (1) { - /* send input to fiber */ - output = mrb_funcall_argv(mrb, receiver, generator->ctx->shared->symbols.sym_call, 1, &input); - if (mrb->exc != NULL) - goto GotException; - if (!mrb_array_p(output)) { - mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "rack app did not return an array")); - goto GotException; - } - /* fetch status */ - mrb_value v = mrb_to_int(mrb, mrb_ary_entry(output, 0)); - if (mrb->exc != NULL) - goto GotException; - status = mrb_fixnum(v); - /* take special action depending on the status code */ - if (status < 0) { - if (status == H2O_MRUBY_CALLBACK_ID_EXCEPTION_RAISED) { - mrb->exc = mrb_obj_ptr(mrb_ary_entry(output, 1)); - goto GotException; - } - receiver = mrb_ary_entry(output, 1); - int next_action = H2O_MRUBY_CALLBACK_NEXT_ACTION_IMMEDIATE; - mrb_value args = mrb_ary_entry(output, 2); - if (mrb_array_p(args)) { - switch (status) { - case H2O_MRUBY_CALLBACK_ID_SEND_CHUNKED_EOS: - input = h2o_mruby_send_chunked_eos_callback(generator, receiver, args, &next_action); - break; - case H2O_MRUBY_CALLBACK_ID_HTTP_JOIN_RESPONSE: - input = h2o_mruby_http_join_response_callback(generator, receiver, args, &next_action); - break; - case H2O_MRUBY_CALLBACK_ID_HTTP_FETCH_CHUNK: - input = h2o_mruby_http_fetch_chunk_callback(generator, receiver, args, &next_action); - break; - default: - input = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "unexpected callback id sent from rack app"); - break; - } - } else { - input = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "callback from rack app did not receive an array arg"); - } - switch (next_action) { - case H2O_MRUBY_CALLBACK_NEXT_ACTION_STOP: - return; - case H2O_MRUBY_CALLBACK_NEXT_ACTION_ASYNC: - goto Async; - default: - assert(next_action == H2O_MRUBY_CALLBACK_NEXT_ACTION_IMMEDIATE); - break; - } - goto Next; - } - /* if no special actions were necessary, then the output is a rack response */ - break; - Next: - mrb_gc_protect(mrb, receiver); - mrb_gc_protect(mrb, input); - } - - h2o_mruby_current_generator = NULL; - - if (!(100 <= status && status <= 999)) { - mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "status returned from rack app is out of range")); - goto GotException; - } - - /* send the response (unless req is already closed) */ - if (generator->req == NULL) - return; - if (generator->req->_generator != NULL) { - mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "unexpectedly received a rack response")); - goto GotException; - } - send_response(generator, status, output, is_delegate); - return; - -GotException: - h2o_mruby_current_generator = NULL; - if (generator->req != NULL) { - report_exception(generator->req, mrb); - if (generator->req->_generator == NULL) { - h2o_send_error_500(generator->req, "Internal Server Error", "Internal Server Error", 0); - } else { - h2o_mruby_send_chunked_close(generator); - } - } - return; - -Async: - h2o_mruby_current_generator = NULL; - if (!mrb_obj_eq(mrb, generator->ctx->proc, receiver)) - mrb_gc_register(mrb, receiver); - return; -} - -h2o_mruby_handler_t *h2o_mruby_register(h2o_pathconf_t *pathconf, h2o_mruby_config_vars_t *vars) -{ - h2o_mruby_handler_t *handler = (void *)h2o_create_handler(pathconf, sizeof(*handler)); - - handler->super.on_context_init = on_context_init; - handler->super.on_context_dispose = on_context_dispose; - handler->super.dispose = on_handler_dispose; - handler->super.on_req = on_req; - handler->config.source = h2o_strdup(NULL, vars->source.base, vars->source.len); - if (vars->path != NULL) - handler->config.path = h2o_strdup(NULL, vars->path, SIZE_MAX).base; - handler->config.lineno = vars->lineno; - - return handler; -} - -mrb_value h2o_mruby_each_to_array(h2o_mruby_context_t *handler_ctx, mrb_value src) -{ - return mrb_funcall_argv(handler_ctx->shared->mrb, mrb_ary_entry(handler_ctx->shared->constants, H2O_MRUBY_PROC_EACH_TO_ARRAY), - handler_ctx->shared->symbols.sym_call, 1, &src); -} - -static int iterate_headers_handle_pair(h2o_mruby_context_t *handler_ctx, mrb_value name, mrb_value value, - int (*cb)(h2o_mruby_context_t *, h2o_iovec_t, h2o_iovec_t, void *), void *cb_data) -{ - mrb_state *mrb = handler_ctx->shared->mrb; - - /* convert name and value to string */ - name = h2o_mruby_to_str(mrb, name); - if (mrb->exc != NULL) - return -1; - value = h2o_mruby_to_str(mrb, value); - if (mrb->exc != NULL) - return -1; - - /* call the callback, splitting the values with '\n' */ - const char *vstart = RSTRING_PTR(value), *vend = vstart + RSTRING_LEN(value), *eol; - while (1) { - for (eol = vstart; eol != vend; ++eol) - if (*eol == '\n') - break; - if (cb(handler_ctx, h2o_iovec_init(RSTRING_PTR(name), RSTRING_LEN(name)), h2o_iovec_init(vstart, eol - vstart), cb_data) != - 0) - return -1; - if (eol == vend) - break; - vstart = eol + 1; - } - - return 0; -} - -int h2o_mruby_iterate_headers(h2o_mruby_context_t *handler_ctx, mrb_value headers, - int (*cb)(h2o_mruby_context_t *, h2o_iovec_t, h2o_iovec_t, void *), void *cb_data) -{ - mrb_state *mrb = handler_ctx->shared->mrb; - - if (!(mrb_hash_p(headers) || mrb_array_p(headers))) { - headers = h2o_mruby_each_to_array(handler_ctx, headers); - if (mrb->exc != NULL) - return -1; - assert(mrb_array_p(headers)); - } - - if (mrb_hash_p(headers)) { - mrb_value keys = mrb_hash_keys(mrb, headers); - mrb_int i, len = RARRAY_LEN(keys); - for (i = 0; i != len; ++i) { - mrb_value k = mrb_ary_entry(keys, i); - mrb_value v = mrb_hash_get(mrb, headers, k); - if (iterate_headers_handle_pair(handler_ctx, k, v, cb, cb_data) != 0) - return -1; - } - } else { - assert(mrb_array_p(headers)); - mrb_int i, len = RARRAY_LEN(headers); - for (i = 0; i != len; ++i) { - mrb_value pair = mrb_ary_entry(headers, i); - if (!mrb_array_p(pair)) { - mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_ARGUMENT_ERROR, "array element of headers MUST by an array")); - return -1; - } - if (iterate_headers_handle_pair(handler_ctx, mrb_ary_entry(pair, 0), mrb_ary_entry(pair, 1), cb, cb_data) != 0) - return -1; - } - } - - return 0; -} diff --git a/web/server/h2o/libh2o/lib/handler/mruby/chunked.c b/web/server/h2o/libh2o/lib/handler/mruby/chunked.c deleted file mode 100644 index 28e3ae433..000000000 --- a/web/server/h2o/libh2o/lib/handler/mruby/chunked.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2015-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 -#include -#include "h2o/mruby_.h" -#include "embedded.c.h" - -struct st_h2o_mruby_chunked_t { - h2o_doublebuffer_t sending; - size_t bytes_left; /* SIZE_MAX indicates that the number is undermined */ - enum { H2O_MRUBY_CHUNKED_TYPE_CALLBACK, H2O_MRUBY_CHUNKED_TYPE_SHORTCUT } type; - union { - struct { - h2o_buffer_t *receiving; - mrb_value body_obj; /* becomes nil on eos */ - } callback; - struct { - h2o_mruby_http_request_context_t *client; - h2o_buffer_t *remaining; - } shortcut; - }; -}; - -static void do_send(h2o_mruby_generator_t *generator, h2o_buffer_t **input, int is_final) -{ - h2o_mruby_chunked_t *chunked = generator->chunked; - - assert(chunked->sending.bytes_inflight == 0); - - h2o_iovec_t buf = h2o_doublebuffer_prepare(&chunked->sending, input, generator->req->preferred_chunk_size); - size_t bufcnt = 1; - - if (is_final && buf.len == chunked->sending.buf->size && (*input)->size == 0) { - if (buf.len == 0) - --bufcnt; - /* terminate the H1 connection if the length of content served did not match the value sent in content-length header */ - if (chunked->bytes_left != SIZE_MAX && chunked->bytes_left != 0) - generator->req->http1_is_persistent = 0; - } else { - if (buf.len == 0) - return; - is_final = 0; - } - - h2o_send(generator->req, &buf, bufcnt, is_final ? H2O_SEND_STATE_FINAL : H2O_SEND_STATE_IN_PROGRESS); -} - -static void do_proceed(h2o_generator_t *_generator, h2o_req_t *req) -{ - h2o_mruby_generator_t *generator = (void *)_generator; - h2o_mruby_chunked_t *chunked = generator->chunked; - h2o_buffer_t **input; - int is_final; - - h2o_doublebuffer_consume(&chunked->sending); - - switch (chunked->type) { - case H2O_MRUBY_CHUNKED_TYPE_CALLBACK: - input = &chunked->callback.receiving; - is_final = mrb_nil_p(chunked->callback.body_obj); - break; - case H2O_MRUBY_CHUNKED_TYPE_SHORTCUT: - if (chunked->shortcut.client != NULL) { - input = h2o_mruby_http_peek_content(chunked->shortcut.client, &is_final); - assert(!is_final); - } else { - input = &chunked->shortcut.remaining; - is_final = 1; - } - break; - default: - h2o_fatal("unexpected type"); - break; - } - - do_send(generator, input, is_final); -} - -static void on_shortcut_notify(h2o_mruby_generator_t *generator) -{ - h2o_mruby_chunked_t *chunked = generator->chunked; - int is_final; - h2o_buffer_t **input = h2o_mruby_http_peek_content(chunked->shortcut.client, &is_final); - - if (chunked->bytes_left != SIZE_MAX) { - if (chunked->bytes_left < (*input)->size) - (*input)->size = chunked->bytes_left; /* trim data too long */ - chunked->bytes_left -= (*input)->size; - } - - /* if final, steal socket input buffer to shortcut.remaining, and reset pointer to client */ - if (is_final) { - chunked->shortcut.remaining = *input; - h2o_buffer_init(input, &h2o_socket_buffer_prototype); - input = &chunked->shortcut.remaining; - chunked->shortcut.client = NULL; - } - - if (chunked->sending.bytes_inflight == 0) - do_send(generator, input, is_final); -} - -static void close_body_obj(h2o_mruby_generator_t *generator) -{ - h2o_mruby_chunked_t *chunked = generator->chunked; - mrb_state *mrb = generator->ctx->shared->mrb; - - if (!mrb_nil_p(chunked->callback.body_obj)) { - /* call close and throw away error */ - if (mrb_respond_to(mrb, chunked->callback.body_obj, generator->ctx->shared->symbols.sym_close)) - mrb_funcall_argv(mrb, chunked->callback.body_obj, generator->ctx->shared->symbols.sym_close, 0, NULL); - mrb->exc = NULL; - mrb_gc_unregister(mrb, chunked->callback.body_obj); - chunked->callback.body_obj = mrb_nil_value(); - } -} - -mrb_value h2o_mruby_send_chunked_init(h2o_mruby_generator_t *generator, mrb_value body) -{ - h2o_mruby_chunked_t *chunked = h2o_mem_alloc_pool(&generator->req->pool, sizeof(*chunked)); - h2o_doublebuffer_init(&chunked->sending, &h2o_socket_buffer_prototype); - chunked->bytes_left = h2o_memis(generator->req->method.base, generator->req->method.len, H2O_STRLIT("HEAD")) - ? 0 - : generator->req->res.content_length; - generator->super.proceed = do_proceed; - generator->chunked = chunked; - - if ((chunked->shortcut.client = h2o_mruby_http_set_shortcut(generator->ctx->shared->mrb, body, on_shortcut_notify)) != NULL) { - chunked->type = H2O_MRUBY_CHUNKED_TYPE_SHORTCUT; - chunked->shortcut.remaining = NULL; - on_shortcut_notify(generator); - return mrb_nil_value(); - } else { - chunked->type = H2O_MRUBY_CHUNKED_TYPE_CALLBACK; - h2o_buffer_init(&chunked->callback.receiving, &h2o_socket_buffer_prototype); - mrb_gc_register(generator->ctx->shared->mrb, body); - chunked->callback.body_obj = body; - return mrb_ary_entry(generator->ctx->shared->constants, H2O_MRUBY_CHUNKED_PROC_EACH_TO_FIBER); - } -} - -void h2o_mruby_send_chunked_dispose(h2o_mruby_generator_t *generator) -{ - h2o_mruby_chunked_t *chunked = generator->chunked; - - h2o_doublebuffer_dispose(&chunked->sending); - - switch (chunked->type) { - case H2O_MRUBY_CHUNKED_TYPE_CALLBACK: - h2o_buffer_dispose(&chunked->callback.receiving); - close_body_obj(generator); - break; - case H2O_MRUBY_CHUNKED_TYPE_SHORTCUT: - /* note: no need to free reference from chunked->client, since it is disposed at the same moment */ - if (chunked->shortcut.remaining != NULL) - h2o_buffer_dispose(&chunked->shortcut.remaining); - break; - } -} - -static mrb_value check_precond(mrb_state *mrb, h2o_mruby_generator_t *generator) -{ - if (generator == NULL || generator->req == NULL) - return mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "downstream HTTP closed"); - if (generator->req->_generator == NULL) - return mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "cannot send chunk before sending headers"); - return mrb_nil_value(); -} - -static mrb_value send_chunked_method(mrb_state *mrb, mrb_value self) -{ - h2o_mruby_generator_t *generator = h2o_mruby_current_generator; - const char *s; - mrb_int len; - - /* parse args */ - mrb_get_args(mrb, "s", &s, &len); - - { /* precond check */ - mrb_value exc = check_precond(mrb, generator); - if (!mrb_nil_p(exc)) - mrb_exc_raise(mrb, exc); - } - - /* append to send buffer, and send out immediately if necessary */ - if (len != 0) { - h2o_mruby_chunked_t *chunked = generator->chunked; - if (chunked->bytes_left != SIZE_MAX) { - if (len > chunked->bytes_left) - len = chunked->bytes_left; - chunked->bytes_left -= len; - } - if (len != 0) { - h2o_buffer_reserve(&chunked->callback.receiving, len); - memcpy(chunked->callback.receiving->bytes + chunked->callback.receiving->size, s, len); - chunked->callback.receiving->size += len; - if (chunked->sending.bytes_inflight == 0) - do_send(generator, &chunked->callback.receiving, 0); - } - } - - return mrb_nil_value(); -} - -mrb_value h2o_mruby_send_chunked_eos_callback(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value input, - int *next_action) -{ - mrb_state *mrb = generator->ctx->shared->mrb; - - { /* precond check */ - mrb_value exc = check_precond(mrb, generator); - if (!mrb_nil_p(exc)) - return exc; - } - - h2o_mruby_send_chunked_close(generator); - - *next_action = H2O_MRUBY_CALLBACK_NEXT_ACTION_STOP; - return mrb_nil_value(); -} - -void h2o_mruby_send_chunked_close(h2o_mruby_generator_t *generator) -{ - h2o_mruby_chunked_t *chunked = generator->chunked; - - /* run_fiber will never be called once we enter the fast path, and therefore this function will never get called in that case */ - assert(chunked->type == H2O_MRUBY_CHUNKED_TYPE_CALLBACK); - - close_body_obj(generator); - - if (chunked->sending.bytes_inflight == 0) - do_send(generator, &chunked->callback.receiving, 1); -} - -void h2o_mruby_send_chunked_init_context(h2o_mruby_shared_context_t *shared_ctx) -{ - mrb_state *mrb = shared_ctx->mrb; - - h2o_mruby_eval_expr(mrb, H2O_MRUBY_CODE_CHUNKED); - h2o_mruby_assert(mrb); - - mrb_define_method(mrb, mrb->kernel_module, "_h2o_send_chunk", send_chunked_method, MRB_ARGS_ARG(1, 0)); - h2o_mruby_define_callback(mrb, "_h2o_send_chunk_eos", H2O_MRUBY_CALLBACK_ID_SEND_CHUNKED_EOS); - - mrb_ary_set(mrb, shared_ctx->constants, H2O_MRUBY_CHUNKED_PROC_EACH_TO_FIBER, - mrb_funcall(mrb, mrb_top_self(mrb), "_h2o_chunked_proc_each_to_fiber", 0)); - h2o_mruby_assert(mrb); -} diff --git a/web/server/h2o/libh2o/lib/handler/mruby/embedded.c.h b/web/server/h2o/libh2o/lib/handler/mruby/embedded.c.h deleted file mode 100644 index db4bb2321..000000000 --- a/web/server/h2o/libh2o/lib/handler/mruby/embedded.c.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * DO NOT EDIT! generated by embed_mruby_code.pl - * Please refer to the respective source files for copyright information. - */ - -/* lib/handler/mruby/embedded/core.rb */ -#define H2O_MRUBY_CODE_CORE \ - "module Kernel\n" \ - " def _h2o_define_callback(name, id)\n" \ - " Kernel.define_method(name) do |*args|\n" \ - " ret = Fiber.yield([ id, _h2o_create_resumer(), args ])\n" \ - " if ret.kind_of? Exception\n" \ - " raise ret\n" \ - " end\n" \ - " ret\n" \ - " end\n" \ - " end\n" \ - " def _h2o_create_resumer()\n" \ - " me = Fiber.current\n" \ - " Proc.new do |v|\n" \ - " me.resume(v)\n" \ - " end\n" \ - " end\n" \ - " def _h2o_proc_each_to_array()\n" \ - " Proc.new do |o|\n" \ - " a = []\n" \ - " o.each do |x|\n" \ - " a << x\n" \ - " end\n" \ - " a\n" \ - " end\n" \ - " end\n" \ - " def _h2o_proc_app_to_fiber()\n" \ - " Proc.new do |app|\n" \ - " cached = nil\n" \ - " Proc.new do |req|\n" \ - " fiber = cached\n" \ - " cached = nil\n" \ - " if !fiber\n" \ - " fiber = Fiber.new do\n" \ - " self_fiber = Fiber.current\n" \ - " req = Fiber.yield\n" \ - " while 1\n" \ - " begin\n" \ - " while 1\n" \ - " resp = app.call(req)\n" \ - " cached = self_fiber\n" \ - " req = Fiber.yield(resp)\n" \ - " end\n" \ - " rescue => e\n" \ - " cached = self_fiber\n" \ - " req = Fiber.yield([-1, e])\n" \ - " end\n" \ - " end\n" \ - " end\n" \ - " fiber.resume\n" \ - " end\n" \ - " fiber.resume(req)\n" \ - " end\n" \ - " end\n" \ - " end\n" \ - "end\n" - -/* lib/handler/mruby/embedded/http_request.rb */ -#define H2O_MRUBY_CODE_HTTP_REQUEST \ - "module H2O\n" \ - " class HttpRequest\n" \ - " def join\n" \ - " if !@resp\n" \ - " @resp = _h2o__http_join_response(self)\n" \ - " end\n" \ - " @resp\n" \ - " end\n" \ - " def _set_response(resp)\n" \ - " @resp = resp\n" \ - " end\n" \ - " end\n" \ - " class HttpInputStream\n" \ - " def each\n" \ - " while c = _h2o__http_fetch_chunk(self)\n" \ - " yield c\n" \ - " end\n" \ - " end\n" \ - " def join\n" \ - " s = \"\"\n" \ - " each do |c|\n" \ - " s << c\n" \ - " end\n" \ - " s\n" \ - " end\n" \ - " class Empty < HttpInputStream\n" \ - " def each; end\n" \ - " end\n" \ - " end\n" \ - "end\n" - -/* lib/handler/mruby/embedded/chunked.rb */ -#define H2O_MRUBY_CODE_CHUNKED \ - "module Kernel\n" \ - " def _h2o_chunked_proc_each_to_fiber()\n" \ - " Proc.new do |src|\n" \ - " fiber = Fiber.new do\n" \ - " src.each do |chunk|\n" \ - " _h2o_send_chunk(chunk)\n" \ - " end\n" \ - " _h2o_send_chunk_eos()\n" \ - " end\n" \ - " fiber.resume\n" \ - " end\n" \ - " end\n" \ - "end\n" diff --git a/web/server/h2o/libh2o/lib/handler/mruby/embedded/chunked.rb b/web/server/h2o/libh2o/lib/handler/mruby/embedded/chunked.rb deleted file mode 100644 index ff4e578f8..000000000 --- a/web/server/h2o/libh2o/lib/handler/mruby/embedded/chunked.rb +++ /dev/null @@ -1,35 +0,0 @@ -# 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. - -module Kernel - - def _h2o_chunked_proc_each_to_fiber() - Proc.new do |src| - fiber = Fiber.new do - src.each do |chunk| - _h2o_send_chunk(chunk) - end - _h2o_send_chunk_eos() - end - fiber.resume - end - end - -end diff --git a/web/server/h2o/libh2o/lib/handler/mruby/embedded/core.rb b/web/server/h2o/libh2o/lib/handler/mruby/embedded/core.rb deleted file mode 100644 index e62583df4..000000000 --- a/web/server/h2o/libh2o/lib/handler/mruby/embedded/core.rb +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Ryosuke Matsumoto, -# Masayoshi Takahashi -# -# 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. - -module Kernel - - def _h2o_define_callback(name, id) - Kernel.define_method(name) do |*args| - ret = Fiber.yield([ id, _h2o_create_resumer(), args ]) - if ret.kind_of? Exception - raise ret - end - ret - end - end - - def _h2o_create_resumer() - me = Fiber.current - Proc.new do |v| - me.resume(v) - end - end - - def _h2o_proc_each_to_array() - Proc.new do |o| - a = [] - o.each do |x| - a << x - end - a - end - end - - def _h2o_proc_app_to_fiber() - Proc.new do |app| - cached = nil - Proc.new do |req| - fiber = cached - cached = nil - if !fiber - fiber = Fiber.new do - self_fiber = Fiber.current - req = Fiber.yield - while 1 - begin - while 1 - resp = app.call(req) - cached = self_fiber - req = Fiber.yield(resp) - end - rescue => e - cached = self_fiber - req = Fiber.yield([-1, e]) - end - end - end - fiber.resume - end - fiber.resume(req) - end - end - end - -end diff --git a/web/server/h2o/libh2o/lib/handler/mruby/embedded/http_request.rb b/web/server/h2o/libh2o/lib/handler/mruby/embedded/http_request.rb deleted file mode 100644 index 3f3247a3c..000000000 --- a/web/server/h2o/libh2o/lib/handler/mruby/embedded/http_request.rb +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2015-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. - -module H2O - - class HttpRequest - def join - if !@resp - @resp = _h2o__http_join_response(self) - end - @resp - end - def _set_response(resp) - @resp = resp - end - end - - class HttpInputStream - def each - while c = _h2o__http_fetch_chunk(self) - yield c - end - end - def join - s = "" - each do |c| - s << c - end - s - end - - class Empty < HttpInputStream - def each; end - end - end - -end diff --git a/web/server/h2o/libh2o/lib/handler/mruby/http_request.c b/web/server/h2o/libh2o/lib/handler/mruby/http_request.c deleted file mode 100644 index 964d03f19..000000000 --- a/web/server/h2o/libh2o/lib/handler/mruby/http_request.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (c) 2015-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 -#include -#include -#include "h2o/mruby_.h" -#include "embedded.c.h" - -struct st_h2o_mruby_http_request_context_t { - h2o_mruby_generator_t *generator; - h2o_http1client_t *client; - mrb_value receiver; - struct { - h2o_buffer_t *buf; - h2o_iovec_t body; /* body.base != NULL indicates that post content exists (and the length MAY be zero) */ - unsigned method_is_head : 1; - unsigned has_transfer_encoding : 1; - } req; - struct { - h2o_buffer_t *after_closed; /* when client becomes NULL, rest of the data will be stored to this pointer */ - int has_content; - } resp; - struct { - mrb_value request; - mrb_value input_stream; - } refs; - void (*shortcut_notify_cb)(h2o_mruby_generator_t *generator); -}; - -static void on_gc_dispose_request(mrb_state *mrb, void *_ctx) -{ - struct st_h2o_mruby_http_request_context_t *ctx = _ctx; - if (ctx != NULL) - ctx->refs.request = mrb_nil_value(); -} - -const static struct mrb_data_type request_type = {"http_request", on_gc_dispose_request}; - -static void on_gc_dispose_input_stream(mrb_state *mrb, void *_ctx) -{ - struct st_h2o_mruby_http_request_context_t *ctx = _ctx; - if (ctx != NULL) - ctx->refs.input_stream = mrb_nil_value(); -} - -const static struct mrb_data_type input_stream_type = {"http_input_stream", on_gc_dispose_input_stream}; - -static mrb_value create_downstream_closed_exception(mrb_state *mrb) -{ - return mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "downstream HTTP closed"); -} - -static mrb_value detach_receiver(struct st_h2o_mruby_http_request_context_t *ctx) -{ - mrb_value ret = ctx->receiver; - assert(!mrb_nil_p(ret)); - ctx->receiver = mrb_nil_value(); - return ret; -} - -static void on_dispose(void *_ctx) -{ - struct st_h2o_mruby_http_request_context_t *ctx = _ctx; - - /* clear the refs */ - if (ctx->client != NULL) { - h2o_http1client_cancel(ctx->client); - ctx->client = NULL; - } - if (!mrb_nil_p(ctx->refs.request)) - DATA_PTR(ctx->refs.request) = NULL; - if (!mrb_nil_p(ctx->refs.input_stream)) - DATA_PTR(ctx->refs.input_stream) = NULL; - - /* clear bufs */ - h2o_buffer_dispose(&ctx->req.buf); - h2o_buffer_dispose(&ctx->resp.after_closed); - - /* notify the app, if it is waiting to hear from us */ - if (!mrb_nil_p(ctx->receiver)) { - mrb_state *mrb = ctx->generator->ctx->shared->mrb; - int gc_arena = mrb_gc_arena_save(mrb); - h2o_mruby_run_fiber(ctx->generator, detach_receiver(ctx), create_downstream_closed_exception(mrb), NULL); - mrb_gc_arena_restore(mrb, gc_arena); - } -} - -static void post_response(struct st_h2o_mruby_http_request_context_t *ctx, int status, const h2o_header_t *headers_sorted, - size_t num_headers) -{ - mrb_state *mrb = ctx->generator->ctx->shared->mrb; - int gc_arena = mrb_gc_arena_save(mrb); - size_t i; - - mrb_value resp = mrb_ary_new_capa(mrb, 3); - - /* set status */ - mrb_ary_set(mrb, resp, 0, mrb_fixnum_value(status)); - - /* set headers */ - mrb_value headers_hash = mrb_hash_new_capa(mrb, (int)num_headers); - for (i = 0; i < num_headers; ++i) { - /* skip the headers, we determine the eos! */ - if (h2o_memis(headers_sorted[i].name, headers_sorted[i].name->len, H2O_STRLIT("content-length")) || - h2o_memis(headers_sorted[i].name, headers_sorted[i].name->len, H2O_STRLIT("transfer-encoding"))) - continue; - /* build and set the hash entry */ - mrb_value k = mrb_str_new(mrb, headers_sorted[i].name->base, headers_sorted[i].name->len); - mrb_value v = mrb_str_new(mrb, headers_sorted[i].value.base, headers_sorted[i].value.len); - while (i + 1 < num_headers && h2o_memis(headers_sorted[i].name->base, headers_sorted[i].name->len, - headers_sorted[i + 1].name->base, headers_sorted[i + 1].name->len)) { - ++i; - v = mrb_str_cat_lit(mrb, v, "\n"); - v = mrb_str_cat(mrb, v, headers_sorted[i].value.base, headers_sorted[i].value.len); - } - mrb_hash_set(mrb, headers_hash, k, v); - } - mrb_ary_set(mrb, resp, 1, headers_hash); - - /* set input stream */ - assert(mrb_nil_p(ctx->refs.input_stream)); - mrb_value input_stream_class; - if (ctx->req.method_is_head || status == 101 || status == 204 || status == 304) { - input_stream_class = mrb_ary_entry(ctx->generator->ctx->shared->constants, H2O_MRUBY_HTTP_EMPTY_INPUT_STREAM_CLASS); - } else { - input_stream_class = mrb_ary_entry(ctx->generator->ctx->shared->constants, H2O_MRUBY_HTTP_INPUT_STREAM_CLASS); - } - ctx->refs.input_stream = h2o_mruby_create_data_instance(mrb, input_stream_class, ctx, &input_stream_type); - mrb_ary_set(mrb, resp, 2, ctx->refs.input_stream); - - if (mrb_nil_p(ctx->receiver)) { - /* is async */ - mrb_funcall(mrb, ctx->refs.request, "_set_response", 1, resp); - if (mrb->exc != NULL) { - fprintf(stderr, "_set_response failed\n"); - abort(); - } - } else { - /* send response to the waiting receiver */ - h2o_mruby_run_fiber(ctx->generator, detach_receiver(ctx), resp, NULL); - } - - mrb_gc_arena_restore(mrb, gc_arena); -} - -static void post_error(struct st_h2o_mruby_http_request_context_t *ctx, const char *errstr) -{ - static const h2o_header_t headers_sorted[] = { - {&H2O_TOKEN_CONTENT_TYPE->buf, NULL, {H2O_STRLIT("text/plain; charset=utf-8")}}, - }; - - ctx->client = NULL; - size_t errstr_len = strlen(errstr); - h2o_buffer_reserve(&ctx->resp.after_closed, errstr_len); - memcpy(ctx->resp.after_closed->bytes + ctx->resp.after_closed->size, errstr, errstr_len); - ctx->resp.after_closed->size += errstr_len; - ctx->resp.has_content = 1; - - post_response(ctx, 500, headers_sorted, sizeof(headers_sorted) / sizeof(headers_sorted[0])); -} - -static mrb_value build_chunk(struct st_h2o_mruby_http_request_context_t *ctx) -{ - mrb_value chunk; - - assert(ctx->resp.has_content); - - if (ctx->client != NULL) { - assert(ctx->client->sock->input->size != 0); - chunk = mrb_str_new(ctx->generator->ctx->shared->mrb, ctx->client->sock->input->bytes, ctx->client->sock->input->size); - h2o_buffer_consume(&ctx->client->sock->input, ctx->client->sock->input->size); - ctx->resp.has_content = 0; - } else { - if (ctx->resp.after_closed->size == 0) { - chunk = mrb_nil_value(); - } else { - chunk = mrb_str_new(ctx->generator->ctx->shared->mrb, ctx->resp.after_closed->bytes, ctx->resp.after_closed->size); - h2o_buffer_consume(&ctx->resp.after_closed, ctx->resp.after_closed->size); - } - /* has_content is retained as true, so that repeated calls will return nil immediately */ - } - - return chunk; -} - -static int on_body(h2o_http1client_t *client, const char *errstr) -{ - struct st_h2o_mruby_http_request_context_t *ctx = client->data; - - if (errstr != NULL) { - h2o_buffer_t *tmp = ctx->resp.after_closed; - ctx->resp.after_closed = client->sock->input; - client->sock->input = tmp; - ctx->client = NULL; - ctx->resp.has_content = 1; - } else if (client->sock->input->size != 0) { - ctx->resp.has_content = 1; - } - - if (ctx->resp.has_content) { - if (ctx->shortcut_notify_cb != NULL) { - ctx->shortcut_notify_cb(ctx->generator); - } else if (!mrb_nil_p(ctx->receiver)) { - int gc_arena = mrb_gc_arena_save(ctx->generator->ctx->shared->mrb); - mrb_value chunk = build_chunk(ctx); - h2o_mruby_run_fiber(ctx->generator, detach_receiver(ctx), chunk, NULL); - mrb_gc_arena_restore(ctx->generator->ctx->shared->mrb, gc_arena); - } - } - return 0; -} - -static int headers_sort_cb(const void *_x, const void *_y) -{ - const h2o_header_t *x = _x, *y = _y; - - if (x->name->len < y->name->len) - return -1; - if (x->name->len > y->name->len) - return 1; - return memcmp(x->name->base, y->name->base, x->name->len); -} - -static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, - h2o_iovec_t msg, h2o_header_t *headers, size_t num_headers, int rlen) -{ - struct st_h2o_mruby_http_request_context_t *ctx = client->data; - - if (errstr != NULL) { - if (errstr != h2o_http1client_error_is_eos) { - /* error */ - post_error(ctx, errstr); - return NULL; - } - /* closed without body */ - ctx->client = NULL; - } - - qsort(headers, num_headers, sizeof(headers[0]), headers_sort_cb); - post_response(ctx, status, headers, num_headers); - return on_body; -} - -static h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr, h2o_iovec_t **reqbufs, size_t *reqbufcnt, - int *method_is_head) -{ - struct st_h2o_mruby_http_request_context_t *ctx = client->data; - - if (errstr != NULL) { - post_error(ctx, errstr); - return NULL; - } - - *reqbufs = h2o_mem_alloc_pool(&ctx->generator->req->pool, sizeof(**reqbufs) * 2); - **reqbufs = h2o_iovec_init(ctx->req.buf->bytes, ctx->req.buf->size); - *reqbufcnt = 1; - if (ctx->req.body.base != NULL) - (*reqbufs)[(*reqbufcnt)++] = ctx->req.body; - *method_is_head = ctx->req.method_is_head; - return on_head; -} - -static inline void append_to_buffer(h2o_buffer_t **buf, const void *src, size_t len) -{ - memcpy((*buf)->bytes + (*buf)->size, src, len); - (*buf)->size += len; -} - -static int flatten_request_header(h2o_mruby_context_t *handler_ctx, h2o_iovec_t name, h2o_iovec_t value, void *_ctx) -{ - struct st_h2o_mruby_http_request_context_t *ctx = _ctx; - - /* ignore certain headers */ - if (h2o_lcstris(name.base, name.len, H2O_STRLIT("content-length")) || - h2o_lcstris(name.base, name.len, H2O_STRLIT("connection")) || h2o_lcstris(name.base, name.len, H2O_STRLIT("host"))) - return 0; - - /* mark the existence of transfer-encoding in order to prevent us from adding content-length header */ - if (h2o_lcstris(name.base, name.len, H2O_STRLIT("transfer-encoding"))) - ctx->req.has_transfer_encoding = 1; - - h2o_buffer_reserve(&ctx->req.buf, name.len + value.len + sizeof(": \r\n") - 1); - append_to_buffer(&ctx->req.buf, name.base, name.len); - append_to_buffer(&ctx->req.buf, H2O_STRLIT(": ")); - append_to_buffer(&ctx->req.buf, value.base, value.len); - append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); - - return 0; -} - -static mrb_value http_request_method(mrb_state *mrb, mrb_value self) -{ - h2o_mruby_generator_t *generator; - struct st_h2o_mruby_http_request_context_t *ctx; - const char *arg_url; - mrb_int arg_url_len; - mrb_value arg_hash; - h2o_iovec_t method; - h2o_url_t url; - - /* parse args */ - arg_hash = mrb_nil_value(); - mrb_get_args(mrb, "s|H", &arg_url, &arg_url_len, &arg_hash); - - /* precond check */ - if ((generator = h2o_mruby_current_generator) == NULL || generator->req == NULL) - mrb_exc_raise(mrb, create_downstream_closed_exception(mrb)); - - /* allocate context and initialize */ - ctx = h2o_mem_alloc_shared(&generator->req->pool, sizeof(*ctx), on_dispose); - memset(ctx, 0, sizeof(*ctx)); - ctx->generator = generator; - ctx->receiver = mrb_nil_value(); - h2o_buffer_init(&ctx->req.buf, &h2o_socket_buffer_prototype); - h2o_buffer_init(&ctx->resp.after_closed, &h2o_socket_buffer_prototype); - ctx->refs.request = mrb_nil_value(); - ctx->refs.input_stream = mrb_nil_value(); - - /* uri */ - if (h2o_url_parse(arg_url, arg_url_len, &url) != 0) - mrb_raise(mrb, E_ARGUMENT_ERROR, "invaild URL"); - - /* method */ - method = h2o_iovec_init(H2O_STRLIT("GET")); - if (mrb_hash_p(arg_hash)) { - mrb_value t = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->shared->symbols.sym_method)); - if (!mrb_nil_p(t)) { - t = mrb_str_to_str(mrb, t); - method = h2o_iovec_init(RSTRING_PTR(t), RSTRING_LEN(t)); - if (h2o_memis(method.base, method.len, H2O_STRLIT("HEAD"))) { - ctx->req.method_is_head = 1; - } - } - } - - /* start building the request */ - h2o_buffer_reserve(&ctx->req.buf, method.len + 1); - append_to_buffer(&ctx->req.buf, method.base, method.len); - append_to_buffer(&ctx->req.buf, H2O_STRLIT(" ")); - h2o_buffer_reserve(&ctx->req.buf, - url.path.len + url.authority.len + sizeof(" HTTP/1.1\r\nConnection: close\r\nHost: \r\n") - 1); - append_to_buffer(&ctx->req.buf, url.path.base, url.path.len); - append_to_buffer(&ctx->req.buf, H2O_STRLIT(" HTTP/1.1\r\nConnection: close\r\nHost: ")); - append_to_buffer(&ctx->req.buf, url.authority.base, url.authority.len); - append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); - - /* headers */ - if (mrb_hash_p(arg_hash)) { - mrb_value headers = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->shared->symbols.sym_headers)); - if (!mrb_nil_p(headers)) { - if (h2o_mruby_iterate_headers(generator->ctx, headers, flatten_request_header, ctx) != 0) { - mrb_value exc = mrb_obj_value(mrb->exc); - mrb->exc = NULL; - mrb_exc_raise(mrb, exc); - } - } - } - /* body */ - if (mrb_hash_p(arg_hash)) { - mrb_value body = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->shared->symbols.sym_body)); - if (!mrb_nil_p(body)) { - if (mrb_obj_eq(mrb, body, generator->rack_input)) { - /* fast path */ - mrb_int pos; - mrb_input_stream_get_data(mrb, body, NULL, NULL, &pos, NULL, NULL); - ctx->req.body = generator->req->entity; - ctx->req.body.base += pos; - ctx->req.body.len -= pos; - } else { - if (!mrb_string_p(body)) { - body = mrb_funcall(mrb, body, "read", 0); - if (!mrb_string_p(body)) - mrb_raise(mrb, E_ARGUMENT_ERROR, "body.read did not return string"); - } - ctx->req.body = h2o_strdup(&ctx->generator->req->pool, RSTRING_PTR(body), RSTRING_LEN(body)); - } - if (!ctx->req.has_transfer_encoding) { - char buf[64]; - size_t l = (size_t)sprintf(buf, "content-length: %zu\r\n", ctx->req.body.len); - h2o_buffer_reserve(&ctx->req.buf, l); - append_to_buffer(&ctx->req.buf, buf, l); - } - } - } - - h2o_buffer_reserve(&ctx->req.buf, 2); - append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); - - /* build request and connect */ - ctx->refs.request = h2o_mruby_create_data_instance( - mrb, mrb_ary_entry(generator->ctx->shared->constants, H2O_MRUBY_HTTP_REQUEST_CLASS), ctx, &request_type); - h2o_http1client_connect(&ctx->client, ctx, &generator->req->conn->ctx->proxy.client_ctx, url.host, h2o_url_get_port(&url), - url.scheme == &H2O_URL_SCHEME_HTTPS, on_connect); - - return ctx->refs.request; -} - -mrb_value h2o_mruby_http_join_response_callback(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value args, - int *next_action) -{ - mrb_state *mrb = generator->ctx->shared->mrb; - struct st_h2o_mruby_http_request_context_t *ctx; - - if (generator->req == NULL) - return create_downstream_closed_exception(mrb); - - if ((ctx = mrb_data_check_get_ptr(mrb, mrb_ary_entry(args, 0), &request_type)) == NULL) - return mrb_exc_new_str_lit(mrb, E_ARGUMENT_ERROR, "HttpRequest#join wrong self"); - - ctx->receiver = receiver; - *next_action = H2O_MRUBY_CALLBACK_NEXT_ACTION_ASYNC; - return mrb_nil_value(); -} - -mrb_value h2o_mruby_http_fetch_chunk_callback(h2o_mruby_generator_t *generator, mrb_value receiver, mrb_value args, - int *next_action) -{ - mrb_state *mrb = generator->ctx->shared->mrb; - struct st_h2o_mruby_http_request_context_t *ctx; - mrb_value ret; - - if (generator->req == NULL) - return create_downstream_closed_exception(mrb); - - if ((ctx = mrb_data_check_get_ptr(mrb, mrb_ary_entry(args, 0), &input_stream_type)) == NULL) - return mrb_exc_new_str_lit(mrb, E_ARGUMENT_ERROR, "_HttpInputStream#each wrong self"); - - if (ctx->resp.has_content) { - ret = build_chunk(ctx); - } else { - ctx->receiver = receiver; - *next_action = H2O_MRUBY_CALLBACK_NEXT_ACTION_ASYNC; - ret = mrb_nil_value(); - } - - return ret; -} - -h2o_mruby_http_request_context_t *h2o_mruby_http_set_shortcut(mrb_state *mrb, mrb_value obj, void (*cb)(h2o_mruby_generator_t *)) -{ - struct st_h2o_mruby_http_request_context_t *ctx; - - if ((ctx = mrb_data_check_get_ptr(mrb, obj, &input_stream_type)) == NULL) - return NULL; - ctx->shortcut_notify_cb = cb; - return ctx; -} - -h2o_buffer_t **h2o_mruby_http_peek_content(h2o_mruby_http_request_context_t *ctx, int *is_final) -{ - *is_final = ctx->client == NULL; - return ctx->client != NULL && ctx->resp.has_content ? &ctx->client->sock->input : &ctx->resp.after_closed; -} - -void h2o_mruby_http_request_init_context(h2o_mruby_shared_context_t *ctx) -{ - mrb_state *mrb = ctx->mrb; - - h2o_mruby_eval_expr(mrb, H2O_MRUBY_CODE_HTTP_REQUEST); - h2o_mruby_assert(mrb); - - struct RClass *module, *klass; - module = mrb_define_module(mrb, "H2O"); - - mrb_define_method(mrb, mrb->kernel_module, "http_request", http_request_method, MRB_ARGS_ARG(1, 2)); - - klass = mrb_class_get_under(mrb, module, "HttpRequest"); - mrb_ary_set(mrb, ctx->constants, H2O_MRUBY_HTTP_REQUEST_CLASS, mrb_obj_value(klass)); - - klass = mrb_class_get_under(mrb, module, "HttpInputStream"); - mrb_ary_set(mrb, ctx->constants, H2O_MRUBY_HTTP_INPUT_STREAM_CLASS, mrb_obj_value(klass)); - - klass = mrb_class_get_under(mrb, klass, "Empty"); - mrb_ary_set(mrb, ctx->constants, H2O_MRUBY_HTTP_EMPTY_INPUT_STREAM_CLASS, mrb_obj_value(klass)); - - h2o_mruby_define_callback(mrb, "_h2o__http_join_response", H2O_MRUBY_CALLBACK_ID_HTTP_JOIN_RESPONSE); - h2o_mruby_define_callback(mrb, "_h2o__http_fetch_chunk", H2O_MRUBY_CALLBACK_ID_HTTP_FETCH_CHUNK); -} diff --git a/web/server/h2o/libh2o/lib/handler/proxy.c b/web/server/h2o/libh2o/lib/handler/proxy.c deleted file mode 100644 index 1d87225e1..000000000 --- a/web/server/h2o/libh2o/lib/handler/proxy.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2014,2015 DeNA Co., Ltd., Masahiro Nagano - * - * 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/socketpool.h" - -struct rp_handler_t { - h2o_handler_t super; - h2o_url_t upstream; /* host should be NULL-terminated */ - h2o_socketpool_t *sockpool; /* non-NULL if config.use_keepalive == 1 */ - h2o_proxy_config_vars_t config; -}; - -static int on_req(h2o_handler_t *_self, h2o_req_t *req) -{ - struct rp_handler_t *self = (void *)_self; - h2o_req_overrides_t *overrides = h2o_mem_alloc_pool(&req->pool, sizeof(*overrides)); - const h2o_url_scheme_t *scheme; - h2o_iovec_t *authority; - - /* setup overrides */ - *overrides = (h2o_req_overrides_t){NULL}; - if (self->sockpool != NULL) { - overrides->socketpool = self->sockpool; - } else if (self->config.preserve_host) { - overrides->hostport.host = self->upstream.host; - overrides->hostport.port = h2o_url_get_port(&self->upstream); - } - overrides->location_rewrite.match = &self->upstream; - overrides->location_rewrite.path_prefix = req->pathconf->path; - overrides->use_proxy_protocol = self->config.use_proxy_protocol; - overrides->client_ctx = h2o_context_get_handler_context(req->conn->ctx, &self->super); - overrides->headers_cmds = self->config.headers_cmds; - - /* determine the scheme and authority */ - if (self->config.preserve_host) { - scheme = req->scheme; - authority = &req->authority; - } else { - scheme = self->upstream.scheme; - authority = &self->upstream.authority; - } - - /* request reprocess */ - h2o_reprocess_request(req, req->method, scheme, *authority, - h2o_build_destination(req, self->upstream.path.base, self->upstream.path.len, 0), overrides, 0); - - return 0; -} - -static void on_context_init(h2o_handler_t *_self, h2o_context_t *ctx) -{ - struct rp_handler_t *self = (void *)_self; - - /* use the loop of first context for handling socketpool timeouts */ - if (self->sockpool != NULL && self->sockpool->timeout == UINT64_MAX) - h2o_socketpool_set_timeout(self->sockpool, ctx->loop, self->config.keepalive_timeout); - - /* setup a specific client context only if we need to */ - if (ctx->globalconf->proxy.io_timeout == self->config.io_timeout && !self->config.websocket.enabled && - self->config.ssl_ctx == ctx->globalconf->proxy.ssl_ctx) - return; - - h2o_http1client_ctx_t *client_ctx = h2o_mem_alloc(sizeof(*ctx)); - client_ctx->loop = ctx->loop; - client_ctx->getaddr_receiver = &ctx->receivers.hostinfo_getaddr; - if (ctx->globalconf->proxy.io_timeout == self->config.io_timeout) { - client_ctx->io_timeout = &ctx->proxy.io_timeout; - } else { - client_ctx->io_timeout = h2o_mem_alloc(sizeof(*client_ctx->io_timeout)); - h2o_timeout_init(client_ctx->loop, client_ctx->io_timeout, self->config.io_timeout); - } - if (self->config.websocket.enabled) { - /* FIXME avoid creating h2o_timeout_t for every path-level context in case the timeout values are the same */ - client_ctx->websocket_timeout = h2o_mem_alloc(sizeof(*client_ctx->websocket_timeout)); - h2o_timeout_init(client_ctx->loop, client_ctx->websocket_timeout, self->config.websocket.timeout); - } else { - client_ctx->websocket_timeout = NULL; - } - client_ctx->ssl_ctx = self->config.ssl_ctx; - - h2o_context_set_handler_context(ctx, &self->super, client_ctx); -} - -static void on_context_dispose(h2o_handler_t *_self, h2o_context_t *ctx) -{ - struct rp_handler_t *self = (void *)_self; - h2o_http1client_ctx_t *client_ctx = h2o_context_get_handler_context(ctx, &self->super); - - if (client_ctx == NULL) - return; - - if (client_ctx->io_timeout != &ctx->proxy.io_timeout) { - h2o_timeout_dispose(client_ctx->loop, client_ctx->io_timeout); - free(client_ctx->io_timeout); - } - if (client_ctx->websocket_timeout != NULL) { - h2o_timeout_dispose(client_ctx->loop, client_ctx->websocket_timeout); - free(client_ctx->websocket_timeout); - } - free(client_ctx); -} - -static void on_handler_dispose(h2o_handler_t *_self) -{ - struct rp_handler_t *self = (void *)_self; - - if (self->config.ssl_ctx != NULL) - SSL_CTX_free(self->config.ssl_ctx); - free(self->upstream.host.base); - free(self->upstream.path.base); - if (self->sockpool != NULL) { - h2o_socketpool_dispose(self->sockpool); - free(self->sockpool); - } -} - -void h2o_proxy_register_reverse_proxy(h2o_pathconf_t *pathconf, h2o_url_t *upstream, h2o_proxy_config_vars_t *config) -{ - struct sockaddr_un sa; - const char *to_sa_err; - struct rp_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self)); - self->super.on_context_init = on_context_init; - self->super.on_context_dispose = on_context_dispose; - self->super.dispose = on_handler_dispose; - self->super.on_req = on_req; - to_sa_err = h2o_url_host_to_sun(upstream->host, &sa); - if (config->keepalive_timeout != 0) { - self->sockpool = h2o_mem_alloc(sizeof(*self->sockpool)); - int is_ssl = upstream->scheme == &H2O_URL_SCHEME_HTTPS; - if (to_sa_err == h2o_url_host_to_sun_err_is_not_unix_socket) { - h2o_socketpool_init_by_hostport(self->sockpool, upstream->host, h2o_url_get_port(upstream), is_ssl, - SIZE_MAX /* FIXME */); - } else { - assert(to_sa_err == NULL); - h2o_socketpool_init_by_address(self->sockpool, (void *)&sa, sizeof(sa), is_ssl, SIZE_MAX /* FIXME */); - } - } - h2o_url_copy(NULL, &self->upstream, upstream); - if (to_sa_err) { - h2o_strtolower(self->upstream.host.base, self->upstream.host.len); - } - self->config = *config; - if (self->config.ssl_ctx != NULL) - SSL_CTX_up_ref(self->config.ssl_ctx); -} diff --git a/web/server/h2o/libh2o/lib/handler/redirect.c b/web/server/h2o/libh2o/lib/handler/redirect.c deleted file mode 100644 index c8b9c5086..000000000 --- a/web/server/h2o/libh2o/lib/handler/redirect.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 "h2o.h" - -#define MODULE_NAME "lib/handler/redirect.c" - -struct st_h2o_redirect_handler_t { - h2o_handler_t super; - int internal; - int status; - h2o_iovec_t prefix; -}; - -static void on_dispose(h2o_handler_t *_self) -{ - h2o_redirect_handler_t *self = (void *)_self; - free(self->prefix.base); -} - -static void redirect_internally(h2o_redirect_handler_t *self, h2o_req_t *req, h2o_iovec_t dest) -{ - h2o_iovec_t method; - h2o_url_t input, resolved; - - /* resolve the URL */ - if (h2o_url_parse_relative(dest.base, dest.len, &input) != 0) { - h2o_req_log_error(req, MODULE_NAME, "invalid destination:%.*s", (int)dest.len, dest.base); - goto SendInternalError; - } - if (input.scheme != NULL && input.authority.base != NULL) { - resolved = input; - } else { - h2o_url_t base; - /* we MUST to set authority to that of hostconf, or internal redirect might create a TCP connection */ - if (h2o_url_init(&base, req->scheme, req->hostconf->authority.hostport, req->path) != 0) { - h2o_req_log_error(req, MODULE_NAME, "failed to parse current authority:%.*s", (int)req->authority.len, - req->authority.base); - goto SendInternalError; - } - h2o_url_resolve(&req->pool, &base, &input, &resolved); - } - - /* determine the method */ - switch (self->status) { - case 307: - case 308: - method = req->method; - break; - default: - method = h2o_iovec_init(H2O_STRLIT("GET")); - req->entity = (h2o_iovec_t){NULL}; - break; - } - - h2o_reprocess_request_deferred(req, method, resolved.scheme, resolved.authority, resolved.path, NULL, 1); - return; - -SendInternalError: - h2o_send_error_503(req, "Internal Server Error", "internal server error", 0); -} - -static int on_req(h2o_handler_t *_self, h2o_req_t *req) -{ - h2o_redirect_handler_t *self = (void *)_self; - h2o_iovec_t dest = h2o_build_destination(req, self->prefix.base, self->prefix.len, 1); - - /* redirect */ - if (self->internal) { - redirect_internally(self, req, dest); - } else { - h2o_send_redirect(req, self->status, "Redirected", dest.base, dest.len); - } - - return 0; -} - -h2o_redirect_handler_t *h2o_redirect_register(h2o_pathconf_t *pathconf, int internal, int status, const char *prefix) -{ - h2o_redirect_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self)); - self->super.dispose = on_dispose; - self->super.on_req = on_req; - self->internal = internal; - self->status = status; - self->prefix = h2o_strdup(NULL, prefix, SIZE_MAX); - return self; -} diff --git a/web/server/h2o/libh2o/lib/handler/reproxy.c b/web/server/h2o/libh2o/lib/handler/reproxy.c deleted file mode 100644 index 369386d27..000000000 --- a/web/server/h2o/libh2o/lib/handler/reproxy.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Daisuke Maki - * - * 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" - -static void on_send(h2o_ostream_t *self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state) -{ - /* nothing to do */ -} - -static void on_setup_ostream(h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t **slot) -{ - h2o_iovec_t dest, method; - ssize_t xru_index; - - /* obtain x-reproxy-url header, or skip to next ostream */ - if ((xru_index = h2o_find_header(&req->res.headers, H2O_TOKEN_X_REPROXY_URL, -1)) == -1) { - h2o_setup_next_ostream(req, slot); - return; - } - dest = req->res.headers.entries[xru_index].value; - h2o_delete_header(&req->res.headers, xru_index); - - /* setup params */ - switch (req->res.status) { - case 307: - case 308: - method = req->method; - break; - default: - method = h2o_iovec_init(H2O_STRLIT("GET")); - req->entity = (h2o_iovec_t){NULL}; - break; - } - - /* request internal redirect (is deferred) */ - h2o_send_redirect_internal(req, method, dest.base, dest.len, 0); - - /* setup filter (that swallows the response until the timeout gets fired) */ - h2o_ostream_t *ostream = h2o_add_ostream(req, sizeof(*ostream), slot); - ostream->do_send = on_send; -} - -void h2o_reproxy_register(h2o_pathconf_t *pathconf) -{ - h2o_filter_t *self = h2o_create_filter(pathconf, sizeof(*self)); - self->on_setup_ostream = on_setup_ostream; -} diff --git a/web/server/h2o/libh2o/lib/handler/status.c b/web/server/h2o/libh2o/lib/handler/status.c deleted file mode 100644 index 93befed3b..000000000 --- a/web/server/h2o/libh2o/lib/handler/status.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * 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 "h2o.h" - -extern h2o_status_handler_t events_status_handler; -extern h2o_status_handler_t requests_status_handler; -extern h2o_status_handler_t durations_status_handler; - -struct st_h2o_status_logger_t { - h2o_logger_t super; -}; - -struct st_h2o_root_status_handler_t { - h2o_handler_t super; - H2O_VECTOR(h2o_multithread_receiver_t *) receivers; -}; - -struct st_h2o_status_context_t { - h2o_context_t *ctx; - h2o_multithread_receiver_t receiver; -}; - -struct st_status_ctx_t { - int active; - void *ctx; -}; -struct st_h2o_status_collector_t { - struct { - h2o_req_t *req; - h2o_multithread_receiver_t *receiver; - } src; - size_t num_remaining_threads_atomic; - H2O_VECTOR(struct st_status_ctx_t) status_ctx; -}; - -struct st_h2o_status_message_t { - h2o_multithread_message_t super; - struct st_h2o_status_collector_t *collector; -}; - -static void collect_reqs_of_context(struct st_h2o_status_collector_t *collector, h2o_context_t *ctx) -{ - int i; - - for (i = 0; i < ctx->globalconf->statuses.size; i++) { - struct st_status_ctx_t *sc = collector->status_ctx.entries + i; - h2o_status_handler_t *sh = ctx->globalconf->statuses.entries + i; - if (sc->active && sh->per_thread != NULL) - sh->per_thread(sc->ctx, ctx); - } - - if (__sync_sub_and_fetch(&collector->num_remaining_threads_atomic, 1) == 0) { - struct st_h2o_status_message_t *message = h2o_mem_alloc(sizeof(*message)); - message->super = (h2o_multithread_message_t){{NULL}}; - message->collector = collector; - h2o_multithread_send_message(collector->src.receiver, &message->super); - } -} - -static void send_response(struct st_h2o_status_collector_t *collector) -{ - static h2o_generator_t generator = {NULL, NULL}; - h2o_req_t *req; - size_t nr_statuses; - int i; - int cur_resp = 0; - - req = collector->src.req; - if (!req) { - h2o_mem_release_shared(collector); - return; - } - - nr_statuses = req->conn->ctx->globalconf->statuses.size; - size_t nr_resp = nr_statuses + 2; // 2 for the footer and header - h2o_iovec_t resp[nr_resp]; - - memset(resp, 0, sizeof(resp[0]) * nr_resp); - resp[cur_resp++] = (h2o_iovec_t){H2O_STRLIT("{\n")}; - - int coma_removed = 0; - for (i = 0; i < req->conn->ctx->globalconf->statuses.size; i++) { - h2o_status_handler_t *sh = &req->conn->ctx->globalconf->statuses.entries[i]; - if (!collector->status_ctx.entries[i].active) { - continue; - } - resp[cur_resp++] = sh->final(collector->status_ctx.entries[i].ctx, req->conn->ctx->globalconf, req); - if (resp[cur_resp - 1].len > 0 && !coma_removed) { - /* requests come in with a leading coma, replace if with a space */ - resp[cur_resp - 1].base[0] = ' '; - coma_removed = 1; - } - } - resp[cur_resp++] = (h2o_iovec_t){H2O_STRLIT("\n}\n")}; - - req->res.status = 200; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/plain; charset=utf-8")); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CACHE_CONTROL, NULL, H2O_STRLIT("no-cache, no-store")); - h2o_start_response(req, &generator); - h2o_send(req, resp, h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD")) ? 0 : nr_resp, - H2O_SEND_STATE_FINAL); - h2o_mem_release_shared(collector); -} - -static void on_collect_notify(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages) -{ - struct st_h2o_status_context_t *status_ctx = H2O_STRUCT_FROM_MEMBER(struct st_h2o_status_context_t, receiver, receiver); - - while (!h2o_linklist_is_empty(messages)) { - struct st_h2o_status_message_t *message = H2O_STRUCT_FROM_MEMBER(struct st_h2o_status_message_t, super, messages->next); - struct st_h2o_status_collector_t *collector = message->collector; - h2o_linklist_unlink(&message->super.link); - free(message); - - if (__sync_add_and_fetch(&collector->num_remaining_threads_atomic, 0) != 0) { - collect_reqs_of_context(collector, status_ctx->ctx); - } else { - send_response(collector); - } - } -} - -static void on_collector_dispose(void *_collector) -{ -} - -static void on_req_close(void *p) -{ - struct st_h2o_status_collector_t *collector = *(void **)p; - collector->src.req = NULL; - h2o_mem_release_shared(collector); -} - -static int on_req_json(struct st_h2o_root_status_handler_t *self, h2o_req_t *req, h2o_iovec_t status_list) -{ - { /* construct collector and send request to every thread */ - struct st_h2o_status_context_t *status_ctx = h2o_context_get_handler_context(req->conn->ctx, &self->super); - struct st_h2o_status_collector_t *collector = h2o_mem_alloc_shared(NULL, sizeof(*collector), on_collector_dispose); - size_t i; - - memset(collector, 0, sizeof(*collector)); - for (i = 0; i < req->conn->ctx->globalconf->statuses.size; i++) { - h2o_status_handler_t *sh; - - h2o_vector_reserve(&req->pool, &collector->status_ctx, collector->status_ctx.size + 1); - sh = &req->conn->ctx->globalconf->statuses.entries[i]; - - if (status_list.base) { - if (!h2o_contains_token(status_list.base, status_list.len, sh->name.base, sh->name.len, ',')) { - collector->status_ctx.entries[collector->status_ctx.size].active = 0; - goto Skip; - } - } - if (sh->init) { - collector->status_ctx.entries[collector->status_ctx.size].ctx = sh->init(); - } - collector->status_ctx.entries[collector->status_ctx.size].active = 1; - Skip: - collector->status_ctx.size++; - } - collector->src.req = req; - collector->src.receiver = &status_ctx->receiver; - collector->num_remaining_threads_atomic = self->receivers.size; - - for (i = 0; i != self->receivers.size; ++i) { - struct st_h2o_status_message_t *message = h2o_mem_alloc(sizeof(*message)); - *message = (struct st_h2o_status_message_t){{{NULL}}, collector}; - h2o_multithread_send_message(self->receivers.entries[i], &message->super); - } - - /* collector is also retained by the on_req_close callback */ - *(struct st_h2o_status_collector_t **)h2o_mem_alloc_shared(&req->pool, sizeof(collector), on_req_close) = collector; - h2o_mem_addref_shared(collector); - } - - return 0; -} - -static int on_req(h2o_handler_t *_self, h2o_req_t *req) -{ - struct st_h2o_root_status_handler_t *self = (void *)_self; - size_t prefix_len = req->pathconf->path.len - (req->pathconf->path.base[req->pathconf->path.len - 1] == '/'); - h2o_iovec_t local_path = h2o_iovec_init(req->path_normalized.base + prefix_len, req->path_normalized.len - prefix_len); - - if (local_path.len == 0 || h2o_memis(local_path.base, local_path.len, H2O_STRLIT("/"))) { - /* root of the handler returns HTML that renders the status */ - h2o_iovec_t fn; - const char *root = getenv("H2O_ROOT"); - if (root == NULL) - root = H2O_TO_STR(H2O_ROOT); - fn = h2o_concat(&req->pool, h2o_iovec_init(root, strlen(root)), h2o_iovec_init(H2O_STRLIT("/share/h2o/status/index.html"))); - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CACHE_CONTROL, NULL, H2O_STRLIT("no-cache")); - return h2o_file_send(req, 200, "OK", fn.base, h2o_iovec_init(H2O_STRLIT("text/html; charset=utf-8")), 0); - } else if (h2o_memis(local_path.base, local_path.len, H2O_STRLIT("/json"))) { - int ret; - /* "/json" maps to the JSON API */ - h2o_iovec_t status_list = {NULL, 0}; /* NULL means we'll show all statuses */ - if (req->query_at != SIZE_MAX && (req->path.len - req->query_at > 6)) { - if (h2o_memis(&req->path.base[req->query_at], 6, "?show=", 6)) { - status_list = h2o_iovec_init(&req->path.base[req->query_at + 6], req->path.len - req->query_at - 6); - } - } - ret = on_req_json(self, req, status_list); - return ret; - } - - return -1; -} - -static void on_context_init(h2o_handler_t *_self, h2o_context_t *ctx) -{ - struct st_h2o_root_status_handler_t *self = (void *)_self; - struct st_h2o_status_context_t *status_ctx = h2o_mem_alloc(sizeof(*status_ctx)); - - status_ctx->ctx = ctx; - h2o_multithread_register_receiver(ctx->queue, &status_ctx->receiver, on_collect_notify); - - h2o_vector_reserve(NULL, &self->receivers, self->receivers.size + 1); - self->receivers.entries[self->receivers.size++] = &status_ctx->receiver; - - h2o_context_set_handler_context(ctx, &self->super, status_ctx); -} - -static void on_context_dispose(h2o_handler_t *_self, h2o_context_t *ctx) -{ - struct st_h2o_root_status_handler_t *self = (void *)_self; - struct st_h2o_status_context_t *status_ctx = h2o_context_get_handler_context(ctx, &self->super); - size_t i; - - for (i = 0; i != self->receivers.size; ++i) - if (self->receivers.entries[i] == &status_ctx->receiver) - break; - assert(i != self->receivers.size); - memmove(self->receivers.entries + i + 1, self->receivers.entries + i, self->receivers.size - i - 1); - --self->receivers.size; - - h2o_multithread_unregister_receiver(ctx->queue, &status_ctx->receiver); - - free(status_ctx); -} - -void h2o_status_register(h2o_pathconf_t *conf) -{ - struct st_h2o_root_status_handler_t *self = (void *)h2o_create_handler(conf, sizeof(*self)); - self->super.on_context_init = on_context_init; - self->super.on_context_dispose = on_context_dispose; - self->super.on_req = on_req; - h2o_config_register_status_handler(conf->global, requests_status_handler); - h2o_config_register_status_handler(conf->global, events_status_handler); - h2o_config_register_status_handler(conf->global, durations_status_handler); -} diff --git a/web/server/h2o/libh2o/lib/handler/status/durations.c b/web/server/h2o/libh2o/lib/handler/status/durations.c deleted file mode 100644 index f011107bf..000000000 --- a/web/server/h2o/libh2o/lib/handler/status/durations.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2016 Fastly - * - * 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 "gkc.h" -#include -#include - -#define GK_EPSILON 0.01 - -struct st_duration_stats_t { - struct gkc_summary *connect_time; - struct gkc_summary *header_time; - struct gkc_summary *body_time; - struct gkc_summary *request_total_time; - struct gkc_summary *process_time; - struct gkc_summary *response_time; - struct gkc_summary *duration; -}; - -struct st_duration_agg_stats_t { - struct st_duration_stats_t stats; - pthread_mutex_t mutex; -}; - -static h2o_logger_t *durations_logger; -static void durations_status_per_thread(void *priv, h2o_context_t *ctx) -{ - struct st_duration_agg_stats_t *agg_stats = priv; - if (durations_logger) { - struct st_duration_stats_t *ctx_stats = h2o_context_get_logger_context(ctx, durations_logger); - pthread_mutex_lock(&agg_stats->mutex); -#define ADD_DURATION(x) \ - do { \ - struct gkc_summary *tmp; \ - tmp = gkc_combine(agg_stats->stats.x, ctx_stats->x); \ - gkc_summary_free(agg_stats->stats.x); \ - agg_stats->stats.x = tmp; \ - } while (0) - ADD_DURATION(connect_time); - ADD_DURATION(header_time); - ADD_DURATION(body_time); - ADD_DURATION(request_total_time); - ADD_DURATION(process_time); - ADD_DURATION(response_time); - ADD_DURATION(duration); -#undef ADD_DURATION - pthread_mutex_unlock(&agg_stats->mutex); - } -} - -static void duration_stats_init(struct st_duration_stats_t *stats) -{ - stats->connect_time = gkc_summary_alloc(GK_EPSILON); - stats->header_time = gkc_summary_alloc(GK_EPSILON); - stats->body_time = gkc_summary_alloc(GK_EPSILON); - stats->request_total_time = gkc_summary_alloc(GK_EPSILON); - stats->process_time = gkc_summary_alloc(GK_EPSILON); - stats->response_time = gkc_summary_alloc(GK_EPSILON); - stats->duration = gkc_summary_alloc(GK_EPSILON); -} - -static void *durations_status_init(void) -{ - struct st_duration_agg_stats_t *agg_stats; - - agg_stats = h2o_mem_alloc(sizeof(*agg_stats)); - - duration_stats_init(&agg_stats->stats); - pthread_mutex_init(&agg_stats->mutex, NULL); - - return agg_stats; -} - -static void duration_stats_free(struct st_duration_stats_t *stats) -{ - gkc_summary_free(stats->connect_time); - gkc_summary_free(stats->header_time); - gkc_summary_free(stats->body_time); - gkc_summary_free(stats->request_total_time); - gkc_summary_free(stats->process_time); - gkc_summary_free(stats->response_time); - gkc_summary_free(stats->duration); -} - -static h2o_iovec_t durations_status_final(void *priv, h2o_globalconf_t *gconf, h2o_req_t *req) -{ - struct st_duration_agg_stats_t *agg_stats = priv; - h2o_iovec_t ret; - -#define BUFSIZE 16384 -#define DURATION_FMT(x) \ - " \"" x "-0\": %lu,\n" \ - " \"" x "-25\": %lu,\n" \ - " \"" x "-50\": %lu,\n" \ - " \"" x "-75\": %lu,\n" \ - " \"" x "-99\": %lu\n" -#define DURATION_VALS(x) \ - gkc_query(agg_stats->stats.x, 0), gkc_query(agg_stats->stats.x, 0.25), gkc_query(agg_stats->stats.x, 0.5), \ - gkc_query(agg_stats->stats.x, 0.75), gkc_query(agg_stats->stats.x, 0.99) - - ret.base = h2o_mem_alloc_pool(&req->pool, BUFSIZE); - ret.len = snprintf( - ret.base, BUFSIZE, - ",\n" DURATION_FMT("connect-time") "," DURATION_FMT("header-time") "," DURATION_FMT("body-time") "," DURATION_FMT( - "request-total-time") "," DURATION_FMT("process-time") "," DURATION_FMT("response-time") "," DURATION_FMT("duration"), - DURATION_VALS(connect_time), DURATION_VALS(header_time), DURATION_VALS(body_time), DURATION_VALS(request_total_time), - DURATION_VALS(process_time), DURATION_VALS(response_time), DURATION_VALS(duration)); - -#undef BUFSIZE -#undef DURATION_FMT -#undef DURATION_VALS - - duration_stats_free(&agg_stats->stats); - pthread_mutex_destroy(&agg_stats->mutex); - - free(agg_stats); - return ret; -} - -static void stat_access(h2o_logger_t *_self, h2o_req_t *req) -{ - struct st_duration_stats_t *ctx_stats = h2o_context_get_logger_context(req->conn->ctx, _self); -#define ADD_OBSERVATION(x, from, until) \ - do { \ - int64_t dur; \ - if (h2o_time_compute_##x(req, &dur)) { \ - gkc_insert_value(ctx_stats->x, dur); \ - } \ - } while (0) - - ADD_OBSERVATION(connect_time, &req->conn->connected_at, &req->timestamps.request_begin_at); - ADD_OBSERVATION(header_time, &req->timestamps.request_begin_at, h2o_timeval_is_null(&req->timestamps.request_body_begin_at) - ? &req->processed_at.at - : &req->timestamps.request_body_begin_at); - ADD_OBSERVATION(body_time, h2o_timeval_is_null(&req->timestamps.request_body_begin_at) ? &req->processed_at.at - : &req->timestamps.request_body_begin_at, - &req->processed_at.at); - ADD_OBSERVATION(request_total_time, &req->timestamps.request_begin_at, &req->processed_at.at); - ADD_OBSERVATION(process_time, &req->processed_at.at, &req->timestamps.response_start_at); - ADD_OBSERVATION(response_time, &req->timestamps.response_start_at, &req->timestamps.response_end_at); - ADD_OBSERVATION(duration, &req->timestamps.request_begin_at, &req->timestamps.response_end_at); -#undef ADD_OBSERVATION -} - -void on_context_init(struct st_h2o_logger_t *self, h2o_context_t *ctx) -{ - struct st_duration_stats_t *duration_stats = h2o_mem_alloc(sizeof(struct st_duration_stats_t)); - duration_stats_init(duration_stats); - h2o_context_set_logger_context(ctx, self, duration_stats); -} - -void on_context_dispose(struct st_h2o_logger_t *self, h2o_context_t *ctx) -{ - struct st_duration_stats_t *duration_stats; - duration_stats = h2o_context_get_logger_context(ctx, self); - duration_stats_free(duration_stats); -} - -void h2o_duration_stats_register(h2o_globalconf_t *conf) -{ - int i, k; - h2o_logger_t *logger; - h2o_hostconf_t *hconf; - - durations_logger = logger = h2o_mem_alloc(sizeof(*logger)); - memset(logger, 0, sizeof(*logger)); - logger->_config_slot = conf->_num_config_slots++; - logger->log_access = stat_access; - logger->on_context_init = on_context_init; - logger->on_context_dispose = on_context_dispose; - - for (k = 0; conf->hosts[k]; k++) { - hconf = conf->hosts[k]; - for (i = 0; i < hconf->paths.size; i++) { - int j; - for (j = 0; j < hconf->paths.entries[i].handlers.size; j++) { - h2o_pathconf_t *pathconf = &hconf->paths.entries[i]; - h2o_vector_reserve(NULL, &pathconf->loggers, pathconf->loggers.size + 1); - pathconf->loggers.entries[pathconf->loggers.size++] = (void *)logger; - } - } - } -} - -h2o_status_handler_t durations_status_handler = { - {H2O_STRLIT("durations")}, durations_status_init, durations_status_per_thread, durations_status_final, -}; diff --git a/web/server/h2o/libh2o/lib/handler/status/events.c b/web/server/h2o/libh2o/lib/handler/status/events.c deleted file mode 100644 index e6ed0b7c6..000000000 --- a/web/server/h2o/libh2o/lib/handler/status/events.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2016 Fastly - * - * 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 - -struct st_events_status_ctx_t { - uint64_t emitted_status_errors[H2O_STATUS_ERROR_MAX]; - uint64_t h2_protocol_level_errors[H2O_HTTP2_ERROR_MAX]; - uint64_t h2_read_closed; - uint64_t h2_write_closed; - pthread_mutex_t mutex; -}; - -static void events_status_per_thread(void *priv, h2o_context_t *ctx) -{ - size_t i; - struct st_events_status_ctx_t *esc = priv; - - pthread_mutex_lock(&esc->mutex); - - for (i = 0; i < H2O_STATUS_ERROR_MAX; i++) { - esc->emitted_status_errors[i] += ctx->emitted_error_status[i]; - } - for (i = 0; i < H2O_HTTP2_ERROR_MAX; i++) { - esc->h2_protocol_level_errors[i] += ctx->http2.events.protocol_level_errors[i]; - } - esc->h2_read_closed += ctx->http2.events.read_closed; - esc->h2_write_closed += ctx->http2.events.write_closed; - - pthread_mutex_unlock(&esc->mutex); -} - -static void *events_status_init(void) -{ - struct st_events_status_ctx_t *ret; - - ret = h2o_mem_alloc(sizeof(*ret)); - memset(ret, 0, sizeof(*ret)); - pthread_mutex_init(&ret->mutex, NULL); - - return ret; -} - -static h2o_iovec_t events_status_final(void *priv, h2o_globalconf_t *gconf, h2o_req_t *req) -{ - struct st_events_status_ctx_t *esc = priv; - h2o_iovec_t ret; - -#define H1_AGG_ERR(status_) esc->emitted_status_errors[H2O_STATUS_ERROR_##status_] -#define H2_AGG_ERR(err_) esc->h2_protocol_level_errors[-H2O_HTTP2_ERROR_##err_] -#define BUFSIZE (2 * 1024) - ret.base = h2o_mem_alloc_pool(&req->pool, BUFSIZE); - ret.len = snprintf(ret.base, BUFSIZE, ",\n" - " \"status-errors.400\": %" PRIu64 ",\n" - " \"status-errors.403\": %" PRIu64 ",\n" - " \"status-errors.404\": %" PRIu64 ",\n" - " \"status-errors.405\": %" PRIu64 ",\n" - " \"status-errors.416\": %" PRIu64 ",\n" - " \"status-errors.417\": %" PRIu64 ",\n" - " \"status-errors.500\": %" PRIu64 ",\n" - " \"status-errors.502\": %" PRIu64 ",\n" - " \"status-errors.503\": %" PRIu64 ",\n" - " \"http2-errors.protocol\": %" PRIu64 ", \n" - " \"http2-errors.internal\": %" PRIu64 ", \n" - " \"http2-errors.flow-control\": %" PRIu64 ", \n" - " \"http2-errors.settings-timeout\": %" PRIu64 ", \n" - " \"http2-errors.stream-closed\": %" PRIu64 ", \n" - " \"http2-errors.frame-size\": %" PRIu64 ", \n" - " \"http2-errors.refused-stream\": %" PRIu64 ", \n" - " \"http2-errors.cancel\": %" PRIu64 ", \n" - " \"http2-errors.compression\": %" PRIu64 ", \n" - " \"http2-errors.connect\": %" PRIu64 ", \n" - " \"http2-errors.enhance-your-calm\": %" PRIu64 ", \n" - " \"http2-errors.inadequate-security\": %" PRIu64 ", \n" - " \"http2.read-closed\": %" PRIu64 ", \n" - " \"http2.write-closed\": %" PRIu64 "\n", - H1_AGG_ERR(400), H1_AGG_ERR(403), H1_AGG_ERR(404), H1_AGG_ERR(405), H1_AGG_ERR(416), H1_AGG_ERR(417), - H1_AGG_ERR(500), H1_AGG_ERR(502), H1_AGG_ERR(503), H2_AGG_ERR(PROTOCOL), H2_AGG_ERR(INTERNAL), - H2_AGG_ERR(FLOW_CONTROL), H2_AGG_ERR(SETTINGS_TIMEOUT), H2_AGG_ERR(STREAM_CLOSED), H2_AGG_ERR(FRAME_SIZE), - H2_AGG_ERR(REFUSED_STREAM), H2_AGG_ERR(CANCEL), H2_AGG_ERR(COMPRESSION), H2_AGG_ERR(CONNECT), - H2_AGG_ERR(ENHANCE_YOUR_CALM), H2_AGG_ERR(INADEQUATE_SECURITY), esc->h2_read_closed, esc->h2_write_closed); - pthread_mutex_destroy(&esc->mutex); - free(esc); - return ret; -#undef BUFSIZE -#undef H1_AGG_ERR -#undef H2_AGG_ERR -} - -h2o_status_handler_t events_status_handler = { - {H2O_STRLIT("events")}, events_status_init, events_status_per_thread, events_status_final, -}; diff --git a/web/server/h2o/libh2o/lib/handler/status/requests.c b/web/server/h2o/libh2o/lib/handler/status/requests.c deleted file mode 100644 index 4854e4a1f..000000000 --- a/web/server/h2o/libh2o/lib/handler/status/requests.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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 "h2o.h" - -struct st_requests_status_ctx_t { - h2o_logconf_t *logconf; - h2o_iovec_t req_data; - pthread_mutex_t mutex; -}; - -struct st_collect_req_status_cbdata_t { - h2o_logconf_t *logconf; - h2o_buffer_t *buffer; -}; - -static int collect_req_status(h2o_req_t *req, void *_cbdata) -{ - struct st_collect_req_status_cbdata_t *cbdata = _cbdata; - - /* collect log */ - char buf[4096]; - size_t len = sizeof(buf); - char *logline = h2o_log_request(cbdata->logconf, req, &len, buf); - assert(len != 0); - --len; /* omit trailing LF */ - - /* append to buffer */ - h2o_buffer_reserve(&cbdata->buffer, len + 3); - memcpy(cbdata->buffer->bytes + cbdata->buffer->size, logline, len); - cbdata->buffer->size += len; - - if (logline != buf) - free(logline); - - return 0; -} - -static void requests_status_per_thread(void *priv, h2o_context_t *ctx) -{ - struct st_requests_status_ctx_t *rsc = priv; - struct st_collect_req_status_cbdata_t cbdata = {rsc->logconf}; - - /* we encountered an error at init() time, return early */ - if (rsc->logconf == NULL) - return; - - h2o_buffer_init(&cbdata.buffer, &h2o_socket_buffer_prototype); - ctx->globalconf->http1.callbacks.foreach_request(ctx, collect_req_status, &cbdata); - ctx->globalconf->http2.callbacks.foreach_request(ctx, collect_req_status, &cbdata); - - /* concat JSON elements */ - if (cbdata.buffer->size != 0) { - pthread_mutex_lock(&rsc->mutex); - if (rsc->req_data.len == 0) - h2o_buffer_consume(&cbdata.buffer, 1); /* skip preceeding comma */ - rsc->req_data.base = h2o_mem_realloc(rsc->req_data.base, rsc->req_data.len + cbdata.buffer->size); - memcpy(rsc->req_data.base + rsc->req_data.len, cbdata.buffer->bytes, cbdata.buffer->size); - rsc->req_data.len += cbdata.buffer->size; - pthread_mutex_unlock(&rsc->mutex); - } - - h2o_buffer_dispose(&cbdata.buffer); -} - -static void *requests_status_init(void) -{ - struct st_requests_status_ctx_t *rsc = h2o_mem_alloc(sizeof(*rsc)); - char errbuf[256]; - -#define ELEMENT(key, expr) "\"" key "\": \"" expr "\"" -#define X_ELEMENT(id) ELEMENT(id, "%{" id "}x") -#define SEPARATOR ", " - const char *fmt = ",\n {" - /* combined_log */ - ELEMENT("host", "%h") SEPARATOR ELEMENT("user", "%u") SEPARATOR ELEMENT("at", "%{%Y%m%dT%H%M%S}t.%{usec_frac}t%{%z}t") - SEPARATOR ELEMENT("method", "%m") SEPARATOR ELEMENT("path", "%U") SEPARATOR ELEMENT("query", "%q") - SEPARATOR ELEMENT("protocol", "%H") SEPARATOR ELEMENT("referer", "%{Referer}i") - SEPARATOR ELEMENT("user-agent", "%{User-agent}i") SEPARATOR - /* time */ - X_ELEMENT("connect-time") SEPARATOR X_ELEMENT("request-header-time") SEPARATOR X_ELEMENT("request-body-time") - SEPARATOR X_ELEMENT("request-total-time") SEPARATOR X_ELEMENT("process-time") SEPARATOR X_ELEMENT("response-time") - SEPARATOR - /* connection */ - X_ELEMENT("connection-id") SEPARATOR X_ELEMENT("ssl.protocol-version") SEPARATOR X_ELEMENT("ssl.session-reused") - SEPARATOR X_ELEMENT("ssl.cipher") SEPARATOR X_ELEMENT("ssl.cipher-bits") SEPARATOR X_ELEMENT("ssl.session-ticket") - SEPARATOR - /* http1 */ - X_ELEMENT("http1.request-index") SEPARATOR - /* http2 */ - X_ELEMENT("http2.stream-id") SEPARATOR X_ELEMENT("http2.priority.received.exclusive") - SEPARATOR X_ELEMENT("http2.priority.received.parent") SEPARATOR X_ELEMENT("http2.priority.received.weight") - SEPARATOR X_ELEMENT("http2.priority.actual.parent") SEPARATOR X_ELEMENT("http2.priority.actual.weight") SEPARATOR - /* misc */ - ELEMENT("authority", "%V") - /* end */ - "}"; -#undef ELEMENT -#undef X_ELEMENT -#undef SEPARATOR - - /* compile logconf */ - if ((rsc->logconf = h2o_logconf_compile(fmt, H2O_LOGCONF_ESCAPE_JSON, errbuf)) == NULL) - /* log format compilation error is an internal logic flaw, therefore we need not send the details to the client */ - fprintf(stderr, "[lib/handler/status/requests.c] failed to compile log format: %s", errbuf); - - rsc->req_data = (h2o_iovec_t){NULL}; - pthread_mutex_init(&rsc->mutex, NULL); - - return rsc; -} - -static h2o_iovec_t requests_status_final(void *priv, h2o_globalconf_t *gconf, h2o_req_t *req) -{ - h2o_iovec_t ret = {NULL}; - struct st_requests_status_ctx_t *rsc = priv; - - if (rsc->logconf != NULL) { - ret = h2o_concat(&req->pool, h2o_iovec_init(H2O_STRLIT(",\n \"requests\": [")), rsc->req_data, - h2o_iovec_init(H2O_STRLIT("\n ]"))); - h2o_logconf_dispose(rsc->logconf); - } - free(rsc->req_data.base); - pthread_mutex_destroy(&rsc->mutex); - - free(rsc); - return ret; -} - -h2o_status_handler_t requests_status_handler = { - {H2O_STRLIT("requests")}, requests_status_init, requests_status_per_thread, requests_status_final, -}; diff --git a/web/server/h2o/libh2o/lib/handler/throttle_resp.c b/web/server/h2o/libh2o/lib/handler/throttle_resp.c deleted file mode 100644 index a0028b502..000000000 --- a/web/server/h2o/libh2o/lib/handler/throttle_resp.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2016 Justin Zhu - * - * 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" - -#ifndef HUNDRED_MS -#define HUNDRED_MS 100 -#endif - -#ifndef ONE_SECOND -#define ONE_SECOND 1000 -#endif - -typedef H2O_VECTOR(h2o_iovec_t) iovec_vector_t; - -typedef struct st_throttle_resp_t { - h2o_ostream_t super; - h2o_timeout_entry_t timeout_entry; - int64_t tokens; - size_t token_inc; - h2o_context_t *ctx; - h2o_req_t *req; - struct { - iovec_vector_t bufs; - h2o_send_state_t stream_state; - } state; -} throttle_resp_t; - -static void real_send(throttle_resp_t *self) -{ - /* a really simple token bucket implementation */ - assert(self->tokens > 0); - size_t i, token_consume; - - token_consume = 0; - - for (i = 0; i < self->state.bufs.size; i++) { - token_consume += self->state.bufs.entries[i].len; - } - - self->tokens -= token_consume; - - h2o_ostream_send_next(&self->super, self->req, self->state.bufs.entries, self->state.bufs.size, self->state.stream_state); - if (!h2o_send_state_is_in_progress(self->state.stream_state)) - h2o_timeout_unlink(&self->timeout_entry); -} - -static void add_token(h2o_timeout_entry_t *entry) -{ - throttle_resp_t *self = H2O_STRUCT_FROM_MEMBER(throttle_resp_t, timeout_entry, entry); - - h2o_timeout_link(self->ctx->loop, &self->ctx->hundred_ms_timeout, &self->timeout_entry); - self->tokens += self->token_inc; - - if (self->tokens > 0) - real_send(self); -} - -static void on_send(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state) -{ - throttle_resp_t *self = (void *)_self; - size_t i; - - /* I don't know if this is a proper way. */ - h2o_vector_reserve(&req->pool, &self->state.bufs, inbufcnt); - /* start to save state */ - for (i = 0; i < inbufcnt; ++i) { - self->state.bufs.entries[i] = inbufs[i]; - } - self->state.bufs.size = inbufcnt; - self->state.stream_state = state; - - /* if there's token, we try to send */ - if (self->tokens > 0) - real_send(self); -} - -static void on_stop(h2o_ostream_t *_self, h2o_req_t *req) -{ - throttle_resp_t *self = (void *)_self; - if (h2o_timeout_is_linked(&self->timeout_entry)) { - h2o_timeout_unlink(&self->timeout_entry); - } -} - -static void on_setup_ostream(h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t **slot) -{ - throttle_resp_t *throttle; - h2o_iovec_t traffic_header_value; - size_t traffic_limit; - - if (req->res.status != 200) - goto Next; - if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("HEAD"))) - goto Next; - - ssize_t xt_index; - if ((xt_index = h2o_find_header(&req->res.headers, H2O_TOKEN_X_TRAFFIC, -1)) == -1) - goto Next; - - traffic_header_value = req->res.headers.entries[xt_index].value; - char *buf = traffic_header_value.base; - - if (H2O_UNLIKELY((traffic_limit = h2o_strtosizefwd(&buf, traffic_header_value.len)) == SIZE_MAX)) - goto Next; - - throttle = (void *)h2o_add_ostream(req, sizeof(throttle_resp_t), slot); - - /* calculate the token increment per 100ms */ - throttle->token_inc = traffic_limit * HUNDRED_MS / ONE_SECOND; - if (req->preferred_chunk_size > throttle->token_inc) - req->preferred_chunk_size = throttle->token_inc; - - h2o_delete_header(&req->res.headers, xt_index); - - throttle->super.do_send = on_send; - throttle->super.stop = on_stop; - throttle->ctx = req->conn->ctx; - throttle->req = req; - throttle->state.bufs.capacity = 0; - throttle->state.bufs.size = 0; - throttle->timeout_entry = (h2o_timeout_entry_t){0}; - throttle->timeout_entry.cb = add_token; - throttle->tokens = throttle->token_inc; - slot = &throttle->super.next; - - h2o_timeout_link(throttle->ctx->loop, &throttle->ctx->hundred_ms_timeout, &throttle->timeout_entry); - -Next: - h2o_setup_next_ostream(req, slot); -} - -void h2o_throttle_resp_register(h2o_pathconf_t *pathconf) -{ - h2o_filter_t *self = h2o_create_filter(pathconf, sizeof(*self)); - self->on_setup_ostream = on_setup_ostream; -} diff --git a/web/server/h2o/libh2o/lib/http1.c b/web/server/h2o/libh2o/lib/http1.c deleted file mode 100644 index 98c4e55ab..000000000 --- a/web/server/h2o/libh2o/lib/http1.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Shota Fukumori, - * 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 "picohttpparser.h" -#include "h2o.h" -#include "h2o/http1.h" -#include "h2o/http2.h" - -#define MAX_PULL_BUF_SZ 65536 - -struct st_h2o_http1_finalostream_t { - h2o_ostream_t super; - int sent_headers; - struct { - void *buf; - h2o_ostream_pull_cb cb; - } pull; -}; - -struct st_h2o_http1_conn_t { - h2o_conn_t super; - h2o_socket_t *sock; - /* internal structure */ - h2o_linklist_t _conns; - h2o_timeout_t *_timeout; - h2o_timeout_entry_t _timeout_entry; - uint64_t _req_index; - size_t _prevreqlen; - size_t _reqsize; - struct st_h2o_http1_req_entity_reader *_req_entity_reader; - struct st_h2o_http1_finalostream_t _ostr_final; - struct { - void *data; - h2o_http1_upgrade_cb cb; - } upgrade; - /* the HTTP request / response (intentionally placed at the last, since it is a large structure and has it's own ctor) */ - h2o_req_t req; -}; - -struct st_h2o_http1_req_entity_reader { - void (*handle_incoming_entity)(struct st_h2o_http1_conn_t *conn); -}; - -struct st_h2o_http1_content_length_entity_reader { - struct st_h2o_http1_req_entity_reader super; - size_t content_length; -}; - -struct st_h2o_http1_chunked_entity_reader { - struct st_h2o_http1_req_entity_reader super; - struct phr_chunked_decoder decoder; - size_t prev_input_size; -}; - -static void proceed_pull(struct st_h2o_http1_conn_t *conn, size_t nfilled); -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 *inbufs, size_t inbufcnt, h2o_send_state_t state); -static void reqread_on_read(h2o_socket_t *sock, const char *err); -static int foreach_request(h2o_context_t *ctx, int (*cb)(h2o_req_t *req, void *cbdata), void *cbdata); - -const h2o_protocol_callbacks_t H2O_HTTP1_CALLBACKS = { - NULL, /* graceful_shutdown (note: nothing special needs to be done for handling graceful shutdown) */ - foreach_request}; - -static int is_msie(h2o_req_t *req) -{ - ssize_t cursor = h2o_find_header(&req->headers, H2O_TOKEN_USER_AGENT, -1); - if (cursor == -1) - return 0; - if (h2o_strstr(req->headers.entries[cursor].value.base, req->headers.entries[cursor].value.len, H2O_STRLIT("; MSIE ")) == - SIZE_MAX) - return 0; - return 1; -} - -static void init_request(struct st_h2o_http1_conn_t *conn, int reinit) -{ - if (reinit) - h2o_dispose_request(&conn->req); - h2o_init_request(&conn->req, &conn->super, NULL); - - ++conn->_req_index; - conn->req._ostr_top = &conn->_ostr_final.super; - conn->_ostr_final.super.do_send = finalostream_send; - conn->_ostr_final.super.start_pull = finalostream_start_pull; - conn->_ostr_final.sent_headers = 0; -} - -static void close_connection(struct st_h2o_http1_conn_t *conn, int close_socket) -{ - h2o_timeout_unlink(&conn->_timeout_entry); - h2o_dispose_request(&conn->req); - if (conn->sock != NULL && close_socket) - h2o_socket_close(conn->sock); - h2o_linklist_unlink(&conn->_conns); - free(conn); -} - -static void set_timeout(struct st_h2o_http1_conn_t *conn, h2o_timeout_t *timeout, h2o_timeout_cb cb) -{ - if (conn->_timeout != NULL) { - h2o_timeout_unlink(&conn->_timeout_entry); - conn->_timeout_entry.cb = NULL; - } - conn->_timeout = timeout; - if (timeout != NULL) { - h2o_timeout_link(conn->super.ctx->loop, timeout, &conn->_timeout_entry); - conn->_timeout_entry.cb = cb; - } -} - -static void process_request(struct st_h2o_http1_conn_t *conn) -{ - if (conn->sock->ssl == NULL && conn->req.upgrade.base != NULL && conn->super.ctx->globalconf->http1.upgrade_to_http2 && - conn->req.upgrade.len >= 3 && h2o_lcstris(conn->req.upgrade.base, 3, H2O_STRLIT("h2c")) && - (conn->req.upgrade.len == 3 || - (conn->req.upgrade.len == 6 && (memcmp(conn->req.upgrade.base + 3, H2O_STRLIT("-14")) == 0 || - memcmp(conn->req.upgrade.base + 3, H2O_STRLIT("-16")) == 0)))) { - if (h2o_http2_handle_upgrade(&conn->req, conn->super.connected_at) == 0) { - return; - } - } - h2o_process_request(&conn->req); -} - -#define DECL_ENTITY_READ_SEND_ERROR_XXX(status_) \ - static void entity_read_send_error_##status_(struct st_h2o_http1_conn_t *conn, const char *reason, const char *body) \ - { \ - conn->_req_entity_reader = NULL; \ - set_timeout(conn, NULL, NULL); \ - h2o_socket_read_stop(conn->sock); \ - conn->req.http1_is_persistent = 0; \ - conn->super.ctx->emitted_error_status[H2O_STATUS_ERROR_##status_]++; \ - h2o_send_error_generic(&conn->req, status_, reason, body, H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION); \ - } - -DECL_ENTITY_READ_SEND_ERROR_XXX(400) -DECL_ENTITY_READ_SEND_ERROR_XXX(413) - -static void on_entity_read_complete(struct st_h2o_http1_conn_t *conn) -{ - conn->_req_entity_reader = NULL; - set_timeout(conn, NULL, NULL); - h2o_socket_read_stop(conn->sock); - process_request(conn); -} - -static void handle_chunked_entity_read(struct st_h2o_http1_conn_t *conn) -{ - struct st_h2o_http1_chunked_entity_reader *reader = (void *)conn->_req_entity_reader; - h2o_buffer_t *inbuf = conn->sock->input; - size_t bufsz; - ssize_t ret; - - /* decode the incoming data */ - if ((bufsz = inbuf->size - reader->prev_input_size) == 0) - return; - ret = phr_decode_chunked(&reader->decoder, inbuf->bytes + reader->prev_input_size, &bufsz); - inbuf->size = reader->prev_input_size + bufsz; - reader->prev_input_size = inbuf->size; - if (ret != -1 && inbuf->size - conn->_reqsize >= conn->super.ctx->globalconf->max_request_entity_size) { - entity_read_send_error_413(conn, "Request Entity Too Large", "request entity is too large"); - return; - } - if (ret < 0) { - if (ret == -2) { - /* incomplete */ - return; - } - /* error */ - entity_read_send_error_400(conn, "Invalid Request", "broken chunked-encoding"); - return; - } - /* complete */ - conn->req.entity = h2o_iovec_init(inbuf->bytes + conn->_reqsize, inbuf->size - conn->_reqsize); - conn->_reqsize = inbuf->size; - inbuf->size += ret; /* restore the number of extra bytes */ - - on_entity_read_complete(conn); -} - -static int create_chunked_entity_reader(struct st_h2o_http1_conn_t *conn) -{ - struct st_h2o_http1_chunked_entity_reader *reader = h2o_mem_alloc_pool(&conn->req.pool, sizeof(*reader)); - conn->_req_entity_reader = &reader->super; - - reader->super.handle_incoming_entity = handle_chunked_entity_read; - memset(&reader->decoder, 0, sizeof(reader->decoder)); - reader->decoder.consume_trailer = 1; - reader->prev_input_size = conn->_reqsize; - - return 0; -} - -static void handle_content_length_entity_read(struct st_h2o_http1_conn_t *conn) -{ - struct st_h2o_http1_content_length_entity_reader *reader = (void *)conn->_req_entity_reader; - - /* wait until: reqsize == conn->_input.size */ - if (conn->sock->input->size < conn->_reqsize) - return; - - /* all input has arrived */ - conn->req.entity = h2o_iovec_init(conn->sock->input->bytes + conn->_reqsize - reader->content_length, reader->content_length); - on_entity_read_complete(conn); -} - -static int create_content_length_entity_reader(struct st_h2o_http1_conn_t *conn, size_t content_length) -{ - struct st_h2o_http1_content_length_entity_reader *reader = h2o_mem_alloc_pool(&conn->req.pool, sizeof(*reader)); - conn->_req_entity_reader = &reader->super; - - reader->super.handle_incoming_entity = handle_content_length_entity_read; - reader->content_length = content_length; - conn->_reqsize += content_length; - - return 0; -} - -static int create_entity_reader(struct st_h2o_http1_conn_t *conn, const struct phr_header *entity_header) -{ - /* strlen("content-length") is unequal to sizeof("transfer-encoding"), and thus checking the length only is sufficient */ - if (entity_header->name_len == sizeof("transfer-encoding") - 1) { - /* transfer-encoding */ - if (!h2o_lcstris(entity_header->value, entity_header->value_len, H2O_STRLIT("chunked"))) { - entity_read_send_error_400(conn, "Invalid Request", "unknown transfer-encoding"); - return -1; - } - return create_chunked_entity_reader(conn); - } else { - /* content-length */ - size_t content_length = h2o_strtosize(entity_header->value, entity_header->value_len); - if (content_length == SIZE_MAX) { - entity_read_send_error_400(conn, "Invalid Request", "broken content-length header"); - return -1; - } - if (content_length > conn->super.ctx->globalconf->max_request_entity_size) { - entity_read_send_error_413(conn, "Request Entity Too Large", "request entity is too large"); - return -1; - } - return create_content_length_entity_reader(conn, (size_t)content_length); - } - /* failed */ - return -1; -} - -static ssize_t init_headers(h2o_mem_pool_t *pool, h2o_headers_t *headers, const struct phr_header *src, size_t len, - h2o_iovec_t *connection, h2o_iovec_t *host, h2o_iovec_t *upgrade, h2o_iovec_t *expect) -{ - ssize_t entity_header_index = -1; - - assert(headers->size == 0); - - /* setup */ - if (len != 0) { - size_t i; - h2o_vector_reserve(pool, headers, len); - for (i = 0; i != len; ++i) { - const h2o_token_t *name_token; - char orig_case[src[i].name_len]; - - /* preserve the original case */ - memcpy(orig_case, src[i].name, src[i].name_len); - /* convert to lower-case in-place */ - h2o_strtolower((char *)src[i].name, src[i].name_len); - if ((name_token = h2o_lookup_token(src[i].name, src[i].name_len)) != NULL) { - if (name_token->is_init_header_special) { - if (name_token == H2O_TOKEN_HOST) { - host->base = (char *)src[i].value; - host->len = src[i].value_len; - } else if (name_token == H2O_TOKEN_CONTENT_LENGTH) { - if (entity_header_index == -1) - entity_header_index = i; - } else if (name_token == H2O_TOKEN_TRANSFER_ENCODING) { - entity_header_index = i; - } else if (name_token == H2O_TOKEN_EXPECT) { - expect->base = (char *)src[i].value; - expect->len = src[i].value_len; - } else if (name_token == H2O_TOKEN_UPGRADE) { - upgrade->base = (char *)src[i].value; - upgrade->len = src[i].value_len; - } else { - assert(!"logic flaw"); - } - } else { - h2o_add_header(pool, headers, name_token, orig_case, src[i].value, src[i].value_len); - if (name_token == H2O_TOKEN_CONNECTION) - *connection = headers->entries[headers->size - 1].value; - } - } else { - h2o_add_header_by_str(pool, headers, src[i].name, src[i].name_len, 0, orig_case, src[i].value, src[i].value_len); - } - } - } - - return entity_header_index; -} - -static ssize_t fixup_request(struct st_h2o_http1_conn_t *conn, struct phr_header *headers, size_t num_headers, int minor_version, - h2o_iovec_t *expect) -{ - ssize_t entity_header_index; - h2o_iovec_t connection = {NULL, 0}, host = {NULL, 0}, upgrade = {NULL, 0}; - - expect->base = NULL; - expect->len = 0; - - conn->req.input.scheme = conn->sock->ssl != NULL ? &H2O_URL_SCHEME_HTTPS : &H2O_URL_SCHEME_HTTP; - conn->req.version = 0x100 | (minor_version != 0); - - /* init headers */ - entity_header_index = - init_headers(&conn->req.pool, &conn->req.headers, headers, num_headers, &connection, &host, &upgrade, expect); - - /* copy the values to pool, since the buffer pointed by the headers may get realloced */ - if (entity_header_index != -1) { - size_t i; - conn->req.input.method = h2o_strdup(&conn->req.pool, conn->req.input.method.base, conn->req.input.method.len); - conn->req.input.path = h2o_strdup(&conn->req.pool, conn->req.input.path.base, conn->req.input.path.len); - for (i = 0; i != conn->req.headers.size; ++i) { - h2o_header_t *header = conn->req.headers.entries + i; - if (!h2o_iovec_is_token(header->name)) { - *header->name = h2o_strdup(&conn->req.pool, header->name->base, header->name->len); - } - header->value = h2o_strdup(&conn->req.pool, header->value.base, header->value.len); - } - if (host.base != NULL) - host = h2o_strdup(&conn->req.pool, host.base, host.len); - if (upgrade.base != NULL) - upgrade = h2o_strdup(&conn->req.pool, upgrade.base, upgrade.len); - } - - /* move host header to req->authority */ - if (host.base != NULL) - conn->req.input.authority = host; - - /* setup persistent flag (and upgrade info) */ - if (connection.base != NULL) { - /* TODO contains_token function can be faster */ - if (h2o_contains_token(connection.base, connection.len, H2O_STRLIT("keep-alive"), ',')) { - conn->req.http1_is_persistent = 1; - } - if (upgrade.base != NULL && h2o_contains_token(connection.base, connection.len, H2O_STRLIT("upgrade"), ',')) { - conn->req.upgrade = upgrade; - } - } else if (conn->req.version >= 0x101) { - /* defaults to keep-alive if >= HTTP/1.1 */ - conn->req.http1_is_persistent = 1; - } - /* disable keep-alive if shutdown is requested */ - if (conn->req.http1_is_persistent && conn->super.ctx->shutdown_requested) - conn->req.http1_is_persistent = 0; - - return entity_header_index; -} - -static void on_continue_sent(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1_conn_t *conn = sock->data; - - if (err != NULL) { - close_connection(conn, 1); - return; - } - - h2o_socket_read_start(sock, reqread_on_read); - conn->_req_entity_reader->handle_incoming_entity(conn); -} - -static int contains_crlf_only(const char *s, size_t len) -{ - for (; len != 0; ++s, --len) - if (!(*s == '\r' || *s == '\n')) - return 0; - return 1; -} - -static void send_bad_request_on_complete(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1_conn_t *conn = sock->data; - close_connection(conn, 1); -} - -static void send_bad_request(struct st_h2o_http1_conn_t *conn) -{ - const static h2o_iovec_t resp = {H2O_STRLIT("HTTP/1.1 400 Bad Request\r\n" - "Content-Type: text/plain; charset=utf-8\r\n" - "Connection: close\r\n" - "Content-Length: 11\r\n" - "\r\n" - "Bad Request")}; - - assert(conn->req.version == 0 && "request has not been parsed successfully"); - assert(conn->req.http1_is_persistent == 0); - h2o_socket_write(conn->sock, (h2o_iovec_t *)&resp, 1, send_bad_request_on_complete); - h2o_socket_read_stop(conn->sock); -} - -static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) -{ - size_t inreqlen = conn->sock->input->size < H2O_MAX_REQLEN ? conn->sock->input->size : H2O_MAX_REQLEN; - int reqlen, minor_version; - struct phr_header headers[H2O_MAX_HEADERS]; - size_t num_headers = H2O_MAX_HEADERS; - ssize_t entity_body_header_index; - h2o_iovec_t expect; - - /* need to set request_begin_at here for keep-alive connection */ - if (conn->req.timestamps.request_begin_at.tv_sec == 0) - conn->req.timestamps.request_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); - - reqlen = phr_parse_request(conn->sock->input->bytes, inreqlen, (const char **)&conn->req.input.method.base, - &conn->req.input.method.len, (const char **)&conn->req.input.path.base, &conn->req.input.path.len, - &minor_version, headers, &num_headers, conn->_prevreqlen); - conn->_prevreqlen = inreqlen; - - switch (reqlen) { - default: // parse complete - conn->_reqsize = reqlen; - if ((entity_body_header_index = fixup_request(conn, headers, num_headers, minor_version, &expect)) != -1) { - conn->req.timestamps.request_body_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); - if (expect.base != NULL) { - if (!h2o_lcstris(expect.base, expect.len, H2O_STRLIT("100-continue"))) { - set_timeout(conn, NULL, NULL); - h2o_socket_read_stop(conn->sock); - h2o_send_error_417(&conn->req, "Expectation Failed", "unknown expectation", - H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION); - return; - } - } - if (create_entity_reader(conn, headers + entity_body_header_index) != 0) { - return; - } - if (expect.base != NULL) { - static const h2o_iovec_t res = {H2O_STRLIT("HTTP/1.1 100 Continue\r\n\r\n")}; - h2o_socket_write(conn->sock, (void *)&res, 1, on_continue_sent); - /* processing of the incoming entity is postponed until the 100 response is sent */ - h2o_socket_read_stop(conn->sock); - return; - } - conn->_req_entity_reader->handle_incoming_entity(conn); - } else { - set_timeout(conn, NULL, NULL); - h2o_socket_read_stop(conn->sock); - process_request(conn); - } - return; - case -2: // incomplete - if (inreqlen == H2O_MAX_REQLEN) { - send_bad_request(conn); - } - return; - case -1: // error - /* upgrade to HTTP/2 if the request starts with: PRI * HTTP/2 */ - if (conn->super.ctx->globalconf->http1.upgrade_to_http2) { - /* should check up to the first octet that phr_parse_request returns an error */ - static const h2o_iovec_t HTTP2_SIG = {H2O_STRLIT("PRI * HTTP/2")}; - if (conn->sock->input->size >= HTTP2_SIG.len && memcmp(conn->sock->input->bytes, HTTP2_SIG.base, HTTP2_SIG.len) == 0) { - h2o_accept_ctx_t accept_ctx = {conn->super.ctx, conn->super.hosts}; - h2o_socket_t *sock = conn->sock; - struct timeval connected_at = conn->super.connected_at; - /* destruct the connection after detatching the socket */ - conn->sock = NULL; - close_connection(conn, 1); - /* and accept as http2 connection */ - h2o_http2_accept(&accept_ctx, sock, connected_at); - return; - } - } - if (inreqlen <= 4 && contains_crlf_only(conn->sock->input->bytes, inreqlen)) { - close_connection(conn, 1); - } else { - send_bad_request(conn); - } - return; - } -} - -void reqread_on_read(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1_conn_t *conn = sock->data; - - if (err != NULL) { - close_connection(conn, 1); - return; - } - - if (conn->_req_entity_reader == NULL) - handle_incoming_request(conn); - else - conn->_req_entity_reader->handle_incoming_entity(conn); -} - -static void reqread_on_timeout(h2o_timeout_entry_t *entry) -{ - struct st_h2o_http1_conn_t *conn = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1_conn_t, _timeout_entry, entry); - - /* TODO log */ - conn->req.http1_is_persistent = 0; - close_connection(conn, 1); -} - -static inline void reqread_start(struct st_h2o_http1_conn_t *conn) -{ - set_timeout(conn, &conn->super.ctx->http1.req_timeout, reqread_on_timeout); - h2o_socket_read_start(conn->sock, reqread_on_read); - if (conn->sock->input->size != 0) - handle_incoming_request(conn); -} - -static void on_send_next_push(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1_conn_t *conn = sock->data; - - if (err != NULL) - close_connection(conn, 1); - else - h2o_proceed_response(&conn->req); -} - -static void on_send_next_pull(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1_conn_t *conn = sock->data; - - if (err != NULL) - close_connection(conn, 1); - else - proceed_pull(conn, 0); -} - -static void on_send_complete(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_http1_conn_t *conn = sock->data; - - assert(conn->req._ostr_top == &conn->_ostr_final.super); - - conn->req.timestamps.response_end_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); - - if (!conn->req.http1_is_persistent) { - /* TODO use lingering close */ - close_connection(conn, 1); - return; - } - - /* handle next request */ - init_request(conn, 1); - h2o_buffer_consume(&conn->sock->input, conn->_reqsize); - conn->_prevreqlen = 0; - conn->_reqsize = 0; - reqread_start(conn); -} - -static void on_upgrade_complete(h2o_socket_t *socket, const char *err) -{ - struct st_h2o_http1_conn_t *conn = socket->data; - h2o_http1_upgrade_cb cb = conn->upgrade.cb; - void *data = conn->upgrade.data; - h2o_socket_t *sock = NULL; - size_t reqsize = 0; - - /* destruct the connection (after detaching the socket) */ - if (err == 0) { - sock = conn->sock; - reqsize = conn->_reqsize; - close_connection(conn, 0); - } else { - close_connection(conn, 1); - } - - cb(data, sock, reqsize); -} - -static size_t flatten_headers_estimate_size(h2o_req_t *req, size_t server_name_and_connection_len) -{ - size_t len = sizeof("HTTP/1.1 \r\ndate: \r\nserver: \r\nconnection: \r\ncontent-length: \r\n\r\n") + 3 + - strlen(req->res.reason) + H2O_TIMESTR_RFC1123_LEN + server_name_and_connection_len + - sizeof(H2O_UINT64_LONGEST_STR) - 1 + sizeof("cache-control: private") - 1; - const h2o_header_t *header, *end; - - for (header = req->res.headers.entries, end = header + req->res.headers.size; header != end; ++header) - len += header->name->len + header->value.len + 4; - - return len; -} - -static size_t flatten_headers(char *buf, h2o_req_t *req, const char *connection) -{ - h2o_context_t *ctx = req->conn->ctx; - h2o_timestamp_t ts; - char *dst = buf; - - h2o_get_timestamp(ctx, &req->pool, &ts); - - assert(req->res.status <= 999); - - /* send essential headers with the first chars uppercased for max. interoperability (#72) */ - if (req->res.content_length != SIZE_MAX) { - dst += sprintf(dst, "HTTP/1.1 %d %s\r\nDate: %s\r\nConnection: %s\r\nContent-Length: %zu\r\n", req->res.status, - req->res.reason, ts.str->rfc1123, connection, req->res.content_length); - } else { - dst += sprintf(dst, "HTTP/1.1 %d %s\r\nDate: %s\r\nConnection: %s\r\n", req->res.status, req->res.reason, ts.str->rfc1123, - connection); - } - if (ctx->globalconf->server_name.len) { - dst += sprintf(dst, "Server: %s\r\n", ctx->globalconf->server_name.base); - } - - { /* flatten the normal headers */ - size_t i; - for (i = 0; i != req->res.headers.size; ++i) { - const h2o_header_t *header = req->res.headers.entries + i; - if (header->name == &H2O_TOKEN_VARY->buf) { - /* replace Vary with Cache-Control: private; see the following URLs to understand why this is necessary - * - http://blogs.msdn.com/b/ieinternals/archive/2009/06/17/vary-header-prevents-caching-in-ie.aspx - * - https://www.igvita.com/2013/05/01/deploying-webp-via-accept-content-negotiation/ - */ - if (is_msie(req)) { - static h2o_header_t cache_control_private = {&H2O_TOKEN_CACHE_CONTROL->buf, NULL, {H2O_STRLIT("private")}}; - header = &cache_control_private; - } - } - memcpy(dst, header->orig_name ? header->orig_name : header->name->base, header->name->len); - dst += header->name->len; - *dst++ = ':'; - *dst++ = ' '; - memcpy(dst, header->value.base, header->value.len); - dst += header->value.len; - *dst++ = '\r'; - *dst++ = '\n'; - } - *dst++ = '\r'; - *dst++ = '\n'; - } - - return dst - buf; -} - -static void proceed_pull(struct st_h2o_http1_conn_t *conn, size_t nfilled) -{ - h2o_iovec_t buf = {conn->_ostr_final.pull.buf, nfilled}; - h2o_send_state_t send_state; - - if (buf.len < MAX_PULL_BUF_SZ) { - h2o_iovec_t cbuf = {buf.base + buf.len, MAX_PULL_BUF_SZ - buf.len}; - send_state = h2o_pull(&conn->req, conn->_ostr_final.pull.cb, &cbuf); - if (send_state == H2O_SEND_STATE_ERROR) { - conn->req.http1_is_persistent = 0; - } - buf.len += cbuf.len; - conn->req.bytes_sent += cbuf.len; - } else { - send_state = H2O_SEND_STATE_IN_PROGRESS; - } - - /* write */ - h2o_socket_write(conn->sock, &buf, 1, h2o_send_state_is_in_progress(send_state) ? on_send_next_pull : on_send_complete); -} - -static void finalostream_start_pull(h2o_ostream_t *_self, h2o_ostream_pull_cb cb) -{ - struct st_h2o_http1_conn_t *conn = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1_conn_t, _ostr_final.super, _self); - const char *connection = conn->req.http1_is_persistent ? "keep-alive" : "close"; - size_t bufsz, headers_len; - - assert(conn->req._ostr_top == &conn->_ostr_final.super); - assert(!conn->_ostr_final.sent_headers); - - conn->req.timestamps.response_start_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); - - /* register the pull callback */ - conn->_ostr_final.pull.cb = cb; - - /* setup the buffer */ - bufsz = flatten_headers_estimate_size(&conn->req, conn->super.ctx->globalconf->server_name.len + strlen(connection)); - if (bufsz < MAX_PULL_BUF_SZ) { - if (MAX_PULL_BUF_SZ - bufsz < conn->req.res.content_length) { - bufsz = MAX_PULL_BUF_SZ; - } else { - bufsz += conn->req.res.content_length; - } - } - conn->_ostr_final.pull.buf = h2o_mem_alloc_pool(&conn->req.pool, bufsz); - - /* fill-in the header */ - headers_len = flatten_headers(conn->_ostr_final.pull.buf, &conn->req, connection); - conn->_ostr_final.sent_headers = 1; - - proceed_pull(conn, headers_len); -} - -void finalostream_send(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t send_state) -{ - struct st_h2o_http1_finalostream_t *self = (void *)_self; - struct st_h2o_http1_conn_t *conn = (struct st_h2o_http1_conn_t *)req->conn; - h2o_iovec_t *bufs = alloca(sizeof(h2o_iovec_t) * (inbufcnt + 1)); - int i; - int bufcnt = 0; - - assert(self == &conn->_ostr_final); - - /* count bytes_sent if other ostreams haven't counted */ - if (req->bytes_counted_by_ostream == 0) { - for (i = 0; i != inbufcnt; ++i) { - req->bytes_sent += inbufs[i].len; - } - } - - if (!self->sent_headers) { - conn->req.timestamps.response_start_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); - /* build headers and send */ - const char *connection = req->http1_is_persistent ? "keep-alive" : "close"; - bufs[bufcnt].base = h2o_mem_alloc_pool( - &req->pool, flatten_headers_estimate_size(req, conn->super.ctx->globalconf->server_name.len + strlen(connection))); - bufs[bufcnt].len = flatten_headers(bufs[bufcnt].base, req, connection); - ++bufcnt; - self->sent_headers = 1; - } - memcpy(bufs + bufcnt, inbufs, sizeof(h2o_iovec_t) * inbufcnt); - bufcnt += inbufcnt; - - if (send_state == H2O_SEND_STATE_ERROR) { - conn->req.http1_is_persistent = 0; - } - - if (bufcnt != 0) { - h2o_socket_write(conn->sock, bufs, bufcnt, - h2o_send_state_is_in_progress(send_state) ? on_send_next_push : on_send_complete); - } else { - on_send_complete(conn->sock, 0); - } -} - -static socklen_t get_sockname(h2o_conn_t *_conn, struct sockaddr *sa) -{ - struct st_h2o_http1_conn_t *conn = (void *)_conn; - return h2o_socket_getsockname(conn->sock, sa); -} - -static socklen_t get_peername(h2o_conn_t *_conn, struct sockaddr *sa) -{ - struct st_h2o_http1_conn_t *conn = (void *)_conn; - return h2o_socket_getpeername(conn->sock, sa); -} - -static h2o_socket_t *get_socket(h2o_conn_t *_conn) -{ - struct st_h2o_http1_conn_t *conn = (void *)_conn; - return conn->sock; -} - -#define DEFINE_TLS_LOGGER(name) \ - static h2o_iovec_t log_##name(h2o_req_t *req) \ - { \ - struct st_h2o_http1_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_request_index(h2o_req_t *req) -{ - struct st_h2o_http1_conn_t *conn = (void *)req->conn; - char *s = h2o_mem_alloc_pool(&req->pool, sizeof(H2O_UINT64_LONGEST_STR)); - size_t len = sprintf(s, "%" PRIu64, conn->_req_index); - return h2o_iovec_init(s, len); -} - -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->http1._conns.next; node != &ctx->http1._conns; node = node->next) { - struct st_h2o_http1_conn_t *conn = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1_conn_t, _conns, node); - int ret = cb(&conn->req, cbdata); - if (ret != 0) - return ret; - } - return 0; -} - -void h2o_http1_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at) -{ - static const h2o_conn_callbacks_t callbacks = { - get_sockname, /* stringify address */ - get_peername, /* ditto */ - NULL, /* push */ - get_socket, /* get underlying socket */ - NULL, /* get debug state */ - {{ - {log_protocol_version, log_session_reused, log_cipher, log_cipher_bits, log_session_id}, /* ssl */ - {log_request_index}, /* http1 */ - {NULL} /* http2 */ - }}}; - struct st_h2o_http1_conn_t *conn = (void *)h2o_create_connection(sizeof(*conn), ctx->ctx, ctx->hosts, connected_at, &callbacks); - - /* zero-fill all properties expect req */ - memset((char *)conn + sizeof(conn->super), 0, offsetof(struct st_h2o_http1_conn_t, req) - sizeof(conn->super)); - - /* init properties that need to be non-zero */ - conn->super.ctx = ctx->ctx; - conn->super.hosts = ctx->hosts; - conn->super.connected_at = connected_at; - conn->super.callbacks = &callbacks; - conn->sock = sock; - sock->data = conn; - h2o_linklist_insert(&ctx->ctx->http1._conns, &conn->_conns); - - init_request(conn, 0); - reqread_start(conn); -} - -void h2o_http1_upgrade(h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_http1_upgrade_cb on_complete, void *user_data) -{ - struct st_h2o_http1_conn_t *conn = (void *)req->conn; - - assert(req->version <= 0x200); /* TODO find a better way to assert instanceof(req->conn) == struct st_h2o_http1_conn_t */ - - h2o_iovec_t *bufs = alloca(sizeof(h2o_iovec_t) * (inbufcnt + 1)); - - conn->upgrade.data = user_data; - conn->upgrade.cb = on_complete; - - bufs[0].base = - h2o_mem_alloc_pool(&conn->req.pool, flatten_headers_estimate_size(&conn->req, conn->super.ctx->globalconf->server_name.len + - sizeof("upgrade") - 1)); - bufs[0].len = flatten_headers(bufs[0].base, &conn->req, "upgrade"); - h2o_memcpy(bufs + 1, inbufs, sizeof(h2o_iovec_t) * inbufcnt); - - h2o_socket_write(conn->sock, bufs, inbufcnt + 1, on_upgrade_complete); -} diff --git a/web/server/h2o/libh2o/lib/http2/cache_digests.c b/web/server/h2o/libh2o/lib/http2/cache_digests.c deleted file mode 100644 index fa28bd238..000000000 --- a/web/server/h2o/libh2o/lib/http2/cache_digests.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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 deleted file mode 100644 index 56e00d71f..000000000 --- a/web/server/h2o/libh2o/lib/http2/casper.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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 deleted file mode 100644 index e2da29304..000000000 --- a/web/server/h2o/libh2o/lib/http2/connection.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* - * 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 deleted file mode 100644 index 86abdaa48..000000000 --- a/web/server/h2o/libh2o/lib/http2/frame.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * 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 deleted file mode 100644 index 4adb15cd7..000000000 --- a/web/server/h2o/libh2o/lib/http2/hpack.c +++ /dev/null @@ -1,917 +0,0 @@ -/* - * 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 deleted file mode 100644 index 8f6afab90..000000000 --- a/web/server/h2o/libh2o/lib/http2/hpack_huffman_table.h +++ /dev/null @@ -1,4954 +0,0 @@ -// !!! 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 deleted file mode 100644 index 4c1243103..000000000 --- a/web/server/h2o/libh2o/lib/http2/hpack_static_table.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3ef8de37f..000000000 --- a/web/server/h2o/libh2o/lib/http2/http2_debug_state.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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 deleted file mode 100644 index 0ea7e4591..000000000 --- a/web/server/h2o/libh2o/lib/http2/scheduler.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1dfe2c3a3..000000000 --- a/web/server/h2o/libh2o/lib/http2/stream.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * 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); - } -} diff --git a/web/server/h2o/libh2o/lib/tunnel.c b/web/server/h2o/libh2o/lib/tunnel.c deleted file mode 100644 index aa86aaf4d..000000000 --- a/web/server/h2o/libh2o/lib/tunnel.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2015 Justin Zhu, 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 "h2o.h" -#include "h2o/http1.h" -#include "h2o/tunnel.h" - -struct st_h2o_tunnel_t { - h2o_context_t *ctx; - h2o_timeout_entry_t timeout_entry; - h2o_timeout_t *timeout; - h2o_socket_t *sock[2]; -}; - -static void on_write_complete(h2o_socket_t *sock, const char *err); - -static void close_connection(struct st_h2o_tunnel_t *tunnel) -{ - h2o_timeout_unlink(&tunnel->timeout_entry); - - h2o_socket_close(tunnel->sock[0]); - h2o_socket_close(tunnel->sock[1]); - - free(tunnel); -} - -static void on_timeout(h2o_timeout_entry_t *entry) -{ - struct st_h2o_tunnel_t *tunnel = H2O_STRUCT_FROM_MEMBER(struct st_h2o_tunnel_t, timeout_entry, entry); - close_connection(tunnel); -} - -static inline void reset_timeout(struct st_h2o_tunnel_t *tunnel) -{ - h2o_timeout_unlink(&tunnel->timeout_entry); - h2o_timeout_link(tunnel->ctx->loop, tunnel->timeout, &tunnel->timeout_entry); -} - -static inline void on_read(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_tunnel_t *tunnel = sock->data; - h2o_socket_t *dst; - assert(tunnel != NULL); - assert(tunnel->sock[0] == sock || tunnel->sock[1] == sock); - - if (err != NULL) { - close_connection(tunnel); - return; - } - - if (sock->bytes_read == 0) - return; - - h2o_socket_read_stop(sock); - reset_timeout(tunnel); - - if (tunnel->sock[0] == sock) - dst = tunnel->sock[1]; - else - dst = tunnel->sock[0]; - - h2o_iovec_t buf; - buf.base = sock->input->bytes; - buf.len = sock->input->size; - h2o_socket_write(dst, &buf, 1, on_write_complete); -} - -static void on_write_complete(h2o_socket_t *sock, const char *err) -{ - struct st_h2o_tunnel_t *tunnel = sock->data; - h2o_socket_t *peer; - assert(tunnel != NULL); - assert(tunnel->sock[0] == sock || tunnel->sock[1] == sock); - - if (err != NULL) { - close_connection(tunnel); - return; - } - - reset_timeout(tunnel); - - if (tunnel->sock[0] == sock) - peer = tunnel->sock[1]; - else - peer = tunnel->sock[0]; - - h2o_buffer_consume(&peer->input, peer->input->size); - h2o_socket_read_start(peer, on_read); -} - -h2o_tunnel_t *h2o_tunnel_establish(h2o_context_t *ctx, h2o_socket_t *sock1, h2o_socket_t *sock2, h2o_timeout_t *timeout) -{ - h2o_tunnel_t *tunnel = h2o_mem_alloc(sizeof(*tunnel)); - tunnel->ctx = ctx; - tunnel->timeout = timeout; - tunnel->timeout_entry = (h2o_timeout_entry_t){0}; - tunnel->timeout_entry.cb = on_timeout; - tunnel->sock[0] = sock1; - tunnel->sock[1] = sock2; - sock1->data = tunnel; - sock2->data = tunnel; - h2o_timeout_link(tunnel->ctx->loop, tunnel->timeout, &tunnel->timeout_entry); - - /* Bring up the tunnel. Note. Upstream always ready first. */ - if (sock2->input->size) - on_read(sock2, NULL); - if (sock1->input->size) - on_read(sock1, NULL); - h2o_socket_read_start(sock2, on_read); - h2o_socket_read_start(sock1, on_read); - - return tunnel; -} - -void h2o_tunnel_break(h2o_tunnel_t *tunnel) -{ - close_connection(tunnel); -} diff --git a/web/server/h2o/libh2o/lib/websocket.c b/web/server/h2o/libh2o/lib/websocket.c deleted file mode 100644 index 2886acda6..000000000 --- a/web/server/h2o/libh2o/lib/websocket.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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 -#include -#include -#include -#include "h2o/websocket.h" - -#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - -static void create_accept_key(char *dst, const char *client_key) -{ - uint8_t sha1buf[20], key_src[60]; - - memcpy(key_src, client_key, 24); - memcpy(key_src + 24, WS_GUID, 36); - SHA1(key_src, sizeof(key_src), sha1buf); - h2o_base64_encode(dst, sha1buf, sizeof(sha1buf), 0); - dst[28] = '\0'; -} - -static void on_close(h2o_websocket_conn_t *conn) -{ - (*conn->cb)(conn, NULL); -} - -static void on_recv(h2o_socket_t *sock, const char *err) -{ - h2o_websocket_conn_t *conn = sock->data; - - if (err != NULL) { - on_close(conn); - return; - } - h2o_websocket_proceed(conn); -} - -static void on_write_complete(h2o_socket_t *sock, const char *err) -{ - h2o_websocket_conn_t *conn = sock->data; - - if (err != NULL) { - on_close(conn); - return; - } - h2o_websocket_proceed(conn); -} - -static ssize_t recv_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *_conn) -{ - h2o_websocket_conn_t *conn = _conn; - - /* return WOULDBLOCK if no data */ - if (conn->sock->input->size == 0) { - wslay_event_set_error(conn->ws_ctx, WSLAY_ERR_WOULDBLOCK); - return -1; - } - - if (conn->sock->input->size < len) - len = conn->sock->input->size; - memcpy(buf, conn->sock->input->bytes, len); - h2o_buffer_consume(&conn->sock->input, len); - return len; -} - -static ssize_t send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *_conn) -{ - h2o_websocket_conn_t *conn = _conn; - h2o_iovec_t buf; - - /* return WOULDBLOCK if pending (TODO: queue fixed number of chunks, instead of only one) */ - if (h2o_socket_is_writing(conn->sock)) { - wslay_event_set_error(conn->ws_ctx, WSLAY_ERR_WOULDBLOCK); - return -1; - } - - /* copy data */ - conn->_write_buf = h2o_mem_realloc(conn->_write_buf, len); - memcpy(conn->_write_buf, data, len); - - /* write */ - buf.base = conn->_write_buf; - buf.len = len; - h2o_socket_write(conn->sock, &buf, 1, on_write_complete); - - return len; -} - -static void on_msg_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *_conn) -{ - h2o_websocket_conn_t *conn = _conn; - (*conn->cb)(conn, arg); -} - -static void on_complete(void *user_data, h2o_socket_t *sock, size_t reqsize) -{ - h2o_websocket_conn_t *conn = user_data; - - /* close the connection on error */ - if (sock == NULL) { - (*conn->cb)(conn, NULL); - return; - } - - conn->sock = sock; - sock->data = conn; - h2o_buffer_consume(&sock->input, reqsize); - h2o_websocket_proceed(conn); -} - -h2o_websocket_conn_t *h2o_upgrade_to_websocket(h2o_req_t *req, const char *client_key, void *data, h2o_websocket_msg_callback cb) -{ - h2o_websocket_conn_t *conn = h2o_mem_alloc(sizeof(*conn)); - char accept_key[29]; - - /* only for http1 connection */ - assert(req->version < 0x200); - - /* setup the context */ - memset(conn, 0, sizeof(*conn)); - // conn->sock = sock; set by on_complete - conn->ws_callbacks.recv_callback = recv_callback; - conn->ws_callbacks.send_callback = send_callback; - conn->ws_callbacks.on_msg_recv_callback = on_msg_callback; - conn->data = data; - conn->cb = cb; - - wslay_event_context_server_init(&conn->ws_ctx, &conn->ws_callbacks, conn); - - /* build response */ - create_accept_key(accept_key, client_key); - req->res.status = 101; - req->res.reason = "Switching Protocols"; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_UPGRADE, NULL, H2O_STRLIT("websocket")); - h2o_add_header_by_str(&req->pool, &req->res.headers, H2O_STRLIT("sec-websocket-accept"), 0, NULL, accept_key, - strlen(accept_key)); - - /* send */ - h2o_http1_upgrade(req, NULL, 0, on_complete, conn); - - return conn; -} - -int h2o_is_websocket_handshake(h2o_req_t *req, const char **ws_client_key) -{ - ssize_t key_header_index; - - *ws_client_key = NULL; - - /* method */ - if (h2o_memis(req->input.method.base, req->input.method.len, H2O_STRLIT("GET"))) { - /* ok */ - } else { - return 0; - } - - /* upgrade header */ - if (req->upgrade.base != NULL && h2o_lcstris(req->upgrade.base, req->upgrade.len, H2O_STRLIT("websocket"))) { - /* ok */ - } else { - return 0; - } - /* sec-websocket-key header */ - if ((key_header_index = h2o_find_header_by_str(&req->headers, H2O_STRLIT("sec-websocket-key"), -1)) != -1) { - if (req->headers.entries[key_header_index].value.len != 24) { - return -1; - } - } else { - return 0; - } - - *ws_client_key = req->headers.entries[key_header_index].value.base; - return 0; -} - -void h2o_websocket_close(h2o_websocket_conn_t *conn) -{ - if (conn->sock != NULL) - h2o_socket_close(conn->sock); - free(conn->_write_buf); - wslay_event_context_free(conn->ws_ctx); - free(conn); -} - -void h2o_websocket_proceed(h2o_websocket_conn_t *conn) -{ - int handled; - - /* run the loop until getting to a point where no more progress can be achieved */ - do { - handled = 0; - if (!h2o_socket_is_writing(conn->sock) && wslay_event_want_write(conn->ws_ctx)) { - if (wslay_event_send(conn->ws_ctx) != 0) { - goto Close; - } - handled = 1; - } - if (conn->sock->input->size != 0 && wslay_event_want_read(conn->ws_ctx)) { - if (wslay_event_recv(conn->ws_ctx) != 0) { - goto Close; - } - handled = 1; - } - } while (handled); - - if (wslay_event_want_read(conn->ws_ctx)) { - h2o_socket_read_start(conn->sock, on_recv); - } else if (h2o_socket_is_writing(conn->sock) || wslay_event_want_write(conn->ws_ctx)) { - h2o_socket_read_stop(conn->sock); - } else { - /* nothing is going on... close the socket */ - goto Close; - } - - return; - -Close: - on_close(conn); -} -- cgit v1.2.3