Merge libfetch-2.30 from NetBSD's pkgsrc.

--HG--
extra : convert_revision : xtraeme%40gmail.com-20100124144753-ni487x8m7r05847b
This commit is contained in:
Juan RP
2010-01-24 15:47:53 +01:00
parent 489f6baaa6
commit 03e8fa53d9
5 changed files with 277 additions and 227 deletions

View File

@ -1,6 +1,6 @@
/* $NetBSD: http.c,v 1.25 2009/10/15 12:36:57 joerg Exp $ */
/* $NetBSD: http.c,v 1.28 2010/01/23 14:53:08 joerg Exp $ */
/*-
* Copyright (c) 2000-2004 Dag-Erling Coïdan Smørav
* Copyright (c) 2000-2004 Dag-Erling Co<EFBFBD>dan Sm<EFBFBD>rgrav
* Copyright (c) 2003 Thomas Klausner <wiz@NetBSD.org>
* Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>
* All rights reserved.
@ -137,6 +137,7 @@ struct httpio
{
conn_t *conn; /* connection */
int chunked; /* chunked mode */
int keep_alive; /* keep-alive mode */
char *buf; /* chunk buffer */
size_t bufsize; /* size of chunk buffer */
ssize_t buflen; /* amount of data currently in buffer */
@ -144,6 +145,7 @@ struct httpio
int eof; /* end-of-file flag */
int error; /* error flag */
size_t chunksize; /* remaining size of current chunk */
off_t contentlength; /* remaining size of the content */
};
/*
@ -206,6 +208,9 @@ http_fillbuf(struct httpio *io, size_t len)
if (io->eof)
return (0);
if (io->contentlength >= 0 && (off_t)len > io->contentlength)
len = io->contentlength;
if (io->chunked == 0) {
if (http_growbuf(io, len) == -1)
return (-1);
@ -213,6 +218,8 @@ http_fillbuf(struct httpio *io, size_t len)
io->error = 1;
return (-1);
}
if (io->contentlength)
io->contentlength -= io->buflen;
io->bufpos = 0;
return (io->buflen);
}
@ -224,6 +231,8 @@ http_fillbuf(struct httpio *io, size_t len)
return (-1);
case 0:
io->eof = 1;
if (fetch_getln(io->conn) == -1)
return (-1);
return (0);
}
}
@ -237,6 +246,8 @@ http_fillbuf(struct httpio *io, size_t len)
return (-1);
}
io->chunksize -= io->buflen;
if (io->contentlength >= 0)
io->contentlength -= io->buflen;
if (io->chunksize == 0) {
char endl[2];
@ -304,9 +315,23 @@ http_closefn(void *v)
{
struct httpio *io = (struct httpio *)v;
fetch_close(io->conn);
if (io->buf)
free(io->buf);
if (io->keep_alive) {
int val;
val = 0;
setsockopt(io->conn->sd, IPPROTO_TCP, TCP_NODELAY, &val,
sizeof(val));
fetch_cache_put(io->conn, fetch_close);
#ifdef TCP_NOPUSH
val = 1;
setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &val,
sizeof(val));
#endif
} else {
fetch_close(io->conn);
}
free(io->buf);
free(io);
}
@ -314,7 +339,7 @@ http_closefn(void *v)
* Wrap a file descriptor up
*/
static fetchIO *
http_funopen(conn_t *conn, int chunked)
http_funopen(conn_t *conn, int chunked, int keep_alive, off_t clength)
{
struct httpio *io;
fetchIO *f;
@ -325,6 +350,8 @@ http_funopen(conn_t *conn, int chunked)
}
io->conn = conn;
io->chunked = chunked;
io->contentlength = clength;
io->keep_alive = keep_alive;
f = fetchIO_unopen(io, http_readfn, http_writefn, http_closefn);
if (f == NULL) {
fetch_syserr();
@ -345,6 +372,7 @@ typedef enum {
hdr_error = -1,
hdr_end = 0,
hdr_unknown = 1,
hdr_connection,
hdr_content_length,
hdr_content_range,
hdr_last_modified,
@ -358,6 +386,7 @@ static struct {
hdr_t num;
const char *name;
} hdr_names[] = {
{ hdr_connection, "Connection" },
{ hdr_content_length, "Content-Length" },
{ hdr_content_range, "Content-Range" },
{ hdr_last_modified, "Last-Modified" },
@ -388,7 +417,7 @@ http_cmd(conn_t *conn, const char *fmt, ...)
return (-1);
}
r = fetch_putln(conn, msg, len);
r = fetch_write(conn, msg, len);
free(msg);
if (r == -1) {
@ -629,7 +658,7 @@ http_basic_auth(conn_t *conn, const char *hdr, const char *usr, const char *pwd)
free(upw);
if (auth == NULL)
return (-1);
r = http_cmd(conn, "%s: Basic %s", hdr, auth);
r = http_cmd(conn, "%s: Basic %s\r\n", hdr, auth);
free(auth);
return (r);
}
@ -671,7 +700,7 @@ http_authorize(conn_t *conn, const char *hdr, const char *p)
* Connect to the correct HTTP server or proxy.
*/
static conn_t *
http_connect(struct url *URL, struct url *purl, const char *flags)
http_connect(struct url *URL, struct url *purl, const char *flags, int *cached)
{
conn_t *conn;
int af, verbose;
@ -679,6 +708,8 @@ http_connect(struct url *URL, struct url *purl, const char *flags)
int val;
#endif
*cached = 1;
#ifdef INET6
af = AF_UNSPEC;
#else
@ -701,7 +732,12 @@ http_connect(struct url *URL, struct url *purl, const char *flags)
return (NULL);
}
if ((conn = fetch_connect(URL->host, URL->port, af, verbose)) == NULL)
if ((conn = fetch_cache_get(URL, af)) != NULL) {
*cached = 1;
return (conn);
}
if ((conn = fetch_connect(URL, af, verbose)) == NULL)
/* fetch_connect() has already set an error code */
return (NULL);
if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0 &&
@ -759,7 +795,7 @@ set_if_modified_since(conn_t *conn, time_t last_modified)
snprintf(buf, sizeof(buf), "%.3s, %02d %.3s %4d %02d:%02d:%02d GMT",
weekdays + tm.tm_wday * 3, tm.tm_mday, months + tm.tm_mon * 3,
tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
http_cmd(conn, "If-Modified-Since: %s", buf);
http_cmd(conn, "If-Modified-Since: %s\r\n", buf);
}
@ -779,7 +815,8 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
{
conn_t *conn;
struct url *url, *new;
int chunked, direct, if_modified_since, need_auth, noredirect, verbose;
int chunked, direct, if_modified_since, need_auth, noredirect;
int keep_alive, verbose, cached;
int e, i, n, val;
off_t offset, clength, length, size;
time_t mtime;
@ -792,6 +829,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
noredirect = CHECK_FLAG('A');
verbose = CHECK_FLAG('v');
if_modified_since = CHECK_FLAG('i');
keep_alive = 0;
if (direct && purl) {
fetchFreeURL(purl);
@ -829,7 +867,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
}
/* connect to server or proxy */
if ((conn = http_connect(url, purl, flags)) == NULL)
if ((conn = http_connect(url, purl, flags, &cached)) == NULL)
goto ouch;
host = url->host;
@ -853,10 +891,10 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
fetch_info("requesting %s://%s%s",
url->scheme, host, url->doc);
if (purl) {
http_cmd(conn, "%s %s://%s%s HTTP/1.1",
http_cmd(conn, "%s %s://%s%s HTTP/1.1\r\n",
op, url->scheme, host, url->doc);
} else {
http_cmd(conn, "%s %s HTTP/1.1",
http_cmd(conn, "%s %s HTTP/1.1\r\n",
op, url->doc);
}
@ -864,7 +902,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
set_if_modified_since(conn, url->last_modified);
/* virtual host */
http_cmd(conn, "Host: %s", host);
http_cmd(conn, "Host: %s\r\n", host);
/* proxy authorization */
if (purl) {
@ -892,19 +930,18 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
/* other headers */
if ((p = getenv("HTTP_REFERER")) != NULL && *p != '\0') {
if (strcasecmp(p, "auto") == 0)
http_cmd(conn, "Referer: %s://%s%s",
http_cmd(conn, "Referer: %s://%s%s\r\n",
url->scheme, host, url->doc);
else
http_cmd(conn, "Referer: %s", p);
http_cmd(conn, "Referer: %s\r\n", p);
}
if ((p = getenv("HTTP_USER_AGENT")) != NULL && *p != '\0')
http_cmd(conn, "User-Agent: %s", p);
http_cmd(conn, "User-Agent: %s\r\n", p);
else
http_cmd(conn, "User-Agent: %s ", _LIBFETCH_VER);
http_cmd(conn, "User-Agent: %s\r\n", _LIBFETCH_VER);
if (url->offset > 0)
http_cmd(conn, "Range: bytes=%lld-", (long long)url->offset);
http_cmd(conn, "Connection: close");
http_cmd(conn, "");
http_cmd(conn, "Range: bytes=%lld-\r\n", (long long)url->offset);
http_cmd(conn, "\r\n");
/*
* Force the queued request to be dispatched. Normally, one
@ -968,6 +1005,9 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
case HTTP_PROTOCOL_ERROR:
/* fall through */
case -1:
--i;
if (cached)
continue;
fetch_syserr();
goto ouch;
default:
@ -986,6 +1026,10 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
case hdr_error:
http_seterr(HTTP_PROTOCOL_ERROR);
goto ouch;
case hdr_connection:
/* XXX too weak? */
keep_alive = (strcasecmp(p, "keep-alive") == 0);
break;
case hdr_content_length:
http_parse_length(p, &clength);
break;
@ -1115,13 +1159,20 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
URL->offset = offset;
URL->length = clength;
if (clength == -1 && !chunked)
keep_alive = 0;
if (conn->err == HTTP_NOT_MODIFIED) {
http_seterr(HTTP_NOT_MODIFIED);
if (keep_alive) {
fetch_cache_put(conn, fetch_close);
conn = NULL;
}
goto ouch;
}
/* wrap it up in a fetchIO */
if ((f = http_funopen(conn, chunked)) == NULL) {
if ((f = http_funopen(conn, chunked, keep_alive, clength)) == NULL) {
fetch_syserr();
goto ouch;
}
@ -1132,6 +1183,13 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
fetchFreeURL(purl);
if (HTTP_ERROR(conn->err)) {
if (keep_alive) {
char buf[512];
do {
} while (fetchIO_read(f, buf, sizeof(buf)) > 0);
}
fetchIO_close(f);
f = NULL;
}
@ -1354,6 +1412,7 @@ parse_index(struct index_parser *parser, const char *buf, size_t len)
return -1;
return end_attr + 1 - buf;
}
/* NOTREACHED */
abort();
}