Fix occasional "Bad Request" response by waiting for data to be sent.

This also makes UtilGetDelim() and UtilGetLine() thread safe in that it
isn't setting a global errno. Of course, errno should be thread safe
already, but this makes it much less ambiguous.
This commit is contained in:
Jordan Bancino 2022-11-02 16:21:03 +00:00
parent 92cc2206a1
commit a8beded518
3 changed files with 33 additions and 16 deletions

View file

@ -41,6 +41,8 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h>
static const char ENABLE = 1; static const char ENABLE = 1;
struct HttpServer struct HttpServer
@ -454,25 +456,38 @@ HttpServerWorkerThread(void *args)
HashMap *requestParams; HashMap *requestParams;
ssize_t requestPathLen; ssize_t requestPathLen;
int lineError = -1;
ssize_t i = 0; ssize_t i = 0;
HttpRequestMethod requestMethod; HttpRequestMethod requestMethod;
if (!fp) if (!fp)
{ {
/* Block for 1 millisecond before continuing so we don't /* Block for 1 millisecond before continuing so we don't
* murder the CPU */ * murder the CPU if the queue is empty. */
UtilSleepMillis(1); UtilSleepMillis(1);
continue; continue;
} }
/* Get the first line of the request */ /* Get the first line of the request.
lineLen = UtilGetLine(&line, &lineSize, fp); *
* Every once in a while, we're too fast for the client. When this
* happens, UtilGetLine() sets lineError to EAGAIN. If we get
* EAGAIN, then clear the error on the stream and try again
* after 1ms. This is typically more than enough time for the
* client to send data. */
while ((lineLen = UtilGetLine(&line, &lineSize, fp, &lineError)) == -1
&& lineError == EAGAIN)
{
clearerr(fp);
UtilSleepMillis(1);
}
if (lineLen == -1) if (lineLen == -1)
{ {
goto bad_request; goto bad_request;
} }
requestMethodPtr = line; requestMethodPtr = line;
for (i = 0; i < lineLen; i++) for (i = 0; i < lineLen; i++)
{ {
@ -535,7 +550,7 @@ HttpServerWorkerThread(void *args)
goto internal_error; goto internal_error;
} }
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) != -1) while ((lineLen = UtilGetLine(&line, &lineSize, fp, &lineError)) != -1)
{ {
char *headerKey; char *headerKey;
char *headerValue; char *headerValue;

View file

@ -31,8 +31,9 @@
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include <sys/time.h>
#include <errno.h> #include <errno.h>
#include <sys/time.h>
#include <limits.h> #include <limits.h>
unsigned long unsigned long
@ -179,7 +180,7 @@ UtilStringToBytes(char *str)
} }
ssize_t ssize_t
UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream) UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream, int *err)
{ {
char *curPos, *newLinePtr; char *curPos, *newLinePtr;
size_t newLinePtrLen; size_t newLinePtrLen;
@ -187,7 +188,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
if (!linePtr || !n || !stream) if (!linePtr || !n || !stream)
{ {
errno = EINVAL; *err = EINVAL;
return -1; return -1;
} }
@ -197,7 +198,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
if (!(*linePtr = Malloc(*n))) if (!(*linePtr = Malloc(*n)))
{ {
errno = ENOMEM; *err = ENOMEM;
return -1; return -1;
} }
} }
@ -210,6 +211,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
if (ferror(stream) || (c == EOF && curPos == *linePtr)) if (ferror(stream) || (c == EOF && curPos == *linePtr))
{ {
*err = errno;
return -1; return -1;
} }
@ -223,9 +225,9 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
if (SSIZE_MAX / 2 < *n) if (SSIZE_MAX / 2 < *n)
{ {
#ifdef EOVERFLOW #ifdef EOVERFLOW
errno = EOVERFLOW; *err = EOVERFLOW;
#else #else
errno = ERANGE; *err = ERANGE;
#endif #endif
return -1; return -1;
} }
@ -234,7 +236,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
if (!(newLinePtr = Realloc(*linePtr, newLinePtrLen))) if (!(newLinePtr = Realloc(*linePtr, newLinePtrLen)))
{ {
errno = ENOMEM; *err = ENOMEM;
return -1; return -1;
} }
@ -256,7 +258,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
} }
ssize_t ssize_t
UtilGetLine(char **linePtr, size_t * n, FILE * stream) UtilGetLine(char **linePtr, size_t * n, FILE * stream, int *err)
{ {
return UtilGetDelim(linePtr, n, '\n', stream); return UtilGetDelim(linePtr, n, '\n', stream, err);
} }

View file

@ -104,9 +104,9 @@ extern size_t
UtilStringToBytes(char *); UtilStringToBytes(char *);
extern ssize_t extern ssize_t
UtilGetDelim(char **, size_t *, int, FILE *); UtilGetDelim(char **, size_t *, int, FILE *, int *);
extern ssize_t extern ssize_t
UtilGetLine(char **, size_t *, FILE *); UtilGetLine(char **, size_t *, FILE *, int *);
#endif /* TELODENDRIA_UTIL_H */ #endif /* TELODENDRIA_UTIL_H */