diff --git a/src/HttpServer.c b/src/HttpServer.c index df9afb6..020c217 100644 --- a/src/HttpServer.c +++ b/src/HttpServer.c @@ -41,6 +41,8 @@ #include #include +#include + 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; diff --git a/src/Util.c b/src/Util.c index d6a0cc3..40e0128 100644 --- a/src/Util.c +++ b/src/Util.c @@ -31,8 +31,9 @@ #include #include #include -#include + #include +#include #include 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); } diff --git a/src/include/Util.h b/src/include/Util.h index 673564f..61a5140 100644 --- a/src/include/Util.h +++ b/src/include/Util.h @@ -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 */