r261230 broke the cases where the amount of data to be read is not

known in advance, or where the caller doesn't care and just keeps
reading until it hits EOF.

In fetch_read(): the socket is non-blocking, so read() will return 0
on EOF, and -1 (errno == EAGAIN) when the connection is still open but
there is no data waiting.  In the first case, we should immediately
return 0.  The EINTR case was also broken, although not in a way that
matters.

In fetch_writev(): use timersub() and timercmp() as in fetch_read().

In http_fillbuf(): set errno to a sensible value when an invalid chunk
header is encountered.

In http_readfn(): as in fetch_read(), a zero return from down the
stack indicates EOF, not an error.  Furthermore, when io->error is
EINTR, clear it (but no errno) before returning so the caller can
retry after dealing with the interrupt.

MFC after:	3 days
This commit is contained in:
Dag-Erling Smørgrav 2014-01-29 12:48:19 +00:00
parent cc47735350
commit 9c1ca3a1dd
2 changed files with 16 additions and 17 deletions

View file

@ -976,13 +976,13 @@ fetch_read(conn_t *conn, char *buf, size_t len)
else
#endif
rlen = fetch_socket_read(conn->sd, buf, len);
if (rlen > 0) {
if (rlen >= 0) {
break;
} else if (rlen == FETCH_READ_ERROR) {
if (errno == EINTR)
break;
fetch_syserr();
return (-1);
}
// assert(rlen == FETCH_READ_WAIT);
if (fetchTimeout > 0) {
gettimeofday(&now, NULL);
if (!timercmp(&timeout, &now, >)) {
@ -1079,7 +1079,7 @@ fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
struct timeval now, timeout, delta;
struct pollfd pfd;
ssize_t wlen, total;
int deltams, r;
int deltams;
memset(&pfd, 0, sizeof pfd);
if (fetchTimeout) {
@ -1093,20 +1093,17 @@ fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
while (iovcnt > 0) {
while (fetchTimeout && pfd.revents == 0) {
gettimeofday(&now, NULL);
delta.tv_sec = timeout.tv_sec - now.tv_sec;
delta.tv_usec = timeout.tv_usec - now.tv_usec;
if (delta.tv_usec < 0) {
delta.tv_usec += 1000000;
delta.tv_sec--;
}
if (delta.tv_sec < 0) {
if (!timercmp(&timeout, &now, >)) {
errno = ETIMEDOUT;
fetch_syserr();
return (-1);
}
deltams = delta.tv_sec * 1000 + delta.tv_usec / 1000;;
timersub(&timeout, &now, &delta);
deltams = delta.tv_sec * 1000 +
delta.tv_usec / 1000;
errno = 0;
if ((r = poll(&pfd, 1, deltams)) == -1) {
pfd.revents = 0;
if (poll(&pfd, 1, deltams) < 0) {
if (errno == EINTR && fetchRestartCalls)
continue;
return (-1);

View file

@ -204,7 +204,7 @@ http_growbuf(struct httpio *io, size_t len)
/*
* Fill the input buffer, do chunk decoding on the fly
*/
static int
static ssize_t
http_fillbuf(struct httpio *io, size_t len)
{
ssize_t nbytes;
@ -230,7 +230,7 @@ http_fillbuf(struct httpio *io, size_t len)
if (io->chunksize == 0) {
switch (http_new_chunk(io)) {
case -1:
io->error = 1;
io->error = EPROTO;
return (-1);
case 0:
io->eof = 1;
@ -276,10 +276,12 @@ http_readfn(void *v, char *buf, int len)
/* empty buffer */
if (!io->buf || io->bufpos == io->buflen) {
if (http_fillbuf(io, len) < 1) {
if (io->error == EINTR)
if ((rlen = http_fillbuf(io, len)) < 0) {
if ((errno = io->error) == EINTR)
io->error = 0;
return (-1);
} else if (rlen == 0) {
return (0);
}
}