From 34d538027cc90c84ddbab434215234ff3fe5cebc Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Mon, 6 Feb 2017 21:35:59 -0800 Subject: [PATCH 01/10] ORIGIN frame This introduces a new option: `http2-origin-frame`. It can be either a scalar or a sequence. When this option is sent, H2O sends an ORIGIN frame as described here: https://github.com/httpwg/http-extensions/blob/master/draft-ietf-httpbis-origin-frame.md --- include/h2o.h | 2 ++ include/h2o/http2_internal.h | 2 ++ lib/core/configurator.c | 39 ++++++++++++++++++++++++++++++++++++ lib/http2/connection.c | 5 +++++ lib/http2/frame.c | 6 ++++++ 5 files changed, 54 insertions(+) diff --git a/include/h2o.h b/include/h2o.h index 3c4fcb18e7..49145a456e 100644 --- a/include/h2o.h +++ b/include/h2o.h @@ -370,6 +370,8 @@ struct st_h2o_globalconf_t { * list of callbacks */ h2o_protocol_callbacks_t callbacks; + /* */ + h2o_iovec_t origin_frame; } http2; struct { diff --git a/include/h2o/http2_internal.h b/include/h2o/http2_internal.h index 9a962e3dc8..46f6d6c546 100644 --- a/include/h2o/http2_internal.h +++ b/include/h2o/http2_internal.h @@ -87,6 +87,7 @@ static h2o_hpack_header_table_entry_t *h2o_hpack_header_table_get(h2o_hpack_head #define H2O_HTTP2_FRAME_TYPE_GOAWAY 7 #define H2O_HTTP2_FRAME_TYPE_WINDOW_UPDATE 8 #define H2O_HTTP2_FRAME_TYPE_CONTINUATION 9 +#define H2O_HTTP2_FRAME_TYPE_ORIGIN 11 #define H2O_HTTP2_FRAME_FLAG_END_STREAM 0x1 #define H2O_HTTP2_FRAME_FLAG_ACK 0x1 @@ -246,6 +247,7 @@ void h2o_http2__encode_rst_stream_frame(h2o_buffer_t **buf, uint32_t stream_id, void h2o_http2_encode_ping_frame(h2o_buffer_t **buf, int is_ack, const uint8_t *data); void h2o_http2_encode_goaway_frame(h2o_buffer_t **buf, uint32_t last_stream_id, int errnum, h2o_iovec_t additional_data); void h2o_http2_encode_window_update_frame(h2o_buffer_t **buf, uint32_t stream_id, int32_t window_size_increment); +void h2o_http2_encode_origin_frame(h2o_buffer_t **buf, h2o_iovec_t payload); 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); int h2o_http2_decode_data_payload(h2o_http2_data_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc); diff --git a/lib/core/configurator.c b/lib/core/configurator.c index cc208b54c5..91782b4386 100644 --- a/lib/core/configurator.c +++ b/lib/core/configurator.c @@ -448,6 +448,41 @@ static int on_config_http2_latency_optimization_max_cwnd(h2o_configurator_comman return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->http2.latency_optimization.max_cwnd); } +static int on_config_http2_origin_frame(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, + yoml_t *node) +{ + switch (node->type) { + case YOML_TYPE_SCALAR: + ctx->globalconf->http2.origin_frame = h2o_strdup_shared(NULL, node->data.scalar, strlen(node->data.scalar)); + h2o_strtolower(ctx->globalconf->http2.origin_frame.base, ctx->globalconf->http2.origin_frame.len); + break; + case YOML_TYPE_SEQUENCE: { + size_t i; + uint16_t elem_lens[node->data.sequence.size]; + h2o_iovec_t elems[node->data.sequence.size * 2]; + 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; + } + elem_lens[i] = htons(strlen(element->data.scalar)); + elems[i*2].base = (char *)&elem_lens[i]; + elems[i*2].len = 2; + elems[i*2 + 1].base = element->data.scalar; + elems[i*2 + 1].len = strlen(element->data.scalar); + } + ctx->globalconf->http2.origin_frame = h2o_concat_list(NULL, elems, node->data.sequence.size * 2); + h2o_strtolower(ctx->globalconf->http2.origin_frame.base, ctx->globalconf->http2.origin_frame.len); + } 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_http2_reprioritize_blocking_assets(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) { @@ -884,6 +919,10 @@ void h2o_configurator__init_core(h2o_globalconf_t *conf) 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-origin-frame", + H2O_CONFIGURATOR_FLAG_GLOBAL | + H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE, + on_config_http2_origin_frame); h2o_configurator_define_command(&c->super, "http2-reprioritize-blocking-assets", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, diff --git a/lib/http2/connection.c b/lib/http2/connection.c index ecfdcb7ca8..8eaa6e8adb 100644 --- a/lib/http2/connection.c +++ b/lib/http2/connection.c @@ -828,6 +828,11 @@ static ssize_t expect_preface(h2o_http2_conn_t *conn, const uint8_t *src, size_t 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_iovec_t origin_frame = conn->super.ctx->globalconf->http2.origin_frame; + if (origin_frame.base) { + /* write origin frame */ + h2o_http2_encode_origin_frame(&conn->_write.buf, origin_frame); + } h2o_http2_conn_request_write(conn); } diff --git a/lib/http2/frame.c b/lib/http2/frame.c index b41812de41..d7b71db2da 100644 --- a/lib/http2/frame.c +++ b/lib/http2/frame.c @@ -108,6 +108,12 @@ void h2o_http2_encode_window_update_frame(h2o_buffer_t **buf, uint32_t stream_id dst = h2o_http2_encode32u(dst, window_size_increment); } +void h2o_http2_encode_origin_frame(h2o_buffer_t **buf, h2o_iovec_t payload) +{ + uint8_t *dst = allocate_frame(buf, payload.len, H2O_HTTP2_FRAME_TYPE_ORIGIN, 0, 0); + memcpy(dst, payload.base, payload.len); +} + 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) { From d1459eee2e3e887f61fa60adfb2d7ee9a3962d8e Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Mon, 13 Feb 2017 13:30:04 -0800 Subject: [PATCH 02/10] ORIGIN frame Move the config logic under the ssl listener config --- include/h2o.h | 5 +++- include/h2o/http2.h | 2 +- include/h2o/http2_internal.h | 1 + lib/core/configurator.c | 39 --------------------------- lib/core/util.c | 10 +++---- lib/http1.c | 2 +- lib/http2/connection.c | 8 +++--- src/main.c | 52 ++++++++++++++++++++++++++++++++++-- 8 files changed, 66 insertions(+), 53 deletions(-) diff --git a/include/h2o.h b/include/h2o.h index 49145a456e..97ba146ee3 100644 --- a/include/h2o.h +++ b/include/h2o.h @@ -1039,7 +1039,10 @@ struct st_h2o_req_t { typedef struct st_h2o_accept_ctx_t { h2o_context_t *ctx; h2o_hostconf_t **hosts; - SSL_CTX *ssl_ctx; + struct { + SSL_CTX *ssl_ctx; + h2o_iovec_t *http2_origin_frame; + } ssl; int expect_proxy_line; h2o_multithread_receiver_t *libmemcached_receiver; } h2o_accept_ctx_t; diff --git a/include/h2o/http2.h b/include/h2o/http2.h index 567e77de24..9e1c4f54da 100644 --- a/include/h2o/http2.h +++ b/include/h2o/http2.h @@ -57,7 +57,7 @@ typedef struct st_h2o_http2_priority_t { extern const h2o_http2_priority_t h2o_http2_default_priority; -void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at); +void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, h2o_iovec_t *http2_origin_frame, struct timeval connected_at); int h2o_http2_handle_upgrade(h2o_req_t *req, struct timeval connected_at); #ifdef __cplusplus diff --git a/include/h2o/http2_internal.h b/include/h2o/http2_internal.h index 46f6d6c546..d025dc8c40 100644 --- a/include/h2o/http2_internal.h +++ b/include/h2o/http2_internal.h @@ -233,6 +233,7 @@ struct st_h2o_http2_conn_t { } _write; h2o_cache_t *push_memo; h2o_http2_casper_t *casper; + h2o_iovec_t *http2_origin_frame; }; int h2o_http2_update_peer_settings(h2o_http2_settings_t *settings, const uint8_t *src, size_t len, const char **err_desc); diff --git a/lib/core/configurator.c b/lib/core/configurator.c index 91782b4386..cc208b54c5 100644 --- a/lib/core/configurator.c +++ b/lib/core/configurator.c @@ -448,41 +448,6 @@ static int on_config_http2_latency_optimization_max_cwnd(h2o_configurator_comman return h2o_configurator_scanf(cmd, node, "%u", &ctx->globalconf->http2.latency_optimization.max_cwnd); } -static int on_config_http2_origin_frame(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, - yoml_t *node) -{ - switch (node->type) { - case YOML_TYPE_SCALAR: - ctx->globalconf->http2.origin_frame = h2o_strdup_shared(NULL, node->data.scalar, strlen(node->data.scalar)); - h2o_strtolower(ctx->globalconf->http2.origin_frame.base, ctx->globalconf->http2.origin_frame.len); - break; - case YOML_TYPE_SEQUENCE: { - size_t i; - uint16_t elem_lens[node->data.sequence.size]; - h2o_iovec_t elems[node->data.sequence.size * 2]; - 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; - } - elem_lens[i] = htons(strlen(element->data.scalar)); - elems[i*2].base = (char *)&elem_lens[i]; - elems[i*2].len = 2; - elems[i*2 + 1].base = element->data.scalar; - elems[i*2 + 1].len = strlen(element->data.scalar); - } - ctx->globalconf->http2.origin_frame = h2o_concat_list(NULL, elems, node->data.sequence.size * 2); - h2o_strtolower(ctx->globalconf->http2.origin_frame.base, ctx->globalconf->http2.origin_frame.len); - } 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_http2_reprioritize_blocking_assets(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) { @@ -919,10 +884,6 @@ void h2o_configurator__init_core(h2o_globalconf_t *conf) 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-origin-frame", - H2O_CONFIGURATOR_FLAG_GLOBAL | - H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE, - on_config_http2_origin_frame); h2o_configurator_define_command(&c->super, "http2-reprioritize-blocking-assets", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_HOST | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, diff --git a/lib/core/util.c b/lib/core/util.c index 50d2b24932..6caf0d7d75 100644 --- a/lib/core/util.c +++ b/lib/core/util.c @@ -126,7 +126,7 @@ static void on_ssl_handshake_complete(h2o_socket_t *sock, const char *err) 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); + h2o_http2_accept(data->ctx, sock, data->ctx->ssl.http2_origin_frame, data->connected_at); goto Exit; } } @@ -258,8 +258,8 @@ static void on_read_proxy_line(h2o_socket_t *sock, const char *err) break; } - if (data->ctx->ssl_ctx != NULL) { - h2o_socket_ssl_handshake(sock, data->ctx->ssl_ctx, NULL, on_ssl_handshake_complete); + if (data->ctx->ssl.ssl_ctx != NULL) { + h2o_socket_ssl_handshake(sock, data->ctx->ssl.ssl_ctx, NULL, on_ssl_handshake_complete); } else { struct st_h2o_accept_data_t *data = sock->data; sock->data = NULL; @@ -272,12 +272,12 @@ 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) { + if (ctx->expect_proxy_line || ctx->ssl.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); + h2o_socket_ssl_handshake(sock, ctx->ssl.ssl_ctx, NULL, on_ssl_handshake_complete); } } else { h2o_http1_accept(ctx, sock, connected_at); diff --git a/lib/http1.c b/lib/http1.c index 792a6b802f..4f74360787 100644 --- a/lib/http1.c +++ b/lib/http1.c @@ -480,7 +480,7 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) conn->sock = NULL; close_connection(conn, 1); /* and accept as http2 connection */ - h2o_http2_accept(&accept_ctx, sock, connected_at); + h2o_http2_accept(&accept_ctx, sock, NULL, connected_at); return; } } diff --git a/lib/http2/connection.c b/lib/http2/connection.c index 8eaa6e8adb..3a87a84abc 100644 --- a/lib/http2/connection.c +++ b/lib/http2/connection.c @@ -828,10 +828,9 @@ static ssize_t expect_preface(h2o_http2_conn_t *conn, const uint8_t *src, size_t 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_iovec_t origin_frame = conn->super.ctx->globalconf->http2.origin_frame; - if (origin_frame.base) { + if (conn->http2_origin_frame) { /* write origin frame */ - h2o_http2_encode_origin_frame(&conn->_write.buf, origin_frame); + h2o_http2_encode_origin_frame(&conn->_write.buf, *conn->http2_origin_frame); } h2o_http2_conn_request_write(conn); } @@ -1312,9 +1311,10 @@ static int foreach_request(h2o_context_t *ctx, int (*cb)(h2o_req_t *req, void *c return 0; } -void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at) +void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, h2o_iovec_t *http2_origin_frame, struct timeval connected_at) { h2o_http2_conn_t *conn = create_conn(ctx->ctx, ctx->hosts, sock, connected_at); + conn->http2_origin_frame = http2_origin_frame; sock->data = conn; h2o_socket_read_start(conn->sock, on_read); update_idle_timeout(conn); diff --git a/src/main.c b/src/main.c index 88c825e497..f086e052eb 100644 --- a/src/main.c +++ b/src/main.c @@ -78,6 +78,7 @@ struct listener_ssl_config_t { H2O_VECTOR(h2o_iovec_t) hostnames; char *certificate_file; SSL_CTX *ctx; + h2o_iovec_t *http2_origin_frame; #ifndef OPENSSL_NO_OCSP struct { uint64_t interval; @@ -392,6 +393,7 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ SSL_CTX *ssl_ctx = NULL; yoml_t *certificate_file = NULL, *key_file = NULL, *dh_file = NULL, *minimum_version = NULL, *cipher_suite = NULL, *ocsp_update_cmd = NULL, *ocsp_update_interval_node = NULL, *ocsp_max_failures_node = NULL; + h2o_iovec_t *http2_origin_frame = NULL; long ssl_options = SSL_OP_ALL; uint64_t ocsp_update_interval = 4 * 60 * 60; /* defaults to 4 hours */ unsigned ocsp_max_failures = 3; /* defaults to 3; permit 3 failures before temporary disabling OCSP stapling */ @@ -464,6 +466,49 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ } continue; } + if (strcmp(key->data.scalar, "http2-origin-frame") == 0) { + switch (value->type) { + case YOML_TYPE_SCALAR: + { + uint16_t name_size; + name_size = strlen(value->data.scalar); + h2o_strtolower(value->data.scalar, name_size); + http2_origin_frame = h2o_mem_alloc(sizeof(*http2_origin_frame)); + http2_origin_frame->len = sizeof(uint16_t) + name_size; + http2_origin_frame->base = h2o_mem_alloc(http2_origin_frame->len); + + memcpy(http2_origin_frame->base + sizeof(name_size), value->data.scalar, name_size); + name_size = htons(name_size); + memcpy(http2_origin_frame->base, &name_size, sizeof(name_size)); + } break; + case YOML_TYPE_SEQUENCE: + { + size_t i; + uint16_t elem_lens[value->data.sequence.size]; + h2o_iovec_t elems[value->data.sequence.size * 2]; + for (i = 0; i != value->data.sequence.size; ++i) { + yoml_t *element = value->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; + } + elem_lens[i] = htons(strlen(element->data.scalar)); + elems[i*2].base = (char *)&elem_lens[i]; + elems[i*2].len = 2; + elems[i*2 + 1].base = element->data.scalar; + elems[i*2 + 1].len = strlen(element->data.scalar); + h2o_strtolower(elems[i*2 + 1].base, elems[i*2 + 1].len); + } + http2_origin_frame = h2o_mem_alloc(sizeof(*http2_origin_frame)); + *http2_origin_frame = h2o_concat_list(NULL, elems, value->data.sequence.size * 2); + } break; + default: + h2o_configurator_errprintf(cmd, value, "argument to `http2-origin-frame` must be either a scalar or a sequence"); + return -1; + } + /* TODO */ + continue; + } h2o_configurator_errprintf(cmd, key, "unknown property: %s", key->data.scalar); return -1; #undef FETCH_PROPERTY @@ -614,6 +659,7 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ listener_setup_ssl_add_host(ssl_config, ctx->hostconf->authority.hostport); } ssl_config->ctx = ssl_ctx; + ssl_config->http2_origin_frame = http2_origin_frame; ssl_config->certificate_file = h2o_strdup(NULL, certificate_file->data.scalar, SIZE_MAX).base; #ifdef OPENSSL_NO_OCSP if (ocsp_update_interval != 0) @@ -1461,8 +1507,10 @@ H2O_NORETURN static void *run_loop(void *_thread_index) memset(listeners + i, 0, sizeof(listeners[i])); listeners[i].accept_ctx.ctx = &conf.threads[thread_index].ctx; listeners[i].accept_ctx.hosts = listener_config->hosts; - if (listener_config->ssl.size != 0) - listeners[i].accept_ctx.ssl_ctx = listener_config->ssl.entries[0]->ctx; + if (listener_config->ssl.size != 0) { + listeners[i].accept_ctx.ssl.ssl_ctx = listener_config->ssl.entries[0]->ctx; + listeners[i].accept_ctx.ssl.http2_origin_frame = listener_config->ssl.entries[0]->http2_origin_frame; + } listeners[i].accept_ctx.expect_proxy_line = listener_config->proxy_protocol; listeners[i].accept_ctx.libmemcached_receiver = &conf.threads[thread_index].memcached; listeners[i].sock = h2o_evloop_socket_create(conf.threads[thread_index].ctx.loop, fd, H2O_SOCKET_FLAG_DONT_READ); From 1194084545f574bc272df32ea7db8555bb965279 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Mon, 13 Feb 2017 16:17:42 -0800 Subject: [PATCH 03/10] Fix example compile --- examples/libh2o/simple.c | 14 +++++++------- examples/libh2o/websocket.c | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/libh2o/simple.c b/examples/libh2o/simple.c index 282da51ef7..f72a89c9f1 100644 --- a/examples/libh2o/simple.c +++ b/examples/libh2o/simple.c @@ -185,31 +185,31 @@ static int setup_ssl(const char *cert_file, const char *key_file) SSL_library_init(); OpenSSL_add_all_algorithms(); - accept_ctx.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - SSL_CTX_set_options(accept_ctx.ssl_ctx, SSL_OP_NO_SSLv2); + accept_ctx.ssl.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); + SSL_CTX_set_options(accept_ctx.ssl.ssl_ctx, SSL_OP_NO_SSLv2); if (USE_MEMCACHED) { accept_ctx.libmemcached_receiver = &libmemcached_receiver; h2o_accept_setup_async_ssl_resumption(h2o_memcached_create_context("127.0.0.1", 11211, 0, 1, "h2o:ssl-resumption:"), 86400); - h2o_socket_ssl_async_resumption_setup_ctx(accept_ctx.ssl_ctx); + h2o_socket_ssl_async_resumption_setup_ctx(accept_ctx.ssl.ssl_ctx); } /* load certificate and private key */ - if (SSL_CTX_use_certificate_file(accept_ctx.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_certificate_file(accept_ctx.ssl.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load server certificate file:%s\n", cert_file); return -1; } - if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load private key file:%s\n", key_file); return -1; } /* setup protocol negotiation methods */ #if H2O_USE_NPN - h2o_ssl_register_npn_protocols(accept_ctx.ssl_ctx, h2o_http2_npn_protocols); + h2o_ssl_register_npn_protocols(accept_ctx.ssl.ssl_ctx, h2o_http2_npn_protocols); #endif #if H2O_USE_ALPN - h2o_ssl_register_alpn_protocols(accept_ctx.ssl_ctx, h2o_http2_alpn_protocols); + h2o_ssl_register_alpn_protocols(accept_ctx.ssl.ssl_ctx, h2o_http2_alpn_protocols); #endif return 0; diff --git a/examples/libh2o/websocket.c b/examples/libh2o/websocket.c index c977bbd63b..2df0499084 100644 --- a/examples/libh2o/websocket.c +++ b/examples/libh2o/websocket.c @@ -81,15 +81,15 @@ static int setup_ssl(const char *cert_file, const char *key_file) SSL_library_init(); OpenSSL_add_all_algorithms(); - accept_ctx.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - SSL_CTX_set_options(accept_ctx.ssl_ctx, SSL_OP_NO_SSLv2); + accept_ctx.ssl.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); + SSL_CTX_set_options(accept_ctx.ssl.ssl_ctx, SSL_OP_NO_SSLv2); /* load certificate and private key */ - if (SSL_CTX_use_certificate_file(accept_ctx.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_certificate_file(accept_ctx.ssl.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load server certificate file:%s\n", cert_file); return -1; } - if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load private key file:%s\n", key_file); return -1; } From 6904ed90b38f384a8d4c69c1ca5f202071b02c84 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Tue, 14 Feb 2017 08:39:28 -0800 Subject: [PATCH 04/10] Remove the ssl struct from accept_ctx --- examples/libh2o/simple.c | 14 +++++++------- examples/libh2o/websocket.c | 8 ++++---- include/h2o.h | 6 ++---- include/h2o/http2.h | 2 +- lib/core/util.c | 10 +++++----- lib/http1.c | 2 +- lib/http2/connection.c | 4 ++-- src/main.c | 4 ++-- 8 files changed, 24 insertions(+), 26 deletions(-) diff --git a/examples/libh2o/simple.c b/examples/libh2o/simple.c index f72a89c9f1..282da51ef7 100644 --- a/examples/libh2o/simple.c +++ b/examples/libh2o/simple.c @@ -185,31 +185,31 @@ static int setup_ssl(const char *cert_file, const char *key_file) SSL_library_init(); OpenSSL_add_all_algorithms(); - accept_ctx.ssl.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - SSL_CTX_set_options(accept_ctx.ssl.ssl_ctx, SSL_OP_NO_SSLv2); + accept_ctx.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); + SSL_CTX_set_options(accept_ctx.ssl_ctx, SSL_OP_NO_SSLv2); if (USE_MEMCACHED) { accept_ctx.libmemcached_receiver = &libmemcached_receiver; h2o_accept_setup_async_ssl_resumption(h2o_memcached_create_context("127.0.0.1", 11211, 0, 1, "h2o:ssl-resumption:"), 86400); - h2o_socket_ssl_async_resumption_setup_ctx(accept_ctx.ssl.ssl_ctx); + h2o_socket_ssl_async_resumption_setup_ctx(accept_ctx.ssl_ctx); } /* load certificate and private key */ - if (SSL_CTX_use_certificate_file(accept_ctx.ssl.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_certificate_file(accept_ctx.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load server certificate file:%s\n", cert_file); return -1; } - if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load private key file:%s\n", key_file); return -1; } /* setup protocol negotiation methods */ #if H2O_USE_NPN - h2o_ssl_register_npn_protocols(accept_ctx.ssl.ssl_ctx, h2o_http2_npn_protocols); + h2o_ssl_register_npn_protocols(accept_ctx.ssl_ctx, h2o_http2_npn_protocols); #endif #if H2O_USE_ALPN - h2o_ssl_register_alpn_protocols(accept_ctx.ssl.ssl_ctx, h2o_http2_alpn_protocols); + h2o_ssl_register_alpn_protocols(accept_ctx.ssl_ctx, h2o_http2_alpn_protocols); #endif return 0; diff --git a/examples/libh2o/websocket.c b/examples/libh2o/websocket.c index 2df0499084..c977bbd63b 100644 --- a/examples/libh2o/websocket.c +++ b/examples/libh2o/websocket.c @@ -81,15 +81,15 @@ static int setup_ssl(const char *cert_file, const char *key_file) SSL_library_init(); OpenSSL_add_all_algorithms(); - accept_ctx.ssl.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - SSL_CTX_set_options(accept_ctx.ssl.ssl_ctx, SSL_OP_NO_SSLv2); + accept_ctx.ssl_ctx = SSL_CTX_new(SSLv23_server_method()); + SSL_CTX_set_options(accept_ctx.ssl_ctx, SSL_OP_NO_SSLv2); /* load certificate and private key */ - if (SSL_CTX_use_certificate_file(accept_ctx.ssl.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_certificate_file(accept_ctx.ssl_ctx, cert_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load server certificate file:%s\n", cert_file); return -1; } - if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_PrivateKey_file(accept_ctx.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "an error occurred while trying to load private key file:%s\n", key_file); return -1; } diff --git a/include/h2o.h b/include/h2o.h index 97ba146ee3..db3be4bd33 100644 --- a/include/h2o.h +++ b/include/h2o.h @@ -1039,10 +1039,8 @@ struct st_h2o_req_t { typedef struct st_h2o_accept_ctx_t { h2o_context_t *ctx; h2o_hostconf_t **hosts; - struct { - SSL_CTX *ssl_ctx; - h2o_iovec_t *http2_origin_frame; - } ssl; + SSL_CTX *ssl_ctx; + h2o_iovec_t *http2_origin_frame; int expect_proxy_line; h2o_multithread_receiver_t *libmemcached_receiver; } h2o_accept_ctx_t; diff --git a/include/h2o/http2.h b/include/h2o/http2.h index 9e1c4f54da..567e77de24 100644 --- a/include/h2o/http2.h +++ b/include/h2o/http2.h @@ -57,7 +57,7 @@ typedef struct st_h2o_http2_priority_t { extern const h2o_http2_priority_t h2o_http2_default_priority; -void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, h2o_iovec_t *http2_origin_frame, struct timeval connected_at); +void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at); int h2o_http2_handle_upgrade(h2o_req_t *req, struct timeval connected_at); #ifdef __cplusplus diff --git a/lib/core/util.c b/lib/core/util.c index 6caf0d7d75..50d2b24932 100644 --- a/lib/core/util.c +++ b/lib/core/util.c @@ -126,7 +126,7 @@ static void on_ssl_handshake_complete(h2o_socket_t *sock, const char *err) 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->ctx->ssl.http2_origin_frame, data->connected_at); + h2o_http2_accept(data->ctx, sock, data->connected_at); goto Exit; } } @@ -258,8 +258,8 @@ static void on_read_proxy_line(h2o_socket_t *sock, const char *err) break; } - if (data->ctx->ssl.ssl_ctx != NULL) { - h2o_socket_ssl_handshake(sock, data->ctx->ssl.ssl_ctx, NULL, on_ssl_handshake_complete); + 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; @@ -272,12 +272,12 @@ 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.ssl_ctx != 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.ssl_ctx, NULL, on_ssl_handshake_complete); + h2o_socket_ssl_handshake(sock, ctx->ssl_ctx, NULL, on_ssl_handshake_complete); } } else { h2o_http1_accept(ctx, sock, connected_at); diff --git a/lib/http1.c b/lib/http1.c index 4f74360787..792a6b802f 100644 --- a/lib/http1.c +++ b/lib/http1.c @@ -480,7 +480,7 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) conn->sock = NULL; close_connection(conn, 1); /* and accept as http2 connection */ - h2o_http2_accept(&accept_ctx, sock, NULL, connected_at); + h2o_http2_accept(&accept_ctx, sock, connected_at); return; } } diff --git a/lib/http2/connection.c b/lib/http2/connection.c index 3a87a84abc..7968bf1d1d 100644 --- a/lib/http2/connection.c +++ b/lib/http2/connection.c @@ -1311,10 +1311,10 @@ static int foreach_request(h2o_context_t *ctx, int (*cb)(h2o_req_t *req, void *c return 0; } -void h2o_http2_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, h2o_iovec_t *http2_origin_frame, struct timeval connected_at) +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); - conn->http2_origin_frame = http2_origin_frame; + conn->http2_origin_frame = ctx->http2_origin_frame; sock->data = conn; h2o_socket_read_start(conn->sock, on_read); update_idle_timeout(conn); diff --git a/src/main.c b/src/main.c index f086e052eb..7ea6451595 100644 --- a/src/main.c +++ b/src/main.c @@ -1508,8 +1508,8 @@ H2O_NORETURN static void *run_loop(void *_thread_index) listeners[i].accept_ctx.ctx = &conf.threads[thread_index].ctx; listeners[i].accept_ctx.hosts = listener_config->hosts; if (listener_config->ssl.size != 0) { - listeners[i].accept_ctx.ssl.ssl_ctx = listener_config->ssl.entries[0]->ctx; - listeners[i].accept_ctx.ssl.http2_origin_frame = listener_config->ssl.entries[0]->http2_origin_frame; + listeners[i].accept_ctx.ssl_ctx = listener_config->ssl.entries[0]->ctx; + listeners[i].accept_ctx.http2_origin_frame = listener_config->ssl.entries[0]->http2_origin_frame; } listeners[i].accept_ctx.expect_proxy_line = listener_config->proxy_protocol; listeners[i].accept_ctx.libmemcached_receiver = &conf.threads[thread_index].memcached; From d6e18509bece6635a8a43d10ebd011d72d31b57b Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Tue, 14 Feb 2017 09:09:30 -0800 Subject: [PATCH 05/10] Factorize the http2_origin_frame building code --- src/main.c | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/main.c b/src/main.c index 7ea6451595..d871285735 100644 --- a/src/main.c +++ b/src/main.c @@ -387,6 +387,24 @@ static void listener_setup_ssl_add_host(struct listener_ssl_config_t *ssl_config ssl_config->hostnames.entries[ssl_config->hostnames.size++] = h2o_iovec_init(host.base, host_end - host.base); } +static h2o_iovec_t *build_http2_origin_frame(const h2o_iovec_t *origins, size_t nr_origins) +{ + size_t i; + h2o_iovec_t *http2_origin_frame = h2o_mem_alloc(sizeof(*http2_origin_frame)); + uint16_t lengths[nr_origins]; + h2o_iovec_t elems[nr_origins * 2]; + for (i = 0; i < nr_origins; i++) { + lengths[i] = htons(origins[i].len); + elems[i*2].base = (char *)&lengths[i]; + elems[i*2].len = 2; + elems[i*2 + 1].base = origins[i].base; + elems[i*2 + 1].len = origins[i].len; + h2o_strtolower(origins[i].base, origins[i].len); + } + *http2_origin_frame = h2o_concat_list(NULL, elems, nr_origins * 2); + return http2_origin_frame; +} + static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *listen_node, yoml_t *ssl_node, struct listener_config_t *listener, int listener_is_new) { @@ -467,46 +485,35 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ continue; } if (strcmp(key->data.scalar, "http2-origin-frame") == 0) { + h2o_iovec_t *origins; + size_t nr_origins; switch (value->type) { case YOML_TYPE_SCALAR: - { - uint16_t name_size; - name_size = strlen(value->data.scalar); - h2o_strtolower(value->data.scalar, name_size); - http2_origin_frame = h2o_mem_alloc(sizeof(*http2_origin_frame)); - http2_origin_frame->len = sizeof(uint16_t) + name_size; - http2_origin_frame->base = h2o_mem_alloc(http2_origin_frame->len); - - memcpy(http2_origin_frame->base + sizeof(name_size), value->data.scalar, name_size); - name_size = htons(name_size); - memcpy(http2_origin_frame->base, &name_size, sizeof(name_size)); - } break; + nr_origins = 1; + origins = alloca(sizeof(*origins)); + origins[0].base = value->data.scalar; + origins[0].len = strlen(value->data.scalar); + break; case YOML_TYPE_SEQUENCE: { size_t i; - uint16_t elem_lens[value->data.sequence.size]; - h2o_iovec_t elems[value->data.sequence.size * 2]; + nr_origins = value->data.sequence.size; + origins = alloca(sizeof(*origins) * nr_origins); for (i = 0; i != value->data.sequence.size; ++i) { yoml_t *element = value->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; } - elem_lens[i] = htons(strlen(element->data.scalar)); - elems[i*2].base = (char *)&elem_lens[i]; - elems[i*2].len = 2; - elems[i*2 + 1].base = element->data.scalar; - elems[i*2 + 1].len = strlen(element->data.scalar); - h2o_strtolower(elems[i*2 + 1].base, elems[i*2 + 1].len); + origins[i].base = element->data.scalar; + origins[i].len = strlen(element->data.scalar); } - http2_origin_frame = h2o_mem_alloc(sizeof(*http2_origin_frame)); - *http2_origin_frame = h2o_concat_list(NULL, elems, value->data.sequence.size * 2); } break; default: h2o_configurator_errprintf(cmd, value, "argument to `http2-origin-frame` must be either a scalar or a sequence"); return -1; } - /* TODO */ + http2_origin_frame = build_http2_origin_frame(origins, nr_origins); continue; } h2o_configurator_errprintf(cmd, key, "unknown property: %s", key->data.scalar); From 42c8fddf301290e33710eb4555edc8bbc83e9a55 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Wed, 15 Feb 2017 21:32:31 -0800 Subject: [PATCH 06/10] Factorize `build_http2_origin_frame` callers code better --- src/main.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/main.c b/src/main.c index d871285735..6a15c119a1 100644 --- a/src/main.c +++ b/src/main.c @@ -387,19 +387,26 @@ static void listener_setup_ssl_add_host(struct listener_ssl_config_t *ssl_config ssl_config->hostnames.entries[ssl_config->hostnames.size++] = h2o_iovec_init(host.base, host_end - host.base); } -static h2o_iovec_t *build_http2_origin_frame(const h2o_iovec_t *origins, size_t nr_origins) +static h2o_iovec_t *build_http2_origin_frame(h2o_configurator_command_t *cmd, yoml_t **origins, size_t nr_origins) { size_t i; h2o_iovec_t *http2_origin_frame = h2o_mem_alloc(sizeof(*http2_origin_frame)); uint16_t lengths[nr_origins]; h2o_iovec_t elems[nr_origins * 2]; for (i = 0; i < nr_origins; i++) { - lengths[i] = htons(origins[i].len); + yoml_t *origin = origins[i]; + if (origin->type != YOML_TYPE_SCALAR) { + h2o_configurator_errprintf(cmd, origin, "element of a sequence passed to http2-origin-frame must be a scalar"); + free(http2_origin_frame); + return NULL; + } + size_t origin_len = strlen(origins[i]->data.scalar); + lengths[i] = htons(origin_len); elems[i*2].base = (char *)&lengths[i]; elems[i*2].len = 2; - elems[i*2 + 1].base = origins[i].base; - elems[i*2 + 1].len = origins[i].len; - h2o_strtolower(origins[i].base, origins[i].len); + elems[i*2 + 1].base = origins[i]->data.scalar; + elems[i*2 + 1].len = origin_len; + h2o_strtolower(elems[i*2 + 1].base, origin_len); } *http2_origin_frame = h2o_concat_list(NULL, elems, nr_origins * 2); return http2_origin_frame; @@ -485,35 +492,19 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ continue; } if (strcmp(key->data.scalar, "http2-origin-frame") == 0) { - h2o_iovec_t *origins; - size_t nr_origins; switch (value->type) { case YOML_TYPE_SCALAR: - nr_origins = 1; - origins = alloca(sizeof(*origins)); - origins[0].base = value->data.scalar; - origins[0].len = strlen(value->data.scalar); + if ((http2_origin_frame = build_http2_origin_frame(cmd, &value, 1)) == NULL) + return -1; break; case YOML_TYPE_SEQUENCE: - { - size_t i; - nr_origins = value->data.sequence.size; - origins = alloca(sizeof(*origins) * nr_origins); - for (i = 0; i != value->data.sequence.size; ++i) { - yoml_t *element = value->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; - } - origins[i].base = element->data.scalar; - origins[i].len = strlen(element->data.scalar); - } - } break; + if ((http2_origin_frame = build_http2_origin_frame(cmd, value->data.sequence.elements, value->data.sequence.size)) == NULL) + return -1; + break; default: h2o_configurator_errprintf(cmd, value, "argument to `http2-origin-frame` must be either a scalar or a sequence"); return -1; } - http2_origin_frame = build_http2_origin_frame(origins, nr_origins); continue; } h2o_configurator_errprintf(cmd, key, "unknown property: %s", key->data.scalar); From 3b749c0dcf699441fe8287040f46c522a102f98c Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Fri, 20 Oct 2017 19:39:42 +0200 Subject: [PATCH 07/10] draft-ietf-httpbis-origin-frame-04 > The ORIGIN frame type is 0xc (decimal 12) --- include/h2o/http2_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/h2o/http2_internal.h b/include/h2o/http2_internal.h index 437d41c17f..7e5fda4f56 100644 --- a/include/h2o/http2_internal.h +++ b/include/h2o/http2_internal.h @@ -87,7 +87,7 @@ static h2o_hpack_header_table_entry_t *h2o_hpack_header_table_get(h2o_hpack_head #define H2O_HTTP2_FRAME_TYPE_GOAWAY 7 #define H2O_HTTP2_FRAME_TYPE_WINDOW_UPDATE 8 #define H2O_HTTP2_FRAME_TYPE_CONTINUATION 9 -#define H2O_HTTP2_FRAME_TYPE_ORIGIN 11 +#define H2O_HTTP2_FRAME_TYPE_ORIGIN 12 #define H2O_HTTP2_FRAME_FLAG_END_STREAM 0x1 #define H2O_HTTP2_FRAME_FLAG_ACK 0x1 From 7112c45ce657df0090dab465d4fe6c3a019e1485 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Sat, 9 Jun 2018 16:19:02 -0700 Subject: [PATCH 08/10] Add test coverage for the origin frame --- t/50origin-frame.t | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 t/50origin-frame.t diff --git a/t/50origin-frame.t b/t/50origin-frame.t new file mode 100644 index 0000000000..e3c9503cb2 --- /dev/null +++ b/t/50origin-frame.t @@ -0,0 +1,58 @@ +use strict; +use warnings; +use Net::EmptyPort qw(check_port empty_port); +use Test::More; +use Time::HiRes; +use t::Util; + +sub test_origin_frame { + my ($origin_conf,$expected) = @_; + my $server = spawn_h2o(sub { + my ($port, $tls_port) = @_; + return << "EOT"; +listen: + port: $tls_port + ssl: + key-file: examples/h2o/wildcard.key + certificate-file: examples/h2o/wildcard.crt + $origin_conf +hosts: + "*.127.0.0.1.xip.io:$tls_port": + paths: + /: + file.dir: examples/doc_root +EOT + }); + + my $output = run_with_h2get($server, <<"EOR"); + h2g = H2.new + host = ARGV[0] + h2g.connect(host) + h2g.send_prefix() + h2g.send_settings() + i = 0 + while i < 3 do + f = h2g.read(-1) + if f.type_num == 12 then + puts f.len + puts f.payload.dump + end + + if f.type == "SETTINGS" and (f.flags == ACK) then + # ignore + elsif f.type == "SETTINGS" then + h2g.send_settings_ack() + end + i += 1 + end +EOR + + chomp $output; + is $output, $expected; +} + +test_origin_frame('', ''); +test_origin_frame('http2-origin-frame: [ ]', "0\n\"\""); +test_origin_frame('http2-origin-frame: [ "https://a.127.0.0.1.xip.io" ]', "28\n\"\\000\\032https://a.127.0.0.1.xip.io\""); +test_origin_frame('http2-origin-frame: [ "https://a.127.0.0.1.xip.io", "https://b.127.0.0.1.xip.io" ]', "56\n\"\\000\\032https://a.127.0.0.1.xip.io\\000\\032https://b.127.0.0.1.xip.io\""); +done_testing(); From 85e6438e51292a0647f673b4c4ea784b9144c1c7 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Sat, 9 Jun 2018 16:52:09 -0700 Subject: [PATCH 09/10] Add wildcart certificates --- examples/h2o/wildcard.crt | 80 +++++++++++++++++++++++++++++++++++++++ examples/h2o/wildcard.key | 27 +++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 examples/h2o/wildcard.crt create mode 100644 examples/h2o/wildcard.key diff --git a/examples/h2o/wildcard.crt b/examples/h2o/wildcard.crt new file mode 100644 index 0000000000..a407526da2 --- /dev/null +++ b/examples/h2o/wildcard.crt @@ -0,0 +1,80 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=H2O Test CA + Validity + Not Before: Jun 9 21:40:42 2018 GMT + Not After : Jun 6 21:40:42 2028 GMT + Subject: CN=*.127.0.0.1.xip.io + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bc:e7:3c:bb:6d:2b:6b:ac:60:a6:3b:cb:f4:0d: + 0a:fa:c7:ad:55:5e:40:a7:b3:f2:bb:de:ab:57:30: + b5:df:ed:a9:c3:fc:46:29:c7:f1:4e:7c:c8:49:d0: + 18:2c:ba:d1:9a:e0:71:e6:1d:de:23:fd:2d:3e:a4: + 1a:44:c8:c1:b8:08:c6:78:5b:b7:e1:30:14:48:b4: + 45:81:29:1a:e5:70:f0:3e:ee:4a:25:2f:0e:2e:d1: + 7a:61:77:6f:f0:55:04:b6:f1:e9:eb:5b:eb:0b:d7: + fc:7d:00:4b:56:5e:af:04:c0:02:17:0c:7a:e2:ab: + 87:40:87:a6:5e:0b:4c:bb:53:77:d4:c6:70:ff:b8: + 7e:fe:a8:06:fe:0e:f3:92:07:3f:6c:86:71:f3:45: + 42:5b:ad:45:ec:65:2c:6c:f2:67:e7:1d:1e:b7:13: + 8b:cf:8b:36:cf:30:af:32:cc:91:b0:d7:10:b1:7d: + cf:4d:4a:fb:04:ad:d8:34:68:35:5c:33:f8:09:11: + 6f:08:e0:42:4e:f7:7e:40:bc:58:00:2a:f7:76:b3: + 2f:68:1d:04:81:96:f2:d5:a8:92:8f:64:d8:9e:d1: + c0:ac:8d:51:56:78:60:f3:fb:31:16:c7:cb:39:fb: + d6:3d:fd:d2:80:3e:37:4b:5b:f1:bf:f1:b0:68:8c: + cd:31 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 0C:42:CB:56:F5:6E:DC:A8:D3:39:A6:84:15:10:F4:81:74:61:FF:35 + X509v3 Authority Key Identifier: + DirName:/CN=H2O Test CA + serial:9A:A4:B5:57:B0:EF:CD:B6 + + Signature Algorithm: sha256WithRSAEncryption + ab:8a:a8:c8:09:f9:f3:87:5b:a6:3c:25:59:85:a1:b5:37:68: + 59:03:ce:30:9d:df:53:b2:7b:a6:4f:8b:57:09:ce:20:78:b7: + f9:b9:ce:c4:16:19:38:b6:e1:82:13:b1:33:84:84:e6:1f:b4: + 62:39:ec:41:df:50:e8:28:16:ce:14:93:54:65:e6:26:32:c8: + 19:a2:4e:cb:28:d1:8c:ce:f6:ef:22:be:9e:f5:07:fe:69:fa: + 09:cc:cb:81:dd:e7:de:73:52:d4:9d:2b:23:de:1d:62:9d:10: + f2:ca:7c:c0:72:29:69:47:db:ae:a7:24:60:81:62:b9:1b:b1: + f7:f1:71:b2:05:20:65:bc:86:c3:9d:d3:19:3e:74:87:0c:e7: + 96:10:c2:fa:31:cf:31:c7:bf:91:83:80:8d:3b:9c:5a:95:2a: + 81:aa:45:1e:53:5b:69:f7:c0:71:51:63:fd:93:67:f8:54:8c: + 1e:96:62:d7:72:df:0e:af:65:72:fc:65:53:8c:25:dc:3c:23: + c9:a5:95:64:bd:d4:04:1d:b8:68:20:a8:dc:23:1a:2c:e9:cc: + 03:5a:d4:1a:0e:6b:08:79:53:bc:ba:e7:d4:68:d2:70:7d:ca: + e3:d8:fc:ba:bc:8a:5f:94:39:d7:68:8a:28:b1:36:1c:f1:55: + 27:73:23:88 +-----BEGIN CERTIFICATE----- +MIIDPDCCAiSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwtIMk8g +VGVzdCBDQTAeFw0xODA2MDkyMTQwNDJaFw0yODA2MDYyMTQwNDJaMB0xGzAZBgNV +BAMMEiouMTI3LjAuMC4xLnhpcC5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALznPLttK2usYKY7y/QNCvrHrVVeQKez8rveq1cwtd/tqcP8RinH8U58 +yEnQGCy60ZrgceYd3iP9LT6kGkTIwbgIxnhbt+EwFEi0RYEpGuVw8D7uSiUvDi7R +emF3b/BVBLbx6etb6wvX/H0AS1ZerwTAAhcMeuKrh0CHpl4LTLtTd9TGcP+4fv6o +Bv4O85IHP2yGcfNFQlutRexlLGzyZ+cdHrcTi8+LNs8wrzLMkbDXELF9z01K+wSt +2DRoNVwz+AkRbwjgQk73fkC8WAAq93azL2gdBIGW8tWoko9k2J7RwKyNUVZ4YPP7 +MRbHyzn71j390oA+N0tb8b/xsGiMzTECAwEAAaOBjTCBijAJBgNVHRMEAjAAMCwG +CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV +HQ4EFgQUDELLVvVu3KjTOaaEFRD0gXRh/zUwMAYDVR0jBCkwJ6EapBgwFjEUMBIG +A1UEAxMLSDJPIFRlc3QgQ0GCCQCapLVXsO/NtjANBgkqhkiG9w0BAQsFAAOCAQEA +q4qoyAn584dbpjwlWYWhtTdoWQPOMJ3fU7J7pk+LVwnOIHi3+bnOxBYZOLbhghOx +M4SE5h+0YjnsQd9Q6CgWzhSTVGXmJjLIGaJOyyjRjM727yK+nvUH/mn6CczLgd3n +3nNS1J0rI94dYp0Q8sp8wHIpaUfbrqckYIFiuRux9/FxsgUgZbyGw53TGT50hwzn +lhDC+jHPMce/kYOAjTucWpUqgapFHlNbaffAcVFj/ZNn+FSMHpZi13LfDq9lcvxl +U4wl3DwjyaWVZL3UBB24aCCo3CMaLOnMA1rUGg5rCHlTvLrn1GjScH3K49j8uryK +X5Q512iKKLE2HPFVJ3MjiA== +-----END CERTIFICATE----- diff --git a/examples/h2o/wildcard.key b/examples/h2o/wildcard.key new file mode 100644 index 0000000000..e909b5fe36 --- /dev/null +++ b/examples/h2o/wildcard.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAvOc8u20ra6xgpjvL9A0K+setVV5Ap7Pyu96rVzC13+2pw/xG +KcfxTnzISdAYLLrRmuBx5h3eI/0tPqQaRMjBuAjGeFu34TAUSLRFgSka5XDwPu5K +JS8OLtF6YXdv8FUEtvHp61vrC9f8fQBLVl6vBMACFwx64quHQIemXgtMu1N31MZw +/7h+/qgG/g7zkgc/bIZx80VCW61F7GUsbPJn5x0etxOLz4s2zzCvMsyRsNcQsX3P +TUr7BK3YNGg1XDP4CRFvCOBCTvd+QLxYACr3drMvaB0EgZby1aiSj2TYntHArI1R +Vnhg8/sxFsfLOfvWPf3SgD43S1vxv/GwaIzNMQIDAQABAoIBADSmVnz+rm1yO/XZ +EL1SrU68PIlgnbCgLPVD2ImSn/5rpTdkpsGaYp03ljNMdpBw+V6rU9OJW5K4S9X7 +sv6c3bFHcNm25ocy+VRSOlUHeeGdGrjPfYbjmJZf+DYWLfLUH15GCqZ4lghVCKBm +ZpkKBsnSIkL+TXnDyQypQitQBvDmlduLXpg70LZ9WaRQRSbmfT29ousJkhaz9tx1 +WVZP21LAmFCHhpmhG+1QyrLiunfXRsMhhPQYB8AukhjYPzIJrmzSeRufHJZ/19Pd +UzttoxQKfLKCXd51YSUhKHoURDyZWPvmzpzfg5JcxqkFodzo1Cfx7aHGvSXEoPw3 +pe3FWykCgYEA6f+eXZ9P38zYr0OJ3cQ24lSoyWaSWGROLi/UKci/vARf3U8RScNI +Jh7yW/palM1tw+YV5m6teXMFkwWjUTg2bqlJ8TMNRPZO2Zv5uoYYChgFdbCiii23 +zCZ+RGJ4YhlNawe7rhNl1ETHZu3El7bKkC0/cr+xVTkzefKO+jl0YD8CgYEAzqor +ROlbzHy0ryGsHFi8mbD7jrJApZ/xx+26f3b37NnpMSIMMWG67bqTl8JHI4GIi5OY +AiFXZ5wqBKpSTZYW0Do79UVMGvOhvj1BqSenJNidvOXwCAJCGnS3zrRpTh4s4tey +WUtzo9bN24OEmrZPVc67NmlmMD13yG7xYihSdo8CgYBkP5PsTi1dFxiZ9Zhh/wb4 +bgalyiDWZ5qq5OjDQfMKrOEZIh+o91W4pzdzuk0GRQBKlg852p7NUj7IHvk5+Zgw +TqyT/igoLFHZnp4dkAdKg8ILCrKH+lAs0Sz1RS6H8IkfWn/Icx0EFLdM3H6F9NTR +ceEl2wQxG8F29DjW8Lhv5wKBgFA6m6Wa+jo+R16dsdUnVcBMhrv000f4+cHltjr5 +knHufqrGTvl0uT7E6btGfpt4E+wrlh1tmCLu6xj4jg70r1KS6OfkyRDFeAsEeNMU +Q7z4IvRMR4y0Y7klip3CSAc9i6tclS45LmFyaGRJgFcXY2Eqal9LN5KOqkuzVh4H +DUxdAoGANy2ZQPAyiLQEjC0KjWWOySaaG5a9ZiKmfkaZCXUoy4Q9oNYfwFZZu/q1 ++y/s8xAJY3r/hNa+eXJVNZInDcON+5WnOyHwh5Thbqck7gsVfiuUeJIIwCoZ1lHB +Y0c6e3U/lGEjsTQnoH0Z9ssizX23fsSUkrQ9RyVSRf6IWMf0MaM= +-----END RSA PRIVATE KEY----- From e534f4c0beda9486b5fca07ee86ca6b39344fd3c Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Sat, 9 Jun 2018 16:57:45 -0700 Subject: [PATCH 10/10] clang format --- lib/http2/connection.c | 1 - src/main.c | 50 +++++++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/http2/connection.c b/lib/http2/connection.c index 5298216189..40276e6c32 100644 --- a/lib/http2/connection.c +++ b/lib/http2/connection.c @@ -1000,7 +1000,6 @@ static ssize_t expect_preface(h2o_http2_conn_t *conn, const uint8_t *src, size_t return H2O_HTTP2_ERROR_PROTOCOL_CLOSE_IMMEDIATELY; } - { /* send SETTINGS and connection-level WINDOW_UPDATE */ h2o_iovec_t vec = h2o_buffer_reserve(&conn->_write.buf, SERVER_PREFACE.len); memcpy(vec.base, SERVER_PREFACE.base, SERVER_PREFACE.len); diff --git a/src/main.c b/src/main.c index 79284855f6..f9841014b8 100644 --- a/src/main.c +++ b/src/main.c @@ -541,11 +541,11 @@ static h2o_iovec_t *build_http2_origin_frame(h2o_configurator_command_t *cmd, yo } size_t origin_len = strlen(origins[i]->data.scalar); lengths[i] = htons(origin_len); - elems[i*2].base = (char *)&lengths[i]; - elems[i*2].len = 2; - elems[i*2 + 1].base = origins[i]->data.scalar; - elems[i*2 + 1].len = origin_len; - h2o_strtolower(elems[i*2 + 1].base, origin_len); + elems[i * 2].base = (char *)&lengths[i]; + elems[i * 2].len = 2; + elems[i * 2 + 1].base = origins[i]->data.scalar; + elems[i * 2 + 1].len = origin_len; + h2o_strtolower(elems[i * 2 + 1].base, origin_len); } *http2_origin_frame = h2o_concat_list(NULL, elems, nr_origins * 2); return http2_origin_frame; @@ -556,7 +556,8 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ { SSL_CTX *ssl_ctx = NULL; yoml_t **certificate_file, **key_file, **dh_file, **min_version, **max_version, **cipher_suite, **ocsp_update_cmd, - **ocsp_update_interval_node, **ocsp_max_failures_node, **cipher_preference_node, **neverbleed_node, **http2_origin_frame_node; + **ocsp_update_interval_node, **ocsp_max_failures_node, **cipher_preference_node, **neverbleed_node, + **http2_origin_frame_node; h2o_iovec_t *http2_origin_frame = NULL; long ssl_options = SSL_OP_ALL; uint64_t ocsp_update_interval = 4 * 60 * 60; /* defaults to 4 hours */ @@ -578,13 +579,14 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ return 0; /* parse */ - if (h2o_configurator_parse_mapping( - cmd, *ssl_node, "certificate-file:s,key-file:s", "min-version:s,minimum-version:s,max-version:s,maximum-version:s," - "cipher-suite:s,ocsp-update-cmd:s,ocsp-update-interval:*," - "ocsp-max-failures:*,dh-file:s,cipher-preference:*,neverbleed:*," - "http2-origin-frame:*", - &certificate_file, &key_file, &min_version, &min_version, &max_version, &max_version, &cipher_suite, &ocsp_update_cmd, - &ocsp_update_interval_node, &ocsp_max_failures_node, &dh_file, &cipher_preference_node, &neverbleed_node, &http2_origin_frame_node) != 0) + if (h2o_configurator_parse_mapping(cmd, *ssl_node, "certificate-file:s,key-file:s", + "min-version:s,minimum-version:s,max-version:s,maximum-version:s," + "cipher-suite:s,ocsp-update-cmd:s,ocsp-update-interval:*," + "ocsp-max-failures:*,dh-file:s,cipher-preference:*,neverbleed:*," + "http2-origin-frame:*", + &certificate_file, &key_file, &min_version, &min_version, &max_version, &max_version, + &cipher_suite, &ocsp_update_cmd, &ocsp_update_interval_node, &ocsp_max_failures_node, + &dh_file, &cipher_preference_node, &neverbleed_node, &http2_origin_frame_node) != 0) return -1; if (cipher_preference_node != NULL) { switch (h2o_configurator_get_one_of(cmd, *cipher_preference_node, "client,server")) { @@ -602,17 +604,19 @@ static int listener_setup_ssl(h2o_configurator_command_t *cmd, h2o_configurator_ return -1; if (http2_origin_frame_node != NULL) { switch ((*http2_origin_frame_node)->type) { - case YOML_TYPE_SCALAR: - if ((http2_origin_frame = build_http2_origin_frame(cmd, http2_origin_frame_node, 1)) == NULL) - return -1; - break; - case YOML_TYPE_SEQUENCE: - if ((http2_origin_frame = build_http2_origin_frame(cmd, (*http2_origin_frame_node)->data.sequence.elements, (*http2_origin_frame_node)->data.sequence.size)) == NULL) - return -1; - break; - default: - h2o_configurator_errprintf(cmd, *http2_origin_frame_node, "argument to `http2-origin-frame` must be either a scalar or a sequence"); + case YOML_TYPE_SCALAR: + if ((http2_origin_frame = build_http2_origin_frame(cmd, http2_origin_frame_node, 1)) == NULL) + return -1; + break; + case YOML_TYPE_SEQUENCE: + if ((http2_origin_frame = build_http2_origin_frame(cmd, (*http2_origin_frame_node)->data.sequence.elements, + (*http2_origin_frame_node)->data.sequence.size)) == NULL) return -1; + break; + default: + h2o_configurator_errprintf(cmd, *http2_origin_frame_node, + "argument to `http2-origin-frame` must be either a scalar or a sequence"); + return -1; } } if (min_version != NULL) {