forked from lda/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
|
[ ] TLS
|
||||||
[ ] SOCKS
|
[ ] SOCKS
|
||||||
[ ] Multi-output
|
[ ] Multi-output
|
||||||
|
[ ] Move UtilStreamCopy()
|
||||||
[~] HTTP Client API
|
[~] HTTP Client API
|
||||||
[ ] Document HttpParseHeaders()
|
[ ] Document HttpParseHeaders()
|
||||||
[ ] HttpClient man page
|
[ ] HttpClient man page
|
||||||
|
|
|
@ -182,6 +182,9 @@ HttpRequestSend(HttpClientContext * context)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fflush(context->stream);
|
||||||
|
shutdown(fileno(context->stream), SHUT_WR);
|
||||||
|
|
||||||
lineLen = UtilGetLine(&line, &lineSize, context->stream);
|
lineLen = UtilGetLine(&line, &lineSize, context->stream);
|
||||||
|
|
||||||
/* Line must contain at least "HTTP/x.x xxx" */
|
/* 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
|
* Every once in a while, we're too fast for the client. When this
|
||||||
* happens, UtilGetLine() sets errno to EAGAIN. If we get
|
* happens, UtilGetLine() sets errno to EAGAIN. If we get
|
||||||
* EAGAIN, then clear the error on the stream and try again
|
* 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. */
|
* client to send data. */
|
||||||
firstRead = UtilServerTs();
|
firstRead = UtilServerTs();
|
||||||
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) == -1
|
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) == -1
|
||||||
|
@ -453,7 +453,7 @@ HttpServerWorkerThread(void *args)
|
||||||
clearerr(fp);
|
clearerr(fp);
|
||||||
|
|
||||||
/* If the server is stopped, or it's been a while, just
|
/* 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)
|
if (server->stop || (UtilServerTs() - firstRead) > 1000 * 30)
|
||||||
{
|
{
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
28
src/Json.c
28
src/Json.c
|
@ -31,6 +31,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
struct JsonValue
|
struct JsonValue
|
||||||
{
|
{
|
||||||
|
@ -705,8 +706,33 @@ static int
|
||||||
JsonConsumeWhitespace(JsonParserState * state)
|
JsonConsumeWhitespace(JsonParserState * state)
|
||||||
{
|
{
|
||||||
int c;
|
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;
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
c = getc(stream);
|
c = fgetc(stream);
|
||||||
|
|
||||||
if (ferror(stream) || (c == EOF && curPos == *linePtr))
|
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);
|
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
|
extern ssize_t
|
||||||
UtilGetLine(char **, size_t *, FILE *);
|
UtilGetLine(char **, size_t *, FILE *);
|
||||||
|
|
||||||
|
extern size_t
|
||||||
|
UtilStreamCopy(FILE *, FILE *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_UTIL_H */
|
#endif /* TELODENDRIA_UTIL_H */
|
||||||
|
|
|
@ -126,7 +126,7 @@ recipe_build() {
|
||||||
out=$(basename "$src" .c)
|
out=$(basename "$src" .c)
|
||||||
out="build/tools/$out"
|
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)"
|
echo "CC $(basename $out)"
|
||||||
mkdir -p "$(dirname $out)"
|
mkdir -p "$(dirname $out)"
|
||||||
if ! $CC $CFLAGS $LDFLAGS -Isrc/include -o "$out" $objs "$src"; then
|
if ! $CC $CFLAGS $LDFLAGS -Isrc/include -o "$out" $objs "$src"; then
|
||||||
|
|
|
@ -32,22 +32,10 @@
|
||||||
#include <HashMap.h>
|
#include <HashMap.h>
|
||||||
#include <HttpClient.h>
|
#include <HttpClient.h>
|
||||||
#include <Uri.h>
|
#include <Uri.h>
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
#define FLAG_HEADERS (1 << 0)
|
#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
|
static void
|
||||||
usage(char *prog)
|
usage(char *prog)
|
||||||
{
|
{
|
||||||
|
@ -170,7 +158,7 @@ main(int argc, char **argv)
|
||||||
* from blocking if no pipe is provided */
|
* from blocking if no pipe is provided */
|
||||||
if (!isatty(fileno(stdin)))
|
if (!isatty(fileno(stdin)))
|
||||||
{
|
{
|
||||||
StreamCopy(stdin, HttpClientStream(cx));
|
UtilStreamCopy(stdin, HttpClientStream(cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
res = HttpRequestSend(cx);
|
res = HttpRequestSend(cx);
|
||||||
|
@ -197,7 +185,7 @@ main(int argc, char **argv)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamCopy(HttpClientStream(cx), stdout);
|
UtilStreamCopy(HttpClientStream(cx), stdout);
|
||||||
|
|
||||||
HttpClientContextFree(cx);
|
HttpClientContextFree(cx);
|
||||||
UriFree(uri);
|
UriFree(uri);
|
||||||
|
|
Loading…
Reference in a new issue