Created
October 24, 2014 06:40
-
-
Save ymmt2005/c6b3baafae20ef35307f to your computer and use it in GitHub Desktop.
proxy handler support backport from 2.4.10 to 2.4.7 for Ubuntu 14.04
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- apache2-2.4.7/modules/proxy/mod_proxy.c 2013-11-16 02:07:52.000000000 +0900 | |
+++ httpd-2.4.10/modules/proxy/mod_proxy.c 2014-06-21 22:47:30.000000000 +0900 | |
@@ -744,22 +744,52 @@ | |
*/ | |
const char *proxyname = r->filename + 6; | |
int j; | |
+ apr_pool_t *rxpool = NULL; | |
for (j = 0; j < num_sec; ++j) | |
{ | |
+ int nmatch = 0; | |
+ int i; | |
+ ap_regmatch_t *pmatch = NULL; | |
+ | |
entry_config = sec_proxy[j]; | |
entry_proxy = ap_get_module_config(entry_config, &proxy_module); | |
- /* XXX: What about case insensitive matching ??? | |
- * Compare regex, fnmatch or string as appropriate | |
- * If the entry doesn't relate, then continue | |
- */ | |
- if (entry_proxy->r | |
- ? ap_regexec(entry_proxy->r, proxyname, 0, NULL, 0) | |
- : (entry_proxy->p_is_fnmatch | |
- ? apr_fnmatch(entry_proxy->p, proxyname, 0) | |
- : strncmp(proxyname, entry_proxy->p, | |
- strlen(entry_proxy->p)))) { | |
+ if (entry_proxy->r) { | |
+ | |
+ if (entry_proxy->refs && entry_proxy->refs->nelts) { | |
+ if (!rxpool) { | |
+ apr_pool_create(&rxpool, r->pool); | |
+ } | |
+ nmatch = entry_proxy->refs->nelts; | |
+ pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); | |
+ } | |
+ | |
+ if (ap_regexec(entry_proxy->r, proxyname, nmatch, pmatch, 0)) { | |
+ continue; | |
+ } | |
+ | |
+ for (i = 0; i < nmatch; i++) { | |
+ if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && | |
+ ((const char **)entry_proxy->refs->elts)[i]) { | |
+ apr_table_setn(r->subprocess_env, | |
+ ((const char **)entry_proxy->refs->elts)[i], | |
+ apr_pstrndup(r->pool, | |
+ proxyname + pmatch[i].rm_so, | |
+ pmatch[i].rm_eo - pmatch[i].rm_so)); | |
+ } | |
+ } | |
+ } | |
+ | |
+ else if ( | |
+ /* XXX: What about case insensitive matching ??? | |
+ * Compare regex, fnmatch or string as appropriate | |
+ * If the entry doesn't relate, then continue | |
+ */ | |
+ entry_proxy->p_is_fnmatch ? apr_fnmatch(entry_proxy->p, | |
+ proxyname, 0) : | |
+ strncmp(proxyname, entry_proxy->p, | |
+ strlen(entry_proxy->p))) { | |
continue; | |
} | |
per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults, | |
@@ -768,6 +798,10 @@ | |
r->per_dir_config = per_dir_defaults; | |
+ if (rxpool) { | |
+ apr_pool_destroy(rxpool); | |
+ } | |
+ | |
return OK; | |
} | |
@@ -893,8 +927,25 @@ | |
struct dirconn_entry *list = (struct dirconn_entry *)conf->dirconn->elts; | |
/* is this for us? */ | |
- if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0) | |
+ if (!r->filename) { | |
return DECLINED; | |
+ } | |
+ | |
+ if (!r->proxyreq) { | |
+ /* We may have forced the proxy handler via config or .htaccess */ | |
+ if (r->handler && | |
+ strncmp(r->handler, "proxy:", 6) == 0 && | |
+ strncmp(r->filename, "proxy:", 6) != 0) { | |
+ r->proxyreq = PROXYREQ_REVERSE; | |
+ r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL); | |
+ apr_table_setn(r->notes, "rewrite-proxy", "1"); | |
+ } | |
+ else { | |
+ return DECLINED; | |
+ } | |
+ } else if (strncmp(r->filename, "proxy:", 6) != 0) { | |
+ return DECLINED; | |
+ } | |
/* handle max-forwards / OPTIONS / TRACE */ | |
if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) { | |
@@ -1314,6 +1365,7 @@ | |
new->p = add->p; | |
new->p_is_fnmatch = add->p_is_fnmatch; | |
new->r = add->r; | |
+ new->refs = add->refs; | |
/* Put these in the dir config so they work inside <Location> */ | |
new->raliases = apr_array_append(p, base->raliases, add->raliases); | |
@@ -1335,7 +1387,6 @@ | |
return new; | |
} | |
- | |
static const char * | |
add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex) | |
{ | |
@@ -1410,6 +1461,36 @@ | |
return add_proxy(cmd, dummy, f1, r1, 1); | |
} | |
+static char *de_socketfy(apr_pool_t *p, char *url) | |
+{ | |
+ char *ptr; | |
+ /* | |
+ * We could be passed a URL during the config stage that contains | |
+ * the UDS path... ignore it | |
+ */ | |
+ if (!strncasecmp(url, "unix:", 5) && | |
+ ((ptr = ap_strchr(url, '|')) != NULL)) { | |
+ /* move past the 'unix:...|' UDS path info */ | |
+ char *ret, *c; | |
+ | |
+ ret = ptr + 1; | |
+ /* special case: "unix:....|scheme:" is OK, expand | |
+ * to "unix:....|scheme://localhost" | |
+ * */ | |
+ c = ap_strchr(ret, ':'); | |
+ if (c == NULL) { | |
+ return NULL; | |
+ } | |
+ if (c[1] == '\0') { | |
+ return apr_pstrcat(p, ret, "//localhost", NULL); | |
+ } | |
+ else { | |
+ return ret; | |
+ } | |
+ } | |
+ return url; | |
+} | |
+ | |
static const char * | |
add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex) | |
{ | |
@@ -1501,7 +1582,7 @@ | |
} | |
new->fake = apr_pstrdup(cmd->pool, f); | |
- new->real = apr_pstrdup(cmd->pool, r); | |
+ new->real = apr_pstrdup(cmd->pool, de_socketfy(cmd->pool, r)); | |
new->flags = flags; | |
if (use_regex) { | |
new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); | |
@@ -1520,13 +1601,26 @@ | |
/* Distinguish the balancer from worker */ | |
if (ap_proxy_valid_balancer_name(r, 9)) { | |
proxy_balancer *balancer = ap_proxy_get_balancer(cmd->pool, conf, r, 0); | |
+ char *fake_copy; | |
+ | |
+ /* | |
+ * In the regex case supplying a fake URL doesn't make sense as it | |
+ * cannot be parsed anyway with apr_uri_parse later on in | |
+ * ap_proxy_define_balancer / ap_proxy_update_balancer | |
+ */ | |
+ if (use_regex) { | |
+ fake_copy = NULL; | |
+ } | |
+ else { | |
+ fake_copy = f; | |
+ } | |
if (!balancer) { | |
- const char *err = ap_proxy_define_balancer(cmd->pool, &balancer, conf, r, f, 0); | |
+ const char *err = ap_proxy_define_balancer(cmd->pool, &balancer, conf, r, fake_copy, 0); | |
if (err) | |
return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL); | |
} | |
else { | |
- ap_proxy_update_balancer(cmd->pool, balancer, f); | |
+ ap_proxy_update_balancer(cmd->pool, balancer, fake_copy); | |
} | |
for (i = 0; i < arr->nelts; i++) { | |
const char *err = set_balancer_param(conf, cmd->pool, balancer, elts[i].key, | |
@@ -1537,7 +1631,7 @@ | |
new->balancer = balancer; | |
} | |
else { | |
- proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, r); | |
+ proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->pool, r)); | |
int reuse = 0; | |
if (!worker) { | |
const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0); | |
@@ -1549,14 +1643,14 @@ | |
reuse = 1; | |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01145) | |
"Sharing worker '%s' instead of creating new worker '%s'", | |
- worker->s->name, new->real); | |
+ ap_proxy_worker_name(cmd->pool, worker), new->real); | |
} | |
for (i = 0; i < arr->nelts; i++) { | |
if (reuse) { | |
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01146) | |
"Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", | |
- elts[i].key, elts[i].val, worker->s->name); | |
+ elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); | |
} else { | |
const char *err = set_worker_param(cmd->pool, worker, elts[i].key, | |
elts[i].val); | |
@@ -1662,6 +1756,7 @@ | |
for (i = 0; i < conf->noproxies->nelts; i++) { | |
if (strcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */ | |
found = 1; | |
+ break; | |
} | |
} | |
@@ -1695,8 +1790,10 @@ | |
/* Don't duplicate entries */ | |
for (i = 0; i < conf->dirconn->nelts; i++) { | |
- if (strcasecmp(arg, list[i].name) == 0) | |
+ if (strcasecmp(arg, list[i].name) == 0) { | |
found = 1; | |
+ break; | |
+ } | |
} | |
if (!found) { | |
@@ -2013,7 +2110,7 @@ | |
} | |
/* Try to find existing worker */ | |
- worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, name); | |
+ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, de_socketfy(cmd->temp_pool, name)); | |
if (!worker) { | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147) | |
"Defining worker '%s' for balancer '%s'", | |
@@ -2022,13 +2119,13 @@ | |
return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL); | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01148) | |
"Defined worker '%s' for balancer '%s'", | |
- worker->s->name, balancer->s->name); | |
+ ap_proxy_worker_name(cmd->pool, worker), balancer->s->name); | |
PROXY_COPY_CONF_PARAMS(worker, conf); | |
} else { | |
reuse = 1; | |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01149) | |
"Sharing worker '%s' instead of creating new worker '%s'", | |
- worker->s->name, name); | |
+ ap_proxy_worker_name(cmd->pool, worker), name); | |
} | |
arr = apr_table_elts(params); | |
@@ -2037,7 +2134,7 @@ | |
if (reuse) { | |
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01150) | |
"Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", | |
- elts[i].key, elts[i].val, worker->s->name); | |
+ elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); | |
} else { | |
err = set_worker_param(cmd->pool, worker, elts[i].key, | |
elts[i].val); | |
@@ -2099,7 +2196,7 @@ | |
} | |
} | |
else { | |
- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, name); | |
+ worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->temp_pool, name)); | |
if (!worker) { | |
if (in_proxy_section) { | |
err = ap_proxy_define_worker(cmd->pool, &worker, NULL, | |
@@ -2196,17 +2293,6 @@ | |
return "Regex could not be compiled"; | |
} | |
} | |
- else if (!strcmp(cmd->path, "~")) { | |
- cmd->path = ap_getword_conf(cmd->pool, &arg); | |
- if (!cmd->path) | |
- return "<Proxy ~ > block must specify a path"; | |
- if (strncasecmp(cmd->path, "proxy:", 6)) | |
- cmd->path += 6; | |
- r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED); | |
- if (!r) { | |
- return "Regex could not be compiled"; | |
- } | |
- } | |
/* initialize our config and fetch it */ | |
conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path, | |
@@ -2220,6 +2306,11 @@ | |
conf->p = cmd->path; | |
conf->p_is_fnmatch = apr_fnmatch_test(conf->p); | |
+ if (r) { | |
+ conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); | |
+ ap_regname(r, conf->refs, AP_REG_MATCH, 1); | |
+ } | |
+ | |
ap_add_per_proxy_conf(cmd->server, new_dir_conf); | |
if (*arg != '\0') { | |
@@ -2245,7 +2336,7 @@ | |
} | |
else { | |
worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, | |
- conf->p); | |
+ de_socketfy(cmd->temp_pool, (char*)conf->p)); | |
if (!worker) { | |
err = ap_proxy_define_worker(cmd->pool, &worker, NULL, | |
sconf, conf->p, 0); | |
@@ -2557,6 +2648,8 @@ | |
ap_proxy_hashfunc(conf->forward->s->name, PROXY_HASHFUNC_FNV); | |
/* Do not disable worker in case of errors */ | |
conf->forward->s->status |= PROXY_WORKER_IGNORE_ERRORS; | |
+ /* Mark as the "generic" worker */ | |
+ conf->forward->s->status |= PROXY_WORKER_GENERIC; | |
ap_proxy_initialize_worker(conf->forward, s, conf->pool); | |
/* Disable address cache for generic forward worker */ | |
conf->forward->s->is_address_reusable = 0; | |
@@ -2572,6 +2665,8 @@ | |
ap_proxy_hashfunc(reverse->s->name, PROXY_HASHFUNC_FNV); | |
/* Do not disable worker in case of errors */ | |
reverse->s->status |= PROXY_WORKER_IGNORE_ERRORS; | |
+ /* Mark as the "generic" worker */ | |
+ reverse->s->status |= PROXY_WORKER_GENERIC; | |
conf->reverse = reverse; | |
ap_proxy_initialize_worker(conf->reverse, s, conf->pool); | |
/* Disable address cache for generic reverse worker */ | |
--- apache2-2.4.7/modules/proxy/mod_proxy.h 2013-09-14 12:03:00.000000000 +0900 | |
+++ httpd-2.4.10/modules/proxy/mod_proxy.h 2014-05-30 22:51:39.000000000 +0900 | |
@@ -219,6 +219,10 @@ | |
unsigned int error_override_set:1; | |
unsigned int alias_set:1; | |
unsigned int add_forwarded_headers:1; | |
+ | |
+ /** Named back references */ | |
+ apr_array_header_t *refs; | |
+ | |
} proxy_dir_conf; | |
/* if we interpolate env vars per-request, we'll need a per-request | |
@@ -249,6 +253,8 @@ | |
unsigned int need_flush:1; /* Flag to decide whether we need to flush the | |
* filter chain or not */ | |
unsigned int inreslist:1; /* connection in apr_reslist? */ | |
+ const char *uds_path; /* Unix domain socket path */ | |
+ const char *ssl_hostname;/* Hostname (SNI) in use by SSL connection */ | |
} proxy_conn_rec; | |
typedef struct { | |
@@ -269,6 +275,7 @@ | |
#define PROXY_WORKER_INITIALIZED 0x0001 | |
#define PROXY_WORKER_IGNORE_ERRORS 0x0002 | |
#define PROXY_WORKER_DRAIN 0x0004 | |
+#define PROXY_WORKER_GENERIC 0x0008 | |
#define PROXY_WORKER_IN_SHUTDOWN 0x0010 | |
#define PROXY_WORKER_DISABLED 0x0020 | |
#define PROXY_WORKER_STOPPED 0x0040 | |
@@ -280,6 +287,7 @@ | |
#define PROXY_WORKER_INITIALIZED_FLAG 'O' | |
#define PROXY_WORKER_IGNORE_ERRORS_FLAG 'I' | |
#define PROXY_WORKER_DRAIN_FLAG 'N' | |
+#define PROXY_WORKER_GENERIC_FLAG 'G' | |
#define PROXY_WORKER_IN_SHUTDOWN_FLAG 'U' | |
#define PROXY_WORKER_DISABLED_FLAG 'D' | |
#define PROXY_WORKER_STOPPED_FLAG 'S' | |
@@ -300,6 +308,8 @@ | |
#define PROXY_WORKER_IS_DRAINING(f) ( (f)->s->status & PROXY_WORKER_DRAIN ) | |
+#define PROXY_WORKER_IS_GENERIC(f) ( (f)->s->status & PROXY_WORKER_GENERIC ) | |
+ | |
/* default worker retry timeout in seconds */ | |
#define PROXY_WORKER_DEFAULT_RETRY 60 | |
@@ -341,6 +351,7 @@ | |
char route[PROXY_WORKER_MAX_ROUTE_SIZE]; /* balancing route */ | |
char redirect[PROXY_WORKER_MAX_ROUTE_SIZE]; /* temporary balancing redirection route */ | |
char flusher[PROXY_WORKER_MAX_SCHEME_SIZE]; /* flush provider used by mod_proxy_fdpass */ | |
+ char uds_path[PROXY_WORKER_MAX_NAME_SIZE]; /* path to worker's unix domain socket if applicable */ | |
int lbset; /* load balancer cluster set */ | |
int retries; /* number of retries on this worker */ | |
int lbstatus; /* Current lbstatus */ | |
@@ -586,6 +597,16 @@ | |
/* Connection pool API */ | |
/** | |
+ * Return the user-land, UDS aware worker name | |
+ * @param p memory pool used for displaying worker name | |
+ * @param worker the worker | |
+ * @return name | |
+ */ | |
+ | |
+PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, | |
+ proxy_worker *worker); | |
+ | |
+/** | |
* Get the worker from proxy configuration | |
* @param p memory pool used for finding worker | |
* @param balancer the balancer that the worker belongs to | |
@@ -776,8 +797,9 @@ | |
* @param url request url | |
* @param proxyname are we connecting directly or via a proxy | |
* @param proxyport proxy host port | |
- * @param server_portstr Via headers server port | |
- * @param server_portstr_size size of the server_portstr buffer | |
+ * @param server_portstr Via headers server port, must be non-NULL | |
+ * @param server_portstr_size size of the server_portstr buffer; must | |
+ * be at least one, even if the protocol doesn't use this | |
* @return OK or HTTP_XXX error | |
*/ | |
PROXY_DECLARE(int) ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, | |
@@ -983,6 +1005,13 @@ | |
*/ | |
int ap_proxy_lb_workers(void); | |
+/** | |
+ * Return the port number of a known scheme (eg: http -> 80). | |
+ * @param scheme scheme to test | |
+ * @return port number or 0 if unknown | |
+ */ | |
+PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme); | |
+ | |
extern module PROXY_DECLARE_DATA proxy_module; | |
#endif /*MOD_PROXY_H*/ | |
--- apache2-2.4.7/modules/proxy/proxy_util.c 2014-10-24 00:12:29.000000000 +0900 | |
+++ httpd-2.4.10/modules/proxy/proxy_util.c 2014-10-24 00:12:08.725976600 +0900 | |
@@ -21,6 +21,7 @@ | |
#include "apr_version.h" | |
#include "apr_hash.h" | |
#include "proxy_util.h" | |
+#include "ajp.h" | |
#if APR_HAVE_UNISTD_H | |
#include <unistd.h> /* for getpid() */ | |
@@ -31,6 +32,13 @@ | |
#define apr_socket_create apr_socket_create_ex | |
#endif | |
+#if APR_HAVE_SYS_UN_H | |
+#include <sys/un.h> | |
+#endif | |
+#if (APR_MAJOR_VERSION < 2) | |
+#include "apr_support.h" /* for apr_wait_for_io_or_timeout() */ | |
+#endif | |
+ | |
APLOG_USE_MODULE(proxy); | |
/* | |
@@ -86,14 +94,20 @@ | |
char *thenil; | |
apr_size_t thelen; | |
+ /* special case handling */ | |
+ if (!dlen) { | |
+ /* XXX: APR_ENOSPACE would be better */ | |
+ return APR_EGENERAL; | |
+ } | |
+ if (!src) { | |
+ *dst = '\0'; | |
+ return APR_SUCCESS; | |
+ } | |
thenil = apr_cpystrn(dst, src, dlen); | |
thelen = thenil - dst; | |
- /* Assume the typical case is smaller copying into bigger | |
- so we have a fast return */ | |
- if ((thelen < dlen-1) || ((strlen(src)) == thelen)) { | |
+ if (src[thelen] == '\0') { | |
return APR_SUCCESS; | |
} | |
- /* XXX: APR_ENOSPACE would be better */ | |
return APR_EGENERAL; | |
} | |
@@ -1109,6 +1123,9 @@ | |
const char *url) | |
{ | |
apr_uri_t puri; | |
+ if (!url) { | |
+ return NULL; | |
+ } | |
if (apr_uri_parse(p, url, &puri) != APR_SUCCESS) { | |
return apr_psprintf(p, "unable to parse: %s", url); | |
} | |
@@ -1218,11 +1235,11 @@ | |
} else { | |
action = "re-using"; | |
} | |
+ balancer->s = shm; | |
+ balancer->s->index = i; | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02337) | |
"%s shm[%d] (0x%pp) for %s", action, i, (void *)shm, | |
balancer->s->name); | |
- balancer->s = shm; | |
- balancer->s->index = i; | |
/* the below should always succeed */ | |
lbmethod = ap_lookup_provider(PROXY_LBMETHOD, balancer->s->lbpname, "0"); | |
if (lbmethod) { | |
@@ -1356,7 +1373,7 @@ | |
ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923) | |
"Pooled connection 0x%pp for worker %s has been" | |
" already returned to the connection pool.", conn, | |
- worker->s->name); | |
+ ap_proxy_worker_name(conn->pool, worker)); | |
return APR_SUCCESS; | |
} | |
@@ -1388,6 +1405,7 @@ | |
{ | |
conn->sock = NULL; | |
conn->connection = NULL; | |
+ conn->ssl_hostname = NULL; | |
apr_pool_clear(conn->scpool); | |
} | |
@@ -1480,6 +1498,16 @@ | |
* WORKER related... | |
*/ | |
+PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, | |
+ proxy_worker *worker) | |
+{ | |
+ if (!(*worker->s->uds_path) || !p) { | |
+ /* just in case */ | |
+ return worker->s->name; | |
+ } | |
+ return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL); | |
+} | |
+ | |
PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, | |
proxy_balancer *balancer, | |
proxy_server_conf *conf, | |
@@ -1495,6 +1523,10 @@ | |
char *url_copy; | |
int i; | |
+ if (!url) { | |
+ return NULL; | |
+ } | |
+ | |
c = ap_strchr_c(url, ':'); | |
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { | |
return NULL; | |
@@ -1573,20 +1605,47 @@ | |
int do_malloc) | |
{ | |
int rv; | |
- apr_uri_t uri; | |
+ apr_uri_t uri, urisock; | |
proxy_worker_shared *wshared; | |
- char *ptr; | |
+ char *ptr, *sockpath = NULL; | |
+ /* | |
+ * Look to see if we are using UDS: | |
+ * require format: unix:/path/foo/bar.sock|http://ignored/path2/ | |
+ * This results in talking http to the socket at /path/foo/bar.sock | |
+ */ | |
+ ptr = ap_strchr((char *)url, '|'); | |
+ if (ptr) { | |
+ *ptr = '\0'; | |
+ rv = apr_uri_parse(p, url, &urisock); | |
+ if (rv == APR_SUCCESS && !strcasecmp(urisock.scheme, "unix")) { | |
+ sockpath = ap_runtime_dir_relative(p, urisock.path);; | |
+ url = ptr+1; /* so we get the scheme for the uds */ | |
+ } | |
+ else { | |
+ *ptr = '|'; | |
+ } | |
+ } | |
rv = apr_uri_parse(p, url, &uri); | |
if (rv != APR_SUCCESS) { | |
- return "Unable to parse URL"; | |
+ return apr_pstrcat(p, "Unable to parse URL: ", url, NULL); | |
} | |
- if (!uri.hostname || !uri.scheme) { | |
- return "URL must be absolute!"; | |
+ if (!uri.scheme) { | |
+ return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); | |
+ } | |
+ /* allow for unix:/path|http: */ | |
+ if (!uri.hostname) { | |
+ if (sockpath) { | |
+ uri.hostname = "localhost"; | |
+ } | |
+ else { | |
+ return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); | |
+ } | |
+ } | |
+ else { | |
+ ap_str_tolower(uri.hostname); | |
} | |
- | |
- ap_str_tolower(uri.hostname); | |
ap_str_tolower(uri.scheme); | |
/* | |
* Workers can be associated w/ balancers or on their | |
@@ -1642,6 +1701,15 @@ | |
wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT); | |
wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV); | |
wshared->was_malloced = (do_malloc != 0); | |
+ if (sockpath) { | |
+ if (PROXY_STRNCPY(wshared->uds_path, sockpath) != APR_SUCCESS) { | |
+ return apr_psprintf(p, "worker uds path (%s) too long", sockpath); | |
+ } | |
+ | |
+ } | |
+ else { | |
+ *wshared->uds_path = '\0'; | |
+ } | |
(*worker)->hash = wshared->hash; | |
(*worker)->context = NULL; | |
@@ -1670,12 +1738,18 @@ | |
} else { | |
action = "re-using"; | |
} | |
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) | |
- "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, | |
- worker->s->name); | |
- | |
worker->s = shm; | |
worker->s->index = i; | |
+ { | |
+ apr_pool_t *pool; | |
+ apr_pool_create(&pool, ap_server_conf->process->pool); | |
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) | |
+ "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, | |
+ ap_proxy_worker_name(pool, worker)); | |
+ if (pool) { | |
+ apr_pool_destroy(pool); | |
+ } | |
+ } | |
return APR_SUCCESS; | |
} | |
@@ -1687,11 +1761,13 @@ | |
if (worker->s->status & PROXY_WORKER_INITIALIZED) { | |
/* The worker is already initialized */ | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00924) | |
- "worker %s shared already initialized", worker->s->name); | |
+ "worker %s shared already initialized", | |
+ ap_proxy_worker_name(p, worker)); | |
} | |
else { | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00925) | |
- "initializing worker %s shared", worker->s->name); | |
+ "initializing worker %s shared", | |
+ ap_proxy_worker_name(p, worker)); | |
/* Set default parameters */ | |
if (!worker->s->retry_set) { | |
worker->s->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY); | |
@@ -1727,11 +1803,13 @@ | |
/* What if local is init'ed and shm isn't?? Even possible? */ | |
if (worker->local_status & PROXY_WORKER_INITIALIZED) { | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00926) | |
- "worker %s local already initialized", worker->s->name); | |
+ "worker %s local already initialized", | |
+ ap_proxy_worker_name(p, worker)); | |
} | |
else { | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927) | |
- "initializing worker %s local", worker->s->name); | |
+ "initializing worker %s local", | |
+ ap_proxy_worker_name(p, worker)); | |
apr_global_mutex_lock(proxy_mutex); | |
/* Now init local worker data */ | |
if (worker->tmutex == NULL) { | |
@@ -1853,6 +1931,8 @@ | |
} | |
else if (r->proxyreq == PROXYREQ_REVERSE) { | |
if (conf->reverse) { | |
+ char *ptr; | |
+ char *ptr2; | |
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, | |
"*: found reverse proxy worker for %s", *url); | |
*balancer = NULL; | |
@@ -1864,6 +1944,36 @@ | |
* regarding the Connection header in the request. | |
*/ | |
apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1"); | |
+ /* | |
+ * In the case of the generic reverse proxy, we need to see if we | |
+ * were passed a UDS url (eg: from mod_proxy) and adjust uds_path | |
+ * as required. | |
+ * | |
+ * NOTE: Here we use a quick note lookup, but we could also | |
+ * check to see if r->filename starts with 'proxy:' | |
+ */ | |
+ if (apr_table_get(r->notes, "rewrite-proxy") && | |
+ (ptr2 = ap_strcasestr(r->filename, "unix:")) && | |
+ (ptr = ap_strchr(ptr2, '|'))) { | |
+ apr_uri_t urisock; | |
+ apr_status_t rv; | |
+ *ptr = '\0'; | |
+ rv = apr_uri_parse(r->pool, ptr2, &urisock); | |
+ if (rv == APR_SUCCESS) { | |
+ char *rurl = ptr+1; | |
+ char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path); | |
+ apr_table_setn(r->notes, "uds_path", sockpath); | |
+ *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */ | |
+ /* r->filename starts w/ "proxy:", so add after that */ | |
+ memmove(r->filename+6, rurl, strlen(rurl)+1); | |
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, | |
+ "*: rewrite of url due to UDS(%s): %s (%s)", | |
+ sockpath, *url, r->filename); | |
+ } | |
+ else { | |
+ *ptr = '|'; | |
+ } | |
+ } | |
} | |
} | |
} | |
@@ -2053,6 +2163,7 @@ | |
int server_port; | |
apr_status_t err = APR_SUCCESS; | |
apr_status_t uerr = APR_SUCCESS; | |
+ const char *uds_path; | |
/* | |
* Break up the URL to determine the host to connect to | |
@@ -2065,7 +2176,7 @@ | |
NULL)); | |
} | |
if (!uri->port) { | |
- uri->port = apr_uri_port_of_scheme(uri->scheme); | |
+ uri->port = ap_proxy_port_of_scheme(uri->scheme); | |
} | |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00944) | |
@@ -2093,84 +2204,117 @@ | |
* to check host and port on the conn and be careful about | |
* spilling the cached addr from the worker. | |
*/ | |
- if (!conn->hostname || !worker->s->is_address_reusable || | |
- worker->s->disablereuse) { | |
- if (proxyname) { | |
- conn->hostname = apr_pstrdup(conn->pool, proxyname); | |
- conn->port = proxyport; | |
- /* | |
- * If we have a forward proxy and the protocol is HTTPS, | |
- * then we need to prepend a HTTP CONNECT request before | |
- * sending our actual HTTPS requests. | |
- * Save our real backend data for using it later during HTTP CONNECT. | |
- */ | |
- if (conn->is_ssl) { | |
- const char *proxy_auth; | |
- | |
- forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info)); | |
- conn->forward = forward; | |
- forward->use_http_connect = 1; | |
- forward->target_host = apr_pstrdup(conn->pool, uri->hostname); | |
- forward->target_port = uri->port; | |
- /* Do we want to pass Proxy-Authorization along? | |
- * If we haven't used it, then YES | |
- * If we have used it then MAYBE: RFC2616 says we MAY propagate it. | |
- * So let's make it configurable by env. | |
- * The logic here is the same used in mod_proxy_http. | |
- */ | |
- proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization"); | |
- if (proxy_auth != NULL && | |
- proxy_auth[0] != '\0' && | |
- r->user == NULL && /* we haven't yet authenticated */ | |
- apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { | |
- forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth); | |
- } | |
- } | |
+ uds_path = (*worker->s->uds_path ? worker->s->uds_path : apr_table_get(r->notes, "uds_path")); | |
+ if (uds_path) { | |
+ if (conn->uds_path == NULL) { | |
+ /* use (*conn)->pool instead of worker->cp->pool to match lifetime */ | |
+ conn->uds_path = apr_pstrdup(conn->pool, uds_path); | |
+ } | |
+ if (conn->uds_path) { | |
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02545) | |
+ "%s: has determined UDS as %s", | |
+ uri->scheme, conn->uds_path); | |
} | |
else { | |
- conn->hostname = apr_pstrdup(conn->pool, uri->hostname); | |
- conn->port = uri->port; | |
- } | |
- socket_cleanup(conn); | |
- if (!worker->s->is_address_reusable || worker->s->disablereuse) { | |
- /* | |
- * Only do a lookup if we should not reuse the backend address. | |
- * Otherwise we will look it up once for the worker. | |
- */ | |
- err = apr_sockaddr_info_get(&(conn->addr), | |
- conn->hostname, APR_UNSPEC, | |
- conn->port, 0, | |
- conn->pool); | |
+ /* should never happen */ | |
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02546) | |
+ "%s: cannot determine UDS (%s)", | |
+ uri->scheme, uds_path); | |
+ | |
} | |
- } | |
- if (worker->s->is_address_reusable && !worker->s->disablereuse) { | |
/* | |
- * Looking up the backend address for the worker only makes sense if | |
- * we can reuse the address. | |
+ * In UDS cases, some structs are NULL. Protect from de-refs | |
+ * and provide info for logging at the same time. | |
*/ | |
- if (!worker->cp->addr) { | |
- if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { | |
- ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); | |
- return HTTP_INTERNAL_SERVER_ERROR; | |
- } | |
+ if (!conn->addr) { | |
+ apr_sockaddr_t *sa; | |
+ apr_sockaddr_info_get(&sa, NULL, APR_UNSPEC, 0, 0, conn->pool); | |
+ conn->addr = sa; | |
+ } | |
+ conn->hostname = "httpd-UDS"; | |
+ conn->port = 0; | |
+ } | |
+ else { | |
+ int will_reuse = worker->s->is_address_reusable && !worker->s->disablereuse; | |
+ if (!conn->hostname || !will_reuse) { | |
+ if (proxyname) { | |
+ conn->hostname = apr_pstrdup(conn->pool, proxyname); | |
+ conn->port = proxyport; | |
+ /* | |
+ * If we have a forward proxy and the protocol is HTTPS, | |
+ * then we need to prepend a HTTP CONNECT request before | |
+ * sending our actual HTTPS requests. | |
+ * Save our real backend data for using it later during HTTP CONNECT. | |
+ */ | |
+ if (conn->is_ssl) { | |
+ const char *proxy_auth; | |
+ forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info)); | |
+ conn->forward = forward; | |
+ forward->use_http_connect = 1; | |
+ forward->target_host = apr_pstrdup(conn->pool, uri->hostname); | |
+ forward->target_port = uri->port; | |
+ /* Do we want to pass Proxy-Authorization along? | |
+ * If we haven't used it, then YES | |
+ * If we have used it then MAYBE: RFC2616 says we MAY propagate it. | |
+ * So let's make it configurable by env. | |
+ * The logic here is the same used in mod_proxy_http. | |
+ */ | |
+ proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization"); | |
+ if (proxy_auth != NULL && | |
+ proxy_auth[0] != '\0' && | |
+ r->user == NULL && /* we haven't yet authenticated */ | |
+ apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { | |
+ forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth); | |
+ } | |
+ } | |
+ } | |
+ else { | |
+ conn->hostname = apr_pstrdup(conn->pool, uri->hostname); | |
+ conn->port = uri->port; | |
+ } | |
+ if (!will_reuse) { | |
+ /* | |
+ * Only do a lookup if we should not reuse the backend address. | |
+ * Otherwise we will look it up once for the worker. | |
+ */ | |
+ err = apr_sockaddr_info_get(&(conn->addr), | |
+ conn->hostname, APR_UNSPEC, | |
+ conn->port, 0, | |
+ conn->pool); | |
+ } | |
+ socket_cleanup(conn); | |
+ conn->close = 0; | |
+ } | |
+ if (will_reuse) { | |
/* | |
- * Worker can have the single constant backend adress. | |
- * The single DNS lookup is used once per worker. | |
- * If dynamic change is needed then set the addr to NULL | |
- * inside dynamic config to force the lookup. | |
+ * Looking up the backend address for the worker only makes sense if | |
+ * we can reuse the address. | |
*/ | |
- err = apr_sockaddr_info_get(&(worker->cp->addr), | |
- conn->hostname, APR_UNSPEC, | |
- conn->port, 0, | |
- worker->cp->pool); | |
- conn->addr = worker->cp->addr; | |
- if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { | |
- ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); | |
+ if (!worker->cp->addr) { | |
+ if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { | |
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); | |
+ return HTTP_INTERNAL_SERVER_ERROR; | |
+ } | |
+ | |
+ /* | |
+ * Worker can have the single constant backend adress. | |
+ * The single DNS lookup is used once per worker. | |
+ * If dynamic change is needed then set the addr to NULL | |
+ * inside dynamic config to force the lookup. | |
+ */ | |
+ err = apr_sockaddr_info_get(&(worker->cp->addr), | |
+ conn->hostname, APR_UNSPEC, | |
+ conn->port, 0, | |
+ worker->cp->pool); | |
+ conn->addr = worker->cp->addr; | |
+ if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { | |
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); | |
+ } | |
+ } | |
+ else { | |
+ conn->addr = worker->cp->addr; | |
} | |
- } | |
- else { | |
- conn->addr = worker->cp->addr; | |
} | |
} | |
/* Close a possible existing socket if we are told to do so */ | |
@@ -2186,22 +2330,56 @@ | |
} | |
/* Get the server port for the Via headers */ | |
- { | |
- server_port = ap_get_server_port(r); | |
- if (ap_is_default_port(server_port, r)) { | |
- strcpy(server_portstr,""); | |
- } | |
- else { | |
- apr_snprintf(server_portstr, server_portstr_size, ":%d", | |
- server_port); | |
- } | |
+ server_port = ap_get_server_port(r); | |
+ AP_DEBUG_ASSERT(server_portstr_size > 0); | |
+ if (ap_is_default_port(server_port, r)) { | |
+ server_portstr[0] = '\0'; | |
+ } | |
+ else { | |
+ apr_snprintf(server_portstr, server_portstr_size, ":%d", | |
+ server_port); | |
} | |
+ | |
/* check if ProxyBlock directive on this host */ | |
if (OK != ap_proxy_checkproxyblock2(r, conf, uri->hostname, | |
proxyname ? NULL : conn->addr)) { | |
return ap_proxyerror(r, HTTP_FORBIDDEN, | |
"Connect to remote machine blocked"); | |
} | |
+ /* | |
+ * When SSL is configured, determine the hostname (SNI) for the request | |
+ * and save it in conn->ssl_hostname. Close any reused connection whose | |
+ * SNI differs. | |
+ */ | |
+ if (conn->is_ssl) { | |
+ proxy_dir_conf *dconf; | |
+ const char *ssl_hostname; | |
+ /* | |
+ * In the case of ProxyPreserveHost on use the hostname of | |
+ * the request if present otherwise use the one from the | |
+ * backend request URI. | |
+ */ | |
+ dconf = ap_get_module_config(r->per_dir_config, &proxy_module); | |
+ if (dconf->preserve_host) { | |
+ ssl_hostname = r->hostname; | |
+ } | |
+ else { | |
+ ssl_hostname = conn->hostname; | |
+ } | |
+ /* | |
+ * Close if a SNI is in use but this request requires no or | |
+ * a different one, or no SNI is in use but one is required. | |
+ */ | |
+ if ((conn->ssl_hostname && (!ssl_hostname || | |
+ strcasecmp(conn->ssl_hostname, | |
+ ssl_hostname) != 0)) || | |
+ (!conn->ssl_hostname && ssl_hostname && conn->sock)) { | |
+ socket_cleanup(conn); | |
+ } | |
+ if (conn->ssl_hostname == NULL) { | |
+ conn->ssl_hostname = apr_pstrdup(conn->scpool, ssl_hostname); | |
+ } | |
+ } | |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00947) | |
"connected %s to %s:%d", *url, conn->hostname, conn->port); | |
return OK; | |
@@ -2372,6 +2550,52 @@ | |
} | |
+#if APR_HAVE_SYS_UN_H | |
+/* lifted from mod_proxy_fdpass.c; tweaked addrlen in connect() call */ | |
+static apr_status_t socket_connect_un(apr_socket_t *sock, | |
+ struct sockaddr_un *sa) | |
+{ | |
+ apr_status_t rv; | |
+ apr_os_sock_t rawsock; | |
+ apr_interval_time_t t; | |
+ | |
+ rv = apr_os_sock_get(&rawsock, sock); | |
+ if (rv != APR_SUCCESS) { | |
+ return rv; | |
+ } | |
+ | |
+ rv = apr_socket_timeout_get(sock, &t); | |
+ if (rv != APR_SUCCESS) { | |
+ return rv; | |
+ } | |
+ | |
+ do { | |
+ const socklen_t addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path) | |
+ + strlen(sa->sun_path) + 1; | |
+ rv = connect(rawsock, (struct sockaddr*)sa, addrlen); | |
+ } while (rv == -1 && errno == EINTR); | |
+ | |
+ if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY) | |
+ && (t > 0)) { | |
+#if APR_MAJOR_VERSION < 2 | |
+ rv = apr_wait_for_io_or_timeout(NULL, sock, 0); | |
+#else | |
+ rv = apr_socket_wait(sock, APR_WAIT_WRITE); | |
+#endif | |
+ | |
+ if (rv != APR_SUCCESS) { | |
+ return rv; | |
+ } | |
+ } | |
+ | |
+ if (rv == -1 && errno != EISCONN) { | |
+ return errno; | |
+ } | |
+ | |
+ return APR_SUCCESS; | |
+} | |
+#endif | |
+ | |
PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, | |
proxy_conn_rec *conn, | |
proxy_worker *worker, | |
@@ -2396,93 +2620,131 @@ | |
proxy_function); | |
} | |
} | |
- while (backend_addr && !connected) { | |
- if ((rv = apr_socket_create(&newsock, backend_addr->family, | |
- SOCK_STREAM, APR_PROTO_TCP, | |
- conn->scpool)) != APR_SUCCESS) { | |
- loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; | |
- ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) | |
- "%s: error creating fam %d socket for target %s", | |
- proxy_function, | |
- backend_addr->family, | |
- worker->s->hostname); | |
- /* | |
- * this could be an IPv6 address from the DNS but the | |
- * local machine won't give us an IPv6 socket; hopefully the | |
- * DNS returned an additional address to try | |
- */ | |
- backend_addr = backend_addr->next; | |
- continue; | |
- } | |
- conn->connection = NULL; | |
+ while ((backend_addr || conn->uds_path) && !connected) { | |
+#if APR_HAVE_SYS_UN_H | |
+ if (conn->uds_path) | |
+ { | |
+ struct sockaddr_un sa; | |
- if (worker->s->recv_buffer_size > 0 && | |
- (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, | |
- worker->s->recv_buffer_size))) { | |
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) | |
- "apr_socket_opt_set(SO_RCVBUF): Failed to set " | |
- "ProxyReceiveBufferSize, using default"); | |
- } | |
+ rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0, | |
+ conn->scpool); | |
+ if (rv != APR_SUCCESS) { | |
+ loglevel = APLOG_ERR; | |
+ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(02453) | |
+ "%s: error creating Unix domain socket for " | |
+ "target %s", | |
+ proxy_function, | |
+ worker->s->hostname); | |
+ break; | |
+ } | |
+ conn->connection = NULL; | |
- rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); | |
- if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { | |
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) | |
- "apr_socket_opt_set(APR_TCP_NODELAY): " | |
- "Failed to set"); | |
- } | |
+ sa.sun_family = AF_UNIX; | |
+ apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path)); | |
- /* Set a timeout for connecting to the backend on the socket */ | |
- if (worker->s->conn_timeout_set) { | |
- apr_socket_timeout_set(newsock, worker->s->conn_timeout); | |
- } | |
- else if (worker->s->timeout_set) { | |
- apr_socket_timeout_set(newsock, worker->s->timeout); | |
- } | |
- else if (conf->timeout_set) { | |
- apr_socket_timeout_set(newsock, conf->timeout); | |
- } | |
- else { | |
- apr_socket_timeout_set(newsock, s->timeout); | |
- } | |
- /* Set a keepalive option */ | |
- if (worker->s->keepalive) { | |
- if ((rv = apr_socket_opt_set(newsock, | |
- APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { | |
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) | |
- "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" | |
- " Keepalive"); | |
- } | |
- } | |
- ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, | |
- "%s: fam %d socket created to connect to %s", | |
- proxy_function, backend_addr->family, worker->s->hostname); | |
- | |
- if (conf->source_address_set) { | |
- local_addr = apr_pmemdup(conn->pool, conf->source_address, | |
- sizeof(apr_sockaddr_t)); | |
- local_addr->pool = conn->pool; | |
- rv = apr_socket_bind(newsock, local_addr); | |
+ rv = socket_connect_un(newsock, &sa); | |
if (rv != APR_SUCCESS) { | |
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) | |
- "%s: failed to bind socket to local address", | |
- proxy_function); | |
+ apr_socket_close(newsock); | |
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454) | |
+ "%s: attempt to connect to Unix domain socket " | |
+ "%s (%s) failed", | |
+ proxy_function, | |
+ conn->uds_path, | |
+ worker->s->hostname); | |
+ break; | |
} | |
} | |
+ else | |
+#endif | |
+ { | |
+ if ((rv = apr_socket_create(&newsock, backend_addr->family, | |
+ SOCK_STREAM, APR_PROTO_TCP, | |
+ conn->scpool)) != APR_SUCCESS) { | |
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; | |
+ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) | |
+ "%s: error creating fam %d socket for " | |
+ "target %s", | |
+ proxy_function, | |
+ backend_addr->family, | |
+ worker->s->hostname); | |
+ /* | |
+ * this could be an IPv6 address from the DNS but the | |
+ * local machine won't give us an IPv6 socket; hopefully the | |
+ * DNS returned an additional address to try | |
+ */ | |
+ backend_addr = backend_addr->next; | |
+ continue; | |
+ } | |
+ conn->connection = NULL; | |
- /* make the connection out of the socket */ | |
- rv = apr_socket_connect(newsock, backend_addr); | |
+ if (worker->s->recv_buffer_size > 0 && | |
+ (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, | |
+ worker->s->recv_buffer_size))) { | |
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) | |
+ "apr_socket_opt_set(SO_RCVBUF): Failed to set " | |
+ "ProxyReceiveBufferSize, using default"); | |
+ } | |
- /* if an error occurred, loop round and try again */ | |
- if (rv != APR_SUCCESS) { | |
- apr_socket_close(newsock); | |
- loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; | |
- ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) | |
- "%s: attempt to connect to %pI (%s) failed", | |
- proxy_function, | |
- backend_addr, | |
- worker->s->hostname); | |
- backend_addr = backend_addr->next; | |
- continue; | |
+ rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); | |
+ if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { | |
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) | |
+ "apr_socket_opt_set(APR_TCP_NODELAY): " | |
+ "Failed to set"); | |
+ } | |
+ | |
+ /* Set a timeout for connecting to the backend on the socket */ | |
+ if (worker->s->conn_timeout_set) { | |
+ apr_socket_timeout_set(newsock, worker->s->conn_timeout); | |
+ } | |
+ else if (worker->s->timeout_set) { | |
+ apr_socket_timeout_set(newsock, worker->s->timeout); | |
+ } | |
+ else if (conf->timeout_set) { | |
+ apr_socket_timeout_set(newsock, conf->timeout); | |
+ } | |
+ else { | |
+ apr_socket_timeout_set(newsock, s->timeout); | |
+ } | |
+ /* Set a keepalive option */ | |
+ if (worker->s->keepalive) { | |
+ if ((rv = apr_socket_opt_set(newsock, | |
+ APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { | |
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) | |
+ "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" | |
+ " Keepalive"); | |
+ } | |
+ } | |
+ ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, | |
+ "%s: fam %d socket created to connect to %s", | |
+ proxy_function, backend_addr->family, worker->s->hostname); | |
+ | |
+ if (conf->source_address_set) { | |
+ local_addr = apr_pmemdup(conn->pool, conf->source_address, | |
+ sizeof(apr_sockaddr_t)); | |
+ local_addr->pool = conn->pool; | |
+ rv = apr_socket_bind(newsock, local_addr); | |
+ if (rv != APR_SUCCESS) { | |
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) | |
+ "%s: failed to bind socket to local address", | |
+ proxy_function); | |
+ } | |
+ } | |
+ | |
+ /* make the connection out of the socket */ | |
+ rv = apr_socket_connect(newsock, backend_addr); | |
+ | |
+ /* if an error occurred, loop round and try again */ | |
+ if (rv != APR_SUCCESS) { | |
+ apr_socket_close(newsock); | |
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; | |
+ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) | |
+ "%s: attempt to connect to %pI (%s) failed", | |
+ proxy_function, | |
+ backend_addr, | |
+ worker->s->hostname); | |
+ backend_addr = backend_addr->next; | |
+ continue; | |
+ } | |
} | |
/* Set a timeout on the socket */ | |
@@ -2498,7 +2760,7 @@ | |
conn->sock = newsock; | |
- if (conn->forward) { | |
+ if (!conn->uds_path && conn->forward) { | |
forward_info *forward = (forward_info *)conn->forward; | |
/* | |
* For HTTP CONNECT we need to prepend CONNECT request before | |
@@ -2779,7 +3041,7 @@ | |
found = 1; | |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02402) | |
"re-grabbing shm[%d] (0x%pp) for worker: %s", i, (void *)shm, | |
- worker->s->name); | |
+ ap_proxy_worker_name(conf->pool, worker)); | |
break; | |
} | |
} | |
@@ -3044,8 +3306,22 @@ | |
* to backend | |
*/ | |
if (do_100_continue) { | |
- apr_table_mergen(r->headers_in, "Expect", "100-Continue"); | |
- r->expecting_100 = 1; | |
+ const char *val; | |
+ | |
+ if (!r->expecting_100) { | |
+ /* Don't forward any "100 Continue" response if the client is | |
+ * not expecting it. | |
+ */ | |
+ apr_table_setn(r->subprocess_env, "proxy-interim-response", | |
+ "Suppress"); | |
+ } | |
+ | |
+ /* Add the Expect header if not already there. */ | |
+ if (((val = apr_table_get(r->headers_in, "Expect")) == NULL) | |
+ || (strcasecmp(val, "100-Continue") != 0 /* fast path */ | |
+ && !ap_find_token(r->pool, val, "100-Continue"))) { | |
+ apr_table_mergen(r->headers_in, "Expect", "100-Continue"); | |
+ } | |
} | |
/* X-Forwarded-*: handling | |
@@ -3190,6 +3466,9 @@ | |
if (transferred != -1) | |
p_conn->worker->s->transferred += transferred; | |
status = ap_pass_brigade(origin->output_filters, bb); | |
+ /* Cleanup the brigade now to avoid buckets lifetime | |
+ * issues in case of error returned below. */ | |
+ apr_brigade_cleanup(bb); | |
if (status != APR_SUCCESS) { | |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01084) | |
"pass request body failed to %pI (%s)", | |
@@ -3209,10 +3488,41 @@ | |
return HTTP_BAD_REQUEST; | |
} | |
} | |
- apr_brigade_cleanup(bb); | |
return OK; | |
} | |
+/* Fill in unknown schemes from apr_uri_port_of_scheme() */ | |
+ | |
+typedef struct proxy_schemes_t { | |
+ const char *name; | |
+ apr_port_t default_port; | |
+} proxy_schemes_t ; | |
+ | |
+static proxy_schemes_t pschemes[] = | |
+{ | |
+ {"fcgi", 8000}, | |
+ {"ajp", AJP13_DEF_PORT}, | |
+ { NULL, 0xFFFF } /* unknown port */ | |
+}; | |
+ | |
+PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme) | |
+{ | |
+ if (scheme) { | |
+ apr_port_t port; | |
+ if ((port = apr_uri_port_of_scheme(scheme)) != 0) { | |
+ return port; | |
+ } else { | |
+ proxy_schemes_t *pscheme; | |
+ for (pscheme = pschemes; pscheme->name != NULL; ++pscheme) { | |
+ if (strcasecmp(scheme, pscheme->name) == 0) { | |
+ return pscheme->default_port; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+ | |
void proxy_util_register_hooks(apr_pool_t *p) | |
{ | |
APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker); | |
--- apache2-2.4.7/include/ap_regex.h 2012-02-12 08:00:36.000000000 +0900 | |
+++ httpd-2.4.10/include/ap_regex.h 2014-01-06 01:14:26.000000000 +0900 | |
@@ -77,6 +77,8 @@ | |
#define AP_REG_NOMEM 0x20 /* nomem in our code */ | |
#define AP_REG_DOTALL 0x40 /* perl's /s flag */ | |
+#define AP_REG_MATCH "MATCH_" /** suggested prefix for ap_regname */ | |
+ | |
/* Error values: */ | |
enum { | |
AP_REG_ASSERT = 1, /** internal error ? */ | |
@@ -149,6 +151,16 @@ | |
AP_DECLARE(apr_size_t) ap_regerror(int errcode, const ap_regex_t *preg, | |
char *errbuf, apr_size_t errbuf_size); | |
+/** | |
+ * Return an array of named regex backreferences | |
+ * @param preg The precompiled regex | |
+ * @param names The array to which the names will be added | |
+ * @param upper If non zero, uppercase the names | |
+ */ | |
+AP_DECLARE(int) ap_regname(const ap_regex_t *preg, | |
+ apr_array_header_t *names, const char *prefix, | |
+ int upper); | |
+ | |
/** Destroy a pre-compiled regex. | |
* @param preg The pre-compiled regex to free. | |
*/ | |
--- apache2-2.4.7/server/util_pcre.c 2012-12-09 22:10:46.000000000 +0900 | |
+++ httpd-2.4.10/server/util_pcre.c 2014-01-06 01:14:26.000000000 +0900 | |
@@ -45,6 +45,7 @@ | |
#include "httpd.h" | |
#include "apr_strings.h" | |
+#include "apr_tables.h" | |
#include "pcre.h" | |
#define APR_WANT_STRFUNC | |
@@ -124,7 +125,7 @@ | |
const char *errorptr; | |
int erroffset; | |
int errcode = 0; | |
- int options = 0; | |
+ int options = PCRE_DUPNAMES; | |
if ((cflags & AP_REG_ICASE) != 0) | |
options |= PCRE_CASELESS; | |
@@ -256,4 +257,43 @@ | |
} | |
} | |
+AP_DECLARE(int) ap_regname(const ap_regex_t *preg, | |
+ apr_array_header_t *names, const char *prefix, | |
+ int upper) | |
+{ | |
+ int namecount; | |
+ int nameentrysize; | |
+ int i; | |
+ char *nametable; | |
+ | |
+ pcre_fullinfo((const pcre *)preg->re_pcre, NULL, | |
+ PCRE_INFO_NAMECOUNT, &namecount); | |
+ pcre_fullinfo((const pcre *)preg->re_pcre, NULL, | |
+ PCRE_INFO_NAMEENTRYSIZE, &nameentrysize); | |
+ pcre_fullinfo((const pcre *)preg->re_pcre, NULL, | |
+ PCRE_INFO_NAMETABLE, &nametable); | |
+ | |
+ for (i = 0; i < namecount; i++) { | |
+ const char *offset = nametable + i * nameentrysize; | |
+ int capture = ((offset[0] << 8) + offset[1]); | |
+ while (names->nelts <= capture) { | |
+ apr_array_push(names); | |
+ } | |
+ if (upper || prefix) { | |
+ char *name = ((char **) names->elts)[capture] = | |
+ prefix ? apr_pstrcat(names->pool, prefix, offset + 2, | |
+ NULL) : | |
+ apr_pstrdup(names->pool, offset + 2); | |
+ if (upper) { | |
+ ap_str_toupper(name); | |
+ } | |
+ } | |
+ else { | |
+ ((const char **)names->elts)[capture] = offset + 2; | |
+ } | |
+ } | |
+ | |
+ return namecount; | |
+} | |
+ | |
/* End of pcreposix.c */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: