version 1.177, 2019/11/04 15:36:36 |
version 1.178, 2019/11/14 23:48:37 |
|
|
#include "cmds.h" |
#include "cmds.h" |
|
|
static int url_get(const char *, const char *, const char *, int); |
static int url_get(const char *, const char *, const char *, int); |
|
static int save_chunked(FILE *, struct tls *, int , char *, size_t); |
static void aborthttp(int); |
static void aborthttp(int); |
static void abortfile(int); |
static void abortfile(int); |
static char hextochar(const char *); |
static char hextochar(const char *); |
|
|
int status; |
int status; |
int save_errno; |
int save_errno; |
const size_t buflen = 128 * 1024; |
const size_t buflen = 128 * 1024; |
|
int chunked = 0; |
|
|
direction = "received"; |
direction = "received"; |
|
|
|
|
* the original URI (path). |
* the original URI (path). |
*/ |
*/ |
if (credentials) |
if (credentials) |
fprintf(fin, "GET %s HTTP/1.0\r\n" |
fprintf(fin, "GET %s HTTP/1.1\r\n" |
|
"Connection: close\r\n" |
"Proxy-Authorization: Basic %s\r\n" |
"Proxy-Authorization: Basic %s\r\n" |
"Host: %s\r\n%s%s\r\n\r\n", |
"Host: %s\r\n%s%s\r\n\r\n", |
epath, credentials, |
epath, credentials, |
proxyhost, buf ? buf : "", httpuseragent); |
proxyhost, buf ? buf : "", httpuseragent); |
else |
else |
fprintf(fin, "GET %s HTTP/1.0\r\n" |
fprintf(fin, "GET %s HTTP/1.1\r\n" |
|
"Connection: close\r\n" |
"Host: %s\r\n%s%s\r\n\r\n", |
"Host: %s\r\n%s%s\r\n\r\n", |
epath, proxyhost, buf ? buf : "", httpuseragent); |
epath, proxyhost, buf ? buf : "", httpuseragent); |
} else { |
} else { |
|
|
#ifndef NOSSL |
#ifndef NOSSL |
if (credentials) { |
if (credentials) { |
fprintf(fin, |
fprintf(fin, |
"GET /%s %s\r\nAuthorization: Basic %s\r\nHost: ", |
"GET /%s HTTP/1.1\r\n" |
epath, restart_point ? |
"Connection: close\r\n" |
"HTTP/1.1\r\nConnection: close" : "HTTP/1.0", |
"Authorization: Basic %s\r\n" |
credentials); |
"Host: ", epath, credentials); |
free(credentials); |
free(credentials); |
credentials = NULL; |
credentials = NULL; |
} else |
} else |
#endif /* NOSSL */ |
#endif /* NOSSL */ |
fprintf(fin, "GET /%s %s\r\nHost: ", epath, |
fprintf(fin, |
#ifndef SMALL |
"GET /%s HTTP/1.1\r\n" |
restart_point ? "HTTP/1.1\r\nConnection: close" : |
"Connection: close\r\n" |
#endif /* !SMALL */ |
"Host: ", epath); |
"HTTP/1.0"); |
|
if (proxyhost) { |
if (proxyhost) { |
fprintf(fin, "%s", proxyhost); |
fprintf(fin, "%s", proxyhost); |
port = NULL; |
port = NULL; |
|
|
retryafter = strtonum(cp, 0, 0, &errstr); |
retryafter = strtonum(cp, 0, 0, &errstr); |
if (errstr != NULL) |
if (errstr != NULL) |
retryafter = -1; |
retryafter = -1; |
|
#define TRANSFER_ENCODING "Transfer-Encoding: " |
|
} else if (strncasecmp(cp, TRANSFER_ENCODING, |
|
sizeof(TRANSFER_ENCODING) - 1) == 0) { |
|
cp += sizeof(TRANSFER_ENCODING) - 1; |
|
cp[strcspn(cp, " \t")] = '\0'; |
|
if (strcasecmp(cp, "chunked") == 0) |
|
chunked = 1; |
} |
} |
free(buf); |
free(buf); |
} |
} |
|
|
|
/* Content-Length should be ignored for Transfer-Encoding: chunked */ |
|
if (chunked) |
|
filesize = -1; |
|
|
if (isunavail) { |
if (isunavail) { |
if (retried || retryafter != 0) |
if (retried || retryafter != 0) |
warnx("Error retrieving %s: 503 Service Unavailable", |
warnx("Error retrieving %s: 503 Service Unavailable", |
|
|
/* Finally, suck down the file. */ |
/* Finally, suck down the file. */ |
if ((buf = malloc(buflen)) == NULL) |
if ((buf = malloc(buflen)) == NULL) |
errx(1, "Can't allocate memory for transfer buffer"); |
errx(1, "Can't allocate memory for transfer buffer"); |
i = 0; |
|
len = 1; |
|
oldinti = signal(SIGINFO, psummary); |
oldinti = signal(SIGINFO, psummary); |
while (len > 0) { |
if (chunked) { |
len = fread(buf, 1, buflen, fin); |
if (save_chunked(fin, tls, out, buf, buflen) == -1) { |
bytes += len; |
signal(SIGINFO, oldinti); |
for (cp = buf, wlen = len; wlen > 0; wlen -= i, cp += i) { |
goto cleanup_url_get; |
if ((i = write(out, cp, wlen)) == -1) { |
} |
warn("Writing %s", savefile); |
} else { |
signal(SIGINFO, oldinti); |
i = 0; |
goto cleanup_url_get; |
len = 1; |
|
while (len > 0) { |
|
len = fread(buf, 1, buflen, fin); |
|
bytes += len; |
|
for (cp = buf, wlen = len; wlen > 0; wlen -= i, cp += i) { |
|
if ((i = write(out, cp, wlen)) == -1) { |
|
warn("Writing %s", savefile); |
|
signal(SIGINFO, oldinti); |
|
goto cleanup_url_get; |
|
} |
|
else if (i == 0) |
|
break; |
} |
} |
else if (i == 0) |
if (hash && !progress) { |
break; |
while (bytes >= hashbytes) { |
|
(void)putc('#', ttyout); |
|
hashbytes += mark; |
|
} |
|
(void)fflush(ttyout); |
|
} |
} |
} |
if (hash && !progress) { |
signal(SIGINFO, oldinti); |
while (bytes >= hashbytes) { |
if (hash && !progress && bytes > 0) { |
|
if (bytes < mark) |
(void)putc('#', ttyout); |
(void)putc('#', ttyout); |
hashbytes += mark; |
(void)putc('\n', ttyout); |
} |
|
(void)fflush(ttyout); |
(void)fflush(ttyout); |
} |
} |
|
if (len != 0) { |
|
warnx("Reading from socket: %s", sockerror(tls)); |
|
goto cleanup_url_get; |
|
} |
} |
} |
signal(SIGINFO, oldinti); |
|
if (hash && !progress && bytes > 0) { |
|
if (bytes < mark) |
|
(void)putc('#', ttyout); |
|
(void)putc('\n', ttyout); |
|
(void)fflush(ttyout); |
|
} |
|
if (len != 0) { |
|
warnx("Reading from socket: %s", sockerror(tls)); |
|
goto cleanup_url_get; |
|
} |
|
progressmeter(1, NULL); |
progressmeter(1, NULL); |
if ( |
if ( |
#ifndef SMALL |
#ifndef SMALL |
|
|
free(newline); |
free(newline); |
free(credentials); |
free(credentials); |
return (rval); |
return (rval); |
|
} |
|
|
|
static int |
|
save_chunked(FILE *fin, struct tls *tls, int out, char *buf, size_t buflen) |
|
{ |
|
|
|
char *header, *end, *cp; |
|
unsigned long chunksize; |
|
size_t hlen, rlen, wlen; |
|
ssize_t written; |
|
char cr, lf; |
|
|
|
for (;;) { |
|
header = ftp_readline(fin, &hlen); |
|
if (header == NULL) |
|
break; |
|
/* strip CRLF and any optional chunk extension */ |
|
header[strcspn(header, ";\r\n")] = '\0'; |
|
errno = 0; |
|
chunksize = strtoul(header, &end, 16); |
|
if (errno || header[0] == '\0' || *end != '\0' || |
|
chunksize > INT_MAX) { |
|
warnx("Invalid chunk size '%s'", header); |
|
free(header); |
|
return -1; |
|
} |
|
free(header); |
|
|
|
if (chunksize == 0) { |
|
/* We're done. Ignore optional trailer. */ |
|
return 0; |
|
} |
|
|
|
for (written = 0; chunksize != 0; chunksize -= rlen) { |
|
rlen = (chunksize < buflen) ? chunksize : buflen; |
|
rlen = fread(buf, 1, rlen, fin); |
|
if (rlen == 0) |
|
break; |
|
bytes += rlen; |
|
for (cp = buf, wlen = rlen; wlen > 0; |
|
wlen -= written, cp += written) { |
|
if ((written = write(out, cp, wlen)) == -1) { |
|
warn("Writing output file"); |
|
return -1; |
|
} |
|
} |
|
} |
|
|
|
if (rlen == 0 || |
|
fread(&cr, 1, 1, fin) != 1 || |
|
fread(&lf, 1, 1, fin) != 1) |
|
break; |
|
|
|
if (cr != '\r' || lf != '\n') { |
|
warnx("Invalid chunked encoding"); |
|
return -1; |
|
} |
|
} |
|
|
|
if (ferror(fin)) |
|
warnx("Error while reading from socket: %s", sockerror(tls)); |
|
else |
|
warnx("Invalid chunked encoding: short read"); |
|
|
|
return -1; |
} |
} |
|
|
/* |
/* |