mirror of
https://github.com/xroche/httrack.git
synced 2026-07-12 20:07:43 +03:00
Compare commits
2 Commits
drop-swf-j
...
harden-zun
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85b0dc9d5e | ||
|
|
197571780a |
@@ -2123,6 +2123,19 @@ static int ae_write_collision(const char *path, const unsigned char *src,
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Write src[0..len) to path as-is; 0 on success. */
|
||||
static int ae_write_raw(const char *path, const unsigned char *src,
|
||||
size_t len) {
|
||||
FILE *const f = FOPEN(path, "wb");
|
||||
int ok;
|
||||
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
ok = fwrite(src, 1, len, f) == len;
|
||||
fclose(f);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Compare path's bytes to expect[0..len); 0 if equal. Streams (large files). */
|
||||
static int ae_check_decoded(const char *path, const unsigned char *expect,
|
||||
size_t len) {
|
||||
@@ -2190,6 +2203,46 @@ static int st_acceptencoding(httrackp *opt, int argc, char **argv) {
|
||||
assertf(ae_write_collision(inpath, body, 64) == 0);
|
||||
assertf(hts_zunpack(inpath, outpath) == 64);
|
||||
assertf(ae_check_decoded(outpath, body, 64) == 0);
|
||||
/* Identity fallback (#47): a plain body mislabeled as compressed is kept
|
||||
verbatim, small and multi-chunk (> one 8 KiB fread). */
|
||||
assertf(ae_write_raw(inpath, small, slen) == 0);
|
||||
assertf(hts_zunpack(inpath, outpath) == (int) slen);
|
||||
assertf(ae_check_decoded(outpath, small, slen) == 0);
|
||||
{
|
||||
const size_t ilen = 16 * 1024;
|
||||
unsigned char *idbody = malloct(ilen);
|
||||
|
||||
assertf(idbody != NULL);
|
||||
for (i = 0; i < ilen; i++)
|
||||
idbody[i] = small[i % slen];
|
||||
assertf(ae_write_raw(inpath, idbody, ilen) == 0);
|
||||
assertf(hts_zunpack(inpath, outpath) == (int) ilen);
|
||||
assertf(ae_check_decoded(outpath, idbody, ilen) == 0);
|
||||
freet(idbody);
|
||||
}
|
||||
/* Truncated gzip (CRC+ISIZE cut), zlib (ADLER32 cut) and raw deflate
|
||||
must all still fail, not fall back to a verbatim copy. */
|
||||
{
|
||||
static const struct {
|
||||
int wb;
|
||||
size_t cut;
|
||||
} tr[] = {{16 + MAX_WBITS, 8}, {MAX_WBITS, 4}, {-MAX_WBITS, 5}};
|
||||
|
||||
for (i = 0; i < sizeof(tr) / sizeof(tr[0]); i++) {
|
||||
unsigned char z[512];
|
||||
size_t zlen;
|
||||
FILE *f;
|
||||
|
||||
assertf(ae_write_packed(inpath, tr[i].wb, small, slen) == 0);
|
||||
f = FOPEN(inpath, "rb");
|
||||
assertf(f != NULL);
|
||||
zlen = fread(z, 1, sizeof(z), f);
|
||||
fclose(f);
|
||||
assertf(zlen > tr[i].cut && zlen < sizeof(z));
|
||||
assertf(ae_write_raw(inpath, z, zlen - tr[i].cut) == 0);
|
||||
assertf(hts_zunpack(inpath, outpath) < 0);
|
||||
}
|
||||
}
|
||||
freet(body);
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -48,6 +48,7 @@ Please visit our Website: http://www.httrack.com
|
||||
|
||||
/*
|
||||
Unpack file into a new file (gzip, zlib RFC1950 or raw deflate RFC1951).
|
||||
A body provably in no deflate framing is copied verbatim (identity).
|
||||
Return value: size of the new file, or -1 if an error occurred
|
||||
*/
|
||||
/* Note: utf-8 */
|
||||
@@ -68,6 +69,10 @@ int hts_zunpack(char *filename, char *newfile) {
|
||||
((inbuf[0] & 0x0f) == Z_DEFLATED &&
|
||||
(((unsigned) inbuf[0] << 8 | inbuf[1]) % 31) == 0)));
|
||||
int attempt;
|
||||
/* not_deflate: the raw attempt hit a data error, so the body is in no
|
||||
deflate framing at all. env_error: local I/O or memory failure. */
|
||||
hts_boolean not_deflate = HTS_FALSE;
|
||||
hts_boolean env_error = HTS_FALSE;
|
||||
|
||||
/* deflate is ambiguous; on failure retry with the other windowBits */
|
||||
for (attempt = 0; attempt < 2 && ret < 0; attempt++) {
|
||||
@@ -78,15 +83,20 @@ int hts_zunpack(char *filename, char *newfile) {
|
||||
|
||||
if (attempt > 0) {
|
||||
/* rewind input; reopening fpout "wb" discards the partial output */
|
||||
if (fseek(in, 0, SEEK_SET) != 0)
|
||||
if (fseek(in, 0, SEEK_SET) != 0) {
|
||||
env_error = HTS_TRUE;
|
||||
break;
|
||||
}
|
||||
navail = fread(inbuf, 1, sizeof(inbuf), in);
|
||||
}
|
||||
fpout = FOPEN(fconv(catbuff, sizeof(catbuff), newfile), "wb");
|
||||
if (fpout == NULL)
|
||||
if (fpout == NULL) {
|
||||
env_error = HTS_TRUE;
|
||||
break;
|
||||
}
|
||||
memset(&strm, 0, sizeof(strm));
|
||||
if (inflateInit2(&strm, windowBits) != Z_OK) {
|
||||
env_error = HTS_TRUE;
|
||||
fclose(fpout);
|
||||
break;
|
||||
}
|
||||
@@ -108,12 +118,17 @@ int hts_zunpack(char *filename, char *newfile) {
|
||||
zerr = inflate(&strm, Z_NO_FLUSH);
|
||||
if (zerr == Z_NEED_DICT || zerr == Z_DATA_ERROR ||
|
||||
zerr == Z_MEM_ERROR || zerr == Z_STREAM_ERROR) {
|
||||
if (zerr == Z_MEM_ERROR || zerr == Z_STREAM_ERROR)
|
||||
env_error = HTS_TRUE;
|
||||
else if (windowBits < 0)
|
||||
not_deflate = HTS_TRUE;
|
||||
ok = HTS_FALSE;
|
||||
break;
|
||||
}
|
||||
produced = sizeof(outbuf) - strm.avail_out;
|
||||
if (produced > 0 &&
|
||||
fwrite(outbuf, 1, produced, fpout) != produced) {
|
||||
env_error = HTS_TRUE;
|
||||
ok = HTS_FALSE;
|
||||
break;
|
||||
}
|
||||
@@ -129,6 +144,28 @@ int hts_zunpack(char *filename, char *newfile) {
|
||||
inflateEnd(&strm);
|
||||
fclose(fpout);
|
||||
}
|
||||
/* keep a mislabeled identity body verbatim only when provably not
|
||||
deflate; truncation or a local failure must keep failing (#47) */
|
||||
if (ret < 0 && !wrapped && not_deflate && !env_error && !ferror(in)) {
|
||||
FILE *const fpout =
|
||||
FOPEN(fconv(catbuff, sizeof(catbuff), newfile), "wb");
|
||||
|
||||
if (fpout != NULL && fseek(in, 0, SEEK_SET) == 0) {
|
||||
int size = 0;
|
||||
|
||||
while ((navail = fread(inbuf, 1, sizeof(inbuf), in)) > 0) {
|
||||
if (fwrite(inbuf, 1, navail, fpout) != navail) {
|
||||
size = -1;
|
||||
break;
|
||||
}
|
||||
size += (int) navail;
|
||||
}
|
||||
if (size >= 0 && !ferror(in))
|
||||
ret = size;
|
||||
}
|
||||
if (fpout != NULL)
|
||||
fclose(fpout);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Diverse seeded /big/ crawl: 12 pattern families, decoy absence, update pass
|
||||
# must 304-revalidate. 360 = 1 index + 96 pages + 192 imgs + 5 shared + 60
|
||||
# must 304-revalidate. 361 = 1 index + 96 pages + 192 imgs + 5 shared + 61
|
||||
# family + 6 singles; the 4 planted errors write -o1 pages, not counted.
|
||||
|
||||
set -euo pipefail
|
||||
@@ -9,7 +9,7 @@ set -euo pipefail
|
||||
: "${top_srcdir:=..}"
|
||||
|
||||
bash "$top_srcdir/tests/local-crawl.sh" --rerun \
|
||||
--errors 4 --files 360 \
|
||||
--errors 4 --files 361 \
|
||||
--found 'big/p/95.html' \
|
||||
--found 'big/a/d1/d2/d3/d4/d5/d6/d7/d8/deep.png' \
|
||||
--found 'big/a/f2-2x.png' \
|
||||
@@ -40,6 +40,7 @@ bash "$top_srcdir/tests/local-crawl.sh" --rerun \
|
||||
--not-found 'big/x/bj.jar' \
|
||||
--not-found 'big/x/is1.png' \
|
||||
--not-found 'big/x/concat.html' \
|
||||
--file-matches 'big/f1/gzid.html' '<p>gzid</p>' \
|
||||
--file-matches 'big/p/2.html' 'srcset="\.\./a/f2-1x\.png 1x, \.\./a/f2-2x\.png 2x"' \
|
||||
--file-matches 'big/a/blk2.css' 'url\(blk2-bg\.png\)' \
|
||||
--file-matches 'big/p/5.html' "document\\.write\\('<a href=\"\\.\\./f5/dw\\.html\"" \
|
||||
|
||||
@@ -374,6 +374,7 @@ def big_index(port):
|
||||
'<img src="/big/a/d1/d2/d3/d4/d5/d6/d7/d8/deep.png">'
|
||||
'<a href="/big/f1/long.html?x=%s">long</a>'
|
||||
'<a href="/big/f1/gzok.html">gzok</a>'
|
||||
'<a href="/big/f1/gzid.html">gzid</a>'
|
||||
'<a href="//127.0.0.1:%d/big/f1/protorel.html">protorel</a>'
|
||||
'<a href="http://127.0.0.1:%d/big/f1/abshost.html">abshost</a>'
|
||||
'<a href="/big/e/404.html">e404</a>'
|
||||
@@ -399,6 +400,7 @@ BIG_SIMPLE_PAGES = {
|
||||
"/big/f1/dir/": "dir index",
|
||||
"/big/f1/long.html": "long",
|
||||
"/big/f1/gzok.html": "gzok",
|
||||
"/big/f1/gzid.html": "gzid",
|
||||
"/big/f1/protorel.html": "protorel",
|
||||
"/big/f1/abshost.html": "abshost",
|
||||
"/big/f5/dw.html": "dw target",
|
||||
@@ -1079,6 +1081,13 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
"text/html",
|
||||
extra=[("Content-Encoding", "gzip")],
|
||||
)
|
||||
elif path == "/big/f1/gzid.html":
|
||||
# Plain body mislabeled as gzip: identity fallback keeps it (#47)
|
||||
self.big_send(
|
||||
body,
|
||||
"text/html",
|
||||
extra=[("Content-Encoding", "gzip")],
|
||||
)
|
||||
else:
|
||||
self.big_send(body, "text/html")
|
||||
elif path == "/big/f1/list.html":
|
||||
|
||||
Reference in New Issue
Block a user