summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam A. Rowe Jr <wrowe@apache.org>2015-06-05 16:50:47 +0000
committerWilliam A. Rowe Jr <wrowe@apache.org>2015-06-05 16:50:47 +0000
commitf40cf5bfb5d8ba531775f92347578f71dbda6332 (patch)
tree8ba2679bfb8a60cc46c0ea7414e5eb6ae36158ea
parentfd377f1545eb06d93e203beacf0711e5498b72f7 (diff)
downloadhttpd-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--CHANGES7
-rw-r--r--STATUS17
-rw-r--r--include/ap_mmn.h3
-rw-r--r--include/http_protocol.h17
-rw-r--r--modules/cache/mod_file_cache.c4
-rw-r--r--modules/dav/fs/repos.c2
-rw-r--r--modules/dav/main/mod_dav.c18
-rw-r--r--modules/generators/mod_asis.c2
-rw-r--r--modules/generators/mod_cgi.c2
-rw-r--r--modules/generators/mod_cgid.c2
-rw-r--r--modules/http/http_filters.c65
-rw-r--r--modules/http/http_request.c76
-rw-r--r--modules/proxy/mod_proxy.c12
-rw-r--r--modules/proxy/mod_proxy_ajp.c77
-rw-r--r--modules/proxy/mod_proxy_http.c8
-rw-r--r--modules/proxy/mod_proxy_scgi.c5
-rw-r--r--modules/ssl/ssl_engine_io.c2
-rw-r--r--server/core.c2
-rw-r--r--server/error_bucket.c3
-rw-r--r--server/util_xml.c1
20 files changed, 196 insertions, 129 deletions
diff --git a/CHANGES b/CHANGES
index 4f11df8855..ebafa68083 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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>]
diff --git a/STATUS b/STATUS
index 7e7f04e5e5..df2da2cf7e 100644
--- a/STATUS
+++ b/STATUS
@@ -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;
}