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;