X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=src%2Ffetchurl.c;h=21e2e661e7a85fa169e81f792a9154acdb3ad8eb;hb=6ff53c22d4ab08760c5e8747cd12e4f8bc0b82f6;hp=1b337244421df9f0f74b7aa5a2d99186670ecd60;hpb=5dd3c3e64a9574112dda77a5afc167f5daa53fd8;p=zpackage diff --git a/src/fetchurl.c b/src/fetchurl.c index 1b33724..21e2e66 100644 --- a/src/fetchurl.c +++ b/src/fetchurl.c @@ -15,7 +15,6 @@ #include #include "tlse.h" -#define MARK fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__) struct tls_uri { char *scheme; @@ -23,9 +22,12 @@ struct tls_uri { char *host; char *port; char *path; + char *encoded_path; char *query; + char *encoded_query; char *fragment; }; + int tls_parse_uri(char *, struct tls_uri *); void tls_free_uri(struct tls_uri *); @@ -207,6 +209,11 @@ int verify_first(struct TLSContext *context, struct TLSCertificate **chain, int } int match = (memcmp(certhash, fp, 64) == 0); + if (!match) { + fprintf(stderr, "host %s certificate changed\n", host); + fprintf(stderr, "was %.64s\n", fp); + fprintf(stderr, "now %.64s\n", certhash); + } close(trustdb); tls_buffer_free(&tbuf); @@ -508,6 +515,53 @@ static void fake_header(struct io *io, int fd) { tls_buffer_append(hdr, "\r\n", 2); } +char *pathlast(char *path) { + char *last = 0; + size_t len = 0; + + if (path == 0) { + return 0; + } + + while (*path == '/') { + path++; + } + + do { + last = path; + len = 0; + while (*path && *path != '/') { + path++; + len++; + } + while (*path == '/') { + path++; + } + } while (*path); + + if (len == 0) { + return 0; + } + + return strndup(last, len); +} + +static time_t file_mtime(char *path) { + struct stat st; + int rv; + + rv = stat(path, &st); + if (rv == -1) { + if (errno == ENOENT) { + return 0; + } + perror("stat failed:"); + return -1; + } + + return st.st_mtime; +} + int main(int ac, char *av[]) { int sockfd, port = -1, rv; ssize_t ret; @@ -519,10 +573,10 @@ int main(int ac, char *av[]) { #endif char *req_file = 0; char *host = 0; - struct tls_uri uri; + struct tls_uri uri = { 0 }; char *outfile = 0; int raw = 0, head = 0; - int out = 1; + int out = 1; /* output file descriptor */ int use_tls = 0; struct io io = { {0}, 0, -1, 0, 0, 0, 0, 0 }; struct TLSContext *clientssl = 0; @@ -532,25 +586,30 @@ int main(int ac, char *av[]) { struct tls_buffer request; char lmtime[80]; char *eoh = 0; + char *user_agent = 0; size_t total = 0; size_t header_len; char *url = 0; int redirs = 0, redirlimit = 50, printstatus = 0; - int verifypolicy = 1; + int verifypolicy = 1, calcoutfile = 0, ifnewer = 0; ltc_mp = tfm_desc; - while ((option = getopt(ac, av, "o:rIfz:#R:SkK")) != -1) { + while ((option = getopt(ac, av, "o:OrIfz:np#R:SkKU:")) != -1) { switch (option) { case 'o': outfile = optarg; break; + case 'O': calcoutfile = 1; break; case 'S': printstatus = 1; head = 1; break; case 'k': verifypolicy = 0; break; case 'K': verifypolicy = 2; break; + case 'U': user_agent = optarg; break; case 'I': head = 1; case 'r': raw = 1; break; case 'f': failsilent = 1; break; case 'z': lmfile = optarg; break; + case 'n': ifnewer = 1; break; case 'R': redirlimit = strtol(optarg, 0, 10); break; + case 'p': case '#': progressbar = 1; break; default: exit(EXIT_FAILURE); @@ -563,34 +622,44 @@ int main(int ac, char *av[]) { exit(EXIT_FAILURE); } + url = strdup(av[optind]); + if (!url) { + exit(EXIT_FAILURE); + } + io.last_modified = 0; - if (lmfile) { - struct stat st; - int rv; - struct tm *mtime; - time_t ts; - rv = stat(lmfile, &st); - if (rv == -1) { - perror("stat failed:"); + if (calcoutfile && !outfile) { + tls_parse_uri(url, &uri); + outfile = pathlast(uri.path); + /* outfile leaks memory here, so if this + * were turned into a library function, + * we'd need to track it + */ + if (!outfile) { + fprintf(stderr, "unable to determine outfile\n"); exit(EXIT_FAILURE); } - ts = st.st_mtime; - io.last_modified = ts; - mtime = gmtime(&ts); - strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime); } - url = strdup(av[optind]); - if (!url) { - exit(EXIT_FAILURE); + if (ifnewer && outfile && !lmfile) { + lmfile = outfile; } - if (outfile) { - out = open(outfile, O_WRONLY|O_CREAT, 0600); - if (out == -1) { - perror("can't open output file:"); + if (lmfile) { + struct tm *mtime; + time_t ts; + + ts = file_mtime(lmfile); + + if (ts == -1) { exit(EXIT_FAILURE); + } else if (ts != 0) { + io.last_modified = ts; + mtime = gmtime(&ts); + strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime); + } else { + lmfile = 0; } } @@ -603,6 +672,7 @@ int main(int ac, char *av[]) { tls_free_uri(&uri); io.response.len = 0; request.len = 0; + eoh = 0; tls_parse_uri(url, &uri); host = uri.host; @@ -615,10 +685,18 @@ int main(int ac, char *av[]) { } else { tls_buffer_append(&request, "GET ", 4); } - tls_buffer_append(&request, uri.path, strlen(uri.path)); + tls_buffer_append(&request, uri.encoded_path, strlen(uri.encoded_path)); + if (uri.encoded_query) { + tls_buffer_append(&request, "?", 1); + tls_buffer_append(&request, uri.encoded_query, strlen(uri.encoded_query)); + } tls_buffer_append(&request, " HTTP/1.1\r\n", 11); append_header(&request, "Host", host); + if (user_agent) { + append_header(&request, "User-Agent", user_agent); + } + append_header(&request, "Accept", "*/*"); append_header(&request, "Connection", "close"); if (lmfile) { append_header(&request, "If-Modified-Since", lmtime); @@ -716,12 +794,16 @@ int main(int ac, char *av[]) { parse_header(&io); switch (io.status_code) { + case 304: + progressbar = 0; + break; case 301: case 302: case 303: case 307: free(url); url = strdup(io.redirect); + close(io.socket); continue; break; } @@ -744,6 +826,14 @@ int main(int ac, char *av[]) { } } + if (outfile) { + out = open(outfile, O_WRONLY|O_CREAT, 0600); + if (out == -1) { + perror("can't open output file:"); + exit(EXIT_FAILURE); + } + } + do { write(out, io.response.buffer, io.response.len); ret = io.response.len; @@ -754,11 +844,8 @@ int main(int ac, char *av[]) { pdots(50, '.', total, total+ret, io.content_length); } else { - int old = total / 1000000; - int new = (total+ret)/1000000; - while (old < new) { - putc('.',stderr); - } + putc('\r', stderr); + fprintf(stderr, "%zu", total+ret); } total += ret; } @@ -771,7 +858,12 @@ int main(int ac, char *av[]) { if (ret < 0) { fprintf(stderr, "%s read error %zd\n", uri.scheme, ret); } - /* futimens(out, ...) */ + struct timespec ts[2]; + ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT; + ts[1].tv_sec = io.last_modified; + ts[1].tv_nsec = 0; + + futimens(out, ts); close(out); tls_buffer_free(&io.response); break; @@ -788,5 +880,5 @@ int main(int ac, char *av[]) { putc('\n',stderr); } - return io.status_code == 200 ? 0 : EXIT_FAILURE; + return io.status_code < 400 ? 0 : EXIT_FAILURE; }