fix cgi-send inactive write event blocking request termination

Sat, 10 Jun 2023 18:12:04 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 10 Jun 2023 18:12:04 +0200
changeset 501
2aa6bd9f166f
parent 500
077aa138e8fb
child 502
11ac3761c0e3

fix cgi-send inactive write event blocking request termination

src/server/safs/cgi.c file | annotate | diff | comparison | revisions
src/server/safs/cgi.h file | annotate | diff | comparison | revisions
--- a/src/server/safs/cgi.c	Wed Jun 07 15:59:00 2023 +0200
+++ b/src/server/safs/cgi.c	Sat Jun 10 18:12:04 2023 +0200
@@ -227,12 +227,16 @@
         if(errno != EWOULDBLOCK) {
             handler->result = REQ_ABORTED;
         }
+        handler->wait_write = TRUE;
         return 1;
+    } else {
+        handler->wait_write = FALSE;
     }
     return 0;
 }
 
 static int cgi_try_write(CGIHandler *handler, EventHandler *ev, Session *sn, char *buf, size_t size) {
+    handler->wait_write = FALSE;
     size_t pos = 0;
     ssize_t wr = 0;
     while(size - pos > 0 && (wr = net_write(sn->csd, buf + pos, size - pos)) > 0) {
@@ -264,6 +268,7 @@
                 handler->events++;
                 handler->poll_out = TRUE;
             }
+            handler->wait_write = TRUE;
         } else {
             handler->result = REQ_ABORTED;
             log_ereport(LOG_FAILURE, "cgi_try_write: %s", strerror(errno));
@@ -298,7 +303,7 @@
     // if writebuf is empty, this does nothing and returns 0
     if(cgi_try_write_flush(handler, sn)) {
         if(handler->result == REQ_ABORTED) {
-            log_ereport(LOG_DEBUG, "cgi-send: req: %p write failed: abort", rq);
+            log_ereport(LOG_DEBUG, "cgi-send: req: %p write failed: %s: abort", strerror(errno), rq);
             return 0;
         } else {
             return 1;
@@ -370,7 +375,7 @@
     if(r < 0 && errno == EWOULDBLOCK) {
         return 1;
     }
-    
+      
     return 0;
 }
 
@@ -467,10 +472,17 @@
     CGIResponseParser *parser = handler->parser;
     Session *sn = parser->sn;
     Request *rq = parser->rq;
-      
-    log_ereport(LOG_DEBUG, "cgi-send: req: %p event-finish %d", rq, handler->events);
+    
     if(--handler->events > 0) {
-        return 0;
+        if(handler->events == 1 && handler->poll_out && !handler->wait_write) {
+            // write event registered, however it will not be activated anymore
+            // we can safely remove the event
+            if(event_removepoll(ev, sn->csd)) {
+                log_ereport(LOG_FAILURE, "cgi_event_finish: event_removepoll: %s", strerror(errno));
+            }
+        } else {
+            return 0;
+        }
     }
     
     if(handler->result == REQ_ABORTED && handler->process.pid != 0) {
--- a/src/server/safs/cgi.h	Wed Jun 07 15:59:00 2023 +0200
+++ b/src/server/safs/cgi.h	Sat Jun 10 18:12:04 2023 +0200
@@ -109,6 +109,12 @@
     WSBool poll_out;
     
     /*
+     * last write returned EWOULDBLOCK
+     * waiting for the next write event
+     */
+    WSBool wait_write;
+    
+    /*
      * number of currently open events (stdout, stderr, [stdout])
      */
     int events;

mercurial