static mrb_value h2o_mrb_req_reprocess_request(mrb_state *mrb, mrb_value self) { h2o_mruby_internal_context_t *mruby_ctx = (h2o_mruby_internal_context_t *)mrb->ud; char *s; mrb_int len; h2o_url_t parsed, base, resolved; if (mruby_ctx->state != H2O_MRUBY_STATE_UNDETERMINED) mrb_raise(mrb, E_RUNTIME_ERROR, "response already sent"); mrb_get_args(mrb, "s", &s, &len); /* resolve the input URL: * * uses `hostconf->authority.hostport` as part of base to prevent relative-path internal redirect generating a TCP connection * * h2o_url_resolve always copies the memory (so the values will be preserved after mruby GC) */ if (h2o_url_parse_relative(s, (size_t)len, &parsed) != 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "failed to parse URL"); h2o_req_t *req = mruby_ctx->req; if (h2o_url_init(&base, req->scheme, req->hostconf->authority.hostport, req->pathconf->path) != 0) mrb_raise(mrb, E_RUNTIME_ERROR, "failed to parse current authority"); h2o_url_resolve(&req->pool, &base, &parsed, &resolved); /* request reprocess */ h2o_reprocess_request_deferred(req, req->method, resolved.scheme, resolved.authority, resolved.path, NULL, 0); mruby_ctx->state = H2O_MRUBY_STATE_RESPONSE_SENT; return mrb_nil_value(); }
static void push_one_path(h2o_mem_pool_t *pool, h2o_iovec_vector_t *paths_to_push, h2o_iovec_t *url, h2o_iovec_t base_path, const h2o_url_scheme_t *input_scheme, h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, h2o_iovec_t *base_authority) { h2o_url_t parsed, resolved; /* check the authority, and extract absolute path */ if (h2o_url_parse_relative(url->base, url->len, &parsed) != 0) return; /* fast-path for abspath form */ if (base_scheme == NULL && parsed.scheme == NULL && parsed.authority.base == NULL && url->len != 0 && url->base[0] == '/') { h2o_vector_reserve(pool, paths_to_push, paths_to_push->size + 1); paths_to_push->entries[paths_to_push->size++] = h2o_strdup(pool, url->base, url->len); return; } /* check scheme and authority if given URL contains either of the two, or if base is specified */ h2o_url_t base = {input_scheme, input_authority, {}, base_path, 65535}; if (base_scheme != NULL) { base.scheme = base_scheme; base.authority = *base_authority; } h2o_url_resolve(pool, &base, &parsed, &resolved); if (input_scheme != resolved.scheme) return; if (!h2o_lcstris(input_authority.base, input_authority.len, resolved.authority.base, resolved.authority.len)) return; h2o_vector_reserve(pool, paths_to_push, paths_to_push->size + 1); paths_to_push->entries[paths_to_push->size++] = resolved.path; }
h2o_iovec_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 void redirect_internally(h2o_redirect_handler_t *self, h2o_req_t *req, h2o_iovec_t dest) { h2o_iovec_t method; h2o_url_t input, resolved; /* resolve the URL */ if (h2o_url_parse_relative(dest.base, dest.len, &input) != 0) { h2o_req_log_error(req, MODULE_NAME, "invalid destination:%.*s", (int)dest.len, dest.base); goto SendInternalError; } if (input.scheme != NULL && input.authority.base != NULL) { resolved = input; } else { h2o_url_t base; /* we MUST to set authority to that of hostconf, or internal redirect might create a TCP connection */ if (h2o_url_init(&base, req->scheme, req->hostconf->authority.hostport, req->path) != 0) { h2o_req_log_error(req, MODULE_NAME, "failed to parse current authority:%.*s", (int)req->authority.len, req->authority.base); goto SendInternalError; } h2o_url_resolve(&req->pool, &base, &input, &resolved); } /* determine the method */ switch (self->status) { case 307: case 308: method = req->method; break; default: method = h2o_iovec_init(H2O_STRLIT("GET")); #ifndef _MSC_VER req->entity = (h2o_iovec_t){NULL}; #else req->entity = (h2o_iovec_t) { 0 }; #endif break; } h2o_reprocess_request_deferred(req, method, resolved.scheme, resolved.authority, resolved.path, NULL, 1); return; SendInternalError: h2o_send_error_503(req, "Internal Server Error", "internal server error", 0); }