add request timeout handler

Sat, 24 Aug 2024 12:13:01 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 24 Aug 2024 12:13:01 +0200
changeset 554
e0a6b761ddbc
parent 553
a166a15f7b74
child 555
66b0accda0a8

add request timeout handler

src/server/daemon/httplistener.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.h file | annotate | diff | comparison | revisions
--- a/src/server/daemon/httplistener.c	Tue Aug 20 12:34:32 2024 +0200
+++ b/src/server/daemon/httplistener.c	Sat Aug 24 12:13:01 2024 +0200
@@ -747,7 +747,7 @@
         return 1;
     }
 
-    int keepidle = 60;
+    int keepidle = 240;
     if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle))) {
         log_ereport(LOG_FAILURE, "listener: cannot set TCP_KEEPIDLE to value %d: %s", keepidle, strerror(errno));
         return 1;
--- a/src/server/daemon/sessionhandler.c	Tue Aug 20 12:34:32 2024 +0200
+++ b/src/server/daemon/sessionhandler.c	Sat Aug 24 12:13:01 2024 +0200
@@ -42,6 +42,8 @@
 struct EventHttpIO {
     HTTPRequest  *request;
     HttpParser   *parser;
+    EVWatchList  watch;
+    Event        *io_event;
     int          error;
 };
 
@@ -221,6 +223,26 @@
     return (SessionHandler*)handler;
 }
 
+void evt_request_timeout(EventHandler *h, EVWatchList *item) {
+    log_ereport(LOG_VERBOSE, "sessionhandler: request timeout");
+    item->intdata = 0;
+    
+    EventHttpIO *io = item->data1;
+    io->error = 4;
+    
+    if(ev_remove_poll(h, io->request->connection->fd)) {
+        log_ereport(LOG_FAILURE, "sessionhandler: request timeout: cannot remove poll");
+    }
+    evt_request_error(h, io->io_event);
+}
+
+int evt_add_request_timeout(EventHandler *h, Event *event) {
+    EventHttpIO *io = event->cookie;
+    io->watch.intdata = 1;
+    ev_watchlist_add(h, &io->watch); 
+    return 0;
+}
+
 void evt_enq_conn(SessionHandler *handler, Connection *conn) {
     Event *event = malloc(sizeof(Event));
     if(!event) {
@@ -245,6 +267,7 @@
     event->fn = conn->ssl && !conn->ssl_accepted ? evt_request_ssl_accept : evt_request_input;
     event->finish = evt_request_finish;
     event->cookie = io;
+    io->io_event = event;
     
     EventHandler *ev = ev_instance(((EventSessionHandler*)handler)->eventhandler);
     
@@ -252,6 +275,26 @@
         // TODO: ev_pollin should log, intercept some errors here
         log_ereport(LOG_FAILURE, "Cannot enqueue connection");
         evt_request_error(ev, event);
+    } else {
+        // add request timeout
+        io->watch.created = time(NULL);
+        io->watch.expire = io->watch.created + 240; // TODO: config
+        io->watch.destroy = evt_request_timeout;
+        io->watch.data1 = io;
+        
+        Event *add_timeout = malloc(sizeof(Event));
+        if(add_timeout) {
+            add_timeout->cookie = io;
+            add_timeout->fn = evt_add_request_timeout;
+            add_timeout->finish = ev_free_event;
+            add_timeout->error = 0;
+            if(event_send(ev, add_timeout)) {
+                log_ereport(LOG_FAILURE, "Cannot add request timeout: event_send failed");
+            }
+        } else {
+            // not an error that breaks everything, a log message is enough
+            log_ereport(LOG_FAILURE, "Cannot add request timeout: OOM");
+        }
     }
 }
 
@@ -316,6 +359,7 @@
     io->request = request;
     io->parser  = parser;
     io->error = 0;
+    ZERO(&io->watch, sizeof(EVWatchList));
     
     return io;
 }
@@ -446,6 +490,11 @@
     EventHttpIO *io = event->cookie;
     HttpParser  *parser  = io->parser;
     HTTPRequest *request = io->request;
+    
+    // remove timeout
+    if(io->watch.intdata) {
+        ev_watchlist_remove(h, &io->watch);
+    }
       
     int r = handle_request(request, NULL, h);
     if(r != 0) {
@@ -478,6 +527,11 @@
         log_ereport(LOG_VERBOSE, "sessionhandler http io error: %d fd: %d", io->error, request->connection->fd);
     }
     
+    // remove timeout
+    if(io->watch.intdata) {
+        ev_watchlist_remove(h, &io->watch);
+    }
+    
     free(request->netbuf->inbuf);
     free(request->netbuf);
     
--- a/src/server/daemon/sessionhandler.h	Tue Aug 20 12:34:32 2024 +0200
+++ b/src/server/daemon/sessionhandler.h	Sat Aug 24 12:13:01 2024 +0200
@@ -156,6 +156,10 @@
 
 SessionHandler* create_event_session_handler(pool_handle_t *pool);
 
+void evt_request_timeout(EventHandler *h, EVWatchList *item);
+
+int evt_add_request_timeout(EventHandler *h, Event *event);
+
 void evt_enq_conn(SessionHandler *handler, Connection *conn);
 
 EventHttpIO* evt_req_init(SessionHandler *handler, Connection *conn);

mercurial