Skip to content

Instantly share code, notes, and snippets.

@ymmt2005
Created October 24, 2014 06:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ymmt2005/c6b3baafae20ef35307f to your computer and use it in GitHub Desktop.
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
--- 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 */
@ymmt2005
Copy link
Author

Usage:

$ apt-get source apache2
$ sudo apt-get -y install build-essential fakeroot
$ sudo apt-get -y build-dep apache2
$ cd apache2-2.4.7
$ patch -p1 < mod_proxy.patch
$ dpkg-buildpackage -rfakeroot -uc -b -j4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment