X-Git-Url: http://git.home-dn.net/?p=manu%2Fsuphp.git;a=blobdiff_plain;f=src%2Fapache2%2Fmod_suphp.c;h=35b22926d3febe96f1d10ee17b58ea38dee664ad;hp=c330844facd7cf49b13bec4e628d4fb40e0eee19;hb=849f4a7977b5780eacae8fad7a078d05f4a615ee;hpb=47bcf8ba77fa8011f9be728c23dbe6915d70251b diff --git a/src/apache2/mod_suphp.c b/src/apache2/mod_suphp.c index c330844..35b2292 100644 --- a/src/apache2/mod_suphp.c +++ b/src/apache2/mod_suphp.c @@ -22,6 +22,7 @@ #include "apr_strings.h" #include "apr_thread_proc.h" #include "apr_buckets.h" +#include "apr_poll.h" #define CORE_PRIVATE @@ -33,6 +34,8 @@ #include "util_script.h" #include "util_filter.h" +/* needed for get_suexec_identity hook */ +#include "unixd.h" module AP_MODULE_DECLARE_DATA suphp_module; @@ -41,46 +44,14 @@ module AP_MODULE_DECLARE_DATA suphp_module; Auxiliary functions *********************/ -static int suphp_bucket_read(apr_bucket *b, char *buf, int len) -{ - const char *dst_end = buf + len - 1; - char * dst = buf; - apr_status_t rv; - const char *bucket_data; - apr_size_t bucket_data_len; - const char *src; - const char *src_end; - int count = 0; - - if (APR_BUCKET_IS_EOS(b)) - return -1; - - rv = apr_bucket_read(b, &bucket_data, &bucket_data_len, APR_BLOCK_READ); - if (!APR_STATUS_IS_SUCCESS(rv) || (bucket_data_len == 0)) - { - return 0; - } - src = bucket_data; - src_end = bucket_data + bucket_data_len; - while ((src < src_end) && (dst < dst_end)) - { - *dst = *src; - dst++; - src++; - count++; - } - *dst = 0; - return count; -} - - -static void suphp_log_script_err(request_rec *r, apr_file_t *script_err) +static apr_status_t suphp_log_script_err(request_rec *r, apr_file_t *script_err) { char argsbuffer[HUGE_STRING_LEN]; char *newline; - - while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, - script_err) == APR_SUCCESS) { + apr_status_t rv; + + while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN, + script_err)) == APR_SUCCESS) { newline = strchr(argsbuffer, '\n'); if (newline) { *newline = '\0'; @@ -88,6 +59,43 @@ static void suphp_log_script_err(request_rec *r, apr_file_t *script_err) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", argsbuffer); } + + return rv; +} + +char *suphp_brigade_read(apr_pool_t *p, apr_bucket_brigade *bb, int bytes) +{ + char *target_buf; + char *next_byte; + char *last_byte; + apr_bucket *b; + + if (bytes == 0) { + return NULL; + } + + target_buf = (char *) apr_palloc(p, bytes + 1); + next_byte = target_buf; + last_byte = target_buf + bytes; + + for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) { + char *buf; + apr_size_t size; + apr_size_t i; + if (apr_bucket_read(b, &buf, &size, APR_BLOCK_READ) == APR_SUCCESS) { + for (i = 0; i < size; i++) { + *next_byte = *buf; + next_byte++; + buf++; + if (next_byte == last_byte) { + *next_byte = 0; + return target_buf; + } + } + } + } + next_byte = 0; + return target_buf; } @@ -115,6 +123,7 @@ typedef struct { char *target_group; #endif apr_table_t *handlers; + char *php_path; } suphp_conf; @@ -124,6 +133,7 @@ static void *suphp_create_dir_config(apr_pool_t *p, char *dir) cfg->php_config = NULL; cfg->engine = SUPHP_ENGINE_UNDEFINED; + cfg->php_path = NULL; cfg->cmode = SUPHP_CONFIG_MODE_DIRECTORY; #ifdef SUPHP_USE_USERGROUP @@ -187,8 +197,13 @@ static void *suphp_create_server_config(apr_pool_t *p, server_rec *s) suphp_conf *cfg = (suphp_conf *) apr_pcalloc(p, sizeof(suphp_conf)); cfg->engine = SUPHP_ENGINE_UNDEFINED; + cfg->php_path = NULL; cfg->cmode = SUPHP_CONFIG_MODE_SERVER; + /* Create table with 0 initial elements */ + /* This size may be increased for performance reasons */ + cfg->handlers = apr_table_make(p, 0); + return (void *) cfg; } @@ -204,7 +219,12 @@ static void *suphp_merge_server_config(apr_pool_t *p, void *base, merged->engine = child->engine; else merged->engine = parent->engine; - + + if (child->php_path != NULL) + merged->php_path = apr_pstrdup(p, child->php_path); + else + merged->php_path = apr_pstrdup(p, parent->php_path); + #ifdef SUPHP_USE_USERGROUP if (child->target_user) merged->target_user = apr_pstrdup(p, child->target_user); @@ -221,6 +241,8 @@ static void *suphp_merge_server_config(apr_pool_t *p, void *base, merged->target_group = NULL; #endif + merged->handlers = apr_table_overlay(p, child->handlers, parent->handlers); + return (void*) merged; } @@ -281,9 +303,14 @@ static const char *suphp_handle_cmd_user_group(cmd_parms *cmd, void *mconfig, static const char *suphp_handle_cmd_add_handler(cmd_parms *cmd, void *mconfig, - const char *arg) + const char *arg) { - suphp_conf *cfg = (suphp_conf *) mconfig; + suphp_conf *cfg; + if (mconfig) + cfg = (suphp_conf *) mconfig; + else + cfg = (suphp_conf *) ap_get_module_config(cmd->server->module_config, &suphp_module); + // Mark active handler with '1' apr_table_set(cfg->handlers, arg, "1"); @@ -292,10 +319,15 @@ static const char *suphp_handle_cmd_add_handler(cmd_parms *cmd, void *mconfig, static const char *suphp_handle_cmd_remove_handler(cmd_parms *cmd, - void *mconfig, - const char *arg) + void *mconfig, + const char *arg) { - suphp_conf *cfg = (suphp_conf *) mconfig; + suphp_conf *cfg; + if (mconfig) + cfg = (suphp_conf *) mconfig; + else + cfg = (suphp_conf *) ap_get_module_config(cmd->server->module_config, &suphp_module); + // Mark deactivated handler with '0' apr_table_set(cfg->handlers, arg, "0"); @@ -303,6 +335,19 @@ static const char *suphp_handle_cmd_remove_handler(cmd_parms *cmd, } +static const char *suphp_handle_cmd_phppath(cmd_parms *cmd, void* mconfig, const char *arg) +{ + server_rec *s = cmd->server; + suphp_conf *cfg; + + cfg = (suphp_conf *) ap_get_module_config(s->module_config, &suphp_module); + + cfg->php_path = apr_pstrdup(cmd->pool, arg); + + return NULL; +} + + static const command_rec suphp_cmds[] = { AP_INIT_FLAG("suPHP_Engine", suphp_handle_cmd_engine, NULL, RSRC_CONF | ACCESS_CONF, @@ -315,16 +360,374 @@ static const command_rec suphp_cmds[] = #endif AP_INIT_ITERATE("suPHP_AddHandler", suphp_handle_cmd_add_handler, NULL, RSRC_CONF | ACCESS_CONF, "Tells mod_suphp to handle these MIME-types"), AP_INIT_ITERATE("suPHP_RemoveHandler", suphp_handle_cmd_remove_handler, NULL, RSRC_CONF | ACCESS_CONF, "Tells mod_suphp not to handle these MIME-types"), + AP_INIT_TAKE1("suPHP_PHPPath", suphp_handle_cmd_phppath, NULL, RSRC_CONF, "Path to the PHP binary used to render source view"), {NULL} }; +/***************************************** + Code for reading script's stdout/stderr + based on mod_cgi's code + *****************************************/ + +#if APR_FILES_AS_SOCKETS + +static const apr_bucket_type_t bucket_type_suphp; + +struct suphp_bucket_data { + apr_pollset_t *pollset; + request_rec *r; +}; + +static apr_bucket *suphp_bucket_create(request_rec *r, apr_file_t *out, apr_file_t *err, apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + apr_status_t rv; + apr_pollfd_t fd; + struct suphp_bucket_data *data = apr_palloc(r->pool, sizeof(*data)); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + b->type = &bucket_type_suphp; + b->length = (apr_size_t) (-1); + b->start = (-1); + + /* Create the pollset */ + rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); + AP_DEBUG_ASSERT(rv == APR_SUCCESS); + + fd.desc_type = APR_POLL_FILE; + fd.reqevents = APR_POLLIN; + fd.p = r->pool; + fd.desc.f = out; /* script's stdout */ + fd.client_data = (void *) 1; + rv = apr_pollset_add(data->pollset, &fd); + AP_DEBUG_ASSERT(rv == APR_SUCCESS); + + fd.desc.f = err; /* script's stderr */ + fd.client_data = (void *) 2; + rv = apr_pollset_add(data->pollset, &fd); + AP_DEBUG_ASSERT(rv == APR_SUCCESS); + + data->r = r; + b->data = data; + return b; +} + +static apr_bucket *suphp_bucket_dup(struct suphp_bucket_data *data, apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + b->type = &bucket_type_suphp; + b->length = (apr_size_t) (-1); + b->start = (-1); + b->data = data; + return b; +} + +/* This utility method is needed, because APR's implementation for the + pipe bucket cannot handle or special bucket type */ +static apr_status_t suphp_read_fd(apr_bucket *b, apr_file_t *fd, const char **str, apr_size_t *len) +{ + char *buf; + apr_status_t rv; + + *str = NULL; + *len = APR_BUCKET_BUFF_SIZE; + buf = apr_bucket_alloc(*len, b->list); + + rv = apr_file_read(fd, buf, len); + + if (*len > 0) { + /* Got data */ + struct suphp_bucket_data *data = b->data; + apr_bucket_heap *h; + + /* Change the current bucket to refer to what we read + and append the pipe bucket after it */ + b = apr_bucket_heap_make(b, buf, *len, apr_bucket_free); + /* Here, b->data is the new heap bucket data */ + h = b->data; + h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ + *str = buf; + APR_BUCKET_INSERT_AFTER(b, suphp_bucket_dup(data, b->list)); + } else { + /* Got no data */ + apr_bucket_free(buf); + b = apr_bucket_immortal_make(b, "", 0); + /* Here, b->data is the reference to the empty string */ + *str = b->data; + } + return rv; +} + +/* Poll on stdout and stderr to make sure the process does not block + because of a full system (stderr) buffer */ +static apr_status_t suphp_bucket_read(apr_bucket *b, const char **str, apr_size_t *len, apr_read_type_e block) { + struct suphp_bucket_data *data = b->data; + apr_interval_time_t timeout; + apr_status_t rv; + int gotdata = 0; + + timeout = (block == APR_NONBLOCK_READ) ? 0 : data->r->server->timeout; + + do { + const apr_pollfd_t *results; + apr_int32_t num; + + rv = apr_pollset_poll(data->pollset, timeout, &num, &results); + if (APR_STATUS_IS_TIMEUP(rv)) { + return (timeout == 0) ? APR_EAGAIN : rv; + } else if (APR_STATUS_IS_EINTR(rv)) { + continue; + } else if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, "Poll failed waiting for suPHP child process"); + return rv; + } + + while (num > 0) { + if (results[0].client_data == (void *) 1) { + /* handle stdout */ + rv = suphp_read_fd(b, results[0].desc.f, str, len); + if (APR_STATUS_IS_EOF(rv)) { + rv = APR_SUCCESS; + } + gotdata = 1; + } else { + /* handle stderr */ + apr_status_t rv2 = suphp_log_script_err(data->r, results[0].desc.f); + if (APR_STATUS_IS_EOF(rv2)) { + apr_pollset_remove(data->pollset, &results[0]); + } + } + num--; + results++; + } + } while (!gotdata); + + return rv; +} + +static const apr_bucket_type_t bucket_type_suphp = { + "SUPHP", 5, APR_BUCKET_DATA, + apr_bucket_destroy_noop, + suphp_bucket_read, + apr_bucket_setaside_notimpl, + apr_bucket_split_notimpl, + apr_bucket_copy_notimpl +}; + +#endif + +static void suphp_discard_output(apr_bucket_brigade *bb) { + apr_bucket *b; + const char *buf; + apr_size_t len; + apr_status_t rv; + for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) { + if (APR_BUCKET_IS_EOS(b)) { + break; + } + rv = apr_bucket_read(b, &buf, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + break; + } + } +} + /****************** Hooks / handlers ******************/ +static int suphp_script_handler(request_rec *r); +static int suphp_source_handler(request_rec *r); + static int suphp_handler(request_rec *r) { + suphp_conf *sconf, *dconf; + + sconf = ap_get_module_config(r->server->module_config, &suphp_module); + dconf = ap_get_module_config(r->per_dir_config, &suphp_module); + + /* only handle request if mod_suphp is active for this handler */ + /* check only first byte of value (second has to be \0) */ + if (apr_table_get(dconf->handlers, r->handler) != NULL) + { + if (*(apr_table_get(dconf->handlers, r->handler)) != '0') + { + return suphp_script_handler(r); + } + } + else + { + if ((apr_table_get(sconf->handlers, r->handler) != NULL) + && (*(apr_table_get(sconf->handlers, r->handler)) != '0')) + { + return suphp_script_handler(r); + } + } + + if (!strcmp(r->handler, "x-httpd-php-source") + || !strcmp(r->handler, "application/x-httpd-php-source")) + { + return suphp_source_handler(r); + } + + return DECLINED; +} + +static int suphp_source_handler(request_rec *r) +{ + suphp_conf *conf; + apr_status_t rv; + apr_pool_t *p; + apr_file_t *file; + apr_proc_t *proc; + apr_procattr_t *procattr; + char **argv; + char **env; + apr_bucket_brigade *bb; + apr_bucket *b; + char *phpexec; + + p = r->main ? r->main->pool : r->pool; + + if (strcmp(r->method, "GET")) + { + return DECLINED; + } + + conf = ap_get_module_config(r->server->module_config, &suphp_module); + phpexec = apr_pstrdup(p, conf->php_path); + if (phpexec == NULL) + { + return DECLINED; + } + + // Try to open file for reading to see whether is is accessible + rv = apr_file_open(&file, apr_pstrdup(p, r->filename), APR_READ, APR_OS_DEFAULT, p); + if (rv == APR_SUCCESS) + { + apr_file_close(file); + file = NULL; + } + else if (rv == EACCES) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "access to %s denied", r->filename); + return HTTP_FORBIDDEN; + } + else if (rv == ENOENT) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "File does not exist: %s", r->filename); + return HTTP_NOT_FOUND; + } + else + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Could not open file: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + env = ap_create_environment(p, r->subprocess_env); + + /* set attributes for new process */ + + if (((rv = apr_procattr_create(&procattr, p)) != APR_SUCCESS) + || ((rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK)) != APR_SUCCESS) + || ((rv = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) + || ((apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) != APR_SUCCESS) + || ((apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS) + || ((apr_procattr_detach_set(procattr, 0)) != APR_SUCCESS)) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "couldn't set child process attributes: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + + /* create new process */ + + argv = apr_palloc(p, 4 * sizeof(char *)); + argv[0] = phpexec; + argv[1] = "-s"; + argv[2] = apr_pstrdup(p, r->filename); + argv[3] = NULL; + + env = ap_create_environment(p, r->subprocess_env); + + proc = apr_pcalloc(p, sizeof(*proc)); + rv = apr_proc_create(proc, phpexec, (const char *const *)argv, (const char *const *)env, procattr, p); + if (rv != APR_SUCCESS) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "couldn't create child process: %s for %s", phpexec, r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + apr_pool_note_subprocess(p, proc, APR_KILL_AFTER_TIMEOUT); + + if (!proc->out) + return APR_EBADF; + apr_file_pipe_timeout_set(proc->out, r->server->timeout); + + if (!proc->in) + return APR_EBADF; + apr_file_pipe_timeout_set(proc->in, r->server->timeout); + + if (!proc->err) + return APR_EBADF; + apr_file_pipe_timeout_set(proc->err, r->server->timeout); + + /* discard input */ + + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + + apr_file_flush(proc->in); + apr_file_close(proc->in); + + rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); + if (rv != APR_SUCCESS) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "couldn't get input from filters: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + suphp_discard_output(bb); + apr_brigade_cleanup(bb); + + /* get output from script */ + +#if APR_FILES_AS_SOCKETS + apr_file_pipe_timeout_set(proc->out, 0); + apr_file_pipe_timeout_set(proc->err, 0); + b = suphp_bucket_create(r, proc->out, proc->err, r->connection->bucket_alloc); +#else + b = apr_bucket_pipe_create(proc->out, r->connection->bucket_alloc); +#endif + APR_BRIGADE_INSERT_TAIL(bb, b); + + b = apr_bucket_eos_create(r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + + /* send output to browser (through filters) */ + + r->content_type = "text/html"; + rv = ap_pass_brigade(r->output_filters, bb); + + /* write errors to logfile */ + + if (rv == APR_SUCCESS && !r->connection->aborted) + { + suphp_log_script_err(r, proc->err); + apr_file_close(proc->err); + } + + return OK; +} + +static int suphp_script_handler(request_rec *r) +{ apr_pool_t *p; suphp_conf *sconf; suphp_conf *dconf; @@ -345,10 +748,16 @@ static int suphp_handler(request_rec *r) #else char strbuf[MAX_STRING_LEN]; #endif + char *tmpbuf; int nph = 0; int eos_reached = 0; char *auth_user = NULL; char *auth_pass = NULL; + +#ifdef SUPHP_USE_USERGROUP + char *ud_user = NULL; + char *ud_group = NULL; +#endif apr_bucket_brigade *bb; apr_bucket *b; @@ -360,12 +769,6 @@ static int suphp_handler(request_rec *r) dconf = ap_get_module_config(r->per_dir_config, &suphp_module); core_conf = (core_dir_config *) ap_get_module_config(r->per_dir_config, &core_module); - /* only handle request if mod_suphp is active for this handler */ - /* check only first byte of value (second has to be \0) */ - if ((apr_table_get(dconf->handlers, r->handler) == NULL) - || (*(apr_table_get(dconf->handlers, r->handler)) == '0')) - return DECLINED; - /* check if suPHP is enabled for this request */ if (((sconf->engine != SUPHP_ENGINE_ON) @@ -398,17 +801,25 @@ static int suphp_handler(request_rec *r) if (!(r->finfo.protection & APR_UREAD)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Insufficient permissions: %s", r->filename); - return HTTP_FORBIDDEN; + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Insufficient permissions: %s", r->filename); + return HTTP_FORBIDDEN; } #ifdef SUPHP_USE_USERGROUP if ((sconf->target_user == NULL || sconf->target_group == NULL) && (dconf->target_user == NULL || dconf->target_group == NULL)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "No user or group set - set suPHP_UserGroup"); - return HTTP_INTERNAL_SERVER_ERROR; + /* Check for userdir request */ + ap_unix_identity_t *userdir_id = NULL; + userdir_id = ap_run_get_suexec_identity(r); + if (userdir_id != NULL && userdir_id->userdir) { + ud_user = apr_psprintf(r->pool, "#%ld", (long) userdir_id->uid); + ud_group = apr_psprintf(r->pool, "#%ld", (long) userdir_id->gid); + } else { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "No user or group set - set suPHP_UserGroup"); + return HTTP_INTERNAL_SERVER_ERROR; + } } #endif @@ -473,22 +884,32 @@ static int suphp_handler(request_rec *r) apr_table_setn(r->subprocess_env, "SUPHP_USER", apr_pstrdup(r->pool, dconf->target_user)); } - else + else if (sconf->target_user) { apr_table_setn(r->subprocess_env, "SUPHP_USER", apr_pstrdup(r->pool, sconf->target_user)); } + else + { + apr_table_setn(r->subprocess_env, "SUPHP_USER", + apr_pstrdup(r->pool, ud_user)); + } if (dconf->target_group) { apr_table_setn(r->subprocess_env, "SUPHP_GROUP", apr_pstrdup(r->pool, dconf->target_group)); } - else + else if (sconf->target_group) { apr_table_setn(r->subprocess_env, "SUPHP_GROUP", apr_pstrdup(r->pool, sconf->target_group)); } + else + { + apr_table_setn(r->subprocess_env, "SUPHP_GROUP", + apr_pstrdup(r->pool, ud_group)); + } #endif env = ap_create_environment(p, r->subprocess_env); @@ -558,7 +979,7 @@ static int suphp_handler(request_rec *r) return rv; } - APR_BRIGADE_FOREACH(bucket, bb) + for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket)) { const char *data; apr_size_t len; @@ -592,33 +1013,41 @@ static int suphp_handler(request_rec *r) /* get output from script and check if non-parsed headers are used */ +#if APR_FILES_AS_SOCKETS + apr_file_pipe_timeout_set(proc->out, 0); + apr_file_pipe_timeout_set(proc->err, 0); + b = suphp_bucket_create(r, proc->out, proc->err, r->connection->bucket_alloc); +#else b = apr_bucket_pipe_create(proc->out, r->connection->bucket_alloc); +#endif + APR_BRIGADE_INSERT_TAIL(bb, b); - len = 8; - if ((suphp_bucket_read(b, strbuf, len) == len) - && !(strcmp(strbuf, "HTTP/1.0") && strcmp(strbuf, "HTTP/1.1"))) + b = apr_bucket_eos_create(r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + + tmpbuf = suphp_brigade_read(p, bb, 8); + if (strlen(tmpbuf) == 8 && !(strncmp(tmpbuf, "HTTP/1.0", 8) && strncmp(tmpbuf, "HTTP/1.1", 8))) { nph = 1; } - b = apr_bucket_eos_create(r->connection->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, b); - - if (proc->out && !nph) + if (!nph) { - /* normal cgi headers, so we have to create the real headers by hand */ + /* normal cgi headers, so we have to create the real headers ourselves */ int ret; const char *location; - - ret = ap_scan_script_header_err_brigade(r, bb, strbuf); - if (ret == HTTP_NOT_MODIFIED) - { - return ret; - } + + ret = ap_scan_script_header_err_brigade(r, bb, strbuf); + if (ret == HTTP_NOT_MODIFIED) + { + return ret; + } else if (ret != APR_SUCCESS) { + suphp_discard_output(bb); + apr_brigade_destroy(bb); suphp_log_script_err(r, proc->err); /* ap_scan_script_header_err_brigade does logging itself, @@ -632,15 +1061,7 @@ static int suphp_handler(request_rec *r) { /* empty brigade (script output) and modify headers */ - const char *buf; - apr_size_t blen; - APR_BRIGADE_FOREACH(b, bb) - { - if (APR_BUCKET_IS_EOS(b)) - break; - if (apr_bucket_read(b, &buf, &blen, APR_BLOCK_READ) != APR_SUCCESS) - break; - } + suphp_discard_output(bb); apr_brigade_destroy(bb); suphp_log_script_err(r, proc->err); r->method = apr_pstrdup(r->pool, "GET"); @@ -653,16 +1074,9 @@ static int suphp_handler(request_rec *r) else if (location && r->status == 200) { /* empty brigade (script output) */ - const char *buf; - apr_size_t blen; - APR_BRIGADE_FOREACH(b, bb) - { - if (APR_BUCKET_IS_EOS(b)) - break; - if (apr_bucket_read(b, &buf, &blen, APR_BLOCK_READ) != APR_SUCCESS) - break; - } + suphp_discard_output(bb); apr_brigade_destroy(bb); + suphp_log_script_err(r, proc->err); return HTTP_MOVED_TEMPORARILY; }