summaryrefslogtreecommitdiff
path: root/modules/proxy
diff options
context:
space:
mode:
authorStefan Fritsch <sf@sfritsch.de>2011-12-27 19:42:17 +0100
committerStefan Fritsch <sf@sfritsch.de>2011-12-27 19:42:17 +0100
commit9e615cb6aa4afcee97f8a1646e5a586261a7b81f (patch)
tree0e09fde2404555dc5daf167b38243b5f89c16549 /modules/proxy
parent1acac7a6b494db24f8f58e44dab7657b6de68742 (diff)
downloadapache2-9e615cb6aa4afcee97f8a1646e5a586261a7b81f.tar.gz
Upstream tarball 2.2.8upstream/2.2.8
Diffstat (limited to 'modules/proxy')
-rw-r--r--modules/proxy/ajp.h2
-rw-r--r--modules/proxy/ajp_header.c14
-rw-r--r--modules/proxy/mod_proxy.c106
-rw-r--r--modules/proxy/mod_proxy.h23
-rw-r--r--modules/proxy/mod_proxy_ajp.c18
-rw-r--r--modules/proxy/mod_proxy_balancer.c124
-rw-r--r--modules/proxy/mod_proxy_ftp.c16
-rw-r--r--modules/proxy/mod_proxy_http.c185
-rw-r--r--modules/proxy/proxy_util.c13
9 files changed, 349 insertions, 152 deletions
diff --git a/modules/proxy/ajp.h b/modules/proxy/ajp.h
index 3451a848..8c022fb3 100644
--- a/modules/proxy/ajp.h
+++ b/modules/proxy/ajp.h
@@ -145,7 +145,7 @@ struct ajp_msg
#define AJP_HEADER_SZ_LEN 2
#define AJP_HEADER_SZ 6
#define AJP_MSG_BUFFER_SZ 8192
-#define AJP_MAX_BUFFER_SZ 16384
+#define AJP_MAX_BUFFER_SZ 65536
#define AJP13_MAX_SEND_BODY_SZ (AJP_MAX_BUFFER_SZ - AJP_HEADER_SZ)
/** Send a request from web server to container*/
diff --git a/modules/proxy/ajp_header.c b/modules/proxy/ajp_header.c
index 07ffba97..6fecb5a9 100644
--- a/modules/proxy/ajp_header.c
+++ b/modules/proxy/ajp_header.c
@@ -162,13 +162,19 @@ static const unsigned char sc_for_req_method_table[] = {
0 /* M_INVALID */
};
-static int sc_for_req_method_by_id(int method_id)
+static int sc_for_req_method_by_id(request_rec *r)
{
- if (method_id < 0 || method_id > M_INVALID)
+ int method_id = r->method_number;
+ if (method_id < 0 || method_id > M_INVALID) {
return UNKNOWN_METHOD;
- else
+ }
+ else if (r->header_only) {
+ return SC_M_HEAD;
+ }
+ else {
return sc_for_req_method_table[method_id] ?
sc_for_req_method_table[method_id] : UNKNOWN_METHOD;
+ }
}
/*
@@ -218,7 +224,7 @@ static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"Into ajp_marshal_into_msgb");
- if ((method = sc_for_req_method_by_id(r->method_number)) == UNKNOWN_METHOD) {
+ if ((method = sc_for_req_method_by_id(r)) == UNKNOWN_METHOD) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"ajp_marshal_into_msgb - No such method %s",
r->method);
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
index 18b554a7..de48638b 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -85,9 +85,10 @@ static const char *set_worker_param(apr_pool_t *p,
* in error state, it will be retried after that timeout.
*/
ival = atoi(val);
- if (ival < 1)
- return "Retry must be at least one second";
+ if (ival < 0)
+ return "Retry must be a positive value";
worker->retry = apr_time_from_sec(ival);
+ worker->retry_set = 1;
}
else if (!strcasecmp(key, "ttl")) {
/* Time in seconds that will destroy all the connections
@@ -219,12 +220,12 @@ static const char *set_worker_param(apr_pool_t *p,
else
worker->status &= ~PROXY_WORKER_HOT_STANDBY;
}
- else if (*v == 'I' || *v == 'i') {
- if (mode)
- worker->status |= PROXY_WORKER_IGNORE_ERRORS;
- else
- worker->status &= ~PROXY_WORKER_IGNORE_ERRORS;
- }
+ else if (*v == 'I' || *v == 'i') {
+ if (mode)
+ worker->status |= PROXY_WORKER_IGNORE_ERRORS;
+ else
+ worker->status &= ~PROXY_WORKER_IGNORE_ERRORS;
+ }
else {
return "Unknown status parameter option";
}
@@ -439,7 +440,9 @@ static int proxy_trans(request_rec *r)
int i, len;
struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
ap_regmatch_t regm[AP_MAX_REG_MATCH];
+ ap_regmatch_t reg1[AP_MAX_REG_MATCH];
char *found = NULL;
+ int mismatch = 0;
if (r->proxyreq) {
/* someone has already set up the proxy, it was possibly ourselves
@@ -454,13 +457,22 @@ static int proxy_trans(request_rec *r)
*/
for (i = 0; i < conf->aliases->nelts; i++) {
+ unsigned int nocanon = ent[i].flags & PROXYPASS_NOCANON;
+ const char *use_uri = nocanon ? r->unparsed_uri : r->uri;
if (ent[i].regex) {
if (!ap_regexec(ent[i].regex, r->uri, AP_MAX_REG_MATCH, regm, 0)) {
if ((ent[i].real[0] == '!') && (ent[i].real[1] == '\0')) {
return DECLINED;
}
- found = ap_pregsub(r->pool, ent[i].real, r->uri, AP_MAX_REG_MATCH,
- regm);
+ /* test that we haven't reduced the URI */
+ if (nocanon && ap_regexec(ent[i].regex, r->unparsed_uri,
+ AP_MAX_REG_MATCH, reg1, 0)) {
+ mismatch = 1;
+ use_uri = r->uri;
+ }
+ found = ap_pregsub(r->pool, ent[i].real, use_uri,
+ AP_MAX_REG_MATCH,
+ (use_uri == r->uri) ? regm : reg1);
/* Note: The strcmp() below catches cases where there
* was no regex substitution. This is so cases like:
*
@@ -478,8 +490,8 @@ static int proxy_trans(request_rec *r)
found = apr_pstrcat(r->pool, "proxy:", found, NULL);
}
else {
- found = apr_pstrcat(r->pool, "proxy:", ent[i].real, r->uri,
- NULL);
+ found = apr_pstrcat(r->pool, "proxy:", ent[i].real,
+ use_uri, NULL);
}
}
}
@@ -490,15 +502,31 @@ static int proxy_trans(request_rec *r)
if ((ent[i].real[0] == '!') && (ent[i].real[1] == '\0')) {
return DECLINED;
}
-
+ if (nocanon
+ && len != alias_match(r->unparsed_uri, ent[i].fake)) {
+ mismatch = 1;
+ use_uri = r->uri;
+ }
found = apr_pstrcat(r->pool, "proxy:", ent[i].real,
- r->uri + len, NULL);
+ use_uri + len, NULL);
}
}
+ if (mismatch) {
+ /* We made a reducing transformation, so we can't safely use
+ * unparsed_uri. Safe fallback is to ignore nocanon.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ "Unescaped URL path matched ProxyPass; ignoring unsafe nocanon");
+ }
+
if (found) {
r->filename = found;
r->handler = "proxy-server";
r->proxyreq = PROXYREQ_REVERSE;
+ if (nocanon && !mismatch) {
+ /* mod_proxy_http needs to be told. Different module. */
+ apr_table_setn(r->notes, "proxy-nocanon", "1");
+ }
return OK;
}
}
@@ -691,8 +719,10 @@ static int proxy_handler(request_rec *r)
/* set configured max-forwards */
maxfwd = conf->maxfwd;
}
- apr_table_set(r->headers_in, "Max-Forwards",
- apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));
+ if (maxfwd >= 0) {
+ apr_table_set(r->headers_in, "Max-Forwards",
+ apr_psprintf(r->pool, "%ld", maxfwd));
+ }
if (r->method_number == M_TRACE) {
core_server_config *coreconf = (core_server_config *)
@@ -708,7 +738,7 @@ static int proxy_handler(request_rec *r)
apr_table_setn(r->notes, "verbose-error-to", "*");
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: TRACE forbidden by server configuration");
- return HTTP_FORBIDDEN;
+ return HTTP_METHOD_NOT_ALLOWED;
}
/* Can't test ap_should_client_block, we aren't ready to send
@@ -859,7 +889,7 @@ static int proxy_handler(request_rec *r)
"If you are using a DSO version of mod_proxy, make sure "
"the proxy submodules are included in the configuration "
"using LoadModule.", r->uri);
- access_status = HTTP_FORBIDDEN;
+ access_status = HTTP_INTERNAL_SERVER_ERROR;
goto cleanup;
}
cleanup:
@@ -994,6 +1024,9 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
= apr_array_append(p, base->cookie_domains, add->cookie_domains);
new->cookie_path_str = base->cookie_path_str;
new->cookie_domain_str = base->cookie_domain_str;
+ new->ftp_directory_charset = add->ftp_directory_charset ?
+ add->ftp_directory_charset :
+ base->ftp_directory_charset;
return new;
}
@@ -1087,6 +1120,7 @@ static const char *
const apr_table_entry_t *elts;
int i;
int use_regex = is_regex;
+ unsigned int flags = 0;
while (*arg) {
word = ap_getword_conf(cmd->pool, &arg);
@@ -1100,8 +1134,12 @@ static const char *
}
f = word;
}
- else if (!r)
+ else if (!r) {
r = word;
+ }
+ else if (!strcasecmp(word,"nocanon")) {
+ flags |= PROXYPASS_NOCANON;
+ }
else {
char *val = strchr(word, '=');
if (!val) {
@@ -1132,6 +1170,7 @@ static const char *
new = apr_array_push(conf->aliases);
new->fake = apr_pstrdup(cmd->pool, f);
new->real = apr_pstrdup(cmd->pool, r);
+ new->flags = flags;
if (use_regex) {
new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
if (new->regex == NULL)
@@ -1146,7 +1185,7 @@ static const char *
arr = apr_table_elts(params);
elts = (const apr_table_entry_t *)arr->elts;
- /* Distinguish the balancer from woker */
+ /* Distinguish the balancer from worker */
if (strncasecmp(r, "balancer:", 9) == 0) {
proxy_balancer *balancer = ap_proxy_get_balancer(cmd->pool, conf, r);
if (!balancer) {
@@ -1169,6 +1208,9 @@ static const char *
const char *err = ap_proxy_add_worker(&worker, cmd->pool, conf, r);
if (err)
return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+ } else {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
+ "worker %s already used by another worker", worker->name);
}
PROXY_COPY_CONF_PARAMS(worker, conf);
@@ -1436,9 +1478,6 @@ static const char *
proxy_server_conf *psf =
ap_get_module_config(parms->server->module_config, &proxy_module);
long s = atol(arg);
- if (s < 0) {
- return "ProxyMaxForwards must be greater or equal to zero..";
- }
psf->maxfwd = s;
psf->maxfwd_set = 1;
@@ -1575,6 +1614,9 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
const char *err;
if ((err = ap_proxy_add_worker(&worker, cmd->pool, conf, name)) != NULL)
return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
+ } else {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
+ "worker %s already used by another worker", worker->name);
}
PROXY_COPY_CONF_PARAMS(worker, conf);
@@ -1685,6 +1727,15 @@ static const char *
return NULL;
}
+static const char *set_ftp_directory_charset(cmd_parms *cmd, void *dconf,
+ const char *arg)
+{
+ proxy_dir_conf *conf = dconf;
+
+ conf->ftp_directory_charset = arg;
+ return NULL;
+}
+
static void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
{
proxy_server_conf *sconf = ap_get_module_config(s->module_config,
@@ -1892,6 +1943,8 @@ static const command_rec proxy_cmds[] =
"Configure Status: proxy status to one of: on | off | full"),
AP_INIT_RAW_ARGS("ProxySet", set_proxy_param, NULL, RSRC_CONF|ACCESS_CONF,
"A balancer or worker name with list of params"),
+ AP_INIT_TAKE1("ProxyFtpDirCharset", set_ftp_directory_charset, NULL,
+ RSRC_CONF|ACCESS_CONF, "Define the character set for proxied FTP listings"),
{NULL}
};
@@ -1978,7 +2031,12 @@ static int proxy_status_hook(request_rec *r, int flags)
ap_rputs("\n\n<table border=\"0\"><tr>"
"<th>SSes</th><th>Timeout</th><th>Method</th>"
"</tr>\n<tr>", r);
- ap_rvputs(r, "<td>", balancer->sticky, NULL);
+ if (balancer->sticky) {
+ ap_rvputs(r, "<td>", balancer->sticky, NULL);
+ }
+ else {
+ ap_rputs("<td> - ", r);
+ }
ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
apr_time_sec(balancer->timeout));
ap_rprintf(r, "<td>%s</td>\n",
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
index e7879525..3944104e 100644
--- a/modules/proxy/mod_proxy.h
+++ b/modules/proxy/mod_proxy.h
@@ -94,7 +94,10 @@ enum enctype {
#endif /*APR_CHARSET_EBCDIC*/
/* default Max-Forwards header setting */
-#define DEFAULT_MAX_FORWARDS 10
+/* Set this to -1, which complies with RFC2616 by not setting
+ * max-forwards if the client didn't send it to us.
+ */
+#define DEFAULT_MAX_FORWARDS -1
/* static information about a remote proxy */
struct proxy_remote {
@@ -106,10 +109,12 @@ struct proxy_remote {
int use_regex; /* simple boolean. True if we have a regex pattern */
};
+#define PROXYPASS_NOCANON 0x01
struct proxy_alias {
const char *real;
const char *fake;
ap_regex_t *regex;
+ unsigned int flags;
};
struct dirconn_entry {
@@ -207,6 +212,7 @@ typedef struct {
apr_array_header_t* cookie_domains;
const apr_strmatch_pattern* cookie_path_str;
const apr_strmatch_pattern* cookie_domain_str;
+ const char *ftp_directory_charset;
} proxy_dir_conf;
typedef struct {
@@ -254,14 +260,16 @@ struct proxy_conn_pool {
#define PROXY_WORKER_NOT_USABLE_BITMAP ( PROXY_WORKER_IN_SHUTDOWN | \
PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR )
-#define PROXY_WORKER_IS_INITIALIZED(f) ( (f)->s->status & \
- PROXY_WORKER_INITIALIZED )
+/* NOTE: these check the shared status */
+#define PROXY_WORKER_IS_INITIALIZED(f) ( (f)->s && \
+ ( (f)->s->status & PROXY_WORKER_INITIALIZED ) )
-#define PROXY_WORKER_IS_STANDBY(f) ( (f)->s->status & \
- PROXY_WORKER_HOT_STANDBY )
+#define PROXY_WORKER_IS_STANDBY(f) ( (f)->s && \
+ ( (f)->s->status & PROXY_WORKER_HOT_STANDBY ) )
-#define PROXY_WORKER_IS_USABLE(f) ( !((f)->s->status & \
- (PROXY_WORKER_NOT_USABLE_BITMAP)) && PROXY_WORKER_IS_INITIALIZED(f) )
+#define PROXY_WORKER_IS_USABLE(f) ( (f)->s && \
+ ( !( (f)->s->status & PROXY_WORKER_NOT_USABLE_BITMAP) ) && \
+ PROXY_WORKER_IS_INITIALIZED(f) )
/* default worker retry timeout in seconds */
#define PROXY_WORKER_DEFAULT_RETRY 60
@@ -328,6 +336,7 @@ struct proxy_worker {
int lbset; /* load balancer cluster set */
apr_interval_time_t ping_timeout;
char ping_timeout_set;
+ char retry_set;
};
/*
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
index d02b4364..bad2b26e 100644
--- a/modules/proxy/mod_proxy_ajp.c
+++ b/modules/proxy/mod_proxy_ajp.c
@@ -131,6 +131,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
int backend_failed = 0;
apr_off_t bb_len;
int data_sent = 0;
+ int headers_sent = 0;
int rv = 0;
apr_int32_t conn_poll_fd;
apr_pollfd_t *conn_poll;
@@ -326,17 +327,24 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
if (status != APR_SUCCESS) {
backend_failed = 1;
}
+ headers_sent = 1;
break;
case CMD_AJP13_SEND_BODY_CHUNK:
/* AJP13_SEND_BODY_CHUNK: piece of data */
status = ajp_parse_data(r, conn->data, &size, &buff);
if (status == APR_SUCCESS) {
+ /* AJP13_SEND_BODY_CHUNK with zero length
+ * is explicit flush message
+ */
if (size == 0) {
- /* AJP13_SEND_BODY_CHUNK with zero length
- * is explicit flush message
- */
- e = apr_bucket_flush_create(r->connection->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(output_brigade, e);
+ if (headers_sent) {
+ e = apr_bucket_flush_create(r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(output_brigade, e);
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "Ignoring flush message received before headers");
+ }
}
else {
e = apr_bucket_transient_create(buff, size,
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
index e2f22235..d2ae88bb 100644
--- a/modules/proxy/mod_proxy_balancer.c
+++ b/modules/proxy/mod_proxy_balancer.c
@@ -19,6 +19,7 @@
#define CORE_PRIVATE
#include "mod_proxy.h"
+#include "scoreboard.h"
#include "ap_mpm.h"
#include "apr_version.h"
#include "apr_hooks.h"
@@ -79,22 +80,37 @@ static int init_balancer_members(proxy_server_conf *conf, server_rec *s,
{
int i;
proxy_worker *workers;
+ int worker_is_initialized;
+ proxy_worker_stat *slot;
workers = (proxy_worker *)balancer->workers->elts;
for (i = 0; i < balancer->workers->nelts; i++) {
+ worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(workers);
+ if (!worker_is_initialized) {
+ /*
+ * If the worker is not initialized check whether its scoreboard
+ * slot is already initialized.
+ */
+ slot = (proxy_worker_stat *) ap_get_scoreboard_lb(workers->id);
+ if (slot) {
+ worker_is_initialized = slot->status & PROXY_WORKER_INITIALIZED;
+ }
+ else {
+ worker_is_initialized = 0;
+ }
+ }
ap_proxy_initialize_worker_share(conf, workers, s);
ap_proxy_initialize_worker(workers, s);
+ if (!worker_is_initialized) {
+ /* Set to the original configuration */
+ workers->s->lbstatus = workers->s->lbfactor =
+ (workers->lbfactor ? workers->lbfactor : 1);
+ workers->s->lbset = workers->lbset;
+ }
++workers;
}
- workers = (proxy_worker *)balancer->workers->elts;
- for (i = 0; i < balancer->workers->nelts; i++) {
- /* Set to the original configuration */
- workers[i].s->lbstatus = workers[i].s->lbfactor =
- (workers[i].lbfactor ? workers[i].lbfactor : 1);
- workers[i].s->lbset = workers[i].lbset;
- }
/* Set default number of attempts to the number of
* workers.
*/
@@ -622,7 +638,7 @@ static int balancer_handler(request_rec *r)
proxy_worker *ws;
ws = ap_proxy_get_worker(r->pool, conf, name);
- if (ws) {
+ if (bsel && ws) {
worker = (proxy_worker *)bsel->workers->elts;
for (n = 0; n < bsel->workers->nelts; n++) {
if (strcasecmp(worker->name, ws->name) == 0) {
@@ -634,33 +650,10 @@ static int balancer_handler(request_rec *r)
}
}
/* First set the params */
- if (bsel) {
- const char *val;
- if ((val = apr_table_get(params, "ss"))) {
- if (strlen(val))
- bsel->sticky = apr_pstrdup(conf->pool, val);
- else
- bsel->sticky = NULL;
- }
- if ((val = apr_table_get(params, "tm"))) {
- int ival = atoi(val);
- if (ival >= 0)
- bsel->timeout = apr_time_from_sec(ival);
- }
- if ((val = apr_table_get(params, "fa"))) {
- int ival = atoi(val);
- if (ival >= 0)
- bsel->max_attempts = ival;
- bsel->max_attempts_set = 1;
- }
- if ((val = apr_table_get(params, "lm"))) {
- proxy_balancer_method *provider;
- provider = ap_lookup_provider(PROXY_LBMETHOD, val, "0");
- if (provider) {
- bsel->lbmethod = provider;
- }
- }
- }
+ /*
+ * Note that it is not possible set the proxy_balancer because it is not
+ * in shared memory.
+ */
if (wsel) {
const char *val;
if ((val = apr_table_get(params, "lf"))) {
@@ -727,7 +720,7 @@ static int balancer_handler(request_rec *r)
ap_rputs("</httpd:manager>", r);
}
else {
- ap_set_content_type(r, "text/html");
+ ap_set_content_type(r, "text/html; charset=ISO-8859-1");
ap_rputs(DOCTYPE_HTML_3_2
"<html><head><title>Balancer Manager</title></head>\n", r);
ap_rputs("<body><h1>Load Balancer Manager for ", r);
@@ -740,14 +733,16 @@ static int balancer_handler(request_rec *r)
for (i = 0; i < conf->balancers->nelts; i++) {
ap_rputs("<hr />\n<h3>LoadBalancer Status for ", r);
- ap_rvputs(r, "<a href=\"", r->uri, "?b=",
- balancer->name + sizeof("balancer://") - 1,
- "\">", NULL);
- ap_rvputs(r, balancer->name, "</a></h3>\n\n", NULL);
+ ap_rvputs(r, balancer->name, "</h3>\n\n", NULL);
ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
"<th>StickySession</th><th>Timeout</th><th>FailoverAttempts</th><th>Method</th>"
"</tr>\n<tr>", r);
- ap_rvputs(r, "<td>", balancer->sticky, NULL);
+ if (balancer->sticky) {
+ ap_rvputs(r, "<td>", balancer->sticky, NULL);
+ }
+ else {
+ ap_rputs("<td> - ", r);
+ }
ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
apr_time_sec(balancer->timeout));
ap_rprintf(r, "<td>%d</td>\n", balancer->max_attempts);
@@ -769,8 +764,10 @@ static int balancer_handler(request_rec *r)
ap_escape_uri(r->pool, worker->name),
"\">", NULL);
ap_rvputs(r, worker->name, "</a></td>", NULL);
- ap_rvputs(r, "<td>", worker->s->route, NULL);
- ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
+ ap_rvputs(r, "<td>", ap_escape_html(r->pool, worker->s->route),
+ NULL);
+ ap_rvputs(r, "</td><td>",
+ ap_escape_html(r->pool, worker->s->redirect), NULL);
ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor);
ap_rprintf(r, "<td>%d</td><td>", worker->s->lbset);
if (worker->s->status & PROXY_WORKER_DISABLED)
@@ -808,10 +805,12 @@ static int balancer_handler(request_rec *r)
ap_rputs("<tr><td>LB Set:</td><td><input name=\"ls\" type=text ", r);
ap_rprintf(r, "value=\"%d\"></td></tr>\n", wsel->s->lbset);
ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
- ap_rvputs(r, "value=\"", wsel->route, NULL);
+ ap_rvputs(r, "value=\"", ap_escape_html(r->pool, wsel->s->route),
+ NULL);
ap_rputs("\"></td></tr>\n", r);
ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
- ap_rvputs(r, "value=\"", wsel->redirect, NULL);
+ ap_rvputs(r, "value=\"", ap_escape_html(r->pool, wsel->s->redirect),
+ NULL);
ap_rputs("\"></td></tr>\n", r);
ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r);
if (wsel->s->status & PROXY_WORKER_DISABLED)
@@ -828,41 +827,6 @@ static int balancer_handler(request_rec *r)
"\">\n</form>\n", NULL);
ap_rputs("<hr />\n", r);
}
- else if (bsel) {
- ap_rputs("<h3>Edit balancer settings for ", r);
- ap_rvputs(r, bsel->name, "</h3>\n", NULL);
- ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
- ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
- ap_rputs("<table><tr><td>StickySession Identifier:</td><td><input name=\"ss\" type=text ", r);
- if (bsel->sticky)
- ap_rvputs(r, "value=\"", bsel->sticky, "\"", NULL);
- ap_rputs("></td><tr>\n<tr><td>Timeout:</td><td><input name=\"tm\" type=text ", r);
- ap_rprintf(r, "value=\"%" APR_TIME_T_FMT "\"></td></tr>\n",
- apr_time_sec(bsel->timeout));
- ap_rputs("<tr><td>Failover Attempts:</td><td><input name=\"fa\" type=text ", r);
- ap_rprintf(r, "value=\"%d\"></td></tr>\n",
- bsel->max_attempts);
- ap_rputs("<tr><td>LB Method:</td><td><select name=\"lm\">", r);
- {
- apr_array_header_t *methods;
- ap_list_provider_names_t *method;
- int i;
- methods = ap_list_provider_names(r->pool, PROXY_LBMETHOD, "0");
- method = (ap_list_provider_names_t *)methods->elts;
- for (i = 0; i < methods->nelts; i++) {
- ap_rprintf(r, "<option value=\"%s\" %s>%s</option>", method->provider_name,
- (!strcasecmp(bsel->lbmethod->name, method->provider_name)) ? "selected" : "",
- method->provider_name);
- method++;
- }
- }
- ap_rputs("</select></td></tr>\n", r);
- ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
- ap_rvputs(r, "</table>\n<input type=hidden name=\"b\" ", NULL);
- ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
- "\">\n</form>\n", NULL);
- ap_rputs("<hr />\n", r);
- }
ap_rputs(ap_psignature("",r), r);
ap_rputs("</body></html>\n", r);
}
diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c
index eac6eff6..3cacac6e 100644
--- a/modules/proxy/mod_proxy_ftp.c
+++ b/modules/proxy/mod_proxy_ftp.c
@@ -517,6 +517,14 @@ static apr_status_t proxy_send_dir_filter(ap_filter_t *f,
}
filename = strrchr(ctx->buffer, ' ');
+ if (filename == NULL) {
+ /* Line is broken. Ignore it. */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+ "proxy_ftp: could not parse line %s", ctx->buffer);
+ /* erase buffer for next time around */
+ ctx->buffer[0] = 0;
+ continue; /* while state is BODY */
+ }
*(filename++) = '\0';
/* handle filenames with spaces in 'em */
@@ -1682,7 +1690,13 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker,
/* set content-type */
if (dirlisting) {
- ap_set_content_type(r, "text/html");
+ proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
+ &proxy_module);
+
+ ap_set_content_type(r, apr_pstrcat(p, "text/html;charset=",
+ dconf->ftp_directory_charset ?
+ dconf->ftp_directory_charset :
+ "ISO-8859-1", NULL));
}
else {
if (r->content_type) {
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index 534cbb5d..e5f654bb 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -17,6 +17,7 @@
/* HTTP routines for Apache proxy */
#include "mod_proxy.h"
+#include "ap_regex.h"
module AP_MODULE_DECLARE_DATA proxy_http_module;
@@ -80,7 +81,26 @@ static int proxy_http_canon(request_rec *r, char *url)
search = r->args;
/* process path */
- path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, r->proxyreq);
+ /* In a reverse proxy, our URL has been processed, so canonicalise
+ * unless proxy-nocanon is set to say it's raw
+ * In a forward proxy, we have and MUST NOT MANGLE the original.
+ */
+ switch (r->proxyreq) {
+ default: /* wtf are we doing here? */
+ case PROXYREQ_REVERSE:
+ if (apr_table_get(r->notes, "proxy-nocanon")) {
+ path = url; /* this is the raw path */
+ }
+ else {
+ path = ap_proxy_canonenc(r->pool, url, strlen(url),
+ enc_path, 0, r->proxyreq);
+ }
+ break;
+ case PROXYREQ_PROXY:
+ path = url;
+ break;
+ }
+
if (path == NULL)
return HTTP_BAD_REQUEST;
@@ -98,29 +118,102 @@ static int proxy_http_canon(request_rec *r, char *url)
}
/* Clear all connection-based headers from the incoming headers table */
-static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
+typedef struct header_dptr {
+ apr_pool_t *pool;
+ apr_table_t *table;
+ apr_time_t time;
+} header_dptr;
+static ap_regex_t *warn_rx;
+static int clean_warning_headers(void *data, const char *key, const char *val)
{
+ apr_table_t *headers = ((header_dptr*)data)->table;
+ apr_pool_t *pool = ((header_dptr*)data)->pool;
+ char *warning;
+ char *date;
+ apr_time_t warn_time;
+ const int nmatch = 3;
+ ap_regmatch_t pmatch[3];
+
+ if (headers == NULL) {
+ ((header_dptr*)data)->table = headers = apr_table_make(pool, 2);
+ }
+/*
+ * Parse this, suckers!
+ *
+ * Warning = "Warning" ":" 1#warning-value
+ *
+ * warning-value = warn-code SP warn-agent SP warn-text
+ * [SP warn-date]
+ *
+ * warn-code = 3DIGIT
+ * warn-agent = ( host [ ":" port ] ) | pseudonym
+ * ; the name or pseudonym of the server adding
+ * ; the Warning header, for use in debugging
+ * warn-text = quoted-string
+ * warn-date = <"> HTTP-date <">
+ *
+ * Buggrit, use a bloomin' regexp!
+ * (\d{3}\s+\S+\s+\".*?\"(\s+\"(.*?)\")?) --> whole in $1, date in $3
+ */
+ while (!ap_regexec(warn_rx, val, nmatch, pmatch, 0)) {
+ warning = apr_pstrndup(pool, val+pmatch[0].rm_so,
+ pmatch[0].rm_eo - pmatch[0].rm_so);
+ warn_time = 0;
+ if (pmatch[2].rm_eo > pmatch[2].rm_so) {
+ /* OK, we have a date here */
+ date = apr_pstrndup(pool, val+pmatch[2].rm_so,
+ pmatch[2].rm_eo - pmatch[2].rm_so);
+ warn_time = apr_date_parse_http(date);
+ }
+ if (!warn_time || (warn_time == ((header_dptr*)data)->time)) {
+ apr_table_addn(headers, key, warning);
+ }
+ val += pmatch[0].rm_eo;
+ }
+ return 1;
+}
+static apr_table_t *ap_proxy_clean_warnings(apr_pool_t *p, apr_table_t *headers)
+{
+ header_dptr x;
+ x.pool = p;
+ x.table = NULL;
+ x.time = apr_date_parse_http(apr_table_get(headers, "Date"));
+ apr_table_do(clean_warning_headers, &x, headers, "Warning", NULL);
+ if (x.table != NULL) {
+ apr_table_unset(headers, "Warning");
+ return apr_table_overlay(p, headers, x.table);
+ }
+ else {
+ return headers;
+ }
+}
+static int clear_conn_headers(void *data, const char *key, const char *val)
+{
+ apr_table_t *headers = ((header_dptr*)data)->table;
+ apr_pool_t *pool = ((header_dptr*)data)->pool;
const char *name;
- char *next = apr_pstrdup(p, apr_table_get(headers, "Connection"));
-
- apr_table_unset(headers, "Proxy-Connection");
- if (!next)
- return;
-
+ char *next = apr_pstrdup(pool, val);
while (*next) {
name = next;
while (*next && !apr_isspace(*next) && (*next != ',')) {
++next;
}
while (*next && (apr_isspace(*next) || (*next == ','))) {
- *next = '\0';
- ++next;
+ *next++ = '\0';
}
apr_table_unset(headers, name);
}
+ return 1;
+}
+static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
+{
+ header_dptr x;
+ x.pool = p;
+ x.table = headers;
+ apr_table_unset(headers, "Proxy-Connection");
+ apr_table_do(clear_conn_headers, &x, headers, "Connection", NULL);
apr_table_unset(headers, "Connection");
}
-
static void add_te_chunked(apr_pool_t *p,
apr_bucket_alloc_t *bucket_alloc,
apr_bucket_brigade *header_brigade)
@@ -755,19 +848,21 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
|| !strcasecmp(headers_in[counter].key, "Trailer")
|| !strcasecmp(headers_in[counter].key, "Upgrade")
- /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
- * suppressed if THIS server requested the authentication,
- * not when a frontend proxy requested it!
- *
- * The solution to this problem is probably to strip out
- * the Proxy-Authorisation header in the authorisation
- * code itself, not here. This saves us having to signal
- * somehow whether this request was authenticated or not.
- */
- || !strcasecmp(headers_in[counter].key,"Proxy-Authorization")
- || !strcasecmp(headers_in[counter].key,"Proxy-Authenticate")) {
+ ) {
continue;
}
+ /* Do we want to strip Proxy-Authorization ?
+ * If we haven't used it, then NO
+ * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
+ * So let's make it configurable by env.
+ */
+ if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) {
+ if (r->user != NULL) { /* we've authenticated */
+ if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
+ continue;
+ }
+ }
+ }
/* Skip Transfer-Encoding and Content-Length for now.
*/
@@ -1233,6 +1328,9 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
int pread_len = 0;
apr_table_t *save_table;
int backend_broke = 0;
+ static const char *hop_by_hop_hdrs[] =
+ {"Keep-Alive", "Proxy-Authenticate", "TE", "Trailer", "Upgrade", NULL};
+ int i;
bb = apr_brigade_create(p, c->bucket_alloc);
@@ -1373,6 +1471,13 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
}
ap_proxy_pre_http_request(origin,rp);
+ /* Clear hop-by-hop headers */
+ for (i=0; hop_by_hop_hdrs[i]; ++i) {
+ apr_table_unset(r->headers_out, hop_by_hop_hdrs[i]);
+ }
+ /* Delete warnings with wrong date */
+ r->headers_out = ap_proxy_clean_warnings(p, r->headers_out);
+
/* handle Via header in response */
if (conf->viaopt != via_off && conf->viaopt != via_block) {
const char *server_name = ap_get_server_name(r);
@@ -1384,8 +1489,8 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
if (server_name == r->hostname)
server_name = r->server->server_hostname;
/* create a "Via:" response header entry and merge it */
- apr_table_mergen(r->headers_out, "Via",
- (conf->viaopt == via_full)
+ apr_table_addn(r->headers_out, "Via",
+ (conf->viaopt == via_full)
? apr_psprintf(p, "%d.%d %s%s (%s)",
HTTP_VERSION_MAJOR(r->proto_num),
HTTP_VERSION_MINOR(r->proto_num),
@@ -1415,9 +1520,33 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
interim_response = ap_is_HTTP_INFO(r->status);
if (interim_response) {
+ /* RFC2616 tells us to forward this.
+ *
+ * OTOH, an interim response here may mean the backend
+ * is playing sillybuggers. The Client didn't ask for
+ * it within the defined HTTP/1.1 mechanisms, and if
+ * it's an extension, it may also be unsupported by us.
+ *
+ * There's also the possibility that changing existing
+ * behaviour here might break something.
+ *
+ * So let's make it configurable.
+ */
+ const char *policy = apr_table_get(r->subprocess_env,
+ "proxy-interim-response");
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
"proxy: HTTP: received interim %d response",
r->status);
+ if (!policy || !strcasecmp(policy, "RFC")) {
+ ap_send_interim_response(r, 1);
+ }
+ /* FIXME: refine this to be able to specify per-response-status
+ * policies and maybe also add option to bail out with 502
+ */
+ else if (strcasecmp(policy, "Suppress")) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
+ "undefined proxy interim response policy");
+ }
}
/* Moved the fixups of Date headers and those affected by
* ProxyPassReverse/etc from here to ap_proxy_read_headers
@@ -1754,11 +1883,17 @@ cleanup:
}
return status;
}
-
+static apr_status_t warn_rx_free(void *p)
+{
+ ap_pregfree((apr_pool_t*)p, warn_rx);
+ return APR_SUCCESS;
+}
static void ap_proxy_http_register_hook(apr_pool_t *p)
{
proxy_hook_scheme_handler(proxy_http_handler, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_canon_handler(proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);
+ warn_rx = ap_pregcomp(p, "[0-9]{3}[ \t]+[^ \t]+[ \t]+\"[^\"]*\"([ \t]+\"([^\"]+)\")?", 0);
+ apr_pool_cleanup_register(p, p, warn_rx_free, apr_pool_cleanup_null);
}
module AP_MODULE_DECLARE_DATA proxy_http_module = {
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index 934f9027..910f3610 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -495,7 +495,7 @@ PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *mes
apr_table_setn(r->notes, "error-notes",
apr_pstrcat(r->pool,
"The proxy server could not handle the request "
- "<em><a href=\"", ap_escape_uri(r->pool, r->uri),
+ "<em><a href=\"", ap_escape_html(r->pool, r->uri),
"\">", ap_escape_html(r->pool, r->method),
"&nbsp;",
ap_escape_html(r->pool, r->uri), "</a></em>.<p>\n"
@@ -907,6 +907,7 @@ PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *c
return HTTP_FORBIDDEN;
}
while (conf_addr) {
+ uri_addr = src_uri_addr;
while (uri_addr) {
char *conf_ip;
char *uri_ip;
@@ -995,12 +996,14 @@ PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade
len = (bufflen-1)-(pos-buff);
}
if (len > 0) {
- pos = apr_cpystrn(pos, response, len);
+ memcpy(pos, response, len);
+ pos += len;
}
}
APR_BUCKET_REMOVE(e);
apr_bucket_destroy(e);
}
+ *pos = '\0';
}
return APR_SUCCESS;
@@ -1647,7 +1650,7 @@ PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf,
void *score = NULL;
#endif
- if (worker->s && PROXY_WORKER_IS_INITIALIZED(worker)) {
+ if (PROXY_WORKER_IS_INITIALIZED(worker)) {
/* The worker share is already initialized */
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: worker %s already initialized",
@@ -1719,7 +1722,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser
}
/* Set default parameters */
- if (!worker->retry) {
+ if (!worker->retry_set) {
worker->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);
}
/* By default address is reusable */
@@ -2053,7 +2056,7 @@ static int is_socket_connected(apr_socket_t *socket)
else
return 0;
}
- else if (APR_STATUS_IS_EAGAIN(status)) {
+ else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) {
return 1;
}
return 0;