src/server/safs/cgi.c

changeset 516
ec22d4ccd081
parent 503
aeaf7db26fac
child 517
be62c9604377
--- a/src/server/safs/cgi.c	Sun Apr 07 10:25:01 2024 +0200
+++ b/src/server/safs/cgi.c	Sun May 12 11:26:59 2024 +0200
@@ -184,7 +184,7 @@
     writeev->fn = cgi_writeevent;
     writeev->finish = cgi_event_finish;
     
-    
+    handler->readev = readev;
     handler->writeev = writeev;
     
     net_setnonblock(sn->csd, 1);
@@ -263,6 +263,7 @@
             handler->writebuf_size = remaining;
             handler->writebuf_pos = 0;
             
+            /*
             // initialize poll, if it isn't already active
             if(!handler->poll_out) {
                 if(event_pollout(ev, sn->csd, handler->writeev)) {
@@ -272,6 +273,7 @@
                 handler->events++;
                 handler->poll_out = TRUE;
             }
+            */
         } else {
             handler->result = REQ_ABORTED;
             log_ereport(LOG_FAILURE, "cgi_try_write: %s", strerror(net_errno(sn->csd)));
@@ -285,27 +287,62 @@
 int cgi_stdout_readevent(EventHandler *ev, Event *event) {
     CGIHandler *handler = event->cookie;
     
-    int ret = cgi_read_output(handler, ev);
-    if(ret == 0) {
-        handler->wait_read = FALSE;
+    CgiIOResult ret = cgi_read_output(handler, ev);
+    switch(ret) {
+        case CGI_IO_COMPLETE: {
+            break;
+        }
+        case CGI_IO_NEED_READ: {
+            return 1;
+        }
+        case CGI_IO_NEED_WRITE: {
+            if(event_pollout(ev, handler->parser->sn->csd, handler->readev)) {
+                handler->result = REQ_ABORTED;
+            } else {
+                handler->poll_out = TRUE;
+            }
+            break;
+        }
+        case CGI_IO_ERROR: {
+            break;
+        }
     }
-    return ret;
+    
+    handler->wait_read = FALSE;
+    return 0;
 }
 
 int cgi_writeevent(EventHandler *ev, Event *event) {
     CGIHandler *handler = event->cookie;
     
     // cgi_read_output will try to flush the buffer
-    int ret = cgi_read_output(handler, ev);
-    if(ret == 0) {
-        handler->poll_out = FALSE;
+    CgiIOResult ret = cgi_read_output(handler, ev);
+    switch(ret) {
+        case CGI_IO_COMPLETE: {
+            break;
+        }
+        case CGI_IO_NEED_READ: {
+            if(ev_pollin(ev, handler->process.out[0], event)) {
+                handler->result = REQ_ABORTED;
+            } else {
+                handler->wait_read = TRUE;
+            }
+        }
+        case CGI_IO_NEED_WRITE: {
+            return 1;
+        }
+        case CGI_IO_ERROR: {
+            break;
+        }
     }
-    return ret;
+    
+    handler->poll_out = FALSE;
+    return 0;
 }
 
 
 
-int cgi_read_output(CGIHandler *handler, EventHandler *ev) {
+CgiIOResult cgi_read_output(CGIHandler *handler, EventHandler *ev) {
     CGIResponseParser *parser = handler->parser;
     Session *sn = parser->sn;
     Request *rq = parser->rq;
@@ -315,15 +352,16 @@
     if(cgi_try_write_flush(handler, sn)) {
         if(handler->result == REQ_ABORTED) {
             log_ereport(LOG_DEBUG, "cgi-send: req: %p write failed: %s: abort", handler->parser->rq, strerror(net_errno(sn->csd)), rq);
-            return 0;
+            return CGI_IO_ERROR;
         } else {
-            return 1;
+            return CGI_IO_NEED_WRITE;
         }
     }
     
     char buf[4096]; // I/O buffer
     ssize_t r;
     
+    int ret = CGI_IO_COMPLETE;
     handler->result = REQ_PROCEED;
     while((r = read(handler->process.out[0], buf, 4096)) > 0) {
         if(parser->cgiheader) {
@@ -335,7 +373,7 @@
                         "broken cgi script response: path: %s", handler->path);
                 protocol_status(sn, rq, 500, NULL);
                 handler->result = REQ_ABORTED;
-                return 0;
+                return CGI_IO_ERROR;
             } else if(ret == 1) {
                 WS_ASSERT(pos <= r);
                 
@@ -349,22 +387,23 @@
                 handler->response = http_create_response(sn, rq);
                 if(!handler->response) {
                     handler->result = REQ_ABORTED;
-                    return 0;
+                    return CGI_IO_ERROR;
                 }
                 
                 int send_response = http_send_response(handler->response);
                 if(send_response < 0) {
                     handler->result = REQ_ABORTED;
+                    ret = CGI_IO_ERROR;
                     break;
                 } else if(send_response == 1) {
                     // EWOULDBLOCK
                     if(!handler->poll_out) {
                         if(event_pollout(ev, sn->csd, handler->writeev)) {
                             handler->result = REQ_ABORTED;
-                            return 0;
+                            return CGI_IO_ERROR;
                         }
                         handler->poll_out = TRUE;
-                        return 1;
+                        return CGI_IO_NEED_WRITE;
                     }
                 } else {
                     handler->response = NULL;
@@ -372,22 +411,22 @@
                 
                 if(pos < r) {
                     if(cgi_try_write(handler, ev, sn, &buf[pos], r-pos)) {
-                        return handler->result == REQ_ABORTED ? 0 : 1;
+                        return handler->result == REQ_ABORTED ? CGI_IO_ERROR : CGI_IO_NEED_WRITE;
                     }
                 }
             }
         } else {
             parser->response_length += r;
             if(cgi_try_write(handler, ev, sn, buf, r)) {
-                return handler->result == REQ_ABORTED ? 0 : 1;
+                return handler->result == REQ_ABORTED ? CGI_IO_ERROR : CGI_IO_NEED_WRITE;
             }
         }
     }
     if(r < 0 && errno == EWOULDBLOCK) {
-        return 1;
+        return CGI_IO_NEED_READ;
     }
     handler->cgi_eof = TRUE; 
-    return 0;
+    return ret;
 }
 
 int cgi_stderr_readevent(EventHandler *ev, Event *event) {

mercurial