2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "buffer.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "keyvalue.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
|
|
|
#include "http_chunk.h"
|
|
|
|
#include "fdevent.h"
|
2017-04-03 18:50:14 +00:00
|
|
|
#include "inet_ntop_cache.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "connections.h"
|
|
|
|
#include "response.h"
|
|
|
|
#include "joblist.h"
|
|
|
|
|
|
|
|
#include "plugin.h"
|
|
|
|
|
2005-05-08 06:25:17 +00:00
|
|
|
#include "crc32.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2017-03-24 01:37:17 +00:00
|
|
|
#include <limits.h>
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
#include "sys-socket.h"
|
|
|
|
|
|
|
|
#define data_proxy data_fastcgi
|
|
|
|
#define data_proxy_init data_fastcgi_init
|
|
|
|
|
|
|
|
#define PROXY_RETRY_TIMEOUT 60
|
|
|
|
|
|
|
|
/**
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2017-03-18 04:10:48 +00:00
|
|
|
* HTTP reverse proxy
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2017-03-18 04:10:48 +00:00
|
|
|
* TODO: - HTTP/1.1
|
|
|
|
* - HTTP/1.1 persistent connection with upstream servers
|
2005-02-20 14:27:00 +00:00
|
|
|
*/
|
2017-03-18 04:10:48 +00:00
|
|
|
|
[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;
|
|
|
|
/*(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;
|
|
|
|
|
2005-05-08 06:25:17 +00:00
|
|
|
typedef enum {
|
|
|
|
PROXY_BALANCE_UNSET,
|
|
|
|
PROXY_BALANCE_FAIR,
|
|
|
|
PROXY_BALANCE_HASH,
|
2016-12-17 07:16:21 +00:00
|
|
|
PROXY_BALANCE_RR,
|
|
|
|
PROXY_BALANCE_STICKY
|
2005-05-08 06:25:17 +00:00
|
|
|
} proxy_balance_t;
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2017-04-01 23:27:05 +00:00
|
|
|
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;
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
typedef struct {
|
|
|
|
array *extensions;
|
2017-04-01 23:27:05 +00:00
|
|
|
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;
|
2007-08-17 22:17:00 +00:00
|
|
|
unsigned short debug;
|
2016-12-10 06:37:49 +00:00
|
|
|
unsigned short replace_http_host;
|
2017-04-01 23:27:05 +00:00
|
|
|
unsigned int forwarded;
|
2005-05-31 08:23:33 +00:00
|
|
|
|
|
|
|
proxy_balance_t balance;
|
[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;
|
2005-02-20 14:27:00 +00:00
|
|
|
} plugin_config;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PLUGIN_DATA;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-05-08 06:25:17 +00:00
|
|
|
buffer *balance_buf;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
plugin_config **config_storage;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
plugin_config conf;
|
|
|
|
} plugin_data;
|
|
|
|
|
2017-04-01 23:27:05 +00:00
|
|
|
static int proxy_check_extforward;
|
|
|
|
|
2006-10-04 13:26:23 +00:00
|
|
|
typedef enum {
|
|
|
|
PROXY_STATE_INIT,
|
|
|
|
PROXY_STATE_CONNECT,
|
|
|
|
PROXY_STATE_PREPARE_WRITE,
|
|
|
|
PROXY_STATE_WRITE,
|
2016-04-07 00:46:43 +00:00
|
|
|
PROXY_STATE_READ
|
2005-05-08 06:25:17 +00:00
|
|
|
} proxy_connection_state_t;
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
enum { PROXY_STDOUT, PROXY_END_REQUEST };
|
2005-05-08 06:25:17 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
typedef struct {
|
|
|
|
proxy_connection_state_t state;
|
|
|
|
time_t state_timestamp;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
data_proxy *host;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
buffer *response;
|
|
|
|
|
2005-09-26 08:56:39 +00:00
|
|
|
chunkqueue *wb;
|
2016-06-10 04:04:10 +00:00
|
|
|
off_t wb_reqlen;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
int fd; /* fd to the proxy process */
|
|
|
|
int fde_ndx; /* index into the fd-event buffer */
|
|
|
|
|
2017-03-18 04:10:48 +00:00
|
|
|
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;
|
2016-09-19 05:27:11 +00:00
|
|
|
plugin_config conf;
|
|
|
|
|
2016-10-25 21:44:45 +00:00
|
|
|
connection *remote_conn; /* dumb pointer */
|
|
|
|
plugin_data *plugin_data; /* dumb pointer */
|
|
|
|
data_array *ext;
|
2005-02-20 14:27:00 +00:00
|
|
|
} handler_ctx;
|
|
|
|
|
|
|
|
/* ok, we need a prototype */
|
2010-08-06 21:57:15 +00:00
|
|
|
static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents);
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2012-08-31 14:11:41 +00:00
|
|
|
static handler_ctx * handler_ctx_init(void) {
|
2005-02-20 14:27:00 +00:00
|
|
|
handler_ctx * hctx;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
hctx = calloc(1, sizeof(*hctx));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
hctx->state = PROXY_STATE_INIT;
|
|
|
|
hctx->host = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
hctx->response = buffer_init();
|
|
|
|
|
2005-09-26 08:56:39 +00:00
|
|
|
hctx->wb = chunkqueue_init();
|
2016-06-10 04:04:10 +00:00
|
|
|
hctx->wb_reqlen = 0;
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
hctx->fd = -1;
|
|
|
|
hctx->fde_ndx = -1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return hctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handler_ctx_free(handler_ctx *hctx) {
|
|
|
|
buffer_free(hctx->response);
|
2005-09-26 08:56:39 +00:00
|
|
|
chunkqueue_free(hctx->wb);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
free(hctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_FUNC(mod_proxy_init) {
|
|
|
|
plugin_data *p;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
p = calloc(1, sizeof(*p));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-05-08 06:25:17 +00:00
|
|
|
p->balance_buf = buffer_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FREE_FUNC(mod_proxy_free) {
|
|
|
|
plugin_data *p = p_d;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
UNUSED(srv);
|
|
|
|
|
2005-05-08 06:25:17 +00:00
|
|
|
buffer_free(p->balance_buf);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (p->config_storage) {
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
|
|
|
plugin_config *s = p->config_storage[i];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-05-14 09:38:33 +00:00
|
|
|
if (NULL == s) continue;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-05-14 09:38:33 +00:00
|
|
|
array_free(s->extensions);
|
2017-04-01 23:27:05 +00:00
|
|
|
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);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-05-14 09:38:33 +00:00
|
|
|
free(s);
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
free(p->config_storage);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
free(p);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
|
|
|
plugin_data *p = p_d;
|
|
|
|
data_unset *du;
|
|
|
|
size_t i = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
config_values_t cv[] = {
|
2005-02-20 14:27:00 +00:00
|
|
|
{ "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
|
|
|
{ "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
|
2005-05-31 08:23:33 +00:00
|
|
|
{ "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
|
2016-12-22 17:44:51 +00:00
|
|
|
{ "proxy.replace-http-host", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
|
2017-04-01 23:27:05 +00:00
|
|
|
{ "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 */
|
2005-02-20 14:27:00 +00:00
|
|
|
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
|
|
|
};
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2013-11-13 11:43:26 +00:00
|
|
|
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
2015-11-07 12:51:11 +00:00
|
|
|
data_config const* config = (data_config const*)srv->config_context->data[i];
|
2005-02-20 14:27:00 +00:00
|
|
|
plugin_config *s;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2017-05-01 00:37:33 +00:00
|
|
|
s = calloc(1, sizeof(plugin_config));
|
2005-02-20 14:27:00 +00:00
|
|
|
s->extensions = array_init();
|
|
|
|
s->debug = 0;
|
2016-12-10 06:37:49 +00:00
|
|
|
s->replace_http_host = 0;
|
2017-04-01 23:27:05 +00:00
|
|
|
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();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
cv[0].destination = s->extensions;
|
|
|
|
cv[1].destination = &(s->debug);
|
2005-05-31 08:23:33 +00:00
|
|
|
cv[2].destination = p->balance_buf;
|
2016-12-10 06:37:49 +00:00
|
|
|
cv[3].destination = &(s->replace_http_host);
|
2017-04-01 23:27:05 +00:00
|
|
|
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;
|
2005-05-31 08:23:33 +00:00
|
|
|
|
|
|
|
buffer_reset(p->balance_buf);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
p->config_storage[i] = s;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-11-07 12:51:11 +00:00
|
|
|
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
if (buffer_string_is_empty(p->balance_buf)) {
|
2005-05-31 08:23:33 +00:00
|
|
|
s->balance = PROXY_BALANCE_FAIR;
|
|
|
|
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
|
|
|
|
s->balance = PROXY_BALANCE_FAIR;
|
|
|
|
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("round-robin"))) {
|
|
|
|
s->balance = PROXY_BALANCE_RR;
|
|
|
|
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
|
|
|
|
s->balance = PROXY_BALANCE_HASH;
|
2016-12-17 07:16:21 +00:00
|
|
|
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("sticky"))) {
|
|
|
|
s->balance = PROXY_BALANCE_STICKY;
|
2005-05-31 08:23:33 +00:00
|
|
|
} else {
|
2006-10-04 13:26:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb",
|
2016-12-17 07:16:21 +00:00
|
|
|
"proxy.balance has to be one of: fair, round-robin, hash, sticky, but not:", p->balance_buf);
|
2005-05-31 08:23:33 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
|
|
|
|
2017-04-01 23:27:05 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-07 12:51:11 +00:00
|
|
|
if (NULL != (du = array_get_element(config->value, "proxy.server"))) {
|
2005-02-20 14:27:00 +00:00
|
|
|
size_t j;
|
|
|
|
data_array *da = (data_array *)du;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2017-03-05 20:39:45 +00:00
|
|
|
if (du->type != TYPE_ARRAY || !array_is_kvarray(da->value)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"unexpected value for proxy.server; expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
/*
|
2005-02-20 14:27:00 +00:00
|
|
|
* proxy.server = ( "<ext>" => ...,
|
|
|
|
* "<ext>" => ... )
|
|
|
|
*/
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (j = 0; j < da->value->used; j++) {
|
|
|
|
data_array *da_ext = (data_array *)da->value->data[j];
|
|
|
|
size_t n;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* proxy.server = ( "<ext>" =>
|
|
|
|
* ( "<host>" => ( ... ),
|
2005-02-20 14:27:00 +00:00
|
|
|
* "<host>" => ( ... )
|
2006-10-04 13:26:23 +00:00
|
|
|
* ),
|
2005-02-20 14:27:00 +00:00
|
|
|
* "<ext>" => ... )
|
|
|
|
*/
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (n = 0; n < da_ext->value->used; n++) {
|
|
|
|
data_array *da_host = (data_array *)da_ext->value->data[n];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
data_proxy *df;
|
|
|
|
data_array *dfa;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
config_values_t pcv[] = {
|
2005-02-20 14:27:00 +00:00
|
|
|
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
|
|
|
{ "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
|
|
|
|
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
|
|
|
};
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2017-03-05 20:39:45 +00:00
|
|
|
if (da_host->type != TYPE_ARRAY || !array_is_kvany(da_host->value)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "SBS",
|
|
|
|
"unexpected value for proxy.server near [",
|
|
|
|
da_host->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
df = data_proxy_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-06-05 09:05:10 +00:00
|
|
|
df->port = 80;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_buffer(df->key, da_host->key);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
pcv[0].destination = df->host;
|
|
|
|
pcv[1].destination = &(df->port);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-11-07 12:51:11 +00:00
|
|
|
if (0 != config_insert_values_internal(srv, da_host->value, pcv, T_CONFIG_SCOPE_CONNECTION)) {
|
2014-02-14 21:06:19 +00:00
|
|
|
df->free((data_unset*) df);
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
if (buffer_string_is_empty(df->host)) {
|
2006-10-04 13:26:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbbbs",
|
|
|
|
"missing key (string):",
|
2005-02-20 14:27:00 +00:00
|
|
|
da->key,
|
|
|
|
da_ext->key,
|
|
|
|
da_host->key,
|
|
|
|
"host");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2014-02-14 21:06:19 +00:00
|
|
|
df->free((data_unset*) df);
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
/* if extension already exists, take it */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
|
|
|
|
dfa = data_array_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_buffer(dfa->key, da_ext->key);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
array_insert_unique(dfa->value, (data_unset *)df);
|
|
|
|
array_insert_unique(s->extensions, (data_unset *)dfa);
|
|
|
|
} else {
|
|
|
|
array_insert_unique(dfa->value, (data_unset *)df);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2017-04-01 23:27:05 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-10-25 21:44:45 +00:00
|
|
|
static void proxy_backend_close(server *srv, handler_ctx *hctx) {
|
2005-02-20 14:27:00 +00:00
|
|
|
if (hctx->fd != -1) {
|
2005-08-08 08:22:06 +00:00
|
|
|
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
|
|
|
|
fdevent_unregister(srv->ev, hctx->fd);
|
2016-08-24 19:30:11 +00:00
|
|
|
fdevent_sched_close(srv->ev, hctx->fd, 1);
|
2016-10-25 21:44:45 +00:00
|
|
|
hctx->fd = -1;
|
|
|
|
hctx->fde_ndx = -1;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2010-04-07 15:34:51 +00:00
|
|
|
if (hctx->host) {
|
|
|
|
hctx->host->usage--;
|
2016-10-25 21:44:45 +00:00
|
|
|
hctx->host = NULL;
|
2010-04-07 15:34:51 +00:00
|
|
|
}
|
2016-10-25 21:44:45 +00:00
|
|
|
}
|
2010-04-07 15:34:51 +00:00
|
|
|
|
2016-11-28 17:39:37 +00:00
|
|
|
static data_proxy * mod_proxy_extension_host_get(server *srv, connection *con, data_array *extension, proxy_balance_t balance, int debug) {
|
2016-10-25 21:44:45 +00:00
|
|
|
unsigned long last_max = ULONG_MAX;
|
|
|
|
int max_usage = INT_MAX;
|
|
|
|
int ndx = -1;
|
|
|
|
size_t k;
|
|
|
|
|
|
|
|
if (extension->value->used == 1) {
|
|
|
|
if ( ((data_proxy *)extension->value->data[0])->is_disabled ) {
|
|
|
|
ndx = -1;
|
|
|
|
} else {
|
|
|
|
ndx = 0;
|
|
|
|
}
|
2016-11-28 17:39:37 +00:00
|
|
|
} else if (extension->value->used != 0) switch(balance) {
|
2016-10-25 21:44:45 +00:00
|
|
|
case PROXY_BALANCE_HASH:
|
|
|
|
/* hash balancing */
|
|
|
|
|
2016-11-28 17:39:37 +00:00
|
|
|
if (debug) {
|
2016-10-25 21:44:45 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sd",
|
|
|
|
"proxy - used hash balancing, hosts:", extension->value->used);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
|
|
|
|
data_proxy *host = (data_proxy *)extension->value->data[k];
|
|
|
|
unsigned long cur_max;
|
|
|
|
|
|
|
|
if (host->is_disabled) continue;
|
|
|
|
|
|
|
|
cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
|
|
|
|
generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
|
|
|
|
generate_crc32c(CONST_BUF_LEN(con->uri.authority));
|
|
|
|
|
2016-11-28 17:39:37 +00:00
|
|
|
if (debug) {
|
2016-10-25 21:44:45 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbbbd",
|
|
|
|
"proxy - election:",
|
|
|
|
con->uri.path,
|
|
|
|
host->host,
|
|
|
|
con->uri.authority,
|
|
|
|
cur_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((last_max == ULONG_MAX) || /* first round */
|
|
|
|
(cur_max > last_max)) {
|
|
|
|
last_max = cur_max;
|
|
|
|
|
|
|
|
ndx = k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case PROXY_BALANCE_FAIR:
|
|
|
|
/* fair balancing */
|
2016-11-28 17:39:37 +00:00
|
|
|
if (debug) {
|
2016-10-25 21:44:45 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"proxy - used fair balancing");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
|
|
|
|
data_proxy *host = (data_proxy *)extension->value->data[k];
|
|
|
|
|
|
|
|
if (host->is_disabled) continue;
|
|
|
|
|
|
|
|
if (host->usage < max_usage) {
|
|
|
|
max_usage = host->usage;
|
|
|
|
|
|
|
|
ndx = k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case PROXY_BALANCE_RR: {
|
|
|
|
data_proxy *host;
|
|
|
|
|
|
|
|
/* round robin */
|
2016-11-28 17:39:37 +00:00
|
|
|
if (debug) {
|
2016-10-25 21:44:45 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"proxy - used round-robin balancing");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* just to be sure */
|
|
|
|
force_assert(extension->value->used < INT_MAX);
|
|
|
|
|
|
|
|
host = (data_proxy *)extension->value->data[0];
|
|
|
|
|
|
|
|
/* Use last_used_ndx from first host in list */
|
|
|
|
k = host->last_used_ndx;
|
|
|
|
ndx = k + 1; /* use next host after the last one */
|
|
|
|
if (ndx < 0) ndx = 0;
|
|
|
|
|
|
|
|
/* Search first active host after last_used_ndx */
|
|
|
|
while ( ndx < (int) extension->value->used
|
|
|
|
&& (host = (data_proxy *)extension->value->data[ndx])->is_disabled ) ndx++;
|
|
|
|
|
|
|
|
if (ndx >= (int) extension->value->used) {
|
|
|
|
/* didn't found a higher id, wrap to the start */
|
|
|
|
for (ndx = 0; ndx <= (int) k; ndx++) {
|
|
|
|
host = (data_proxy *)extension->value->data[ndx];
|
|
|
|
if (!host->is_disabled) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No active host found */
|
|
|
|
if (host->is_disabled) ndx = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save new index for next round */
|
|
|
|
((data_proxy *)extension->value->data[0])->last_used_ndx = ndx;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2016-12-17 07:16:21 +00:00
|
|
|
case PROXY_BALANCE_STICKY:
|
|
|
|
/* source sticky balancing */
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sd",
|
|
|
|
"proxy - used sticky balancing, hosts:", extension->value->used);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
|
|
|
|
data_proxy *host = (data_proxy *)extension->value->data[k];
|
|
|
|
unsigned long cur_max;
|
|
|
|
|
|
|
|
if (host->is_disabled) continue;
|
|
|
|
|
|
|
|
cur_max = generate_crc32c(CONST_BUF_LEN(con->dst_addr_buf)) +
|
|
|
|
generate_crc32c(CONST_BUF_LEN(host->host)) +
|
|
|
|
host->port;
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbbdd",
|
|
|
|
"proxy - election:",
|
|
|
|
con->dst_addr_buf,
|
|
|
|
host->host,
|
|
|
|
host->port,
|
|
|
|
cur_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((last_max == ULONG_MAX) || /* first round */
|
|
|
|
(cur_max > last_max)) {
|
|
|
|
last_max = cur_max;
|
|
|
|
|
|
|
|
ndx = k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2016-10-25 21:44:45 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* found a server */
|
|
|
|
if (ndx != -1) {
|
|
|
|
data_proxy *host = (data_proxy *)extension->value->data[ndx];
|
|
|
|
|
2016-11-28 17:39:37 +00:00
|
|
|
if (debug) {
|
2016-10-25 21:44:45 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbd",
|
|
|
|
"proxy - found a host",
|
|
|
|
host->host, host->port);
|
|
|
|
}
|
|
|
|
|
|
|
|
host->usage++;
|
|
|
|
return host;
|
|
|
|
} else {
|
|
|
|
/* no handler found */
|
|
|
|
con->http_status = 503; /* Service Unavailable */
|
|
|
|
con->mode = DIRECT;
|
|
|
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb",
|
|
|
|
"no proxy-handler found for:",
|
|
|
|
con->uri.path);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void proxy_connection_close(server *srv, handler_ctx *hctx) {
|
|
|
|
plugin_data *p;
|
|
|
|
connection *con;
|
|
|
|
|
|
|
|
p = hctx->plugin_data;
|
|
|
|
con = hctx->remote_conn;
|
|
|
|
|
|
|
|
proxy_backend_close(srv, hctx);
|
2005-02-20 14:27:00 +00:00
|
|
|
handler_ctx_free(hctx);
|
2006-10-04 13:26:23 +00:00
|
|
|
con->plugin_ctx[p->id] = NULL;
|
2016-04-07 00:46:43 +00:00
|
|
|
|
2016-05-27 04:24:33 +00:00
|
|
|
/* finish response (if not already con->file_started, con->file_finished) */
|
|
|
|
if (con->mode == p->id) {
|
|
|
|
http_response_backend_done(srv, con);
|
2016-04-07 00:46:43 +00:00
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2016-10-25 21:44:45 +00:00
|
|
|
static handler_t proxy_reconnect(server *srv, handler_ctx *hctx) {
|
|
|
|
proxy_backend_close(srv, hctx);
|
|
|
|
|
2016-11-28 17:39:37 +00:00
|
|
|
hctx->host = mod_proxy_extension_host_get(srv, hctx->remote_conn, hctx->ext, hctx->conf.balance, (int)hctx->conf.debug);
|
2016-10-25 21:44:45 +00:00
|
|
|
if (NULL == hctx->host) return HANDLER_FINISHED;
|
|
|
|
|
|
|
|
hctx->state = PROXY_STATE_INIT;
|
|
|
|
return HANDLER_COMEBACK;
|
|
|
|
}
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
|
|
|
|
struct sockaddr *proxy_addr;
|
|
|
|
struct sockaddr_in proxy_addr_in;
|
2015-07-11 11:20:18 +00:00
|
|
|
#if defined(HAVE_SYS_UN_H)
|
|
|
|
struct sockaddr_un proxy_addr_un;
|
|
|
|
#endif
|
2009-04-26 21:02:16 +00:00
|
|
|
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
|
|
|
|
struct sockaddr_in6 proxy_addr_in6;
|
|
|
|
#endif
|
2005-02-20 14:27:00 +00:00
|
|
|
socklen_t servlen;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
data_proxy *host= hctx->host;
|
|
|
|
int proxy_fd = hctx->fd;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
|
2015-07-11 11:20:18 +00:00
|
|
|
#if defined(HAVE_SYS_UN_H)
|
|
|
|
if (strstr(host->host->ptr, "/")) {
|
2015-08-30 10:16:28 +00:00
|
|
|
if (buffer_string_length(host->host) + 1 > sizeof(proxy_addr_un.sun_path)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sB",
|
|
|
|
"ERROR: Unix Domain socket filename too long:",
|
|
|
|
host->host);
|
|