Merge libfetch-2.30 from NetBSD's pkgsrc.
--HG-- extra : convert_revision : xtraeme%40gmail.com-20100124144753-ni487x8m7r05847b
This commit is contained in:
107
lib/fetch/http.c
107
lib/fetch/http.c
@ -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();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user