h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t prefix_len) { 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 */ 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); return h2o_concat_list(&req->pool, parts, num_parts); }
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_vector_t paths_to_push = {}; h2o_iovec_t iter = h2o_iovec_init(value, value_len), token_value; const char *token; size_t token_len; /* extract URL values from Link: </pushed.css>; rel=preload */ do { if ((token = h2o_next_token(&iter, ';', &token_len, NULL)) == NULL) break; /* first element should be <URL> */ if (!(token_len >= 2 && token[0] == '<' && token[token_len - 1] == '>')) break; h2o_iovec_t url = h2o_iovec_init(token + 1, token_len - 2); /* find rel=preload */ int preload = 0, nopush = 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++; } } if (!nopush && preload) push_one_path(pool, &paths_to_push, &url, base_path, input_scheme, input_authority, base_scheme, base_authority); } while (token != NULL); return paths_to_push; }
static void on_connection_ready(struct st_h2o_http1client_t *client) { h2o_iovec_t proxy_protocol = h2o_iovec_init(NULL, 0); int chunked = 0; h2o_iovec_t connection_header = h2o_iovec_init(NULL, 0); h2o_httpclient_properties_t props = { &proxy_protocol, &chunked, &connection_header, }; h2o_iovec_t method; h2o_url_t url; h2o_header_t *headers; size_t num_headers; h2o_iovec_t body; client->super._cb.on_head = client->super._cb.on_connect(&client->super, NULL, &method, &url, (const h2o_header_t **)&headers, &num_headers, &body, &client->proceed_req, &props, client->_origin); if (client->super._cb.on_head == NULL) { close_client(client); return; } h2o_iovec_t reqbufs[3]; size_t reqbufcnt = 0; if (props.proxy_protocol->base != NULL) reqbufs[reqbufcnt++] = *props.proxy_protocol; reqbufs[reqbufcnt++] = build_request(client, method, url, *props.connection_header, headers, num_headers); client->_is_chunked = *props.chunked; client->_method_is_head = h2o_memis(method.base, method.len, H2O_STRLIT("HEAD")); if (client->proceed_req != NULL) { if (body.base != NULL) { h2o_buffer_init(&client->_body_buf, &h2o_socket_buffer_prototype); if (h2o_buffer_append(&client->_body_buf, body.base, body.len) == 0) { on_send_request(client->sock, "Internal error"); return; } } h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_req_body_done); } else { if (client->_is_chunked) { assert(body.base != NULL); reqbufcnt += encode_chunk(client, reqbufs + reqbufcnt, body); } else if (body.base != NULL) { reqbufs[reqbufcnt++] = body; } h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_send_request); } /* TODO no need to set the timeout if all data has been written into TCP sendbuf */ client->super._timeout.cb = on_send_timeout; h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout); client->super.timings.request_begin_at = h2o_gettimeofday(client->super.ctx->loop); }
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(H2O_STRLIT("-")); } }
static int on_config_mruby_handler_path(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) { struct mruby_configurator_t *self = (void *)cmd->configurator; if (node->data.scalar[0] == '\0') { self->vars->mruby_handler_path = h2o_iovec_init(NULL, 0); } else { self->vars->mruby_handler_path = h2o_iovec_init(node->data.scalar, strlen(node->data.scalar)); h2o_mruby_register(ctx->pathconf, self->vars); } return 0; }
size_t encode_chunk(struct st_h2o_http1client_t *client, h2o_iovec_t *bufs, h2o_iovec_t chunk) { size_t i = 0; bufs[i].len = snprintf(client->_chunk_len_str, sizeof(client->_chunk_len_str), "%zx\r\n", chunk.len); bufs[i++].base = client->_chunk_len_str; if (chunk.base != NULL) bufs[i++] = h2o_iovec_init(chunk.base, chunk.len); bufs[i++] = h2o_iovec_init("\r\n", 2); return i; }
void test_build_destination(void) { h2o_pathconf_t conf_not_slashed = {NULL, {H2O_STRLIT("/abc")}}, conf_slashed = {NULL, {H2O_STRLIT("/abc/")}}; h2o_req_t req; h2o_iovec_t dest; int escape; for (escape = 0; escape <= 1; escape++) { h2o_init_request(&req, NULL, NULL); note("escaping: %s", escape ? "on" : "off"); req.path_normalized = h2o_iovec_init(H2O_STRLIT("/abc/xyz")); req.query_at = req.path_normalized.len; req.input.path = req.path = h2o_concat(&req.pool, req.path_normalized, h2o_iovec_init(H2O_STRLIT("?q"))); /* basic pattern */ req.pathconf = &conf_not_slashed; dest = h2o_build_destination(&req, H2O_STRLIT("/def"), escape); ok(h2o_memis(dest.base, dest.len, H2O_STRLIT("/def/xyz?q"))); dest = h2o_build_destination(&req, H2O_STRLIT("/def/"), escape); ok(h2o_memis(dest.base, dest.len, H2O_STRLIT("/def/xyz?q"))); req.pathconf = &conf_slashed; dest = h2o_build_destination(&req, H2O_STRLIT("/def"), escape); ok(h2o_memis(dest.base, dest.len, H2O_STRLIT("/def/xyz?q"))); dest = h2o_build_destination(&req, H2O_STRLIT("/def/"), escape); ok(h2o_memis(dest.base, dest.len, H2O_STRLIT("/def/xyz?q"))); /* test wo. query */ if (escape) { req.pathconf = &conf_not_slashed; req.query_at = SIZE_MAX; dest = h2o_build_destination(&req, H2O_STRLIT("/def"), escape); ok(h2o_memis(dest.base, dest.len, H2O_STRLIT("/def/xyz"))); } /* no trailing */ req.path_normalized = h2o_iovec_init(H2O_STRLIT("/abc")); req.query_at = req.path_normalized.len; req.input.path = req.path = h2o_concat(&req.pool, req.path_normalized, h2o_iovec_init(H2O_STRLIT("?q"))); req.pathconf = &conf_not_slashed; dest = h2o_build_destination(&req, H2O_STRLIT("/def"), escape); ok(h2o_memis(dest.base, dest.len, H2O_STRLIT("/def?q"))); dest = h2o_build_destination(&req, H2O_STRLIT("/def/"), escape); ok(h2o_memis(dest.base, dest.len, H2O_STRLIT("/def/?q"))); } h2o_mem_clear_pool(&req.pool); }
h2o_iovec_t h2o_extract_push_path_from_link_header(h2o_mem_pool_t *pool, const char *value, size_t value_len, const h2o_url_scheme_t *base_scheme, h2o_iovec_t *base_authority, h2o_iovec_t *base_path) { h2o_iovec_t url; h2o_url_t parsed, resolved; { /* extract URL value from: Link: </pushed.css>; rel=preload */ h2o_iovec_t iter = h2o_iovec_init(value, value_len), token_value; const char *token; size_t token_len; /* first element should be <URL> */ if ((token = h2o_next_token(&iter, ';', &token_len, NULL)) == NULL) goto None; if (!(token_len >= 2 && token[0] == '<' && token[token_len - 1] == '>')) goto None; url = h2o_iovec_init(token + 1, token_len - 2); /* find rel=preload */ while ((token = h2o_next_token(&iter, ';', &token_len, &token_value)) != NULL) { if (h2o_lcstris(token, token_len, H2O_STRLIT("rel")) && h2o_lcstris(token_value.base, token_value.len, H2O_STRLIT("preload"))) break; } if (token == NULL) goto None; } /* check the authority, and extract absolute path */ if (h2o_url_parse_relative(url.base, url.len, &parsed) != 0) goto None; /* return the URL found in Link header, if it is an absolute path-only URL */ if (parsed.scheme == NULL && parsed.authority.base == NULL && url.len != 0 && url.base[0] == '/') return h2o_strdup(pool, url.base, url.len); /* check scheme and authority if given URL contains either of the two */ h2o_url_t base = {base_scheme, *base_authority, {}, *base_path, 65535}; h2o_url_resolve(pool, &base, &parsed, &resolved); if (base.scheme != resolved.scheme) goto None; if (parsed.authority.base != NULL && !h2o_lcstris(base.authority.base, base.authority.len, resolved.authority.base, resolved.authority.len)) goto None; return resolved.path; None: return (h2o_iovec_t){}; }
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 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; }
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){}; /* 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; }
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.connect_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT; config->proxy.first_byte_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT; config->proxy.emit_x_forwarded_headers = 1; config->proxy.emit_via_header = 1; config->proxy.emit_missing_date_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.active_stream_window_size = H2O_DEFAULT_HTTP2_ACTIVE_STREAM_WINDOW_SIZE; 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->send_informational_mode = H2O_SEND_INFORMATIONAL_MODE_EXCEPT_H1; config->mimemap = h2o_mimemap_create(); h2o_socketpool_init_global(&config->proxy.global_socketpool, SIZE_MAX); h2o_configurator__init_core(config); }
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, 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, 1); return 0; }
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"))); close_connection(conn); }
static void do_compress(h2o_compress_context_t *_self, h2o_iovec_t *inbufs, size_t inbufcnt, int is_final, h2o_iovec_t **outbufs, size_t *outbufcnt) { 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 = compress_chunk(self, inbufs[i].base, inbufs[i].len, Z_NO_FLUSH, outbufindex); last_buf = inbufs[i]; } else { last_buf = h2o_iovec_init(NULL, 0); } outbufindex = compress_chunk(self, last_buf.base, last_buf.len, is_final ? Z_FINISH : Z_SYNC_FLUSH, outbufindex); *outbufs = self->bufs.entries; *outbufcnt = outbufindex + 1; if (is_final) { deflateEnd(&self->zs); self->zs_is_open = 0; } }
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(conn, 413, "Request Entity Too Large", "request entity is too large"); return; } if (ret < 0) { if (ret == -2) { /* incomplete */ return; } /* error */ entity_read_send_error(conn, 400, "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 */ return on_entity_read_complete(conn); }
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, H2O_ALIGNOF(*ostream), sizeof(*ostream), slot); ostream->do_send = on_send; }
static h2o_iovec_t rewrite_location(h2o_mem_pool_t *pool, const char *location, size_t location_len, h2o_proxy_location_t *upstream, h2o_iovec_t req_scheme, h2o_iovec_t req_authority, h2o_iovec_t req_basepath) { h2o_iovec_t loc_scheme, loc_host, loc_path; uint16_t loc_port; if (h2o_parse_url(location, location_len, &loc_scheme, &loc_host, &loc_port, &loc_path) != 0 || ! test_location_match(upstream, loc_scheme, loc_host, loc_port, loc_path)) return h2o_iovec_init(location, location_len); return h2o_concat(pool, req_scheme, h2o_iovec_init(H2O_STRLIT("://")), req_authority, req_basepath, h2o_iovec_init(loc_path.base + upstream->path.len, loc_path.len - upstream->path.len)); }
static void test_next_token(void) { h2o_iovec_t iter; const char *token; size_t token_len; #define NEXT() \ if ((token = h2o_next_token(&iter, ',', &token_len, NULL)) == NULL) { \ ok(0); \ return; \ } iter = h2o_iovec_init(H2O_STRLIT("public, max-age=86400, must-revalidate")); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("public"))); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("max-age=86400"))); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("must-revalidate"))); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); iter = h2o_iovec_init(H2O_STRLIT(" public ,max-age=86400 ,")); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("public"))); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("max-age=86400"))); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); iter = h2o_iovec_init(H2O_STRLIT("")); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); iter = h2o_iovec_init(H2O_STRLIT(", ,a, ")); NEXT(); ok(token_len == 0); NEXT(); ok(token_len == 0); NEXT(); ok(h2o_memis(token, token_len, H2O_STRLIT("a"))); token = h2o_next_token(&iter, ',', &token_len, NULL); ok(token == NULL); #undef NEXT }
void test_lib__handler__fastcgi_c() { h2o_globalconf_t globalconf; h2o_hostconf_t *hostconf; h2o_pathconf_t *pathconf; h2o_config_init(&globalconf); globalconf.server_name = h2o_iovec_init(H2O_STRLIT("h2o/1.2.1-alpha1")); hostconf = h2o_config_register_host(&globalconf, h2o_iovec_init(H2O_STRLIT("default")), 65535); pathconf = h2o_config_register_path(hostconf, "/"); h2o_context_init(&ctx, test_loop, &globalconf); subtest("build-request", test_build_request); h2o_context_dispose(&ctx); h2o_config_dispose(&globalconf); }
void test_build_destination_escaping(void) { h2o_req_t req; h2o_iovec_t dest; int escape = 0; int i, j; struct { char *pathconf; char *dest; char *input; char *output; } tests[] = { {"/abc", "/def", "/abc/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/%61bc/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/%61%62c/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/%61%62%63/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/./%61%62%63/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/../%61%62%63/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/././%61%62%63/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/./.././%61%62%63/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/./../blah/../%61%62%63/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/./../blah/.././%61%62c/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/./../blah/.././../../%61b%63/xyz?query&m=n/o", "/def/xyz?query&m=n/o"}, {"/abc", "/def", "/abc/xyz/?query&m=n/o", "/def/xyz/?query&m=n/o"}, {"/abc", "/def", "/abc/xyz/.?query&m=n/o", "/def/xyz/.?query&m=n/o"}, {"/abc", "/def", "/abc/xyz/./?query&m=n/o", "/def/xyz/./?query&m=n/o"}, {"/abc", "/def", "/abc/xyz/..?query&m=n/o", "/def/xyz/..?query&m=n/o"}, {"/abc", "/def", "/abc/xyz/../?query&m=n/o", "/def/xyz/../?query&m=n/o"}, {"/abc", "/def", "/abc/xyz/../a?query&m=n/o", "/def/xyz/../a?query&m=n/o"}, {"/abc", "/def", "/abc/%yz/?query&m=n/o", "/def/%yz/?query&m=n/o"}, {"/abc", "/def", "/abc/%78yz/?query&m=n/o", "/def/%78yz/?query&m=n/o"}, {"/", "/", "/xyz/../mno", "/xyz/../mno"}, {"/", "/", "/xyz/../mno/..", "/xyz/../mno/.."}, {"/", "/def", "/xyz/../mno", "/def/xyz/../mno"}, {"/", "/def/", "/xyz/../mno", "/def/xyz/../mno"}, {"/", "/def", "/xyz/../", "/def/xyz/../"}, {"/", "/def/", "/xyz/..", "/def/xyz/.."}, }; h2o_init_request(&req, NULL, NULL); /* 'j' runs the test with a missing leading '/' in the input path */ for (j = 0; j <= 1; j++) { for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { h2o_pathconf_t conf = {NULL, {tests[i].pathconf, strlen(tests[i].pathconf)}}; req.pathconf = &conf; req.path = req.input.path = h2o_iovec_init(tests[i].input + j, strlen(tests[i].input) - j); req.norm_indexes = NULL; req.path_normalized = h2o_url_normalize_path(&req.pool, req.path.base, req.path.len, &req.query_at, &req.norm_indexes); dest = h2o_build_destination(&req, tests[i].dest, strlen(tests[i].dest), escape); note("%s: %d, %sskipping the leading '/'", tests[i].input, i, !j ? "not " : ""); ok(dest.len == strlen(tests[i].output)); ok(h2o_memis(dest.base, dest.len, tests[i].output, strlen(tests[i].output))); } } h2o_mem_clear_pool(&req.pool); }
static void __get_keys_send(get_keys_generator_t *self, int e, MDB_val* k, h2o_req_t *req) { if (0 == e && 0 >= strncmp(k->mv_data, self->key->s, min(self->key->len, k->mv_size))) { #define SEND_BUFS 2 h2o_iovec_t body[SEND_BUFS]; body[0] = h2o_iovec_init(k->mv_data, k->mv_size); body[1] = h2o_iovec_init("\n", 1); h2o_send(req, body, SEND_BUFS, 0); } else { h2o_send(req, NULL, 0, 1); __get_keys_close((h2o_generator_t*)self, req); } }
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); }
static int on_req(h2o_handler_t *_self, h2o_req_t *req) { h2o_redirect_handler_t *self = (void *)_self; /* build the URL */ h2o_iovec_t path = h2o_iovec_init(req->path_normalized.base + req->pathconf->path.len, req->path_normalized.len - req->pathconf->path.len); h2o_iovec_t query = req->query_at != SIZE_MAX ? h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at) : h2o_iovec_init(H2O_STRLIT("")); h2o_iovec_t dest = h2o_concat(&req->pool, self->prefix, path, query); if (self->internal) { redirect_internally(self, req, dest); } else { h2o_send_redirect(req, self->status, "Redirected", dest.base, dest.len); } return 0; }
static void test_next_token2(void) { h2o_iovec_t iter, value; const char *name; size_t name_len; #define NEXT() \ if ((name = h2o_next_token(&iter, ',', &name_len, &value)) == NULL) { \ ok(0); \ return; \ } iter = h2o_iovec_init(H2O_STRLIT("public, max-age=86400, must-revalidate")); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("public"))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("max-age"))); ok(h2o_memis(value.base, value.len, H2O_STRLIT("86400"))); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("must-revalidate"))); ok(value.base == NULL); ok(value.len == 0); name = h2o_next_token(&iter, ',', &name_len, &value); ok(name == NULL); iter = h2o_iovec_init(H2O_STRLIT("public, max-age = 86400 = c , must-revalidate=")); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("public"))); ok(value.base == NULL); ok(value.len == 0); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("max-age"))); ok(h2o_memis(value.base, value.len, H2O_STRLIT("86400 = c"))); NEXT(); ok(h2o_memis(name, name_len, H2O_STRLIT("must-revalidate"))); name = h2o_next_token(&iter, ',', &name_len, &value); ok(h2o_memis(value.base, value.len, H2O_STRLIT(""))); #undef NEXT }
static void check(const h2o_url_scheme_t *scheme, const char *host, const char *expected) { h2o_loopback_conn_t *conn = h2o_loopback_create(&ctx, ctx.globalconf->hosts); conn->req.input.method = h2o_iovec_init(H2O_STRLIT("GET")); conn->req.input.scheme = scheme; conn->req.input.authority = h2o_iovec_init(host, strlen(host)); conn->req.input.path = h2o_iovec_init(H2O_STRLIT("/")); h2o_loopback_run_loop(conn); ok(conn->req.res.status == 200); size_t index = h2o_find_header_by_str(&conn->req.res.headers, H2O_STRLIT("x-authority"), SIZE_MAX); ok(index != SIZE_MAX); if (index != SIZE_MAX) { ok(h2o_memis(conn->req.res.headers.entries[index].value.base, conn->req.res.headers.entries[index].value.len, expected, strlen(expected))); } h2o_loopback_destroy(conn); }
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 ssize_t fixup_request(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.scheme = conn->sock->ssl != NULL ? h2o_iovec_init(H2O_STRLIT("https")) : h2o_iovec_init(H2O_STRLIT("http")); conn->req.version = 0x100 | minor_version; /* 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.method = h2o_strdup(&conn->req.pool, conn->req.method.base, conn->req.method.len); conn->req.path = h2o_strdup(&conn->req.pool, conn->req.path.base, conn->req.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.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; } return entity_header_index; }
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); }
static h2o_iovec_t requests_status_final(void *priv, h2o_globalconf_t *gconf, h2o_req_t *req) { #ifndef _MSC_VER h2o_iovec_t ret = {NULL}; #else h2o_iovec_t ret = { 0 }; #endif 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); #ifndef _MSC_VER pthread_mutex_destroy(&rsc->mutex); #else uv_mutex_destroy(&rsc->mutex); #endif free(rsc); return ret; }