You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Yann Ylavic <yl...@gmail.com> on 2017/11/08 23:26:02 UTC

Re: [Bug 61551] Event MPM workers stuck in Gracefully Finishing with no connections left

On Sun, Oct 1, 2017 at 2:50 PM,  <bu...@apache.org> wrote:
> https://bz.apache.org/bugzilla/show_bug.cgi?id=61551
>
> --- Comment #18 from Eric Covener <co...@gmail.com> ---
>
> Maybe a bit premature to ask mod_Security to make a change API wise.
>
> Looks like a process_connection() hook could complete without changing
> the state and there is no catch-all for that in process_socket(). Yann,
> probably up your alley how we could ditch that connection.  Hard for
> mod_security to know we expect it to do anything (set it to linger? How about
> allowing errors returned by process_connection?

I came up to the same solution, how about:

Index: server/mpm/event/event.c
===================================================================
--- server/mpm/event/event.c    (revision 1814399)
+++ server/mpm/event/event.c    (working copy)
@@ -1010,8 +1010,8 @@ static void process_socket(apr_thread_t *thd, apr_
          * otherwise write, should set the sense appropriately.
          */
         apr_atomic_inc32(&clogged_count);
-        ap_run_process_connection(c);
-        if (cs->pub.state != CONN_STATE_SUSPENDED) {
+        rc = ap_run_process_connection(c);
+        if (rc || cs->pub.state != CONN_STATE_SUSPENDED) {
             cs->pub.state = CONN_STATE_LINGER;
         }
         apr_atomic_dec32(&clogged_count);
@@ -1018,12 +1018,23 @@ static void process_socket(apr_thread_t *thd, apr_
     }
     else if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE) {
 read_request:
-        ap_run_process_connection(c);
+        rc = ap_run_process_connection(c);

-        /* state will be updated upon return
-         * fall thru to either wait for readability/timeout or
-         * do lingering close
+        /* State will be updated upon successful return: fall thru to either
+         * wait for readability/timeout, do write completion or lingering
+         * close. But forcibly close the connection if the run failed (handler
+         * raised an error for it) or the state is something unexpected at the
+         * MPM level (meaning that no module handled it and we can't do much
+         * here; note that if a handler wants mpm_event to keep POLLIN for the
+         * rest of the request line it should use CHECK_REQUEST_LINE_READABLE
+         * and not simply return OK with the initial READ_REQUEST_LINE state).
          */
+        if (rc || (cs->pub.state != CONN_STATE_CHECK_REQUEST_LINE_READABLE
+                   && cs->pub.state != CONN_STATE_WRITE_COMPLETION
+                   && cs->pub.state != CONN_STATE_SUSPENDED
+                   && cs->pub.state != CONN_STATE_LINGER)) {
+            cs->pub.state = CONN_STATE_LINGER;
+        }
     }

     if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {
?

It shouldn't break anything since no module/handler can currently
return any other state without mpm_event to simply forget about the
connection (leak it).
I also don't see why we should continue if some process_connection hook failed.

That should address the mod_security case I think.

Thoughts?