forked from Telodendria/Telodendria
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:
parent
92cc2206a1
commit
a8beded518
3 changed files with 33 additions and 16 deletions
|
@ -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;
|
||||||
|
|
20
src/Util.c
20
src/Util.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue