lighttpd1.4/src/mod_proxy.c

1010 lines
38 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 "keyvalue.h"
#include "log.h"
#include "plugin.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 https_remap;
int upgrade;
[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 {
[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_plugin_config gw;
array *forwarded_params;
[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
array *header_params;
unsigned short replace_http_host;
unsigned int forwarded;
[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
http_header_remap_opts header;
} plugin_config;
typedef struct {
PLUGIN_DATA;
plugin_config **config_storage;
plugin_config conf;
} 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;
http_response_opts opts;
[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
http_header_remap_opts remap_hdrs;
plugin_config conf;
} handler_ctx;
INIT_FUNC(mod_proxy_init) {
plugin_data *p;
p = calloc(1, sizeof(*p));
return p;
}
FREE_FUNC(mod_proxy_free) {
plugin_data *p = p_d;
UNUSED(srv);
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (NULL == s) continue;
array_free(s->forwarded_params);
[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
array_free(s->header_params);
[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
/*assert(0 == offsetof(s->gw));*/
gw_plugin_config_free(&s->gw);
/*free(s);*//*free'd by gw_plugin_config_free()*/
}
free(p->config_storage);
}
free(p);
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
plugin_data *p = p_d;
data_unset *du;
size_t i = 0;
config_values_t cv[] = {
{ "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
[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
{ "proxy.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "proxy.replace-http-host", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ "proxy.forwarded", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
[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
{ "proxy.header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
[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
{ "proxy.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
for (i = 0; i < srv->config_context->used; i++) {
data_config const* config = (data_config const*)srv->config_context->data[i];
plugin_config *s;
s = calloc(1, sizeof(plugin_config));
[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
s->gw.debug = 0;
s->replace_http_host = 0;
s->forwarded_params = array_init();
s->forwarded = PROXY_FORWARDED_NONE;
[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
s->header_params = array_init();
[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
s->gw.ext_mapping = array_init();
[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
cv[0].destination = NULL; /* T_CONFIG_LOCAL */
cv[1].destination = &(s->gw.debug);
cv[2].destination = NULL; /* T_CONFIG_LOCAL */
cv[3].destination = &(s->replace_http_host);
cv[4].destination = s->forwarded_params;
[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
cv[5].destination = s->header_params;
[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
cv[6].destination = s->gw.ext_mapping;
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
return HANDLER_ERROR;
}
[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
du = array_get_element(config->value, "proxy.server");
if (!gw_set_defaults_backend(srv, (gw_plugin_data *)p, du, i, 0)) {
return HANDLER_ERROR;
}
[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
du = array_get_element(config->value, "proxy.balance");
if (!gw_set_defaults_balance(srv, &s->gw, du)) {
return HANDLER_ERROR;
}
/* disable check-local for all exts (default enabled) */
if (s->gw.exts) { /*(check after gw_set_defaults_backend())*/
for (size_t j = 0; j < s->gw.exts->used; ++j) {
gw_extension *ex = s->gw.exts->exts[j];
for (size_t n = 0; n < ex->used; ++n) {
ex->hosts[n]->check_local = 0;
}
}
}
if (!array_is_kvany(s->forwarded_params)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"unexpected value for proxy.forwarded; expected ( \"param\" => \"value\" )");
return HANDLER_ERROR;
}
for (size_t j = 0, used = s->forwarded_params->used; j < used; ++j) {
proxy_forwarded_t param;
du = s->forwarded_params->data[j];
if (buffer_is_equal_string(du->key, CONST_STR_LEN("by"))) {
param = PROXY_FORWARDED_BY;
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("for"))) {
param = PROXY_FORWARDED_FOR;
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("host"))) {
param = PROXY_FORWARDED_HOST;
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proto"))) {
param = PROXY_FORWARDED_PROTO;
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("remote_user"))) {
param = PROXY_FORWARDED_REMOTE_USER;
} else {
log_error_write(srv, __FILE__, __LINE__, "sb",
"proxy.forwarded keys must be one of: by, for, host, proto, remote_user, but not:", du->key);
return HANDLER_ERROR;
}
if (du->type == TYPE_STRING) {
data_string *ds = (data_string *)du;
if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
s->forwarded |= param;
} else if (!buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"proxy.forwarded values must be one of: 0, 1, enable, disable; error for key:", du->key);
return HANDLER_ERROR;
}
} else if (du->type == TYPE_INTEGER) {
data_integer *di = (data_integer *)du;
if (di->value) s->forwarded |= param;
} else {
log_error_write(srv, __FILE__, __LINE__, "sb",
"proxy.forwarded values must be one of: 0, 1, enable, disable; error for key:", du->key);
return HANDLER_ERROR;
}
}
[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 (!array_is_kvany(s->header_params)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) )");
return HANDLER_ERROR;
}
for (size_t j = 0, used = s->header_params->used; j < used; ++j) {
data_array *da = (data_array *)s->header_params->data[j];
if (buffer_is_equal_string(da->key, CONST_STR_LEN("https-remap"))) {
data_string *ds = (data_string *)da;
if (ds->type != TYPE_STRING) {
log_error_write(srv, __FILE__, __LINE__, "s",
"unexpected value for proxy.header; expected \"enable\" or \"disable\" for https-remap");
return HANDLER_ERROR;
}
s->header.https_remap = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))
&& !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
continue;
}
else if (buffer_is_equal_string(da->key, CONST_STR_LEN("upgrade"))) {
data_string *ds = (data_string *)da;
if (ds->type != TYPE_STRING) {
log_error_write(srv, __FILE__, __LINE__, "s",
"unexpected value for proxy.header; expected \"upgrade\" => \"enable\" or \"disable\"");
return HANDLER_ERROR;
}
s->header.upgrade = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))
&& !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
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
if (da->type != TYPE_ARRAY || !array_is_kvstring(da->value)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) ) near key", da->key);
return HANDLER_ERROR;
}
if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-urlpath"))) {
s->header.urlpaths = da->value;
}
else if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-host-request"))) {
s->header.hosts_request = da->value;
}
else if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-host-response"))) {
s->header.hosts_response = da->value;
}
else {
log_error_write(srv, __FILE__, __LINE__, "sb",
"unexpected key for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) ) near key", da->key);
return HANDLER_ERROR;
}
}
}
for (i = 0; i < srv->srvconf.modules->used; i++) {
data_string *ds = (data_string *)srv->srvconf.modules->data[i];
if (buffer_is_equal_string(ds->value, 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;
size_t mlen = buffer_string_length(k);
if (1 == mlen && k->ptr[0] == '-') {
/* match with authority provided in Host (if is_req)
* (If no Host in client request, then matching against empty
* string will probably not match, and no remap will be
* performed) */
k = is_req
? remap_hdrs->http_host
: remap_hdrs->forwarded_host;
if (NULL == k) continue;
mlen = buffer_string_length(k);
}
if (mlen == alen && 0 == strncasecmp(s, k->ptr, alen)) {
if (buffer_is_equal_string(ds->value, CONST_STR_LEN("-"))) {
return remap_hdrs->http_host;
}
else if (!buffer_string_is_empty(ds->value)) {
/*(save first matched request host for response match)*/
if (is_req && NULL == remap_hdrs->forwarded_host)
remap_hdrs->forwarded_host = ds->value;
return ds->value;
} /*(else leave authority as-is and stop matching)*/
break;
}
}
}
return NULL;
}
/* (future: might move to http-header-glue.c) */
static size_t http_header_remap_host (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req, size_t alen)
{
const buffer * const m =
http_header_remap_host_match(b, off, remap_hdrs, is_req, alen);
if (NULL == m) return alen; /*(no match; return original authority length)*/
buffer_substr_replace(b, off, alen, m);
return buffer_string_length(m); /*(length of replacement authority)*/
}
/* (future: might move to http-header-glue.c) */
static void http_header_remap_urlpath (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req)
{
const array *urlpaths = remap_hdrs->urlpaths;
if (urlpaths) {
const char * const s = b->ptr+off;
const size_t plen = buffer_string_length(b) - off; /*(urlpath len)*/
if (is_req) { /* request */
for (size_t i = 0, used = urlpaths->used; i < used; ++i) {
const data_string * const ds = (data_string *)urlpaths->data[i];
const size_t mlen = buffer_string_length(ds->key);
if (mlen <= plen && 0 == memcmp(s, ds->key->ptr, mlen)) {
if (NULL == remap_hdrs->forwarded_urlpath)
remap_hdrs->forwarded_urlpath = ds;
buffer_substr_replace(b, off, mlen, ds->value);
break;
}
}
}
else { /* response; perform reverse map */
if (NULL != remap_hdrs->forwarded_urlpath) {
const data_string * const ds = remap_hdrs->forwarded_urlpath;
const size_t mlen = buffer_string_length(ds->value);
if (mlen <= plen && 0 == memcmp(s, ds->value->ptr, mlen)) {
buffer_substr_replace(b, off, mlen, ds->key);
return;
}
}
for (size_t i = 0, used = urlpaths->used; i < used; ++i) {
const data_string * const ds = (data_string *)urlpaths->data[i];
const size_t mlen = buffer_string_length(ds->value);
if (mlen <= plen && 0 == memcmp(s, ds->value->ptr, mlen)) {
buffer_substr_replace(b, off, mlen, ds->key);
break;
}
}
}
}
}
/* (future: might move to http-header-glue.c) */
static void http_header_remap_uri (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req)
{
/* find beginning of URL-path (might be preceded by scheme://authority
* (caller should make sure any leading whitespace is prior to offset) */
if (b->ptr[off] != '/') {
char *s = b->ptr+off;
size_t alen; /*(authority len (host len))*/
size_t slen; /*(scheme len)*/
const buffer *m;
/* skip over scheme and authority of URI to find beginning of URL-path
* (value might conceivably be relative URL-path instead of URI) */
if (NULL == (s = strchr(s, ':')) || s[1] != '/' || s[2] != '/') return;
slen = s - (b->ptr+off);
s += 3;
off = (size_t)(s - b->ptr);
if (NULL != (s = strchr(s, '/'))) {
alen = (size_t)(s - b->ptr) - off;
if (0 == alen) return; /*(empty authority, e.g. "http:///")*/
}
else {
alen = buffer_string_length(b) - off;
if (0 == alen) return; /*(empty authority, e.g. "http:///")*/
buffer_append_string_len(b, CONST_STR_LEN("/"));
}
/* remap authority (if configured) and set offset to url-path */
m = http_header_remap_host_match(b, off, remap_hdrs, is_req, alen);
if (NULL != m) {
if (remap_hdrs->https_remap
&& (is_req ? 5==slen && 0==memcmp(b->ptr+off-slen-3,"https",5)
: 4==slen && 0==memcmp(b->ptr+off-slen-3,"http",4))){
if (is_req) {
memcpy(b->ptr+off-slen-3+4,"://",3); /*("https"=>"http")*/
--off;
++alen;
}
else {/*(!is_req)*/
memcpy(b->ptr+off-slen-3+4,"s://",4); /*("http" =>"https")*/
++off;
--alen;
}
}
buffer_substr_replace(b, off, alen, m);
alen = buffer_string_length(m);/*(length of replacement authority)*/
}
off += alen;
}
/* remap URLs (if configured) */
http_header_remap_urlpath(b, off, remap_hdrs, is_req);
}
/* (future: might move to http-header-glue.c) */
static void http_header_remap_setcookie (buffer *b, size_t off, http_header_remap_opts *remap_hdrs)
{
/* Given the special-case of Set-Cookie and the (too) loosely restricted
* characters allowed, for best results, the Set-Cookie value should be the
* entire string in b from offset to end of string. In response headers,
* lighttpd may concatenate multiple Set-Cookie headers into single entry
* in con->response.headers, separated by "\r\nSet-Cookie: " */
for (char *s, *n = b->ptr+off; (s = n); ) {
size_t len;
n = strchr(s, '\n');
if (NULL == n) {
len = (size_t)(b->ptr + buffer_string_length(b) - s);
}
else {
len = (size_t)(n - s);
n += sizeof("Set-Cookie: "); /*(include +1 for '\n')*/
}
for (char *e = s; NULL != (s = memchr(e, ';', len)); ) {
do { ++s; } while (*s == ' ' || *s == '\t');
if ('\0' == *s) return;
[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)*/
e = memchr(s, '=', len - (size_t)(s - e));
if (NULL == e) { e = s+1; continue; }
++e;
switch ((int)(e - s - 1)) {
case 4:
if (0 == strncasecmp(s, "path", 4)) {
if (*e == '"') ++e;
if (*e != '/') continue;
off = (size_t)(e - b->ptr);
http_header_remap_urlpath(b, off, remap_hdrs, 0);
e = b->ptr+off; /*(b may have been reallocated)*/
continue;
}
break;
case 6:
if (0 == strncasecmp(s, "domain", 6)) {
size_t alen = 0;
if (*e == '"') ++e;
if (*e == '.') ++e;
if (*e == ';') continue;
off = (size_t)(e - b->ptr);
for (char c; (c = e[alen]) != ';' && c != ' ' && c != '\t'
&& c != '\r' && c != '\0'; ++alen);
len = http_header_remap_host(b, off, remap_hdrs, 0, alen);
e = b->ptr+off+len; /*(b may have been reallocated)*/
continue;
}
break;
default:
break;
}
}
}
}
static void proxy_append_header(connection *con, const char *key, const size_t klen, const char *value, const size_t vlen) {
data_string *ds_dst;
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
ds_dst = data_string_init();
}
buffer_copy_string_len(ds_dst->key, key, klen);
buffer_copy_string_len(ds_dst->value, value, vlen);
array_insert_unique(con->request.headers, (data_unset *)ds_dst);
}
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;
char *p;
buffer_string_prepare_append(b, len*2 + 4);
p = b->ptr + buffer_string_length(b);
for (size_t i = 0; i < len; ++i) {
int c = s[i];
if (c == '"' || c == '\\' || c == 0x7F || (c < 0x20 && c != '\t'))
p[j++] = '\\';
p[j++] = c;
}
buffer_commit(b, j);
}
static void proxy_set_Forwarded(connection *con, const unsigned int flags) {
data_string *ds = NULL, *dsfor = NULL, *dsproto = NULL, *dshost = NULL;
buffer *b;
int semicolon = 0;
if (proxy_check_extforward) {
dsfor = (data_string *)
array_get_element(con->environment, "_L_EXTFORWARD_ACTUAL_FOR");
dsproto = (data_string *)
array_get_element(con->environment, "_L_EXTFORWARD_ACTUAL_PROTO");
dshost = (data_string *)
array_get_element(con->environment, "_L_EXTFORWARD_ACTUAL_HOST");
}
/* note: set "Forwarded" prior to updating X-Forwarded-For (below) */
if (flags)
ds = (data_string *)
array_get_element(con->request.headers, "Forwarded");
if (flags && NULL == ds) {
data_string *xff;
ds = (data_string *)
array_get_unused_element(con->request.headers, TYPE_STRING);
if (NULL == ds) ds = data_string_init();
buffer_copy_string_len(ds->key, CONST_STR_LEN("Forwarded"));
array_insert_unique(con->request.headers, (data_unset *)ds);
xff = (data_string *)
array_get_element(con->request.headers, "X-Forwarded-For");
if (NULL != xff && !buffer_string_is_empty(xff->value)) {
/* use X-Forwarded-For contents to seed Forwarded */
char *s = xff->value->ptr;
size_t used = buffer_string_length(xff->value);
for (size_t i=0, j, ipv6; i < used; ++i) {
while (s[i] == ' ' || s[i] == '\t' || s[i] == ',') ++i;
if (s[i] == '\0') break;
j = i;
do {
++i;
} while (s[i]!=' ' && s[i]!='\t' && s[i]!=',' && s[i]!='\0');
buffer_append_string_len(ds->value, CONST_STR_LEN("for="));
/* over-simplified test expecting only IPv4 or IPv6 addresses,
* (not expecting :port, so treat existence of colon as IPv6,
* and not expecting unix paths, especially not containing ':')
* quote all strings, backslash-escape since IPs not validated*/
ipv6 = (NULL != memchr(s+j, ':', i-j)); /*(over-simplified) */
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
if (ipv6)
buffer_append_string_len(ds->value, CONST_STR_LEN("["));
buffer_append_string_backslash_escaped(ds->value, s+j, i-j);
if (ipv6)
buffer_append_string_len(ds->value, CONST_STR_LEN("]"));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
buffer_append_string_len(ds->value, CONST_STR_LEN(", "));
}
}
} else if (flags) { /*(NULL != ds)*/
buffer_append_string_len(ds->value, CONST_STR_LEN(", "));
}
if (flags & PROXY_FORWARDED_FOR) {
2017-10-29 05:23:19 +00:00
int family = sock_addr_get_family(&con->dst_addr);
buffer_append_string_len(ds->value, CONST_STR_LEN("for="));
if (NULL != dsfor) {
/* over-simplified test expecting only IPv4 or IPv6 addresses,
* (not expecting :port, so treat existence of colon as IPv6,
* and not expecting unix paths, especially not containing ':')
* quote all strings and backslash-escape since IPs not validated
* (should be IP from original con->dst_addr_buf,
* so trustable and without :port) */
int ipv6 = (NULL != strchr(dsfor->value->ptr, ':'));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
if (ipv6) buffer_append_string_len(ds->value, CONST_STR_LEN("["));
buffer_append_string_backslash_escaped(
ds->value, CONST_BUF_LEN(dsfor->value));
if (ipv6) buffer_append_string_len(ds->value, CONST_STR_LEN("]"));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
2017-10-29 05:23:19 +00:00
} else if (family == AF_INET) {
/*(Note: if :port is added, then must be quoted-string:
* e.g. for="...:port")*/
buffer_append_string_buffer(ds->value, con->dst_addr_buf);
2017-10-29 05:23:19 +00:00
} else if (family == AF_INET6) {
buffer_append_string_len(ds->value, CONST_STR_LEN("\"["));
buffer_append_string_buffer(ds->value, con->dst_addr_buf);
buffer_append_string_len(ds->value, CONST_STR_LEN("]\""));
} else {
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
buffer_append_string_backslash_escaped(
ds->value, CONST_BUF_LEN(con->dst_addr_buf));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
}
semicolon = 1;
}
if (flags & PROXY_FORWARDED_BY) {
2017-10-29 05:23:19 +00:00
int family = sock_addr_get_family(&con->srv_socket->addr);
/* Note: getsockname() and inet_ntop() are expensive operations.
* (recommendation: do not to enable by=... unless required)
* future: might use con->srv_socket->srv_token if addr is not
* INADDR_ANY or in6addr_any, but must omit optional :port
* from con->srv_socket->srv_token for consistency */
if (semicolon) buffer_append_string_len(ds->value, CONST_STR_LEN(";"));
buffer_append_string_len(ds->value, CONST_STR_LEN("by="));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
#ifdef HAVE_SYS_UN_H
2017-10-29 05:23:19 +00:00
/* special-case: might need to encode unix domain socket path */
if (family == AF_UNIX) {
buffer_append_string_backslash_escaped(
ds->value, CONST_BUF_LEN(con->srv_socket->srv_token));
2017-10-29 05:23:19 +00:00
}
else
#endif
2017-10-29 05:23:19 +00:00
{
sock_addr addr;
socklen_t addrlen = sizeof(addr);
if (0 == getsockname(con->fd,(struct sockaddr *)&addr, &addrlen)) {
sock_addr_stringify_append_buffer(ds->value, &addr);
}
}
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
semicolon = 1;
}
if (flags & PROXY_FORWARDED_PROTO) {
/* expecting "http" or "https"
* (not checking if quoted-string and encoding needed) */
if (semicolon) buffer_append_string_len(ds->value, CONST_STR_LEN(";"));
buffer_append_string_len(ds->value, CONST_STR_LEN("proto="));
if (NULL != dsproto) {
buffer_append_string_buffer(ds->value, dsproto->value);
} else if (con->srv_socket->is_ssl) {
buffer_append_string_len(ds->value, CONST_STR_LEN("https"));
} else {
buffer_append_string_len(ds->value, CONST_STR_LEN("http"));
}
semicolon = 1;
}
if (flags & PROXY_FORWARDED_HOST) {
if (NULL != dshost) {
if (semicolon)
buffer_append_string_len(ds->value, CONST_STR_LEN(";"));
buffer_append_string_len(ds->value, CONST_STR_LEN("host=\""));
buffer_append_string_backslash_escaped(
ds->value, CONST_BUF_LEN(dshost->value));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
semicolon = 1;
} else if (!buffer_string_is_empty(con->request.http_host)) {
if (semicolon)
buffer_append_string_len(ds->value, CONST_STR_LEN(";"));
buffer_append_string_len(ds->value, CONST_STR_LEN("host=\""));
buffer_append_string_backslash_escaped(
ds->value, CONST_BUF_LEN(con->request.http_host));
buffer_append_string_len(ds->value, CONST_STR_LEN("\""));
semicolon = 1;
}
}
if (flags & PROXY_FORWARDED_REMOTE_USER) {
data_string *remote_user = (data_string *)
array_get_element(con->environment, "REMOTE_USER");
if (NULL != remote_user) {
if (semicolon)
buffer_append_string_len(ds->value, CONST_STR_LEN(";"));
buffer_append_string_len(ds->value,CONST_STR_LEN("remote_user=\""));
buffer_append_string_backslash_escaped(
ds->value, CONST_BUF_LEN(remote_user->value));
buffer_append_string_len(ds->value,CONST_STR_LEN("\""));
semicolon = 1;
}
}
/* legacy X-* headers, including X-Forwarded-For */
b = (NULL != dsfor) ? dsfor->value : con->dst_addr_buf;
proxy_append_header(con, CONST_STR_LEN("X-Forwarded-For"),
CONST_BUF_LEN(b));
b = (NULL != dshost) ? dshost->value : con->request.http_host;
if (!buffer_string_is_empty(b)) {
proxy_append_header(con, CONST_STR_LEN("X-Host"),
CONST_BUF_LEN(b));
proxy_append_header(con, CONST_STR_LEN("X-Forwarded-Host"),