diff options
author | William A. Rowe Jr <wrowe@apache.org> | 2015-06-05 16:50:47 +0000 |
---|---|---|
committer | William A. Rowe Jr <wrowe@apache.org> | 2015-06-05 16:50:47 +0000 |
commit | f40cf5bfb5d8ba531775f92347578f71dbda6332 (patch) | |
tree | 8ba2679bfb8a60cc46c0ea7414e5eb6ae36158ea | |
parent | fd377f1545eb06d93e203beacf0711e5498b72f7 (diff) | |
download | httpd-f40cf5bfb5d8ba531775f92347578f71dbda6332.tar.gz |
core, modules: Avoid error response/document handling by the core if some
handler or input filter already did it while reading the request (causing
a double response body).
Submitted by: ylavic
Backports: r1482522 (partial, ap_map_http_request_error() things only!),
r1529988, r1529991, r1643537, r1643543, r1657897, r1665625,
r1665721, r1674056
Reviewed by: ylavic, wrowe, covener
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1683808 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | STATUS | 17 | ||||
-rw-r--r-- | include/ap_mmn.h | 3 | ||||
-rw-r--r-- | include/http_protocol.h | 17 | ||||
-rw-r--r-- | modules/cache/mod_file_cache.c | 4 | ||||
-rw-r--r-- | modules/dav/fs/repos.c | 2 | ||||
-rw-r--r-- | modules/dav/main/mod_dav.c | 18 | ||||
-rw-r--r-- | modules/generators/mod_asis.c | 2 | ||||
-rw-r--r-- | modules/generators/mod_cgi.c | 2 | ||||
-rw-r--r-- | modules/generators/mod_cgid.c | 2 | ||||
-rw-r--r-- | modules/http/http_filters.c | 65 | ||||
-rw-r--r-- | modules/http/http_request.c | 76 | ||||
-rw-r--r-- | modules/proxy/mod_proxy.c | 12 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_ajp.c | 77 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_http.c | 8 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_scgi.c | 5 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_io.c | 2 | ||||
-rw-r--r-- | server/core.c | 2 | ||||
-rw-r--r-- | server/error_bucket.c | 3 | ||||
-rw-r--r-- | server/util_xml.c | 1 |
20 files changed, 196 insertions, 129 deletions
@@ -1,6 +1,13 @@ -*- coding: utf-8 -*- Changes with Apache 2.2.30 + *) http: Make ap_die() robust against any HTTP error code and not modify + response status (finally logged) when nothing is to be done. [Yann Ylavic] + + *) core, modules: Avoid error response/document handling by the core if some + handler or input filter already did it while reading the request (causing + a double response body). [Yann Ylavic] + *) FreeBSD: Disable IPv4-mapped listening sockets by default for versions 5+ instead of just for FreeBSD 5. PR 53824. [Jeff Trawick, Olli Hauer <ohauer gmx de>] @@ -109,23 +109,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: (modulo CHANGES) +1: ylavic, wrowe, covener - *) core, modules: Avoid error response/document handling by the core if some - handler or input filter already did it while reading the request (causing - a double response body). - trunk patch: http://svn.apache.org/r1482522 (partial, ap_map_http_request_error() things only!) - http://svn.apache.org/r1529988 - http://svn.apache.org/r1529991 - http://svn.apache.org/r1643537 - http://svn.apache.org/r1643543 - http://svn.apache.org/r1657897 - http://svn.apache.org/r1665625 - http://svn.apache.org/r1665721 - http://svn.apache.org/r1674056 - 2.4.x patch: http://people.apache.org/~ylavic/httpd-2.4.x-ap_map_http_request_error-v2.patch - 2.2.x patch: http://people.apache.org/~ylavic/httpd-2.2.x-ap_map_http_request_error-v2.patch - +1: ylavic, wrowe, covener - ylavic: Depends on httpd-2.2.x-ap_die.patch above. - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index eb2a4a67ac..d532d7e61f 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -157,6 +157,7 @@ * 20051115.37 (2.2.30) Add ap_get_server_name_for_url() * 20051115.38 (2.2.30) Add ap_proxy_set_scoreboard_lb() in mod_proxy.h * 20051115.39 (2.2.30) Add ap_proxy_connection_reusable() + * 20051115.40 (2.2.30) Add ap_map_http_request_error() */ #define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */ @@ -164,7 +165,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20051115 #endif -#define MODULE_MAGIC_NUMBER_MINOR 39 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 40 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_protocol.h b/include/http_protocol.h index 76e3436c11..185d62cc98 100644 --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -432,6 +432,23 @@ AP_DECLARE(int) ap_should_client_block(request_rec *r); */ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz); +/* + * Map specific APR codes returned by the filter stack to HTTP error + * codes, or the default status code provided. Use it as follows: + * + * return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); + * + * If the filter has already handled the error, AP_FILTER_ERROR will + * be returned, which is cleanly passed through. + * + * These mappings imply that the filter stack is reading from the + * downstream client, the proxy will map these codes differently. + * @param rv APR status code + * @param status Default HTTP code should the APR code not be recognised + * @return Mapped HTTP status code + */ +AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status); + /** * In HTTP/1.1, any method can have a body. However, most GET handlers * wouldn't know what to do with a request body if they received one. diff --git a/modules/cache/mod_file_cache.c b/modules/cache/mod_file_cache.c index 17ec6f4a81..4449bad3af 100644 --- a/modules/cache/mod_file_cache.c +++ b/modules/cache/mod_file_cache.c @@ -285,7 +285,7 @@ static int mmap_handler(request_rec *r, a_file *file) APR_BRIGADE_INSERT_TAIL(bb, b); if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) - return HTTP_INTERNAL_SERVER_ERROR; + return AP_FILTER_ERROR; #endif return OK; } @@ -304,7 +304,7 @@ static int sendfile_handler(request_rec *r, a_file *file) APR_BRIGADE_INSERT_TAIL(bb, b); if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) - return HTTP_INTERNAL_SERVER_ERROR; + return AP_FILTER_ERROR; #endif return OK; } diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 6723becbf8..0ec7bc87f9 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -999,7 +999,7 @@ static dav_error * dav_fs_deliver(const dav_resource *resource, APR_BRIGADE_INSERT_TAIL(bb, bkt); if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { - return dav_new_error(pool, HTTP_FORBIDDEN, 0, + return dav_new_error(pool, AP_FILTER_ERROR, 0, "Could not write contents to filter."); } diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index 83f3dd1243..4c5d8924f4 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -593,6 +593,11 @@ static int dav_handle_err(request_rec *r, dav_error *err, /* log the errors */ dav_log_err(r, err, APLOG_ERR); + if (!ap_is_HTTP_VALID_RESPONSE(err->status)) { + /* we have responded already */ + return AP_FILTER_ERROR; + } + if (response == NULL) { dav_error *stackerr = err; @@ -1004,8 +1009,17 @@ static int dav_method_put(request_rec *r) APR_BLOCK_READ, DAV_READ_BLOCKSIZE); if (rc != APR_SUCCESS) { - err = dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "Could not get next bucket brigade"); + int http_err; + const char *msg; + if (APR_STATUS_IS_TIMEUP(rc)) { + http_err = HTTP_REQUEST_TIME_OUT; + msg = "Timeout reading the body"; + } + else { + http_err = ap_map_http_request_error(rc, HTTP_BAD_REQUEST); + msg = "Error reading the body"; + } + err = dav_new_error(r->pool, http_err, 0, msg); break; } diff --git a/modules/generators/mod_asis.c b/modules/generators/mod_asis.c index 1ed2f67070..bf9bf59ff0 100644 --- a/modules/generators/mod_asis.c +++ b/modules/generators/mod_asis.c @@ -118,7 +118,7 @@ static int asis_handler(request_rec *r) if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "mod_asis: ap_pass_brigade failed for file %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; + return AP_FILTER_ERROR; } } else { diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c index f9980f9d2a..837bedcdcc 100644 --- a/modules/generators/mod_cgi.c +++ b/modules/generators/mod_cgi.c @@ -839,7 +839,7 @@ static int cgi_handler(request_rec *r) if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Error reading request entity data"); - return HTTP_INTERNAL_SERVER_ERROR; + return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); } for (bucket = APR_BRIGADE_FIRST(bb); diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c index f8705e3b3d..768d9211ae 100644 --- a/modules/generators/mod_cgid.c +++ b/modules/generators/mod_cgid.c @@ -1472,7 +1472,7 @@ static int cgid_handler(request_rec *r) if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Error reading request entity data"); - return HTTP_INTERNAL_SERVER_ERROR; + return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); } for (bucket = APR_BRIGADE_FIRST(bb); diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 0c4b67a05b..347df85ebc 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -418,7 +418,10 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, e = apr_bucket_flush_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); - ap_pass_brigade(f->c->output_filters, bb); + rv = ap_pass_brigade(f->c->output_filters, bb); + if (rv != APR_SUCCESS) { + return AP_FILTER_ERROR; + } } } @@ -1398,6 +1401,39 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, return ap_pass_brigade(f->next, b); } +/* + * Map specific APR codes returned by the filter stack to HTTP error + * codes, or the default status code provided. Use it as follows: + * + * return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); + * + * If the filter has already handled the error, AP_FILTER_ERROR will + * be returned, which is cleanly passed through. + * + * These mappings imply that the filter stack is reading from the + * downstream client, the proxy will map these codes differently. + */ +AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status) +{ + switch (rv) { + case AP_FILTER_ERROR: { + return AP_FILTER_ERROR; + } + case APR_ENOSPC: { + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + case APR_ENOTIMPL: { + return HTTP_NOT_IMPLEMENTED; + } + case APR_ETIMEDOUT: { + return HTTP_REQUEST_TIME_OUT; + } + default: { + return status; + } + } +} + /* In HTTP/1.1, any method can have a body. However, most GET handlers * wouldn't know what to do with a request body if they received one. * This helper routine tests for and reads any message body in the request, @@ -1415,7 +1451,8 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, AP_DECLARE(int) ap_discard_request_body(request_rec *r) { apr_bucket_brigade *bb; - int rv, seen_eos; + int seen_eos; + apr_status_t rv; /* Sometimes we'll get in a state where the input handling has * detected an error where we want to drop the connection, so if @@ -1438,21 +1475,8 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r) APR_BLOCK_READ, HUGE_STRING_LEN); if (rv != APR_SUCCESS) { - /* FIXME: If we ever have a mapping from filters (apr_status_t) - * to HTTP error codes, this would be a good place for them. - * - * If we received the special case AP_FILTER_ERROR, it means - * that the filters have already handled this error. - * Otherwise, we should assume we have a bad request. - */ - if (rv == AP_FILTER_ERROR) { - apr_brigade_destroy(bb); - return rv; - } - else { - apr_brigade_destroy(bb); - return HTTP_BAD_REQUEST; - } + apr_brigade_destroy(bb); + return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); } for (bucket = APR_BRIGADE_FIRST(bb); @@ -1622,6 +1646,13 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, /* We lose the failure code here. This is why ap_get_client_block should * not be used. */ + if (rv == AP_FILTER_ERROR) { + /* AP_FILTER_ERROR means a filter has responded already, + * we are DONE. + */ + apr_brigade_destroy(bb); + return -1; + } if (rv != APR_SUCCESS) { /* if we actually fail here, we want to just return and * stop trying to read data from the client. diff --git a/modules/http/http_request.c b/modules/http/http_request.c index aedee167ba..fc8d43309d 100644 --- a/modules/http/http_request.c +++ b/modules/http/http_request.c @@ -72,19 +72,22 @@ static void update_r_in_filters(ap_filter_t *f, } } -AP_DECLARE(void) ap_die(int type, request_rec *r) +static void ap_die_r(int type, request_rec *r, int recursive_error) { - int error_index = ap_index_of_response(type); - char *custom_response = ap_response_code_string(r, error_index); - int recursive_error = 0; + char *custom_response; request_rec *r_1st_err = r; - if (type == AP_FILTER_ERROR) { + if (type == OK || type == DONE) { + ap_finalize_request_protocol(r); + return; + } + + if (!ap_is_HTTP_VALID_RESPONSE(type)) { ap_filter_t *next; /* * Check if we still have the ap_http_header_filter in place. If - * this is the case we should not ignore AP_FILTER_ERROR here because + * this is the case we should not ignore the error here because * it means that we have not sent any response at all and never * will. This is bad. Sent an internal server error instead. */ @@ -98,8 +101,14 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) * next->frec == ap_http_header_filter */ if (next) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "Custom error page caused AP_FILTER_ERROR"); + if (type != AP_FILTER_ERROR) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Invalid response status %i", type); + } + else { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Response from AP_FILTER_ERROR"); + } type = HTTP_INTERNAL_SERVER_ERROR; } else { @@ -107,20 +116,13 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) } } - if (type == DONE) { - ap_finalize_request_protocol(r); - return; - } - /* * The following takes care of Apache redirects to custom response URLs * Note that if we are already dealing with the response to some other * error condition, we just report on the original error, and give up on * any attempt to handle the other thing "intelligently"... */ - if (r->status != HTTP_OK) { - recursive_error = type; - + if (recursive_error != HTTP_OK) { while (r_1st_err->prev && (r_1st_err->prev->status != HTTP_OK)) r_1st_err = r_1st_err->prev; /* Get back to original error */ @@ -140,6 +142,11 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) custom_response = NULL; /* Do NOT retry the custom thing! */ } + else { + int error_index = ap_index_of_response(type); + custom_response = ap_response_code_string(r, error_index); + recursive_error = 0; + } r->status = type; @@ -215,6 +222,11 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) ap_send_error_response(r_1st_err, recursive_error); } +AP_DECLARE(void) ap_die(int type, request_rec *r) +{ + ap_die_r(type, r, r->status); +} + static void check_pipeline_flush(request_rec *r) { apr_bucket *e; @@ -283,18 +295,7 @@ void ap_process_request(request_rec *r) } } - if (access_status == DONE) { - /* e.g., something not in storage like TRACE */ - access_status = OK; - } - - if (access_status == OK) { - ap_finalize_request_protocol(r); - } - else { - r->status = HTTP_OK; - ap_die(access_status, r); - } + ap_die_r(access_status, r, HTTP_OK); /* * We want to flush the last packet if this isn't a pipelining connection @@ -543,8 +544,8 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r) AP_DECLARE(void) ap_internal_redirect(const char *new_uri, request_rec *r) { - request_rec *new = internal_internal_redirect(new_uri, r); int access_status; + request_rec *new = internal_internal_redirect(new_uri, r); /* ap_die was already called, if an error occured */ if (!new) { @@ -558,12 +559,7 @@ AP_DECLARE(void) ap_internal_redirect(const char *new_uri, request_rec *r) access_status = ap_invoke_handler(new); } } - if (access_status == OK) { - ap_finalize_request_protocol(new); - } - else { - ap_die(access_status, new); - } + ap_die(access_status, new); } /* This function is designed for things like actions or CGI scripts, when @@ -584,15 +580,9 @@ AP_DECLARE(void) ap_internal_redirect_handler(const char *new_uri, request_rec * ap_set_content_type(new, r->content_type); access_status = ap_process_request_internal(new); if (access_status == OK) { - if ((access_status = ap_invoke_handler(new)) != 0) { - ap_die(access_status, new); - return; - } - ap_finalize_request_protocol(new); - } - else { - ap_die(access_status, new); + access_status = ap_invoke_handler(new); } + ap_die(access_status, new); } AP_DECLARE(void) ap_allow_methods(request_rec *r, int reset, ...) diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 0c80e82cb8..b5e7fee2cc 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -850,19 +850,15 @@ static int proxy_handler(request_rec *r) case M_TRACE: { int access_status; r->proxyreq = PROXYREQ_NONE; - if ((access_status = ap_send_http_trace(r))) - ap_die(access_status, r); - else - ap_finalize_request_protocol(r); + access_status = ap_send_http_trace(r); + ap_die(access_status, r); return OK; } case M_OPTIONS: { int access_status; r->proxyreq = PROXYREQ_NONE; - if ((access_status = ap_send_http_options(r))) - ap_die(access_status, r); - else - ap_finalize_request_protocol(r); + access_status = ap_send_http_options(r); + ap_die(access_status, r); return OK; } default: { diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index 8e59b1beb4..9e6f75773f 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -174,13 +174,13 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, apr_byte_t conn_reuse = 0; const char *tenc; int havebody = 1; - int output_failed = 0; + int client_failed = 0; int backend_failed = 0; apr_off_t bb_len; int data_sent = 0; int request_ended = 0; int headers_sent = 0; - int rv = 0; + int rv = OK; apr_int32_t conn_poll_fd; apr_pollfd_t *conn_poll; proxy_server_conf *psf = @@ -256,10 +256,10 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, if (status != APR_SUCCESS) { /* We had a failure: Close connection to backend */ conn->close++; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + ap_log_error(APLOG_MARK, APLOG_DEBUG, status, r->server, "proxy: ap_get_brigade failed"); apr_brigade_destroy(input_brigade); - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } /* have something */ @@ -390,7 +390,13 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, ap_log_error(APLOG_MARK, APLOG_DEBUG, status, r->server, "ap_get_brigade failed"); - output_failed = 1; + if (APR_STATUS_IS_TIMEUP(status)) { + rv = HTTP_REQUEST_TIME_OUT; + } + else if (status == AP_FILTER_ERROR) { + rv = AP_FILTER_ERROR; + } + client_failed = 1; break; } bufsiz = maxsize; @@ -401,7 +407,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, ap_log_error(APLOG_MARK, APLOG_DEBUG, status, r->server, "apr_brigade_flatten failed"); - output_failed = 1; + rv = HTTP_INTERNAL_SERVER_ERROR; + client_failed = 1; break; } } @@ -513,7 +520,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, "proxy: error processing body.%s", r->connection->aborted ? " Client aborted connection." : ""); - output_failed = 1; + client_failed = 1; } data_sent = 1; apr_brigade_cleanup(output_brigade); @@ -540,7 +547,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, output_brigade) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "proxy: error processing end"); - output_failed = 1; + client_failed = 1; } /* XXX: what about flush here? See mod_jk */ data_sent = 1; @@ -554,23 +561,27 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, /* * If connection has been aborted by client: Stop working. - * Nevertheless, we regard our operation so far as a success: - * So reset output_failed to 0 and set result to CMD_AJP13_END_RESPONSE - * But: Close this connection to the backend. + * Pretend we are done (data_sent) to avoid further processing. */ if (r->connection->aborted) { - conn->close++; - output_failed = 0; - result = CMD_AJP13_END_RESPONSE; - request_ended = 1; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "client connection aborted"); + /* no response yet (or ever), set status for access log */ + if (!headers_sent) { + r->status = HTTP_BAD_REQUEST; + } + client_failed = 1; + /* return DONE */ + data_sent = 1; + break; } /* * We either have finished successfully or we failed. * So bail out */ - if ((result == CMD_AJP13_END_RESPONSE) || backend_failed - || output_failed) + if ((result == CMD_AJP13_END_RESPONSE) + || backend_failed || client_failed) break; /* read the response */ @@ -592,14 +603,14 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, */ apr_brigade_cleanup(output_brigade); - if (backend_failed || output_failed) { + if (backend_failed || client_failed) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: Processing of request failed backend: %i, " - "output: %i", backend_failed, output_failed); + "Processing of request failed backend: %i, client: %i", + backend_failed, client_failed); /* We had a failure: Close connection to backend */ - conn->close++; - /* Return DONE to avoid error messages being added to the stream */ + conn->close = 1; if (data_sent) { + /* Return DONE to avoid error messages being added to the stream */ rv = DONE; } } @@ -609,8 +620,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, /* We had a failure: Close connection to backend */ conn->close++; backend_failed = 1; - /* Return DONE to avoid error messages being added to the stream */ if (data_sent) { + /* Return DONE to avoid error messages being added to the stream */ rv = DONE; } } @@ -659,6 +670,15 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, rv = HTTP_INTERNAL_SERVER_ERROR; } } + else if (client_failed) { + int level = (r->connection->aborted) ? APLOG_DEBUG : APLOG_ERR; + ap_log_error(APLOG_MARK, level, status, r->server, + "dialog with client %pI failed", + r->connection->remote_addr); + if (rv == OK) { + rv = HTTP_BAD_REQUEST; + } + } /* * Ensure that we sent an EOS bucket thru the filter chain, if we already @@ -666,14 +686,17 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, * one to the brigade already (no longer making it empty). So we should * not do this in this case. */ - if (data_sent && !r->eos_sent && APR_BRIGADE_EMPTY(output_brigade)) { + if (data_sent && !r->eos_sent && !r->connection->aborted + && APR_BRIGADE_EMPTY(output_brigade)) { e = apr_bucket_eos_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(output_brigade, e); } - /* If we have added something to the brigade above, sent it */ - if (!APR_BRIGADE_EMPTY(output_brigade)) - ap_pass_brigade(r->output_filters, output_brigade); + /* If we have added something to the brigade above, send it */ + if (!APR_BRIGADE_EMPTY(output_brigade) + && ap_pass_brigade(r->output_filters, output_brigade) != APR_SUCCESS) { + rv = AP_FILTER_ERROR; + } apr_brigade_destroy(output_brigade); diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 24ca8eca3c..261c946d63 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -383,7 +383,7 @@ static int stream_reqbody_chunked(apr_pool_t *p, HUGE_STRING_LEN); if (status != APR_SUCCESS) { - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } } @@ -518,7 +518,7 @@ static int stream_reqbody_cl(apr_pool_t *p, HUGE_STRING_LEN); if (status != APR_SUCCESS) { - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } } @@ -647,7 +647,7 @@ static int spool_reqbody_cl(apr_pool_t *p, HUGE_STRING_LEN); if (status != APR_SUCCESS) { - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } } @@ -1000,7 +1000,7 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, " from %s (%s)", p_conn->addr, p_conn->hostname ? p_conn->hostname: "", c->remote_ip, c->remote_host ? c->remote_host: ""); - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } apr_brigade_length(temp_brigade, 1, &bytes); diff --git a/modules/proxy/mod_proxy_scgi.c b/modules/proxy/mod_proxy_scgi.c index b9f05c0e5e..fe9b95afe9 100644 --- a/modules/proxy/mod_proxy_scgi.c +++ b/modules/proxy/mod_proxy_scgi.c @@ -421,8 +421,9 @@ static int pass_response(request_rec *r, proxy_conn_rec *conn) } } - /* XXX: What could we do with that return code? */ - (void)ap_pass_brigade(r->output_filters, bb); + if (ap_pass_brigade(r->output_filters, bb)) { + return AP_FILTER_ERROR; + } return OK; } diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index 7884a0a121..f2869eb2db 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -1610,7 +1610,7 @@ int ssl_io_buffer_fill(request_rec *r, apr_size_t maxlen) if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not read request body for SSL buffer"); - return HTTP_INTERNAL_SERVER_ERROR; + return ap_map_http_request_error(rv, HTTP_INTERNAL_SERVER_ERROR); } /* Iterate through the returned brigade: setaside each bucket diff --git a/server/core.c b/server/core.c index 4f2df326ba..ddcfa6004b 100644 --- a/server/core.c +++ b/server/core.c @@ -3839,7 +3839,7 @@ static int default_handler(request_rec *r) ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, "default_handler: ap_pass_brigade returned %i", status); - return HTTP_INTERNAL_SERVER_ERROR; + return AP_FILTER_ERROR; } } else { /* unusual method (not GET or POST) */ diff --git a/server/error_bucket.c b/server/error_bucket.c index d113c171a8..8b69343beb 100644 --- a/server/error_bucket.c +++ b/server/error_bucket.c @@ -61,6 +61,9 @@ AP_DECLARE(apr_bucket *) ap_bucket_error_create(int error, const char *buf, APR_BUCKET_INIT(b); b->free = apr_bucket_free; b->list = list; + if (!ap_is_HTTP_VALID_RESPONSE(error)) { + error = HTTP_INTERNAL_SERVER_ERROR; + } return ap_bucket_error_make(b, error, buf, p); } diff --git a/server/util_xml.c b/server/util_xml.c index dc88b3ddbe..9d58578a79 100644 --- a/server/util_xml.c +++ b/server/util_xml.c @@ -55,6 +55,7 @@ AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc) READ_BLOCKSIZE); if (status != APR_SUCCESS) { + result = ap_map_http_request_error(status, HTTP_BAD_REQUEST); goto read_error; } |