]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
core, modules: Avoid error response/document handling by the core if some
authorWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 5 Jun 2015 16:50:47 +0000 (16:50 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 5 Jun 2015 16:50:47 +0000 (16:50 +0000)
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

20 files changed:
CHANGES
STATUS
include/ap_mmn.h
include/http_protocol.h
modules/cache/mod_file_cache.c
modules/dav/fs/repos.c
modules/dav/main/mod_dav.c
modules/generators/mod_asis.c
modules/generators/mod_cgi.c
modules/generators/mod_cgid.c
modules/http/http_filters.c
modules/http/http_request.c
modules/proxy/mod_proxy.c
modules/proxy/mod_proxy_ajp.c
modules/proxy/mod_proxy_http.c
modules/proxy/mod_proxy_scgi.c
modules/ssl/ssl_engine_io.c
server/core.c
server/error_bucket.c
server/util_xml.c

diff --git a/CHANGES b/CHANGES
index 4f11df885599fad47eb1287c3c1c71890a29d83f..ebafa680838aab48cd238fce9331a32f51e28ffe 100644 (file)
--- 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 7e7f04e5e525b7e22697c9a6e68fcf17bdbd9186..df2da2cf7eff4df961b54939d393a06d5f7d1774 100644 (file)
--- 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 ]
index eb2a4a67ac320e7c22655201aae61eb5d93dac27..d532d7e61fa4df4865ced89874338436a9e91db3 100644 (file)
  * 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" */
 #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
index 76e3436c115e2e8626a3cc38b5409ea6846892a4..185d62cc985bf1734634e3dfdd3d604a8b9f9cd2 100644 (file)
@@ -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.
index 17ec6f4a81230e75805d4e7c7c3fd38956a5fea7..4449bad3af51b07e7cf9dd110d4c9d290fe494f2 100644 (file)
@@ -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;
 }
index 6723becbf878cd067a5413c8033ffdc11048eee0..0ec7bc87f91935c5054d0b6614ad58e58ca6b0c5 100644 (file)
@@ -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.");
     }
 
index 83f3dd1243e4490bb349a2d89bff92e72f2a6195..4c5d8924f423d1245f64fa3a97664ac97d644665 100644 (file)
@@ -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;
             }
 
index 1ed2f67070ac4254cd3cacf789c4986d47ef64d4..bf9bf59ff0c8ac223a8ff5b5f77b4a2f076f9b79 100644 (file)
@@ -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 {
index f9980f9d2a662077ba58eacc97aacd1238f8ef21..837bedcdcc5647717935c13104db27066bcd1e53 100644 (file)
@@ -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);
index f8705e3b3d8cd4b4befef389a0798ab43493fba1..768d9211ae6a1f20b1e15a84cc71b0bbe880c89a 100644 (file)
@@ -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);
index 0c4b67a05b2a184dc230e4cd15b51052af51d9d4..347df85ebc375b13f5de0158fe1e4219e1072ff1 100644 (file)
@@ -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.
index aedee167bae09f064173ea794c5a79e0e479ab22..fc8d43309d57e80cb4fff83f2250fc2ea4e57e4e 100644 (file)
@@ -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, ...)
index 0c80e82cb893d1dfc0fdf792292d78cf5ee4bbae..b5e7fee2cc8288df19234f3960321edc6a6de3fa 100644 (file)
@@ -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: {
index 8e59b1beb42c3c0b895076d25f74ec76b288760f..9e6f75773fef24674a8328e3390e9ca1c3f80840 100644 (file)
@@ -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);
 
index 24ca8eca3ce6a81d7a0efc1321d99adfd73dc670..261c946d63123dcfd5ede62eed5b6c253b21427b 100644 (file)
@@ -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);
index b9f05c0e5e00cb56eec3654058b757c6045d316a..fe9b95afe91608c4b7be593e47b248131fbc68f1 100644 (file)
@@ -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;
 }
index 7884a0a121bfd61e39035179f68fec48dd356a30..f2869eb2dbaa20f3e2f0faf3f152398b452af01e 100644 (file)
@@ -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
index 4f2df326ba6837b7079cc05ff7ee3bc23d3136e5..ddcfa6004b6ed83ff3e86c65cf5647b9274c9ff3 100644 (file)
@@ -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) */
index d113c171a8dece1fd2993ee8921d74e1f329d762..8b69343beb4389126777977a47216da0acd6063f 100644 (file)
@@ -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);
 }
 
index dc88b3ddbe316fc9696ae9513b0e829a818daf27..9d58578a7990ad26f4e1dcd65cefecde167a5346 100644 (file)
@@ -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;
         }