lighttpd1.4/src/mod_proxy.c

1146 lines
43 KiB
C
Raw Normal View History

#include "first.h"
[core] shared code for socket backends common codebase for socket backends, based off mod_fastcgi with some features added for mod_proxy (mostly intended to reduce code duplication and enhance code isolation) mod_fastcgi and mod_scgi can now use fastcgi.balance and scgi.balance for similar behavior as proxy.balance, but the balancing is per-host and not per-proc. proxy.balance is also per-host and not per-proc. mod_proxy and mod_scgi can now use proxy.map-extensions and scgi.map-extensions, similar to fastcgi.map-extensions. mod_fastcgi behavior change (affects only mod_status): - statistics tags have been renamed from "fastcgi.*" to "gw.*" "fastcgi.backend.*" -> "gw.backend.*" "fastcgi.active-requests" -> "gw.active-requests" ("fastcgi.requests" remains "fastcgi.requests") ("proxy.requests" is new) ("scgi.requests" is new) mod_scgi behavior change (likely minor): - removed scgi_proclist_sort_down() and scgi_proclist_sort_up(). procs now chosen based on load as measured by num socket connnections Note: modules using gw_backend.[ch] are currently still independent modules. If it had been written as a single module with fastcgi, scgi, proxy implementations, then there would have been a chance of breaking some existing user configurations where module ordering made a difference for which module handled a given request, though for most people, this would have made no difference. Details about mod_fastcgi code transformations: unsigned int debug -> int debug fastcgi_env member removed from plugin_config renamed "fcgi" and "fastcgi" to "gw", and "FCGI" to "GW" reorganize routines for high-level and lower-level interfaces some lower-level internal interfaces changed to use host,proc,debug args rather than knowing about higher-level (app) hctx and plugin_data tabs->spaces and reformatting
2017-07-14 05:29:18 +00:00
#include <string.h>
#include <stdlib.h>
#include "gw_backend.h"
#include "base.h"
#include "array.h"
#include "buffer.h"
#include "fdevent.h"
#include "http_kv.h"
#include "http_header.h"
#include "log.h"
2017-10-29 05:23:19 +00:00
#include "sock_addr.h"
[core] shared code for socket backends common codebase for socket backends, based off mod_fastcgi with some features added for mod_proxy (mostly intended to reduce code duplication and enhance code isolation) mod_fastcgi and mod_scgi can now use fastcgi.balance and scgi.balance for similar behavior as proxy.balance, but the balancing is per-host and not per-proc. proxy.balance is also per-host and not per-proc. mod_proxy and mod_scgi can now use proxy.map-extensions and scgi.map-extensions, similar to fastcgi.map-extensions. mod_fastcgi behavior change (affects only mod_status): - statistics tags have been renamed from "fastcgi.*" to "gw.*" "fastcgi.backend.*" -> "gw.backend.*" "fastcgi.active-requests" -> "gw.active-requests" ("fastcgi.requests" remains "fastcgi.requests") ("proxy.requests" is new) ("scgi.requests" is new) mod_scgi behavior change (likely minor): - removed scgi_proclist_sort_down() and scgi_proclist_sort_up(). procs now chosen based on load as measured by num socket connnections Note: modules using gw_backend.[ch] are currently still independent modules. If it had been written as a single module with fastcgi, scgi, proxy implementations, then there would have been a chance of breaking some existing user configurations where module ordering made a difference for which module handled a given request, though for most people, this would have made no difference. Details about mod_fastcgi code transformations: unsigned int debug -> int debug fastcgi_env member removed from plugin_config renamed "fcgi" and "fastcgi" to "gw", and "FCGI" to "GW" reorganize routines for high-level and lower-level interfaces some lower-level internal interfaces changed to use host,proc,debug args rather than knowing about higher-level (app) hctx and plugin_data tabs->spaces and reformatting
2017-07-14 05:29:18 +00:00
#include "status_counter.h"
/**
*
* HTTP reverse proxy
*
* TODO: - HTTP/1.1
* - HTTP/1.1 persistent connection with upstream servers
*/
[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
2017-04-28 22:53:08 +00:00
/* (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 force_http10;
[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
2017-04-28 22:53:08 +00:00
int https_remap;
int upgrade;
int connect_method;
[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
2017-04-28 22:53:08 +00:00
/*(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_FORWARDED_NONE = 0x00,
PROXY_FORWARDED_FOR = 0x01,
PROXY_FORWARDED_PROTO = 0x02,
PROXY_FORWARDED_HOST = 0x04,
PROXY_FORWARDED_BY = 0x08,
PROXY_FORWARDED_REMOTE_USER = 0x10
} proxy_forwarded_t;
typedef struct {
gw_plugin_config gw; /* start must match layout of gw_plugin_config */
unsigned int replace_http_host;
unsigned int forwarded;
http_header_remap_opts header;
} plugin_config;
typedef struct {
PLUGIN_DATA;
pid_t srv_pid; /* must match layout of gw_plugin_data through conf member */
plugin_config conf;
plugin_config defaults;
} plugin_data;
static int proxy_check_extforward;
typedef struct {
[core] shared code for socket backends common codebase for socket backends, based off mod_fastcgi with some features added for mod_proxy (mostly intended to reduce code duplication and enhance code isolation) mod_fastcgi and mod_scgi can now use fastcgi.balance and scgi.balance for similar behavior as proxy.balance, but the balancing is per-host and not per-proc. proxy.balance is also per-host and not per-proc. mod_proxy and mod_scgi can now use proxy.map-extensions and scgi.map-extensions, similar to fastcgi.map-extensions. mod_fastcgi behavior change (affects only mod_status): - statistics tags have been renamed from "fastcgi.*" to "gw.*" "fastcgi.backend.*" -> "gw.backend.*" "fastcgi.active-requests" -> "gw.active-requests" ("fastcgi.requests" remains "fastcgi.requests") ("proxy.requests" is new) ("scgi.requests" is new) mod_scgi behavior change (likely minor): - removed scgi_proclist_sort_down() and scgi_proclist_sort_up(). procs now chosen based on load as measured by num socket connnections Note: modules using gw_backend.[ch] are currently still independent modules. If it had been written as a single module with fastcgi, scgi, proxy implementations, then there would have been a chance of breaking some existing user configurations where module ordering made a difference for which module handled a given request, though for most people, this would have made no difference. Details about mod_fastcgi code transformations: unsigned int debug -> int debug fastcgi_env member removed from plugin_config renamed "fcgi" and "fastcgi" to "gw", and "FCGI" to "GW" reorganize routines for high-level and lower-level interfaces some lower-level internal interfaces changed to use host,proc,debug args rather than knowing about higher-level (app) hctx and plugin_data tabs->spaces and reformatting
2017-07-14 05:29:18 +00:00
gw_handler_ctx gw;
plugin_config conf;
} handler_ctx;
INIT_FUNC(mod_proxy_init) {
return calloc(1, sizeof(plugin_data));
}
static void mod_proxy_free_config(plugin_data * const p)
{
if (NULL == p->cvlist) return;
/* (init i to 0 if global context; to 1 to skip empty global context) */
for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
for (; -1 != cpv->k_id; ++cpv) {
switch (cpv->k_id) {
case 5: /* proxy.header */
if (cpv->vtype == T_CONFIG_LOCAL) free(cpv->v.v);
break;
default:
break;
}
}
}
}
FREE_FUNC(mod_proxy_free) {
plugin_data * const p = p_d;
mod_proxy_free_config(p);
gw_free(p);
}
static void mod_proxy_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv)
{
switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
case 0: /* proxy.server */
if (cpv->vtype == T_CONFIG_LOCAL) {
gw_plugin_config * const gw = cpv->v.v;
pconf->gw.exts = gw->exts;
pconf->gw.exts_auth = gw->exts_auth;
pconf->gw.exts_resp = gw->exts_resp;
}
break;
case 1: /* proxy.balance */
/*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
pconf->gw.balance = (int)cpv->v.u;
break;
case 2: /* proxy.debug */
pconf->gw.debug = (int)cpv->v.u;
break;
case 3: /* proxy.map-extensions */
pconf->gw.ext_mapping = cpv->v.a;
break;
case 4: /* proxy.forwarded */
/*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
pconf->forwarded = cpv->v.u;
break;
case 5: /* proxy.header */
/*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
pconf->header = *(http_header_remap_opts *)cpv->v.v; /*(copies struct)*/
break;
case 6: /* proxy.replace-http-host */
pconf->replace_http_host = cpv->v.u;
break;
default:/* should not happen */
return;
}
}
static void mod_proxy_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv)
{
do {
mod_proxy_merge_config_cpv(pconf, cpv);
} while ((++cpv)->k_id != -1);
}
static void mod_proxy_patch_config(request_st * const r, plugin_data * const p)
{
memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
for (int i = 1, used = p->nconfig; i < used; ++i) {
if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
mod_proxy_merge_config(&p->conf, p->cvlist+p->cvlist[i].v.u2[0]);
}
}
static unsigned int mod_proxy_parse_forwarded(server *srv, const array *a)
{
unsigned int forwarded = 0;
for (uint32_t j = 0, used = a->used; j < used; ++j) {
proxy_forwarded_t param;
data_unset *du = a->data[j];
if (buffer_eq_slen(&du->key, CONST_STR_LEN("by")))
param = PROXY_FORWARDED_BY;
else if (buffer_eq_slen(&du->key, CONST_STR_LEN("for")))
param = PROXY_FORWARDED_FOR;
else if (buffer_eq_slen(&du->key, CONST_STR_LEN("host")))
param = PROXY_FORWARDED_HOST;
else if (buffer_eq_slen(&du->key, CONST_STR_LEN("proto")))
param = PROXY_FORWARDED_PROTO;
else if (buffer_eq_slen(&du->key, CONST_STR_LEN("remote_user")))
param = PROXY_FORWARDED_REMOTE_USER;
else {
log_error(srv->errh, __FILE__, __LINE__,
"proxy.forwarded keys must be one of: "
"by, for, host, proto, remote_user, but not: %s", du->key.ptr);
return UINT_MAX;
}
int val = config_plugin_value_tobool(du, 2);
if (2 == val) {
log_error(srv->errh, __FILE__, __LINE__,
"proxy.forwarded values must be one of: "
"0, 1, enable, disable; error for key: %s", du->key.ptr);
return UINT_MAX;
}
if (val)
forwarded |= param;
}
return forwarded;
}
[core] shared code for socket backends common codebase for socket backends, based off mod_fastcgi with some features added for mod_proxy (mostly intended to reduce code duplication and enhance code isolation) mod_fastcgi and mod_scgi can now use fastcgi.balance and scgi.balance for similar behavior as proxy.balance, but the balancing is per-host and not per-proc. proxy.balance is also per-host and not per-proc. mod_proxy and mod_scgi can now use proxy.map-extensions and scgi.map-extensions, similar to fastcgi.map-extensions. mod_fastcgi behavior change (affects only mod_status): - statistics tags have been renamed from "fastcgi.*" to "gw.*" "fastcgi.backend.*" -> "gw.backend.*" "fastcgi.active-requests" -> "gw.active-requests" ("fastcgi.requests" remains "fastcgi.requests") ("proxy.requests" is new) ("scgi.requests" is new) mod_scgi behavior change (likely minor): - removed scgi_proclist_sort_down() and scgi_proclist_sort_up(). procs now chosen based on load as measured by num socket connnections Note: modules using gw_backend.[ch] are currently still independent modules. If it had been written as a single module with fastcgi, scgi, proxy implementations, then there would have been a chance of breaking some existing user configurations where module ordering made a difference for which module handled a given request, though for most people, this would have made no difference. Details about mod_fastcgi code transformations: unsigned int debug -> int debug fastcgi_env member removed from plugin_config renamed "fcgi" and "fastcgi" to "gw", and "FCGI" to "GW" reorganize routines for high-level and lower-level interfaces some lower-level internal interfaces changed to use host,proc,debug args rather than knowing about higher-level (app) hctx and plugin_data tabs->spaces and reformatting
2017-07-14 05:29:18 +00:00
static http_header_remap_opts * mod_proxy_parse_header_opts(server *srv, const array *a)
{
http_header_remap_opts header;
memset(&header, 0, sizeof(header));
for (uint32_t j = 0, used = a->used; j < used; ++j) {
data_array *da = (data_array *)a->data[j];
if (buffer_eq_slen(&da->key, CONST_STR_LEN("https-remap"))) {
int val = config_plugin_value_tobool((data_unset *)da, 2);
if (2 == val) {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected value for proxy.header; "
"expected \"https-remap\" => \"enable\" or \"disable\"");
return NULL;
}
header.https_remap = val;
continue;
}
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("force-http10"))) {
int val = config_plugin_value_tobool((data_unset *)da, 2);
if (2 == val) {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected value for proxy.header; "
"expected \"force-http10\" => \"enable\" or \"disable\"");
return NULL;
}
header.force_http10 = val;
continue;
}
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("upgrade"))) {
int val = config_plugin_value_tobool((data_unset *)da, 2);
if (2 == val) {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected value for proxy.header; "
"expected \"upgrade\" => \"enable\" or \"disable\"");
return NULL;
}
header.upgrade = val;
continue;
}
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("connect"))) {
int val = config_plugin_value_tobool((data_unset *)da, 2);
if (2 == val) {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected value for proxy.header; "
"expected \"connect\" => \"enable\" or \"disable\"");
return NULL;
}
header.connect_method = val;
continue;
}
if (da->type != TYPE_ARRAY || !array_is_kvstring(&da->value)) {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected value for proxy.header; "
"expected ( \"param\" => ( \"key\" => \"value\" ) ) near key %s",
da->key.ptr);
return NULL;
}
if (buffer_eq_slen(&da->key, CONST_STR_LEN("map-urlpath"))) {
header.urlpaths = &da->value;
}
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("map-host-request"))) {
header.hosts_request = &da->value;
}
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("map-host-response"))) {
header.hosts_response = &da->value;
}
else {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected key for proxy.header; "
"expected ( \"param\" => ( \"key\" => \"value\" ) ) near key %s",
da->key.ptr);
return NULL;
}
}
[core] shared code for socket backends common codebase for socket backends, based off mod_fastcgi with some features added for mod_proxy (mostly intended to reduce code duplication and enhance code isolation) mod_fastcgi and mod_scgi can now use fastcgi.balance and scgi.balance for similar behavior as proxy.balance, but the balancing is per-host and not per-proc. proxy.balance is also per-host and not per-proc. mod_proxy and mod_scgi can now use proxy.map-extensions and scgi.map-extensions, similar to fastcgi.map-extensions. mod_fastcgi behavior change (affects only mod_status): - statistics tags have been renamed from "fastcgi.*" to "gw.*" "fastcgi.backend.*" -> "gw.backend.*" "fastcgi.active-requests" -> "gw.active-requests" ("fastcgi.requests" remains "fastcgi.requests") ("proxy.requests" is new) ("scgi.requests" is new) mod_scgi behavior change (likely minor): - removed scgi_proclist_sort_down() and scgi_proclist_sort_up(). procs now chosen based on load as measured by num socket connnections Note: modules using gw_backend.[ch] are currently still independent modules. If it had been written as a single module with fastcgi, scgi, proxy implementations, then there would have been a chance of breaking some existing user configurations where module ordering made a difference for which module handled a given request, though for most people, this would have made no difference. Details about mod_fastcgi code transformations: unsigned int debug -> int debug fastcgi_env member removed from plugin_config renamed "fcgi" and "fastcgi" to "gw", and "FCGI" to "GW" reorganize routines for high-level and lower-level interfaces some lower-level internal interfaces changed to use host,proc,debug args rather than knowing about higher-level (app) hctx and plugin_data tabs->spaces and reformatting
2017-07-14 05:29:18 +00:00
http_header_remap_opts *opts = malloc(sizeof(header));
force_assert(opts);
memcpy(opts, &header, sizeof(header));
return opts;
}
SETDEFAULTS_FUNC(mod_proxy_set_defaults)
{
static const config_plugin_keys_t cpk[] = {
{ CONST_STR_LEN("proxy.server"),
T_CONFIG_ARRAY_KVARRAY,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("proxy.balance"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("proxy.debug"),
T_CONFIG_INT,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("proxy.map-extensions"),
T_CONFIG_ARRAY_KVSTRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("proxy.forwarded"),
T_CONFIG_ARRAY_KVANY,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("proxy.header"),
T_CONFIG_ARRAY_KVANY,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("proxy.replace-http-host"),
T_CONFIG_BOOL,
T_CONFIG_SCOPE_CONNECTION }
,{ NULL, 0,
T_CONFIG_UNSET,
T_CONFIG_SCOPE_UNSET }
};
plugin_data * const p = p_d;
if (!config_plugin_values_init(srv, p, cpk, "mod_proxy"))
return HANDLER_ERROR;
/* process and validate config directives
* (init i to 0 if global context; to 1 to skip empty global context) */
for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
gw_plugin_config *gw = NULL;
for (; -1 != cpv->k_id; ++cpv) {
switch (cpv->k_id) {
case 0: /* proxy.server */
gw = calloc(1, sizeof(gw_plugin_config));
force_assert(gw);
if (!gw_set_defaults_backend(srv, (gw_plugin_data *)p, cpv->v.a,
gw, 0, cpk[cpv->k_id].k)) {
gw_plugin_config_free(gw);
return HANDLER_ERROR;
}
/* error if "mode" = "authorizer";
* proxy can not act as authorizer */
/*(check after gw_set_defaults_backend())*/
if (gw->exts_auth && gw->exts_auth->used) {
log_error(srv->errh, __FILE__, __LINE__,
"%s must not define any hosts with "
"attribute \"mode\" = \"authorizer\"", cpk[cpv->k_id].k);
gw_plugin_config_free(gw);
return HANDLER_ERROR;
}
cpv->v.v = gw;
cpv->vtype = T_CONFIG_LOCAL;
break;
case 1: /* proxy.balance */
cpv->v.u = (unsigned int)gw_get_defaults_balance(srv, cpv->v.b);
break;
case 2: /* proxy.debug */
case 3: /* proxy.map-extensions */
break;
case 4: /* proxy.forwarded */
cpv->v.u = mod_proxy_parse_forwarded(srv, cpv->v.a);
if (UINT_MAX == cpv->v.u) return HANDLER_ERROR;
cpv->vtype = T_CONFIG_LOCAL;
break;
case 5: /* proxy.header */
cpv->v.v = mod_proxy_parse_header_opts(srv, cpv->v.a);
if (NULL == cpv->v.v) return HANDLER_ERROR;
cpv->vtype = T_CONFIG_LOCAL;
break;
case 6: /* proxy.replace-http-host */
break;
default:/* should not happen */
break;
}
}
/* disable check-local for all exts (default enabled) */
if (gw && gw->exts) { /*(check after gw_set_defaults_backend())*/
2019-11-23 04:13:12 +00:00
gw_exts_clear_check_local(gw->exts);
}
}
/* default is 0 */
/*p->defaults.balance = (unsigned int)gw_get_defaults_balance(srv, NULL);*/
p->defaults.header.force_http10 =
config_feature_bool(srv, "proxy.force-http10", 0);
/* initialize p->defaults from global config context */
if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
if (-1 != cpv->k_id)
mod_proxy_merge_config(&p->defaults, cpv);
}
/* special-case behavior if mod_extforward is loaded */
for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) {
buffer *m = &((data_string *)srv->srvconf.modules->data[i])->value;
if (buffer_eq_slen(m, CONST_STR_LEN("mod_extforward"))) {
proxy_check_extforward = 1;
break;
}
}
return HANDLER_GO_ON;
}
[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
2017-04-28 22:53:08 +00:00
/* (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;
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
size_t mlen = buffer_clen(k);
[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
2017-04-28 22:53:08 +00:00
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;
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
mlen = buffer_clen(k);
[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
2017-04-28 22:53:08 +00:00
}
if (buffer_eq_icase_ss(s, alen, k->ptr, mlen)) {
if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("-"))) {
[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
2017-04-28 22:53:08 +00:00
return remap_hdrs->http_host;
}
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
else if (!buffer_is_blank(&ds->value)) {
[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
2017-04-28 22:53:08 +00:00
/*(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;
[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
2017-04-28 22:53:08 +00:00
} /*(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);
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
return buffer_clen(m); /*(length of replacement authority)*/
[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
2017-04-28 22:53:08 +00:00
}
/* (future: might move to http-header-glue.c) */
static size_t http_header_remap_urlpath (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req)
[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
2017-04-28 22:53:08 +00:00
{
const array *urlpaths = remap_hdrs->urlpaths;
if (urlpaths) {
const char * const s = b->ptr+off;
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
const size_t plen = buffer_clen(b) - off; /*(urlpath len)*/
[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
2017-04-28 22:53:08 +00:00
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];
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
const size_t mlen = buffer_clen(&ds->key);
if (mlen <= plen && 0 == memcmp(s, ds->key.ptr, mlen)) {
[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
2017-04-28 22:53:08 +00:00
if (NULL == remap_hdrs->forwarded_urlpath)
remap_hdrs->forwarded_urlpath = ds;
buffer_substr_replace(b, off, mlen, &ds->value);
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
return buffer_clen(&ds->value);/*(replacement len)*/
[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
2017-04-28 22:53:08 +00:00
}
}
}
else { /* response; perform reverse map */
if (NULL != remap_hdrs->forwarded_urlpath) {
const data_string * const ds = remap_hdrs->forwarded_urlpath;
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
const size_t mlen = buffer_clen(&ds->value);
if (mlen <= plen && 0 == memcmp(s, ds->value.ptr, mlen)) {
buffer_substr_replace(b, off, mlen, &ds->key);
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
return buffer_clen(&ds->key); /*(replacement len)*/
[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
2017-04-28 22:53:08 +00:00
}
}
for (size_t i = 0, used = urlpaths->used; i < used; ++i) {
const data_string * const ds = (data_string *)urlpaths->data[i];
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
const size_t mlen = buffer_clen(&ds->value);
if (mlen <= plen && 0 == memcmp(s, ds->value.ptr, mlen)) {
buffer_substr_replace(b, off, mlen, &ds->key);
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
return buffer_clen(&ds->key); /*(replacement len)*/
[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
2017-04-28 22:53:08 +00:00
}
}
}
}
return 0;
[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
2017-04-28 22:53:08 +00:00
}
/* (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 {
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
alen = buffer_clen(b) - off;
[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
2017-04-28 22:53:08 +00:00
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);
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00
alen = buffer_clen(m);/*(length of replacement authority)*/
[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
2017-04-28 22:53:08 +00:00
}
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 r->resp_headers, separated by "\r\nSet-Cookie: " */
for (char *s = b->ptr+off, *e; *s; s = e) {
[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
2017-04-28 22:53:08 +00:00
size_t len;
{
while (*s != ';' && *s != '\n' && *s != '\0') ++s;
if (*s == '\n') {
/*(include +1 for '\n', but leave ' ' for ++s below)*/
s += sizeof("Set-Cookie:");
}
if ('\0' == *s) return;
[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
2017-04-28 22:53:08 +00:00
do { ++s; } while (*s == ' ' || *s == '\t');
if ('\0' == *s) return;
e = s+1;
if ('=' == *s) continue;
[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
2017-04-28 22:53:08 +00:00
/*(interested only in Domain and Path attributes)*/
while (*e != '=' && *e != '\0') ++e;
if ('\0' == *e) return;
[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
2017-04-28 22:53:08 +00:00
++e;
switch ((int)(e - s - 1)) {
case 4:
if (buffer_eq_icase_ssn(s, "path", 4)) {
[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
2017-04-28 22:53:08 +00:00
if (*e == '"') ++e;
if (*e != '/') continue;
off = (size_t)(e - b->ptr);
len = http_header_remap_urlpath(b, off, remap_hdrs, 0);
e = b->ptr+off+len; /*(b may have been reallocated)*/
[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
2017-04-28 22:53:08 +00:00
continue;
}
break;
case 6:
if (buffer_eq_icase_ssn(s, "domain", 6)) {
[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
2017-04-28 22:53:08 +00:00
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 buffer_append_string_backslash_escaped(buffer *b, const char *s, size_t len) {
/* (future: might move to buffer.c) */
size_t j = 0;
[multiple] reduce redundant NULL buffer checks This commit is a large set of code changes and results in removal of hundreds, perhaps thousands, of CPU instructions, a portion of which are on hot code paths. Most (buffer *) used by lighttpd are not NULL, especially since buffers were inlined into numerous larger structs such as request_st and chunk. In the small number of instances where that is not the case, a NULL check is often performed earlier in a function where that buffer is later used with a buffer_* func. In the handful of cases that remained, a NULL check was added, e.g. with r->http_host and r->conf.server_tag. - check for empty strings at config time and set value to NULL if blank string will be ignored at runtime; at runtime, simple pointer check for NULL can be used to check for a value that has been set and is not blank ("") - use buffer_is_blank() instead of buffer_string_is_empty(), and use buffer_is_unset() instead of buffer_is_empty(), where buffer is known not to be NULL so that NULL check can be skipped - use buffer_clen() instead of buffer_string_length() when buffer is known not to be NULL (to avoid NULL check at runtime) - use buffer_truncate() instead of buffer_string_set_length() to truncate string, and use buffer_extend() to extend Examples where buffer known not to be NULL: - cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL (though we might set it to NULL if buffer_is_blank(cpv->v.b)) - address of buffer is arg (&foo) (compiler optimizer detects this in most, but not all, cases) - buffer is checked for NULL earlier in func - buffer is accessed in same scope without a NULL check (e.g. b->ptr) internal behavior change: callers must not pass a NULL buffer to some funcs. - buffer_init_buffer() requires non-null args - buffer_copy_buffer() requires non-null args - buffer_append_string_buffer() requires non-null args - buffer_string_space() requires non-null arg
2021-06-09 02:57:36 +00:00