forked from Telodendria/Telodendria
Fix I/O in JsonConsumeWhitespace() and UtilStreamCopy().
These functions previously operated on the assumption that fgetc() would block; however it will not block on HttpServer streams because those are non-blocking. They now check error conditions properly before failing prematurely.
This commit is contained in:
parent
fd12dee62e
commit
2d9b706f38
8 changed files with 76 additions and 20 deletions
1
TODO.txt
1
TODO.txt
|
@ -15,6 +15,7 @@ Milestone: v0.3.0
|
|||
[ ] TLS
|
||||
[ ] SOCKS
|
||||
[ ] Multi-output
|
||||
[ ] Move UtilStreamCopy()
|
||||
[~] HTTP Client API
|
||||
[ ] Document HttpParseHeaders()
|
||||
[ ] HttpClient man page
|
||||
|
|
|
@ -182,6 +182,9 @@ HttpRequestSend(HttpClientContext * context)
|
|||
return 0;
|
||||
}
|
||||
|
||||
fflush(context->stream);
|
||||
shutdown(fileno(context->stream), SHUT_WR);
|
||||
|
||||
lineLen = UtilGetLine(&line, &lineSize, context->stream);
|
||||
|
||||
/* Line must contain at least "HTTP/x.x xxx" */
|
||||
|
|
|
@ -444,7 +444,7 @@ HttpServerWorkerThread(void *args)
|
|||
* Every once in a while, we're too fast for the client. When this
|
||||
* happens, UtilGetLine() sets errno 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
|
||||
* after a few ms. This is typically more than enough time for the
|
||||
* client to send data. */
|
||||
firstRead = UtilServerTs();
|
||||
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) == -1
|
||||
|
@ -453,7 +453,7 @@ HttpServerWorkerThread(void *args)
|
|||
clearerr(fp);
|
||||
|
||||
/* If the server is stopped, or it's been a while, just
|
||||
* give up. */
|
||||
* give up so we aren't wasting a thread on this client. */
|
||||
if (server->stop || (UtilServerTs() - firstRead) > 1000 * 30)
|
||||
{
|
||||
goto finish;
|
||||
|
|
28
src/Json.c
28
src/Json.c
|
@ -31,6 +31,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct JsonValue
|
||||
{
|
||||
|
@ -705,8 +706,33 @@ static int
|
|||
JsonConsumeWhitespace(JsonParserState * state)
|
||||
{
|
||||
int c;
|
||||
while (1)
|
||||
{
|
||||
c = fgetc(state->stream);
|
||||
|
||||
while (isspace(c = fgetc(state->stream)));
|
||||
if (feof(state->stream))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ferror(state->stream))
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
clearerr(state->stream);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isspace(c))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
|
37
src/Util.c
37
src/Util.c
|
@ -246,7 +246,7 @@ UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream)
|
|||
|
||||
while (1)
|
||||
{
|
||||
c = getc(stream);
|
||||
c = fgetc(stream);
|
||||
|
||||
if (ferror(stream) || (c == EOF && curPos == *linePtr))
|
||||
{
|
||||
|
@ -300,3 +300,38 @@ UtilGetLine(char **linePtr, size_t * n, FILE * stream)
|
|||
{
|
||||
return UtilGetDelim(linePtr, n, '\n', stream);
|
||||
}
|
||||
|
||||
size_t
|
||||
UtilStreamCopy(FILE *in, FILE *out)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
int c;
|
||||
|
||||
while (1)
|
||||
{
|
||||
c = fgetc(in);
|
||||
|
||||
if (feof(in))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ferror(in))
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
clearerr(in);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fputc(c, out);
|
||||
bytes++;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
|
|
@ -50,4 +50,7 @@ extern ssize_t
|
|||
extern ssize_t
|
||||
UtilGetLine(char **, size_t *, FILE *);
|
||||
|
||||
extern size_t
|
||||
UtilStreamCopy(FILE *, FILE *);
|
||||
|
||||
#endif /* TELODENDRIA_UTIL_H */
|
||||
|
|
|
@ -126,7 +126,7 @@ recipe_build() {
|
|||
out=$(basename "$src" .c)
|
||||
out="build/tools/$out"
|
||||
|
||||
if [ $(mod_time "$src") -ge $(mod_time "$out") ]; then
|
||||
if [ $(mod_time "$src") -ge $(mod_time "$out") ] || [ $do_rebuild -eq 1 ]; then
|
||||
echo "CC $(basename $out)"
|
||||
mkdir -p "$(dirname $out)"
|
||||
if ! $CC $CFLAGS $LDFLAGS -Isrc/include -o "$out" $objs "$src"; then
|
||||
|
|
|
@ -32,22 +32,10 @@
|
|||
#include <HashMap.h>
|
||||
#include <HttpClient.h>
|
||||
#include <Uri.h>
|
||||
#include <Util.h>
|
||||
|
||||
#define FLAG_HEADERS (1 << 0)
|
||||
|
||||
/* TODO: Will eventually be provided by the Stream API */
|
||||
static void
|
||||
StreamCopy(FILE * in, FILE * out)
|
||||
{
|
||||
int c;
|
||||
|
||||
/* TODO: This should be buffered, not char-by-char */
|
||||
while ((c = fgetc(in)) != EOF)
|
||||
{
|
||||
fputc(c, out);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(char *prog)
|
||||
{
|
||||
|
@ -170,7 +158,7 @@ main(int argc, char **argv)
|
|||
* from blocking if no pipe is provided */
|
||||
if (!isatty(fileno(stdin)))
|
||||
{
|
||||
StreamCopy(stdin, HttpClientStream(cx));
|
||||
UtilStreamCopy(stdin, HttpClientStream(cx));
|
||||
}
|
||||
|
||||
res = HttpRequestSend(cx);
|
||||
|
@ -197,7 +185,7 @@ main(int argc, char **argv)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
StreamCopy(HttpClientStream(cx), stdout);
|
||||
UtilStreamCopy(HttpClientStream(cx), stdout);
|
||||
|
||||
HttpClientContextFree(cx);
|
||||
UriFree(uri);
|
||||
|
|
Loading…
Reference in a new issue