From 036d3d3d66f33539dc8ab52de8d2049a5ca2587d Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 28 Apr 2017 18:53:08 -0400 Subject: [PATCH] [mod_proxy] simple host/url mapping in headers (fixes #152) Provide a simple mechanism for mapping host and urlpath header strings in proxied request and response well-known headers. This *is not* intended as a one-size-fits-all, infinitely extensible, regex rewriting engine. Instead, the proxy.header directive aims to provide built-in functionality in mod_proxy for a few common use cases by performing simple host matching or urlpath prefix matching, and using the mapping of the first match. More complex use cases could possibly be handled by a custom lighttpd module (which does not currently exist). Note: the contents of the HTTP request-line and HTTP headers may or may not be in normalized canonical forms, which may or may not influence the simple matching performed. Admins should take care to provide safe defaults (fail closed) if mapping is expected to occur and blindly passing non-mapped requests is undesirable. proxy.header = ( #"map-host-request" => ( #"-" => "...",#replace provided given Host request authority #"..." => "-",#preserve existing authority (no further matching) #"..." => "", #preserve existing authority (no further matching) # #(equivalent to "xxx" => "xxx") #"xxx" => "yyy", #map one string ("xxx") to another ("yyy") #), #"map-host-response" => ( #"-" => "...",#replace authority used in backend request #"..." => "-",#replace with original authority #"..." => "", #preserve existing authority (no further matching) # #(equivalent to "xxx" => "xxx") #"xxx" => "yyy", #map one string ("xxx") to another ("yyy") #), #"map-urlpath" => ( #"/xxx" => "/yyy",#map one urlpath prefix to another #"/xxx/" => "/", #map one urlpath prefix to another #"/xxx" => "", #map one urlpath prefix to another #"/key" => "/value", # Note: request headers have matching "key" prefix replaced with # "value", and response headers have matching "value" prefix # replaced with "key", with a pre-test of the "value" from the # first-matched "key" in request headers (if there was a match) #), #"https-remap" => "enable", # For https requests from client, map https:// to http:// # when map-host-request matches URI in request, and map http:// # to https:// when map-host-response matches URI in response. # (mod_proxy currently sends all backend requests as http) ) x-ref: "feature to remove part of the URI when passing along requests..." https://redmine.lighttpd.net/issues/152 --- src/base.h | 2 + src/http-header-glue.c | 8 + src/mod_proxy.c | 406 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 394 insertions(+), 22 deletions(-) diff --git a/src/base.h b/src/base.h index d6a4a1b8..f92b84f4 100644 --- a/src/base.h +++ b/src/base.h @@ -129,6 +129,8 @@ typedef union { #define HTTP_DATE BV(3) #define HTTP_LOCATION BV(4) #define HTTP_TRANSFER_ENCODING BV(5) +#define HTTP_CONTENT_LOCATION BV(6) +#define HTTP_SET_COOKIE BV(7) typedef struct { /** HEADER */ diff --git a/src/http-header-glue.c b/src/http-header-glue.c index 6a582067..b5238cd5 100644 --- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -1083,6 +1083,9 @@ static int http_response_process_headers(server *srv, connection *con, http_resp (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0; con->parsed_response |= HTTP_CONNECTION; } + else if (0 == strncasecmp(key, "Set-Cookie", key_len)) { + con->parsed_response |= HTTP_SET_COOKIE; + } break; case 14: if (0 == strncasecmp(key, "Content-Length", key_len)) { @@ -1090,6 +1093,11 @@ static int http_response_process_headers(server *srv, connection *con, http_resp con->parsed_response |= HTTP_CONTENT_LENGTH; } break; + case 16: + if (0 == strncasecmp(key, "Content-Location", key_len)) { + con->parsed_response |= HTTP_CONTENT_LOCATION; + } + break; case 17: if (0 == strncasecmp(key, "Transfer-Encoding", key_len)) { if (opts->backend == BACKEND_PROXY) continue; diff --git a/src/mod_proxy.c b/src/mod_proxy.c index f91c6941..ed85e300 100644 --- a/src/mod_proxy.c +++ b/src/mod_proxy.c @@ -39,6 +39,18 @@ * - HTTP/1.1 persistent connection with upstream servers */ +/* (future: might split struct and move part to http-header-glue.c) */ +typedef struct http_header_remap_opts { + const array *urlpaths; + const array *hosts_request; + const array *hosts_response; + int https_remap; + /*(not used in plugin_config, but used in handler_ctx)*/ + const buffer *http_host; + const buffer *forwarded_host; + const data_string *forwarded_urlpath; +} http_header_remap_opts; + typedef enum { PROXY_BALANCE_UNSET, PROXY_BALANCE_FAIR, @@ -59,11 +71,13 @@ typedef enum { typedef struct { array *extensions; array *forwarded_params; + array *header_params; unsigned short debug; unsigned short replace_http_host; unsigned int forwarded; proxy_balance_t balance; + http_header_remap_opts header; } plugin_config; typedef struct { @@ -103,6 +117,7 @@ typedef struct { int fde_ndx; /* index into the fd-event buffer */ http_response_opts opts; + http_header_remap_opts remap_hdrs; plugin_config conf; connection *remote_conn; /* dumb pointer */ @@ -167,6 +182,7 @@ FREE_FUNC(mod_proxy_free) { array_free(s->extensions); array_free(s->forwarded_params); + array_free(s->header_params); free(s); } @@ -189,6 +205,7 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) { { "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "proxy.replace-http-host", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ { "proxy.forwarded", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 4 */ + { "proxy.header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -204,12 +221,14 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) { s->replace_http_host = 0; s->forwarded_params = array_init(); s->forwarded = PROXY_FORWARDED_NONE; + s->header_params = array_init(); cv[0].destination = s->extensions; cv[1].destination = &(s->debug); cv[2].destination = p->balance_buf; cv[3].destination = &(s->replace_http_host); cv[4].destination = s->forwarded_params; + cv[5].destination = s->header_params; buffer_reset(p->balance_buf); @@ -277,6 +296,45 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) { } } + if (!array_is_kvany(s->header_params)) { + log_error_write(srv, __FILE__, __LINE__, "s", + "unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) )"); + return HANDLER_ERROR; + } + for (size_t j = 0, used = s->header_params->used; j < used; ++j) { + data_array *da = (data_array *)s->header_params->data[j]; + if (buffer_is_equal_string(da->key, CONST_STR_LEN("https-remap"))) { + data_string *ds = (data_string *)da; + if (ds->type != TYPE_STRING) { + log_error_write(srv, __FILE__, __LINE__, "s", + "unexpected value for proxy.header; expected \"enable\" or \"disable\" for https-remap"); + return HANDLER_ERROR; + } + s->header.https_remap = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable")) + && !buffer_is_equal_string(ds->value, CONST_STR_LEN("0")); + continue; + } + if (da->type != TYPE_ARRAY || !array_is_kvstring(da->value)) { + log_error_write(srv, __FILE__, __LINE__, "sb", + "unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) ) near key", da->key); + return HANDLER_ERROR; + } + if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-urlpath"))) { + s->header.urlpaths = da->value; + } + else if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-host-request"))) { + s->header.hosts_request = da->value; + } + else if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-host-response"))) { + s->header.hosts_response = da->value; + } + else { + log_error_write(srv, __FILE__, __LINE__, "sb", + "unexpected key for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) ) near key", da->key); + return HANDLER_ERROR; + } + } + if (NULL != (du = array_get_element(config->value, "proxy.server"))) { size_t j; data_array *da = (data_array *)du; @@ -670,6 +728,213 @@ static int proxy_establish_connection(server *srv, handler_ctx *hctx) { return 0; } + +/* (future: might move to http-header-glue.c) */ +static const buffer * http_header_remap_host_match (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req, size_t alen) +{ + const array *hosts = is_req + ? remap_hdrs->hosts_request + : remap_hdrs->hosts_response; + if (hosts) { + const char * const s = b->ptr+off; + for (size_t i = 0, used = hosts->used; i < used; ++i) { + const data_string * const ds = (data_string *)hosts->data[i]; + const buffer *k = ds->key; + size_t mlen = buffer_string_length(k); + if (1 == mlen && k->ptr[0] == '-') { + /* match with authority provided in Host (if is_req) + * (If no Host in client request, then matching against empty + * string will probably not match, and no remap will be + * performed) */ + k = is_req + ? remap_hdrs->http_host + : remap_hdrs->forwarded_host; + if (NULL == k) continue; + mlen = buffer_string_length(k); + } + if (mlen == alen && 0 == strncasecmp(s, k->ptr, alen)) { + if (buffer_is_equal_string(ds->value, CONST_STR_LEN("-"))) { + return remap_hdrs->http_host; + } + else if (!buffer_string_is_empty(ds->value)) { + /*(save first matched request host for response match)*/ + if (is_req && NULL == remap_hdrs->forwarded_host) + remap_hdrs->forwarded_host = ds->value; + return ds->value; + } /*(else leave authority as-is and stop matching)*/ + break; + } + } + } + return NULL; +} + + +/* (future: might move to http-header-glue.c) */ +static size_t http_header_remap_host (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req, size_t alen) +{ + const buffer * const m = + http_header_remap_host_match(b, off, remap_hdrs, is_req, alen); + if (NULL == m) return alen; /*(no match; return original authority length)*/ + + buffer_substr_replace(b, off, alen, m); + return buffer_string_length(m); /*(length of replacement authority)*/ +} + + +/* (future: might move to http-header-glue.c) */ +static void http_header_remap_urlpath (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req) +{ + const array *urlpaths = remap_hdrs->urlpaths; + if (urlpaths) { + const char * const s = b->ptr+off; + const size_t plen = buffer_string_length(b) - off; /*(urlpath len)*/ + if (is_req) { /* request */ + for (size_t i = 0, used = urlpaths->used; i < used; ++i) { + const data_string * const ds = (data_string *)urlpaths->data[i]; + const size_t mlen = buffer_string_length(ds->key); + if (mlen <= plen && 0 == memcmp(s, ds->key->ptr, mlen)) { + if (NULL == remap_hdrs->forwarded_urlpath) + remap_hdrs->forwarded_urlpath = ds; + buffer_substr_replace(b, off, mlen, ds->value); + break; + } + } + } + else { /* response; perform reverse map */ + if (NULL != remap_hdrs->forwarded_urlpath) { + const data_string * const ds = remap_hdrs->forwarded_urlpath; + const size_t mlen = buffer_string_length(ds->value); + if (mlen <= plen && 0 == memcmp(s, ds->value->ptr, mlen)) { + buffer_substr_replace(b, off, mlen, ds->key); + return; + } + } + for (size_t i = 0, used = urlpaths->used; i < used; ++i) { + const data_string * const ds = (data_string *)urlpaths->data[i]; + const size_t mlen = buffer_string_length(ds->value); + if (mlen <= plen && 0 == memcmp(s, ds->value->ptr, mlen)) { + buffer_substr_replace(b, off, mlen, ds->key); + break; + } + } + } + } +} + + +/* (future: might move to http-header-glue.c) */ +static void http_header_remap_uri (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req) +{ + /* find beginning of URL-path (might be preceded by scheme://authority + * (caller should make sure any leading whitespace is prior to offset) */ + if (b->ptr[off] != '/') { + char *s = b->ptr+off; + size_t alen; /*(authority len (host len))*/ + size_t slen; /*(scheme len)*/ + const buffer *m; + /* skip over scheme and authority of URI to find beginning of URL-path + * (value might conceivably be relative URL-path instead of URI) */ + if (NULL == (s = strchr(s, ':')) || s[1] != '/' || s[2] != '/') return; + slen = s - (b->ptr+off); + s += 3; + off = (size_t)(s - b->ptr); + if (NULL != (s = strchr(s, '/'))) { + alen = (size_t)(s - b->ptr) - off; + if (0 == alen) return; /*(empty authority, e.g. "http:///")*/ + } + else { + alen = buffer_string_length(b) - off; + if (0 == alen) return; /*(empty authority, e.g. "http:///")*/ + buffer_append_string_len(b, CONST_STR_LEN("/")); + } + + /* remap authority (if configured) and set offset to url-path */ + m = http_header_remap_host_match(b, off, remap_hdrs, is_req, alen); + if (NULL != m) { + if (remap_hdrs->https_remap + && (is_req ? 5==slen && 0==memcmp(b->ptr+off-slen-3,"https",5) + : 4==slen && 0==memcmp(b->ptr+off-slen-3,"http",4))){ + if (is_req) { + memcpy(b->ptr+off-slen-3+4,"://",3); /*("https"=>"http")*/ + --off; + ++alen; + } + else {/*(!is_req)*/ + memcpy(b->ptr+off-slen-3+4,"s://",4); /*("http" =>"https")*/ + ++off; + --alen; + } + } + buffer_substr_replace(b, off, alen, m); + alen = buffer_string_length(m);/*(length of replacement authority)*/ + } + off += alen; + } + + /* remap URLs (if configured) */ + http_header_remap_urlpath(b, off, remap_hdrs, is_req); +} + + +/* (future: might move to http-header-glue.c) */ +static void http_header_remap_setcookie (buffer *b, size_t off, http_header_remap_opts *remap_hdrs) +{ + /* Given the special-case of Set-Cookie and the (too) loosely restricted + * characters allowed, for best results, the Set-Cookie value should be the + * entire string in b from offset to end of string. In response headers, + * lighttpd may concatenate multiple Set-Cookie headers into single entry + * in con->response.headers, separated by "\r\nSet-Cookie: " */ + for (char *s, *n = b->ptr+off; (s = n); ) { + size_t len; + n = strchr(s, '\n'); + if (NULL == n) { + len = (size_t)(b->ptr + buffer_string_length(b) - s); + } + else { + len = (size_t)(n - s); + n += sizeof("Set-Cookie: "); /*(include +1 for '\n')*/ + } + for (char *e = s; NULL != (s = memchr(e, ';', len)); ) { + do { ++s; } while (*s == ' ' || *s == '\t'); + if ('\0' == s) return; + /*(interested only in Domain and Path attributes)*/ + e = memchr(s, '=', len - (size_t)(s - e)); + if (NULL == e) { e = s+1; continue; } + ++e; + switch ((int)(e - s - 1)) { + case 4: + if (0 == strncasecmp(s, "path", 4)) { + if (*e == '"') ++e; + if (*e != '/') continue; + off = (size_t)(e - b->ptr); + http_header_remap_urlpath(b, off, remap_hdrs, 0); + e = b->ptr+off; /*(b may have been reallocated)*/ + continue; + } + break; + case 6: + if (0 == strncasecmp(s, "domain", 6)) { + size_t alen = 0; + if (*e == '"') ++e; + if (*e == '.') ++e; + if (*e == ';') continue; + off = (size_t)(e - b->ptr); + for (char c; (c = e[alen]) != ';' && c != ' ' && c != '\t' + && c != '\r' && c != '\0'; ++alen); + len = http_header_remap_host(b, off, remap_hdrs, 0, alen); + e = b->ptr+off+len; /*(b may have been reallocated)*/ + continue; + } + break; + default: + break; + } + } + } +} + + static void proxy_append_header(connection *con, const char *key, const size_t klen, const char *value, const size_t vlen) { data_string *ds_dst; @@ -904,24 +1169,23 @@ static void proxy_set_Forwarded(connection *con, const unsigned int flags) { static int proxy_create_env(server *srv, handler_ctx *hctx) { - size_t i; - connection *con = hctx->remote_conn; - buffer *b; - int replace_http_host = 0; + buffer *b = buffer_init(); + const int remap_headers = (NULL != hctx->remap_hdrs.urlpaths + || NULL != hctx->remap_hdrs.hosts_request); + buffer_string_prepare_copy(b, 8192-1); /* build header */ - b = buffer_init(); - /* request line */ buffer_copy_string(b, get_http_method_name(con->request.http_method)); buffer_append_string_len(b, CONST_STR_LEN(" ")); - buffer_append_string_buffer(b, con->request.uri); + if (remap_headers) + http_header_remap_uri(b, buffer_string_length(b) - buffer_string_length(con->request.uri), &hctx->remap_hdrs, 1); buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n")); + if (hctx->conf.replace_http_host && !buffer_string_is_empty(hctx->host->key)) { - replace_http_host = 1; if (hctx->conf.debug > 1) { log_error_write(srv, __FILE__, __LINE__, "SBS", "proxy - using \"", hctx->host->key, "\" as HTTP Host"); @@ -929,6 +1193,14 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { buffer_append_string_len(b, CONST_STR_LEN("Host: ")); buffer_append_string_buffer(b, hctx->host->key); buffer_append_string_len(b, CONST_STR_LEN("\r\n")); + } else if (!buffer_string_is_empty(con->request.http_host)) { + buffer_append_string_len(b, CONST_STR_LEN("Host: ")); + buffer_append_string_buffer(b, con->request.http_host); + if (remap_headers) { + size_t alen = buffer_string_length(con->request.http_host); + http_header_remap_host(b, buffer_string_length(b) - alen, &hctx->remap_hdrs, 1, alen); + } + buffer_append_string_len(b, CONST_STR_LEN("\r\n")); } /* "Forwarded" and legacy X- headers */ @@ -952,26 +1224,67 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { } /* request header */ - for (i = 0; i < con->request.headers->used; i++) { - data_string *ds; - - ds = (data_string *)con->request.headers->data[i]; - - if (!buffer_string_is_empty(ds->value) && !buffer_is_empty(ds->key)) { - if (replace_http_host && - buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Host"))) continue; + for (size_t i = 0, used = con->request.headers->used; i < used; ++i) { + data_string *ds = (data_string *)con->request.headers->data[i]; + const size_t klen = buffer_string_length(ds->key); + size_t vlen; + switch (klen) { + default: + break; + case 4: + if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Host"))) continue; /*(handled further above)*/ + break; + case 10: if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Connection"))) continue; + if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Set-Cookie"))) continue; /*(response header only; avoid accidental reflection)*/ + break; + case 16: if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue; + break; + case 5: /* Do not emit HTTP_PROXY in environment. * Some executables use HTTP_PROXY to configure * outgoing proxy. See also https://httpoxy.org/ */ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) continue; + break; + case 0: + continue; + } + + vlen = buffer_string_length(ds->value); + if (0 == vlen) continue; - buffer_append_string_buffer(b, ds->key); - buffer_append_string_len(b, CONST_STR_LEN(": ")); - buffer_append_string_buffer(b, ds->value); - buffer_append_string_len(b, CONST_STR_LEN("\r\n")); + buffer_append_string_len(b, ds->key->ptr, klen); + buffer_append_string_len(b, CONST_STR_LEN(": ")); + buffer_append_string_len(b, ds->value->ptr, vlen); + buffer_append_string_len(b, CONST_STR_LEN("\r\n")); + + if (!remap_headers) continue; + + /* check for hdrs for which to remap URIs in-place after append to b */ + + switch (klen) { + default: + continue; + #if 0 /* "URI" is HTTP response header (non-standard; historical in Apache) */ + case 3: + if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("URI"))) break; + continue; + #endif + #if 0 /* "Location" is HTTP response header */ + case 8: + if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Location"))) break; + continue; + #endif + case 11: /* "Destination" is WebDAV request header */ + if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Destination"))) break; + continue; + case 16: /* "Content-Location" may be HTTP request or response header */ + if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Content-Location"))) break; + continue; } + + http_header_remap_uri(b, buffer_string_length(b) - vlen - 2, &hctx->remap_hdrs, 1); } buffer_append_string_len(b, CONST_STR_LEN("Connection: close\r\n\r\n")); @@ -1150,6 +1463,7 @@ static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data PATCH(balance); PATCH(replace_http_host); PATCH(forwarded); + PATCH(header); /*(copies struct)*/ /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -1173,6 +1487,8 @@ static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data PATCH(replace_http_host); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.forwarded"))) { PATCH(forwarded); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.header"))) { + PATCH(header); /*(copies struct)*/ } } } @@ -1266,9 +1582,44 @@ SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { } +static handler_t proxy_response_read(server *srv, handler_ctx *hctx) { + connection * const con = hctx->remote_conn; + const int file_started = con->file_started; + const handler_t rc = + http_response_read(srv, con, &hctx->opts, + hctx->response, hctx->fd, &hctx->fde_ndx); + + if (file_started || !con->file_started || con->mode == DIRECT) return rc; + + /* response headers just completed */ + + /* rewrite paths, if needed */ + + if (NULL == hctx->remap_hdrs.urlpaths + && NULL == hctx->remap_hdrs.hosts_response) + return rc; + + if (con->parsed_response & HTTP_LOCATION) { + data_string *ds = (data_string *) + array_get_element(con->response.headers, "Location"); + if (ds) http_header_remap_uri(ds->value, 0, &hctx->remap_hdrs, 0); + } + if (con->parsed_response & HTTP_CONTENT_LOCATION) { + data_string *ds = (data_string *) + array_get_element(con->response.headers, "Content-Location"); + if (ds) http_header_remap_uri(ds->value, 0, &hctx->remap_hdrs, 0); + } + if (con->parsed_response & HTTP_SET_COOKIE) { + data_string *ds = (data_string *) + array_get_element(con->response.headers, "Set-Cookie"); + if (ds) http_header_remap_setcookie(ds->value, 0, &hctx->remap_hdrs); + } + + return rc; +} + static handler_t proxy_recv_response(server *srv, handler_ctx *hctx) { - switch (http_response_read(srv, hctx->remote_conn, &hctx->opts, - hctx->response, hctx->fd, &hctx->fde_ndx)) { + switch (proxy_response_read(srv, hctx)) { default: return HANDLER_GO_ON; case HANDLER_ERROR: @@ -1409,6 +1760,17 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p hctx->opts.xsendfile_allow = 0; hctx->opts.xsendfile_docroot = NULL; + hctx->remap_hdrs = p->conf.header; /*(copies struct)*/ + hctx->remap_hdrs.http_host = con->request.http_host; + /* mod_proxy currently sends all backend requests as http. + * https-remap is a flag since it might not be needed if backend + * honors Forwarded or X-Forwarded-Proto headers, e.g. by using + * lighttpd mod_extforward or similar functionality in backend*/ + if (hctx->remap_hdrs.https_remap) { + hctx->remap_hdrs.https_remap = + buffer_is_equal_string(con->uri.scheme, CONST_STR_LEN("https")); + } + con->plugin_ctx[p->id] = hctx; con->mode = p->id;