void h2o__proxy_process_request(h2o_req_t *req) { h2o_req_overrides_t *overrides = req->overrides; h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); struct rp_generator_t *self; if (overrides != NULL) { if (overrides->socketpool != NULL) { self = proxy_send_prepare(req, 1); h2o_http1client_connect_with_pool(&self->client, self, client_ctx, overrides->socketpool, on_connect); return; } else if (overrides->hostport.host.base != NULL) { self = proxy_send_prepare(req, 0); h2o_http1client_connect(&self->client, self, client_ctx, req->overrides->hostport.host, req->overrides->hostport.port, 0, on_connect); return; } } { /* default logic */ h2o_iovec_t host; uint16_t port; if (h2o_url_parse_hostport(req->authority.base, req->authority.len, &host, &port) == NULL) { h2o_req_log_error(req, "lib/core/proxy.c", "invalid URL supplied for internal redirection:%s://%.*s%.*s", req->scheme->name.base, (int)req->authority.len, req->authority.base, (int)req->path.len, req->path.base); h2o_send_error_502(req, "Gateway Error", "internal error", 0); return; } if (port == 65535) port = req->scheme->default_port; self = proxy_send_prepare(req, 0); h2o_http1client_connect(&self->client, self, client_ctx, host, port, req->scheme == &H2O_URL_SCHEME_HTTPS, on_connect); return; } }
static h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr, h2o_iovec_t **reqbufs, size_t *reqbufcnt, int *method_is_head) { struct rp_generator_t *self = client->data; if (errstr != NULL) { self->client = NULL; h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr); h2o_send_error_502(self->src_req, "Gateway Error", errstr, 0); return NULL; } *reqbufs = self->up_req.bufs; *reqbufcnt = self->up_req.bufs[1].base != NULL ? 2 : 1; *method_is_head = self->up_req.is_head; self->client->informational_cb = on_1xx; return on_head; }
static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, h2o_iovec_t msg, h2o_header_t *headers, size_t num_headers, int rlen) { struct rp_generator_t *self = client->data; h2o_req_t *req = self->src_req; size_t i; if (errstr != NULL && errstr != h2o_http1client_error_is_eos) { self->client = NULL; h2o_req_log_error(req, "lib/core/proxy.c", "%s", errstr); h2o_send_error_502(req, "Gateway Error", errstr, 0); return NULL; } /* copy the response (note: all the headers must be copied; http1client discards the input once we return from this callback) */ req->res.status = status; req->res.reason = h2o_strdup(&req->pool, msg.base, msg.len).base; for (i = 0; i != num_headers; ++i) { if (h2o_iovec_is_token(headers[i].name)) { const h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, headers[i].name); h2o_iovec_t value; if (token->proxy_should_drop) { goto Skip; } if (token == H2O_TOKEN_CONTENT_LENGTH) { if (req->res.content_length != SIZE_MAX || (req->res.content_length = h2o_strtosize(headers[i].value.base, headers[i].value.len)) == SIZE_MAX) { self->client = NULL; h2o_req_log_error(req, "lib/core/proxy.c", "%s", "invalid response from upstream (malformed content-length)"); h2o_send_error_502(req, "Gateway Error", "invalid response from upstream", 0); return NULL; } goto Skip; } else if (token == H2O_TOKEN_LOCATION) { if (req->res_is_delegated && (300 <= status && status <= 399) && status != 304) { self->client = NULL; h2o_iovec_t method = h2o_get_redirect_method(req->method, status); h2o_send_redirect_internal(req, method, headers[i].value.base, headers[i].value.len, 1); return NULL; } if (req->overrides != NULL && req->overrides->location_rewrite.match != NULL) { value = rewrite_location(&req->pool, headers[i].value.base, headers[i].value.len, req->overrides->location_rewrite.match, req->input.scheme, req->input.authority, req->overrides->location_rewrite.path_prefix); if (value.base != NULL) goto AddHeader; } goto AddHeaderDuped; } else if (token == H2O_TOKEN_LINK) { h2o_iovec_t new_value; new_value = h2o_push_path_in_link_header(req, headers[i].value.base, headers[i].value.len); if (!new_value.len) goto Skip; headers[i].value.base = new_value.base; headers[i].value.len = new_value.len; } else if (token == H2O_TOKEN_SERVER) { if (!req->conn->ctx->globalconf->proxy.preserve_server_header) goto Skip; } else if (token == H2O_TOKEN_X_COMPRESS_HINT) { req->compress_hint = compress_hint_to_enum(headers[i].value.base, headers[i].value.len); goto Skip; } /* default behaviour, transfer the header downstream */ AddHeaderDuped: value = h2o_strdup(&req->pool, headers[i].value.base, headers[i].value.len); AddHeader: h2o_add_header(&req->pool, &req->res.headers, token, headers[i].orig_name, value.base, value.len); Skip:; } else { h2o_iovec_t name = h2o_strdup(&req->pool, headers[i].name->base, headers[i].name->len); h2o_iovec_t value = h2o_strdup(&req->pool, headers[i].value.base, headers[i].value.len); h2o_add_header_by_str(&req->pool, &req->res.headers, name.base, name.len, 0, headers[i].orig_name, value.base, value.len); } } if (self->is_websocket_handshake && req->res.status == 101) { h2o_http1client_ctx_t *client_ctx = get_client_ctx(req); assert(client_ctx->websocket_timeout != NULL); h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_UPGRADE, NULL, H2O_STRLIT("websocket")); on_websocket_upgrade(self, client_ctx->websocket_timeout, rlen); self->client = NULL; return NULL; } /* declare the start of the response */ h2o_start_response(req, &self->super); if (errstr == h2o_http1client_error_is_eos) { self->client = NULL; h2o_send(req, NULL, 0, H2O_SEND_STATE_FINAL); return NULL; } return on_body; }