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 <fcntl.h>
#include <errno.h>
static const char ENABLE = 1;
struct HttpServer
@ -454,25 +456,38 @@ HttpServerWorkerThread(void *args)
HashMap *requestParams;
ssize_t requestPathLen;
int lineError = -1;
ssize_t i = 0;
HttpRequestMethod requestMethod;
if (!fp)
{
/* Block for 1 millisecond before continuing so we don't
* murder the CPU */
* murder the CPU if the queue is empty. */
UtilSleepMillis(1);
continue;
}
/* Get the first line of the request */
lineLen = UtilGetLine(&line, &lineSize, fp);
/* Get the first line of the request.
*
* 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)
{
goto bad_request;
}
requestMethodPtr = line;
for (i = 0; i < lineLen; i++)
{
@ -535,7 +550,7 @@ HttpServerWorkerThread(void *args)
goto internal_error;
}
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) != -1)
while ((lineLen = UtilGetLine(&line, &lineSize, fp, &lineError)) != -1)
{
char *headerKey;
char *headerValue;

View file

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