Download raw body.
optimize got-fetch-http a bit
Stefan Sperling <stsp@stsp.name> wrote: > On Tue, Apr 15, 2025 at 08:11:42AM +0200, op@omarpolo.com wrote: > > + > > + if (out != NULL) { > > + fwrite(rbuf->buf + rbuf->cur, 1, avail, out); > > Please check for errors from fwrite() instead of ignoring them. > I realize this is always going to stdout, but I would prefer to keep > error checking idioms in place everywhere. Fair enough; there were none before and that's why I haven't added them, but I agree. Here's an updated diff. diff /home/op/w/got path + /home/op/w/got commit - 493d280daf90dd38c229a3d7b19d98201aabc3ea blob - 6f0e0e861b6c26170d813b19ca2271295f30eb22 file + libexec/got-fetch-http/got-fetch-http.c --- libexec/got-fetch-http/got-fetch-http.c +++ libexec/got-fetch-http/got-fetch-http.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2024 Tobias Heider <me@tobhe.de> - * Copyright (c) 2022 Omar Polo <op@openbsd.org> + * Copyright (c) 2022, 2025 Omar Polo <op@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -64,19 +64,6 @@ bufio_getdelim_sync(struct bufio *bio, const char *nl, return buf_getdelim(&bio->rbuf, nl, len); } -static size_t -bufio_drain_sync(struct bufio *bio, void *d, size_t len) -{ - int r; - - do { - r = bufio_read(bio); - if (r == -1 && errno != EAGAIN) - errx(1, "bufio_read: %s", bufio_io_err(bio)); - } while (r == -1 && errno == EAGAIN); - return bufio_drain(bio, d, len); -} - static void bufio_close_sync(struct bufio *bio) { @@ -268,53 +255,81 @@ http_parse_reply(struct bufio *bio, int *chunked, cons } static ssize_t -http_read(struct bufio *bio, int chunked, size_t *chunksz, char *buf, size_t bufsz) +http_read(struct bufio *bio, int chunked, size_t *chunksz, char *buf, size_t bufsz, + FILE *out) { + struct buf *rbuf = &bio->rbuf; const char *errstr; - char *line = NULL; - size_t r; - ssize_t ret = 0, linelen; + char *chunk, *endln; + size_t avail, w; + ssize_t r, ret = 0; - if (!chunked) - return bufio_drain_sync(bio, buf, bufsz); + while (out != NULL || bufsz > 0) { + if (rbuf->cur == rbuf->len) { + rbuf->cur = 0; + rbuf->len = 0; + r = bufio_read(bio); + if (r == -1) { + warnx("bufio_read: %s", bufio_io_err(bio)); + return (-1); + } + if (r == 0) + return ret; + } - while (bufsz > 0) { - if (*chunksz == 0) { - again: - line = bufio_getdelim_sync(bio, "\r\n", &linelen); - if (line == NULL) { - buf_drain(&bio->rbuf, linelen); + if (chunked && *chunksz == 0) { + for (;;) { + chunk = rbuf->buf + rbuf->cur; + avail = rbuf->len - rbuf->cur; + endln = memmem(chunk, avail, "\r\n", 2); + if (endln == NULL) { + r = bufio_read(bio); + if (r == -1) { + warnx("bufio_read: %s", + bufio_io_err(bio)); + return (-1); + } + if (r == 0) + return ret; + continue; + } + rbuf->cur += (endln - chunk) + 2; + *endln = '\0'; + /* was the CRLF after the chunk? */ + if (chunk == endln) + continue; break; } - if (*line == '\0') { - buf_drain(&bio->rbuf, linelen); - goto again; /* was the CRLF after the chunk */ - } - *chunksz = hexstrtonum(line, 0, INT_MAX, &errstr); + *chunksz = hexstrtonum(chunk, 0, INT_MAX, &errstr); if (errstr != NULL) { warnx("invalid HTTP chunk: size is %s (%s)", - errstr, line); - ret = -1; - break; + errstr, chunk); + return (-1); } - if (*chunksz == 0) { - buf_drain(&bio->rbuf, linelen); + if (*chunksz == 0) break; - } - buf_drain(&bio->rbuf, linelen); } - r = bufio_drain_sync(bio, buf, MINIMUM(*chunksz, bufsz)); - if (r == 0) { - break; + avail = rbuf->len - rbuf->cur; + if (chunked && avail > *chunksz) + avail = *chunksz; + + if (out != NULL) { + w = fwrite(rbuf->buf + rbuf->cur, 1, avail, out); + if (w != avail) + return (-1); + } else { + avail = MINIMUM(avail, bufsz); + memcpy(buf, rbuf->buf + rbuf->cur, avail); } - ret += r; - buf += r; - bufsz -= r; - *chunksz -= r; + rbuf->cur += avail; + ret += avail; + buf += avail; + bufsz -= avail; + *chunksz -= avail; } return ret; @@ -374,7 +389,7 @@ get_refs(int https, const char *host, const char *port goto err; /* skip first pack; why git over http is like this? */ - r = http_read(&bio, chunked, &chunksz, buf, 4); + r = http_read(&bio, chunked, &chunksz, buf, 4, NULL); if (r <= 0) goto err; @@ -387,23 +402,13 @@ get_refs(int https, const char *host, const char *port /* TODO: validate it's # service=git-upload-pack\n */ while (skip > 0) { r = http_read(&bio, chunked, &chunksz, buf, - MINIMUM(skip, sizeof(buf))); + MINIMUM(skip, sizeof(buf)), NULL); if (r <= 0) goto err; skip -= r; } - for (;;) { - r = http_read(&bio, chunked, &chunksz, buf, sizeof(buf)); - if (r == -1) - goto err; - - if (r == 0) - break; - - fwrite(buf, 1, r, stdout); - } - + http_read(&bio, chunked, &chunksz, NULL, 0, stdout); fflush(stdout); ret = 0; err: @@ -496,17 +501,8 @@ upload_request(int https, const char *host, const char goto err; /* Fetch pack file data from server. */ - for (;;) { - r = http_read(&bio, chunked, &chunksz, buf, sizeof(buf)); - if (r == -1) - goto err; + http_read(&bio, chunked, &chunksz, NULL, 0, stdout); - if (r == 0) - break; - - fwrite(buf, 1, r, stdout); - } - ret = 0; err: bufio_close_sync(&bio);
optimize got-fetch-http a bit