When the MPM process handling the connection is or will be exiting, we
can incorrectly tell the client that the connection will be held open
after the current request.  This can result in user intervention
(retry the POST?) or failures for some requests sent subsequently on
that connection.

The case where we already know we're exiting at the time we determine
the keep-alive setting is simple to handle:

Index: modules/http/http_protocol.c
===================================================================
--- modules/http/http_protocol.c        (revision 593813)
+++ modules/http/http_protocol.c        (working copy)
@@ -48,6 +48,7 @@
 #include "util_charset.h"
 #include "util_ebcdic.h"
 #include "util_time.h"
+#include "ap_mpm.h"

 #include "mod_core.h"

@@ -187,6 +188,7 @@
      *       or they're a buggy twit coming through a HTTP/1.1 proxy
      *   and    the client is requesting an HTTP/1.0-style keep-alive
      *       or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
+     *   and this MPM process is not already exiting
      *   THEN we can be persistent, which requires more headers be output.
      *
      * Note that the condition evaluation order is extremely important.
@@ -212,7 +214,8 @@
         && (!apr_table_get(r->subprocess_env, "nokeepalive")
             || apr_table_get(r->headers_in, "Via"))
         && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
-            || (r->proto_num >= HTTP_VERSION(1,1)))) {
+            || (r->proto_num >= HTTP_VERSION(1,1)))
+        && !ap_graceful_stop_signalled()) {
         int left = r->server->keep_alive_max - r->connection->keepalives;

         r->connection->keepalive = AP_CONN_KEEPALIVE;

It isn't so clear how to handle the remaining window, in which the MPM
process starts exiting while we send the response (and after we've
already determined the keepalive setting).

>From ap_process_http_connection():

        if (r->status == HTTP_OK) {
            cs->state = CONN_STATE_HANDLER;
            ap_process_request(r);
            r = NULL;
        }

        if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
            break;

        XXXXXXXXXXX
        We could skip checking for graceful exit here since it is checked
        as part of the keepalive determination, but the MPM process
        could remain active much longer than expected (maybe we just
        downloaded a very large file).
        XXXXXXXXXXX

        if (ap_graceful_stop_signalled())
            break;

For the remaining timing window, I'm afraid that a vhost-specific
setting is needed to control whether we respect the connection
keepalive setting or the MPM state.   (The latter is apparently good
enough for most folks, and it does avoid unexpected delays in child
processes exiting and switching to new configs.)

Thoughts?

Reply via email to