httrack-3.49.21/0000755000175000017500000000000015237105307007076 5httrack-3.49.21/fuzz/0000755000175000017500000000000015237105307010074 5httrack-3.49.21/fuzz/run-fuzzers.sh0000755000175000017500000000262315237104167012673 #!/bin/bash # Drive every built harness against its seed corpus. # run-fuzzers.sh check deterministic replay (CI smoke) # run-fuzzers.sh [seconds] timed mutation run (discovery) # Replay is crash/leak-only and never mutates; the per-unit -timeout guards # both modes against pathological slowdowns (e.g. pre-#501 strjoker). set -euo pipefail srcdir=$(cd "$(dirname "$0")" && pwd) bld=${1:?usage: run-fuzzers.sh [check|seconds]} mode=${2:-20} status=0 for f in "$bld"/fuzz-*; do if [ ! -f "$f" ] || [ ! -r "$f" ]; then continue; fi case "$f" in *.o | *.c | *.dSYM) continue ;; esac name=$(basename "$f") corpus="$srcdir/corpus/${name#fuzz-}" if [ "$mode" = "check" ]; then echo "=== $name (replay) ===" [ -d "$corpus" ] || continue if ! "$f" -runs=0 -timeout=25 -rss_limit_mb=2048 "$corpus"; then echo "*** $name FAILED on its corpus" >&2 status=1 fi continue fi work=$(mktemp -d) args=("$work") [ -d "$corpus" ] && args+=("$corpus") echo "=== $name (${mode}s) ===" if ! "$f" -max_total_time="$mode" -timeout=25 -rss_limit_mb=2048 \ -artifact_prefix="$work/" -print_final_stats=1 "${args[@]}"; then echo "*** $name FAILED; artifacts:" >&2 ls -l "$work" >&2 status=1 else rm -rf "$work" fi done exit $status httrack-3.49.21/fuzz/fuzz-url.c0000644000175000017500000000332215237104167011761 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the URL splitter and path normalizer (htslib.c): ident_url_absolute is the first parser to touch a raw URL; fil_simplifie collapses ./ and ../ in place. */ #include "fuzz.h" #include "htscore.h" #include "htslib.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *s = fuzz_strdup(data, size); lien_adrfil *af = calloct(1, sizeof(*af)); /* fil_simplifie rewrites in place and may grow an empty path to "./" */ char *path = malloct(size + 3); (void) ident_url_absolute(s, af); memcpy(path, s, size + 1); fil_simplifie(path); freet(path); freet(af); freet(s); return 0; } httrack-3.49.21/fuzz/fuzz-unescape.c0000644000175000017500000000347415237104167012772 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the URL percent-decoders (htslib.c). First input byte picks the output buffer size, so the bounded-copy contract is exercised. */ #include "fuzz.h" #include "httrack-library.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { static const size_t bsizes[] = {1, 2, 16, 256, 8192}; size_t bsize; char *s, *catbuff; if (size == 0) return 0; bsize = bsizes[data[0] % (sizeof(bsizes) / sizeof(bsizes[0]))]; data++, size--; s = fuzz_strdup(data, size); catbuff = malloct(bsize); (void) unescape_http(catbuff, bsize, s); (void) unescape_http_unharm(catbuff, bsize, s, 0); (void) unescape_http_unharm(catbuff, bsize, s, 1); unescape_amp(s); freet(catbuff); freet(s); return 0; } httrack-3.49.21/fuzz/fuzz-sitemap.c0000644000175000017500000000377315237104167012633 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 2026 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the sitemap scanner (htssitemap.c): raw XML, gzip-framed bodies and truncated streams all arrive here straight off the network. */ #include "fuzz.h" #include "htssitemap.h" static hts_boolean sm_count(void *arg, const char *url) { int *const n = (int *) arg; (void) url; (*n)++; return HTS_TRUE; } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { static const int caps[] = {0, 1, 16, HTS_SITEMAP_MAX_URLS_DOC}; hts_boolean is_index; char *body; int n = 0, cap; if (size == 0) return 0; cap = caps[data[0] % (sizeof(caps) / sizeof(caps[0]))]; data++, size--; /* A heap copy of exactly `size` bytes: the scanner must never rely on a terminator, and ASan turns any overread into a report. */ body = malloct(size != 0 ? size : 1); memcpy(body, data, size); (void) hts_sitemap_scan(body, size, cap, &is_index, sm_count, &n); freet(body); return 0; } httrack-3.49.21/fuzz/fuzz-singlefile.c0000644000175000017500000001442715237104167013310 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 2026 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the --single-file rewriter (htssinglefile.c): hostile HTML walked through the tag, CSS url()/@import and srcset parsers, then re-serialized. The resolver is aimed at a private temp tree, so the inlining half (MIME guess, base64, nested stylesheet) is reached and nothing else on disk is. */ #include "fuzz.h" #include "httrack-library.h" #include "htssinglefile.h" #include #include #include /* Between a.png and big.png, so one input reaches both the inline path and the over-cap fallback. */ #define FUZZ_SF_CAP 64 static char sf_root[512]; static char sf_page[600]; /* The asset tree, in removal order: the subdirectory comes after its file. */ static const char *const sf_files[] = {"a.png", "big.png", "j.js", "s.css", "sub/b.css", "sub", NULL}; static void sf_cleanup(void) { char path[700]; int i; for (i = 0; sf_files[i] != NULL; i++) { snprintf(path, sizeof(path), "%s/%s", sf_root, sf_files[i]); (void) remove(path); } (void) remove(sf_root); } /* One httrackp for the whole run: the mark secret lives on it, so a fresh one per input would make every mark in the corpus unrecognisable. */ static httrackp *sf_opt = NULL; /* A missing asset would silently reduce the target to its parser half. */ static void sf_write(const char *name, const char *data, size_t len) { char path[700]; FILE *fp; snprintf(path, sizeof(path), "%s/%s", sf_root, name); fp = fopen(path, "wb"); if (fp == NULL || fwrite(data, 1, len, fp) != len) abort(); fclose(fp); } static void sf_text(const char *name, const char *data) { sf_write(name, data, strlen(data)); } /* Append ref plus a real mark for it. The secret is drawn per httrackp, so a fixture cannot spell one; every mark the target sees is built here. */ static void sf_marked(String *out, const char *ref, char cls) { char mark[SINGLEFILE_MARK_MAX]; StringCat(*out, ref); StringCat(*out, singlefile_mark(sf_opt, mark, sizeof(mark), cls, strlen(ref))); } /* \001\002 in an input becomes plus its mark, which is the only way a corpus file can reach the mark parser at all. */ static void sf_expand_input(const char *in, size_t len, String *out) { size_t i, start = 0; StringClear(*out); for (i = 0; i < len; i++) { if (in[i] == '\001') { start = StringLength(*out); } else if (in[i] == '\002') { char mark[SINGLEFILE_MARK_MAX]; StringCat(*out, singlefile_mark(sf_opt, mark, sizeof(mark), SINGLEFILE_CLASS_ANY, StringLength(*out) - start)); } else { StringAddchar(*out, in[i]); } } } static void sf_css(const char *name, const char *pre, const char *ref, const char *post) { String body = STRING_EMPTY; StringCopy(body, pre); sf_marked(&body, ref, SINGLEFILE_CLASS_ANY); StringCat(body, post); sf_write(name, StringBuff(body), StringLength(body)); StringFree(body); } static void sf_init(void) { static const char png[] = "\x89PNG\r\n\x1a\n"; static const char big[4096] = "\x89PNG"; const char *tmp = getenv("TMPDIR"); char path[700]; hts_init(); sf_opt = hts_create_opt(); sf_opt->log = sf_opt->errlog = NULL; sf_opt->single_file_max_size = FUZZ_SF_CAP; snprintf(sf_root, sizeof(sf_root), "%s/httrack-fuzz-sf-XXXXXX", tmp != NULL && tmp[0] != '\0' ? tmp : "/tmp"); if (mkdtemp(sf_root) == NULL) abort(); atexit(sf_cleanup); snprintf(sf_page, sizeof(sf_page), "%s/page.html", sf_root); snprintf(path, sizeof(path), "%s/sub", sf_root); if (mkdir(path, 0700) != 0) abort(); sf_write("a.png", png, sizeof(png) - 1); sf_write("big.png", big, sizeof(big)); sf_text("j.js", "var x=1;\n"); /* Marked, so an inlined stylesheet recurses into its own marks and its un-inlinable reference is rebased; unmarked assets leave the target as a bare scan that reaches nothing. */ { String css = STRING_EMPTY; StringCopy(css, "@import url("); sf_marked(&css, "sub/b.css", SINGLEFILE_CLASS_CSS); StringCat(css, ");\ndiv{background:url("); sf_marked(&css, "a.png", SINGLEFILE_CLASS_ANY); StringCat(css, ")}\np{background:url("); sf_marked(&css, "big.png", SINGLEFILE_CLASS_ANY); StringCat(css, ")}\n"); sf_write("s.css", StringBuff(css), StringLength(css)); StringFree(css); } sf_css("sub/b.css", "p{background:url(", "../a.png", ")}\n"); } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { static int inited = 0; String out = STRING_EMPTY; String in = STRING_EMPTY; char *html; size_t html_len; if (!inited) { sf_init(); inited = 1; } sf_expand_input((const char *) data, size, &in); html_len = StringLength(in); /* Exact-length, unterminated: the rewriter is span-based, so ASan bounds a read past html_len instead of it landing on a terminator. */ html = malloct(html_len != 0 ? html_len : 1); memcpy(html, StringBuff(in), html_len); StringFree(in); StringClear(out); (void) singlefile_rewrite_html(sf_opt, sf_root, sf_page, html, html_len, SINGLEFILE_MAX_PAGE_SIZE, &out); StringFree(out); freet(html); return 0; } httrack-3.49.21/fuzz/fuzz-meta.c0000644000175000017500000000270515237104167012111 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz hts_getCharsetFromMeta (htscharset.c): scans raw attacker HTML for a charset declaration. */ #include "fuzz.h" #include "htscharset.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *html = fuzz_strdup(data, size); char *charset = hts_getCharsetFromMeta(html, size); freet(charset); freet(html); return 0; } httrack-3.49.21/fuzz/fuzz-idna.c0000644000175000017500000000302315237104167012070 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the IDNA/punycode codec (htscharset.c, CVE-prone lineage). */ #include "fuzz.h" #include "htscharset.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *s = fuzz_strdup(data, size); { char *idna = hts_convertStringUTF8ToIDNA(s, size); freet(idna); } { char *utf8 = hts_convertStringIDNAToUTF8(s, size); freet(utf8); } (void) hts_isStringIDNA(s, size); freet(s); return 0; } httrack-3.49.21/fuzz/fuzz-htsparse.c0000644000175000017500000001206215237104167013011 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 2026 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Please visit our Website: http://www.httrack.com */ /* Fuzz the real htsparse() over a mocked engine: the minimal crawl state httpmirror() builds, then a page walked through the parser and discarded. The str/stre wiring below mirrors htsparse()'s call site in htscore.c; update it in lockstep if those structs gain a field the parser reads. */ #include "fuzz.h" #include "httrack-library.h" #include "htscore.h" #include "htsback.h" #include "htshash.h" #include "htsrobots.h" #include "htsparse.h" #include "htsmodules.h" #include "coucal.h" /* htsparse ignores str.addLink on the internal parse; stub it. */ static int fuzz_addlink(htsmoduleStruct *str, char *link) { (void) str; (void) link; return 0; } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { static int inited = 0; httrackp *opt; cache_back cache; hash_struct hash; robots_wizard robots; struct_back *sback; char **filters = NULL; int filptr = 0; htsblk r; htsmoduleStruct str; htsmoduleStructExtended stre; int ptr, error = 0, store_errpage = 0; int makeindex_done = 0, makeindex_links = 0; FILE *makeindex_fp = NULL; char makeindex_firstlink[HTS_URLMAXSIZE * 2] = ""; LLint stat_fragment = 0, makestat_total = 0; int makestat_lnk = 0; char base[HTS_URLMAXSIZE * 2] = ""; char codebase[HTS_URLMAXSIZE * 2] = ""; char err_msg[1024] = ""; if (!inited) { hts_init(); inited = 1; } opt = hts_create_opt(); opt->log = opt->errlog = NULL; opt->robots = 0; memset(&cache, 0, sizeof(cache)); cache.type = 0; /* no on-disk cache */ cache.hashtable = coucal_new(0); cache.cached_tests = coucal_new(0); coucal_value_is_malloc(cache.cached_tests, 1); memset(&robots, 0, sizeof(robots)); strcpybuff(robots.adr, "!"); opt->robotsptr = &robots; opt->maxfilter = maximum(opt->maxfilter, 128); filters_init(&filters, opt->maxfilter, 0); opt->filters.filters = &filters; opt->filters.filptr = &filptr; opt->hash = &hash; hts_record_init(opt); hash_init(opt, &hash, opt->urlhack); hash.liens = (const lien_url *const *const *) &opt->liens; sback = back_new(opt, opt->maxsoc * 32 + 1024); /* ptr=1 (index 1 is the parsed page) selects full HTML parsing + the rewriter; urladr()/urlfil()/savename() alias heap(ptr), save=/dev/null. */ hts_record_link(opt, "example.com", "/", "/dev/null", "", "", NULL); hts_record_link(opt, "example.com", "/index.html", "/dev/null", "", "", NULL); ptr = 1; /* NUL-terminated in a size+1 alloc: htsparse one-past-reads onto the NUL. */ hts_init_htsblk(&r); r.statuscode = 200; r.size = (LLint) size; r.adr = malloct(size + 1); if (size) memcpy(r.adr, data, size); r.adr[size] = '\0'; strcpybuff(r.contenttype, "text/html"); memset(&str, 0, sizeof(str)); memset(&stre, 0, sizeof(stre)); str.err_msg = err_msg; str.filename = heap(ptr)->sav; str.mime = r.contenttype; str.url_host = heap(ptr)->adr; str.url_file = heap(ptr)->fil; str.size = (int) r.size; str.addLink = fuzz_addlink; str.opt = opt; str.sback = sback; str.cache = &cache; str.hashptr = &hash; str.numero_passe = 0; str.ptr_ = &ptr; str.page_charset_ = NULL; stre.r_ = &r; stre.error_ = &error; stre.exit_xh_ = &opt->state.exit_xh; stre.store_errpage_ = &store_errpage; stre.base = base; stre.codebase = codebase; stre.filters_ = &filters; stre.filptr_ = &filptr; stre.robots_ = &robots; stre.hash_ = &hash; stre.makeindex_done_ = &makeindex_done; stre.makeindex_fp_ = &makeindex_fp; stre.makeindex_links_ = &makeindex_links; stre.makeindex_firstlink_ = makeindex_firstlink; stre.template_header_ = ""; stre.template_body_ = ""; stre.template_footer_ = ""; stre.stat_fragment_ = &stat_fragment; stre.makestat_time = 0; stre.makestat_fp = NULL; stre.makestat_total_ = &makestat_total; stre.makestat_lnk_ = &makestat_lnk; stre.maketrack_fp = NULL; (void) htsparse(&str, &stre); freet(r.adr); back_delete_all(opt, &cache, sback); back_free(&sback); hash_free(&hash); coucal_delete(&cache.hashtable); coucal_delete(&cache.cached_tests); checkrobots_free(&robots); if (filters != NULL) { if (filters[0] != NULL) freet(filters[0]); freet(filters); } hts_record_free(opt); hts_free_opt(opt); return 0; } httrack-3.49.21/fuzz/fuzz-header.c0000644000175000017500000000466415237104167012421 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 2026 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the HTTP response-header parser (htslib.c): treatfirstline on the status line, treathead on each following header. Both consume raw bytes off the wire and copy fields into fixed htsblk buffers; treathead also mutates its line in place and drives cookie parsing. */ #include "fuzz.h" #include "htslib.h" #include "htsbauth.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *buf = fuzz_strdup(data, size); htsblk r; t_cookie *cookie = calloct(1, sizeof(*cookie)); char *line = malloct(size + 1); char *p = buf; int first = 1; memset(&r, 0, sizeof(r)); cookie->max_len = (int) sizeof(cookie->data); r.location = malloct(HTS_URLMAXSIZE * 2); r.location[0] = '\0'; /* feed one header line at a time, as the receive loop does */ while (p != NULL && *p != '\0') { char *nl = strchr(p, '\n'); size_t n = (nl != NULL) ? (size_t) (nl - p) : strlen(p); size_t i, len = 0; /* binput drops every '\r' on the wire; mirror it */ for (i = 0; i < n; i++) if (p[i] != '\r') line[len++] = p[i]; line[len] = '\0'; if (first) { treatfirstline(&r, line); first = 0; } else { treathead(cookie, "www.example.com", "/", &r, line); } p = (nl != NULL) ? nl + 1 : NULL; } freet(r.location); freet(line); freet(cookie); freet(buf); return 0; } httrack-3.49.21/fuzz/fuzz-filters.c0000644000175000017500000000432515237104167012633 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the wildcard filter matcher (htsfilters.c; #148 bracket-range OOB was here). Input splits on the first NUL: pattern, then subject string. */ #include "fuzz.h" #include "htsfilters.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *buf = fuzz_strdup(data, size); const char *joker = buf; const uint8_t *sep = memchr(data, '\0', size); /* subject in its own allocation so ASan bounds it apart from the pattern */ char *nom = sep != NULL ? fuzz_strdup(sep + 1, (data + size) - (sep + 1)) : fuzz_strdup(data + size, 0); (void) strjoker(nom, joker, NULL, NULL); { LLint sz = (LLint) size; int size_flag = 0; (void) strjoker(nom, joker, &sz, &size_flag); } (void) strjokerfind(nom, joker); { char *filter = malloct(strlen(joker) + 2); char *filters[1]; LLint sz = (LLint) size; int size_flag = 0, depth = 0; filter[0] = '-'; memcpy(filter + 1, joker, strlen(joker) + 1); filters[0] = filter; (void) fa_strjoker(0, filters, 1, nom, &sz, &size_flag, &depth); freet(filter); } freet(nom); freet(buf); return 0; } httrack-3.49.21/fuzz/fuzz-entities.c0000644000175000017500000000340515237104167013005 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the HTML entity decoder (htsencoding.c). First input byte picks the destination size, so truncation bounds get exercised too. */ #include "fuzz.h" #include "htsencoding.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { static const size_t dsizes[] = {1, 2, 8, 64, 4096}; size_t dsize; char *src, *dest; if (size == 0) return 0; dsize = dsizes[data[0] % (sizeof(dsizes) / sizeof(dsizes[0]))]; data++, size--; src = fuzz_strdup(data, size); dest = malloct(dsize); (void) hts_unescapeEntities(src, dest, dsize); (void) hts_unescapeEntitiesWithCharset(src, dest, dsize, "iso-8859-1"); freet(dest); freet(src); return 0; } httrack-3.49.21/fuzz/fuzz-charset.c0000644000175000017500000000470715237104167012620 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the charset codecs: hts_convertStringToUTF8/FromUTF8 and the UTF-8/UCS4 primitives (htscharset.c). First input byte picks the charset. */ #include "fuzz.h" #include "htscharset.h" static const char *const charsets[] = { "utf-8", "iso-8859-1", "iso-8859-2", "iso-8859-15", "windows-1252", "us-ascii", "shift_jis", "euc-jp", "iso-2022-jp", "gb2312", "big5", "euc-kr", "koi8-r", "utf-16", "unknown-charset", }; int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { const char *charset; char *s; if (size == 0) return 0; charset = charsets[data[0] % (sizeof(charsets) / sizeof(charsets[0]))]; data++, size--; s = fuzz_strdup(data, size); { char *utf8 = hts_convertStringToUTF8(s, size, charset); freet(utf8); } { char *enc = hts_convertStringFromUTF8(s, size, charset); freet(enc); } { size_t nChars = 0; hts_UCS4 *ucs = hts_convertUTF8StringToUCS4(s, size, &nChars); if (ucs != NULL) { char *back = hts_convertUCS4StringToUTF8(ucs, nChars); freet(back); freet(ucs); } } { size_t i = 0; while (i < size) { hts_UCS4 uc = 0; const size_t nr = hts_readUTF8(s + i, size - i, &uc); char out[8]; if (nr == 0) break; hts_writeUTF8(uc, out, sizeof(out)); i += nr; } } freet(s); return 0; } httrack-3.49.21/fuzz/fuzz-cachendx.c0000644000175000017500000000436515237104167012744 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 2026 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz the cache-index (.ndx) parser: a corrupt or truncated index must not walk the length-prefixed cache_brstr/cache_binput scan past the buffer. Mirrors the -#C cache-listing scan (htscoremain.c). */ #include "fuzz.h" #include "htscache.h" #include "htslib.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *buf = fuzz_strdup(data, size); const char *const end = buf + size; char firstline[256]; char *a = buf; /* header: two length-prefixed fields (version, last-modified) */ a += cache_brstr(a, firstline, sizeof(firstline)); a += cache_brstr(a, firstline, sizeof(firstline)); /* body: newline-delimited host/file/position triples; the length-prefixed scan must stay inside the buffer */ while (a != NULL && a < end) { char BIGSTK line[HTS_URLMAXSIZE * 2]; char linepos[256]; int pos; a = strchr(a + 1, '\n'); if (a == NULL) break; a++; a += cache_binput(a, end, line, HTS_URLMAXSIZE); a += cache_binput(a, end, line + strlen(line), HTS_URLMAXSIZE); a += cache_binput(a, end, linepos, 200); sscanf(linepos, "%d", &pos); (void) pos; } freet(buf); return 0; } httrack-3.49.21/fuzz/fuzz.h0000644000175000017500000000313015237104167011163 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 1998 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Shared helpers for the libFuzzer harnesses. */ #ifndef FUZZ_H #define FUZZ_H #define HTS_INTERNAL_BYTECODE #include #include #include #include "htsbase.h" /* Heap NUL-terminated copy of the fuzzer input, so ASan bounds every read. */ HTS_UNUSED static char *fuzz_strdup(const uint8_t *data, size_t size) { char *s = malloct(size + 1); memcpy(s, data, size); s[size] = '\0'; return s; } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); #endif httrack-3.49.21/fuzz/fuzz-arc.c0000644000175000017500000000635315237104167011733 /* ------------------------------------------------------------ */ /* HTTrack Website Copier, Offline Browser for Windows and Unix Copyright (C) 2026 Xavier Roche and other contributors SPDX-License-Identifier: GPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Ethical use: we kindly ask that you NOT use this software to harvest email addresses or to collect any other private information about people. Doing so would dishonor our work and waste the many hours we have spent on it. Please visit our Website: http://www.httrack.com */ /* Fuzz proxytrack's .arc reader the way `--convert` drives it: the record loop seeks on lengths read from the file, and every entry reaches a writer. */ #include "fuzz.h" #include #include #include #include #include "coucal.h" #include "proxy/store.h" /* An .arc past this size says nothing a smaller one cannot. */ #define FUZZ_ARC_MAXSIZE (1024 * 1024) static char arc_dir[256]; static char arc_in[sizeof(arc_dir) + sizeof("/in.arc")]; static char arc_out[sizeof(arc_dir) + sizeof("/out.arc")]; static void fuzz_arc_cleanup(void) { (void) unlink(arc_in); (void) unlink(arc_out); (void) rmdir(arc_dir); } /* proxytrack's main() installs one; without it coucal logs stats per free */ static void fuzz_arc_coucal_log(coucal_opaque arg, coucal_loglevel level, const char *format, va_list args) { (void) arg; (void) level; (void) format; (void) args; } /* PT_GetType() picks the format from the extension, so the names end in .arc */ static int fuzz_arc_setup(void) { if (arc_in[0] == '\0') { const char *const tmp = getenv("TMPDIR"); coucal_set_global_assert_handler(fuzz_arc_coucal_log, NULL); snprintf(arc_dir, sizeof(arc_dir), "%s/fuzz-arc-XXXXXX", tmp != NULL && *tmp != '\0' ? tmp : "/tmp"); if (mkdtemp(arc_dir) == NULL) { return -1; } snprintf(arc_out, sizeof(arc_out), "%s/out.arc", arc_dir); snprintf(arc_in, sizeof(arc_in), "%s/in.arc", arc_dir); atexit(fuzz_arc_cleanup); } return 0; } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { PT_Indexes indexes; FILE *fp; hts_boolean written; if (size > FUZZ_ARC_MAXSIZE || fuzz_arc_setup() != 0) { return 0; } if ((fp = fopen(arc_in, "wb")) == NULL) { return 0; } written = fwrite(data, 1, size, fp) == size ? HTS_TRUE : HTS_FALSE; if (fclose(fp) != 0 || !written) { return 0; } indexes = PT_New(); if (indexes != NULL) { if (PT_AddIndex(indexes, arc_in) > 0) { /* the writer reads back every entry the loader indexed */ (void) PT_SaveCache(indexes, arc_out); } PT_Delete(indexes); } return 0; } httrack-3.49.21/fuzz/README.md0000644000175000017500000000210415237104167011273 # Fuzzing httrack libFuzzer harnesses for the pure hostile-input parsers (charset/UTF-8/IDNA codecs, entity and percent decoders, wildcard filters, URL splitter). Off by default; needs clang. ```sh ./bootstrap mkdir /var/tmp/bld-fuzz && cd /var/tmp/bld-fuzz CC=clang CFLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g -O1" \ LDFLAGS="-fsanitize=address,undefined" \ bash /path/to/httrack/configure --enable-fuzzers --disable-shared make bash /path/to/httrack/fuzz/run-fuzzers.sh fuzz 60 # 60s per target ``` Run one target by hand: `fuzz/fuzz-url -max_total_time=300 corpusdir fuzz/corpus/url`. Seed corpora live in `corpus//`; a crash reproducer is replayed with `fuzz/fuzz-url crash-file`. `fuzz-arc` is the odd one out: it drives proxytrack's `.arc` reader the way `--convert` does, through a temp file rather than a buffer, and it compiles `src/proxy/store.c` into the harness because proxytrack does not link libhttrack. Both readers and the writer print to stderr on malformed input, so pass `-close_fd_mask=2` for anything longer than a corpus replay. httrack-3.49.21/fuzz/Makefile.in0000644000175000017500000010635315237105266012075 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @FUZZERS_TRUE@noinst_PROGRAMS = fuzz-charset$(EXEEXT) \ @FUZZERS_TRUE@ fuzz-meta$(EXEEXT) fuzz-idna$(EXEEXT) \ @FUZZERS_TRUE@ fuzz-entities$(EXEEXT) fuzz-unescape$(EXEEXT) \ @FUZZERS_TRUE@ fuzz-filters$(EXEEXT) fuzz-url$(EXEEXT) \ @FUZZERS_TRUE@ fuzz-header$(EXEEXT) fuzz-cachendx$(EXEEXT) \ @FUZZERS_TRUE@ fuzz-htsparse$(EXEEXT) fuzz-singlefile$(EXEEXT) \ @FUZZERS_TRUE@ fuzz-sitemap$(EXEEXT) fuzz-arc$(EXEEXT) subdir = fuzz ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_add_fortify_source.m4 \ $(top_srcdir)/m4/check_codecs.m4 \ $(top_srcdir)/m4/check_zlib.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/snprintf.m4 $(top_srcdir)/m4/visibility.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_fuzz_arc_OBJECTS = fuzz_arc-fuzz-arc.$(OBJEXT) \ $(top_builddir)/src/proxy/fuzz_arc-store.$(OBJEXT) fuzz_arc_OBJECTS = $(am_fuzz_arc_OBJECTS) fuzz_arc_LDADD = $(LDADD) am__DEPENDENCIES_1 = fuzz_arc_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_fuzz_cachendx_OBJECTS = fuzz-cachendx.$(OBJEXT) fuzz_cachendx_OBJECTS = $(am_fuzz_cachendx_OBJECTS) fuzz_cachendx_LDADD = $(LDADD) fuzz_cachendx_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_charset_OBJECTS = fuzz-charset.$(OBJEXT) fuzz_charset_OBJECTS = $(am_fuzz_charset_OBJECTS) fuzz_charset_LDADD = $(LDADD) fuzz_charset_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_entities_OBJECTS = fuzz-entities.$(OBJEXT) fuzz_entities_OBJECTS = $(am_fuzz_entities_OBJECTS) fuzz_entities_LDADD = $(LDADD) fuzz_entities_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_filters_OBJECTS = fuzz-filters.$(OBJEXT) fuzz_filters_OBJECTS = $(am_fuzz_filters_OBJECTS) fuzz_filters_LDADD = $(LDADD) fuzz_filters_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_header_OBJECTS = fuzz-header.$(OBJEXT) fuzz_header_OBJECTS = $(am_fuzz_header_OBJECTS) fuzz_header_LDADD = $(LDADD) fuzz_header_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_htsparse_OBJECTS = fuzz-htsparse.$(OBJEXT) fuzz_htsparse_OBJECTS = $(am_fuzz_htsparse_OBJECTS) fuzz_htsparse_LDADD = $(LDADD) fuzz_htsparse_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_idna_OBJECTS = fuzz-idna.$(OBJEXT) fuzz_idna_OBJECTS = $(am_fuzz_idna_OBJECTS) fuzz_idna_LDADD = $(LDADD) fuzz_idna_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_meta_OBJECTS = fuzz-meta.$(OBJEXT) fuzz_meta_OBJECTS = $(am_fuzz_meta_OBJECTS) fuzz_meta_LDADD = $(LDADD) fuzz_meta_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_singlefile_OBJECTS = fuzz-singlefile.$(OBJEXT) fuzz_singlefile_OBJECTS = $(am_fuzz_singlefile_OBJECTS) fuzz_singlefile_LDADD = $(LDADD) fuzz_singlefile_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_sitemap_OBJECTS = fuzz-sitemap.$(OBJEXT) fuzz_sitemap_OBJECTS = $(am_fuzz_sitemap_OBJECTS) fuzz_sitemap_LDADD = $(LDADD) fuzz_sitemap_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_unescape_OBJECTS = fuzz-unescape.$(OBJEXT) fuzz_unescape_OBJECTS = $(am_fuzz_unescape_OBJECTS) fuzz_unescape_LDADD = $(LDADD) fuzz_unescape_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) am_fuzz_url_OBJECTS = fuzz-url.$(OBJEXT) fuzz_url_OBJECTS = $(am_fuzz_url_OBJECTS) fuzz_url_LDADD = $(LDADD) fuzz_url_DEPENDENCIES = $(top_builddir)/src/libhttrack.la \ $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = \ $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Po \ ./$(DEPDIR)/fuzz-cachendx.Po ./$(DEPDIR)/fuzz-charset.Po \ ./$(DEPDIR)/fuzz-entities.Po ./$(DEPDIR)/fuzz-filters.Po \ ./$(DEPDIR)/fuzz-header.Po ./$(DEPDIR)/fuzz-htsparse.Po \ ./$(DEPDIR)/fuzz-idna.Po ./$(DEPDIR)/fuzz-meta.Po \ ./$(DEPDIR)/fuzz-singlefile.Po ./$(DEPDIR)/fuzz-sitemap.Po \ ./$(DEPDIR)/fuzz-unescape.Po ./$(DEPDIR)/fuzz-url.Po \ ./$(DEPDIR)/fuzz_arc-fuzz-arc.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(fuzz_arc_SOURCES) $(fuzz_cachendx_SOURCES) \ $(fuzz_charset_SOURCES) $(fuzz_entities_SOURCES) \ $(fuzz_filters_SOURCES) $(fuzz_header_SOURCES) \ $(fuzz_htsparse_SOURCES) $(fuzz_idna_SOURCES) \ $(fuzz_meta_SOURCES) $(fuzz_singlefile_SOURCES) \ $(fuzz_sitemap_SOURCES) $(fuzz_unescape_SOURCES) \ $(fuzz_url_SOURCES) DIST_SOURCES = $(fuzz_arc_SOURCES) $(fuzz_cachendx_SOURCES) \ $(fuzz_charset_SOURCES) $(fuzz_entities_SOURCES) \ $(fuzz_filters_SOURCES) $(fuzz_header_SOURCES) \ $(fuzz_htsparse_SOURCES) $(fuzz_idna_SOURCES) \ $(fuzz_meta_SOURCES) $(fuzz_singlefile_SOURCES) \ $(fuzz_sitemap_SOURCES) $(fuzz_unescape_SOURCES) \ $(fuzz_url_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ README.md DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BASH_SHELL = @BASH_SHELL@ BROTLI_ENABLED = @BROTLI_ENABLED@ BROTLI_LIBS = @BROTLI_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CFLAGS_PIE = @CFLAGS_PIE@ CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_CFLAGS = @DEFAULT_CFLAGS@ DEFAULT_LDFLAGS = @DEFAULT_LDFLAGS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DL_LIBS = @DL_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ GREP = @GREP@ HAVE_VISIBILITY = @HAVE_VISIBILITY@ HTTPS_SUPPORT = @HTTPS_SUPPORT@ ICONV_LIBS = @ICONV_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LDFLAGS_PIE = @LDFLAGS_PIE@ LFS_FLAG = @LFS_FLAG@ LIBC_FORCE_LINK = @LIBC_FORCE_LINK@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_CV_OBJDIR = @LT_CV_OBJDIR@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ ONLINE_UNIT_TESTS = @ONLINE_UNIT_TESTS@ OPENSSL_LIBS = @OPENSSL_LIBS@ ORIGIN_RPATH = @ORIGIN_RPATH@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG_LIBS_PRIVATE = @PKGCONFIG_LIBS_PRIVATE@ PKGCONFIG_REQUIRES_PRIVATE = @PKGCONFIG_REQUIRES_PRIVATE@ PKGCONFIG_RPATH = @PKGCONFIG_RPATH@ PKGCONFIG_RPATH_LDFLAG = @PKGCONFIG_RPATH_LDFLAG@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ RPATH_ORIGIN_LDFLAGS = @RPATH_ORIGIN_LDFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SHLIBPATH_VAR = @SHLIBPATH_VAR@ SOCKET_LIBS = @SOCKET_LIBS@ STRIP = @STRIP@ TESTS_LIST = @TESTS_LIST@ THREADS_CFLAGS = @THREADS_CFLAGS@ THREADS_LIBS = @THREADS_LIBS@ V6_FLAG = @V6_FLAG@ V6_SUPPORT = @V6_SUPPORT@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ ZSTD_ENABLED = @ZSTD_ENABLED@ ZSTD_LIBS = @ZSTD_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = \ @DEFAULT_CFLAGS@ \ @THREADS_CFLAGS@ \ @V6_FLAG@ \ @LFS_FLAG@ \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/coucal # Static-link libhttrack.la: the internal symbols are hidden in the .so. AM_LDFLAGS = @DEFAULT_LDFLAGS@ -fsanitize=fuzzer -static-libtool-libs LDADD = $(top_builddir)/src/libhttrack.la $(THREADS_LIBS) fuzz_charset_SOURCES = fuzz-charset.c fuzz.h fuzz_meta_SOURCES = fuzz-meta.c fuzz.h fuzz_idna_SOURCES = fuzz-idna.c fuzz.h fuzz_entities_SOURCES = fuzz-entities.c fuzz.h fuzz_unescape_SOURCES = fuzz-unescape.c fuzz.h fuzz_filters_SOURCES = fuzz-filters.c fuzz.h fuzz_url_SOURCES = fuzz-url.c fuzz.h fuzz_header_SOURCES = fuzz-header.c fuzz.h fuzz_cachendx_SOURCES = fuzz-cachendx.c fuzz.h fuzz_htsparse_SOURCES = fuzz-htsparse.c fuzz.h fuzz_singlefile_SOURCES = fuzz-singlefile.c fuzz.h fuzz_sitemap_SOURCES = fuzz-sitemap.c fuzz.h # proxytrack does not link libhttrack, so its store compiles into the harness; # coucal, minizip and md5 still come from the static libhttrack above. fuzz_arc_SOURCES = fuzz-arc.c fuzz.h $(top_srcdir)/src/proxy/store.c fuzz_arc_CPPFLAGS = $(AM_CPPFLAGS) -DZLIB_CONST # List corpus files explicitly: automake does not expand EXTRA_DIST globs. EXTRA_DIST = README.md run-fuzzers.sh \ corpus/charset/utf8.txt corpus/charset/latin1.txt corpus/charset/sjis.txt \ corpus/meta/meta-charset.html corpus/meta/meta-http-equiv.html \ corpus/idna/idna.txt corpus/idna/unicode.txt \ corpus/idna/regress-multilabel-leak.txt \ corpus/entities/entities.txt \ corpus/unescape/percent.txt \ corpus/filters/filter.bin corpus/filters/filter-size.bin \ corpus/filters/regress-empty-subject-unique.bin \ corpus/filters/redos-star-classes.bin \ corpus/filters/regress-classdepth-timeout.bin \ corpus/url/http-url.txt corpus/url/relative-path.txt \ corpus/url/regress-file-empty-path.txt corpus/url/regress-long-path-abort.txt \ corpus/header/full-response.txt corpus/header/redirect.txt \ corpus/cachendx/new-format.txt corpus/cachendx/old-format.txt \ corpus/cachendx/regress-overadvance.bin \ corpus/cachendx/regress-truncated-entry.bin \ corpus/htsparse/basic.html corpus/htsparse/script-inscript.html \ corpus/htsparse/meta-usemap.html corpus/htsparse/malformed.html \ corpus/singlefile/img-src.html corpus/singlefile/link-rel.html \ corpus/singlefile/style-block.html corpus/singlefile/style-attr.html \ corpus/singlefile/srcset.html corpus/singlefile/rawtext.html \ corpus/singlefile/malformed.html \ corpus/singlefile/mark-at-eof.html corpus/singlefile/mark-only.html \ corpus/singlefile/mark-degenerate.html corpus/singlefile/traversal.html \ corpus/sitemap/urlset.xml corpus/sitemap/sitemapindex.xml \ corpus/sitemap/truncated.xml corpus/sitemap/urlset.xml.gz \ corpus/arc/roundtrip.arc corpus/arc/truncated.arc \ corpus/arc/regress-null-body.arc all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fuzz/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu fuzz/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstPROGRAMS: $(am__rm_f) $(noinst_PROGRAMS) test -z "$(EXEEXT)" || $(am__rm_f) $(noinst_PROGRAMS:$(EXEEXT)=) $(top_builddir)/src/proxy/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/src/proxy @: >>$(top_builddir)/src/proxy/$(am__dirstamp) $(top_builddir)/src/proxy/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/src/proxy/$(DEPDIR) @: >>$(top_builddir)/src/proxy/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/src/proxy/fuzz_arc-store.$(OBJEXT): \ $(top_builddir)/src/proxy/$(am__dirstamp) \ $(top_builddir)/src/proxy/$(DEPDIR)/$(am__dirstamp) fuzz-arc$(EXEEXT): $(fuzz_arc_OBJECTS) $(fuzz_arc_DEPENDENCIES) $(EXTRA_fuzz_arc_DEPENDENCIES) @rm -f fuzz-arc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_arc_OBJECTS) $(fuzz_arc_LDADD) $(LIBS) fuzz-cachendx$(EXEEXT): $(fuzz_cachendx_OBJECTS) $(fuzz_cachendx_DEPENDENCIES) $(EXTRA_fuzz_cachendx_DEPENDENCIES) @rm -f fuzz-cachendx$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_cachendx_OBJECTS) $(fuzz_cachendx_LDADD) $(LIBS) fuzz-charset$(EXEEXT): $(fuzz_charset_OBJECTS) $(fuzz_charset_DEPENDENCIES) $(EXTRA_fuzz_charset_DEPENDENCIES) @rm -f fuzz-charset$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_charset_OBJECTS) $(fuzz_charset_LDADD) $(LIBS) fuzz-entities$(EXEEXT): $(fuzz_entities_OBJECTS) $(fuzz_entities_DEPENDENCIES) $(EXTRA_fuzz_entities_DEPENDENCIES) @rm -f fuzz-entities$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_entities_OBJECTS) $(fuzz_entities_LDADD) $(LIBS) fuzz-filters$(EXEEXT): $(fuzz_filters_OBJECTS) $(fuzz_filters_DEPENDENCIES) $(EXTRA_fuzz_filters_DEPENDENCIES) @rm -f fuzz-filters$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_filters_OBJECTS) $(fuzz_filters_LDADD) $(LIBS) fuzz-header$(EXEEXT): $(fuzz_header_OBJECTS) $(fuzz_header_DEPENDENCIES) $(EXTRA_fuzz_header_DEPENDENCIES) @rm -f fuzz-header$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_header_OBJECTS) $(fuzz_header_LDADD) $(LIBS) fuzz-htsparse$(EXEEXT): $(fuzz_htsparse_OBJECTS) $(fuzz_htsparse_DEPENDENCIES) $(EXTRA_fuzz_htsparse_DEPENDENCIES) @rm -f fuzz-htsparse$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_htsparse_OBJECTS) $(fuzz_htsparse_LDADD) $(LIBS) fuzz-idna$(EXEEXT): $(fuzz_idna_OBJECTS) $(fuzz_idna_DEPENDENCIES) $(EXTRA_fuzz_idna_DEPENDENCIES) @rm -f fuzz-idna$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_idna_OBJECTS) $(fuzz_idna_LDADD) $(LIBS) fuzz-meta$(EXEEXT): $(fuzz_meta_OBJECTS) $(fuzz_meta_DEPENDENCIES) $(EXTRA_fuzz_meta_DEPENDENCIES) @rm -f fuzz-meta$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_meta_OBJECTS) $(fuzz_meta_LDADD) $(LIBS) fuzz-singlefile$(EXEEXT): $(fuzz_singlefile_OBJECTS) $(fuzz_singlefile_DEPENDENCIES) $(EXTRA_fuzz_singlefile_DEPENDENCIES) @rm -f fuzz-singlefile$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_singlefile_OBJECTS) $(fuzz_singlefile_LDADD) $(LIBS) fuzz-sitemap$(EXEEXT): $(fuzz_sitemap_OBJECTS) $(fuzz_sitemap_DEPENDENCIES) $(EXTRA_fuzz_sitemap_DEPENDENCIES) @rm -f fuzz-sitemap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_sitemap_OBJECTS) $(fuzz_sitemap_LDADD) $(LIBS) fuzz-unescape$(EXEEXT): $(fuzz_unescape_OBJECTS) $(fuzz_unescape_DEPENDENCIES) $(EXTRA_fuzz_unescape_DEPENDENCIES) @rm -f fuzz-unescape$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_unescape_OBJECTS) $(fuzz_unescape_LDADD) $(LIBS) fuzz-url$(EXEEXT): $(fuzz_url_OBJECTS) $(fuzz_url_DEPENDENCIES) $(EXTRA_fuzz_url_DEPENDENCIES) @rm -f fuzz-url$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fuzz_url_OBJECTS) $(fuzz_url_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/src/proxy/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-cachendx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-charset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-entities.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-filters.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-header.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-htsparse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-idna.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-meta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-singlefile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-sitemap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-unescape.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz-url.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz_arc-fuzz-arc.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< fuzz_arc-fuzz-arc.o: fuzz-arc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fuzz_arc-fuzz-arc.o -MD -MP -MF $(DEPDIR)/fuzz_arc-fuzz-arc.Tpo -c -o fuzz_arc-fuzz-arc.o `test -f 'fuzz-arc.c' || echo '$(srcdir)/'`fuzz-arc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fuzz_arc-fuzz-arc.Tpo $(DEPDIR)/fuzz_arc-fuzz-arc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fuzz-arc.c' object='fuzz_arc-fuzz-arc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fuzz_arc-fuzz-arc.o `test -f 'fuzz-arc.c' || echo '$(srcdir)/'`fuzz-arc.c fuzz_arc-fuzz-arc.obj: fuzz-arc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fuzz_arc-fuzz-arc.obj -MD -MP -MF $(DEPDIR)/fuzz_arc-fuzz-arc.Tpo -c -o fuzz_arc-fuzz-arc.obj `if test -f 'fuzz-arc.c'; then $(CYGPATH_W) 'fuzz-arc.c'; else $(CYGPATH_W) '$(srcdir)/fuzz-arc.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fuzz_arc-fuzz-arc.Tpo $(DEPDIR)/fuzz_arc-fuzz-arc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fuzz-arc.c' object='fuzz_arc-fuzz-arc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fuzz_arc-fuzz-arc.obj `if test -f 'fuzz-arc.c'; then $(CYGPATH_W) 'fuzz-arc.c'; else $(CYGPATH_W) '$(srcdir)/fuzz-arc.c'; fi` $(top_builddir)/src/proxy/fuzz_arc-store.o: $(top_builddir)/src/proxy/store.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT $(top_builddir)/src/proxy/fuzz_arc-store.o -MD -MP -MF $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Tpo -c -o $(top_builddir)/src/proxy/fuzz_arc-store.o `test -f '$(top_builddir)/src/proxy/store.c' || echo '$(srcdir)/'`$(top_builddir)/src/proxy/store.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Tpo $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_builddir)/src/proxy/store.c' object='$(top_builddir)/src/proxy/fuzz_arc-store.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o $(top_builddir)/src/proxy/fuzz_arc-store.o `test -f '$(top_builddir)/src/proxy/store.c' || echo '$(srcdir)/'`$(top_builddir)/src/proxy/store.c $(top_builddir)/src/proxy/fuzz_arc-store.obj: $(top_builddir)/src/proxy/store.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT $(top_builddir)/src/proxy/fuzz_arc-store.obj -MD -MP -MF $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Tpo -c -o $(top_builddir)/src/proxy/fuzz_arc-store.obj `if test -f '$(top_builddir)/src/proxy/store.c'; then $(CYGPATH_W) '$(top_builddir)/src/proxy/store.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/src/proxy/store.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Tpo $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_builddir)/src/proxy/store.c' object='$(top_builddir)/src/proxy/fuzz_arc-store.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fuzz_arc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o $(top_builddir)/src/proxy/fuzz_arc-store.obj `if test -f '$(top_builddir)/src/proxy/store.c'; then $(CYGPATH_W) '$(top_builddir)/src/proxy/store.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/src/proxy/store.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/src/proxy/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/src/proxy/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Po -rm -f ./$(DEPDIR)/fuzz-cachendx.Po -rm -f ./$(DEPDIR)/fuzz-charset.Po -rm -f ./$(DEPDIR)/fuzz-entities.Po -rm -f ./$(DEPDIR)/fuzz-filters.Po -rm -f ./$(DEPDIR)/fuzz-header.Po -rm -f ./$(DEPDIR)/fuzz-htsparse.Po -rm -f ./$(DEPDIR)/fuzz-idna.Po -rm -f ./$(DEPDIR)/fuzz-meta.Po -rm -f ./$(DEPDIR)/fuzz-singlefile.Po -rm -f ./$(DEPDIR)/fuzz-sitemap.Po -rm -f ./$(DEPDIR)/fuzz-unescape.Po -rm -f ./$(DEPDIR)/fuzz-url.Po -rm -f ./$(DEPDIR)/fuzz_arc-fuzz-arc.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/src/proxy/$(DEPDIR)/fuzz_arc-store.Po -rm -f ./$(DEPDIR)/fuzz-cachendx.Po -rm -f ./$(DEPDIR)/fuzz-charset.Po -rm -f ./$(DEPDIR)/fuzz-entities.Po -rm -f ./$(DEPDIR)/fuzz-filters.Po -rm -f ./$(DEPDIR)/fuzz-header.Po -rm -f ./$(DEPDIR)/fuzz-htsparse.Po -rm -f ./$(DEPDIR)/fuzz-idna.Po -rm -f ./$(DEPDIR)/fuzz-meta.Po -rm -f ./$(DEPDIR)/fuzz-singlefile.Po -rm -f ./$(DEPDIR)/fuzz-sitemap.Po -rm -f ./$(DEPDIR)/fuzz-unescape.Po -rm -f ./$(DEPDIR)/fuzz-url.Po -rm -f ./$(DEPDIR)/fuzz_arc-fuzz-arc.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% httrack-3.49.21/fuzz/Makefile.am0000644000175000017500000000604515237104167012060 # libFuzzer harnesses; built only with --enable-fuzzers (requires clang). if FUZZERS noinst_PROGRAMS = fuzz-charset fuzz-meta fuzz-idna fuzz-entities \ fuzz-unescape fuzz-filters fuzz-url fuzz-header fuzz-cachendx \ fuzz-htsparse fuzz-singlefile fuzz-sitemap fuzz-arc endif AM_CPPFLAGS = \ @DEFAULT_CFLAGS@ \ @THREADS_CFLAGS@ \ @V6_FLAG@ \ @LFS_FLAG@ \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/coucal # Static-link libhttrack.la: the internal symbols are hidden in the .so. AM_LDFLAGS = @DEFAULT_LDFLAGS@ -fsanitize=fuzzer -static-libtool-libs LDADD = $(top_builddir)/src/libhttrack.la $(THREADS_LIBS) fuzz_charset_SOURCES = fuzz-charset.c fuzz.h fuzz_meta_SOURCES = fuzz-meta.c fuzz.h fuzz_idna_SOURCES = fuzz-idna.c fuzz.h fuzz_entities_SOURCES = fuzz-entities.c fuzz.h fuzz_unescape_SOURCES = fuzz-unescape.c fuzz.h fuzz_filters_SOURCES = fuzz-filters.c fuzz.h fuzz_url_SOURCES = fuzz-url.c fuzz.h fuzz_header_SOURCES = fuzz-header.c fuzz.h fuzz_cachendx_SOURCES = fuzz-cachendx.c fuzz.h fuzz_htsparse_SOURCES = fuzz-htsparse.c fuzz.h fuzz_singlefile_SOURCES = fuzz-singlefile.c fuzz.h fuzz_sitemap_SOURCES = fuzz-sitemap.c fuzz.h # proxytrack does not link libhttrack, so its store compiles into the harness; # coucal, minizip and md5 still come from the static libhttrack above. fuzz_arc_SOURCES = fuzz-arc.c fuzz.h $(top_srcdir)/src/proxy/store.c fuzz_arc_CPPFLAGS = $(AM_CPPFLAGS) -DZLIB_CONST # List corpus files explicitly: automake does not expand EXTRA_DIST globs. EXTRA_DIST = README.md run-fuzzers.sh \ corpus/charset/utf8.txt corpus/charset/latin1.txt corpus/charset/sjis.txt \ corpus/meta/meta-charset.html corpus/meta/meta-http-equiv.html \ corpus/idna/idna.txt corpus/idna/unicode.txt \ corpus/idna/regress-multilabel-leak.txt \ corpus/entities/entities.txt \ corpus/unescape/percent.txt \ corpus/filters/filter.bin corpus/filters/filter-size.bin \ corpus/filters/regress-empty-subject-unique.bin \ corpus/filters/redos-star-classes.bin \ corpus/filters/regress-classdepth-timeout.bin \ corpus/url/http-url.txt corpus/url/relative-path.txt \ corpus/url/regress-file-empty-path.txt corpus/url/regress-long-path-abort.txt \ corpus/header/full-response.txt corpus/header/redirect.txt \ corpus/cachendx/new-format.txt corpus/cachendx/old-format.txt \ corpus/cachendx/regress-overadvance.bin \ corpus/cachendx/regress-truncated-entry.bin \ corpus/htsparse/basic.html corpus/htsparse/script-inscript.html \ corpus/htsparse/meta-usemap.html corpus/htsparse/malformed.html \ corpus/singlefile/img-src.html corpus/singlefile/link-rel.html \ corpus/singlefile/style-block.html corpus/singlefile/style-attr.html \ corpus/singlefile/srcset.html corpus/singlefile/rawtext.html \ corpus/singlefile/malformed.html \ corpus/singlefile/mark-at-eof.html corpus/singlefile/mark-only.html \ corpus/singlefile/mark-degenerate.html corpus/singlefile/traversal.html \ corpus/sitemap/urlset.xml corpus/sitemap/sitemapindex.xml \ corpus/sitemap/truncated.xml corpus/sitemap/urlset.xml.gz \ corpus/arc/roundtrip.arc corpus/arc/truncated.arc \ corpus/arc/regress-null-body.arc httrack-3.49.21/fuzz/corpus/0000755000175000017500000000000015237105307011407 5httrack-3.49.21/fuzz/corpus/url/0000755000175000017500000000000015237105307012211 5httrack-3.49.21/fuzz/corpus/url/regress-long-path-abort.txt0000644000175000017500000000563315237104167017352 ftpumŠ[/../e0O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/.../e0O/../itpumÙŠ[/../O/../f9O_iW/.¿ù../O/../9O_imÙŠW/../_/../../e0O/../f9O_./f9O_iW/../O/../90O/./e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW/../O/../../e0O/../f9O_imÙŠW/../O/.._iW/../O/../9O_imÙŠW/../O/../../e0O/../f9O_i/../O/../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e0O/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW//O/../f9O_i../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/.../e0O/../itpumÙŠ[/../O/../f9O_iW/.¿ù../O/../9O_imÙŠW/../_/../../e0O/../f9O_./f9O_iW/../O/../90O/./e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW/../O/../../e0O/../f9O_imÙŠW/../O/.._iW/../O/../9O_imÙŠW/../O/../../e0O/../f9O_i/../O/../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e0O/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW//O/../f9O_iW/.¿ù../O/../9O_imÙŠW/../_/../../e0O/../f9O_./f9O_iW/../O/../90O/./e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW/../O/../../e0O/../f9O_imÙŠW/../O/.._f9O_i../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/.../e0O/../itpumÙŠ[/../O/../f9O_iW/.¿ù../O/../9O_imÙŠW/../_/../../e0O/../f9O_./f9O_iW/../O/../90O/./e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW/../O/../../e0O/../f9O_imÙŠW/../O/.._iW/../O/../9O_imÙŠW/../O/../../e0O/../f9O_i/../O/../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e0O/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW//O/../f9O_iW/.¿ù../O/../9O_imÙŠW/../_/../../e0O/../f9O_./f9O_iW/../O/../90O/./e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW/../O/../../e0O/../f9O_imÙŠW/../O/.._iW/../O/../9O_imÙŠW/../O/../../e0O/../f9O_i/../O/../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/iW/../O/../9O_imÙŠW/../O/../../e0O/../f9O_i/../O/../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e0O/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imW/.¿ù../O/../9O_imÙŠW/../_/../../e0O/../f9O_./f9O_iW/../O/../90O/./e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW/../O/../../e0O/../f9O_imÙŠW/../O/.._iW/../O/../9O_imÙŠW/../O/../../e0O/../f9O_i/../O/../f9O_iW/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙŠ[/../O/../f9O_iW/../O/../9O_imÙŠW/../O/../../e0O/../f9OmÙŠW/../O/../9O_imÙŠW/../O/..O_imÙŠW/../O/../../e0O/9O_imÙŠW/../O/../httrack-3.49.21/fuzz/corpus/url/regress-file-empty-path.txt0000644000175000017500000000000715237104167017347 file://httrack-3.49.21/fuzz/corpus/url/relative-path.txt0000644000175000017500000000004515237104167015441 ftp://ftp.example.com/pub/../file.txthttrack-3.49.21/fuzz/corpus/url/http-url.txt0000644000175000017500000000010015237104167014443 http://user:pass@www.example.com:8080/a/b/../c/./d.html?q=1#fraghttrack-3.49.21/fuzz/corpus/unescape/0000755000175000017500000000000015237105307013212 5httrack-3.49.21/fuzz/corpus/unescape/percent.txt0000644000175000017500000000003315237104167015332 %41%zz%%20%c3%a9+%2e%2e%2fhttrack-3.49.21/fuzz/corpus/sitemap/0000755000175000017500000000000015237105307013051 5httrack-3.49.21/fuzz/corpus/sitemap/urlset.xml.gz0000644000175000017500000000010515237104167015447 ‹Afjÿ³)-Ê)N-±³Òv69ùÉv%%Vúúz%©Å%úéUz%¹96ú )}°*}¨E)@<httrack-3.49.21/fuzz/corpus/sitemap/truncated.xml0000644000175000017500000000003515237104167015505 http://h.test/xhttrack-3.49.21/fuzz/corpus/sitemap/sitemapindex.xml0000644000175000017500000000012415237104167016205 http://h.test/s2.xml.gz httrack-3.49.21/fuzz/corpus/sitemap/urlset.xml0000644000175000017500000000020415237104167015030 http://h.test/a.htmlhttps://h.test/b?x=1&y=2 httrack-3.49.21/fuzz/corpus/singlefile/0000755000175000017500000000000015237105307013530 5httrack-3.49.21/fuzz/corpus/singlefile/traversal.html0000644000175000017500000000016315237104167016344 httrack-3.49.21/fuzz/corpus/singlefile/mark-degenerate.html0000644000175000017500000000005315237104167017372  == "" a.png#!htsinlin #!htsinlinhttrack-3.49.21/fuzz/corpus/singlefile/mark-only.html0000644000175000017500000000000215237104167016242 httrack-3.49.21/fuzz/corpus/singlefile/mark-at-eof.html0000644000175000017500000000000715237104167016441 a.pnghttrack-3.49.21/fuzz/corpus/singlefile/malformed.html0000644000175000017500000000017415237104167016311

x

httrack-3.49.21/fuzz/corpus/singlefile/rawtext.html0000644000175000017500000000013615237104167016037 httrack-3.49.21/fuzz/corpus/singlefile/srcset.html0000644000175000017500000000006615237104167015646 httrack-3.49.21/fuzz/corpus/singlefile/style-attr.html0000644000175000017500000000013215237104167016445
httrack-3.49.21/fuzz/corpus/singlefile/style-block.html0000644000175000017500000000013215237104167016565 httrack-3.49.21/fuzz/corpus/singlefile/link-rel.html0000644000175000017500000000016315237104167016056 httrack-3.49.21/fuzz/corpus/singlefile/img-src.html0000644000175000017500000000017515237104167015705 over-cap httrack-3.49.21/fuzz/corpus/meta/0000755000175000017500000000000015237105307012335 5httrack-3.49.21/fuzz/corpus/meta/meta-http-equiv.html0000644000175000017500000000011015237104167016170 httrack-3.49.21/fuzz/corpus/meta/meta-charset.html0000644000175000017500000000007615237104167015526 xhttrack-3.49.21/fuzz/corpus/idna/0000755000175000017500000000000015237105307012322 5httrack-3.49.21/fuzz/corpus/idna/regress-multilabel-leak.txt0000644000175000017500000000002615237104167017520 büchev.例å­bücheplehttrack-3.49.21/fuzz/corpus/idna/unicode.txt0000644000175000017500000000002615237104167014432 bücher.例å­.examplehttrack-3.49.21/fuzz/corpus/idna/idna.txt0000644000175000017500000000003115237104167013713 xn--bcher-kva.example.comhttrack-3.49.21/fuzz/corpus/htsparse/0000755000175000017500000000000015237105307013240 5httrack-3.49.21/fuzz/corpus/htsparse/malformed.html0000644000175000017500000000031615237104167016017 bare wsp x
z
httrack-3.49.21/fuzz/corpus/htsparse/basic.html0000644000175000017500000000075015237104167015134 Seed

Hi

next abs
httrack-3.49.21/fuzz/corpus/header/0000755000175000017500000000000015237105307012637 5httrack-3.49.21/fuzz/corpus/header/redirect.txt0000644000175000017500000000013215237104167015120 HTTP/1.0 301 Moved Location: /elsewhere Content-Disposition: attachment; filename="a.pdf" httrack-3.49.21/fuzz/corpus/header/full-response.txt0000644000175000017500000000044315237104167016122 HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Content-Length: 1234 Content-Encoding: gzip Last-Modified: Mon, 01 Jan 2024 00:00:00 GMT Etag: "abc" Location: http://example.com/x Set-Cookie: ID=42; path=/; domain=.example.com Content-Range: bytes 0-99/100 Transfer-Encoding: chunked httrack-3.49.21/fuzz/corpus/filters/0000755000175000017500000000000015237105307013057 5httrack-3.49.21/fuzz/corpus/filters/regress-classdepth-timeout.bin0000644000175000017500000000771215237104167020771 *[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahttrack-3.49.21/fuzz/corpus/filters/redos-star-classes.bin0000644000175000017500000000037215237104167017214 *[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]*[a]baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahttrack-3.49.21/fuzz/corpus/filters/regress-empty-subject-unique.bin0000644000175000017500000000000615237104167021237 **((httrack-3.49.21/fuzz/corpus/filters/filter-size.bin0000644000175000017500000000006215237104167015727 -*[A-Z,a-z]*[>10,<50].zipwww.example.com/File.ziphttrack-3.49.21/fuzz/corpus/filters/filter.bin0000644000175000017500000000005215237104167014756 +*.gif*[<100]http://example.com/image.gifhttrack-3.49.21/fuzz/corpus/entities/0000755000175000017500000000000015237105307013233 5httrack-3.49.21/fuzz/corpus/entities/entities.txt0000644000175000017500000000007715237104167015547 &<>A☃é¬arealentity;�httrack-3.49.21/fuzz/corpus/charset/0000755000175000017500000000000015237105307013040 5httrack-3.49.21/fuzz/corpus/charset/sjis.txt0000644000175000017500000000001515237104167014470 ƒRƒ“ƒsƒ…[ƒ^httrack-3.49.21/fuzz/corpus/charset/latin1.txt0000644000175000017500000000001515237104167014710 café naïve ¤httrack-3.49.21/fuzz/corpus/charset/utf8.txt0000644000175000017500000000002615237104167014410 café € 🎠naïvehttrack-3.49.21/fuzz/corpus/cachendx/0000755000175000017500000000000015237105307013164 5httrack-3.49.21/fuzz/corpus/cachendx/regress-truncated-entry.bin0000644000175000017500000000003715237104167020401 8 CACHE-1.1 1 x www.example.comhttrack-3.49.21/fuzz/corpus/cachendx/regress-overadvance.bin0000644000175000017500000000001715237104167017544 32768 CACHE-1.1httrack-3.49.21/fuzz/corpus/cachendx/old-format.txt0000644000175000017500000000003615237104167015713 3 1.0 www.example.com /page 5 httrack-3.49.21/fuzz/corpus/cachendx/new-format.txt0000644000175000017500000000011515237104167015724 8 CACHE-1.1 28 Mon, 01 Jan 2024 00:00:00 GMT www.example.com /index.html 123 httrack-3.49.21/fuzz/corpus/arc/0000755000175000017500000000000015237105307012154 5httrack-3.49.21/fuzz/corpus/arc/regress-null-body.arc0000644000175000017500000000034015237104167016140 filedesc://t.arc 0.0.0.0 20250101000000 text/plain 200 - - 0 t.arc 9 2 0 test http://example.com/p.html 0.0.0.0 20250101000000 text/html -1 - - 0 t.arc 77 HTTP/1.1 -1 Broken Content-Type: text/html Content-Length: 10 httrack-3.49.21/fuzz/corpus/arc/truncated.arc0000644000175000017500000000032415237104167014556 filedesc://t.arc 0.0.0.0 20250101000000 text/plain 200 - - 0 t.arc 9 2 0 test http://example.com/q.html 0.0.0.0 20250101000000 text/html 200 - - 0 t.arc 2000000000 HTTP/1.1 200 OK Content-Type: text/html HIhttrack-3.49.21/fuzz/corpus/arc/roundtrip.arc0000644000175000017500000000042715237104167014617 filedesc://t.arc 0.0.0.0 20250101000000 text/plain 200 - - 0 t.arc 9 2 0 test http://example.com/p.html 0.0.0.0 20250101000000 text/html 200 - - 0 t.arc 120 HTTP/1.1 200 OK Content-Type: text/html Last-Modified: Wed, 01 Jan 2025 00:00:00 GMT Content-Length: 10 BODYMARKERhttrack-3.49.21/test-driver0000755000175000017500000001213715237105266011224 #! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2024-06-19.01; # UTC # Copyright (C) 2011-2024 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <. GNU Automake home page: . General help using GNU software: . END } test_name= # Used for reporting. log_file= # Where to save the output of the test script. trs_file= # Where to save the metadata of the test run. expect_failure=no color_tests=no collect_skipped_logs=yes enable_hard_errors=yes while test $# -gt 0; do case $1 in --help) print_usage; exit $?;; --version) echo "test-driver (GNU Automake) $scriptversion"; exit $?;; --test-name) test_name=$2; shift;; --log-file) log_file=$2; shift;; --trs-file) trs_file=$2; shift;; --color-tests) color_tests=$2; shift;; --collect-skipped-logs) collect_skipped_logs=$2; shift;; --expect-failure) expect_failure=$2; shift;; --enable-hard-errors) enable_hard_errors=$2; shift;; --) shift; break;; -*) usage_error "invalid option: '$1'";; *) break;; esac shift done missing_opts= test x"$test_name" = x && missing_opts="$missing_opts --test-name" test x"$log_file" = x && missing_opts="$missing_opts --log-file" test x"$trs_file" = x && missing_opts="$missing_opts --trs-file" if test x"$missing_opts" != x; then usage_error "the following mandatory options are missing:$missing_opts" fi if test $# -eq 0; then usage_error "missing argument" fi if test $color_tests = yes; then # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'. red='' # Red. grn='' # Green. lgn='' # Light green. blu='' # Blue. mgn='' # Magenta. std='' # No color. else red= grn= lgn= blu= mgn= std= fi do_exit='rm -f $log_file $trs_file; (exit $st); exit $st' trap "st=129; $do_exit" 1 trap "st=130; $do_exit" 2 trap "st=141; $do_exit" 13 trap "st=143; $do_exit" 15 # Test script is run here. We create the file first, then append to it, # to ameliorate tests themselves also writing to the log file. Our tests # don't, but others can (automake bug#35762). : >"$log_file" "$@" >>"$log_file" 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then tweaked_estatus=1 else tweaked_estatus=$estatus fi case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=$collect_skipped_logs;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report the test outcome and exit status in the logs, so that one can # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). echo "$res $test_name (exit status: $estatus)" >>"$log_file" # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: httrack-3.49.21/tests/0000755000175000017500000000000015237105307010240 5httrack-3.49.21/tests/install-manifest.txt0000644000175000017500000001115315237104167014177 @BINDIR@/htsserver @BINDIR@/httrack @BINDIR@/proxytrack @BINDIR@/webhttrack @DATADIR@/applications/WebHTTrack-Websites.desktop @DATADIR@/applications/WebHTTrack.desktop @DATADIR@/httrack/html @DATADIR@/httrack/lang.def @DATADIR@/httrack/lang.indexes @DATADIR@/httrack/lang/Bulgarian.txt @DATADIR@/httrack/lang/Castellano.txt @DATADIR@/httrack/lang/Cesky.txt @DATADIR@/httrack/lang/Chinese-BIG5.txt @DATADIR@/httrack/lang/Chinese-Simplified.txt @DATADIR@/httrack/lang/Croatian.txt @DATADIR@/httrack/lang/Dansk.txt @DATADIR@/httrack/lang/Deutsch.txt @DATADIR@/httrack/lang/Eesti.txt @DATADIR@/httrack/lang/English.txt @DATADIR@/httrack/lang/Finnish.txt @DATADIR@/httrack/lang/Francais.txt @DATADIR@/httrack/lang/Greek.txt @DATADIR@/httrack/lang/Italiano.txt @DATADIR@/httrack/lang/Japanese.txt @DATADIR@/httrack/lang/Macedonian.txt @DATADIR@/httrack/lang/Magyar.txt @DATADIR@/httrack/lang/Nederlands.txt @DATADIR@/httrack/lang/Norsk.txt @DATADIR@/httrack/lang/Polski.txt @DATADIR@/httrack/lang/Portugues-Brasil.txt @DATADIR@/httrack/lang/Portugues.txt @DATADIR@/httrack/lang/Romanian.txt @DATADIR@/httrack/lang/Russian.txt @DATADIR@/httrack/lang/Slovak.txt @DATADIR@/httrack/lang/Slovenian.txt @DATADIR@/httrack/lang/Svenska.txt @DATADIR@/httrack/lang/Turkish.txt @DATADIR@/httrack/lang/Ukrainian.txt @DATADIR@/httrack/lang/Uzbek.txt @DATADIR@/httrack/libtest/callbacks-example-baselinks.c @DATADIR@/httrack/libtest/callbacks-example-changecontent.c @DATADIR@/httrack/libtest/callbacks-example-contentfilter.c @DATADIR@/httrack/libtest/callbacks-example-displayheader.c @DATADIR@/httrack/libtest/callbacks-example-filename.c @DATADIR@/httrack/libtest/callbacks-example-filename2.c @DATADIR@/httrack/libtest/callbacks-example-filenameiisbug.c @DATADIR@/httrack/libtest/callbacks-example-listlinks.c @DATADIR@/httrack/libtest/callbacks-example-log.c @DATADIR@/httrack/libtest/callbacks-example-simple.c @DATADIR@/httrack/libtest/example-main.c @DATADIR@/httrack/libtest/example-main.h @DATADIR@/httrack/libtest/readme.txt @DATADIR@/httrack/templates/index-body.html @DATADIR@/httrack/templates/index-footer.html @DATADIR@/httrack/templates/index-header.html @DATADIR@/httrack/templates/topindex-body.html @DATADIR@/httrack/templates/topindex-bodycat.html @DATADIR@/httrack/templates/topindex-footer.html @DATADIR@/httrack/templates/topindex-header.html @DATADIR@/icons/hicolor/128x128/apps/httrack.png @DATADIR@/icons/hicolor/16x16/apps/httrack.png @DATADIR@/icons/hicolor/256x256/apps/httrack.png @DATADIR@/icons/hicolor/32x32/apps/httrack.png @DATADIR@/icons/hicolor/48x48/apps/httrack.png @DATADIR@/icons/hicolor/64x64/apps/httrack.png @DATADIR@/icons/hicolor/scalable/apps/httrack.svg @DATADIR@/metainfo/com.httrack.WebHTTrack.metainfo.xml @DATADIR@/pixmaps/httrack.xpm @DATADIR@/pixmaps/httrack16x16.xpm @DATADIR@/pixmaps/httrack32x32.xpm @DATADIR@/pixmaps/httrack48x48.xpm @INCLUDEDIR@/httrack/config.h @INCLUDEDIR@/httrack/htsarrays.h @INCLUDEDIR@/httrack/htsbasenet.h @INCLUDEDIR@/httrack/htsbauth.h @INCLUDEDIR@/httrack/htsconfig.h @INCLUDEDIR@/httrack/htsdefines.h @INCLUDEDIR@/httrack/htsglobal.h @INCLUDEDIR@/httrack/htsmodules.h @INCLUDEDIR@/httrack/htsnet.h @INCLUDEDIR@/httrack/htsopt.h @INCLUDEDIR@/httrack/htssafe.h @INCLUDEDIR@/httrack/htsstrings.h @INCLUDEDIR@/httrack/htswrap.h @INCLUDEDIR@/httrack/httrack-library.h @LIBDIR@/httrack/libbaselinks.so @LIBDIR@/httrack/libbaselinks.so.1 @LIBDIR@/httrack/libbaselinks.so.1.@revision@ @LIBDIR@/httrack/libchangecontent.so @LIBDIR@/httrack/libchangecontent.so.1 @LIBDIR@/httrack/libchangecontent.so.1.@revision@ @LIBDIR@/httrack/libcontentfilter.so @LIBDIR@/httrack/libcontentfilter.so.1 @LIBDIR@/httrack/libcontentfilter.so.1.@revision@ @LIBDIR@/httrack/libdisplayheader.so @LIBDIR@/httrack/libdisplayheader.so.1 @LIBDIR@/httrack/libdisplayheader.so.1.@revision@ @LIBDIR@/httrack/libfilename.so @LIBDIR@/httrack/libfilename.so.1 @LIBDIR@/httrack/libfilename.so.1.@revision@ @LIBDIR@/httrack/libfilename2.so @LIBDIR@/httrack/libfilename2.so.1 @LIBDIR@/httrack/libfilename2.so.1.@revision@ @LIBDIR@/httrack/libfilenameiisbug.so @LIBDIR@/httrack/libfilenameiisbug.so.1 @LIBDIR@/httrack/libfilenameiisbug.so.1.@revision@ @LIBDIR@/httrack/liblistlinks.so @LIBDIR@/httrack/liblistlinks.so.1 @LIBDIR@/httrack/liblistlinks.so.1.@revision@ @LIBDIR@/httrack/liblog.so @LIBDIR@/httrack/liblog.so.1 @LIBDIR@/httrack/liblog.so.1.@revision@ @LIBDIR@/httrack/libsimple.so @LIBDIR@/httrack/libsimple.so.1 @LIBDIR@/httrack/libsimple.so.1.@revision@ @LIBDIR@/libhttrack.so @LIBDIR@/libhttrack.so.3 @LIBDIR@/libhttrack.so.3.@revision@ @LIBDIR@/pkgconfig/libhttrack.pc @MANDIR@/man1/htsserver.1 @MANDIR@/man1/httrack.1 @MANDIR@/man1/proxytrack.1 @MANDIR@/man1/webhttrack.1 httrack-3.49.21/tests/server.key0000644000175000017500000000325015237104167012203 -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDx78mogNhTnoWw Ra51NeGtapQ1PfTYLlIMUzuloFXOsR1/ozRkFucqHNftF22wf0gg4VQJSBSf3rwj 79vsnt3nyaD03bTAafpHXkd+IJxQowiG8TfOJF0R/Qg9g7DCE66R9agQpMJCSGxI in9p/4ld4Hn6869d4hNq4fHxNf/qkj2cnf8DYxrldz2FGsi6yMed4tzz2Am4ZbPg wep+fy843ZdYrVIms9vJluNa9E+6Vpw9FwdjzQ/IBBMLvGaC2pDkc95YelaEnQrA lTO/0l5vjc8XuTQFlo3DbUg+WEld/pxvCqsd/q1mqjL0WbxtXl2zCwGzAoJxrjVE PfA8QSbtAgMBAAECggEACgNK4klq1T3IpKdNoBY5yoE7CbUQZBNkBpSPRxHgBezj SVFfgrZGnOySrIJSt4JHtuynG2Hl+0ku74HRep/ck+eOsh5W3mZvGvMLnGxhwR3u Or99osTIgU0VQTkpC0SLQ16FCnih0uJycNIikdLR7uuya1tt1OyIBzK7XlNGIywT p85zJc7/6TfTC9eM7lqh7JGR7KplBxSvgZL1pUr7y4rNpKms6uzOvPND79CcKnbU BBA9Tu4qdOkoOljsZKkvh3pihxyG9X6d8QTZ/uX3pkvliwSFBc+Sz9EootA3/4r5 gVWpQ2t/AY7fY4hqzLIX/HivVaPj3cWk1G+SHm0XNQKBgQD5I9rijqFvV/p6FmUl FbnjJFFHHgZLivlGxAC5vOyJNQQaqdeDzg7yMotNmQTggVGjT6sjdosQb3n+ctuk EhQnZSU5VkNKv1+PTR35WrRkaECCaqz3Pv79pV9GVcX3it7UuYjNiOeSPqINWe+X 49JwnJFz+qQ1BchAwOis4zkENwKBgQD4mShDaYLOO97VpgZj4cGxHHWyEK9CRQvp I7HxRmfaWS3JHwb88lOmALEU6pAj5cYJPAznv8BnUWcVHalZbkQ1JWYtUJRqj6OI Ym7rw/nm4Ay5ijbdEism173dSk3IjOe+PdAlxzsOuVzYdBTqElmeQWtBzhY9aHvX r+A02C2j+wKBgHHDo6Gsi57yR5gUPd9vSlCkNtEIrss0DJv5yHMIB+KnaNZcE+NF 5qFF30Jxyz5RDtxJ9tXcvaeln8lG3XDQKI/MqfDCqTuqo5ImHrfMaW8oA70JxS2p gHqGVzkg1aMxsIrmpcdk6olnPExocvWivGdbtzeEjhMALu8Sp6y6nUCFAoGBAK5h KLgYw/OMVaQCIMthaa+l6f0s7PMMYe1453H6VBD6qz4/8HPwO7LfG1gzrUYxADgs ElVh0UHn/On383nS+i9Ze5Hfyyvwc+LQQURKJPrJQMPJavCptPE7NmiKnYNHK6vr yh0l4oxShAklbCJBGvICq4zuVfVfXDeQnDIVTfaPAoGBAMCrZqYdOUhUu+aUqxZq qO/TTQxrxftU63jGUg+o042TdgI4KWLn07wvHJ8/E2OqF35eXenvcuKbNLI1l72J 4cp+3cUv8iAXThTRYEztr5CS/wta4o4CNN8zfjn5dV9AI4Hmt4V7EaGWpBcViGbj n0Mhag+dO8DHuenqi1yfMrAt -----END PRIVATE KEY----- httrack-3.49.21/tests/server.crt0000644000175000017500000000234515237104167012207 -----BEGIN CERTIFICATE----- MIIDbzCCAlegAwIBAgIUdWkDDomnY3WW95UqJ+UOASuR/i0wDQYJKoZIhvcNAQEL BQAwODESMBAGA1UEAwwJMTI3LjAuMC4xMSIwIAYDVQQKDBlIVFRyYWNrIGxvY2Fs IHRlc3Qgc2VydmVyMCAXDTI2MDYxNTE0NDQxMFoYDzIwNTYwNjA3MTQ0NDEwWjA4 MRIwEAYDVQQDDAkxMjcuMC4wLjExIjAgBgNVBAoMGUhUVHJhY2sgbG9jYWwgdGVz dCBzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDx78mogNhT noWwRa51NeGtapQ1PfTYLlIMUzuloFXOsR1/ozRkFucqHNftF22wf0gg4VQJSBSf 3rwj79vsnt3nyaD03bTAafpHXkd+IJxQowiG8TfOJF0R/Qg9g7DCE66R9agQpMJC SGxIin9p/4ld4Hn6869d4hNq4fHxNf/qkj2cnf8DYxrldz2FGsi6yMed4tzz2Am4 ZbPgwep+fy843ZdYrVIms9vJluNa9E+6Vpw9FwdjzQ/IBBMLvGaC2pDkc95YelaE nQrAlTO/0l5vjc8XuTQFlo3DbUg+WEld/pxvCqsd/q1mqjL0WbxtXl2zCwGzAoJx rjVEPfA8QSbtAgMBAAGjbzBtMB0GA1UdDgQWBBTHE0KKW8REV4HxajzVsIBxz3iL 9zAfBgNVHSMEGDAWgBTHE0KKW8REV4HxajzVsIBxz3iL9zAPBgNVHRMBAf8EBTAD AQH/MBoGA1UdEQQTMBGHBH8AAAGCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOC AQEAYlTEftrwGJBXuPmtxhmtw2HO/VTC4TGnq67hH5H+ptwgZJuuxCQ5KW6flTyp FTyMhha33WD4EBL3wqqJsWr9Y4BXqi4G0lRqXBcC1oIUa2VYIDMER7kaY1qTSqE8 ARpwdB2BhvngAzDLc+4Jt4jQMRGr8fHAwxpDBoIZ1knbyzYNP73Bajse6/8YtxUu nB2BsldjZnLvyHvRxUpWp92OyQih4jYSrlN6olDFlKDg7++kMhkHtJQW9a1t54VN 0ZXrB1ZRuHUUvGBq26x71riTWor7HNOSQaGeCMQjZNQkh5tfshNygUGSZVXTEwhG xSrOL7NqBt2+EkVwf7LjGzjmBw== -----END CERTIFICATE----- httrack-3.49.21/tests/install-headers-sweep.sh0000644000175000017500000002071015237104167014717 #!/bin/bash # # Compile every installed header on its own and in each ordered pair, in both # HTS_INTERNAL_BYTECODE states. One compiler run per batch: a spawn per unit # costs more than the compile on the Windows runner. 269 sweeps what automake # installed; the MSVC job has no automake and stages the same DevIncludes_DATA # list out of the source tree (#1153). Units carry the names of the headers they # include, so the compiler's own diagnostic says which pair broke. set -euo pipefail # shellcheck source=tests/testlib.sh . "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/testlib.sh" usage() { echo "usage: ${0##*/} {--srcdir DIR [--builddir DIR] | --headers-dir DIR}" \ "[--backend cl|cc] [--cc CMD] [--cxx CMD] [--self-test] [-- CPPFLAGS...]" >&2 exit 1 } srcdir="" builddir="" hdrdir="" backend=cc cc_cmd="" cxx_cmd="" cxx_set=0 selftest=0 extra=() while [ $# -gt 0 ]; do case $1 in --self-test) selftest=1 shift ;; --srcdir) srcdir=${2-} shift 2 || usage ;; --builddir) builddir=${2-} shift 2 || usage ;; --headers-dir) hdrdir=${2-} shift 2 || usage ;; --backend) backend=${2-} shift 2 || usage ;; --cc) cc_cmd=${2-} shift 2 || usage ;; --cxx) cxx_cmd=${2-} cxx_set=1 shift 2 || usage ;; --) shift extra=("$@") break ;; *) usage ;; esac done # One flag vocabulary per compiler driver. Both read @file, so the batch never # reaches the command line. case $backend in cl) : "${cc_cmd:=cl}" [ "$cxx_set" = 1 ] || cxx_cmd=$cc_cmd # -W3 matches the vcxproj and no -WX: the property under test is that a # consumer's unit compiles at all. -MP for the runner's cores. common=(-nologo -c -W3 -MP) c_lang=(-TC) cxx_lang=(-TP) ;; cc) : "${cc_cmd:=${CC:-cc}}" [ "$cxx_set" = 1 ] || cxx_cmd=${CXX:-c++} common=(-fsyntax-only) c_lang=(-x c) cxx_lang=(-x c++) ;; *) usage ;; esac read -r -a cc_argv <<<"$cc_cmd" read -r -a cxx_argv <<<"$cxx_cmd" langs=(c) if [ "${#cxx_argv[@]}" -gt 0 ]; then langs+=(cxx) else echo "note: no C++ compiler given, C leg only" >&2 fi tmp=$(mktemp -d) || exit 1 cleanup_push rm -rf "$tmp" mkdir -p "$tmp/include/httrack" "$tmp/tu" "$tmp/obj" headers=() if [ -n "$hdrdir" ]; then [ -z "$srcdir" ] || usage for h in "$hdrdir"/*.h; do cp "$h" "$tmp/include/httrack/" headers+=("${h##*/}") done else [ -n "$srcdir" ] || usage srcdir=$(cd "$srcdir" && pwd) || fail "no such source tree" [ -f "$srcdir/src/Makefile.am" ] || fail "$srcdir is not a source tree" [ -z "$builddir" ] || builddir=$(cd "$builddir" && pwd) || fail "no such build tree" declared=() while read -r h; do declared+=("$h"); done < <(abs_top_srcdir=$srcdir declared_headers) [ "${#declared[@]}" -ge 10 ] || fail "read only ${#declared[@]} headers out of DevIncludes_DATA, the parse is wrong" # An entry outside src/ is a build product: it comes from the build tree or # not at all. MSVC generates no config.h, which htsglobal.h includes on its # POSIX branch only. Never $srcdir/src/../, which would stage a stray file. absent=() for h in "${declared[@]}"; do case $h in ../*) from=${builddir:+$builddir/${h#../}} ;; *) from=$srcdir/src/$h ;; esac if [ -n "$from" ] && [ -f "$from" ]; then cp "$from" "$tmp/include/httrack/${h##*/}" headers+=("${h##*/}") elif [ "${h#../}" != "$h" ]; then absent+=("$h") else fail "$h is in DevIncludes_DATA but not in $srcdir/src" fi done [ "${#absent[@]}" -eq 0 ] || echo "note: not built here, so out of the sweep: ${absent[*]}" >&2 fi n=${#headers[@]} [ "$n" -ge 10 ] || fail "only $n headers to sweep, the list cannot be right" # The count alone cannot see a Makefile.am reformat the awk mis-parses: a set that # lost these and stayed above the floor would sweep, and pass, without them. for h in htsglobal.h httrack-library.h htssafe.h htsbasenet.h htsopt.h; do [ -f "$tmp/include/httrack/$h" ] || fail "$h is not in the set to sweep" done modes=(-UHTS_INTERNAL_BYTECODE -DHTS_INTERNAL_BYTECODE) gen() { # gen NAME HEADER... local f=$1 shift printf '#include \n' "$@" >"$tmp/tu/$f.c" } units=() for a in "${headers[@]}"; do gen "${a%.h}" "$a" units+=("../tu/${a%.h}.c") for b in "${headers[@]}"; do [ "$a" != "$b" ] || continue gen "${a%.h}--${b%.h}" "$a" "$b" units+=("../tu/${a%.h}--${b%.h}.c") done done # n first headers x (itself + n-1 seconds). A generator that lost a nesting # level, or that collided two names, would still sweep something. [ "${#units[@]}" -eq $((n * n)) ] || fail "generated ${#units[@]} units, want $((n * n))" written=("$tmp"/tu/*.c) [ "${#written[@]}" -eq "${#units[@]}" ] || fail "the unit names are not unique" # Run from obj/ with relative operands. cl drops each .obj in the working # directory, and MSYS rewrites no argument that is not a leading-slash path, so # anything passed after -- must be absolute. cd "$tmp/obj" sweep_log=$tmp/obj/cc.log compile() { # compile c|cxx MODE UNIT... local lang=$1 mode=$2 rc=0 shift 2 { printf '%s\n' "${common[@]}" -I../include "$mode" [ "${#extra[@]}" -eq 0 ] || printf '%s\n' "${extra[@]}" if [ "$lang" = c ]; then printf '%s\n' "${c_lang[@]}"; else printf '%s\n' "${cxx_lang[@]}"; fi printf '%s\n' "$@" } >batch.rsp if [ "$lang" = c ]; then "${cc_argv[@]}" @batch.rsp >"$sweep_log" 2>&1 || rc=$? else "${cxx_argv[@]}" @batch.rsp >"$sweep_log" 2>&1 || rc=$? fi return "$rc" } # Nothing below means anything if the driver cannot find its own runtime headers, # or cannot report a bad unit sitting in the middle of a batch. printf '#include \n' >"$tmp/tu/ok.c" printf '#include "no-such-header-1153.h"\n' >"$tmp/tu/missing.c" # Synthetic, because asserting that a real header still breaks would forbid ever # hardening it. printf '#define HTS_SWEEP_TAKEN 1\n' >"$tmp/include/httrack/sweep-first.h" printf '#ifndef HTS_SWEEP_TAKEN\ntypedef int sweep_t;\n#endif\nsweep_t sweep_f(void);\n' \ >"$tmp/include/httrack/sweep-second.h" # A header must react to the bytecode mode, or both halves run the same case # twice and the unit count still reads right. TEST_CPPFLAGS carrying -D does it. printf '#ifndef HTS_INTERNAL_BYTECODE\n#error not in bytecode mode\n#endif\n' \ >"$tmp/include/httrack/sweep-bytecode.h" gen good sweep-second.h sweep-first.h gen bad sweep-first.h sweep-second.h gen bytecode sweep-bytecode.h for lang in "${langs[@]}"; do compile "$lang" "${modes[0]}" ../tu/ok.c ../tu/good.c || { cat "$sweep_log" >&2 fail "the $backend $lang driver cannot compile and the control pair" } ! compile "$lang" "${modes[0]}" ../tu/missing.c || fail "the $backend $lang driver accepted a missing include, the sweep proves nothing" ! compile "$lang" "${modes[0]}" ../tu/ok.c ../tu/bad.c ../tu/good.c || fail "the $backend $lang driver missed a one-order-only pair inside a batch" compile "$lang" "${modes[1]}" ../tu/bytecode.c || fail "${modes[1]} does not reach a $lang header, so that half of the sweep is a duplicate" ! compile "$lang" "${modes[0]}" ../tu/bytecode.c || fail "${modes[0]} leaves HTS_INTERNAL_BYTECODE defined for $lang, so both halves are one" done rm -f "$tmp/include/httrack/sweep-first.h" "$tmp/include/httrack/sweep-second.h" \ "$tmp/include/httrack/sweep-bytecode.h" "$tmp/tu/ok.c" "$tmp/tu/missing.c" \ "$tmp/tu/good.c" "$tmp/tu/bad.c" "$tmp/tu/bytecode.c" # Staging, generation and the controls, without paying for the whole set again. if [ "$selftest" = 1 ]; then echo "self-test ok: $n headers staged, ${#units[@]} units, ${langs[*]} controls fire" exit 0 fi began=$SECONDS bad=0 for lang in "${langs[@]}"; do for mode in "${modes[@]}"; do compile "$lang" "$mode" "${units[@]}" || { head -40 "$sweep_log" >&2 echo "the headers do not compile as $lang standalone and pairwise ($mode)" >&2 bad=1 } done done echo "swept $n headers standalone and pairwise x ${#modes[@]} bytecode modes x ${langs[*]}" \ "= $((${#modes[@]} * ${#langs[@]} * ${#units[@]})) units in $((SECONDS - began))s with $backend" [ "$bad" -eq 0 ] || exit 1 exit 0 httrack-3.49.21/tests/ci-windows-watchdog.ps10000644000175000017500000002641615237104167014502 # Off-box telemetry for the Windows suite step (#795): it spawns and kills # nothing, so a wedge cannot disarm it, and reports as a commit status, the only # channel that outlives a dead runner. Every status carries the same state. param( [string]$ProgressLog = '', [int]$IntervalSeconds = 30, [int]$PollSeconds = 5, # Cannot outlive the step, whatever the caller forgets to kill. [int]$MaxSeconds = 2700, # Seam for the suite's own test, which points it at a sink it can count. [string]$ApiBase = 'https://api.github.com', [switch]$NoPost, [switch]$SelfTest ) $ErrorActionPreference = 'Stop' # Windows PowerShell renders a progress bar per web call otherwise. $ProgressPreference = 'SilentlyContinue' # --- decisions, kept pure so -SelfTest can drive them by return value --------- function Get-WatchdogAction { param([int]$Now, [int]$Posted, [int]$Interval) if (($Now - $Posted) -ge $Interval) { return 'post' } return 'wait' } # Posts to skip after a rejected one: a fork PR's token is read-only for the run. function Get-NextBackoff { param([int]$Current) if ($Current -lt 1) { return 1 } return [Math]::Min($Current * 2, 32) } # The (skip, backoff) pair after an attempted post, $Ok being whether it landed: # a rejection that later resolves has to leave nothing behind. function Get-NextThrottle { param([bool]$Ok, [int]$Backoff) if ($Ok) { return @(0, 0) } $b = Get-NextBackoff $Backoff return @($b, $b) } # GitHub truncates a description at 140 chars, so the counters take the cut, not # the fields a wedge is read for. $Static below zero is unknown. function Format-WatchdogStatus { param([int]$Elapsed, [int]$Static, [string]$InFlight, [string]$Counters) $q = '?' if ($Static -ge 0) { $q = [string]$Static } $t = ($InFlight -replace '\s+', ' ').Trim() if ($t.Length -gt 46) { $t = $t.Substring(0, 46) } $s = 't={0}s q={1}s {2} | {3}' -f $Elapsed, $q, $t, $Counters if ($s.Length -gt 140) { $s = $s.Substring(0, 140) } return $s } # --- probes ------------------------------------------------------------------ # One try/catch per counter: a probe that fails costs its own field, not the loop. # In-process only. A CIM query is richer, but its connect to a wedged WMI service # is unbounded, and would hang the one reporter still standing. function Get-WatchdogCounters { $f = New-Object System.Collections.ArrayList try { $ps = @(Get-Process) [void]$f.Add('p={0}' -f $ps.Count) [void]$f.Add('h={0}' -f (($ps | Measure-Object -Property Handles -Sum).Sum)) } catch { [void]$f.Add('p=? h=?') } try { $drive = New-Object System.IO.DriveInfo($env:SystemDrive + '\') [void]$f.Add('d={0}' -f [int]($drive.AvailableFreeSpace / 1MB)) } catch { [void]$f.Add('d=?') } return ($f -join ' ') } # Ok separates "nothing moved" from "could not read it", which would otherwise report # a wedge for an unreadable file. Share flags: the driver appends as we read. function Get-ProgressTail { param([string]$Path) $r = @{ Ok = $false; Signature = ''; Line = '' } if (-not $Path) { return $r } try { $share = [System.IO.FileShare]::ReadWrite -bor [System.IO.FileShare]::Delete $fs = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, $share) try { $sr = New-Object System.IO.StreamReader($fs) $text = $sr.ReadToEnd() } finally { $fs.Dispose() } $lines = @($text -split "`r?`n" | Where-Object { $_ -ne '' }) if ($lines.Count -gt 0) { $r.Line = $lines[-1] } $r.Signature = '{0}|{1}' -f $text.Length, $r.Line $r.Ok = $true } catch { } return $r } function Write-WatchdogLog { param([string]$Message) # A full disk is a state the sick runner reaches, and a log line lost to it # must not take the loop reporting off-box with it. try { Write-Host ('[watchdog {0:HH:mm:ss}] {1}' -f (Get-Date), $Message) } catch { } } # --- reporting --------------------------------------------------------------- $script:Repo = $env:WATCHDOG_REPO $script:Sha = $env:WATCHDOG_SHA $script:Token = $env:WATCHDOG_TOKEN $script:TargetUrl = $env:WATCHDOG_URL $script:Context = $env:WATCHDOG_CONTEXT if (-not $script:Context) { $script:Context = 'windows-suite-watchdog' } # One state always, so nothing downstream can read a verdict out of telemetry: # GitHub records the job's conclusion already. -NoPost is the test's hard stop, # whatever the environment holds. function Send-WatchdogStatus { param([string]$Description) if ($NoPost -or $SelfTest) { return $false } if (-not $script:Token -or -not $script:Repo -or -not $script:Sha) { return $false } $body = @{ state = 'success'; context = $script:Context; description = $Description } if ($script:TargetUrl) { $body['target_url'] = $script:TargetUrl } try { Invoke-RestMethod -Method Post -TimeoutSec 20 ` -Uri ('{0}/repos/{1}/statuses/{2}' -f $ApiBase.TrimEnd('/'), $script:Repo, $script:Sha) ` -UserAgent 'httrack-windows-suite-watchdog' ` -Headers @{ Authorization = ('Bearer {0}' -f $script:Token) Accept = 'application/vnd.github+json' } -ContentType 'application/json' -Body ($body | ConvertTo-Json -Compress) | Out-Null return $true } catch { Write-WatchdogLog ('status post failed: {0}' -f $_.Exception.Message) return $false } } # --- self-test ---------------------------------------------------------------- function Invoke-WatchdogSelfTest { $bad = New-Object System.Collections.ArrayList function Assert-That($cond, $what) { if (-not $cond) { [void]$bad.Add($what) } } Assert-That ((Get-WatchdogAction 30 0 30) -eq 'post') 'a post due exactly on the interval was skipped' Assert-That ((Get-WatchdogAction 29 0 30) -eq 'wait') 'posted ahead of the interval' Assert-That ((Get-WatchdogAction 5000 4990 30) -eq 'wait') 'posted off cadence' Assert-That ((Get-NextBackoff 0) -eq 1) 'the first rejection does not back off' Assert-That ((Get-NextBackoff 1) -eq 2) 'the backoff does not grow' Assert-That ((Get-NextBackoff 32) -eq 32) 'the backoff is not capped' $ok = Get-NextThrottle $true 8 Assert-That ($ok[0] -eq 0 -and $ok[1] -eq 0) 'a landed post leaves the run throttled' $ko = Get-NextThrottle $false 0 Assert-That ($ko[0] -eq 1 -and $ko[1] -eq 1) 'a first rejection skips nothing' $ko = Get-NextThrottle $false 4 Assert-That ($ko[0] -eq 8 -and $ko[1] -eq 8) 'a repeat rejection does not widen the gap' $long = '43_local-update-truncate-with-a-very-long-name-indeed.test' $line = Format-WatchdogStatus 812 41 $long 'p=118 h=41230 d=13210' Assert-That ($line.Length -le 140) ('status description is {0} characters' -f $line.Length) Assert-That ($line -like 't=812s q=41s 43_local-update-truncate*') ('status leads with the wrong fields: {0}' -f $line) Assert-That ($line -like '*d=13210') 'the counters did not survive a long test name' # -match, not -like: '?' is a wildcard there, so q=0s would satisfy it too. Assert-That ((Format-WatchdogStatus 8 -1 'x' 'y') -match '^t=8s q=\?s x \| y$') 'an unknown staticness reads as a number' $clip = Format-WatchdogStatus 1 2 ('x' * 80) 'c' Assert-That ($clip -match '^t=1s q=2s x{46} \| c$') ('the in-flight name was not clipped to 46: {0}' -f $clip) $wide = Format-WatchdogStatus 1 2 ('x' * 300) ('y' * 300) Assert-That ($wide.Length -le 140) ('an oversized status was not clipped: {0}' -f $wide.Length) # Cut from the tail: the head carries the fields a wedge is read for. Assert-That ($wide -like 't=1s q=2s x*') ('clipping dropped the leading fields: {0}' -f $wide) $gone = Get-ProgressTail -Path ('no-such-progress-log-{0}.tmp' -f $PID) Assert-That (-not $gone.Ok) 'an unreadable log reads as one that was read' $f = New-Object System.IO.FileInfo([System.IO.Path]::GetTempFileName()) try { [System.IO.File]::WriteAllText($f.FullName, "first`nRUN 42_probe.test at 7s`n") $tail = Get-ProgressTail -Path $f.FullName Assert-That ($tail.Ok) 'a readable log reads as unreadable' Assert-That ($tail.Line -eq 'RUN 42_probe.test at 7s') ('the tail is not the last line: {0}' -f $tail.Line) } finally { [System.IO.File]::Delete($f.FullName) } # Space-separated key=value: the counters share the 140-char description with # the fields a wedge is read for, and '?' from a failed probe is a value. $c = Get-WatchdogCounters Assert-That ($c -match '^[a-z]+=\S+( [a-z]+=\S+)*$') ('the counters are not key=value pairs: {0}' -f $c) foreach ($k in 'p', 'h', 'd') { Assert-That ($c -match ('(^| ){0}=' -f $k)) ('the counters dropped {0}=: {1}' -f $k, $c) } Assert-That ($c.Length -le 60) ('the counters take {0} of the 140 characters' -f $c.Length) # Nothing else reads these: every other leg passes its own schedule. Assert-That ($IntervalSeconds -eq 30) ('the default status cadence is {0}s' -f $IntervalSeconds) Assert-That ($PollSeconds -eq 5) ('the default poll is {0}s' -f $PollSeconds) Assert-That (-not (Send-WatchdogStatus 'self-test')) 'the self-test can reach the API' if ($bad.Count -gt 0) { foreach ($b in $bad) { Write-Host ('self-test FAIL: {0}' -f $b) } exit 1 } Write-Host 'watchdog self-test OK' exit 0 } if ($SelfTest) { Invoke-WatchdogSelfTest } # --- main loop ---------------------------------------------------------------- # Windows PowerShell still defaults below TLS 1.2, which api.github.com refuses. try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch { } $sw = [System.Diagnostics.Stopwatch]::StartNew() $lastSig = '' $movedAt = 0 # Negative, so the first tick posts: an early status is itself a datum. $postedAt = -$IntervalSeconds $backoff = 0 $skip = 0 # Guarded like the rest; the launcher waits for this exact line. try { Write-Host 'watchdog ready' } catch { } Write-WatchdogLog ('watching {0} every {1}s' -f $ProgressLog, $IntervalSeconds) while ($sw.Elapsed.TotalSeconds -lt $MaxSeconds) { # Measured, never accumulated: starvation is what makes a sleep overshoot. $now = [int]$sw.Elapsed.TotalSeconds try { $tail = Get-ProgressTail -Path $ProgressLog if ($tail.Ok -and $tail.Signature -ne $lastSig) { $lastSig = $tail.Signature $movedAt = $now } if ((Get-WatchdogAction $now $postedAt $IntervalSeconds) -eq 'post') { $postedAt = $now $static = -1 if ($tail.Ok) { $static = $now - $movedAt } $desc = Format-WatchdogStatus $now $static $tail.Line (Get-WatchdogCounters) # Logged whatever the backoff decides: it throttles the API, not the # artifact, which is all a run whose token cannot post will leave. Write-WatchdogLog $desc if ($skip -gt 0) { $skip-- } else { $next = Get-NextThrottle (Send-WatchdogStatus $desc) $backoff $skip = $next[0] $backoff = $next[1] } } } catch { Write-WatchdogLog ('tick failed: {0}' -f $_.Exception.Message) } Start-Sleep -Seconds $PollSeconds } Write-WatchdogLog ('stopping after {0}s' -f [int]$sw.Elapsed.TotalSeconds) httrack-3.49.21/tests/ci-windows-suite.sh0000644000175000017500000005064315237104167013741 #!/bin/bash # # Drives the offline test suite on the Windows runner (per-test budget, suite # deadline, engine reaping, skip gate, wedge watchdog #795). $1 is the directory # holding the built httrack.exe. Sourcing defines the helpers and drives nothing. testdir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=tests/testlib.sh . "$testdir/testlib.sh" # shellcheck source=tests/proclib.sh . "$testdir/proclib.sh" # Emit one GitHub annotation at level $1. The runner keeps only the first 10 of # each level per step and drops the rest silently, so the level is a budget: pick # one the step does not spend elsewhere. Led by a newline, since a command is only # read at a line head. sed/awk, not ${v//p/r}: bash 3.2 cannot parse $'..' inside one. ci_annotate() { local level=$1 title=$2 msg msg=$(printf '%s' "$3" | tr -d '\r' | sed 's/%/%25/g' | awk 'NR > 1 { printf "%%0A" } { printf "%s", $0 }' || true) printf '\n::%s title=%s::%s\n' "$level" "$title" "$msg" } # End a wedged suite before its runner dies: a step that fails on its own terms # keeps its log, a lost runner keeps nothing, annotations included (#795). Quiet # for $1s, then names the test in flight from $3 every $2s; kills $5 once $3 has # been static for $4s, or unconditionally $6s in (0: never). Staticness, never # elapsed time: a healthy test in flight and a wedged one look identical by the # clock, but every outcome writes a line, the per-test timeout included, so $4 past # that timeout means it never fired. The cap covers what staticness cannot: each of # those lines buys another $4s, so a tail of blown budgets walks the step onto the # workflow timeout, which keeps neither the log nor the artifacts (#1126). # Assigns into hb_time rather than printing: reading the clock forks nothing, which # matters when the box has none to spare. Overridable for the unit test virtual clock. hb_time=0 hb_now() { hb_time=$SECONDS; } # Start the off-box telemetry over the progress log $1, setting ci_watchdog_pid; # return 1 with no PowerShell available. Forks nothing and kills nothing, so it # reports where the heartbeat below cannot (#795). ci_start_native_watchdog() { local progress=$1 ps1 c exe='' waited=0 ps1="$testdir/ci-windows-watchdog.ps1" test -r "$ps1" || return 1 for c in pwsh powershell.exe; do if command -v "$c" >/dev/null 2>&1; then exe=$c break fi done test -n "$exe" || return 1 # Never the step's stdout: a background holder of that pipe keeps the step # open past the suite (#949), and tests/*.log reaches the artifact anyway. : >watchdog.log WATCHDOG_TOKEN="${ci_watchdog_token:-}" \ "$exe" -NoProfile -NonInteractive -ExecutionPolicy Bypass \ -File "$(nativepath "$ps1")" \ -ProgressLog "$(nativepath "$progress")" \ >>watchdog.log 2>&1 & ci_watchdog_pid=$! # $! comes from the fork, not the exec: wait for it to actually speak. while test "$waited" -lt 30; do grep -q '^watchdog ready$' watchdog.log && return 0 kill -0 "$ci_watchdog_pid" 2>/dev/null || break sleep 1 waited=$((waited + 1)) done kill_pid "$ci_watchdog_pid" ci_watchdog_pid='' return 1 } # End the step, announcing $2 first: the kill runs no EXIT trap, so an unexplained # death is all the log would otherwise hold. ci_heartbeat_kill() { local main=$1 ci_annotate error "suite watchdog" "$2" # Ahead of the kill, which runs no EXIT trap: an orphan would outlive the # step and overwrite its last status with a frozen tail. test -z "${watchdog:-}" || kill_pid "$watchdog" # Direct first: kill_tree may reap this watchdog before its own root (#953). kill_pid "$main" kill_tree "$main" } ci_suite_heartbeat() { local quiet=$1 every=$2 progress=$3 stuck=$4 main=$5 hard=${6:-0} local tick=$2 begin now line said moved last='' # Measured, never accumulated: the starvation this watchdog exists to catch is # exactly what makes a sleep overshoot, and drift only ever delays the kill. test "$tick" -le 30 || tick=30 hb_now begin=$hb_time said=$begin moved=$begin while :; do # Guarded: a tick that cannot exec returns 127, and under the caller's errexit a # bare failure would end the watchdog in silence (#1038). sleep "$tick" >/dev/null 2>&1 || : # holds no stdout: the caller's trap orphans it hb_now now=$hb_time # Guarded: under the caller's errexit a bare substitution assignment would # end the watchdog in silence, which reads as protection and is not. line=$(tail -n 1 "$progress" 2>/dev/null || true) test "$line" = "$last" || { last=$line moved=$now; } # Ahead of the quiet window, which only delays the staticness verdict: a # cap that inherited that delay could not be set below it. if test "$hard" -gt 0 && test $((now - begin)) -ge "$hard"; then ci_heartbeat_kill "$main" \ "killing the step: ${hard}s cap reached, in flight: $last" return 0 fi test $((now - begin)) -ge "$quiet" || continue # Every tick, not on the annotation cadence, which would let a late wedge # outlive the step's own timeout before being caught. if test $((now - moved)) -ge "$stuck"; then ci_heartbeat_kill "$main" \ "killing the step: $((now - moved))s without progress, in flight: $last" return 0 fi test $((now - said)) -ge "$every" || continue said=$now # notice, not warning: reap_leftover_processes spends the warning budget. ci_annotate notice "suite still running" "$( printf '%ss elapsed, %ss without progress, in flight: %s\n' \ "$((now - begin))" "$((now - moved))" "$last" list_stray_processes 0 named | head -n 8 )" done } # Only a direct run drives a suite. Asked of the shell, not derived from $0, # which a caller can set to this very path (172_ci-windows-driver.test). (return 0 2>/dev/null) && return 0 # Explicit now that this is a script; GitHub's "shell: bash" gave the step both. set -euo pipefail bin=${1:?usage: ci-windows-suite.sh } export PATH="$bin:$PATH" command -v httrack >/dev/null || { echo "::error::no httrack.exe in $bin" exit 1 } # Out of the environment before the first child forks below: an inherited token # could post a commit status in the name of the run. ci_watchdog_token=${WATCHDOG_TOKEN:-} unset WATCHDOG_TOKEN # httrack.exe is native, so MSYS rewrites any argument shaped like a # POSIX path, and a URL path is shaped exactly like one: "/a/b.html" # reached the engine as "C:/Program Files/Git/a/b.html". Switch that # off, and hand the tests a TMPDIR that is already a Windows path. export MSYS_NO_PATHCONV=1 export MSYS2_ARG_CONV_EXCL='*' TMPDIR="$(cygpath -m "$RUNNER_TEMP")" export TMPDIR # Mirror what configure hands the suite. LC_ALL sets the codeset MSYS maps # a UTF-8 mirror name onto UTF-16 with, which the intl crawls "test -f". export HTTPS_SUPPORT=yes BROTLI_ENABLED=yes ZSTD_ENABLED=yes export LC_ALL=C.UTF-8 # A wedged crawl must not eat the job's timeout budget. timeout(1)'s # signals can't reap a native httrack.exe (MSYS signals don't reach it), # so a hang orphaned processes that starved the runner; run_with_timeout # TerminateProcess-es the whole tree. 600s is unchanged: it clears the # 540s a three-pass crawl may legitimately take under local-crawl.sh's # own watchdogs, against a slowest healthy test here of 39s. per_test=600 # The whole suite must give up before the workflow's 45-minute step # timeout: a cancelled step keeps neither its log nor the artifacts the # later if:always() steps would upload, one failing on its own terms keeps # both. Left at the serial budget though the pool costs 4 min, because it # bounds a wedge and not a healthy run: fitted to the pool it reds a merely # slow run and every jobs=1 one (23 min), and the traced rerun below gets # only what is left of it, so a tight value drops the trace on exactly the # runs worth diagnosing. suite_deadline=1500 started=$SECONDS # Reaches the artifact whenever the step ends on its own terms, which the # tail of its log may not. Absolute, since a .test may have chdir'd. progress=suite-progress.log : >"$progress" export HTTRACK_PROGRESS_LOG="$PWD/$progress" # A dying runner takes both, and every annotation with them (measured, see # #795), so the watchdog's job is to end the step first: one that fails on # its own terms keeps its log. Also left at the serial budget: under the pool # any live worker keeps the log moving, so staticness now catches a stalled # suite and nothing narrower -- one wedged test is bounded by $per_test and # by $hard_deadline below. stuck=900 # Orthogonal to that heartbeat rather than a spare of it: the heartbeat needs # 960s of quiet and 900s of static log, and every #795 death measured so far # lands inside the first 750s of the step. watchdog='' ci_watchdog_pid='' # Wall-clock backstop, because staticness alone bounds nothing: the deadline above # is read before each dispatch, and past it the tests in flight may still spend # $per_test and then a traced rerun, each writing a progress line that re-arms # $stuck. 2400s clears that 1500+600 worst case with room for the hang dump, and # leaves 300s of the step's 45 minutes to fail on our own terms and upload (#1126). hard_deadline=2400 ci_start_native_watchdog "$PWD/$progress" && watchdog=$ci_watchdog_pid test -n "$watchdog" || echo "no off-box watchdog: no usable PowerShell" ci_suite_heartbeat 960 360 "$progress" "$stuck" $$ "$hard_deadline" & heartbeat=$! trap 'set +e; kill "$heartbeat" 2>/dev/null; test -z "$watchdog" || kill_pid "$watchdog"' EXIT pass=0 fail=0 skip=0 failed="" skipped="" deadline=0 # Tests in flight at once, min(2*nproc, 16) as ci.yml gives "make check" on every # platform: each binds its own ephemeral-port server, and they mostly sleep. cores=$(nproc 2>/dev/null || echo "${NUMBER_OF_PROCESSORS:-2}") case "$cores" in '' | 0 | *[!0-9]*) cores=2 ;; esac jobs=$((cores * 2)) test "$jobs" -le 16 || jobs=16 # So a test can pin the width; a nonsense value is named rather than obeyed. case "${HTTRACK_SUITE_JOBS:-}" in '') ;; 0 | *[!0-9]*) echo "::warning::ignoring HTTRACK_SUITE_JOBS=$HTTRACK_SUITE_JOBS" ;; *) jobs=$HTTRACK_SUITE_JOBS ;; esac # wait -n is bash 4.3, and macOS drives this script under 3.2 # (172_ci-windows-driver.test): with no way to wait for a free slot, run serially. pool= if test "${BASH_VERSINFO[0]}" -gt 4 || { test "${BASH_VERSINFO[0]}" -eq 4 && test "${BASH_VERSINFO[1]}" -ge 3; }; then pool=1 fi test -n "$pool" || jobs=1 # kill_tree's last-resort sweep (testlib.sh) kills every engine and every python # on the host, so it is sound only while one test is in flight. if test "$jobs" -gt 1; then unset HTTRACK_EXCLUSIVE_HOST else export HTTRACK_EXCLUSIVE_HOST=1 fi # A worker cannot increment a counter of ours, so every outcome is written here # and the tally read back once the pool has drained. results=suite-results rm -rf "$results" mkdir -p "$results" # Run test $1 to completion: its verdict on stdout, a failure's 25-line tail into # $results/$1.tail, and its status last into $results/$1.rc, which says it got there. run_one_test() ( local t=$1 rc=0 left ttmp # Its own TMPDIR, since dump_crawl_logs (testlib.sh) globs the whole of it. # Windows-shaped like the export above: the tests hand it to a native exe. ttmp="$TMPDIR/suite.$t" rm -rf "$ttmp" 2>/dev/null || true mkdir -p "$ttmp" # Same guard "make check" uses on POSIX, so a wedge is diagnosed the # same way on every platform. It dumps before it kills, which a bare # run_with_timeout cannot: by the time that returns, the tree whose # stack we wanted is already gone. HTTRACK_TEST_TIMEOUT=$per_test TMPDIR="$ttmp" \ bash ./test-timeout.sh "$t" >"$t.log" 2>&1 || rc=$? case "$rc" in 0) echo "PASS $t" ;; 77) echo "SKIP $t" ;; 124) # test-timeout.sh has already written the process list, the stacks # and the killed crawl's own logs into $t.log. echo "FAIL $t (timed out, tree killed)" tail -n 25 "$t.log" | sed 's/^/ /' >"$results/$t.tail" ;; *) echo "FAIL $t (exit $rc)" # Captured before the trace appends below, or an intermittent failure # reports the tail of the re-run that passed. tail -n 25 "$t.log" | sed 's/^/ /' >"$results/$t.tail" # These assert with `test "$(...)" == "..." || exit 1`, which # says nothing at all on failure. Re-run traced, still bounded. # Charged to the suite deadline rather than given a budget of its # own: a failure just under that deadline would else spend # $per_test twice and land on the workflow's own timeout (#1126). left=$((suite_deadline - (SECONDS - started))) test "$left" -le "$per_test" || left=$per_test if [ "$left" -gt 0 ]; then # Noted first, or a slow trace reads as a wedge to the watchdog, # which would then kill the step in the middle of writing it. echo "RERUN $t" >>"$progress" # Handed the same TMPDIR: the trace runs outside test-timeout.sh, # which is what gave the first run one of its own. TMPDIR="$ttmp" run_with_timeout "$left" bash -x "$t" >>"$t.log" 2>&1 || true echo " --- traced re-run ---" >>"$results/$t.tail" tail -n 25 "$t.log" | sed 's/^/ /' >>"$results/$t.tail" else echo "no trace: past the ${suite_deadline}s suite deadline" | tee -a "$t.log" | sed 's/^/ /' >>"$results/$t.tail" fi ;; esac echo "$rc $t" >>"$progress" # Never fatal: Windows may still hold a file the killed tree left open. rm -rf "$ttmp" 2>/dev/null || true echo "$rc" >"$results/$t.rc" ) # Workers still running, into $workers. Counted, not taken from wait -n, which # returns for any job (the heartbeat included) and cannot be told which to watch. workers=0 count_workers() { local p workers=0 for p in ${pids[@]+"${pids[@]}"}; do if kill -0 "$p" 2>/dev/null; then workers=$((workers + 1)); fi done } # label:pattern, globbed rather than enumerated so a new NNN_engine-*.test or # NNN_local-*.test is picked up instead of silently getting zero coverage. Every # entry carries a metacharacter, or nullglob cannot empty it and the gate below # has nothing to catch. # testlib and crawllib cover what most tests here rest on. categories=(runnable:'00_runnable*.test' engine:'*_engine-*.test' zlib:'*_zlib-*.test' local:'*_local-*.test' watchdog:'*_watchdog*.test' testlib:'*_testlib-*.test' crawllib:'*_crawllib*.test' crawl-harness:'*_crawl-harness-*.test' proxy-https:'*_crawl_proxy_https.test' log-salvage:'*_crawl-log-salvage.test') tests=() shopt -s nullglob for c in "${categories[@]}"; do # shellcheck disable=SC2206 # expanding the pattern is the point matched=(${c#*:}) # Named, and before anything runs: left unexpanded the pattern reaches # test-timeout.sh literally and is counted as a test failing 127 (#952). test -n "${matched[0]:-}" || { echo "::error::test category ${c%%:*} matched no tests (${c#*:})" exit 1 } tests+=("${matched[@]}") done shopt -u nullglob pids=() ran_tests=() for t in "${tests[@]}"; do elapsed=$((SECONDS - started)) if [ "$elapsed" -ge "$suite_deadline" ]; then echo "::error::suite deadline: ${elapsed}s elapsed, stopping before $t" echo "DEADLINE before $t after ${elapsed}s" >>"$progress" # Per-test start times, so the slow ones are named rather than guessed. sed 's/^/ /' "$progress" deadline=1 break fi echo "RUN $t at ${elapsed}s" >>"$progress" ran_tests+=("$t") if test "$jobs" -eq 1; then # Never fatal: a worker killed by a signal is one failed test, not the # end of the suite, and only the gates below may stop it (errexit). run_one_test "$t" || true continue fi count_workers while test "$workers" -ge "$jobs"; do wait -n 2>/dev/null || true count_workers done run_one_test "$t" & pids+=("$!") done # Never a bare wait, which would also wait on the heartbeat and never return. for p in ${pids[@]+"${pids[@]}"}; do wait "$p" 2>/dev/null || true done # In test order, once nothing is still writing: eight workers interleaving their # failure tails is noise. for t in ${ran_tests[@]+"${ran_tests[@]}"}; do # read, not $(cat): a fork per test costs tens of milliseconds under MSYS. rc= test ! -r "$results/$t.rc" || read -r rc <"$results/$t.rc" || true case "$rc" in 0) pass=$((pass + 1)) ;; 77) skip=$((skip + 1)) skipped="$skipped $t" ;; *) fail=$((fail + 1)) failed="$failed $t" # A worker killed before it could report leaves no status behind. test -n "$rc" || echo "FAIL $t (its worker left no status)" ;; esac test ! -s "$results/$t.tail" || cat "$results/$t.tail" done # An orphaned httrack.exe spins and starves the runner ("lost communication"). Once, # at the end: matching by image name, an earlier reap cannot spare a live sibling. reap_leftover_processes "the suite" | tee -a "$progress" echo "ran=$((pass + fail + skip)) pass=$pass fail=$fail skip=$skip" | tee -a "$GITHUB_STEP_SUMMARY" # Every gate here exits 77, so an all-skipped suite would report green having # tested nothing: pin the skips, and floor the passes in case the glob empties. # One name per line, so two branches each appending one don't collide on the # same line; compared as a sorted set below, so glob discovery order can't # cause a false mismatch either. # footer-overflow and purge-longpath skip on Windows (need a path past MAX_PATH); # webdav-default and proxytrack-quiet read proxytrack's console through a pty, # which Windows Python does not build; # badmtime needs a filesystem that stores an mtime past gmtime's range; # single-file-gui and holdport drive htsserver, which this job does not build; # update-304-leak and cmdline-leak need a LeakSanitizer build, which MSVC has no # equivalent of; # crash-symbolize and backtrace-empty need backtrace(), which Windows has no # equivalent of; # string-oom drives a helper binary that only the automake build produces; # datadir-ospath copies the unwrapped binary the automake build leaves in .libs, # and needs the loader variable libtool picked, neither of which this job has; # link-control-bytes names its fixtures with the raw control bytes the requests # decode back to, which NTFS refuses; # memresume, repaircache and resume-recovery interrupt pass 1 with a signal # MSYS cannot deliver to a native exe; # ftp-deadhost-interrupt, ftp-sigterm, abort-purge, signal-receive and # ftp-stop-window need that same signal (deadhost's --timeout half runs as 245, # abort-purge's --max-time half as 268); # close-once interposes close() through LD_PRELOAD, which MSYS has no equivalent for. expected_skips="01_engine-footer-overflow.test 253_local-ftp-close-once.test 100_local-purge-longpath.test 158_local-link-control-bytes.test 114_local-update-304-leak.test 283_engine-cmdline-leak.test 120_local-proxytrack-webdav-default.test 143_engine-backtrace-empty.test 152_engine-string-oom.test 153_local-proxytrack-quiet.test 215_engine-datadir-ospath.test 243_local-ftp-deadhost-interrupt.test 255_local-ftp-sigterm.test 261_local-abort-purge.test 262_local-signal-receive.test 263_local-ftp-stop-window.test 235_local-resume-recovery.test 48_local-crange-memresume.test 71_local-crange-repaircache.test 80_engine-crash-symbolize.test 88_local-proxytrack-badmtime.test 241_local-single-file-gui.test 288_testlib-holdport.test" # First, or the deadline reads as an unexplained shortfall in the gates below. [ "$deadline" -eq 0 ] || { echo "::error::suite did not finish within ${suite_deadline}s" exit 1 } [ "$pass" -ge 90 ] || { echo "::error::only $pass tests passed ($skip skipped)" exit 1 } # Word-split on whitespace (space-joined $skipped, newline-joined # expected_skips both work) and sort, so the compare is a set, not a string. # shellcheck disable=SC2086 # the splitting is what makes it a set got=$(printf '%s\n' $skipped | sort) # shellcheck disable=SC2086 want=$(printf '%s\n' $expected_skips | sort) if [ "$got" != "$want" ]; then echo "::error::skip set changed from expected; - missing, + newly skipped" diff -u <(echo "$want") <(echo "$got") | tail -n +3 | sed 's/^/ /' exit 1 fi [ "$fail" -eq 0 ] || { echo "::error::failing:$failed" exit 1 } httrack-3.49.21/tests/guide-image-check.py0000755000175000017500000000740315237104167013774 #!/usr/bin/env python3 """Compare guide.html's hardcoded geometry against the files it ships. Usage: guide-image-check.py Stdlib only: the suite cannot assume Pillow on a build host, and no CI leg has it. """ import os import re import struct import sys # Floor: a parse that matched nothing would satisfy every check below. MIN_IMAGES = 40 SIGNATURE = b"\x89PNG\r\n\x1a\n" # Signature, then the first chunk's length, its IHDR type, and the two sizes. HEADER = len(SIGNATURE) + 4 + 4 + 4 + 4 COMMENT = re.compile(r"", re.S) IMG_TAG = re.compile(r"]*>", re.I) # The leading space keeps data-height="..." one key rather than a height. ATTR = re.compile(r'\s([A-Za-z-]+)="([^"]*)"') def png_size(path): """Width and height out of the IHDR. Raises ValueError on anything else.""" with open(path, "rb") as fp: head = fp.read(HEADER) if head[: len(SIGNATURE)] != SIGNATURE: raise ValueError("not a PNG, so its size cannot be read") if len(head) < HEADER: raise ValueError("truncated inside the IHDR") if head[12:16] != b"IHDR": raise ValueError("no IHDR where a PNG keeps it") return struct.unpack(">II", head[16:HEADER]) def attributes(tag): """First value wins, as a browser does with a repeated attribute.""" attrs = {} for name, value in ATTR.findall(tag): attrs.setdefault(name.lower(), value) return attrs def check(html_dir): """Return (number of img/ tags, list of defect messages).""" with open(os.path.join(html_dir, "guide.html"), encoding="utf-8") as fp: # A commented-out screenshot is not a reference. text = COMMENT.sub("", fp.read()) refs = [] bad = [] for tag in IMG_TAG.findall(text): attrs = attributes(tag) src = attrs.get("src") if src is None: bad.append("%s: no src this checker can read" % tag) continue if not src.startswith("img/"): # Every other src is chrome, shared with the rest of the doc set. if "img/" in src: bad.append("%s: an img/ path spelled past the check" % src) continue refs.append(src) path = os.path.join(html_dir, src) if not os.path.isfile(path): bad.append("%s: referenced by guide.html, not shipped" % src) continue if "width" not in attrs or "height" not in attrs: bad.append("%s: carries no width/height" % src) continue try: width, height = png_size(path) except (OSError, ValueError) as exc: bad.append("%s: %s" % (src, exc)) continue if (attrs["width"], attrs["height"]) != (str(width), str(height)): bad.append( "%s: guide.html says %sx%s, the file is %dx%d" % (src, attrs["width"], attrs["height"], width, height) ) if len(refs) < MIN_IMAGES: bad.append( "only %d tags reference img/, want at least %d" % (len(refs), MIN_IMAGES) ) seen = set(refs) for name in sorted(os.listdir(os.path.join(html_dir, "img"))): # doc-images.py owns this prefix; the rest of img/ serves other pages. if name.startswith("guide-") and "img/" + name not in seen: bad.append("img/%s: shipped, but guide.html no longer shows it" % name) return len(refs), bad def main(): if len(sys.argv) != 2: sys.stderr.write("usage: %s \n" % sys.argv[0]) return 2 count, bad = check(sys.argv[1]) for message in bad: sys.stderr.write("FAIL: %s\n" % message) if bad: return 1 print("guide.html: %d image sizes match their files" % count) return 0 if __name__ == "__main__": sys.exit(main()) httrack-3.49.21/tests/crawllib.sh0000644000175000017500000001127215237104167012321 #!/bin/bash # # local-server.py launch and crawl helpers, shared by local-crawl.sh and by the # tests that drive the server themselves. Sourced, not run. # shellcheck source=tests/testlib.sh . "$(dirname "${BASH_SOURCE[0]}")/testlib.sh" # Engine time cap, and the watchdog above it: the cap fires first on a healthy # crawl, so only a genuine wedge trips the watchdog. CRAWL_MAX_TIME=120 # A function, not a value: 72_watchdog-crawl and 258 set CRAWL_DEADLINE after # this file is sourced. crawl_deadline() { printf '%s\n' "${CRAWL_DEADLINE:-180}"; } # Live servers, in start order; a stopped one leaves an empty slot. cleanup_push # expands its arguments at push time, so a teardown holding the pid itself could # not be disarmed, and 240 stops its server mid-test on purpose. SRV_PIDS=() # Teardown for the server in slot $1. Signalling a pid the system has since # recycled would kill an unrelated process and then stall reap_bounded for its # whole grace period, so a slot is read, not a pid. local_server_reap() { local pid=${SRV_PIDS[$1]:-} test -n "$pid" || return 0 SRV_PIDS[$1]= stop_server "$pid" } # Stop server $1 now and disarm its teardown, for a test whose next step needs # the server gone. local_server_stop() { local i for ((i = 0; i < ${#SRV_PIDS[@]}; i++)); do test "${SRV_PIDS[$i]:-}" != "$1" || SRV_PIDS[i]= done stop_server "$1" } # Start local-server.py in the background on an ephemeral port and wait for its # "PORT n" line. Sets SRV_PORT, SRV_PID, SRV_LOG and BASEURL, registers the # reaping cleanup and appends to SRV_PIDS. A second call overwrites all four and # truncates the default log, so a caller wanting two servers saves each set and # gives each its own --log. Options, ahead of any server argument; -- ends them: # --root DIR tree to serve (default: the shared server-root fixture) # --log FILE where the announcement lands (default: $tmpdir/server.log) # --env V=VAL an environment variable for the server, repeatable # --tls serve HTTPS with the test certificate; BASEURL says https # shellcheck disable=SC2120 # most callers want the fixture and no options local_server_start() { local root="${testdir}/server-root" log='' envs=() tls=() scheme=http while test $# -gt 0; do case $1 in --root) root=$2 shift 2 ;; --tls) scheme=https tls=(--tls --cert "$(nativepath "${testdir}/server.crt")") tls+=(--key "$(nativepath "${testdir}/server.key")") shift ;; --log) log=$2 shift 2 ;; --env) envs+=("$2") shift 2 ;; --) shift break ;; *) break ;; esac done test -n "${SRV_PYTHON:-}" || SRV_PYTHON=$(find_python) || skip "python3 not found" test -n "$log" || log="${tmpdir:?no tmpdir and no --log}/server.log" SRV_LOG=$log : >"$SRV_LOG" # Stdin off the terminal: run_with_timeout toggles job control, and a # background job that touches the tty is stopped with SIGTTIN. env ${envs[@]+"${envs[@]}"} "$SRV_PYTHON" \ "$(nativepath "${testdir}/local-server.py")" \ --root "$(nativepath "$root")" ${tls[@]+"${tls[@]}"} "$@" \ >"$SRV_LOG" 2>&1 "$log" 2>&1 || rc=$? test "$rc" -ne 124 || fail "crawl watchdog fired after ${deadline}s" return "$rc" } httrack-3.49.21/tests/httpclient.py0000644000175000017500000000533215237104167012716 #!/usr/bin/env python3 """Raw HTTP/1.0 client for the htsserver tests. Speaks the socket directly: the tests assert on status-line and header bytes urllib parses away, and need a reply even from a headerless fragment. """ import argparse import socket import sys import urllib.parse def build_request(args): if args.field or args.post is not None: if args.field: # urlencode, not quote(): a browser sends "+" for a space, and the # server decodes that on its own branch. body = urllib.parse.urlencode([tuple(f.split("=", 1)) for f in args.field]) else: body = args.post return ( "POST %s HTTP/1.0\r\nHost: 127.0.0.1\r\n" "Content-type: application/x-www-form-urlencoded\r\n" "Content-length: %d\r\n\r\n%s" % (args.path or "/", len(body), body) ) return "GET %s HTTP/1.0\r\nHost: 127.0.0.1\r\n\r\n" % ( args.path or "/server/index.html" ) def main(): p = argparse.ArgumentParser(description=__doc__) p.add_argument("--port", type=int, required=True) p.add_argument("--path") p.add_argument("--post", help="raw urlencoded body; POSTs it") p.add_argument( "--field", action="append", metavar="K=V", help="POST field, form-encoded here; repeatable", ) p.add_argument("--timeout", type=float, default=30) p.add_argument( "--headers-only", action="store_true", help="stop at the end of the header block; the server need not close", ) p.add_argument("--head-file", help="write the header block here, not to stdout") p.add_argument("--body-file", help="write the body here, not to stdout") args = p.parse_args() s = socket.create_connection(("127.0.0.1", args.port), 10) s.settimeout(args.timeout) s.sendall(build_request(args).encode()) out = b"" try: while True: if args.headers_only and b"\r\n\r\n" in out: break chunk = s.recv(65536) if not chunk: break out += chunk except socket.timeout: # Exit rather than hang: a wedged server is the failure under test. sys.stderr.write("timed out after %d bytes\n" % len(out)) sys.exit(9) s.close() if args.headers_only: out = out.split(b"\r\n\r\n")[0] if args.head_file or args.body_file: head, _, body = out.partition(b"\r\n\r\n") if args.head_file: open(args.head_file, "wb").write(head) if args.body_file: open(args.body_file, "wb").write(body) return # The GUI is served ISO-8859-1, and a mirrored file can hold any byte. sys.stdout.write(out.decode("latin-1")) main() httrack-3.49.21/tests/webhttracklib.sh0000644000175000017500000001621215237104167013346 #!/bin/bash # # htsserver launch, request and reaping helpers. Sourced, not run. HTS_TESTDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=tests/testlib.sh . "${HTS_TESTDIR}/testlib.sh" HTS_DISTDIR=$(cd "${top_srcdir:-${HTS_TESTDIR}/..}" && pwd) HTS_BG_PIDS=() HTS_SRV_PIDS=() HTS_REAPED_PIDS=() HTS_TMP_LOGS=() HTS_CR=$(printf '\r') # htsserver, plus a python3 the Debian buildd chroot may not have: that one skips. htsserver_require() { command -v htsserver >/dev/null || fail "no htsserver in PATH" HTS_PYTHON=$(find_python) || skip "python3 not found" } # shellcheck disable=SC2120 # one port is the common case htsserver_freeport() { local python=${HTS_PYTHON} freeport "$@" } # First URL= and PID= of the announcement, or empty. Windows announces no pid. htsserver_announced() { local line HTS_URL= HTS_PID= test -r "${HTS_LOG}" || return 0 while read -r line; do line=${line%"$HTS_CR"} case ${line} in URL=*) test -n "${HTS_URL}" || HTS_URL=${line#URL=} ;; PID=*) test -n "${HTS_PID}" || HTS_PID=${line#PID=} ;; esac done <"${HTS_LOG}" } # The server process; reads htsserver_start's locals and its background stdout. htsserver_exec() { # htsserver keeps SIGTERM ignored across its exec, so only -9 reaps it. trap '' TERM TTOU XFSZ test -z "${wlimit}" || ulimit -f "${wlimit}" test -z "${home}" || export HOME="${home}" exec htsserver "${root%/}/" --port "${HTS_PORT}" "$@" 2>&1 } # Start htsserver in the background on a free port and wait for its # announcement. Sets HTS_URL, HTS_PORT, HTS_LOG, HTS_BGPID and HTS_PID (the # server's own pid, which Windows does not announce). Options, ahead of any # htsserver argument: # --root DIR tree to serve (default: the dist root) # --home DIR $HOME for the server, so no ~/.httrack.ini leaks in # --log FILE where the announcement lands (default: a temp file) # --port N a port already picked, to keep the fork out of a window the # caller is timing; owned by the caller, so a lost bind fails # rather than being redrawn # --write-limit N ulimit -f N; the log rides a pipe, which the cap spares # shellcheck disable=SC2120 # most callers need no htsserver argument htsserver_start() { local root=${HTS_DISTDIR} home='' log='' wlimit='' port='' while test $# -gt 0; do case $1 in --root) root=$2 shift 2 ;; --home) home=$2 shift 2 ;; --log) log=$2 shift 2 ;; --write-limit) wlimit=$2 shift 2 ;; --port) port=$2 shift 2 ;; --) shift break ;; *) break ;; esac done # freeport hands back a port it has already released, so a neighbour can take # it before the server binds: redraw and retry, as start_proxytrack does. local ownlog='' try start test -n "${log}" || ownlog=1 for try in 1 2 3; do HTS_PORT=${port} test -n "${HTS_PORT}" || HTS_PORT=$(htsserver_freeport) || fail "no free loopback port" # One log per attempt: a killed attempt's writer can still be draining. if test -n "${ownlog}"; then log=$(mktemp) HTS_TMP_LOGS+=("${log}") fi HTS_LOG=${log} : >"${HTS_LOG}" if test -n "${wlimit}"; then # Process substitution, not a pipeline: $! must be the server. In a # pipeline it is the reader, so a start that never announces leaves the # server unkilled and parks the reaping wait on the whole job. htsserver_exec "$@" > >(cat >"${HTS_LOG}") & else htsserver_exec "$@" >"${HTS_LOG}" & fi HTS_BGPID=$! HTS_BG_PIDS+=("${HTS_BGPID}") # A sed and a sleep per tick is a process per tick (#795), and the deadline # self-extends rather than expiring on a loaded parallel run. start=$SECONDS while :; do htsserver_announced test -z "${HTS_URL}" || break kill -0 "${HTS_BGPID}" 2>/dev/null || break test "$((SECONDS - start))" -lt 60 || break poll_wait 0.1 done test -z "${HTS_URL}" || break # Only a lost bind is worth redrawing; anything else is a regression. grep -qE "${BIND_LOST}" "${HTS_LOG}" || fail "htsserver did not come up: $(cat "${HTS_LOG}")" test -z "${port}" || fail "htsserver could not bind port ${port}: $(cat "${HTS_LOG}")" stop_server "${HTS_BGPID}" # Loud, so an intermittent bind regression cannot hide behind the retry. echo "htsserver did not get port ${HTS_PORT}, retrying" >&2 done test -n "${HTS_URL}" || fail "htsserver bound none of 3 ports: $(cat "${HTS_LOG}")" test -z "${HTS_PID}" || HTS_SRV_PIDS+=("${HTS_PID}") } # Reap every server started so far and remember them for # htsserver_assert_reaped. Safe from a cleanup trap, and safe to call twice. htsserver_stop() { local pid HTS_REAPED_PIDS=(${HTS_BG_PIDS[@]+"${HTS_BG_PIDS[@]}"} ${HTS_SRV_PIDS[@]+"${HTS_SRV_PIDS[@]}"}) # Grouped: bash announces a killed job at any command boundary, so the # notice escapes a redirect on the wait alone once there are two servers. { for pid in ${HTS_SRV_PIDS[@]+"${HTS_SRV_PIDS[@]}"} \ ${HTS_BG_PIDS[@]+"${HTS_BG_PIDS[@]}"}; do kill -9 "${pid}" 2>/dev/null || true done for pid in ${HTS_BG_PIDS[@]+"${HTS_BG_PIDS[@]}"}; do reap_bounded "${pid}" || true done } 2>/dev/null HTS_SRV_PIDS=() HTS_BG_PIDS=() } # Teardown: reap, then drop the logs the library allocated. Keep it out of # htsserver_stop, which a test may call mid-run before reading the log back. htsserver_cleanup() { htsserver_stop rm -f ${HTS_TMP_LOGS[@]+"${HTS_TMP_LOGS[@]}"} HTS_TMP_LOGS=() } # A leaked htsserver wedges the parallel harness behind a green log. htsserver_assert_reaped() { local pid test "${#HTS_REAPED_PIDS[@]}" -gt 0 || fail "nothing was reaped to assert on" for pid in ${HTS_REAPED_PIDS[@]+"${HTS_REAPED_PIDS[@]}"}; do ! kill -0 "${pid}" 2>/dev/null || fail "htsserver ${pid} survived" done } htsserver_alive() { test -n "${HTS_PID:-}" && kill -0 "${HTS_PID}" 2>/dev/null; } # Raw HTTP against $HTS_PORT; tests/httpclient.py documents the options. htsserver_client() { "${HTS_PYTHON}" "${HTS_TESTDIR}/httpclient.py" --port "${HTS_PORT}" "$@" } # The reply to a GET of $1, status line and headers included. htsserver_get() { htsserver_client --path "$1"; } # The reply to a POST of the urlencoded body $1, to / unless $2 names a page. htsserver_post() { htsserver_client --path "${2:-/}" --post "$1"; } # The session id the server renders into every form, as a browser picks it up. # Callers assert its length: an empty one makes every later check vacuous. htsserver_sid() { firstline "$(htsserver_get /server/index.html | sed -n 's/.*name="sid" value="\([0-9a-f]*\)".*/\1/p')" } httrack-3.49.21/tests/proclib.sh0000644000175000017500000003102415237104167012151 #!/bin/bash # # Process forensics for a wedged test: what is still running, and a stack for # each engine process. Sourced after testlib.sh, not run. # Engine and fixture-server processes, matched on the executable basename only. # Matching the whole ps line instead would catch every unrelated command whose # arguments merely mention a path containing "httrack". Derived from testlib.sh's # ENGINE_EXES, never spelled out again (#1067). ENGINE_EXE_RE="^(lt-)?(${ENGINE_EXES// /|})([.]exe)?\$" # The same set against tasklist, whose first column is the image basename. # Anchored, or "notepad-httrack-notes.exe" reads as a leaked engine. ENGINE_IMAGE_RE="^(${ENGINE_EXES// /|})[.]exe" FIXTURE_SERVER_RE='^(local-server|proxy-https-server|proxy-connect-server|socks5-server|tls-stall-server)[.]py$' # Under qemu-user the kernel reports the binfmt interpreter as the command, and # the program's own argv[0] lands one place right (Debian's hppa buildd # emulates). qemu-img and friends take a disk image, not a program; these lists # feed kill, so shifting past one would read the image path as the process. QEMU_INTERP_RE='^qemu-[[:alnum:]_]+(-static)?$|^[[:alnum:]_]+-binfmt(-[[:upper:]]+)?$' QEMU_IMAGE_TOOL_RE='^qemu-(img|nbd|io|ga|edid|keymap)(-static)?$' # awk prologue for the matchers below, taking those two as -v qint and -v qimg. # shellcheck disable=SC2016 # awk fields, not shell expansions AWK_PROC_NAMES=' function basen(s) { sub(/.*[\/\\]/, "", s); return s } function qemushift( n) { n = basen($6) if (n ~ qimg) return 0 return n ~ qint ? 1 : 0 }' # The name of the program pid $1 is running, empty if it is gone. Fed to the # prologue above as a one-row listing, so the shift is decided in one place. proc_program_name() { # proc_program_name local a args= { while IFS= read -r -d '' a; do args="${args:+$args }$a"; done <"/proc/$1/cmdline"; } 2>/dev/null test -n "$args" || return 1 awk -v qint="$QEMU_INTERP_RE" -v qimg="$QEMU_IMAGE_TOOL_RE" "$AWK_PROC_NAMES"' { print basen($(6 + qemushift())) }' <<<"1 1 1 0 S $args" } # Every process as "PID PPID PGID ELAPSED S COMMAND", header first. A Fedora # build root has no procps, and an empty list reads as "nothing running" (#1021). ps_snapshot() { local snap # POSIX keywords, so the ps route holds on macOS too; a ps that lists nothing # (hidepid, a locked-down container) is no better than an absent one. if snap=$(ps -A -o pid,ppid,pgid,etime,state,args 2>/dev/null | awk 'NR > 1 { rows++ } { print } END { exit rows ? 0 : 1 }'); then printf '%s\n' "$snap" return 0 fi proc_snapshot && return 0 # Every consumer drops line 1, so the notice rides in the header's place. printf 'no process list: this host has neither ps nor a readable /proc\n' return 1 } # The same six columns out of /proc, in bash alone; elapsed as plain seconds. proc_snapshot() { local d stat rest arg args comm hz uptime local -a f local ws # spelled out of line: bash 3.2 fails to parse $'..' inside ${v//p/r} ws=$' \t\n\v\f\r' test -r /proc/self/stat || return 1 hz=$(getconf CLK_TCK 2>/dev/null) || hz= # A zero or non-numeric tick would abort the shell in the division below. case "$hz" in '' | 0 | *[!0-9]*) hz=100 ;; esac read -r uptime _ /dev/null || return 1 printf 'PID PPID PGID ELAPSED S COMMAND\n' for d in /proc/[0-9]*; do # Braced: a failed open reports to the caller's stderr, not the redirect. { read -r stat <"$d/stat"; } 2>/dev/null || continue # comm may hold spaces and parens; every field past it is numeric. rest=${stat##*') '} comm=${stat#*(} comm=${comm%)*} read -ra f <<<"$rest" || continue test "${#f[@]}" -ge 20 || continue # short read: the process is going away args= # Whitespace inside an argv would split the row or shift the columns the # consumers match on, which ps avoids by mapping those bytes away. { while IFS= read -r -d '' arg; do args="${args:+$args }${arg//["$ws"]/ }" done <"$d/cmdline"; } 2>/dev/null || true printf '%s %s %s %s %s %s\n' "${d#/proc/}" "${f[1]}" "${f[2]}" \ "$(((${uptime%%.*} * hz - f[19]) / hz))" \ "${f[0]}" "${args:-[$comm]}" done } # List processes a hung test may have left running, one per line. $1 is the test's # process group; $2 selects "group" (that group's members, whatever their name), # "others" (engine and fixture processes outside it, which under "make check -j" # belong to healthy siblings) or "named" (every engine and fixture process on the # host). Read-only: it never signals anything. list_stray_processes() { local pgid=${1:-0} mode=${2:-group} if is_windows; then # No process groups here, so every mode gives the same host-wide list. No # slash switches: without MSYS_NO_PATHCONV a /fi would be rewritten to a # path. Plain output is Image Name + PID, which is all we need. test "$mode" != others || return 0 tasklist 2>/dev/null | grep -Ei "$ENGINE_IMAGE_RE|^python" || true else # Fields 6 and 7 are the command and its first argument (the interpreter # and its script, for the Python fixtures). ps_snapshot | awk -v pg="$pgid" -v mode="$mode" -v eng="$ENGINE_EXE_RE" -v srv="$FIXTURE_SERVER_RE" \ -v qint="$QEMU_INTERP_RE" -v qimg="$QEMU_IMAGE_TOOL_RE" \ "$AWK_PROC_NAMES"' NR == 1 { print; next } { ingroup = (pg > 0 && $3 == pg) q = qemushift() c = basen($(6 + q)) s = basen($(7 + q)) named = (c ~ eng || s ~ srv) if (mode == "group" ? ingroup : \ mode == "named" ? named : (named && !ingroup)) print }' || true fi } # Kill engine processes a finished test left behind, and print what was found so # the leak is attributed to the test that just ran: an orphaned httrack.exe spins # and starves the runner, which is how the Windows job dies of "lost # communication" rather than a clean timeout. SERIAL RUNNERS ONLY -- it matches by # name host-wide, so under a parallel "make check" it would kill a healthy # sibling's engine. Only the engine images: a runner may run python.exe of its # own, and tasklist alone cannot tell that one from a leaked fixture server. reap_leftover_processes() { local label=${1:-} left if is_windows; then left=$(tasklist 2>/dev/null | grep -Ei "$ENGINE_IMAGE_RE" || true) else left=$(list_stray_processes 0 named | awk 'NR > 1') fi test -n "$left" || return 0 printf '::warning::%s left processes behind\n' "$label" printf '%s\n' "$left" if is_windows; then taskkill_engines else printf '%s\n' "$left" | awk '{ print $1 }' | while read -r p; do kill -9 "$p" 2>/dev/null || true; done fi return 0 } # Pids of engine processes in process group $1. Scoped to the group because the # caller signals them, and under "make check -j" a global match would abort a # healthy sibling test's engine. Matches the executable basename only, so a # harness script whose *path* contains "httrack" is not mistaken for the engine. list_engine_pids() { local pgid=${1:-0} test "$pgid" -gt 0 2>/dev/null || return 0 ps_snapshot | awk -v pg="$pgid" -v eng="$ENGINE_EXE_RE" \ -v qint="$QEMU_INTERP_RE" -v qimg="$QEMU_IMAGE_TOOL_RE" "$AWK_PROC_NAMES"' NR > 1 && $3 == pg { if (basen($(6 + qemushift())) ~ eng) print $1 }' } # Ask the wedged test's engine processes for a stack. What is obtainable differs # per platform, and each branch says which one it took: a dump that silently # produces nothing reads as coverage when it is not. # # Linux httrack's own SIGABRT handler (sig_fatal in httrack.c) symbolizes via # addr2line and writes to the process's OWN stderr, so the trace lands in # whatever log the test gave it -- the caller must salvage those logs. # It walks only the signalled thread, and it aborts the process. # macOS htsbacktrace.c gates that handler on __linux, so SIGABRT would yield # "No stack trace available on this OS". sample(1) is OS-provided, needs # no root, covers every thread and leaves the process running. # # gdb -p is not an option on either: it is EPERM from a sibling under yama # ptrace_scope=1, which is how a harness watchdog necessarily invokes it. request_engine_backtraces() { local p os local sent='' abrt='' os=$(uname -s 2>/dev/null || echo unknown) for p in $(list_engine_pids "$1"); do sent=1 test ! -r "/proc/$p/wchan" || printf 'pid %s blocked in: %s\n' "$p" "$(cat "/proc/$p/wchan")" case "$os" in Linux) kill -ABRT "$p" 2>/dev/null && abrt=1 ;; Darwin) if test -x /usr/bin/sample; then # Drop the trailing image map: ~40 lines of load addresses that # say nothing about the hang. /usr/bin/sample "$p" 2 -mayDie -file /dev/stdout 2>&1 | sed '/^Binary Images:/,$d' || printf 'pid %s: sample(1) failed\n' "$p" else printf 'pid %s: no stack, /usr/bin/sample is absent\n' "$p" fi ;; *) printf 'pid %s: no stack mechanism known for %s\n' "$p" "$os" ;; esac done test -n "$sent" || printf 'no engine process left to ask (see the list above)\n' test -z "$abrt" || sleep 3 # let the handlers symbolize and print } # Stack of every native engine process, through cdb. Windows has neither half of # the POSIX route: htsbacktrace.c is gated on __linux, and MSYS signals never # reach a native httrack.exe. cdb ships with the SDK on the runner image but that # is incidental, so probe for it and say so when it is missing. The MSVC build # writes PDBs beside the binaries, which the test step already puts on PATH, so # frames resolve to names. Opt-in (HTTRACK_EXCLUSIVE_HOST), because with no # process group to scope by it stacks every engine on the host: under a parallel # run that freezes each sibling's for up to 60s, and a cdb killed by its own # timeout can take its debuggee with it. dump_windows_stacks() { local c p local cdb='' found='' if test -z "${HTTRACK_EXCLUSIVE_HOST:-}"; then printf 'no stacks: other tests are running on this host\n' return 0 fi for c in "$(command -v cdb 2>/dev/null)" \ "/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/cdb.exe" \ "/c/Program Files (x86)/Windows Kits/10/Debuggers/x86/cdb.exe"; do test -n "$c" || continue test -x "$c" || continue cdb=$c break done if test -z "$cdb"; then printf 'no stack: cdb.exe is not in the SDK Debuggers directories or on PATH\n' return 0 fi for p in $(tasklist 2>/dev/null | grep -Ei "$ENGINE_IMAGE_RE" | awk '{print $2}'); do found=1 printf -- '--- cdb stack of pid %s ---\n' "$p" # Bounded, so a debugger that wedges cannot become the new hang. "qd" # detaches and leaves the process for kill_tree. run_with_timeout 60 "$cdb" -p "$p" -c '~*kv; qd' 2>&1 || printf 'cdb failed or timed out on pid %s\n' "$p" done test -n "$found" || printf 'no engine process left to ask (see the list above)\n' } # Report what a wedged test left behind, into the log the harness keeps: the test # that blew its budget, the processes still running, and a stack for each engine # process. $1 is the timed-out job's pid (its process group leader on POSIX). # Never deletes, so it is safe under a parallel "make check". dump_hang_diagnostics() { local pid=$1 label=${2:-?} secs=${3:-?} printf '\n===== TIMEOUT: %s exceeded its %ss budget =====\n' "$label" "$secs" if is_windows; then printf -- '--- still running ---\n' list_stray_processes 0 group printf -- '--- stacks (via cdb) ---\n' dump_windows_stacks else printf -- '--- the test'\''s own process tree (group %s) ---\n' "$pid" list_stray_processes "$pid" group # Under "make check -j" these belong to healthy siblings, so they are # reported but never signalled; a leaked orphan also lands here. printf -- '--- other engine processes on this host ---\n' list_stray_processes "$pid" others printf -- '--- stacks (via the engine SIGABRT handler) ---\n' request_engine_backtraces "$pid" fi printf -- '===== end of diagnostics: %s =====\n' "$label" } httrack-3.49.21/tests/testlib.sh0000644000175000017500000006031115237104167012166 #!/bin/bash # # Helpers shared by the crawl tests. Sourced, not run: it resolves $testdir and # $top_srcdir, and leaves shell options to the caller, since the suite drivers # source it too and errexit would end them on the first failing test. # shellcheck disable=SC2034 # resolved here for the caller, not used here testdir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # Relative, as each test spelled it before: 100 hands this path straight to # python.exe, which cannot resolve an absolute MSYS one. make check exports its # own value, so the default only serves a hand-run and the Windows suite. : "${top_srcdir:=..}" fail() { echo "FAIL: $*" >&2 exit 1 } # 77 is automake's "skipped", not a failure. skip() { echo "$*; skipping" >&2 exit 77 } # Guard form, so a bare `is_windows && skip ...` cannot end an errexit test that # is merely not on Windows. skip_on_windows() { ! is_windows || skip "$*"; } # Assertions, each printing what it wanted beside what arrived: a bare # `|| exit 1` reds a test without naming the value that differed. assert_eq() { # assert_eq WANT GOT [LABEL] test "$1" = "$2" || fail "${3:+$3: }expected [$1], got [$2]" } # Unanchored ERE: ^ and $ are the whole subject's ends, not a line's. # Keep $1 unquoted here, or bash 3.2 matches it as a literal string. assert_match() { # assert_match RE TEXT [LABEL] [[ $2 =~ $1 ]] || fail "${3:+$3: }no match for /$1/ in: $2" } assert_file() { test -f "$1" || fail "${2:+$2: }missing file: $1"; } # Every step skip_if_out_of_budget projects against ran. A skip is an exit, so a # loop that quietly ran fewer paces against a count that is a lie. assert_steps_ran() { # assert_steps_ran WANT GOT assert_eq "$1" "$2" "steps the budget is paced against" } # Run engine self-test NAME: stdout must equal WANT, status must be 0 (which a # `test "$(...)" = ...` cannot see). expect_ok takes a command, for a real -O. assert_selftest() { # assert_selftest WANT NAME [ARGS...] local want=$1 name=$2 got rc=0 shift 2 got=$(httrack -O /dev/null "-#test=$name" "$@") || rc=$? test "$rc" -eq 0 || fail "-#test=$name $*: exited $rc, output: $got" test "$got" = "$want" || fail "-#test=$name $*: expected [$want], got [$got]" } # Absolute path to httrack, since make check's relative ../src breaks once a test # cd's away. assert_selftest runs the bare name, so a test that cd's calls this. httrack_path() { local p dir p=$(command -v httrack) || fail "no httrack in PATH" # Assigned, so a failed cd is named here instead of yielding a bare /httrack. dir=$(cd "$(dirname "$p")" && pwd) || fail "cannot reach $(dirname "$p")" printf '%s\n' "$dir/$(basename "$p")" } # A literal, not $'..': Apple's bash 3.2 loses quote state on that inside a # parameter expansion and the whole file dies of "unexpected EOF". TESTLIB_NL=' ' # First line of $1. A "| head -1" would close the pipe early and, under pipefail, # SIGPIPE the producer into a spurious failure. firstline() { printf '%s\n' "${1%%"$TESTLIB_NL"*}"; } # LIFO teardown: cleanup_push CMD ARG... registers a command and its arguments, # expanded now, run in reverse on the way out; the first call installs both traps, # the signal half of which most tests never wrote (#773). A flat argv, not a shell # snippet, so no eval -- wrap a redirection or a late value in a function. # Self-preserving, since 172 sources a driver that sources this file a second time. CLEANUP_ARGV=(${CLEANUP_ARGV[@]+"${CLEANUP_ARGV[@]}"}) CLEANUP_FRAMES=(${CLEANUP_FRAMES[@]+"${CLEANUP_FRAMES[@]}"}) cleanup_push() { CLEANUP_FRAMES+=("${#CLEANUP_ARGV[@]}") CLEANUP_ARGV+=("$@") test "${#CLEANUP_FRAMES[@]}" -eq 1 || return 0 trap 'set +e; run_cleanups' EXIT # No PIPE: bash cannot trap a signal it inherited as ignored, which is how the # runners hand SIGPIPE down, and a real one drains via the EXIT trap (#1136). trap 'set +e; run_cleanups; exit 1' HUP INT QUIT TERM } # Drains the stack, so the EXIT trap after a signal is a no-op. Both slices carry # the `[@]+` guard: on bash 3.2 an empty-array expansion under `set -u` is fatal. run_cleanups() { local i start for ((i = ${#CLEANUP_FRAMES[@]} - 1; i >= 0; i--)); do start=${CLEANUP_FRAMES[i]} ${CLEANUP_ARGV[@]+"${CLEANUP_ARGV[@]:start}"} || true CLEANUP_ARGV=(${CLEANUP_ARGV[@]+"${CLEANUP_ARGV[@]:0:start}"}) done CLEANUP_FRAMES=() } # Python 3 interpreter, or empty: Windows only installs python.exe, and a bare # "python" may be 2.x or the Store stub. find_python() { local py for py in "${PYTHON:-}" python3 python; do test -n "$py" || continue "$py" -c 'import sys; sys.exit(sys.version_info[0] != 3)' 2>/dev/null || continue printf '%s\n' "$py" return 0 done return 1 } # Native form of a path: a non-MSYS binary cannot resolve Git Bash's /d/a/... ones. nativepath() { if is_windows && command -v cygpath >/dev/null 2>&1; then cygpath -m "$1" else printf '%s\n' "$1" fi } # POSIX form of a path. Anything MSYS splits on a colon needs it, a PATH entry # below the drive-letter TMPDIR above all. posixpath() { if is_windows && command -v cygpath >/dev/null 2>&1; then cygpath -u "$1" else printf '%s\n' "$1" fi } # Key before cert in $1/both.pem, the single path load_cert_chain() takes. make_tls_pem() { local dir=$1 src src=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) cat "$src/server.key" "$src/server.crt" >"$dir/both.pem" || { echo "FAIL: could not write $dir/both.pem from the fixture in $src" >&2 exit 1 } } # Longest surviving run of char $2 in file $1, or 0: the length a field was # clipped to, read back out of a binary artifact. runlen() { grep -ao "$2\\+" "$1" | awk '{ print length($0) }' | sort -rn | head -n1 || true } # Run an engine self-test and require its "