summaryrefslogtreecommitdiff
path: root/modules/proxy/proxy_util.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2016-12-05 22:19:16 +0300
committerIgor Pashev <pashev.igor@gmail.com>2016-12-05 22:19:16 +0300
commit89e9332e2bacdba1cf44aabfcfc082c0de62871c (patch)
tree156ad5e5b00e6966642b2d600dafa5f0cc1d43ac /modules/proxy/proxy_util.c
parentf51547f19e44fc1f511837443cb92ba28c189b9c (diff)
parentadb6f181257af28ee67af15fc49d2699a0080d4c (diff)
downloadapache2-89e9332e2bacdba1cf44aabfcfc082c0de62871c.tar.gz
Merge branch 'master' of git://anonscm.debian.org/pkg-apache/apache2
Diffstat (limited to 'modules/proxy/proxy_util.c')
-rw-r--r--modules/proxy/proxy_util.c790
1 files changed, 572 insertions, 218 deletions
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index d05f0cdc..0d2c8563 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() */
@@ -53,24 +54,6 @@ typedef struct {
const char *proxy_auth; /* Proxy authorization */
} forward_info;
-/* Keep synced with mod_proxy.h! */
-static struct wstat {
- unsigned int bit;
- char flag;
- const char *name;
-} wstat_tbl[] = {
- {PROXY_WORKER_INITIALIZED, PROXY_WORKER_INITIALIZED_FLAG, "Init "},
- {PROXY_WORKER_IGNORE_ERRORS, PROXY_WORKER_IGNORE_ERRORS_FLAG, "Ign "},
- {PROXY_WORKER_DRAIN, PROXY_WORKER_DRAIN_FLAG, "Drn "},
- {PROXY_WORKER_IN_SHUTDOWN, PROXY_WORKER_IN_SHUTDOWN_FLAG, "Shut "},
- {PROXY_WORKER_DISABLED, PROXY_WORKER_DISABLED_FLAG, "Dis "},
- {PROXY_WORKER_STOPPED, PROXY_WORKER_STOPPED_FLAG, "Stop "},
- {PROXY_WORKER_IN_ERROR, PROXY_WORKER_IN_ERROR_FLAG, "Err "},
- {PROXY_WORKER_HOT_STANDBY, PROXY_WORKER_HOT_STANDBY_FLAG, "Stby "},
- {PROXY_WORKER_FREE, PROXY_WORKER_FREE_FLAG, "Free "},
- {0x0, '\0', NULL}
-};
-
/* Global balancer counter */
int PROXY_DECLARE_DATA proxy_lb_workers = 0;
static int lb_workers_limit = 0;
@@ -652,7 +635,7 @@ PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t
#if 0
if (addr[i] == ':') {
- ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(03234)
"@@@@ handle optional port in proxy_is_domainname()");
/* @@@@ handle optional port */
}
@@ -939,7 +922,7 @@ PROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r,
part = url;
}
}
- if (l1 >= l2 && strncasecmp(real, part, l2) == 0) {
+ if (l2 > 0 && l1 >= l2 && strncasecmp(real, part, l2) == 0) {
u = apr_pstrcat(r->pool, ent[i].fake, &part[l2], NULL);
return ap_is_url(u) ? u : ap_construct_url(r->pool, u, r);
}
@@ -1123,6 +1106,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);
}
@@ -1155,7 +1141,7 @@ PROXY_DECLARE(char *) ap_proxy_define_balancer(apr_pool_t *p,
c = strchr(uri, ':');
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
- return "Bad syntax for a balancer name";
+ return apr_psprintf(p, "Bad syntax for a balancer name (%s)", uri);
/* remove path from uri */
if ((q = strchr(c + 3, '/')))
*q = '\0';
@@ -1316,6 +1302,14 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balance
* CONNECTION related...
*/
+static void socket_cleanup(proxy_conn_rec *conn)
+{
+ conn->sock = NULL;
+ conn->connection = NULL;
+ conn->ssl_hostname = NULL;
+ apr_pool_clear(conn->scpool);
+}
+
static apr_status_t conn_pool_cleanup(void *theworker)
{
proxy_worker *worker = (proxy_worker *)theworker;
@@ -1347,6 +1341,13 @@ static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
worker->cp = cp;
}
+PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn)
+{
+ proxy_worker *worker = conn->worker;
+
+ return ! (conn->close || !worker->s->is_address_reusable || worker->s->disablereuse);
+}
+
static apr_status_t connection_cleanup(void *theconn)
{
proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
@@ -1356,7 +1357,7 @@ static apr_status_t connection_cleanup(void *theconn)
* If the connection pool is NULL the worker
* cleanup has been run. Just return.
*/
- if (!worker->cp) {
+ if (!worker->cp->pool) {
return APR_SUCCESS;
}
@@ -1375,7 +1376,7 @@ static apr_status_t connection_cleanup(void *theconn)
}
/* determine if the connection need to be closed */
- if (conn->close || !worker->s->is_address_reusable || worker->s->disablereuse) {
+ if (!worker->s->is_address_reusable || worker->s->disablereuse) {
apr_pool_t *p = conn->pool;
apr_pool_clear(p);
conn = apr_pcalloc(p, sizeof(proxy_conn_rec));
@@ -1384,6 +1385,12 @@ static apr_status_t connection_cleanup(void *theconn)
apr_pool_create(&(conn->scpool), p);
apr_pool_tag(conn->scpool, "proxy_conn_scpool");
}
+ else if (conn->close
+ || (conn->connection
+ && conn->connection->keepalive == AP_CONN_CLOSE)) {
+ socket_cleanup(conn);
+ conn->close = 0;
+ }
if (worker->s->hmax && worker->cp->res) {
conn->inreslist = 1;
@@ -1398,13 +1405,6 @@ static apr_status_t connection_cleanup(void *theconn)
return APR_SUCCESS;
}
-static void socket_cleanup(proxy_conn_rec *conn)
-{
- conn->sock = NULL;
- conn->connection = NULL;
- apr_pool_clear(conn->scpool);
-}
-
PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn,
request_rec *r)
{
@@ -1480,10 +1480,11 @@ static apr_status_t connection_constructor(void **resource, void *params,
static apr_status_t connection_destructor(void *resource, void *params,
apr_pool_t *pool)
{
- proxy_conn_rec *conn = (proxy_conn_rec *)resource;
+ proxy_worker *worker = params;
/* Destroy the pool only if not called from reslist_destroy */
- if (conn->worker->cp->pool) {
+ if (worker->cp->pool) {
+ proxy_conn_rec *conn = resource;
apr_pool_destroy(conn->pool);
}
@@ -1523,6 +1524,8 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
return NULL;
}
+ url = ap_proxy_de_socketfy(p, url);
+
c = ap_strchr_c(url, ':');
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
return NULL;
@@ -1678,9 +1681,14 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
memset(wshared, 0, sizeof(proxy_worker_shared));
+ wshared->port = (uri.port ? uri.port : ap_proxy_port_of_scheme(uri.scheme));
+ if (uri.port && uri.port == ap_proxy_port_of_scheme(uri.scheme)) {
+ uri.port = 0;
+ }
ptr = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD);
if (PROXY_STRNCPY(wshared->name, ptr) != APR_SUCCESS) {
- return apr_psprintf(p, "worker name (%s) too long", ptr);
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02808)
+ "Alert! worker name (%s) too long; truncated to: %s", ptr, wshared->name);
}
if (PROXY_STRNCPY(wshared->scheme, uri.scheme) != APR_SUCCESS) {
return apr_psprintf(p, "worker scheme (%s) too long", uri.scheme);
@@ -1688,11 +1696,13 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
if (PROXY_STRNCPY(wshared->hostname, uri.hostname) != APR_SUCCESS) {
return apr_psprintf(p, "worker hostname (%s) too long", uri.hostname);
}
- wshared->port = uri.port;
wshared->flush_packets = flush_off;
wshared->flush_wait = PROXY_FLUSH_WAIT;
wshared->is_address_reusable = 1;
wshared->lbfactor = 1;
+ wshared->passes = 1;
+ wshared->fails = 1;
+ wshared->interval = apr_time_from_sec(HCHECK_WATHCHDOG_DEFAULT_INTERVAL);
wshared->smax = -1;
wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT);
wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV);
@@ -1706,6 +1716,9 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
else {
*wshared->uds_path = '\0';
}
+ if (!balancer) {
+ wshared->status |= PROXY_WORKER_IGNORE_ERRORS;
+ }
(*worker)->hash = wshared->hash;
(*worker)->context = NULL;
@@ -1872,7 +1885,14 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke
server_rec *s)
{
if (worker->s->status & PROXY_WORKER_IN_ERROR) {
- if (apr_time_now() > worker->s->error_time + worker->s->retry) {
+ if (PROXY_WORKER_IS(worker, PROXY_WORKER_STOPPED)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(3305)
+ "%s: Won't retry worker (%s): stopped",
+ proxy_function, worker->s->hostname);
+ return DECLINED;
+ }
+ if ((worker->s->status & PROXY_WORKER_IGNORE_ERRORS)
+ || apr_time_now() > worker->s->error_time + worker->s->retry) {
++worker->s->retries;
worker->s->status &= ~PROXY_WORKER_IN_ERROR;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00932)
@@ -1892,6 +1912,40 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke
}
}
+/*
+ * In the case of the reverse proxy, we need to see if we
+ * were passed a UDS url (eg: from mod_proxy) and adjust uds_path
+ * as required.
+ */
+static void fix_uds_filename(request_rec *r, char **url)
+{
+ char *ptr, *ptr2;
+ if (!r || !r->filename) return;
+
+ if (!strncmp(r->filename, "proxy:", 6) &&
+ (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 = '|';
+ }
+ }
+}
+
PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
proxy_balancer **balancer,
request_rec *r,
@@ -1906,8 +1960,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
"%s: found worker %s for %s",
(*worker)->s->scheme, (*worker)->s->name, *url);
-
*balancer = NULL;
+ fix_uds_filename(r, url);
access_status = OK;
}
else if (r->proxyreq == PROXYREQ_PROXY) {
@@ -1928,7 +1982,7 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
else if (r->proxyreq == PROXYREQ_REVERSE) {
if (conf->reverse) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
- "*: found reverse proxy worker for %s", *url);
+ "*: using default reverse proxy worker for %s (no keepalive)", *url);
*balancer = NULL;
*worker = conf->reverse;
access_status = OK;
@@ -1938,6 +1992,7 @@ 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");
+ fix_uds_filename(r, url);
}
}
}
@@ -2023,7 +2078,14 @@ PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
proxy_function, backend_addr->family, backend_name);
if (conf->source_address) {
- rv = apr_socket_bind(*newsock, conf->source_address);
+ apr_sockaddr_t *local_addr;
+ /* Make a copy since apr_socket_bind() could change
+ * conf->source_address, which we don't want.
+ */
+ local_addr = apr_pmemdup(r->pool, conf->source_address,
+ sizeof(apr_sockaddr_t));
+ local_addr->pool = r->pool;
+ rv = apr_socket_bind(*newsock, local_addr);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00938)
"%s: failed to bind socket to local address",
@@ -2097,29 +2159,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 +2189,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
@@ -2173,8 +2213,12 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
* The scheme handler decides if this is permanent or
* short living pool.
*/
- /* are we connecting directly, or via a proxy? */
- if (!proxyname) {
+ /* Unless we are connecting the backend via a (forward Proxy)Remote, we
+ * have to use the original form of the URI (non absolute), but this is
+ * also the case via a remote proxy using the CONNECT method since the
+ * original request (and URI) is to be embedded in the body.
+ */
+ if (!proxyname || conn->is_ssl) {
*url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
uri->query ? uri->query : "",
uri->fragment ? "#" : "",
@@ -2190,85 +2234,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 +2360,60 @@ 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 if (conn->forward
+ && ((forward_info *)(conn->forward))->use_http_connect) {
+ ssl_hostname = ((forward_info *)conn->forward)->target_host;
+ }
+ 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;
@@ -2312,7 +2426,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
#endif
#if USE_ALTERNATE_IS_CONNECTED && defined(APR_MSG_PEEK)
-static int is_socket_connected(apr_socket_t *socket)
+PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket)
{
apr_pollfd_t pfds[1];
apr_status_t status;
@@ -2350,7 +2464,7 @@ static int is_socket_connected(apr_socket_t *socket)
}
#else
-static int is_socket_connected(apr_socket_t *sock)
+PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *sock)
{
apr_size_t buffer_len = 1;
@@ -2412,6 +2526,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
"Proxy-agent: %s" CRLF CRLF,
ap_get_server_banner());
+ ap_xlate_proto_to_ascii(buffer, nbytes);
apr_socket_send(backend->sock, buffer, &nbytes);
/* Receive the whole CONNECT response */
@@ -2423,7 +2538,8 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
len += nbytes;
left -= nbytes;
buffer[len] = '\0';
- if (strstr(buffer + len - nbytes, "\r\n\r\n") != NULL) {
+ if (strstr(buffer + len - nbytes, CRLF_ASCII CRLF_ASCII) != NULL) {
+ ap_xlate_proto_from_ascii(buffer, len);
complete = 1;
break;
}
@@ -2435,7 +2551,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
status = apr_socket_recv(backend->sock, drain_buffer, &nbytes);
drain_buffer[nbytes] = '\0';
nbytes = sizeof(drain_buffer) - 1;
- if (strstr(drain_buffer, "\r\n\r\n") != NULL) {
+ if (strstr(drain_buffer, CRLF_ASCII CRLF_ASCII) != NULL) {
break;
}
}
@@ -2443,7 +2559,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
/* Check for HTTP_OK response status */
if (status == APR_SUCCESS) {
- int major, minor;
+ unsigned int major, minor;
/* Only scan for three character status code */
char code_str[4];
@@ -2461,7 +2577,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00950)
"send_http_connect: the forward proxy returned code is '%s'",
code_str);
- status = APR_INCOMPLETE;
+ status = APR_INCOMPLETE;
}
}
}
@@ -2470,14 +2586,17 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
}
-#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)
+/* TODO: In APR 2.x: Extend apr_sockaddr_t to possibly be a path !!! */
+PROXY_DECLARE(apr_status_t) ap_proxy_connect_uds(apr_socket_t *sock,
+ const char *uds_path,
+ apr_pool_t *p)
{
+#if APR_HAVE_SYS_UN_H
apr_status_t rv;
apr_os_sock_t rawsock;
apr_interval_time_t t;
+ struct sockaddr_un *sa;
+ apr_socklen_t addrlen, pathlen;
rv = apr_os_sock_get(&rawsock, sock);
if (rv != APR_SUCCESS) {
@@ -2489,32 +2608,35 @@ static apr_status_t socket_connect_un(apr_socket_t *sock,
return rv;
}
+ pathlen = strlen(uds_path);
+ /* copy the UDS path (including NUL) to the sockaddr_un */
+ addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path) + pathlen;
+ sa = (struct sockaddr_un *)apr_palloc(p, addrlen + 1);
+ memcpy(sa->sun_path, uds_path, pathlen + 1);
+ sa->sun_family = AF_UNIX;
+
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);
+ } while (rv == -1 && (rv = errno) == EINTR);
- if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY)
- && (t > 0)) {
+ if (rv && rv != EISCONN) {
+ if ((rv == EINPROGRESS || rv == EALREADY) && (t > 0)) {
#if APR_MAJOR_VERSION < 2
- rv = apr_wait_for_io_or_timeout(NULL, sock, 0);
+ rv = apr_wait_for_io_or_timeout(NULL, sock, 0);
#else
- rv = apr_socket_wait(sock, APR_WAIT_WRITE);
+ 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;
-}
+#else
+ return APR_ENOTIMPL;
#endif
+}
PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_conn_rec *conn,
@@ -2533,19 +2655,31 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
if (conn->sock) {
- if (!(connected = is_socket_connected(conn->sock))) {
+ if (!(connected = ap_proxy_is_socket_connected(conn->sock))) {
+ /* This clears conn->scpool (and associated data), so backup and
+ * restore any ssl_hostname for this connection set earlier by
+ * ap_proxy_determine_connection().
+ */
+ char ssl_hostname[PROXY_WORKER_RFC1035_NAME_SIZE];
+ if (!conn->ssl_hostname || PROXY_STRNCPY(ssl_hostname,
+ conn->ssl_hostname)) {
+ ssl_hostname[0] = '\0';
+ }
+
socket_cleanup(conn);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00951)
"%s: backend socket is disconnected.",
proxy_function);
+
+ if (ssl_hostname[0]) {
+ conn->ssl_hostname = apr_pstrdup(conn->scpool, ssl_hostname);
+ }
}
}
while ((backend_addr || conn->uds_path) && !connected) {
#if APR_HAVE_SYS_UN_H
if (conn->uds_path)
{
- struct sockaddr_un sa;
-
rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0,
conn->scpool);
if (rv != APR_SUCCESS) {
@@ -2559,10 +2693,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
}
conn->connection = NULL;
- sa.sun_family = AF_UNIX;
- apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path));
-
- rv = socket_connect_un(newsock, &sa);
+ rv = ap_proxy_connect_uds(newsock, conn->uds_path, conn->scpool);
if (rv != APR_SUCCESS) {
apr_socket_close(newsock);
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454)
@@ -2573,6 +2704,13 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
worker->s->hostname);
break;
}
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02823)
+ "%s: connection established with Unix domain socket "
+ "%s (%s)",
+ proxy_function,
+ conn->uds_path,
+ worker->s->hostname);
}
else
#endif
@@ -2639,9 +2777,9 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_function, backend_addr->family, worker->s->hostname);
if (conf->source_address_set) {
- local_addr = apr_pmemdup(conn->pool, conf->source_address,
+ local_addr = apr_pmemdup(conn->scpool, conf->source_address,
sizeof(apr_sockaddr_t));
- local_addr->pool = conn->pool;
+ local_addr->pool = conn->scpool;
rv = apr_socket_bind(newsock, local_addr);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956)
@@ -2665,6 +2803,12 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
backend_addr = backend_addr->next;
continue;
}
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02824)
+ "%s: connection established with %pI (%s)",
+ proxy_function,
+ backend_addr,
+ worker->s->hostname);
}
/* Set a timeout on the socket */
@@ -2707,35 +2851,76 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
connected = 1;
}
- /*
- * Put the entire worker to error state if
- * the PROXY_WORKER_IGNORE_ERRORS flag is not set.
- * Altrough some connections may be alive
- * no further connections to the worker could be made
- */
- if (!connected && PROXY_WORKER_IS_USABLE(worker) &&
- !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
- worker->s->error_time = apr_time_now();
- worker->s->status |= PROXY_WORKER_IN_ERROR;
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00959)
- "ap_proxy_connect_backend disabling worker for (%s) for %"
- APR_TIME_T_FMT "s",
- worker->s->hostname, apr_time_sec(worker->s->retry));
+ if (PROXY_WORKER_IS_USABLE(worker)) {
+ /*
+ * Put the entire worker to error state if
+ * the PROXY_WORKER_IGNORE_ERRORS flag is not set.
+ * Although some connections may be alive
+ * no further connections to the worker could be made
+ */
+ if (!connected) {
+ if (!(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
+ worker->s->error_time = apr_time_now();
+ worker->s->status |= PROXY_WORKER_IN_ERROR;
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00959)
+ "ap_proxy_connect_backend disabling worker for (%s) for %"
+ APR_TIME_T_FMT "s",
+ worker->s->hostname, apr_time_sec(worker->s->retry));
+ }
+ }
+ else {
+ if (worker->s->retries) {
+ /*
+ * A worker came back. So here is where we need to
+ * either reset all params to initial conditions or
+ * apply some sort of aging
+ */
+ }
+ worker->s->error_time = 0;
+ worker->s->retries = 0;
+ }
+ return connected ? OK : DECLINED;
}
else {
- if (worker->s->retries) {
- /*
- * A worker came back. So here is where we need to
- * either reset all params to initial conditions or
- * apply some sort of aging
- */
+ /*
+ * The worker is in error likely done by a different thread / process
+ * e.g. for a timeout or bad status. We should respect this and should
+ * not continue with a connection via this worker even if we got one.
+ */
+ if (connected) {
+ socket_cleanup(conn);
}
- worker->s->error_time = 0;
- worker->s->retries = 0;
+ return DECLINED;
}
- return connected ? OK : DECLINED;
}
+static apr_status_t connection_shutdown(void *theconn)
+{
+ proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
+ conn_rec *c = conn->connection;
+ if (c) {
+ if (!c->aborted) {
+ apr_interval_time_t saved_timeout = 0;
+ apr_socket_timeout_get(conn->sock, &saved_timeout);
+ if (saved_timeout) {
+ apr_socket_timeout_set(conn->sock, 0);
+ }
+
+ (void)ap_shutdown_conn(c, 0);
+ c->aborted = 1;
+
+ if (saved_timeout) {
+ apr_socket_timeout_set(conn->sock, saved_timeout);
+ }
+ }
+
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02642)
+ "proxy: connection shutdown");
+ }
+ return APR_SUCCESS;
+}
+
+
PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
proxy_conn_rec *conn,
conn_rec *c,
@@ -2808,6 +2993,11 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
}
apr_socket_timeout_set(conn->sock, current_timeout);
+ /* Shutdown the connection before closing it (eg. SSL connections
+ * need to be close-notify-ed).
+ */
+ apr_pool_pre_cleanup_register(conn->scpool, conn, connection_shutdown);
+
return OK;
}
@@ -2881,7 +3071,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_set_wstatus(char c, int set, proxy_worker *
{
unsigned int *status = &w->s->status;
char flag = toupper(c);
- struct wstat *pwt = wstat_tbl;
+ proxy_wstat_t *pwt = proxy_wstat_tbl;
while (pwt->bit) {
if (flag == pwt->flag) {
if (set)
@@ -2899,12 +3089,15 @@ PROXY_DECLARE(char *) ap_proxy_parse_wstatus(apr_pool_t *p, proxy_worker *w)
{
char *ret = "";
unsigned int status = w->s->status;
- struct wstat *pwt = wstat_tbl;
+ proxy_wstat_t *pwt = proxy_wstat_tbl;
while (pwt->bit) {
if (status & pwt->bit)
ret = apr_pstrcat(p, ret, pwt->name, NULL);
pwt++;
}
+ if (!*ret) {
+ ret = "??? ";
+ }
if (PROXY_WORKER_IS_USABLE(w))
ret = apr_pstrcat(p, ret, "Ok ", NULL);
return ret;
@@ -3051,7 +3244,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);
@@ -3121,7 +3314,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
char *buf;
const apr_array_header_t *headers_in_array;
const apr_table_entry_t *headers_in;
- apr_table_t *headers_in_copy;
+ apr_table_t *saved_headers_in;
apr_bucket *e;
int do_100_continue;
conn_rec *origin = p_conn->connection;
@@ -3193,6 +3386,21 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ /*
+ * Save the original headers in here and restore them when leaving, since
+ * we will apply proxy purpose only modifications (eg. clearing hop-by-hop
+ * headers, add Via or X-Forwarded-* or Expect...), whereas the originals
+ * will be needed later to prepare the correct response and logging.
+ *
+ * Note: We need to take r->pool for apr_table_copy as the key / value
+ * pairs in r->headers_in have been created out of r->pool and
+ * p might be (and actually is) a longer living pool.
+ * This would trigger the bad pool ancestry abort in apr_table_copy if
+ * apr is compiled with APR_POOL_DEBUG.
+ */
+ saved_headers_in = r->headers_in;
+ r->headers_in = apr_table_copy(r->pool, saved_headers_in);
+
/* handle Via */
if (conf->viaopt == via_block) {
/* Block all outgoing Via: headers */
@@ -3226,8 +3434,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
@@ -3277,21 +3499,12 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
}
proxy_run_fixups(r);
- /*
- * Make a copy of the headers_in table before clearing the connection
- * headers as we need the connection headers later in the http output
- * filter to prepare the correct response headers.
- *
- * Note: We need to take r->pool for apr_table_copy as the key / value
- * pairs in r->headers_in have been created out of r->pool and
- * p might be (and actually is) a longer living pool.
- * This would trigger the bad pool ancestry abort in apr_table_copy if
- * apr is compiled with APR_POOL_DEBUG.
- */
- headers_in_copy = apr_table_copy(r->pool, r->headers_in);
- ap_proxy_clear_connection(r, headers_in_copy);
+ if (ap_proxy_clear_connection(r, r->headers_in) < 0) {
+ return HTTP_BAD_REQUEST;
+ }
+
/* send request headers */
- headers_in_array = apr_table_elts(headers_in_copy);
+ headers_in_array = apr_table_elts(r->headers_in);
headers_in = (const apr_table_entry_t *) headers_in_array->elts;
for (counter = 0; counter < headers_in_array->nelts; counter++) {
if (headers_in[counter].key == NULL
@@ -3337,7 +3550,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
/* for sub-requests, ignore freshness/expiry headers */
if (r->main) {
- if ( !strcasecmp(headers_in[counter].key, "If-Match")
+ if ( !strcasecmp(headers_in[counter].key, "If-Match")
|| !strcasecmp(headers_in[counter].key, "If-Modified-Since")
|| !strcasecmp(headers_in[counter].key, "If-Range")
|| !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
@@ -3353,6 +3566,11 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
}
+
+ /* Restore the original headers in (see comment above),
+ * we won't modify them anymore.
+ */
+ r->headers_in = saved_headers_in;
return OK;
}
@@ -3408,6 +3626,9 @@ static proxy_schemes_t pschemes[] =
{
{"fcgi", 8000},
{"ajp", AJP13_DEF_PORT},
+ {"scgi", SCGI_DEF_PORT},
+ {"h2c", DEFAULT_HTTP_PORT},
+ {"h2", DEFAULT_HTTPS_PORT},
{ NULL, 0xFFFF } /* unknown port */
};
@@ -3429,6 +3650,139 @@ PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme)
return 0;
}
+PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r,
+ apr_bucket_brigade *from,
+ apr_bucket_brigade *to)
+{
+ apr_bucket *e;
+ apr_bucket *new;
+ const char *data;
+ apr_size_t bytes;
+ apr_status_t rv = APR_SUCCESS;
+ apr_bucket_alloc_t *bucket_alloc = to->bucket_alloc;
+
+ apr_brigade_cleanup(to);
+ for (e = APR_BRIGADE_FIRST(from);
+ e != APR_BRIGADE_SENTINEL(from);
+ e = APR_BUCKET_NEXT(e)) {
+ if (!APR_BUCKET_IS_METADATA(e)) {
+ apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ);
+ new = apr_bucket_transient_create(data, bytes, bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(to, new);
+ }
+ else if (APR_BUCKET_IS_FLUSH(e)) {
+ new = apr_bucket_flush_create(bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(to, new);
+ }
+ else if (APR_BUCKET_IS_EOS(e)) {
+ new = apr_bucket_eos_create(bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(to, new);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(03304)
+ "Unhandled bucket type of type %s in"
+ " ap_proxy_buckets_lifetime_transform", e->type->name);
+ rv = APR_EGENERAL;
+ }
+ }
+ return rv;
+}
+
+PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
+ request_rec *r,
+ conn_rec *c_i,
+ conn_rec *c_o,
+ apr_bucket_brigade *bb_i,
+ apr_bucket_brigade *bb_o,
+ const char *name,
+ int *sent,
+ apr_off_t bsize,
+ int after)
+{
+ apr_status_t rv;
+#ifdef DEBUGGING
+ apr_off_t len;
+#endif
+
+ do {
+ apr_brigade_cleanup(bb_i);
+ rv = ap_get_brigade(c_i->input_filters, bb_i, AP_MODE_READBYTES,
+ APR_NONBLOCK_READ, bsize);
+ if (rv == APR_SUCCESS) {
+ if (c_o->aborted) {
+ return APR_EPIPE;
+ }
+ if (APR_BRIGADE_EMPTY(bb_i)) {
+ break;
+ }
+#ifdef DEBUGGING
+ len = -1;
+ apr_brigade_length(bb_i, 0, &len);
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03306)
+ "ap_proxy_transfer_between_connections: "
+ "read %" APR_OFF_T_FMT
+ " bytes from %s", len, name);
+#endif
+ if (sent) {
+ *sent = 1;
+ }
+ ap_proxy_buckets_lifetime_transform(r, bb_i, bb_o);
+ if (!after) {
+ apr_bucket *b;
+
+ /*
+ * Do not use ap_fflush here since this would cause the flush
+ * bucket to be sent in a separate brigade afterwards which
+ * causes some filters to set aside the buckets from the first
+ * brigade and process them when the flush arrives in the second
+ * brigade. As set asides of our transformed buckets involve
+ * memory copying we try to avoid this. If we have the flush
+ * bucket in the first brigade they directly process the
+ * buckets without setting them aside.
+ */
+ b = apr_bucket_flush_create(bb_o->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb_o, b);
+ }
+ rv = ap_pass_brigade(c_o->output_filters, bb_o);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(03307)
+ "ap_proxy_transfer_between_connections: "
+ "error on %s - ap_pass_brigade",
+ name);
+ }
+ } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(03308)
+ "ap_proxy_transfer_between_connections: "
+ "error on %s - ap_get_brigade",
+ name);
+ }
+ } while (rv == APR_SUCCESS);
+
+ if (after) {
+ ap_fflush(c_o->output_filters, bb_o);
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r,
+ "ap_proxy_transfer_between_connections complete");
+
+ if (APR_STATUS_IS_EAGAIN(rv)) {
+ rv = APR_SUCCESS;
+ }
+
+ return rv;
+}
+
+PROXY_DECLARE (const char *) ap_proxy_show_hcmethod(hcmethod_t method)
+{
+ proxy_hcmethods_t *m = proxy_hcmethods;
+ for (; m->name; m++) {
+ if (m->method == method) {
+ return m->name;
+ }
+ }
+ return "???";
+}
+
void proxy_util_register_hooks(apr_pool_t *p)
{
APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker);