summaryrefslogtreecommitdiff
path: root/modules/proxy
diff options
context:
space:
mode:
authorArno Töll <arno@debian.org>2014-07-20 06:23:00 -1100
committerArno Töll <arno@debian.org>2014-07-20 06:23:00 -1100
commitcb35beef2a938b80c9e4b5d6a408eca437aa74db (patch)
tree87ae6e0d2b3a8ce318fe8ab559494808a451035e /modules/proxy
parent2a463b3cd73c32ee9dcd508248d0194923f435f4 (diff)
downloadapache2-cb35beef2a938b80c9e4b5d6a408eca437aa74db.tar.gz
Imported Upstream version 2.4.10
Diffstat (limited to 'modules/proxy')
-rw-r--r--modules/proxy/ajp_header.c20
-rw-r--r--modules/proxy/ajp_header.h5
-rw-r--r--modules/proxy/mod_proxy.c40
-rw-r--r--modules/proxy/mod_proxy.h10
-rw-r--r--modules/proxy/mod_proxy_balancer.c2
-rw-r--r--modules/proxy/mod_proxy_fcgi.c158
-rw-r--r--modules/proxy/mod_proxy_http.c26
-rw-r--r--modules/proxy/mod_proxy_scgi.c13
-rw-r--r--modules/proxy/mod_proxy_wstunnel.c51
-rw-r--r--modules/proxy/proxy_util.c306
-rw-r--r--modules/proxy/scgi.h36
11 files changed, 439 insertions, 228 deletions
diff --git a/modules/proxy/ajp_header.c b/modules/proxy/ajp_header.c
index 074f0a8d..8f9a2fcd 100644
--- a/modules/proxy/ajp_header.c
+++ b/modules/proxy/ajp_header.c
@@ -435,6 +435,26 @@ static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
return AJP_EOVERFLOW;
}
}
+ /* Forward the local ip address information, which was forgotten
+ * from the builtin data of the AJP 13 protocol.
+ * Since the servlet spec allows to retrieve it via getLocalAddr(),
+ * we provide the address to the Tomcat connector as a request
+ * attribute. Modern Tomcat versions know how to retrieve
+ * the local address from this attribute.
+ */
+ {
+ const char *key = SC_A_REQ_LOCAL_ADDR;
+ char *val = r->connection->local_ip;
+ if (ajp_msg_append_uint8(msg, SC_A_REQ_ATTRIBUTE) ||
+ ajp_msg_append_string(msg, key) ||
+ ajp_msg_append_string(msg, val)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02646)
+ "ajp_marshal_into_msgb: "
+ "Error appending attribute %s=%s",
+ key, val);
+ return AJP_EOVERFLOW;
+ }
+ }
/* Use the environment vars prefixed with AJP_
* and pass it to the header striping that prefix.
*/
diff --git a/modules/proxy/ajp_header.h b/modules/proxy/ajp_header.h
index 22d89080..0f5fdaa8 100644
--- a/modules/proxy/ajp_header.h
+++ b/modules/proxy/ajp_header.h
@@ -51,6 +51,11 @@
* to contain the forwarded remote port.
*/
#define SC_A_REQ_REMOTE_PORT ("AJP_REMOTE_PORT")
+/*
+ * The following request attribute is recognized by Tomcat
+ * to contain the forwarded local ip address.
+ */
+#define SC_A_REQ_LOCAL_ADDR ("AJP_LOCAL_ADDR")
/*
* Request methods, coded as numbers instead of strings.
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
index 627a0496..b331a6c5 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -927,8 +927,25 @@ static int proxy_handler(request_rec *r)
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"))) {
@@ -1584,13 +1601,26 @@ static const char *
/* 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,
@@ -2618,6 +2648,8 @@ static void child_init(apr_pool_t *p, server_rec *s)
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;
@@ -2633,6 +2665,8 @@ static void child_init(apr_pool_t *p, server_rec *s)
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 */
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
index eb0106d6..4ead22e7 100644
--- a/modules/proxy/mod_proxy.h
+++ b/modules/proxy/mod_proxy.h
@@ -254,6 +254,7 @@ typedef struct {
* 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 {
@@ -274,6 +275,7 @@ struct proxy_conn_pool {
#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
@@ -285,6 +287,7 @@ struct proxy_conn_pool {
#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'
@@ -305,6 +308,8 @@ PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR )
#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
@@ -792,8 +797,9 @@ PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
* @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,
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
index c927d3bf..acfd3861 100644
--- a/modules/proxy/mod_proxy_balancer.c
+++ b/modules/proxy/mod_proxy_balancer.c
@@ -1602,7 +1602,7 @@ static int balancer_handler(request_rec *r)
ap_rputs("<h3>Edit balancer settings for ", r);
ap_rvputs(r, bsel->s->name, "</h3>\n", NULL);
ap_rputs("<form method='POST' enctype='application/x-www-form-urlencoded' action='", r);
- ap_rvputs(r, action, "'>\n", NULL);
+ ap_rvputs(r, ap_escape_uri(r->pool, action), "'>\n", NULL);
ap_rputs("<dl>\n<table>\n", r);
provs = ap_list_provider_names(r->pool, PROXY_LBMETHOD, "0");
if (provs) {
diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c
index 4f407951..e2fb59cd 100644
--- a/modules/proxy/mod_proxy_fcgi.c
+++ b/modules/proxy/mod_proxy_fcgi.c
@@ -90,26 +90,13 @@ static int proxy_fcgi_canon(request_rec *r, char *url)
static apr_status_t send_data(proxy_conn_rec *conn,
struct iovec *vec,
int nvec,
- apr_size_t *len,
- int blocking)
+ apr_size_t *len)
{
- apr_status_t rv = APR_SUCCESS, arv;
+ apr_status_t rv = APR_SUCCESS;
apr_size_t written = 0, to_write = 0;
int i, offset;
- apr_interval_time_t old_timeout;
apr_socket_t *s = conn->sock;
- if (!blocking) {
- arv = apr_socket_timeout_get(s, &old_timeout);
- if (arv != APR_SUCCESS) {
- return arv;
- }
- arv = apr_socket_timeout_set(s, 0);
- if (arv != APR_SUCCESS) {
- return arv;
- }
- }
-
for (i = 0; i < nvec; i++) {
to_write += vec[i].iov_len;
}
@@ -118,7 +105,7 @@ static apr_status_t send_data(proxy_conn_rec *conn,
while (to_write) {
apr_size_t n = 0;
rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
- if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) {
+ if (rv != APR_SUCCESS) {
break;
}
if (n > 0) {
@@ -141,12 +128,6 @@ static apr_status_t send_data(proxy_conn_rec *conn,
conn->worker->s->transferred += written;
*len = written;
- if (!blocking) {
- arv = apr_socket_timeout_set(s, old_timeout);
- if ((arv != APR_SUCCESS) && (rv == APR_SUCCESS)) {
- return arv;
- }
- }
return rv;
}
@@ -207,7 +188,7 @@ static apr_status_t send_begin_request(proxy_conn_rec *conn,
vec[1].iov_base = (void *)abrb;
vec[1].iov_len = sizeof(abrb);
- return send_data(conn, vec, 2, &len, 1);
+ return send_data(conn, vec, 2, &len);
}
static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r,
@@ -294,7 +275,7 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r,
vec[1].iov_base = body;
vec[1].iov_len = required_len;
- rv = send_data(conn, vec, 2, &len, 1);
+ rv = send_data(conn, vec, 2, &len);
apr_pool_clear(temp_pool);
if (rv) {
@@ -309,7 +290,7 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r,
vec[0].iov_base = (void *)farray;
vec[0].iov_len = sizeof(farray);
- return send_data(conn, vec, 1, &len, 1);
+ return send_data(conn, vec, 1, &len);
}
enum {
@@ -383,7 +364,8 @@ static int handle_headers(request_rec *r,
static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
request_rec *r, apr_pool_t *setaside_pool,
- apr_uint16_t request_id)
+ apr_uint16_t request_id,
+ const char **err)
{
apr_bucket_brigade *ib, *ob;
int seen_end_of_headers = 0, done = 0;
@@ -395,7 +377,16 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
unsigned char farray[AP_FCGI_HEADER_LEN];
apr_pollfd_t pfd;
int header_state = HDR_STATE_READING_HEADERS;
-
+ char stack_iobuf[AP_IOBUFSIZE];
+ apr_size_t iobuf_size = AP_IOBUFSIZE;
+ char *iobuf = stack_iobuf;
+
+ *err = NULL;
+ if (conn->worker->s->io_buffer_size_set) {
+ iobuf_size = conn->worker->s->io_buffer_size;
+ iobuf = apr_palloc(r->pool, iobuf_size);
+ }
+
pfd.desc_type = APR_POLL_SOCKET;
pfd.desc.s = conn->sock;
pfd.p = r->pool;
@@ -418,19 +409,20 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
if (APR_STATUS_IS_EINTR(rv)) {
continue;
}
+ *err = "polling";
break;
}
if (pfd.rtnevents & APR_POLLOUT) {
- char writebuf[AP_IOBUFSIZE];
- apr_size_t writebuflen;
+ apr_size_t to_send, writebuflen;
int last_stdin = 0;
- int nvec = 0;
+ char *iobuf_cursor;
rv = ap_get_brigade(r->input_filters, ib,
AP_MODE_READBYTES, APR_BLOCK_READ,
- sizeof(writebuf));
+ iobuf_size);
if (rv != APR_SUCCESS) {
+ *err = "reading input brigade";
break;
}
@@ -438,30 +430,48 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
last_stdin = 1;
}
- writebuflen = sizeof(writebuf);
+ writebuflen = iobuf_size;
- rv = apr_brigade_flatten(ib, writebuf, &writebuflen);
+ rv = apr_brigade_flatten(ib, iobuf, &writebuflen);
apr_brigade_cleanup(ib);
if (rv != APR_SUCCESS) {
+ *err = "flattening brigade";
break;
}
- ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id,
- (apr_uint16_t) writebuflen, 0);
- ap_fcgi_header_to_array(&header, farray);
+ to_send = writebuflen;
+ iobuf_cursor = iobuf;
+ while (to_send > 0) {
+ int nvec = 0;
+ apr_size_t write_this_time;
+
+ write_this_time =
+ to_send < AP_FCGI_MAX_CONTENT_LEN ? to_send : AP_FCGI_MAX_CONTENT_LEN;
+
+ ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id,
+ (apr_uint16_t)write_this_time, 0);
+ ap_fcgi_header_to_array(&header, farray);
- vec[nvec].iov_base = (void *)farray;
- vec[nvec].iov_len = sizeof(farray);
- ++nvec;
- if (writebuflen) {
- vec[nvec].iov_base = writebuf;
- vec[nvec].iov_len = writebuflen;
+ vec[nvec].iov_base = (void *)farray;
+ vec[nvec].iov_len = sizeof(farray);
++nvec;
- }
+ if (writebuflen) {
+ vec[nvec].iov_base = iobuf_cursor;
+ vec[nvec].iov_len = write_this_time;
+ ++nvec;
+ }
+
+ rv = send_data(conn, vec, nvec, &len);
+ if (rv != APR_SUCCESS) {
+ *err = "sending stdin";
+ break;
+ }
- rv = send_data(conn, vec, nvec, &len, 0);
+ to_send -= write_this_time;
+ iobuf_cursor += write_this_time;
+ }
if (rv != APR_SUCCESS) {
break;
}
@@ -469,33 +479,29 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
if (last_stdin) {
pfd.reqevents = APR_POLLIN; /* Done with input data */
- if (writebuflen) { /* empty AP_FCGI_STDIN not already sent? */
- ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id,
- 0, 0);
- ap_fcgi_header_to_array(&header, farray);
+ /* signal EOF (empty FCGI_STDIN) */
+ ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id,
+ 0, 0);
+ ap_fcgi_header_to_array(&header, farray);
- vec[0].iov_base = (void *)farray;
- vec[0].iov_len = sizeof(farray);
+ vec[0].iov_base = (void *)farray;
+ vec[0].iov_len = sizeof(farray);
- rv = send_data(conn, vec, 1, &len, 1);
+ rv = send_data(conn, vec, 1, &len);
+ if (rv != APR_SUCCESS) {
+ *err = "sending empty stdin";
+ break;
}
}
}
if (pfd.rtnevents & APR_POLLIN) {
- /* readbuf has one byte on the end that is always 0, so it's
- * able to work with a strstr when we search for the end of
- * the headers, even if we fill the entire length in the recv. */
- char readbuf[AP_IOBUFSIZE + 1];
apr_size_t readbuflen;
apr_uint16_t clen, rid;
apr_bucket *b;
unsigned char plen;
unsigned char type, version;
- memset(readbuf, 0, sizeof(readbuf));
- memset(farray, 0, sizeof(farray));
-
/* First, we grab the header... */
rv = get_data_full(conn, (char *) farray, AP_FCGI_HEADER_LEN);
if (rv != APR_SUCCESS) {
@@ -528,8 +534,8 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
}
recv_again:
- if (clen > sizeof(readbuf) - 1) {
- readbuflen = sizeof(readbuf) - 1;
+ if (clen > iobuf_size) {
+ readbuflen = iobuf_size;
} else {
readbuflen = clen;
}
@@ -538,24 +544,24 @@ recv_again:
* recv call, this will eventually change when we move to real
* nonblocking recv calls. */
if (readbuflen != 0) {
- rv = get_data(conn, readbuf, &readbuflen);
+ rv = get_data(conn, iobuf, &readbuflen);
if (rv != APR_SUCCESS) {
+ *err = "reading response body";
break;
}
- readbuf[readbuflen] = 0;
}
switch (type) {
case AP_FCGI_STDOUT:
if (clen != 0) {
- b = apr_bucket_transient_create(readbuf,
+ b = apr_bucket_transient_create(iobuf,
readbuflen,
c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ob, b);
if (! seen_end_of_headers) {
- int st = handle_headers(r, &header_state, readbuf);
+ int st = handle_headers(r, &header_state, iobuf);
if (st == 1) {
int status;
@@ -591,9 +597,14 @@ recv_again:
r->status = HTTP_OK;
}
- if (script_error_status == HTTP_OK) {
+ if (script_error_status == HTTP_OK
+ && !APR_BRIGADE_EMPTY(ob)) {
+ /* Send the part of the body that we read while
+ * reading the headers.
+ */
rv = ap_pass_brigade(r->output_filters, ob);
if (rv != APR_SUCCESS) {
+ *err = "passing brigade to output filters";
break;
}
}
@@ -618,6 +629,7 @@ recv_again:
if (script_error_status == HTTP_OK) {
rv = ap_pass_brigade(r->output_filters, ob);
if (rv != APR_SUCCESS) {
+ *err = "passing brigade to output filters";
break;
}
}
@@ -638,6 +650,7 @@ recv_again:
APR_BRIGADE_INSERT_TAIL(ob, b);
rv = ap_pass_brigade(r->output_filters, ob);
if (rv != APR_SUCCESS) {
+ *err = "passing brigade to output filters";
break;
}
}
@@ -650,7 +663,7 @@ recv_again:
/* TODO: Should probably clean up this logging a bit... */
if (clen) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01071)
- "Got error '%s'", readbuf);
+ "Got error '%s'", iobuf);
}
if (clen > readbuflen) {
@@ -670,7 +683,7 @@ recv_again:
}
if (plen) {
- rv = get_data_full(conn, readbuf, plen);
+ rv = get_data_full(conn, iobuf, plen);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
APLOGNO(02537) "Error occurred reading padding");
@@ -708,6 +721,7 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
apr_uint16_t request_id = 1;
apr_status_t rv;
apr_pool_t *temp_pool;
+ const char *err;
/* Step 1: Send AP_FCGI_BEGIN_REQUEST */
rv = send_begin_request(conn, request_id);
@@ -730,10 +744,14 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r,
}
/* Step 3: Read records from the back end server and handle them. */
- rv = dispatch(conn, conf, r, temp_pool, request_id);
+ rv = dispatch(conn, conf, r, temp_pool, request_id, &err);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01075)
- "Error dispatching request to %s:", server_portstr);
+ "Error dispatching request to %s: %s%s%s",
+ server_portstr,
+ err ? "(" : "",
+ err ? err : "",
+ err ? ")" : "");
conn->close = 1;
return HTTP_SERVICE_UNAVAILABLE;
}
@@ -754,7 +772,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
int status;
char server_portstr[32];
conn_rec *origin = NULL;
- proxy_conn_rec *backend;
+ proxy_conn_rec *backend = NULL;
proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
&proxy_module);
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index 3aec4cfe..141452bf 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -1306,7 +1306,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
"error reading status line from remote "
"server %s:%d", backend->hostname, backend->port);
if (APR_STATUS_IS_TIMEUP(rc)) {
- apr_table_set(r->notes, "proxy_timedout", "1");
+ apr_table_setn(r->notes, "proxy_timedout", "1");
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01103) "read timeout");
if (do_100_continue) {
return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, "Timeout on 100-Continue");
@@ -1745,7 +1745,6 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
#endif
/* sanity check */
if (APR_BRIGADE_EMPTY(bb)) {
- apr_brigade_cleanup(bb);
break;
}
@@ -1977,25 +1976,10 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
* requested, such that mod_ssl can check if it is requested to do
* so.
*/
- if (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 != 0) && (r->hostname != NULL)) {
- ssl_hostname = r->hostname;
- }
- else {
- ssl_hostname = uri->hostname;
- }
-
- apr_table_set(backend->connection->notes, "proxy-request-hostname",
- ssl_hostname);
+ if (backend->ssl_hostname) {
+ apr_table_setn(backend->connection->notes,
+ "proxy-request-hostname",
+ backend->ssl_hostname);
}
}
diff --git a/modules/proxy/mod_proxy_scgi.c b/modules/proxy/mod_proxy_scgi.c
index f77a986e..7fb2b873 100644
--- a/modules/proxy/mod_proxy_scgi.c
+++ b/modules/proxy/mod_proxy_scgi.c
@@ -37,13 +37,13 @@
#include "util_script.h"
#include "mod_proxy.h"
+#include "scgi.h"
#define SCHEME "scgi"
#define PROXY_FUNCTION "SCGI"
#define SCGI_MAGIC "SCGI"
#define SCGI_PROTOCOL_VERSION "1"
-#define SCGI_DEFAULT_PORT (4000)
/* just protect from typos */
#define CONTENT_LENGTH "CONTENT_LENGTH"
@@ -176,13 +176,15 @@ static int scgi_canon(request_rec *r, char *url)
{
char *host, sport[sizeof(":65535")];
const char *err, *path;
- apr_port_t port = SCGI_DEFAULT_PORT;
+ apr_port_t port, def_port;
if (strncasecmp(url, SCHEME "://", sizeof(SCHEME) + 2)) {
return DECLINED;
}
url += sizeof(SCHEME); /* Keep slashes */
+ port = def_port = SCGI_DEF_PORT;
+
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00857)
@@ -190,7 +192,12 @@ static int scgi_canon(request_rec *r, char *url)
return HTTP_BAD_REQUEST;
}
- apr_snprintf(sport, sizeof(sport), ":%u", port);
+ if (port != def_port) {
+ apr_snprintf(sport, sizeof(sport), ":%u", port);
+ }
+ else {
+ sport[0] = '\0';
+ }
if (ap_strchr(host, ':')) { /* if literal IPv6 address */
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
index d17eaff6..a2172fe2 100644
--- a/modules/proxy/mod_proxy_wstunnel.c
+++ b/modules/proxy/mod_proxy_wstunnel.c
@@ -103,10 +103,12 @@ static int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES,
APR_NONBLOCK_READ, AP_IOBUFSIZE);
if (rv == APR_SUCCESS) {
- if (c_o->aborted)
+ if (c_o->aborted) {
return APR_EPIPE;
- if (APR_BRIGADE_EMPTY(bb))
+ }
+ if (APR_BRIGADE_EMPTY(bb)) {
break;
+ }
#ifdef DEBUGGING
len = -1;
apr_brigade_length(bb, 0, &len);
@@ -130,9 +132,12 @@ static int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
}
} while (rv == APR_SUCCESS);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r, "wstunnel_transfer complete");
+
if (APR_STATUS_IS_EAGAIN(rv)) {
rv = APR_SUCCESS;
}
+
return rv;
}
@@ -178,7 +183,6 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
conn_rec *c = r->connection;
apr_socket_t *sock = conn->sock;
conn_rec *backconn = conn->connection;
- int client_error = 0;
char *buf;
apr_bucket_brigade *header_brigade;
apr_bucket *e;
@@ -224,7 +228,7 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
pollfd.p = p;
pollfd.desc_type = APR_POLL_SOCKET;
- pollfd.reqevents = APR_POLLIN;
+ pollfd.reqevents = APR_POLLIN | APR_POLLHUP;
pollfd.desc.s = sock;
pollfd.client_data = NULL;
apr_pollset_add(pollset, &pollfd);
@@ -232,13 +236,16 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
pollfd.desc.s = client_socket;
apr_pollset_add(pollset, &pollfd);
+ remove_reqtimeout(c->input_filters);
r->output_filters = c->output_filters;
r->proto_output_filters = c->output_filters;
r->input_filters = c->input_filters;
r->proto_input_filters = c->input_filters;
- remove_reqtimeout(r->input_filters);
+ /* This handler should take care of the entire connection; make it so that
+ * nothing else is attempted on the connection after returning. */
+ c->keepalive = AP_CONN_CLOSE;
while (1) { /* Infinite loop until error (one side closes the connection) */
if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled))
@@ -257,38 +264,34 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
if (cur->desc.s == sock) {
pollevent = cur->rtnevents;
- if (pollevent & APR_POLLIN) {
+ if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02446)
"sock was readable");
rv = proxy_wstunnel_transfer(r, backconn, c, bb, "sock");
- }
- else if ((pollevent & APR_POLLERR)
- || (pollevent & APR_POLLHUP)) {
- rv = APR_EPIPE;
- ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447)
- "err/hup on backconn");
+ }
+ else if (pollevent & APR_POLLERR) {
+ rv = APR_EPIPE;
+ ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447)
+ "error on backconn");
}
else {
rv = APR_EGENERAL;
ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02605)
"unknown event on backconn %d", pollevent);
}
- if (rv != APR_SUCCESS)
- client_error = 1;
}
else if (cur->desc.s == client_socket) {
pollevent = cur->rtnevents;
- if (pollevent & APR_POLLIN) {
+ if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02448)
"client was readable");
rv = proxy_wstunnel_transfer(r, c, backconn, bb, "client");
}
- else if ((pollevent & APR_POLLERR)
- || (pollevent & APR_POLLHUP)) {
+ else if (pollevent & APR_POLLERR) {
rv = APR_EPIPE;
c->aborted = 1;
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607)
- "err/hup on client conn");
+ "error on client conn");
}
else {
rv = APR_EGENERAL;
@@ -311,9 +314,6 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
"finished with poll() - cleaning up");
- if (client_error) {
- return HTTP_INTERNAL_SERVER_ERROR;
- }
return OK;
}
@@ -332,9 +332,11 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker,
conn_rec *c = r->connection;
apr_pool_t *p = r->pool;
apr_uri_t *uri;
+ int is_ssl = 0;
if (strncasecmp(url, "wss:", 4) == 0) {
scheme = "WSS";
+ is_ssl = 1;
}
else if (strncasecmp(url, "ws:", 3) == 0) {
scheme = "WS";
@@ -358,7 +360,7 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker,
return status;
}
- backend->is_ssl = 0;
+ backend->is_ssl = is_ssl;
backend->close = 0;
retry = 0;
@@ -386,7 +388,10 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker,
if ((status = ap_proxy_connection_create(scheme, backend,
c, r->server)) != OK)
break;
- }
+ }
+
+ backend->close = 1; /* must be after ap_proxy_determine_connection */
+
/* Step Three: Process the Request */
status = ap_proxy_wstunnel_request(p, r, backend, worker, conf, uri, locurl,
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index d05f0cdc..bc840499 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -22,6 +22,7 @@
#include "apr_hash.h"
#include "proxy_util.h"
#include "ajp.h"
+#include "scgi.h"
#if APR_HAVE_UNISTD_H
#include <unistd.h> /* for getpid() */
@@ -1123,6 +1124,9 @@ PROXY_DECLARE(char *) ap_proxy_update_balancer(apr_pool_t *p,
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);
}
@@ -1402,6 +1406,7 @@ static void socket_cleanup(proxy_conn_rec *conn)
{
conn->sock = NULL;
conn->connection = NULL;
+ conn->ssl_hostname = NULL;
apr_pool_clear(conn->scpool);
}
@@ -1927,6 +1932,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
}
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;
@@ -1938,6 +1945,36 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
* 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 = '|';
+ }
+ }
}
}
}
@@ -2097,29 +2134,6 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
(*conn)->close = 0;
(*conn)->inreslist = 0;
- if (*worker->s->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, worker->s->uds_path);
- }
- if ((*conn)->uds_path) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02545)
- "%s: has determined UDS as %s",
- proxy_function, (*conn)->uds_path);
- }
- else {
- /* should never happen */
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02546)
- "%s: cannot determine UDS (%s)",
- proxy_function, worker->s->uds_path);
-
- }
- }
- else {
- (*conn)->uds_path = NULL;
- }
-
-
return OK;
}
@@ -2150,6 +2164,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
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
@@ -2190,85 +2205,117 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
* 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 || *worker->s->uds_path) {
- 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);
}
- else {
- conn->hostname = apr_pstrdup(conn->pool, uri->hostname);
- conn->port = uri->port;
+ 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);
}
- socket_cleanup(conn);
- if (!(*worker->s->uds_path) &&
- (!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);
+ else {
+ /* 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->uds_path) && 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 */
@@ -2284,22 +2331,56 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
}
/* 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;
@@ -3051,7 +3132,7 @@ static int find_conn_headers(void *data, const char *key, const char *val)
const char *name;
do {
- while (*val == ',') {
+ while (*val == ',' || *val == ';') {
val++;
}
name = ap_get_token(x->pool, &val, 0);
@@ -3226,8 +3307,22 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
* 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
@@ -3408,6 +3503,7 @@ static proxy_schemes_t pschemes[] =
{
{"fcgi", 8000},
{"ajp", AJP13_DEF_PORT},
+ {"scgi", SCGI_DEF_PORT},
{ NULL, 0xFFFF } /* unknown port */
};
diff --git a/modules/proxy/scgi.h b/modules/proxy/scgi.h
new file mode 100644
index 00000000..a2e5e965
--- /dev/null
+++ b/modules/proxy/scgi.h
@@ -0,0 +1,36 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file scgi.h
+ * @brief Shared SCGI-related definitions
+ *
+ * @ingroup APACHE_INTERNAL
+ * @{
+ */
+
+#ifndef SCGI_H
+#define SCGI_H
+
+/* This is not defined by the protocol. It is a convention
+ * of mod_proxy_scgi, and mod_proxy utility routines must
+ * use the same value as mod_proxy_scgi.
+ */
+#define SCGI_DEF_PORT 4000
+
+/** @} */
+
+#endif /* SCGI_H */