static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, h2o_iovec_t msg, struct phr_header *headers, size_t num_headers) { struct rp_generator_t *self = client->data; size_t i; if (errstr != NULL && errstr != h2o_http1client_error_is_eos) { self->client = NULL; h2o_send_error(self->src_req, 502, "Gateway Error", errstr, 0); return NULL; } /* copy the response */ self->src_req->res.status = status; self->src_req->res.reason = h2o_strdup(&self->src_req->pool, msg.base, msg.len).base; for (i = 0; i != num_headers; ++i) { const h2o_token_t *token = h2o_lookup_token(headers[i].name, headers[i].name_len); h2o_iovec_t value; if (token != NULL) { if (token->is_connection_specific) { goto Skip; } if (token == H2O_TOKEN_CONTENT_LENGTH) { if (self->src_req->res.content_length != SIZE_MAX || (self->src_req->res.content_length = h2o_strtosize(headers[i].value, headers[i].value_len)) == SIZE_MAX) { self->client = NULL; h2o_send_error(self->src_req, 502, "Gateway Error", "invalid response from upstream", 0); return NULL; } goto Skip; } else if (token == H2O_TOKEN_LOCATION) { value = rewrite_location(&self->src_req->pool, headers[i].value, headers[i].value_len, self->upstream, self->src_req->scheme, self->src_req->authority, self->src_req->pathconf->path); goto AddHeader; } /* default behaviour, transfer the header downstream */ value = h2o_strdup(&self->src_req->pool, headers[i].value, headers[i].value_len); AddHeader: h2o_add_header(&self->src_req->pool, &self->src_req->res.headers, token, value.base, value.len); Skip: ; } else { h2o_iovec_t name = h2o_strdup(&self->src_req->pool, headers[i].name, headers[i].name_len); h2o_iovec_t value = h2o_strdup(&self->src_req->pool, headers[i].value, headers[i].value_len); h2o_add_header_by_str(&self->src_req->pool, &self->src_req->res.headers, name.base, name.len, 0, value.base, value.len); } } /* declare the start of the response */ h2o_start_response(self->src_req, &self->super); if (errstr == h2o_http1client_error_is_eos) { self->client = NULL; h2o_send(self->src_req, NULL, 0, 1); return NULL; } return on_body; }
static h2o_http1client_body_cb on_head(h2o_http1client_t *client, const char *errstr, int minor_version, int status, h2o_iovec_t msg, struct phr_header *headers, size_t num_headers) { 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(req, 502, "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) { const h2o_token_t *token = h2o_lookup_token(headers[i].name, headers[i].name_len); h2o_iovec_t value; if (token != NULL) { 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, 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(req, 502, "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, 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, 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_puth_path_in_link_header(req, headers[i].value, headers[i].value_len); } /* default behaviour, transfer the header downstream */ AddHeaderDuped: value = h2o_strdup(&req->pool, headers[i].value, headers[i].value_len); AddHeader: h2o_add_header(&req->pool, &req->res.headers, token, value.base, value.len); Skip: ; } else { h2o_iovec_t name = h2o_strdup(&req->pool, headers[i].name, headers[i].name_len); h2o_iovec_t value = h2o_strdup(&req->pool, headers[i].value, headers[i].value_len); h2o_add_header_by_str(&req->pool, &req->res.headers, name.base, name.len, 0, 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, H2O_STRLIT("websocket")); on_websocket_upgrade(self, client_ctx->websocket_timeout); 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, 1); return NULL; } return on_body; }