mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
libfetch: Reduce copying
Reduce the amount of copying we do when performing buffered reads. MFC after: 1 week Reviewed by: op Differential Revision: https://reviews.freebsd.org/D58113
This commit is contained in:
1 parent
d4e0e1fbc2
commit
60382b4a04
4 files changed
+61
-50
No files matched your search
+29
-16
@@ -1437,12 +1437,23 @@ fetch_getln(conn_t *conn)
|
||||
/* allocate initial buffer */
|
||||
if (conn->buf == NULL) {
|
||||
if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL)
|
||||
return (-1);
|
||||
goto fail;
|
||||
conn->line = conn->buf;
|
||||
conn->bufsize = MIN_BUF_SIZE;
|
||||
conn->buflen = 0;
|
||||
conn->pos = 0;
|
||||
}
|
||||
|
||||
/* look at the data we already have */
|
||||
if (conn->pos < conn->buflen) {
|
||||
conn->line = conn->buf + conn->pos;
|
||||
while (conn->pos < conn->buflen)
|
||||
if (conn->buf[conn->pos++] == '\n')
|
||||
goto found;
|
||||
/* reset for the upcoming memmove() */
|
||||
conn->pos = conn->line - conn->buf;
|
||||
}
|
||||
|
||||
/* move residual data up */
|
||||
if (conn->buflen > 0) {
|
||||
if (conn->pos < conn->buflen) {
|
||||
@@ -1451,20 +1462,16 @@ fetch_getln(conn_t *conn)
|
||||
}
|
||||
conn->buflen -= conn->pos;
|
||||
conn->pos -= conn->pos;
|
||||
conn->line = conn->buf;
|
||||
}
|
||||
|
||||
/* do we have a complete line? */
|
||||
while (conn->pos < conn->buflen)
|
||||
if (conn->buf[conn->pos++] == '\n')
|
||||
goto found;
|
||||
|
||||
for (;;) {
|
||||
/* read as much as we can right now */
|
||||
rlen = fetch_read(conn, conn->buf + conn->buflen,
|
||||
conn->bufsize - conn->buflen - 1);
|
||||
/* error */
|
||||
if (rlen < 0)
|
||||
return (-1);
|
||||
goto fail;
|
||||
/* advance and terminate */
|
||||
conn->buflen += rlen;
|
||||
conn->buf[conn->buflen] = '\0';
|
||||
@@ -1480,21 +1487,25 @@ fetch_getln(conn_t *conn)
|
||||
tmp = conn->buf;
|
||||
tmpsize = conn->bufsize * 2;
|
||||
if ((tmp = realloc(tmp, tmpsize)) == NULL)
|
||||
return (-1);
|
||||
conn->buf = tmp;
|
||||
goto fail;
|
||||
conn->line = conn->buf = tmp;
|
||||
conn->bufsize = tmpsize;
|
||||
}
|
||||
}
|
||||
/* connection closed, return what's left */
|
||||
conn->pos = conn->buflen;
|
||||
found:
|
||||
rlen = conn->pos;
|
||||
if (rlen > 0 && conn->buf[rlen - 1] == '\n')
|
||||
conn->buf[--rlen] = '\0';
|
||||
if (rlen > 0 && conn->buf[rlen - 1] == '\r')
|
||||
conn->buf[--rlen] = '\0';
|
||||
DEBUGF("<<< %.*s\n", (int)rlen, conn->buf);
|
||||
return (rlen);
|
||||
conn->linelen = (conn->buf + conn->pos) - conn->line;
|
||||
if (conn->linelen > 0 && conn->line[conn->linelen - 1] == '\n')
|
||||
conn->line[--conn->linelen] = '\0';
|
||||
if (conn->linelen > 0 && conn->line[conn->linelen - 1] == '\r')
|
||||
conn->line[--conn->linelen] = '\0';
|
||||
DEBUGF("<<< %.*s\n", (int)conn->linelen, conn->line);
|
||||
return (conn->linelen);
|
||||
fail:
|
||||
conn->line = NULL;
|
||||
conn->linelen = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1520,6 +1531,8 @@ fetch_bufread(conn_t *conn, void *buf, size_t len)
|
||||
conn->buflen = 0;
|
||||
conn->pos = 0;
|
||||
}
|
||||
conn->line = NULL;
|
||||
conn->linelen = 0;
|
||||
|
||||
/* return residual data first */
|
||||
if (conn->buflen > conn->pos) {
|
||||
|
||||
@@ -49,8 +49,10 @@ typedef struct fetchconn conn_t;
|
||||
struct fetchconn {
|
||||
int sd; /* socket descriptor */
|
||||
char *buf; /* buffer */
|
||||
char *line; /* line (within buffer) */
|
||||
size_t bufsize; /* buffer size */
|
||||
size_t buflen; /* length of buffer contents */
|
||||
size_t linelen; /* length of line */
|
||||
size_t pos; /* current position in buffer */
|
||||
int err; /* last protocol reply code */
|
||||
#ifdef WITH_SSL
|
||||
|
||||
+12
-11
@@ -148,8 +148,9 @@ ftp_chkerr(conn_t *conn)
|
||||
fetch_syserr();
|
||||
return (-1);
|
||||
}
|
||||
if (isftpinfo(conn->buf)) {
|
||||
while (conn->buflen && !isftpreply(conn->buf)) {
|
||||
|
||||
if (isftpinfo(conn->line)) {
|
||||
while (rlen && !isftpreply(conn->line)) {
|
||||
if ((rlen = fetch_getln(conn)) < 0) {
|
||||
fetch_syserr();
|
||||
return (-1);
|
||||
@@ -157,14 +158,14 @@ ftp_chkerr(conn_t *conn)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isftpreply(conn->buf)) {
|
||||
if (!isftpreply(conn->line)) {
|
||||
ftp_seterr(FTP_PROTOCOL_ERROR);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
conn->err = (conn->buf[0] - '0') * 100
|
||||
+ (conn->buf[1] - '0') * 10
|
||||
+ (conn->buf[2] - '0');
|
||||
conn->err = (conn->line[0] - '0') * 100
|
||||
+ (conn->line[1] - '0') * 10
|
||||
+ (conn->line[2] - '0');
|
||||
|
||||
return (conn->err);
|
||||
}
|
||||
@@ -236,8 +237,8 @@ ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen)
|
||||
if (conn->err != FTP_WORKING_DIRECTORY &&
|
||||
conn->err != FTP_FILE_ACTION_OK)
|
||||
return (FTP_PROTOCOL_ERROR);
|
||||
end = conn->buf + conn->buflen;
|
||||
src = conn->buf + 4;
|
||||
end = conn->line + conn->linelen;
|
||||
src = conn->line + 4;
|
||||
if (src >= end || *src++ != '"')
|
||||
return (FTP_PROTOCOL_ERROR);
|
||||
for (q = 0, dst = pwd; src < end && pwdlen--; ++src) {
|
||||
@@ -417,7 +418,7 @@ ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
|
||||
ftp_seterr(e);
|
||||
return (-1);
|
||||
}
|
||||
for (ln = conn->buf + 4; *ln && isspace((unsigned char)*ln); ln++)
|
||||
for (ln = conn->line + 4; *ln && isspace((unsigned char)*ln); ln++)
|
||||
/* nothing */ ;
|
||||
for (us->size = 0; *ln && isdigit((unsigned char)*ln); ln++)
|
||||
us->size = us->size * 10 + *ln - '0';
|
||||
@@ -435,7 +436,7 @@ ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
|
||||
ftp_seterr(e);
|
||||
return (-1);
|
||||
}
|
||||
for (ln = conn->buf + 4; *ln && isspace((unsigned char)*ln); ln++)
|
||||
for (ln = conn->line + 4; *ln && isspace((unsigned char)*ln); ln++)
|
||||
/* nothing */ ;
|
||||
switch (strspn(ln, "0123456789")) {
|
||||
case 14:
|
||||
@@ -688,7 +689,7 @@ ftp_transfer(conn_t *conn, const char *oper, const char *file,
|
||||
* Find address and port number. The reply to the PASV command
|
||||
* is IMHO the one and only weak point in the FTP protocol.
|
||||
*/
|
||||
ln = conn->buf;
|
||||
ln = conn->line;
|
||||
switch (e) {
|
||||
case FTP_PASSIVE_MODE:
|
||||
case FTP_LPASSIVE_MODE:
|
||||
|
||||
+18
-23
@@ -126,8 +126,7 @@
|
||||
* I/O functions for decoding chunked streams
|
||||
*/
|
||||
|
||||
struct httpio
|
||||
{
|
||||
struct httpio {
|
||||
conn_t *conn; /* connection */
|
||||
int chunked; /* chunked mode */
|
||||
char *buf; /* chunk buffer */
|
||||
@@ -148,17 +147,14 @@ struct httpio
|
||||
static int
|
||||
http_new_chunk(struct httpio *io)
|
||||
{
|
||||
unsigned char *p, *eol;
|
||||
char *p;
|
||||
|
||||
if (fetch_getln(io->conn) == -1)
|
||||
return (-1);
|
||||
|
||||
p = (unsigned char *)io->conn->buf;
|
||||
if (io->conn->pos < 2 || !isxdigit(*p))
|
||||
return (-1);
|
||||
|
||||
eol = (unsigned char *)io->conn->buf + io->conn->pos;
|
||||
while (p < eol && *p && !isspace(*p) && *p != ';') {
|
||||
for (p = io->conn->line;
|
||||
*p != '\0' && !isspace((unsigned char)*p) && *p != ';';
|
||||
p++) {
|
||||
io->chunksize <<= 4;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
io->chunksize += *p - '0';
|
||||
@@ -168,7 +164,6 @@ http_new_chunk(struct httpio *io)
|
||||
io->chunksize += 10 + *p - 'a';
|
||||
else
|
||||
return (-1);
|
||||
p++;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -435,9 +430,9 @@ http_get_reply(conn_t *conn)
|
||||
* on finding one, but if we do, insist on it being 1.0 or 1.1.
|
||||
* We don't care about the reason phrase.
|
||||
*/
|
||||
if (strncmp(conn->buf, "HTTP", 4) != 0)
|
||||
if (conn->linelen < 4 || strncmp(conn->line, "HTTP", 4) != 0)
|
||||
return (HTTP_PROTOCOL_ERROR);
|
||||
p = conn->buf + 4;
|
||||
p = conn->line + 4;
|
||||
if (*p == '/') {
|
||||
if (p[1] != '1' || p[2] != '.' || (p[3] != '0' && p[3] != '1'))
|
||||
return (HTTP_PROTOCOL_ERROR);
|
||||
@@ -521,17 +516,17 @@ http_next_header(conn_t *conn, http_headerbuf_t *hbuf, const char **p)
|
||||
{
|
||||
unsigned int i, len;
|
||||
|
||||
if (conn->pos == 0 || conn->buf[0] == '\0')
|
||||
if (conn->linelen == 0)
|
||||
return (hdr_end);
|
||||
|
||||
/* Copy the line to the headerbuf */
|
||||
if (hbuf->bufsize < conn->pos + 1) {
|
||||
if ((hbuf->buf = realloc(hbuf->buf, conn->pos + 1)) == NULL)
|
||||
if (hbuf->bufsize <= conn->linelen) {
|
||||
if ((hbuf->buf = realloc(hbuf->buf, conn->linelen + 1)) == NULL)
|
||||
return (hdr_syserror);
|
||||
hbuf->bufsize = conn->pos + 1;
|
||||
hbuf->bufsize = conn->linelen + 1;
|
||||
}
|
||||
strcpy(hbuf->buf, conn->buf);
|
||||
hbuf->buflen = conn->buflen;
|
||||
memcpy(hbuf->buf, conn->line, conn->linelen + 1);
|
||||
hbuf->buflen = conn->linelen;
|
||||
|
||||
/*
|
||||
* Fetch possible continuation lines. Stop at 1st non-continuation
|
||||
@@ -545,19 +540,19 @@ http_next_header(conn_t *conn, http_headerbuf_t *hbuf, const char **p)
|
||||
* Note: we previously considered a pure whitespace line
|
||||
* equivalent to an empty one. This was incorrect.
|
||||
*/
|
||||
if (conn->buf[0] != ' ' && conn->buf[0] != "\t"[0])
|
||||
if (conn->line[0] != ' ' && conn->line[0] != '\t')
|
||||
break;
|
||||
|
||||
/* Got a continuation line. Concatenate to previous */
|
||||
len = hbuf->buflen + conn->buflen;
|
||||
if (hbuf->bufsize < len + 1) {
|
||||
len = hbuf->buflen + conn->linelen;
|
||||
if (hbuf->bufsize <= len) {
|
||||
len *= 2;
|
||||
if ((hbuf->buf = realloc(hbuf->buf, len + 1)) == NULL)
|
||||
return (hdr_syserror);
|
||||
hbuf->bufsize = len + 1;
|
||||
}
|
||||
strcpy(hbuf->buf + hbuf->buflen, conn->buf);
|
||||
hbuf->buflen += conn->buflen;
|
||||
memcpy(hbuf->buf + hbuf->buflen, conn->line, conn->linelen + 1);
|
||||
hbuf->buflen += conn->linelen;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in new issue
Block a user