diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/core.c | 15 | ||||
-rw-r--r-- | server/log.c | 38 | ||||
-rw-r--r-- | server/mpm/experimental/event/event.c | 22 | ||||
-rw-r--r-- | server/mpm/winnt/child.c | 93 | ||||
-rw-r--r-- | server/mpm/winnt/mpm_winnt.c | 85 | ||||
-rw-r--r-- | server/mpm/winnt/nt_eventlog.c | 30 | ||||
-rw-r--r-- | server/mpm_common.c | 2 | ||||
-rw-r--r-- | server/protocol.c | 45 | ||||
-rw-r--r-- | server/scoreboard.c | 54 |
9 files changed, 280 insertions, 104 deletions
diff --git a/server/core.c b/server/core.c index b4aca33b..0e479b0c 100644 --- a/server/core.c +++ b/server/core.c @@ -227,8 +227,7 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) /* Create this conf by duplicating the base, replacing elements * (or creating copies for merging) where new-> values exist. */ - conf = (core_dir_config *)apr_palloc(a, sizeof(core_dir_config)); - memcpy(conf, base, sizeof(core_dir_config)); + conf = (core_dir_config *)apr_pmemdup(a, base, sizeof(core_dir_config)); conf->d = new->d; conf->d_is_fnmatch = new->d_is_fnmatch; @@ -286,10 +285,9 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) else if (new->response_code_strings != NULL) { /* If we merge, the merge-result must have it's own array */ - conf->response_code_strings = apr_palloc(a, + conf->response_code_strings = apr_pmemdup(a, + base->response_code_strings, sizeof(*conf->response_code_strings) * RESPONSE_CODES); - memcpy(conf->response_code_strings, base->response_code_strings, - sizeof(*conf->response_code_strings) * RESPONSE_CODES); for (i = 0; i < RESPONSE_CODES; ++i) { if (new->response_code_strings[i] != NULL) { @@ -497,8 +495,7 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) core_server_config *virt = (core_server_config *)virtv; core_server_config *conf; - conf = (core_server_config *)apr_palloc(p, sizeof(core_server_config)); - memcpy(conf, virt, sizeof(core_server_config)); + conf = (core_server_config *)apr_pmemdup(p, virt, sizeof(core_server_config)); if (!conf->access_name) { conf->access_name = base->access_name; @@ -1173,6 +1170,9 @@ static const char *set_document_root(cmd_parms *cmd, void *dummy, /* Make it absolute, relative to ServerRoot */ arg = ap_server_root_relative(cmd->pool, arg); + if (arg == NULL) { + return "DocumentRoot must be a directory"; + } /* TODO: ap_configtestonly && ap_docrootcheck && */ if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg, @@ -3906,6 +3906,7 @@ static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server, c->id = id; c->bucket_alloc = alloc; + c->clogging_input_filters = 0; return c; } diff --git a/server/log.c b/server/log.c index 14b4fdc2..3aa20b0b 100644 --- a/server/log.c +++ b/server/log.c @@ -161,15 +161,26 @@ static apr_status_t clear_handle_list(void *v) return APR_SUCCESS; } -/* remember to close this handle in the child process */ +/* remember to close this handle in the child process + * + * On Win32 this makes zero sense, because we don't + * take the parent process's child procs. + * If the win32 parent instead passed each and every + * logger write handle from itself down to the child, + * and the parent manages all aspects of keeping the + * reliable pipe log children alive, this would still + * make no sense :) Cripple it on Win32. + */ static void close_handle_in_child(apr_pool_t *p, apr_file_t *f) { +#ifndef WIN32 read_handle_t *new_handle; new_handle = apr_pcalloc(p, sizeof(read_handle_t)); new_handle->next = read_handles; new_handle->handle = f; read_handles = new_handle; +#endif } void ap_logs_child_init(apr_pool_t *p, server_rec *s) @@ -263,7 +274,7 @@ static int log_child(apr_pool_t *p, const char *progname, apr_status_t rc; apr_procattr_t *procattr; apr_proc_t *procnew; - apr_file_t *errfile; + apr_file_t *outfile, *errfile; if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) && ((rc = apr_procattr_cmdtype_set(procattr, @@ -282,8 +293,11 @@ static int log_child(apr_pool_t *p, const char *progname, pname = apr_pstrdup(p, args[0]); procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew)); - if (dummy_stderr) { - if ((rc = apr_file_open_stdout(&errfile, p)) == APR_SUCCESS) + if ((rc = apr_file_open_stdout(&outfile, p)) == APR_SUCCESS) { + rc = apr_procattr_child_out_set(procattr, outfile, NULL); + if (dummy_stderr) + rc = apr_procattr_child_err_set(procattr, outfile, NULL); + else if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS) rc = apr_procattr_child_err_set(procattr, errfile, NULL); } @@ -421,6 +435,16 @@ int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */, apr_pool_destroy(stderr_pool); stderr_pool = stderr_p; replace_stderr = 0; + /* + * Now that we have dup'ed s_main->error_log to stderr_log + * close it and set s_main->error_log to stderr_log. This avoids + * this fd being inherited by the next piped logger who would + * keep open the writing end of the pipe that this one uses + * as stdin. This in turn would prevent the piped logger from + * exiting. + */ + apr_file_close(s_main->error_log); + s_main->error_log = stderr_log; } } /* note that stderr may still need to be replaced with something @@ -877,6 +901,12 @@ static apr_status_t piped_log_spawn(piped_log *pl) else { char **args; const char *pname; + apr_file_t *outfile, *errfile; + + if ((status = apr_file_open_stdout(&outfile, pl->p)) == APR_SUCCESS) + status = apr_procattr_child_out_set(procattr, outfile, NULL); + if ((status = apr_file_open_stderr(&errfile, pl->p)) == APR_SUCCESS) + status = apr_procattr_child_err_set(procattr, errfile, NULL); apr_tokenize_to_argv(pl->program, &args, pl->p); pname = apr_pstrdup(pl->p, args[0]); diff --git a/server/mpm/experimental/event/event.c b/server/mpm/experimental/event/event.c index 2a6913b3..261468ea 100644 --- a/server/mpm/experimental/event/event.c +++ b/server/mpm/experimental/event/event.c @@ -623,6 +623,15 @@ static int process_socket(apr_pool_t * p, apr_socket_t * sock, c->sbh = sbh; } + if (c->clogging_input_filters && !c->aborted) { + /* Since we have an input filter which 'cloggs' the input stream, + * like mod_ssl, lets just do the normal read from input filters, + * like the Worker MPM does. + */ + ap_run_process_connection(c); + cs->state = CONN_STATE_LINGER; + } + if (cs->state == CONN_STATE_READ_REQUEST_LINE) { if (!c->aborted) { ap_run_process_connection(c); @@ -639,7 +648,6 @@ static int process_socket(apr_pool_t * p, apr_socket_t * sock, if (cs->state == CONN_STATE_LINGER) { ap_lingering_close(c); - apr_bucket_alloc_destroy(cs->bucket_alloc); apr_pool_clear(p); ap_push_pool(worker_queue_info, p); return 1; @@ -1020,12 +1028,19 @@ static void *listener_thread(apr_thread_t * thd, void *dummy) cs = APR_RING_FIRST(&timeout_head); timeout_time = time_now + TIMEOUT_FUDGE_FACTOR; while (!APR_RING_EMPTY(&timeout_head, conn_state_t, timeout_list) - && cs->expiration_time < timeout_time - && get_worker(&have_idle_worker)) { + && cs->expiration_time < timeout_time) { cs->state = CONN_STATE_LINGER; APR_RING_REMOVE(cs, timeout_list); + apr_thread_mutex_unlock(timeout_mutex); + + if (!get_worker(&have_idle_worker)) { + apr_thread_mutex_lock(timeout_mutex); + APR_RING_INSERT_HEAD(&timeout_head, cs, + conn_state_t, timeout_list); + break; + } rc = push2worker(&cs->pfd, event_pollset); @@ -1038,6 +1053,7 @@ static void *listener_thread(apr_thread_t * thd, void *dummy) */ } have_idle_worker = 0; + apr_thread_mutex_lock(timeout_mutex); cs = APR_RING_FIRST(&timeout_head); } apr_thread_mutex_unlock(timeout_mutex); diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index 8996bfd8..d918e47a 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -80,6 +80,7 @@ void mpm_recycle_completion_context(PCOMP_CONTEXT context) */ if (context) { apr_pool_clear(context->ptrans); + context->ba = apr_bucket_alloc_create(context->ptrans); context->next = NULL; ResetEvent(context->Overlapped.hEvent); apr_thread_mutex_lock(qlock); @@ -175,7 +176,7 @@ PCOMP_CONTEXT mpm_get_completion_context(void) apr_pool_tag(context->ptrans, "transaction"); context->accept_socket = INVALID_SOCKET; - context->ba = apr_bucket_alloc_create(pchild); + context->ba = apr_bucket_alloc_create(context->ptrans); apr_atomic_inc32(&num_completion_contexts); apr_thread_mutex_unlock(child_lock); @@ -432,12 +433,12 @@ static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); apr_allocator_owner_set(allocator, context->ptrans); apr_pool_tag(context->ptrans, "transaction"); - context->ba = apr_bucket_alloc_create(pchild); apr_thread_mutex_unlock(child_lock); } while (1) { apr_pool_clear(context->ptrans); + context->ba = apr_bucket_alloc_create(context->ptrans); context->accept_socket = remove_job(); if (context->accept_socket == INVALID_SOCKET) { return NULL; @@ -863,14 +864,15 @@ void child_main(apr_pool_t *pconf) apr_hash_t *ht; ap_listen_rec *lr; HANDLE child_events[2]; - int threads_created = 0; + HANDLE *child_handles; int listener_started = 0; + int threads_created = 0; + int watch_thread; + int time_remains; + int cld; int tid; - HANDLE *child_handles; int rv; - time_t end_time; int i; - int cld; apr_pool_create(&pchild, pconf); apr_pool_tag(pchild, "pchild"); @@ -1109,21 +1111,71 @@ void child_main(apr_pool_t *pconf) apr_thread_mutex_unlock(qlock); } - /* Give busy worker threads a chance to service their connections */ - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Waiting for %d worker threads to exit.", my_pid, threads_created); - end_time = time(NULL) + 180; - while (threads_created) { - rv = wait_for_many_objects(threads_created, child_handles, (DWORD)(end_time - time(NULL))); - if (rv != WAIT_TIMEOUT) { - rv = rv - WAIT_OBJECT_0; - ap_assert((rv >= 0) && (rv < threads_created)); - cleanup_thread(child_handles, &threads_created, rv); + /* Give busy threads a chance to service their connections, + * (no more than the global server timeout period which + * we track in msec remaining). + */ + watch_thread = 0; + time_remains = (int)(ap_server_conf->timeout / APR_TIME_C(1000)); + + while (threads_created) + { + int nFailsafe = MAXIMUM_WAIT_OBJECTS; + DWORD dwRet; + + /* Every time we roll over to wait on the first group + * of MAXIMUM_WAIT_OBJECTS threads, take a breather, + * and infrequently update the error log. + */ + if (watch_thread >= threads_created) { + if ((time_remains -= 100) < 0) + break; + + /* Every 30 seconds give an update */ + if ((time_remains % 30000) == 0) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, + ap_server_conf, + "Child %d: Waiting %d more seconds " + "for %d worker threads to finish.", + my_pid, time_remains / 1000, threads_created); + } + /* We'll poll from the top, 10 times per second */ + Sleep(100); + watch_thread = 0; + } + + /* Fairness, on each iteration we will pick up with the thread + * after the one we just removed, even if it's a single thread. + * We don't block here. + */ + dwRet = WaitForMultipleObjects(min(threads_created - watch_thread, + MAXIMUM_WAIT_OBJECTS), + child_handles + watch_thread, 0, 0); + + if (dwRet == WAIT_FAILED) { + break; + } + if (dwRet == WAIT_TIMEOUT) { + /* none ready */ + watch_thread += MAXIMUM_WAIT_OBJECTS; continue; } - break; + else if (dwRet >= WAIT_ABANDONED_0) { + /* We just got the ownership of the object, which + * should happen at most MAXIMUM_WAIT_OBJECTS times. + * It does NOT mean that the object is signaled. + */ + if ((nFailsafe--) < 1) + break; + } + else { + watch_thread += (dwRet - WAIT_OBJECT_0); + if (watch_thread >= threads_created) + break; + cleanup_thread(child_handles, &threads_created, watch_thread); + } } - + /* Kill remaining threads off the hard way */ if (threads_created) { ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, @@ -1136,7 +1188,10 @@ void child_main(apr_pool_t *pconf) 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)); - ap_update_child_status_from_indexes(0, *score_idx, SERVER_DEAD, NULL); + if (score_idx) { + ap_update_child_status_from_indexes(0, *score_idx, + SERVER_DEAD, NULL); + } } ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %d: All worker threads have exited.", my_pid); diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index 4b37d741..120adfc0 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -625,6 +625,7 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_ apr_pool_t *ptemp; apr_procattr_t *attr; apr_proc_t new_child; + apr_file_t *child_out, *child_err; HANDLE hExitEvent; HANDLE waitlist[2]; /* see waitlist_e */ char *cmd; @@ -678,6 +679,22 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_ return -1; } + /* httpd-2.0/2.2 specific to work around apr_proc_create bugs */ + if (((rv = apr_file_open_stdout(&child_out, p)) + != APR_SUCCESS) || + ((rv = apr_procattr_child_out_set(attr, child_out, NULL)) + != APR_SUCCESS)) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, + "Parent: Could not set child process stdout"); + } + if (((rv = apr_file_open_stderr(&child_err, p)) + != APR_SUCCESS) || + ((rv = apr_procattr_child_err_set(attr, child_err, NULL)) + != APR_SUCCESS)) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, + "Parent: Could not set child process stderr"); + } + /* Create the child_ready_event */ waitlist[waitlist_ready] = CreateEvent(NULL, TRUE, FALSE, NULL); if (!waitlist[waitlist_ready]) { @@ -975,9 +992,11 @@ die_now: event_handles[CHILD_HANDLE] = NULL; } } + CloseHandle(child_exit_event); return 0; /* Tell the caller we do not want to restart */ } winnt_mpm_state = AP_MPMQ_STARTING; + CloseHandle(child_exit_event); return 1; /* Tell the caller we want a restart */ } @@ -1081,7 +1100,7 @@ void winnt_rewrite_args(process_rec *process) pid = getenv("AP_PARENT_PID"); if (pid) { - HANDLE filehand, newhand; + HANDLE filehand; HANDLE hproc = GetCurrentProcess(); /* This is the child */ @@ -1094,17 +1113,12 @@ void winnt_rewrite_args(process_rec *process) /* The parent gave us stdin, we need to remember this * handle, and no longer inherit it at our children * (we can't slurp it up now, we just aren't ready yet). + * The original handle is closed below, at apr_file_dup2() */ pipe = GetStdHandle(STD_INPUT_HANDLE); - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { - /* This doesn't work for 9x, but it's cleaner. */ - SetHandleInformation(pipe, HANDLE_FLAG_INHERIT, 0); - } - else if (DuplicateHandle(hproc, pipe, - hproc, &filehand, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - CloseHandle(pipe); + if (DuplicateHandle(hproc, pipe, + hproc, &filehand, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { pipe = filehand; } @@ -1114,13 +1128,17 @@ void winnt_rewrite_args(process_rec *process) * Don't infect child processes with our stdin * handle, use another handle to NUL! */ - if ((filehand = GetStdHandle(STD_OUTPUT_HANDLE)) - && DuplicateHandle(hproc, filehand, - hproc, &newhand, 0, - TRUE, DUPLICATE_SAME_ACCESS)) { - SetStdHandle(STD_INPUT_HANDLE, newhand); + { + apr_file_t *infile, *outfile; + if ((apr_file_open_stdout(&outfile, process->pool) == APR_SUCCESS) + && (apr_file_open_stdin(&infile, process->pool) == APR_SUCCESS)) + apr_file_dup2(infile, outfile, process->pool); } + /* This child needs the existing stderr opened for logging, + * already + */ + /* The parent is responsible for providing the * COMPLETE ARGUMENTS REQUIRED to the child. * @@ -1286,19 +1304,10 @@ void winnt_rewrite_args(process_rec *process) if ((rv = apr_file_open(&nullfile, "NUL", APR_READ | APR_WRITE, APR_OS_DEFAULT, process->pool)) == APR_SUCCESS) { - HANDLE hproc = GetCurrentProcess(); - HANDLE nullstdout = NULL; - HANDLE nullhandle; - - /* Duplicate the handle to be inherited by children */ - if ((apr_os_file_get(&nullhandle, nullfile) == APR_SUCCESS) - && DuplicateHandle(hproc, nullhandle, - hproc, &nullstdout, - 0, TRUE, DUPLICATE_SAME_ACCESS)) { - SetStdHandle(STD_OUTPUT_HANDLE, nullstdout); - } - - /* Close the original handle, we used the duplicate */ + apr_file_t *nullstdout; + if (apr_file_open_stdout(&nullstdout, process->pool) + == APR_SUCCESS) + apr_file_dup2(nullstdout, nullfile, process->pool); apr_file_close(nullfile); } } @@ -1426,6 +1435,26 @@ static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *pt service_name); exit(APEXIT_INIT); } + else if (!one_process && !ap_my_generation) { + /* Open a null handle to soak stdout in this process. + * We need to emulate apr_proc_detach, unix performs this + * same check in the pre_config hook (although it is + * arguably premature). Services already fixed this. + */ + apr_file_t *nullfile; + apr_status_t rv; + apr_pool_t *pproc = apr_pool_parent_get(pconf); + + if ((rv = apr_file_open(&nullfile, "NUL", + APR_READ | APR_WRITE, APR_OS_DEFAULT, + pproc)) == APR_SUCCESS) { + apr_file_t *nullstdout; + if (apr_file_open_stdout(&nullstdout, pproc) + == APR_SUCCESS) + apr_file_dup2(nullstdout, nullfile, pproc); + apr_file_close(nullfile); + } + } /* Win9x: disable AcceptEx */ if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { diff --git a/server/mpm/winnt/nt_eventlog.c b/server/mpm/winnt/nt_eventlog.c index a0ae68c9..baa1a88b 100644 --- a/server/mpm/winnt/nt_eventlog.c +++ b/server/mpm/winnt/nt_eventlog.c @@ -21,6 +21,7 @@ #include "mpm_winnt.h" #include "apr_strings.h" #include "apr_lib.h" +#include "apr_portable.h" #include "ap_regkey.h" static char *display_name = NULL; @@ -138,7 +139,8 @@ void mpm_nt_eventlog_stderr_open(char *argv0, apr_pool_t *p) HANDLE hPipeWrite = NULL; HANDLE hDup = NULL; DWORD threadid; - int fd; + apr_file_t *eventlog_file; + apr_file_t *stderr_file; display_name = argv0; @@ -159,27 +161,11 @@ void mpm_nt_eventlog_stderr_open(char *argv0, apr_pool_t *p) WaitForSingleObject(stderr_ready, INFINITE); - /* Flush stderr and unset its buffer, then commit and replace stderr. - * This is typically a noop for Win2K/XP since services with NULL std - * handles [but valid FILE *'s, oddly enough], but is required - * for NT 4.0 and to use this code outside of services. - */ - fflush(stderr); - setvbuf(stderr, NULL, _IONBF, 0); - _commit(2 /* stderr */); - fd = _open_osfhandle((long) hPipeWrite, - _O_WRONLY | _O_BINARY); - _dup2(fd, 2); - _close(fd); - _setmode(2, _O_BINARY); - - /* hPipeWrite was _close()'ed above, and _dup2()'ed - * to fd 2 creating a new, inherited Win32 handle. - * Recover that real handle from fd 2. - */ - hPipeWrite = (HANDLE)_get_osfhandle(2); - - SetStdHandle(STD_ERROR_HANDLE, hPipeWrite); + if ((apr_file_open_stderr(&stderr_file, p) + == APR_SUCCESS) + && (apr_os_file_put(&eventlog_file, &hPipeWrite, APR_WRITE, p) + == APR_SUCCESS)) + apr_file_dup2(stderr_file, eventlog_file, p); /* The code above _will_ corrupt the StdHandle... * and we must do so anyways. We set this up only diff --git a/server/mpm_common.c b/server/mpm_common.c index f8063733..a95b2312 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -699,7 +699,7 @@ static apr_status_t dummy_connection(ap_pod_t *pod) * adminstrators can track down the cause of the odd-looking * requests in their logs. */ - srequest = apr_pstrcat(p, "GET / HTTP/1.0\r\nUser-Agent: ", + srequest = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ", ap_get_server_banner(), " (internal dummy connection)\r\n\r\n", NULL); diff --git a/server/protocol.c b/server/protocol.c index b7145bb7..e5b2e030 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -1399,9 +1399,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_old_write_filter( * can simply insert our buffered data at the front and * pass the whole bundle down the chain. */ - APR_BRIGADE_CONCAT(ctx->bb, bb); - bb = ctx->bb; - ctx->bb = NULL; + APR_BRIGADE_PREPEND(bb, ctx->bb); } return ap_pass_brigade(f->next, bb); @@ -1539,9 +1537,6 @@ AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va) written = apr_vformatter(r_flush, &vd.vbuff, fmt, va); - /* tack on null terminator on remaining string */ - *(vd.vbuff.curpos) = '\0'; - if (written != -1) { int n = vd.vbuff.curpos - vrprintf_buf; @@ -1633,6 +1628,44 @@ AP_DECLARE(void) ap_set_last_modified(request_rec *r) } } +typedef struct hdr_ptr { + ap_filter_t *f; + apr_bucket_brigade *bb; +} hdr_ptr; + +static int send_header(void *data, const char *key, const char *val) +{ + ap_fputstrs(((hdr_ptr*)data)->f, ((hdr_ptr*)data)->bb, + key, ": ", val, CRLF, NULL); + return 1; +} + +AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers) +{ + hdr_ptr x; + + if (r->proto_num < 1001) { + /* don't send interim response to HTTP/1.0 Client */ + return; + } + if (!ap_is_HTTP_INFO(r->status)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, NULL, + "Status is %d - not sending interim response", r->status); + return; + } + + x.f = r->connection->output_filters; + x.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + ap_fputstrs(x.f, x.bb, AP_SERVER_PROTOCOL, " ", r->status_line, CRLF, NULL); + if (send_headers) { + apr_table_do(send_header, &x, r->headers_out, NULL); + apr_table_clear(r->headers_out); + } + ap_fputs(x.f, x.bb, CRLF); + ap_fflush(x.f, x.bb); + apr_brigade_destroy(x.bb); +} + AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request, (request_rec *r), (r), OK, DECLINED) AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction, diff --git a/server/scoreboard.c b/server/scoreboard.c index 9cb7359a..0f657131 100644 --- a/server/scoreboard.c +++ b/server/scoreboard.c @@ -40,6 +40,7 @@ AP_DECLARE_DATA scoreboard *ap_scoreboard_image = NULL; AP_DECLARE_DATA const char *ap_scoreboard_fname = NULL; AP_DECLARE_DATA int ap_extended_status = 0; +AP_DECLARE_DATA int ap_mod_status_reqtail = 0; #if APR_HAS_SHARED_MEMORY @@ -157,7 +158,7 @@ static apr_status_t create_namebased_scoreboard(apr_pool_t *pool, rv = apr_shm_create(&ap_scoreboard_shm, scoreboard_size, fname, pool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "unable to create scoreboard \"%s\" " + "unable to create or access scoreboard \"%s\" " "(name-based shared memory failure)", fname); return rv; } @@ -204,7 +205,7 @@ static apr_status_t open_scoreboard(apr_pool_t *pconf) global_pool); /* anonymous shared memory */ if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "Unable to create scoreboard " + "Unable to create or access scoreboard " "(anonymous shared memory failure)"); return rv; } @@ -380,6 +381,42 @@ AP_DECLARE(void) ap_create_sb_handle(ap_sb_handle_t **new_sbh, apr_pool_t *p, (*new_sbh)->thread_num = thread_num; } +static void copy_request(char *rbuf, apr_size_t rbuflen, request_rec *r) +{ + char *p; + + if (r->the_request == NULL) { + apr_cpystrn(rbuf, "NULL", rbuflen); + return; /* short circuit below */ + } + + if (r->parsed_uri.password == NULL) { + p = r->the_request; + } + else { + /* Don't reveal the password in the server-status view */ + p = apr_pstrcat(r->pool, r->method, " ", + apr_uri_unparse(r->pool, &r->parsed_uri, + APR_URI_UNP_OMITPASSWORD), + r->assbackwards ? NULL : " ", r->protocol, NULL); + } + + /* now figure out if we copy over the 1st rbuflen chars or the last */ + if (!ap_mod_status_reqtail) { + apr_cpystrn(rbuf, p, rbuflen); + } + else { + apr_size_t slen = strlen(p); + if (slen < rbuflen) { + /* it all fits anyway */ + apr_cpystrn(rbuf, p, rbuflen); + } + else { + apr_cpystrn(rbuf, p+(slen-rbuflen+1), rbuflen); + } + } +} + AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, int thread_num, int status, @@ -422,18 +459,7 @@ AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, conn_rec *c = r->connection; apr_cpystrn(ws->client, ap_get_remote_host(c, r->per_dir_config, REMOTE_NOLOOKUP, NULL), sizeof(ws->client)); - if (r->the_request == NULL) { - apr_cpystrn(ws->request, "NULL", sizeof(ws->request)); - } else if (r->parsed_uri.password == NULL) { - apr_cpystrn(ws->request, r->the_request, sizeof(ws->request)); - } else { - /* Don't reveal the password in the server-status view */ - apr_cpystrn(ws->request, apr_pstrcat(r->pool, r->method, " ", - apr_uri_unparse(r->pool, &r->parsed_uri, - APR_URI_UNP_OMITPASSWORD), - r->assbackwards ? NULL : " ", r->protocol, NULL), - sizeof(ws->request)); - } + copy_request(ws->request, sizeof(ws->request), r); apr_cpystrn(ws->vhost, r->server->server_hostname, sizeof(ws->vhost)); } |