fix: Gesamt-Timeout für HTTP-Anfragen
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.
This commit is contained in:
@@ -33,19 +33,35 @@ static void simple_error(int status, const char *msg)
|
|||||||
strcpy(s_resp.body, msg);
|
strcpy(s_resp.body, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define NL_HTTP_REQUEST_TIMEOUT_MS 5000u
|
||||||
|
|
||||||
static void serve(int fd)
|
static void serve(int fd)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
nl_http_request_t req;
|
nl_http_request_t req;
|
||||||
nl_http_parse_t pr = NL_HTTP_INCOMPLETE;
|
nl_http_parse_t pr = NL_HTTP_INCOMPLETE;
|
||||||
size_t len = 0, out;
|
size_t len = 0, out;
|
||||||
|
uint32_t deadline = nl_app_now_ms() + NL_HTTP_REQUEST_TIMEOUT_MS;
|
||||||
|
|
||||||
tv.tv_sec = 5;
|
tv.tv_sec = 5;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
|
|
||||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &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) {
|
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)
|
if (n <= 0)
|
||||||
return; /* timeout or closed: drop silently */
|
return; /* timeout or closed: drop silently */
|
||||||
len += (size_t)n;
|
len += (size_t)n;
|
||||||
|
|||||||
Reference in New Issue
Block a user