diff options
author | Stefan Fritsch <sf@sfritsch.de> | 2011-12-27 19:42:17 +0100 |
---|---|---|
committer | Stefan Fritsch <sf@sfritsch.de> | 2011-12-27 19:42:17 +0100 |
commit | 9e615cb6aa4afcee97f8a1646e5a586261a7b81f (patch) | |
tree | 0e09fde2404555dc5daf167b38243b5f89c16549 /modules/proxy | |
parent | 1acac7a6b494db24f8f58e44dab7657b6de68742 (diff) | |
download | apache2-9e615cb6aa4afcee97f8a1646e5a586261a7b81f.tar.gz |
Upstream tarball 2.2.8upstream/2.2.8
Diffstat (limited to 'modules/proxy')
-rw-r--r-- | modules/proxy/ajp.h | 2 | ||||
-rw-r--r-- | modules/proxy/ajp_header.c | 14 | ||||
-rw-r--r-- | modules/proxy/mod_proxy.c | 106 | ||||
-rw-r--r-- | modules/proxy/mod_proxy.h | 23 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_ajp.c | 18 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_balancer.c | 124 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_ftp.c | 16 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_http.c | 185 | ||||
-rw-r--r-- | modules/proxy/proxy_util.c | 13 |
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), " ", 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; |