From 5f45b9e996ac305f55c96bda3f667e5376fad2fc Mon Sep 17 00:00:00 2001 From: Michael Sauer Date: Fri, 11 Sep 2026 23:51:11 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20Gesamt-Timeout=20f=C3=BCr=20HTTP-Anfrage?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I2: SO_RCVTIMEO=5s war ein Timeout pro recv(), nicht für die gesamte Anfrage. Ein Client, der 1 Byte alle 4,9 s schickt, konnte den einzigen HTTP-Server-Task damit stundenlang belegen (Spec §7.2 will 5 s pro Header). serve() rechnet jetzt eine absolute Deadline (nl_app_now_ms() + 5000 ms) und setzt SO_RCVTIMEO vor jedem recv() auf die verbleibende Zeit (mindestens 1 ms); ist die Deadline überschritten, wird die Verbindung sofort verworfen. Nicht host-testbar (nl_http_server.c bindet SDK-Sockets ein); über den Firmware-Build verifiziert. --- src/net/nl_http_server.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/net/nl_http_server.c b/src/net/nl_http_server.c index 2fbc0ca..0e89f45 100644 --- a/src/net/nl_http_server.c +++ b/src/net/nl_http_server.c @@ -33,19 +33,35 @@ static void simple_error(int status, const char *msg) strcpy(s_resp.body, msg); } +#define NL_HTTP_REQUEST_TIMEOUT_MS 5000u + static void serve(int fd) { struct timeval tv; nl_http_request_t req; nl_http_parse_t pr = NL_HTTP_INCOMPLETE; size_t len = 0, out; + uint32_t deadline = nl_app_now_ms() + NL_HTTP_REQUEST_TIMEOUT_MS; tv.tv_sec = 5; tv.tv_usec = 0; - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); + /* I2: 5 s is a deadline for the whole header+body read, not a per-recv() timeout - + * otherwise a client trickling in 1 byte per <5 s occupies the single server task forever. */ while (pr == NL_HTTP_INCOMPLETE && len < sizeof s_buf) { - int n = recv(fd, s_buf + len, sizeof s_buf - len, 0); + uint32_t now = nl_app_now_ms(); + uint32_t remaining_ms; + int n; + + if ((int32_t)(deadline - now) <= 0) + return; /* overall deadline passed: drop silently */ + remaining_ms = deadline - now; + tv.tv_sec = remaining_ms / 1000u; + tv.tv_usec = (remaining_ms % 1000u) * 1000u; + if (tv.tv_sec == 0 && tv.tv_usec == 0) + tv.tv_usec = 1000; /* at least 1 ms */ + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); + n = recv(fd, s_buf + len, sizeof s_buf - len, 0); if (n <= 0) return; /* timeout or closed: drop silently */ len += (size_t)n;