summaryrefslogtreecommitdiffstats
path: root/lib/libfetch
diff options
context:
space:
mode:
authormurray <murray@FreeBSD.org>2008-12-15 08:27:44 +0000
committermurray <murray@FreeBSD.org>2008-12-15 08:27:44 +0000
commit72a890ccd7d1c4fd04c561303e0ad5e45a6a4aaa (patch)
tree9ece849067a9d612c3bf00d2dd2a07b33b383a74 /lib/libfetch
parent3475c71ce83c2101fd0d42512193048affde82cc (diff)
downloadFreeBSD-src-72a890ccd7d1c4fd04c561303e0ad5e45a6a4aaa.zip
FreeBSD-src-72a890ccd7d1c4fd04c561303e0ad5e45a6a4aaa.tar.gz
Add support for HTTP 1.1 If-Modified-Since behavior.
fetch(1) accepts a new argument -i <file> that if specified will cause the file to be downloaded only if it is more recent than the mtime of <file>. libfetch(3) accepts the mtime in the url structure and a flag to indicate when this behavior is desired. PR: bin/87841 Submitted by: Jukka A. Ukkonen <jau@iki.fi> (partially) Reviewed by: des, ru MFC after: 3 weeks
Diffstat (limited to 'lib/libfetch')
-rw-r--r--lib/libfetch/fetch.325
-rw-r--r--lib/libfetch/fetch.h1
-rw-r--r--lib/libfetch/http.c28
3 files changed, 50 insertions, 4 deletions
diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3
index 81b7164..9b312b0 100644
--- a/lib/libfetch/fetch.3
+++ b/lib/libfetch/fetch.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 18, 2007
+.Dd December 14, 2008
.Dt FETCH 3
.Os
.Sh NAME
@@ -165,9 +165,16 @@ struct url {
char *doc;
off_t offset;
size_t length;
+ time_t ims_time;
};
.Ed
.Pp
+The
+.Va ims_time
+field stores the time value for
+.Li If-Modified-Since
+HTTP requests.
+.Pp
The pointer returned by
.Fn fetchMakeURL
or
@@ -353,6 +360,22 @@ and
.Fn fetchPutHTTP
will use a direct connection even if a proxy server is defined.
.Pp
+If the
+.Ql i
+(if-modified-since) flag is specified, and
+the
+.Va ims_time
+field is set in
+.Vt "struct url" ,
+then
+.Fn fetchXGetHTTP
+and
+.Fn fetchGetHTTP
+will send a conditional
+.Li If-Modified-Since
+HTTP header to only fetch the content if it is newer than
+.Va ims_time .
+.Pp
Since there seems to be no good way of implementing the HTTP PUT
method in a manner consistent with the rest of the
.Nm fetch
diff --git a/lib/libfetch/fetch.h b/lib/libfetch/fetch.h
index 10d911a..e620a01 100644
--- a/lib/libfetch/fetch.h
+++ b/lib/libfetch/fetch.h
@@ -46,6 +46,7 @@ struct url {
char *doc;
off_t offset;
size_t length;
+ time_t ims_time;
};
struct url_stat {
diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c
index 39a8cfaa..dd98349 100644
--- a/lib/libfetch/http.c
+++ b/lib/libfetch/http.c
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <ctype.h>
#include <err.h>
@@ -92,6 +93,7 @@ __FBSDID("$FreeBSD$");
#define HTTP_MOVED_PERM 301
#define HTTP_MOVED_TEMP 302
#define HTTP_SEE_OTHER 303
+#define HTTP_NOT_MODIFIED 304
#define HTTP_TEMP_REDIRECT 307
#define HTTP_NEED_AUTH 401
#define HTTP_NEED_PROXY_AUTH 407
@@ -797,20 +799,23 @@ FILE *
http_request(struct url *URL, const char *op, struct url_stat *us,
struct url *purl, const char *flags)
{
+ char timebuf[80];
+ char hbuf[MAXHOSTNAMELEN + 7], *host;
conn_t *conn;
struct url *url, *new;
- int chunked, direct, need_auth, noredirect, verbose;
+ int chunked, direct, ims, need_auth, noredirect, verbose;
int e, i, n, val;
off_t offset, clength, length, size;
time_t mtime;
const char *p;
FILE *f;
hdr_t h;
- char hbuf[MAXHOSTNAMELEN + 7], *host;
+ struct tm *timestruct;
direct = CHECK_FLAG('d');
noredirect = CHECK_FLAG('A');
verbose = CHECK_FLAG('v');
+ ims = CHECK_FLAG('i');
if (direct && purl) {
fetchFreeURL(purl);
@@ -879,6 +884,14 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
op, url->doc);
}
+ if (ims && url->ims_time) {
+ timestruct = gmtime((time_t *)&url->ims_time);
+ (void)strftime(timebuf, 80, "%a, %d %b %Y %T GMT",
+ timestruct);
+ if (verbose)
+ fetch_info("If-Modified-Since: %s", timebuf);
+ http_cmd(conn, "If-Modified-Since: %s", timebuf);
+ }
/* virtual host */
http_cmd(conn, "Host: %s", host);
@@ -940,6 +953,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
switch (http_get_reply(conn)) {
case HTTP_OK:
case HTTP_PARTIAL:
+ case HTTP_NOT_MODIFIED:
/* fine */
break;
case HTTP_MOVED_PERM:
@@ -1074,7 +1088,10 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
}
/* we have a hit or an error */
- if (conn->err == HTTP_OK || conn->err == HTTP_PARTIAL || HTTP_ERROR(conn->err))
+ if (conn->err == HTTP_OK
+ || conn->err == HTTP_NOT_MODIFIED
+ || conn->err == HTTP_PARTIAL
+ || HTTP_ERROR(conn->err))
break;
/* all other cases: we got a redirect */
@@ -1102,6 +1119,11 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
(long long)offset, (long long)length,
(long long)size, (long long)clength));
+ if (conn->err == HTTP_NOT_MODIFIED) {
+ http_seterr(HTTP_NOT_MODIFIED);
+ return (NULL);
+ }
+
/* check for inconsistencies */
if (clength != -1 && length != -1 && clength != length) {
http_seterr(HTTP_PROTOCOL_ERROR);
OpenPOWER on IntegriCloud