Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge r1881790, r1904513, r1909400, r1909401, r1909402, r1909451, r1912459, r1913432,r1913534 from trunk #390

Closed
3 changes: 3 additions & 0 deletions changes-entries/enablereuse.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*) mod_proxy: Ignore (and warn about) enablereuse=on for ProxyPassMatch when
some dollar substitution (backreference) happens in the hostname or port
part of the URL. [Yann Ylavic]
3 changes: 3 additions & 0 deletions changes-entries/pr37355.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*) mod_proxy: Add optional third argument for ProxyRemote, which
configures Basic authentication credentials to pass to the remote
proxy. PR 37355. [Joe Orton]
3 changes: 3 additions & 0 deletions changes-entries/proxy_backend_dns_ttl.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

*) mod_proxy: Allow to set a TTL for how long DNS resolutions to backend
systems are cached. [Yann Ylavic]
49 changes: 34 additions & 15 deletions docs/manual/mod/mod_proxy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -654,9 +654,10 @@ context in 2.3.3 and later.</compatibility>
<directivesynopsis>
<name>ProxyRemote</name>
<description>Remote proxy used to handle certain requests</description>
<syntax>ProxyRemote <var>match</var> <var>remote-server</var></syntax>
<syntax>ProxyRemote <var>match</var> <var>remote-server</var> [<var>username:password</var>]</syntax>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>
<compatibility>The optional third argument is usable only in httpd 2.5.1 and later.</compatibility>

<usage>
<p>This defines remote proxies to this proxy. <var>match</var> is either the
Expand Down Expand Up @@ -690,6 +691,15 @@ ProxyRemote "ftp" "http://ftpproxy.mydomain:8080"
<p>This option also supports reverse proxy configuration; a backend
webserver can be embedded within a virtualhost URL space even if that
server is hidden by another forward proxy.</p>

<p>An optional third argument <var>username:password</var> may be
given, which defines the Basic authentication credentials to pass
to the configured remote proxy. The credentials will always be
sent without first waiting for the remote proxy to send a Basic
authentication challenge. The <a
href="mod_proxy_http.html#env">Proxy-Chain-Auth</a> environment
variable has no effect if this argument is used.</p>

</usage>
</directivesynopsis>

Expand Down Expand Up @@ -1281,6 +1291,11 @@ ProxyPass "/example" "http://backend.example.com" max=20 ttl=120 retry=300
interfering with the authorizations that are to be enforced in by the Apache httpd.</p>
</note>
</td></tr>
<tr><td><a id="addressttl" name="addressttl">addressttl</a></td>
<td>-1</td>
<td><p>TTL in seconds for how long DNS resolutions of the backend address are cached.
-1 means until restart of Apache httpd.</p>
</td></tr>

</table>

Expand Down Expand Up @@ -1500,6 +1515,9 @@ ProxyPassReverse "/mirror/foo/" "https://backend.example.com/"
<contextlist><context>server config</context><context>virtual host</context>
<context>directory</context>
</contextlist>
<compatibility>Since 2.4.47 the <var>key=value</var> Parameters are honored
when the <var>url</var> parameter contains backreference(s) (see note below).
</compatibility>

<usage>
<p>This directive is equivalent to <directive module="mod_proxy">ProxyPass</directive>
Expand All @@ -1521,20 +1539,7 @@ ProxyPassMatch "^/(.*\.gif)$" "http://backend.example.com/$1"
<p>will cause a local request for
<code>http://example.com/foo/bar.gif</code> to be internally converted
into a proxy request to <code>http://backend.example.com/foo/bar.gif</code>.</p>
<note><title>Note</title>
<p>The URL argument must be parsable as a URL <em>before</em> regexp
substitutions (as well as after). This limits the matches you can use.
For instance, if we had used</p>
<highlight language="config">
ProxyPassMatch "^(/.*\.gif)$" "http://backend.example.com:8000$1"
</highlight>
<p>in our previous example, it would fail with a syntax error
at server startup. This is a bug (PR 46665 in the ASF bugzilla),
and the workaround is to reformulate the match:</p>
<highlight language="config">
ProxyPassMatch "^/(.*\.gif)$" "http://backend.example.com:8000/$1"
</highlight>
</note>

<p>The <code>!</code> directive is useful in situations where you don't want
to reverse-proxy a subdirectory.</p>

Expand All @@ -1553,6 +1558,20 @@ ProxyPassMatch "^/(.*\.gif)$" "http://backend.example.com:8000/$1"
expression, the original URL will be appended to the URL parameter.
</p>
</note>
<note>
<title><var><code>key=value</code> Parameters versus <var>url</var> with backreference(s)</title>
<p>Since Apache HTTP Server 2.4.47, the <code>key=value</code> Parameters
are no longer ignored in a <directive>ProxyPassMatch</directive> using
an <var>url</var> with backreference(s). However to keep the existing
behavior regarding reuse/keepalive of backend connections (which were
never reused before for these URLs), the parameter <var>enablereuse</var>
(or <var>disablereuse</var>) default to <code>off</code> (resp. <code>on</code>)
in this case. Setting <code>enablereuse=on</code> explicitely allows to
reuse connections <strong>unless</strong> some backreference(s) belong in
the <code>authority</code> part (hostname and/or port) of the <var>url</var>
(this condition is enforced since Apache HTTP Server 2.4.55, and produces
a warning at startup because these URLs are not reusable per se).</p>
</note>

<note type="warning">
<title>Security Warning</title>
Expand Down
3 changes: 2 additions & 1 deletion include/ap_mmn.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,14 +597,15 @@
* 20120211.127 (2.4.56-dev) Add ap_proxy_canonenc_ex
* 20120211.128 (2.4.55-dev) Add AP_CTIME_OPTION_GMTOFF to util_time.h
* 20120211.129 (2.4.58-dev) Add ap_get_pollfd_from_conn()
* 20120211.130 (2.4.59-dev) Add ap_proxy_determine_address()
*/

#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */

#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20120211
#endif
#define MODULE_MAGIC_NUMBER_MINOR 129 /* 0...n */
#define MODULE_MAGIC_NUMBER_MINOR 130 /* 0...n */

/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
Expand Down
52 changes: 42 additions & 10 deletions modules/proxy/mod_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,24 @@ static const char *set_worker_param(apr_pool_t *p,
return "EnableReuse must be On|Off";
worker->s->disablereuse_set = 1;
}
else if (!strcasecmp(key, "addressttl")) {
/* Address TTL in seconds
*/
apr_interval_time_t ttl;
if (strcmp(val, "-1") == 0) {
worker->s->address_ttl = -1;
}
else if (ap_timeout_parameter_parse(val, &ttl, "s") == APR_SUCCESS
&& (ttl <= apr_time_from_sec(APR_INT32_MAX))
&& (ttl % apr_time_from_sec(1)) == 0) {
worker->s->address_ttl = apr_time_sec(ttl);
}
else {
return "AddressTTL must be -1 or a number of seconds not "
"exceeding " APR_STRINGIFY(APR_INT32_MAX);
}
worker->s->address_ttl_set = 1;
}
else if (!strcasecmp(key, "route")) {
/* Worker route.
*/
Expand Down Expand Up @@ -1460,11 +1478,20 @@ static int proxy_handler(request_rec *r)
/* handle the scheme */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01142)
"Trying to run scheme_handler against proxy");

if (ents[i].creds) {
apr_table_set(r->notes, "proxy-basic-creds", ents[i].creds);
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
"Using proxy auth creds %s", ents[i].creds);
}

access_status = proxy_run_scheme_handler(r, worker,
conf, url,
ents[i].hostname,
ents[i].port);

if (ents[i].creds) apr_table_unset(r->notes, "proxy-basic-creds");

/* Did the scheme handler process the request? */
if (access_status != DECLINED) {
const char *cl_a;
Expand Down Expand Up @@ -1902,8 +1929,8 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
return new;
}

static const char *
add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex)
static const char *add_proxy(cmd_parms *cmd, void *dummy, const char *f1,
const char *r1, const char *creds, int regex)
{
server_rec *s = cmd->server;
proxy_server_conf *conf =
Expand Down Expand Up @@ -1961,19 +1988,24 @@ static const char *
new->port = port;
new->regexp = reg;
new->use_regex = regex;
if (creds) {
new->creds = apr_pstrcat(cmd->pool, "Basic ",
ap_pbase64encode(cmd->pool, (char *)creds),
NULL);
}
return NULL;
}

static const char *
add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
static const char *add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1,
const char *r1, const char *creds)
{
return add_proxy(cmd, dummy, f1, r1, 0);
return add_proxy(cmd, dummy, f1, r1, creds, 0);
}

static const char *
add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
static const char *add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1,
const char *r1, const char *creds)
{
return add_proxy(cmd, dummy, f1, r1, 1);
return add_proxy(cmd, dummy, f1, r1, creds, 1);
}

PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url)
Expand Down Expand Up @@ -3012,9 +3044,9 @@ static const command_rec proxy_cmds[] =
"location, in regular expression syntax"),
AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF,
"on if the true proxy requests should be accepted"),
AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
AP_INIT_TAKE23("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
"a scheme, partial URL or '*' and a proxy server"),
AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
AP_INIT_TAKE23("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
"a regex pattern and a proxy server"),
AP_INIT_FLAG("ProxyPassInterpolateEnv", ap_set_flag_slot_char,
(void*)APR_OFFSETOF(proxy_dir_conf, interpolate_env),
Expand Down
33 changes: 33 additions & 0 deletions modules/proxy/mod_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct proxy_remote {
const char *protocol; /* the scheme used to talk to this proxy */
const char *hostname; /* the hostname of this proxy */
ap_regex_t *regexp; /* compiled regex (if any) for the remote */
const char *creds; /* auth credentials (if any) for the proxy */
int use_regex; /* simple boolean. True if we have a regex pattern */
apr_port_t port; /* the port for this proxy */
};
Expand Down Expand Up @@ -263,6 +264,8 @@ typedef struct {
apr_array_header_t* cookie_domains;
} proxy_req_conf;

struct proxy_address; /* opaque TTL'ed and refcount'ed address */

typedef struct {
conn_rec *connection;
request_rec *r; /* Request record of the backend request
Expand All @@ -288,6 +291,9 @@ typedef struct {
* and its scpool/bucket_alloc (NULL before),
* must be left cleaned when used (locally).
*/
apr_pool_t *uds_pool; /* Subpool for reusing UDS paths */
apr_pool_t *fwd_pool; /* Subpool for reusing ProxyRemote infos */
struct proxy_address *address; /* Current remote address */
} proxy_conn_rec;

typedef struct {
Expand Down Expand Up @@ -484,6 +490,9 @@ typedef struct {
unsigned int response_field_size_set:1;
char secret[PROXY_WORKER_MAX_SECRET_SIZE]; /* authentication secret (e.g. AJP13) */
char name_ex[PROXY_WORKER_EXT_NAME_SIZE]; /* Extended name (>96 chars for 2.4.x) */
unsigned int address_ttl_set:1;
apr_int32_t address_ttl; /* backend address' TTL (seconds) */
apr_uint32_t address_expiry; /* backend address' next expiry time */
} proxy_worker_shared;

#define ALIGNED_PROXY_WORKER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_worker_shared)))
Expand All @@ -500,6 +509,7 @@ struct proxy_worker {
#endif
void *context; /* general purpose storage */
ap_conf_vector_t *section_config; /* <Proxy>-section wherein defined */
struct proxy_address *volatile address; /* current worker address (if reusable) */
};

/* default to health check every 30 seconds */
Expand Down Expand Up @@ -1024,6 +1034,29 @@ PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
request_rec *r,
proxy_server_conf *conf);

/* Bitmask for ap_proxy_determine_address() */
#define PROXY_DETERMINE_ADDRESS_CHECK (1u << 0)
/**
* Resolve an address, reusing the one of the worker if any.
* @param proxy_function calling proxy scheme (http, ajp, ...)
* @param conn proxy connection the address is used for
* @param hostname host to resolve (should be the worker's if reusable)
* @param hostport port to resolve (should be the worker's if reusable)
* @param flags bitmask of PROXY_DETERMINE_ADDRESS_*
* @param r current request (if any)
* @param s current server (or NULL if r != NULL and ap_proxyerror()
* should be called on error)
* @return APR_SUCCESS or an error, APR_EEXIST if the address is still
* the same and PROXY_DETERMINE_ADDRESS_CHECK is asked
*/
PROXY_DECLARE(apr_status_t) ap_proxy_determine_address(const char *proxy_function,
proxy_conn_rec *conn,
const char *hostname,
apr_port_t hostport,
unsigned int flags,
request_rec *r,
server_rec *s);

/**
* Determine backend hostname and port
* @param p memory pool used for processing
Expand Down
35 changes: 12 additions & 23 deletions modules/proxy/mod_proxy_ajp.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
if (status != APR_SUCCESS) {
conn->close = 1;
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00868)
"request failed to %pI (%s:%d)",
conn->worker->cp->addr,
conn->worker->s->hostname_ex,
(int)conn->worker->s->port);
"request failed to %pI (%s:%hu)",
conn->addr, conn->hostname, conn->port);
if (status == AJP_EOVERFLOW)
return HTTP_BAD_REQUEST;
else if (status == AJP_EBAD_METHOD) {
Expand Down Expand Up @@ -336,10 +334,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
conn->close = 1;
apr_brigade_destroy(input_brigade);
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00876)
"send failed to %pI (%s:%d)",
conn->worker->cp->addr,
conn->worker->s->hostname_ex,
(int)conn->worker->s->port);
"send failed to %pI (%s:%hu)",
conn->addr, conn->hostname, conn->port);
/*
* It is fatal when we failed to send a (part) of the request
* body.
Expand Down Expand Up @@ -378,10 +374,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
conn->close = 1;
apr_brigade_destroy(input_brigade);
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00878)
"read response failed from %pI (%s:%d)",
conn->worker->cp->addr,
conn->worker->s->hostname_ex,
(int)conn->worker->s->port);
"read response failed from %pI (%s:%hu)",
conn->addr, conn->hostname, conn->port);

/* If we had a successful cping/cpong and then a timeout
* we assume it is a request that cause a back-end timeout,
Expand Down Expand Up @@ -677,10 +671,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00892)
"got response from %pI (%s:%d)",
conn->worker->cp->addr,
conn->worker->s->hostname_ex,
(int)conn->worker->s->port);
"got response from %pI (%s:%hu)",
conn->addr, conn->hostname, conn->port);

if (ap_proxy_should_override(conf, r->status)) {
/* clear r->status for override error, otherwise ErrorDocument
Expand All @@ -702,10 +694,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,

if (backend_failed) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00893)
"dialog to %pI (%s:%d) failed",
conn->worker->cp->addr,
conn->worker->s->hostname_ex,
(int)conn->worker->s->port);
"dialog to %pI (%s:%hu) failed",
conn->addr, conn->hostname, conn->port);
/*
* If we already send data, signal a broken backend connection
* upwards in the chain.
Expand Down Expand Up @@ -850,9 +840,8 @@ static int proxy_ajp_handler(request_rec *r, proxy_worker *worker,
if (status != APR_SUCCESS) {
backend->close = 1;
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00897)
"cping/cpong failed to %pI (%s:%d)",
worker->cp->addr, worker->s->hostname_ex,
(int)worker->s->port);
"cping/cpong failed to %pI (%s:%hu)",
backend->addr, backend->hostname, backend->port);
status = HTTP_SERVICE_UNAVAILABLE;
retry++;
continue;
Expand Down
Loading