diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/config.c | 76 | ||||
-rw-r--r-- | server/core.c | 69 | ||||
-rw-r--r-- | server/main.c | 5 | ||||
-rw-r--r-- | server/mpm/event/event.c | 37 | ||||
-rw-r--r-- | server/mpm/winnt/child.c | 11 | ||||
-rw-r--r-- | server/mpm/worker/worker.c | 39 | ||||
-rw-r--r-- | server/protocol.c | 2 | ||||
-rw-r--r-- | server/scoreboard.c | 92 | ||||
-rw-r--r-- | server/util.c | 180 | ||||
-rw-r--r-- | server/util_script.c | 15 |
10 files changed, 435 insertions, 91 deletions
diff --git a/server/config.c b/server/config.c index bca8b53c..7c7a1e00 100644 --- a/server/config.c +++ b/server/config.c @@ -1115,7 +1115,11 @@ static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, args = ap_resolve_env(temp_pool, l); #endif - cmd_name = ap_getword_conf(p, &args); + /* The first word is the name of a directive. We can safely use the + * 'temp_pool' for it. If it matches the name of a known directive, we + * can reference the string within the module if needed. Otherwise, we + * can still make a copy in the 'p' pool. */ + cmd_name = ap_getword_conf(temp_pool, &args); if (*cmd_name == '\0') { /* Note: this branch should not occur. An empty line should have * triggered the exit further above. @@ -1136,10 +1140,11 @@ static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, newdir = apr_pcalloc(p, sizeof(ap_directive_t)); newdir->filename = parms->config_file->name; newdir->line_num = parms->config_file->line_number; - newdir->directive = cmd_name; newdir->args = apr_pstrdup(p, args); if ((cmd = ap_find_command_in_modules(cmd_name, &mod)) != NULL) { + newdir->directive = cmd->name; + if (cmd->req_override & EXEC_ON_READ) { ap_directive_t *sub_tree = NULL; @@ -1173,6 +1178,11 @@ static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, return retval; } } + else { + /* No known directive found? Make a copy of what we have parsed. */ + newdir->directive = apr_pstrdup(p, cmd_name); + } + if (cmd_name[0] == '<') { if (cmd_name[1] != '/') { @@ -1780,6 +1790,54 @@ static int fname_alphasort(const void *fn1, const void *fn2) return strcmp(f1->fname,f2->fname); } +/** + * Used by -D DUMP_INCLUDES to output the config file "tree". + */ +static void dump_config_name(const char *fname, apr_pool_t *p) +{ + unsigned i, recursion, line_number; + void *data; + apr_file_t *out = NULL; + + apr_file_open_stdout(&out, p); + + /* ap_include_sentinel is defined by the core Include directive; use it to + * figure out how deep in the stack we are. + */ + apr_pool_userdata_get(&data, "ap_include_sentinel", p); + + if (data) { + recursion = *(unsigned *)data; + } else { + recursion = 0; + } + + /* Indent once for each level. */ + for (i = 0; i < (recursion + 1); ++i) { + apr_file_printf(out, " "); + } + + /* ap_include_lineno is similarly defined to tell us where in the last + * config file we were. + */ + apr_pool_userdata_get(&data, "ap_include_lineno", p); + + if (data) { + line_number = *(unsigned *)data; + } else { + line_number = 0; + } + + /* Print the line number and the name of the parsed file. */ + if (line_number > 0) { + apr_file_printf(out, "(%u)", line_number); + } else { + apr_file_printf(out, "(*)"); + } + + apr_file_printf(out, " %s\n", fname); +} + AP_DECLARE(const char *) ap_process_resource_config(server_rec *s, const char *fname, ap_directive_t **conftree, @@ -1804,6 +1862,10 @@ AP_DECLARE(const char *) ap_process_resource_config(server_rec *s, fname, &rv); } + if (ap_exists_config_define("DUMP_INCLUDES")) { + dump_config_name(fname, p); + } + parms.config_file = cfp; error = ap_build_config(&parms, p, ptemp, conftree); ap_cfg_closefile(cfp); @@ -2397,6 +2459,16 @@ AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp, init_config_globals(p); + if (ap_exists_config_define("DUMP_INCLUDES")) { + apr_file_t *out = NULL; + apr_file_open_stdout(&out, p); + + /* Included files will be dumped as the config is walked; print a + * header. + */ + apr_file_printf(out, "Included configuration files:\n"); + } + /* All server-wide config files now have the SAME syntax... */ error = process_command_config(s, ap_server_pre_read_config, conftree, p, ptemp); diff --git a/server/core.c b/server/core.c index b3d72f43..e8c1ef67 100644 --- a/server/core.c +++ b/server/core.c @@ -409,6 +409,15 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) conf->cgi_pass_auth = new->cgi_pass_auth != AP_CGI_PASS_AUTH_UNSET ? new->cgi_pass_auth : base->cgi_pass_auth; + if (new->cgi_var_rules) { + if (!conf->cgi_var_rules) { + conf->cgi_var_rules = new->cgi_var_rules; + } + else { + conf->cgi_var_rules = apr_hash_overlay(a, new->cgi_var_rules, conf->cgi_var_rules); + } + } + AP_CORE_MERGE_FLAG(qualify_redirect_url, conf, base, new); return (void*)conf; @@ -966,7 +975,10 @@ AP_DECLARE(const char *) ap_get_useragent_host(request_rec *r, int hostname_lookups; int ignored_str_is_ip; - if (r->useragent_addr == conn->client_addr) { + /* Guard here when examining the host before the read_request hook + * has populated an r->useragent_addr + */ + if (!r->useragent_addr || (r->useragent_addr == conn->client_addr)) { return ap_get_remote_host(conn, r->per_dir_config, type, str_is_ip); } @@ -1547,7 +1559,9 @@ static const char *set_document_root(cmd_parms *cmd, void *dummy, conf->ap_document_root = arg; } else { - return "DocumentRoot must be a directory"; + return apr_psprintf(cmd->pool, + "DocumentRoot '%s' is not a directory, or is not readable", + arg); } } return NULL; @@ -1796,6 +1810,31 @@ static const char *set_cgi_pass_auth(cmd_parms *cmd, void *d_, int flag) return NULL; } +static const char *set_cgi_var(cmd_parms *cmd, void *d_, + const char *var, const char *rule_) +{ + core_dir_config *d = d_; + char *rule = apr_pstrdup(cmd->pool, rule_); + + ap_str_tolower(rule); + + if (!strcmp(var, "REQUEST_URI")) { + if (strcmp(rule, "current-uri") && strcmp(rule, "original-uri")) { + return "Valid rules for REQUEST_URI are 'current-uri' and 'original-uri'"; + } + } + else { + return apr_pstrcat(cmd->pool, "Unrecognized CGI variable: \"", + var, "\"", NULL); + } + + if (!d->cgi_var_rules) { + d->cgi_var_rules = apr_hash_make(cmd->pool); + } + apr_hash_set(d->cgi_var_rules, var, APR_HASH_KEY_STRING, rule); + return NULL; +} + static const char *set_qualify_redirect_url(cmd_parms *cmd, void *d_, int flag) { core_dir_config *d = d_; @@ -3133,6 +3172,10 @@ static const char *include_config (cmd_parms *cmd, void *dummy, int optional = cmd->cmd->cmd_data ? 1 : 0; void *data; + /* NOTE: ap_include_sentinel is also used by ap_process_resource_config() + * during DUMP_INCLUDES; don't change its type or remove it without updating + * the other. + */ apr_pool_userdata_get(&data, "ap_include_sentinel", cmd->pool); if (data) { recursion = data; @@ -3157,6 +3200,24 @@ static const char *include_config (cmd_parms *cmd, void *dummy, name, NULL); } + if (ap_exists_config_define("DUMP_INCLUDES")) { + unsigned *line_number; + + /* NOTE: ap_include_lineno is used by ap_process_resource_config() + * during DUMP_INCLUDES; don't change its type or remove it without + * updating the other. + */ + apr_pool_userdata_get(&data, "ap_include_lineno", cmd->pool); + if (data) { + line_number = data; + } else { + data = line_number = apr_palloc(cmd->pool, sizeof(*line_number)); + apr_pool_userdata_setn(data, "ap_include_lineno", NULL, cmd->pool); + } + + *line_number = cmd->config_file->line_number; + } + error = ap_process_fnmatch_configs(cmd->server, conffile, &conftree, cmd->pool, cmd->temp_pool, optional); @@ -4293,6 +4354,8 @@ AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF, AP_INIT_FLAG("CGIPassAuth", set_cgi_pass_auth, NULL, OR_AUTHCFG, "Controls whether HTTP authorization headers, normally hidden, will " "be passed to scripts"), +AP_INIT_TAKE2("CGIVar", set_cgi_var, NULL, OR_FILEINFO, + "Controls how some CGI variables are set"), AP_INIT_FLAG("QualifyRedirectURL", set_qualify_redirect_url, NULL, OR_FILEINFO, "Controls whether HTTP authorization headers, normally hidden, will " "be passed to scripts"), @@ -4841,7 +4904,7 @@ static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server, conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec)); c->sbh = sbh; - (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL); + ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL); /* Got a connection structure, so initialize what fields we can * (the rest are zeroed out by pcalloc). diff --git a/server/main.c b/server/main.c index cfa5a9d3..c5f35b9b 100644 --- a/server/main.c +++ b/server/main.c @@ -426,6 +426,8 @@ static void usage(process_rec *process) ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, " -M : a synonym for -t -D DUMP_MODULES"); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + " -t -D DUMP_INCLUDES: show all included configuration files"); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, " -t : run syntax check for config files"); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, " -T : start without DocumentRoot(s) check"); @@ -524,6 +526,9 @@ int main(int argc, const char * const argv[]) /* Setting -D DUMP_MODULES is equivalent to setting -M */ else if (strcmp(opt_arg, "DUMP_MODULES") == 0) ap_run_mode = AP_SQ_RM_CONFIG_DUMP; + /* Setting -D DUMP_INCLUDES is a type of configuration dump */ + else if (strcmp(opt_arg, "DUMP_INCLUDES") == 0) + ap_run_mode = AP_SQ_RM_CONFIG_DUMP; break; case 'e': diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 2418471f..baeb5a76 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -1114,7 +1114,7 @@ read_request: if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) { ap_filter_t *output_filter = c->output_filters; apr_status_t rv; - ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c); + ap_update_child_status(sbh, SERVER_BUSY_WRITE, NULL); while (output_filter->next != NULL) { output_filter = output_filter->next; } @@ -1910,7 +1910,8 @@ static void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy) } ap_update_child_status_from_indexes(process_slot, thread_slot, - dying ? SERVER_GRACEFUL : SERVER_READY, NULL); + dying ? SERVER_GRACEFUL + : SERVER_READY, NULL); worker_pop: if (workers_may_exit) { break; @@ -1965,9 +1966,8 @@ static void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy) } ap_update_child_status_from_indexes(process_slot, thread_slot, - dying ? SERVER_DEAD : - SERVER_GRACEFUL, - (request_rec *) NULL); + dying ? SERVER_DEAD + : SERVER_GRACEFUL, NULL); apr_thread_exit(thd, APR_SUCCESS); return NULL; @@ -2017,8 +2017,7 @@ static void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy) thread_starter *ts = dummy; apr_thread_t **threads = ts->threads; apr_threadattr_t *thread_attr = ts->threadattr; - int child_num_arg = ts->child_num_arg; - int my_child_num = child_num_arg; + int my_child_num = ts->child_num_arg; proc_info *my_info; apr_status_t rv; int i; @@ -2102,7 +2101,7 @@ static void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy) /* threads_per_child does not include the listener thread */ for (i = 0; i < threads_per_child; i++) { int status = - ap_scoreboard_image->servers[child_num_arg][i].status; + ap_scoreboard_image->servers[my_child_num][i].status; if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { continue; @@ -2524,13 +2523,14 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) int all_dead_threads = 1; int child_threads_active = 0; - if (i >= retained->max_daemons_limit - && totally_free_length == retained->idle_spawn_rate[child_bucket]) + if (i >= retained->max_daemons_limit && + totally_free_length == retained->idle_spawn_rate[child_bucket]) { /* short cut if all active processes have been examined and * enough empty scoreboard slots have been found */ break; + } ps = &ap_scoreboard_image->parent[i]; for (j = 0; j < threads_per_child; j++) { ws = &ap_scoreboard_image->servers[i][j]; @@ -2728,8 +2728,7 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets) for (i = 0; i < threads_per_child; i++) ap_update_child_status_from_indexes(child_slot, i, - SERVER_DEAD, - (request_rec *) NULL); + SERVER_DEAD, NULL); event_note_child_killed(child_slot, 0, 0); ps = &ap_scoreboard_image->parent[child_slot]; @@ -2830,10 +2829,16 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) ap_daemons_limit = num_buckets; if (ap_daemons_to_start < num_buckets) ap_daemons_to_start = num_buckets; - if (min_spare_threads < threads_per_child * num_buckets) - min_spare_threads = threads_per_child * num_buckets; - if (max_spare_threads < min_spare_threads + threads_per_child * num_buckets) - max_spare_threads = min_spare_threads + threads_per_child * num_buckets; + /* We want to create as much children at a time as the number of buckets, + * so to optimally accept connections (evenly distributed accross buckets). + * Thus min_spare_threads should at least maintain num_buckets children, + * and max_spare_threads allow num_buckets more children w/o triggering + * immediately (e.g. num_buckets idle threads margin, one per bucket). + */ + if (min_spare_threads < threads_per_child * (num_buckets - 1) + num_buckets) + min_spare_threads = threads_per_child * (num_buckets - 1) + num_buckets; + if (max_spare_threads < min_spare_threads + (threads_per_child + 1) * num_buckets) + max_spare_threads = min_spare_threads + (threads_per_child + 1) * num_buckets; /* If we're doing a graceful_restart then we're going to see a lot * of children exiting immediately when we get into the main loop diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index e4d1c150..dee35df5 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -894,8 +894,7 @@ static DWORD __stdcall worker_main(void *thread_num_val) } } - ap_update_child_status_from_indexes(0, thread_num, SERVER_DEAD, - (request_rec *) NULL); + ap_update_child_status_from_indexes(0, thread_num, SERVER_DEAD, NULL); return 0; } @@ -1314,13 +1313,13 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid) threads_created); } for (i = 0; i < threads_created; i++) { - int *score_idx; + int *idx; TerminateThread(child_handles[i], 1); CloseHandle(child_handles[i]); /* Reset the scoreboard entry for the thread we just whacked */ - score_idx = apr_hash_get(ht, &child_handles[i], sizeof(HANDLE)); - if (score_idx) { - ap_update_child_status_from_indexes(0, *score_idx, SERVER_DEAD, NULL); + idx = apr_hash_get(ht, &child_handles[i], sizeof(HANDLE)); + if (idx) { + ap_update_child_status_from_indexes(0, *idx, SERVER_DEAD, NULL); } } ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, APLOGNO(00364) diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index 24aa46bd..d0ed6040 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -928,7 +928,8 @@ static void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy) ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid; ap_scoreboard_image->servers[process_slot][thread_slot].tid = apr_os_thread_current(); ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->my_generation; - ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL); + ap_update_child_status_from_indexes(process_slot, thread_slot, + SERVER_STARTING, NULL); #ifdef HAVE_PTHREAD_KILL unblock_signal(WORKER_SIGNAL); @@ -949,7 +950,8 @@ static void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy) is_idle = 1; } - ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY, NULL); + ap_update_child_status_from_indexes(process_slot, thread_slot, + SERVER_READY, NULL); worker_pop: if (workers_may_exit) { break; @@ -995,7 +997,8 @@ worker_pop: } ap_update_child_status_from_indexes(process_slot, thread_slot, - (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL); + dying ? SERVER_DEAD + : SERVER_GRACEFUL, NULL); apr_thread_exit(thd, APR_SUCCESS); return NULL; @@ -1043,8 +1046,7 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) thread_starter *ts = dummy; apr_thread_t **threads = ts->threads; apr_threadattr_t *thread_attr = ts->threadattr; - int child_num_arg = ts->child_num_arg; - int my_child_num = child_num_arg; + int my_child_num = ts->child_num_arg; proc_info *my_info; apr_status_t rv; int i; @@ -1078,7 +1080,7 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) while (1) { /* threads_per_child does not include the listener thread */ for (i = 0; i < threads_per_child; i++) { - int status = ap_scoreboard_image->servers[child_num_arg][i].status; + int status = ap_scoreboard_image->servers[my_child_num][i].status; if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { continue; @@ -1515,11 +1517,13 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) int all_dead_threads = 1; int child_threads_active = 0; - if (i >= retained->max_daemons_limit && totally_free_length == retained->idle_spawn_rate[child_bucket]) + if (i >= retained->max_daemons_limit && + totally_free_length == retained->idle_spawn_rate[child_bucket]) { /* short cut if all active processes have been examined and * enough empty scoreboard slots have been found */ break; + } ps = &ap_scoreboard_image->parent[i]; for (j = 0; j < threads_per_child; j++) { ws = &ap_scoreboard_image->servers[i][j]; @@ -1553,7 +1557,8 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) } } active_thread_count += child_threads_active; - if (any_dead_threads && totally_free_length < retained->idle_spawn_rate[child_bucket] + if (any_dead_threads + && totally_free_length < retained->idle_spawn_rate[child_bucket] && free_length < MAX_SPAWN_RATE / num_buckets && (!ps->pid /* no process in the slot */ || ps->quiescing)) { /* or at least one is going away */ @@ -1730,8 +1735,8 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets) process_score *ps; for (i = 0; i < threads_per_child; i++) - ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD, - (request_rec *) NULL); + ap_update_child_status_from_indexes(child_slot, i, + SERVER_DEAD, NULL); worker_note_child_killed(child_slot, 0, 0); ps = &ap_scoreboard_image->parent[child_slot]; @@ -1831,10 +1836,16 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_daemons_limit = num_buckets; if (ap_daemons_to_start < num_buckets) ap_daemons_to_start = num_buckets; - if (min_spare_threads < threads_per_child * num_buckets) - min_spare_threads = threads_per_child * num_buckets; - if (max_spare_threads < min_spare_threads + threads_per_child * num_buckets) - max_spare_threads = min_spare_threads + threads_per_child * num_buckets; + /* We want to create as much children at a time as the number of buckets, + * so to optimally accept connections (evenly distributed accross buckets). + * Thus min_spare_threads should at least maintain num_buckets children, + * and max_spare_threads allow num_buckets more children w/o triggering + * immediately (e.g. num_buckets idle threads margin, one per bucket). + */ + if (min_spare_threads < threads_per_child * (num_buckets - 1) + num_buckets) + min_spare_threads = threads_per_child * (num_buckets - 1) + num_buckets; + if (max_spare_threads < min_spare_threads + (threads_per_child + 1) * num_buckets) + max_spare_threads = min_spare_threads + (threads_per_child + 1) * num_buckets; /* If we're doing a graceful_restart then we're going to see a lot * of children exiting immediately when we get into the main loop diff --git a/server/protocol.c b/server/protocol.c index 817cd3e1..88d0f992 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -992,7 +992,7 @@ request_rec *ap_read_request(conn_rec *conn) goto traceout; } else if (r->status == HTTP_REQUEST_TIME_OUT) { - ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); + ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, NULL); if (!r->connection->keepalives) { ap_run_log_transaction(r); } diff --git a/server/scoreboard.c b/server/scoreboard.c index 7dc6ae25..8e3403f7 100644 --- a/server/scoreboard.c +++ b/server/scoreboard.c @@ -464,22 +464,18 @@ static int update_child_status_internal(int child_num, { int old_status; worker_score *ws; - process_score *ps; int mpm_generation; ws = &ap_scoreboard_image->servers[child_num][thread_num]; old_status = ws->status; - if (status >= 0) { - ws->status = status; - - ps = &ap_scoreboard_image->parent[child_num]; - - if (status == SERVER_READY - && old_status == SERVER_STARTING) { - ws->thread_num = child_num * thread_limit + thread_num; - ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation); - ps->generation = mpm_generation; - } + ws->status = status; + + if (status == SERVER_READY + && old_status == SERVER_STARTING) { + process_score *ps = &ap_scoreboard_image->parent[child_num]; + ws->thread_num = child_num * thread_limit + thread_num; + ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation); + ps->generation = mpm_generation; } if (ap_extended_status) { @@ -497,45 +493,47 @@ static int update_child_status_internal(int child_num, ws->conn_bytes = 0; ws->last_used = apr_time_now(); } - if (status == SERVER_READY) { - ws->client[0]='\0'; - ws->vhost[0]='\0'; + + if (descr) { + apr_cpystrn(ws->request, descr, sizeof(ws->request)); + } + else if (r) { + copy_request(ws->request, sizeof(ws->request), r); + } + else if (c) { ws->request[0]='\0'; - ws->protocol[0]='\0'; } - else { - if (descr) { - apr_cpystrn(ws->request, descr, sizeof(ws->request)); - } - else if (r) { - copy_request(ws->request, sizeof(ws->request), r); - } - if (r) { - if (!(val = ap_get_useragent_host(r, REMOTE_NOLOOKUP, NULL))) - apr_cpystrn(ws->client, r->useragent_ip, sizeof(ws->client)); - else - apr_cpystrn(ws->client, val, sizeof(ws->client)); - } - else if (c) { - if (!(val = ap_get_remote_host(c, c->base_server->lookup_defaults, - REMOTE_NOLOOKUP, NULL))) - apr_cpystrn(ws->client, c->client_ip, sizeof(ws->client)); - else - apr_cpystrn(ws->client, val, sizeof(ws->client)); - } - if (s) { - if (c) { - apr_snprintf(ws->vhost, sizeof(ws->vhost), "%s:%d", - s->server_hostname, c->local_addr->port); - } - else { - apr_cpystrn(ws->vhost, s->server_hostname, sizeof(ws->vhost)); - } - } + + if (r && r->useragent_ip) { + if (!(val = ap_get_useragent_host(r, REMOTE_NOLOOKUP, NULL))) + apr_cpystrn(ws->client, r->useragent_ip, sizeof(ws->client)); + else + apr_cpystrn(ws->client, val, sizeof(ws->client)); + } + else if (c) { + if (!(val = ap_get_remote_host(c, c->base_server->lookup_defaults, + REMOTE_NOLOOKUP, NULL))) + apr_cpystrn(ws->client, c->client_ip, sizeof(ws->client)); + else + apr_cpystrn(ws->client, val, sizeof(ws->client)); + } + + if (s) { if (c) { - val = ap_get_protocol(c); - apr_cpystrn(ws->protocol, val, sizeof(ws->protocol)); + apr_snprintf(ws->vhost, sizeof(ws->vhost), "%s:%d", + s->server_hostname, c->local_addr->port); } + else { + apr_cpystrn(ws->vhost, s->server_hostname, sizeof(ws->vhost)); + } + } + else if (c) { + ws->vhost[0]='\0'; + } + + if (c) { + val = ap_get_protocol(c); + apr_cpystrn(ws->protocol, val, sizeof(ws->protocol)); } } diff --git a/server/util.c b/server/util.c index 916213c3..06da7897 100644 --- a/server/util.c +++ b/server/util.c @@ -96,7 +96,6 @@ #undef APLOG_MODULE_INDEX #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX - /* * Examine a field value (such as a media-/content-type) string and return * it sans any parameters; e.g., strip off any ';charset=foo' and the like. @@ -821,6 +820,60 @@ AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line) return res; } +AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line) +{ + return ap_getword_conf2(p, (const char **) line); +} + +AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line) +{ + const char *str = *line, *strend; + char *res; + char quote; + int count = 1; + + while (apr_isspace(*str)) + ++str; + + if (!*str) { + *line = str; + return ""; + } + + if ((quote = *str) == '"' || quote == '\'') + return ap_getword_conf(p, line); + + if (quote == '{') { + strend = str + 1; + while (*strend) { + if (*strend == '}' && !--count) + break; + if (*strend == '{') + ++count; + if (*strend == '\\' && strend[1] && strend[1] == '\\') { + ++strend; + } + ++strend; + } + res = substring_conf(p, str + 1, strend - str - 1, 0); + + if (*strend == '}') + ++strend; + } + else { + strend = str; + while (*strend && !apr_isspace(*strend)) + ++strend; + + res = substring_conf(p, str, strend - str, 0); + } + + while (apr_isspace(*strend)) + ++strend; + *line = strend; + return res; +} + AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp) { #ifdef DEBUG @@ -3119,3 +3172,128 @@ AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, return (ap_array_str_index(array, s, 0) >= 0); } +#if !APR_CHARSET_EBCDIC +/* + * Our own known-fast translation table for casecmp by character. + * Only ASCII alpha characters 41-5A are folded to 61-7A, other + * octets (such as extended latin alphabetics) are never case-folded. + * NOTE: Other than Alpha A-Z/a-z, each code point is unique! + */ +static const short ucharmap[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; +#else /* APR_CHARSET_EBCDIC */ +/* + * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison, + * provides unique identity of every char value (strict ISO-646 + * conformance, arbitrary election of an ISO-8859-1 ordering, and + * very arbitrary control code assignments into C1 to achieve + * identity and a reversible mapping of code points), + * then folding the equivalences of ASCII 41-5A into 61-7A, + * presenting comparison results in a somewhat ISO/IEC 10646 + * (ASCII-like) order, depending on the EBCDIC code page in use. + * + * NOTE: Other than Alpha A-Z/a-z, each code point is unique! + */ +static const short ucharmap[] = { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, + 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, + 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC, + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, + 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, + 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE, + 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, + 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7, + 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, + 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, + 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F +}; +#endif + +AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2) +{ + const unsigned char *str1 = (const unsigned char *)s1; + const unsigned char *str2 = (const unsigned char *)s2; + for (;;) + { + const int c1 = (int)(*str1); + const int c2 = (int)(*str2); + const int cmp = ucharmap[c1] - ucharmap[c2]; + /* Not necessary to test for !c2, this is caught by cmp */ + if (cmp || !c1) + return cmp; + str1++; + str2++; + } +} + +AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n) +{ + const unsigned char *str1 = (const unsigned char *)s1; + const unsigned char *str2 = (const unsigned char *)s2; + while (n--) + { + const int c1 = (int)(*str1); + const int c2 = (int)(*str2); + const int cmp = ucharmap[c1] - ucharmap[c2]; + /* Not necessary to test for !c2, this is caught by cmp */ + if (cmp || !c1) + return cmp; + str1++; + str2++; + } + return 0; +} + diff --git a/server/util_script.c b/server/util_script.c index 9a03b026..308e009a 100644 --- a/server/util_script.c +++ b/server/util_script.c @@ -370,12 +370,25 @@ static char *original_uri(request_rec *r) AP_DECLARE(void) ap_add_cgi_vars(request_rec *r) { apr_table_t *e = r->subprocess_env; + core_dir_config *conf = + (core_dir_config *)ap_get_core_module_config(r->per_dir_config); + int request_uri_from_original = 1; + const char *request_uri_rule; apr_table_setn(e, "GATEWAY_INTERFACE", "CGI/1.1"); apr_table_setn(e, "SERVER_PROTOCOL", r->protocol); apr_table_setn(e, "REQUEST_METHOD", r->method); apr_table_setn(e, "QUERY_STRING", r->args ? r->args : ""); - apr_table_setn(e, "REQUEST_URI", original_uri(r)); + + if (conf->cgi_var_rules) { + request_uri_rule = apr_hash_get(conf->cgi_var_rules, "REQUEST_URI", + APR_HASH_KEY_STRING); + if (request_uri_rule && !strcmp(request_uri_rule, "current-uri")) { + request_uri_from_original = 0; + } + } + apr_table_setn(e, "REQUEST_URI", + request_uri_from_original ? original_uri(r) : r->uri); /* Note that the code below special-cases scripts run from includes, * because it "knows" that the sub_request has been hacked to have the |