check received content length if the Content-Length header is set - hurl - Goph… | |
git clone git://git.codemadness.org/hurl | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 85d6ee233ea16724799840840cb19c955cc0842f | |
parent a931b2c32a110fc26258afe16cc77d1c7f5d1e44 | |
Author: Hiltjo Posthuma <[email protected]> | |
Date: Mon, 9 Aug 2021 18:54:46 +0200 | |
check received content length if the Content-Length header is set | |
This prevents corrupted downloads, noticed when my connection was crappy. | |
Diffstat: | |
M hurl.c | 58 ++++++++++++++++++++++++++---… | |
1 file changed, 50 insertions(+), 8 deletions(-) | |
--- | |
diff --git a/hurl.c b/hurl.c | |
@@ -64,6 +64,32 @@ sighandler(int signo) | |
} | |
int | |
+parse_content_length(const char *s, size_t *length) | |
+{ | |
+ const char *p; | |
+ char *end; | |
+ long long l; | |
+ | |
+ if (!(p = strcasestr(s, "\r\nContent-Length:"))) | |
+ return -1; | |
+ | |
+ p += sizeof("\r\nContent-Length:") - 1; | |
+ p += strspn(p, " \t"); | |
+ | |
+ if (!isdigit(*p)) | |
+ return -1; | |
+ | |
+ errno = 0; | |
+ l = strtoll(p, &end, 10); | |
+ if (errno || p == end || (*end != '\0' && *end != '\r') || l < 0) | |
+ return -1; | |
+ | |
+ *length = l; | |
+ | |
+ return 0; | |
+} | |
+ | |
+int | |
uri_parse(const char *s, struct uri *u) | |
{ | |
const char *p = s; | |
@@ -221,9 +247,9 @@ https_request(void) | |
struct tls *t; | |
char buf[READ_BUF_SIZ], *p; | |
const char *errstr; | |
- size_t n, len; | |
+ size_t bodylen, expectedlen, n, len; | |
ssize_t r; | |
- int fd = -1, httpok = 0, ret = 1, stdport; | |
+ int cs, fd = -1, httpok = 0, ret = 1, stdport; | |
if (pledge("stdio dns inet rpath unveil", NULL) == -1) | |
err(1, "pledge"); | |
@@ -308,7 +334,9 @@ https_request(void) | |
goto err; | |
} | |
*p = '\0'; /* NUL terminate header part */ | |
+ cs = parse_content_length(buf, &expectedlen); | |
p += strlen("\r\n\r\n"); | |
+ bodylen = strlen(p); /* (partial) body after header */ | |
if (httpok) { | |
n = len - (p - buf); | |
@@ -336,6 +364,7 @@ https_request(void) | |
goto err; | |
} | |
len += r; | |
+ bodylen += r; | |
if (httpok) { | |
r = fwrite(buf, 1, r, stdout); | |
@@ -349,10 +378,15 @@ https_request(void) | |
break; | |
} | |
if (config_maxresponsesiz && len >= config_maxresponsesiz) { | |
- fprintf(stderr, "tls_read: response too big: %zu >= %zu\n", | |
+ fprintf(stderr, "response too big: %zu >= %zu\n", | |
len, config_maxresponsesiz); | |
goto err; | |
} | |
+ if (cs != -1 && expectedlen != bodylen) { | |
+ fprintf(stderr, "Content-Length mismatch: %zu expected != %zu … | |
+ expectedlen, bodylen); | |
+ goto err; | |
+ } | |
ret = 0; | |
err: | |
@@ -368,9 +402,9 @@ int | |
http_request(void) | |
{ | |
char buf[READ_BUF_SIZ], *p; | |
- size_t n, len; | |
+ size_t bodylen, expectedlen, n, len; | |
ssize_t r; | |
- int fd = -1, httpok = 0, ret = 1, stdport; | |
+ int cs, fd = -1, httpok = 0, ret = 1, stdport; | |
if (pledge("stdio dns inet", NULL) == -1) | |
err(1, "pledge"); | |
@@ -426,7 +460,9 @@ http_request(void) | |
goto err; | |
} | |
*p = '\0'; /* NUL terminate header part */ | |
+ cs = parse_content_length(buf, &expectedlen); | |
p += strlen("\r\n\r\n"); | |
+ bodylen = strlen(p); /* (partial) body after header */ | |
if (httpok) { | |
n = len - (p - buf); | |
@@ -451,6 +487,7 @@ http_request(void) | |
goto err; | |
} | |
len += r; | |
+ bodylen += r; | |
if (httpok) { | |
r = fwrite(buf, 1, r, stdout); | |
@@ -464,10 +501,15 @@ http_request(void) | |
break; | |
} | |
if (config_maxresponsesiz && len >= config_maxresponsesiz) { | |
- fprintf(stderr, "read: response too big: %zu >= %zu\n", | |
+ fprintf(stderr, "response too big: %zu >= %zu\n", | |
len, config_maxresponsesiz); | |
goto err; | |
} | |
+ if (cs != -1 && expectedlen != bodylen) { | |
+ fprintf(stderr, "Content-Length mismatch: %zu expected != %zu … | |
+ expectedlen, bodylen); | |
+ goto err; | |
+ } | |
ret = 0; | |
err: | |
@@ -534,7 +576,7 @@ gopher_request(void) | |
break; | |
} | |
if (config_maxresponsesiz && len >= config_maxresponsesiz) { | |
- fprintf(stderr, "read: response too big: %zu >= %zu\n", | |
+ fprintf(stderr, "response too big: %zu >= %zu\n", | |
len, config_maxresponsesiz); | |
goto err; | |
} | |
@@ -633,7 +675,7 @@ gophers_request(void) | |
break; | |
} | |
if (config_maxresponsesiz && len >= config_maxresponsesiz) { | |
- fprintf(stderr, "read: response too big: %zu >= %zu\n", | |
+ fprintf(stderr, "response too big: %zu >= %zu\n", | |
len, config_maxresponsesiz); | |
goto err; | |
} |