Exemple #1
0
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;
    }
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}