void h2o_socket_ssl_server_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, h2o_socket_cb handshake_cb) { static BIO_METHOD bio_methods = {BIO_TYPE_FD, "h2o_socket", write_bio, read_bio, puts_bio, NULL, ctrl_bio, new_bio, free_bio, NULL}; BIO *bio; sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* 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); bio = BIO_new(&bio_methods); bio->ptr = sock; bio->init = 1; sock->ssl->ssl = SSL_new(ssl_ctx); SSL_set_bio(sock->ssl->ssl, bio, bio); sock->ssl->handshake.cb = handshake_cb; proceed_handshake(sock, 0); }
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)); /* 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); create_ssl(sock, ssl_ctx); sock->ssl->handshake.cb = handshake_cb; if (server_name == NULL) { /* is server */ if (SSL_CTX_sess_get_get_cb(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 { sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base; SSL_set_tlsext_host_name(sock->ssl->ssl, sock->ssl->handshake.client.server_name); proceed_handshake(sock, 0); } }
void h2o_socket_ssl_server_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, h2o_socket_cb handshake_cb) { static BIO_METHOD bio_methods = { BIO_TYPE_FD, "h2o_socket", write_bio, read_bio, puts_bio, NULL, ctrl_bio, new_bio, free_bio, NULL }; BIO *bio; sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); h2o_mem_init_pool(&sock->ssl->output.pool); bio = BIO_new(&bio_methods); bio->ptr = sock; bio->init = 1; sock->ssl->ssl = SSL_new(ssl_ctx); SSL_set_bio(sock->ssl->ssl, bio, bio); sock->ssl->handshake.cb = handshake_cb; proceed_handshake(sock, 0); }
static void test_extract_push_path_from_link_header(void) { h2o_mem_pool_t pool; h2o_iovec_t path; h2o_iovec_t base_authority = {H2O_STRLIT("basehost")}, base_path = {H2O_STRLIT("/basepath/")}; #define BASE &H2O_URL_SCHEME_HTTP, &base_authority, &base_path h2o_mem_init_pool(&pool); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http://basehost/otherpath>; rel=preload"), BASE); ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</otherpath>; rel=preload"), BASE); ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<otherpath>; rel=preload"), BASE); ok(h2o_memis(path.base, path.len, H2O_STRLIT("/basepath/otherpath"))); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<../otherpath>; rel=preload"), BASE); ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http:otherpath>; rel=preload"), BASE); ok(h2o_memis(path.base, path.len, H2O_STRLIT("/basepath/otherpath"))); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<../otherpath>; rel=author"), BASE); ok(path.base == NULL); ok(path.len == 0); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http://basehost:81/otherpath>; rel=preload"), BASE); ok(path.base == NULL); ok(path.len == 0); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<https://basehost/otherpath>; rel=preload"), BASE); ok(path.base == NULL); ok(path.len == 0); path = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<https:otherpath>; rel=preload"), BASE); ok(path.base == NULL); ok(path.len == 0); h2o_mem_clear_pool(&pool); #undef BASE }
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)); /* 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); create_ssl(sock, ssl_ctx); sock->ssl->handshake.cb = handshake_cb; if (server_name == NULL) { /* is server */ if (SSL_CTX_sess_get_get_cb(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 { h2o_cache_t *session_cache = h2o_socket_ssl_get_session_cache(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->ssl, (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->ssl, sock->ssl->handshake.client.server_name); proceed_handshake(sock, 0); } }
static void test_resolve(void) { h2o_mem_pool_t pool; h2o_url_t base, relative, resolved; h2o_iovec_t final; int ret; h2o_mem_init_pool(&pool); ret = h2o_url_parse("http://example.com/dir/index.html", SIZE_MAX, &base); ok(ret == 0); ret = h2o_url_parse_relative("../assets/jquery.js", SIZE_MAX, &relative); ok(ret == 0); final = h2o_url_resolve(&pool, &base, &relative, &resolved);
static void test_decode_base64(void) { h2o_mem_pool_t pool; char buf[256]; h2o_mem_init_pool(&pool); h2o_iovec_t src = {H2O_STRLIT("The quick brown fox jumps over the lazy dog.")}, decoded; h2o_base64_encode(buf, (const uint8_t *)src.base, src.len, 1); ok(strcmp(buf, "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4") == 0); decoded = h2o_decode_base64url(&pool, buf, strlen(buf)); ok(src.len == decoded.len); ok(strcmp(decoded.base, src.base) == 0); h2o_mem_clear_pool(&pool); }
static void test_htmlescape(void) { h2o_mem_pool_t pool; h2o_mem_init_pool(&pool); #define TEST(src, expected) \ do { \ h2o_iovec_t escaped = h2o_htmlescape(&pool, H2O_STRLIT(src)); \ ok(h2o_memis(escaped.base, escaped.len, H2O_STRLIT(expected))); \ } while (0) TEST("hello world", "hello world"); TEST("x < y", "x < y"); TEST("\0\"&'<>", "\0"&'<>"); #undef TEST h2o_mem_clear_pool(&pool); }
static void test_uri_escape(void) { h2o_mem_pool_t pool; h2o_mem_init_pool(&pool); #define TEST(src, preserve, expected) \ do { \ h2o_iovec_t escaped = h2o_uri_escape(&pool, H2O_STRLIT(src), preserve); \ ok(h2o_memis(escaped.base, escaped.len, H2O_STRLIT(expected))); \ } while (0) TEST("abc", NULL, "abc"); TEST("a/c", NULL, "a%2Fc"); TEST("a/c", "/", "a/c"); TEST("\xe3\x81\x82", NULL, "%E3%81%82"); TEST("a\0!", NULL, "a%00!"); TEST("a/\0!", "/", "a/%00!"); #undef TEST h2o_mem_clear_pool(&pool); }
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.content_length = SIZE_MAX; if (src != NULL) { #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(authority); COPY(method); COPY(path); COPY(scheme); req->version = src->version; h2o_vector_reserve(&req->pool, (h2o_vector_t*)&req->headers, sizeof(h2o_header_t), src->headers.size); memcpy(req->headers.entries, src->headers.entries, sizeof(req->headers.entries[0]) * src->headers.size); req->headers.size = src->headers.size; req->entity = src->entity; req->http1_is_persistent = src->http1_is_persistent; if (src->upgrade.base != NULL) { COPY(upgrade); } else { req->upgrade.base = NULL; req->upgrade.len = 0; } #undef COPY } }
static void test_normalize_path(void) { h2o_mem_pool_t pool; h2o_mem_init_pool(&pool); size_t q; h2o_iovec_t b = h2o_url_normalize_path(&pool, H2O_STRLIT("/"), &q); ok(b.len == 1); ok(memcmp(b.base, H2O_STRLIT("/")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc/../def"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/def")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc/../../def"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/def")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc/./def"), &q); ok(b.len == 8); ok(memcmp(b.base, H2O_STRLIT("/abc/def")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc/def/.."), &q); ok(b.len == 5); ok(memcmp(b.base, H2O_STRLIT("/abc/")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc/def/."), &q); ok(b.len == 9); ok(memcmp(b.base, H2O_STRLIT("/abc/def/")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc?xx"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); ok(q == 4); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/abc/../def?xx"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/def")) == 0); ok(q == 11); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/a%62c"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/a%6"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/a%6")) == 0); ok(q == SIZE_MAX); b = h2o_url_normalize_path(&pool, H2O_STRLIT("/a%6?"), &q); ok(b.len == 4); ok(memcmp(b.base, H2O_STRLIT("/a%6")) == 0); ok(q == 4); h2o_mem_clear_pool(&pool); }
static void test_extract_push_path_from_link_header(void) { h2o_mem_pool_t pool; h2o_iovec_t base_path = {H2O_STRLIT("/basepath/")}, input_authority = {H2O_STRLIT("basehost")}, other_authority = {H2O_STRLIT("otherhost")}; h2o_mem_init_pool(&pool); #define DO_CHECK(_base_scheme, _base_authority, _input, _filtered_expected, ...) \ do { \ h2o_iovec_t input = h2o_iovec_init(_input, strlen(_input)), filtered; \ struct expected_t expected[] = {__VA_ARGS__, {NULL}}, *e = expected; \ h2o_extract_push_path_from_link_header(&pool, input.base, input.len, base_path, &H2O_URL_SCHEME_HTTP, input_authority, \ _base_scheme, _base_authority, check_path, &e, &filtered); \ ok(e->path == NULL); \ if (_filtered_expected != NULL) { \ ok(h2o_memis(filtered.base, filtered.len, _filtered_expected, strlen(_filtered_expected))); \ } else { \ ok(h2o_memis(filtered.base, filtered.len, input.base, input.len)); \ } \ } while (0) // basic tests DO_CHECK(NULL, NULL, "<http://basehost/otherpath>; rel=preload", NULL, {"/otherpath"}); DO_CHECK(NULL, NULL, "</otherpath>; rel=preload", NULL, {"/otherpath"}); DO_CHECK(NULL, NULL, "<otherpath>; rel=preload", NULL, {"/basepath/otherpath"}); DO_CHECK(NULL, NULL, "<../otherpath>; rel=preload", NULL, {"/otherpath"}); DO_CHECK(NULL, NULL, "<http:otherpath>; rel=preload", NULL, {"/basepath/otherpath"}); // negative filters DO_CHECK(NULL, NULL, "<../otherpath>; rel=author", NULL, {NULL}); DO_CHECK(NULL, NULL, "<http://basehost:81/otherpath>; rel=preload", NULL, {NULL}); DO_CHECK(NULL, NULL, "<https://basehost/otherpath>; rel=preload", NULL, {NULL}); DO_CHECK(NULL, NULL, "<https:otherpath>; rel=preload", NULL, {NULL}); // scheme and authority DO_CHECK(&H2O_URL_SCHEME_HTTPS, &input_authority, "</otherpath>; rel=preload", NULL, {NULL}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "</otherpath>; rel=preload", NULL, {"/otherpath"}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &other_authority, "<http://basehost/otherpath>; rel=preload", NULL, {"/otherpath"}); // attributes DO_CHECK(NULL, NULL, "<http:otherpath>; rel=preload; nopush", NULL, {NULL}); DO_CHECK(NULL, NULL, "<http:otherpath>; rel=preload; x-http2-push-only", "", {"/basepath/otherpath"}); DO_CHECK(NULL, NULL, "<http:otherpath>; rel=preload; critical", NULL, {"/basepath/otherpath", 1}); // multiple entries DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "</firstpath>; rel=preload, </secondpath>; rel=preload", NULL, {"/firstpath"}, {"/secondpath"}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "</firstpath>; rel=preload; nopush, </secondpath>; rel=preload", NULL, {"/secondpath"}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "</firstpath>; rel=preload; nopush, </secondpath>; nopush; rel=preload; </thirdpath>", NULL, {NULL}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "</firstpath>; rel=preload; nopush, <secondpath>; rel=notpreload", NULL, {NULL}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "</firstpath>; rel=preload, </secondpath>; rel=preload; nopush, </thirdpath>; rel=preload", NULL, {"/firstpath"}, {"/thirdpath"}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "hogefoo", NULL, {NULL}); DO_CHECK(&H2O_URL_SCHEME_HTTP, &input_authority, "</111>; rel=preload, </222>; rel=preload; nopush, </333>; rel=preload; x-http2-push-only, </444>; rel=preload", "</111>; rel=preload, </222>; rel=preload; nopush, </444>; rel=preload", {"/111"}, {"/333"}, {"/444"}); h2o_mem_clear_pool(&pool); #undef DO_CHECK }
static void test_extract_push_path_from_link_header(void) { h2o_mem_pool_t pool; h2o_iovec_vector_t paths; h2o_iovec_t path; h2o_iovec_t base_path = {H2O_STRLIT("/basepath/")}, input_authority = {H2O_STRLIT("basehost")}, other_authority = {H2O_STRLIT("otherhost")}; #define INPUT base_path, &H2O_URL_SCHEME_HTTP, input_authority h2o_mem_init_pool(&pool); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http://basehost/otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/basepath/otherpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<../otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http:otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/basepath/otherpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<../otherpath>; rel=author"), INPUT, NULL, NULL); ok(paths.size == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http://basehost:81/otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<https://basehost/otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<https:otherpath>; rel=preload"), INPUT, NULL, NULL); ok(paths.size == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</otherpath>; rel=preload"), INPUT, &H2O_URL_SCHEME_HTTPS, &input_authority); ok(paths.size == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</otherpath>; rel=preload"), INPUT, &H2O_URL_SCHEME_HTTP, &input_authority); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</otherpath>; rel=preload"), INPUT, &H2O_URL_SCHEME_HTTP, &other_authority); ok(paths.entries == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http://basehost/otherpath>; rel=preload"), INPUT, &H2O_URL_SCHEME_HTTP, &other_authority); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/otherpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("<http:otherpath>; rel=preload; nopush"), INPUT, NULL, NULL); ok(paths.entries == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</firstpath>; rel=preload, </secondpath>; rel=preload"), INPUT, &H2O_URL_SCHEME_HTTP, &input_authority); ok(paths.size == 2); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/firstpath"))); path = paths.entries[1]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/secondpath"))); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</firstpath>; rel=preload; nopush, </secondpath>; rel=preload"), INPUT, &H2O_URL_SCHEME_HTTP, &input_authority); ok(paths.size == 1); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/secondpath"))); paths = h2o_extract_push_path_from_link_header( &pool, H2O_STRLIT("</firstpath>; rel=preload; nopush, </secondpath>; nopush; rel=preload; </thirdpath>"), INPUT, &H2O_URL_SCHEME_HTTP, &input_authority); ok(paths.size == 0); paths = h2o_extract_push_path_from_link_header(&pool, H2O_STRLIT("</firstpath>; rel=preload; nopush, <secondpath>; rel=notpreload"), INPUT, &H2O_URL_SCHEME_HTTP, &input_authority); ok(paths.size == 0); paths = h2o_extract_push_path_from_link_header( &pool, H2O_STRLIT("</firstpath>; rel=preload, </secondpath>; rel=preload; nopush, </thirdpath>; rel=preload"), INPUT, &H2O_URL_SCHEME_HTTP, &input_authority); ok(paths.size == 2); path = paths.entries[0]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/firstpath"))); path = paths.entries[1]; ok(h2o_memis(path.base, path.len, H2O_STRLIT("/thirdpath"))); h2o_mem_clear_pool(&pool); #undef INPUT }
static void test_request(h2o_iovec_t first_req, h2o_iovec_t second_req, h2o_iovec_t third_req) { h2o_hpack_header_table_t header_table; h2o_req_t req; h2o_iovec_t in; int r, allow_psuedo; memset(&header_table, 0, sizeof(header_table)); header_table.hpack_capacity = 4096; memset(&req, 0, sizeof(req)); h2o_mem_init_pool(&req.pool); allow_psuedo = 1; in = first_req; r = h2o_hpack_parse_headers(&req, &header_table, &allow_psuedo, (const uint8_t*)in.base, in.len); ok(r == 0); ok(allow_psuedo == 1); ok(req.authority.len == 15); ok(memcmp(req.authority.base, H2O_STRLIT("www.example.com")) == 0); ok(req.method.len == 3); ok(memcmp(req.method.base, H2O_STRLIT("GET")) == 0); ok(req.path.len == 1); ok(memcmp(req.path.base, H2O_STRLIT("/")) == 0); ok(req.scheme.len == 4); ok(memcmp(req.scheme.base, H2O_STRLIT("http")) == 0); ok(req.headers.size == 0); h2o_mem_clear_pool(&req.pool); memset(&req, 0, sizeof(req)); h2o_mem_init_pool(&req.pool); allow_psuedo = 1; in = second_req; r = h2o_hpack_parse_headers(&req, &header_table, &allow_psuedo, (const uint8_t*)in.base, in.len); ok(r == 0); ok(allow_psuedo == 0); ok(req.authority.len == 15); ok(memcmp(req.authority.base, H2O_STRLIT("www.example.com")) == 0); ok(req.method.len == 3); ok(memcmp(req.method.base, H2O_STRLIT("GET")) == 0); ok(req.path.len == 1); ok(memcmp(req.path.base, H2O_STRLIT("/")) == 0); ok(req.scheme.len == 4); ok(memcmp(req.scheme.base, H2O_STRLIT("http")) == 0); ok(req.headers.size == 1); ok(h2o_lcstris(req.headers.entries[0].name->base, req.headers.entries[0].name->len, H2O_STRLIT("cache-control"))); ok(h2o_lcstris(req.headers.entries[0].value.base, req.headers.entries[0].value.len, H2O_STRLIT("no-cache"))); h2o_mem_clear_pool(&req.pool); memset(&req, 0, sizeof(req)); h2o_mem_init_pool(&req.pool); allow_psuedo = 1; in = third_req; r = h2o_hpack_parse_headers(&req, &header_table, &allow_psuedo, (const uint8_t*)in.base, in.len); ok(r == 0); ok(allow_psuedo == 0); ok(req.authority.len == 15); ok(memcmp(req.authority.base, H2O_STRLIT("www.example.com")) == 0); ok(req.method.len == 3); ok(memcmp(req.method.base, H2O_STRLIT("GET")) == 0); ok(req.path.len == 11); ok(memcmp(req.path.base, H2O_STRLIT("/index.html")) == 0); ok(req.scheme.len == 5); ok(memcmp(req.scheme.base, H2O_STRLIT("https")) == 0); ok(req.headers.size == 1); ok(h2o_lcstris(req.headers.entries[0].name->base, req.headers.entries[0].name->len, H2O_STRLIT("custom-key"))); ok(h2o_lcstris(req.headers.entries[0].value.base, req.headers.entries[0].value.len, H2O_STRLIT("custom-value"))); h2o_hpack_dispose_header_table(&header_table); h2o_mem_clear_pool(&req.pool); }
void test_lib__http2__hpack(void) { h2o_mem_pool_t pool; h2o_mem_init_pool(&pool); note("decode_int"); { h2o_iovec_t in; const uint8_t *p; int32_t out; #define TEST(input, output) \ in = h2o_iovec_init(H2O_STRLIT(input)); \ p = (const uint8_t*)in.base; \ out = decode_int(&p, p + in.len, 7); \ ok(out == output); \ ok(p == (const uint8_t*)in.base + in.len); TEST("\x00", 0); TEST("\x03", 3); TEST("\x81", 1); TEST("\x7f\x00", 127); TEST("\x7f\x01", 128); TEST("\x7f\x7f", 254); TEST("\x7f\x81\x00", 128); TEST("\x7f\x80\x01", 255); TEST("\x7f\xff\xff\xff\x7f", 0xfffffff + 127); /* failures */ TEST("", -1); TEST("\x7f", -1); TEST("\x7f\xff", -1); TEST("\x7f\xff\xff\xff\xff", -1); #undef TEST } note("decode_huffman"); { h2o_iovec_t huffcode = { H2O_STRLIT("\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff") }; h2o_iovec_t *decoded = decode_huffman(&pool, (const uint8_t*)huffcode.base, huffcode.len); ok(decoded->len == sizeof("www.example.com") -1); ok(strcmp(decoded->base, "www.example.com") == 0); } h2o_mem_clear_pool(&pool); note("decode_header (literal header field with indexing)"); { struct st_h2o_decode_header_result_t result; h2o_hpack_header_table_t header_table; h2o_iovec_t in; int r; memset(&header_table, 0, sizeof(header_table)); header_table.hpack_capacity = 4096; in = h2o_iovec_init(H2O_STRLIT("\x40\x0a\x63\x75\x73\x74\x6f\x6d\x2d\x6b\x65\x79\x0d\x63\x75\x73\x74\x6f\x6d\x2d\x68\x65\x61\x64\x65\x72")); const uint8_t *p = (const uint8_t*)in.base; r = decode_header(&pool, &result, &header_table, &p, p + in.len); ok(r == 0); ok(result.name->len == 10); ok(strcmp(result.name->base, "custom-key") == 0); ok(result.value->len == 13); ok(strcmp(result.value->base, "custom-header") == 0); ok(header_table.hpack_size == 55); } h2o_mem_clear_pool(&pool); note("decode_header (literal header field without indexing)"); { struct st_h2o_decode_header_result_t result; h2o_hpack_header_table_t header_table; h2o_iovec_t in; int r; memset(&header_table, 0, sizeof(header_table)); header_table.hpack_capacity = 4096; in = h2o_iovec_init(H2O_STRLIT("\x04\x0c\x2f\x73\x61\x6d\x70\x6c\x65\x2f\x70\x61\x74\x68")); const uint8_t *p = (const uint8_t*)in.base; r = decode_header(&pool, &result, &header_table, &p, p + in.len); ok(r == 0); ok(result.name == &H2O_TOKEN_PATH->buf); ok(result.value->len == 12); ok(strcmp(result.value->base, "/sample/path") == 0); ok(header_table.hpack_size == 0); } h2o_mem_clear_pool(&pool); note("decode_header (literal header field never indexed)"); { struct st_h2o_decode_header_result_t result; h2o_hpack_header_table_t header_table; h2o_iovec_t in; int r; memset(&header_table, 0, sizeof(header_table)); header_table.hpack_capacity = 4096; in = h2o_iovec_init(H2O_STRLIT("\x10\x08\x70\x61\x73\x73\x77\x6f\x72\x64\x06\x73\x65\x63\x72\x65\x74")); const uint8_t *p = (const uint8_t*)in.base; r = decode_header(&pool, &result, &header_table, &p, p + in.len); ok(r == 0); ok(result.name->len == 8); ok(strcmp(result.name->base, "password") == 0); ok(result.value->len == 6); ok(strcmp(result.value->base, "secret") == 0); ok(header_table.hpack_size == 0); } h2o_mem_clear_pool(&pool); note("decode_header (indexed header field)"); { struct st_h2o_decode_header_result_t result; h2o_hpack_header_table_t header_table; h2o_iovec_t in; int r; memset(&header_table, 0, sizeof(header_table)); header_table.hpack_capacity = 4096; in = h2o_iovec_init(H2O_STRLIT("\x82")); const uint8_t *p = (const uint8_t*)in.base; r = decode_header(&pool, &result, &header_table, &p, p + in.len); ok(r == 0); ok(result.name == &H2O_TOKEN_METHOD->buf); ok(result.value->len == 3); ok(strcmp(result.value->base, "GET") == 0); ok(header_table.hpack_size == 0); } h2o_mem_clear_pool(&pool); note("request examples without huffman coding"); test_request( h2o_iovec_init(H2O_STRLIT("\x82\x86\x84\x41\x0f\x77\x77\x77\x2e\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d")), h2o_iovec_init(H2O_STRLIT("\x82\x86\x84\xbe\x58\x08\x6e\x6f\x2d\x63\x61\x63\x68\x65")), h2o_iovec_init(H2O_STRLIT("\x82\x87\x85\xbf\x40\x0a\x63\x75\x73\x74\x6f\x6d\x2d\x6b\x65\x79\x0c\x63\x75\x73\x74\x6f\x6d\x2d\x76\x61\x6c\x75\x65"))); note("request examples with huffman coding"); test_request( h2o_iovec_init(H2O_STRLIT("\x82\x86\x84\x41\x8c\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff")), h2o_iovec_init(H2O_STRLIT("\x82\x86\x84\xbe\x58\x86\xa8\xeb\x10\x64\x9c\xbf")), h2o_iovec_init(H2O_STRLIT("\x82\x87\x85\xbf\x40\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f\x89\x25\xa8\x49\xe9\x5b\xb8\xe8\xb4\xbf"))); note("encode_huffman"); { h2o_iovec_t huffcode = { H2O_STRLIT("\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff") }; char buf[sizeof("www.example.com")]; size_t l = encode_huffman((uint8_t*)buf, (uint8_t*)H2O_STRLIT("www.example.com")); ok(l == huffcode.len); ok(memcmp(buf, huffcode.base, huffcode.len) == 0); } note("response examples with huffmann coding"); { h2o_hpack_header_table_t header_table; h2o_res_t res; memset(&header_table, 0, sizeof(header_table)); header_table.hpack_capacity = 256; memset(&res, 0, sizeof(res)); res.status = 302; res.reason = "Found"; h2o_add_header(&pool, &res.headers, H2O_TOKEN_CACHE_CONTROL, H2O_STRLIT("private")); h2o_add_header(&pool, &res.headers, H2O_TOKEN_DATE, H2O_STRLIT("Mon, 21 Oct 2013 20:13:21 GMT")); h2o_add_header(&pool, &res.headers, H2O_TOKEN_LOCATION, H2O_STRLIT("https://www.example.com")); check_flatten(&header_table, &res, H2O_STRLIT("\x08\x03\x33\x30\x32\x58\x85\xae\xc3\x77\x1a\x4b\x61\x96\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66\xe0\x82\xa6\x2d\x1b\xff\x6e\x91\x9d\x29\xad\x17\x18\x63\xc7\x8f\x0b\x97\xc8\xe9\xae\x82\xae\x43\xd3")); memset(&res, 0, sizeof(res)); res.status = 307; res.reason = "Temporary Redirect"; h2o_add_header(&pool, &res.headers, H2O_TOKEN_CACHE_CONTROL, H2O_STRLIT("private")); h2o_add_header(&pool, &res.headers, H2O_TOKEN_DATE, H2O_STRLIT("Mon, 21 Oct 2013 20:13:21 GMT")); h2o_add_header(&pool, &res.headers, H2O_TOKEN_LOCATION, H2O_STRLIT("https://www.example.com")); check_flatten(&header_table, &res, H2O_STRLIT("\x08\x03\x33\x30\x37\xc0\xbf\xbe")); #if 0 h2o_iovec_init(H2O_STRLIT("\x48\x03\x33\x30\x37\xc1\xc0\xbf")), h2o_iovec_init(H2O_STRLIT("\x88\xc1\x61\x1d\x4d\x6f\x6e\x2c\x20\x32\x31\x20\x4f\x63\x74\x20\x32\x30\x31\x33\x20\x32\x30\x3a\x31\x33\x3a\x32\x32\x20\x47\x4d\x54\xc0\x5a\x04\x67\x7a\x69\x70\x77\x38\x66\x6f\x6f\x3d\x41\x53\x44\x4a\x4b\x48\x51\x4b\x42\x5a\x58\x4f\x51\x57\x45\x4f\x50\x49\x55\x41\x58\x51\x57\x45\x4f\x49\x55\x3b\x20\x6d\x61\x78\x2d\x61\x67\x65\x3d\x33\x36\x30\x30\x3b\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x31"))); #endif } h2o_mem_clear_pool(&pool); }