Compare commits

..

2 Commits

Author SHA1 Message Date
Xavier Roche
cf483a24e4 Remove commented-out code across the engine
Sweep of ~650 lines of //-disabled statements, declarations, and calls
(plus three /*-wrapped dead blocks in htscoremain.c and htscore.c and
the MFC pApp remnant in htsserver.c). Prose comments stay, including
labels that describe live code; usage examples and config-knob docs
(HTS_TRACE_MALLOC, the htsweb.c DEBUG toggle) were kept. Insertions are
clang-format rewraps of live lines that became touched by the deletions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-06 10:42:28 +02:00
Xavier Roche
abaea566bd Remove dead #if 0 blocks and their orphaned satellites
All #if 0 code that has been disabled for years goes away: the sig_ask
interactive signal handlers, check_rate, HTS_TOTAL_RECV_CHECK, the
make_empty_index no-op body (function removed with its only call site),
the htscharset sample main(), the dead FTP CWD sequence, and assorted
disabled fragments in the parser and engine. Blocks with a live #else
keep that branch. The htsweb.c DEBUG toggle stays: its #else arm is the
live definition and the macro is used.

The htsparse.c 3.43 note about not post-excluding authorized links is
kept as a plain comment; commented-out declarations and calls that only
served the removed blocks go with them. French comments rewrapped by
the formatter were translated in passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-06 10:16:21 +02:00
40 changed files with 27 additions and 846 deletions

View File

@@ -278,45 +278,6 @@ jobs:
if: failure()
run: cat tests/test-suite.log 2>/dev/null || true
# libFuzzer smoke: build the fuzz/ harnesses over the pure hostile-input
# parsers and replay each seed corpus under ASan+UBSan+LeakSanitizer. Replay
# (not open-ended mutation) keeps CI deterministic -- it can't hit strjoker's
# catastrophic backtracking -- and pins the regression seeds for the bugs the
# fuzzers found. Deep discovery is a maintainer / OSS-Fuzz activity.
fuzz:
name: fuzz (libFuzzer corpus replay, clang)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Install build dependencies
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential clang autoconf automake libtool autoconf-archive \
zlib1g-dev libssl-dev
- name: Configure (fuzzers, static)
run: |
set -euo pipefail
autoreconf -fi
./configure CC=clang \
CFLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g -O1 -fno-omit-frame-pointer" \
LDFLAGS="-fsanitize=address,undefined" \
--enable-fuzzers --disable-shared
- name: Build
run: make -j"$(nproc)"
- name: Replay corpora
env:
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1:halt_on_error=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: bash fuzz/run-fuzzers.sh fuzz check
# Optional-dependency build: compile and test with HTTPS/OpenSSL disabled --
# the configuration users on minimal systems build, and one libssl is not even
# installed here so configure cannot silently re-enable it. The matrix above

View File

@@ -1,5 +1,5 @@
SUBDIRS = src man m4 libtest templates lang html tests fuzz
SUBDIRS = src man m4 libtest templates lang html tests
ACLOCAL_AMFLAGS = -I m4

View File

@@ -102,8 +102,7 @@ AX_CHECK_COMPILE_FLAG([-Wignored-qualifiers], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -
AX_CHECK_COMPILE_FLAG([-Werror=attribute-warning], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=attribute-warning"])
AX_CHECK_COMPILE_FLAG([-Werror=user-defined-warnings], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=user-defined-warnings"])
AX_CHECK_COMPILE_FLAG([-fstrict-aliasing -Wstrict-aliasing], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstrict-aliasing -Wstrict-aliasing"])
AX_CHECK_COMPILE_FLAG([-fstack-protector-strong], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector-strong"],
[AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"])])
AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"])
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"])
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"])
AX_CHECK_LINK_FLAG([-Wl,--discard-all], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--discard-all"])
@@ -111,13 +110,6 @@ AX_CHECK_LINK_FLAG([-Wl,--no-undefined], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,
AX_CHECK_LINK_FLAG([-Wl,-z,relro,-z,now], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,relro,-z,now"])
AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,noexecstack"])
# Fortify libc calls (=3, else =2) unless the toolchain predefines it; skip
# sanitizer builds, whose interceptors want the unfortified calls.
case "$CFLAGS" in
*-fsanitize=*) ;;
*) AX_ADD_FORTIFY_SOURCE ;;
esac
# Force libc back into DT_NEEDED for libraries that reach it only through
# libhttrack (libhtsjava, the libtest callbacks), but only with a GNU-style
# linker; Apple ld rejects these flags and links libSystem unconditionally.
@@ -318,37 +310,6 @@ AC_ARG_ENABLE([online-unit-tests],
])
AC_SUBST(ONLINE_UNIT_TESTS,$online_unit_tests)
## libFuzzer harnesses (fuzz/); requires clang
AC_MSG_CHECKING(whether to build fuzzers)
AC_ARG_ENABLE([fuzzers],
[AS_HELP_STRING([--enable-fuzzers],[Build libFuzzer harnesses in fuzz/ (requires clang) @<:@default=no@:>@])],
[
case "${enableval}" in
no|yes)
fuzzers=$enableval
AC_MSG_RESULT($enableval)
;;
*)
AC_MSG_ERROR(bad value for fuzzers, expected yes/no)
;;
esac
],
[
fuzzers=no
AC_MSG_RESULT(no)
])
if test x"$fuzzers" = x"yes"; then
# Instrument the whole build for coverage; harnesses link -fsanitize=fuzzer.
AX_CHECK_COMPILE_FLAG([-fsanitize=fuzzer-no-link],
[DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fsanitize=fuzzer-no-link"],
[AC_MSG_ERROR([--enable-fuzzers requires libFuzzer support (clang)])])
# clang's static sanitizer runtimes clash with -Wl,--no-undefined on the .so.
if test x"$enable_shared" != x"no"; then
AC_MSG_ERROR([--enable-fuzzers requires --disable-shared])
fi
fi
AM_CONDITIONAL([FUZZERS], [test x"$fuzzers" = x"yes"])
# Final output
AC_CONFIG_FILES([
Makefile
@@ -360,6 +321,5 @@ lang/Makefile
html/Makefile
libtest/Makefile
tests/Makefile
fuzz/Makefile
])
AC_OUTPUT

View File

@@ -1,38 +0,0 @@
# 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
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
# 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/url/http-url.txt corpus/url/relative-path.txt \
corpus/url/regress-file-empty-path.txt corpus/url/regress-long-path-abort.txt

View File

@@ -1,15 +0,0 @@
# 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/<target>/`; a crash reproducer is replayed with `fuzz/fuzz-url crash-file`.

View File

@@ -1 +0,0 @@
café naďve ¤

View File

@@ -1 +0,0 @@
コンピュータ

Binary file not shown.

View File

@@ -1 +0,0 @@
&amp;&lt;&gt;&#65;&#x2603;&eacute;&notarealentity;&#xFFFFFFFF;

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
**((

View File

@@ -1 +0,0 @@
xn--bcher-kva.example.com

View File

@@ -1 +0,0 @@
büchev.ä¾å­bücheple

View File

@@ -1 +0,0 @@
bücher.例子.example

View File

@@ -1 +0,0 @@
<html><head><meta charset="utf-8"></head><body>x</body></html>

View File

@@ -1 +0,0 @@
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

View File

@@ -1 +0,0 @@
%41%zz%%20%c3%a9+%2e%2e%2f

View File

@@ -1 +0,0 @@
http://user:pass@www.example.com:8080/a/b/../c/./d.html?q=1#frag

View File

@@ -1 +0,0 @@
file://

View File

@@ -1 +0,0 @@
ftpumŠ[/../e0O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._f9O_i../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/i<>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_im<69>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/9O_imÙ<6D>Š<EFBFBD>W/../O/../

View File

@@ -1 +0,0 @@
ftp://ftp.example.com/pub/../file.txt

View File

@@ -1,84 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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;
}

View File

@@ -1,51 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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;
}

View File

@@ -1,65 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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;
}

View File

@@ -1,47 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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;
}

View File

@@ -1,40 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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
<meta> 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;
}

View File

@@ -1,53 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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;
}

View File

@@ -1,49 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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;
}

View File

@@ -1,51 +0,0 @@
/* ------------------------------------------------------------ */
/*
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 <http://www.gnu.org/licenses/>.
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 <stddef.h>
#include <stdint.h>
#include <string.h>
#include "htsbase.h"
/* Heap NUL-terminated copy of the fuzzer input, so ASan bounds every read. */
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

View File

@@ -1,41 +0,0 @@
#!/bin/bash
# Drive every built harness against its seed corpus.
# run-fuzzers.sh <build-fuzz-dir> check deterministic replay (CI smoke)
# run-fuzzers.sh <build-fuzz-dir> [seconds] timed mutation run (discovery)
# Replay is crash/leak-only and never mutates, so it can't hit strjoker's
# catastrophic backtracking; the timed mode can, hence the per-unit -timeout.
set -euo pipefail
srcdir=$(cd "$(dirname "$0")" && pwd)
bld=${1:?usage: run-fuzzers.sh <build-fuzz-dir> [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

View File

@@ -1,119 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_ADD_FORTIFY_SOURCE
#
# DESCRIPTION
#
# Check whether -D_FORTIFY_SOURCE=2 can be added to CPPFLAGS without macro
# redefinition warnings, other cpp warnings or linker. Some distributions
# (such as Ubuntu or Gentoo Linux) enable _FORTIFY_SOURCE globally in
# their compilers, leading to unnecessary warnings in the form of
#
# <command-line>:0:0: error: "_FORTIFY_SOURCE" redefined [-Werror]
# <built-in>: note: this is the location of the previous definition
#
# which is a problem if -Werror is enabled. This macro checks whether
# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2
# to CPPFLAGS.
#
# Newer mingw-w64 msys2 package comes with a bug in
# headers-git-7.0.0.5546.d200317d-1. It broke -D_FORTIFY_SOURCE support,
# and would need -lssp or -fstack-protector. See
# https://github.com/msys2/MINGW-packages/issues/5803. Try to actually
# link it.
#
# LICENSE
#
# Copyright (c) 2017 David Seifert <soap@gentoo.org>
# Copyright (c) 2019, 2023 Reini Urban <rurban@cpan.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[
ac_save_cflags=$CFLAGS
ac_cwerror_flag=yes
AX_CHECK_COMPILE_FLAG([-Werror],[CFLAGS="$CFLAGS -Werror"])
ax_add_fortify_3_failed=
AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=3 to CPPFLAGS])
AC_LINK_IFELSE([
AC_LANG_PROGRAM([],
[[
#ifndef _FORTIFY_SOURCE
return 0;
#else
_FORTIFY_SOURCE_already_defined;
#endif
]]
)],
AC_LINK_IFELSE([
AC_LANG_SOURCE([[
#define _FORTIFY_SOURCE 3
#include <string.h>
int main(void) {
char *s = " ";
strcpy(s, "x");
return strlen(s)-1;
}
]]
)],
[
AC_MSG_RESULT([yes])
CFLAGS=$ac_save_cflags
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=3"
], [
AC_MSG_RESULT([no])
ax_add_fortify_3_failed=1
],
),
[
AC_MSG_RESULT([no])
ax_add_fortify_3_failed=1
])
if test -n "$ax_add_fortify_3_failed"
then
AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CPPFLAGS])
AC_LINK_IFELSE([
AC_LANG_PROGRAM([],
[[
#ifndef _FORTIFY_SOURCE
return 0;
#else
_FORTIFY_SOURCE_already_defined;
#endif
]]
)],
AC_LINK_IFELSE([
AC_LANG_SOURCE([[
#define _FORTIFY_SOURCE 2
#include <string.h>
int main(void) {
char *s = " ";
strcpy(s, "x");
return strlen(s)-1;
}
]]
)],
[
AC_MSG_RESULT([yes])
CFLAGS=$ac_save_cflags
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2"
], [
AC_MSG_RESULT([no])
CFLAGS=$ac_save_cflags
],
),
[
AC_MSG_RESULT([no])
CFLAGS=$ac_save_cflags
])
fi
])

View File

@@ -910,19 +910,19 @@ char *hts_convertStringUTF8ToIDNA(const char *s, size_t size) {
/* Reader: can read bytes up to j */
#define RD ( utfSeq < j ? segData[utfSeq++] : -1 )
/* Writer: a malformed sequence abandons the encode (NULL) */
#define WR(C) \
do { \
if ((C) != -1) { \
/* copy character */ \
assertf(segOutputSize < segSize); \
segInt[segOutputSize++] = (C); \
} else { \
freet(segInt); \
FREE_BUFFER(); \
return NULL; \
} \
} while (0)
/* Writer: upon error, return FFFD (replacement character) */
#define WR(C) do { \
if ((C) != -1) { \
/* copy character */ \
assertf(segOutputSize < segSize); \
segInt[segOutputSize++] = (C); \
} \
/* In case of error, abort. */ \
else { \
FREE_BUFFER(); \
return NULL; \
} \
} while(0)
/* Read/Write Unicode character. */
READ_UNICODE(RD, WR);
@@ -1144,7 +1144,7 @@ int hts_isStringUTF8(const char *s, size_t size) {
/* Reader: can read bytes up to j */
#define RD ( i < size ? data[i++] : -1 )
/* Writer: a malformed sequence means the string is not UTF-8 (return 0) */
/* Writer: upon error, return FFFD (replacement character) */
#define WR(C) if ((C) == -1) { return 0; }
/* Read Unicode character. */

View File

@@ -286,7 +286,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
if (!unique)
max = (int) strlen(chaine);
else /* *(a) only match a (not aaaaa) */
max = strnotempty(chaine) ? 1 : 0; /* empty chaine: no char to eat */
max = 1;
while(i < (int) max) {
if (pass[(int) (unsigned char) chaine[i]]) { // caractère autorisé
if ((adr = strjoker(chaine + i + 1, joker + jmp, size, size_flag))) {

View File

@@ -2497,10 +2497,6 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
// effacer adrfil->adr et adrfil->fil
adrfil->adr[0] = adrfil->fil[0] = '\0';
// Reject an over-long URL: a root-relative path is copied whole into fil[].
if (strlen(url) >= HTS_URLMAXSIZE * 2)
return -1;
#if HDEBUG
printf("protocol: %s\n", url);
#endif
@@ -2576,7 +2572,7 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
if (*p == '/' || *p == '\\') { /* adrfil->file:///.. */
strcatbuff(adrfil->fil, p); // fichier local ; adrfil->adr="#"
} else {
if (*p == '\0' || p[1] != ':') { /* empty path: not a DOS drive letter */
if (p[1] != ':') {
strcatbuff(adrfil->fil, "//"); /* adrfil->file://server/foo */
strcatbuff(adrfil->fil, p);
} else {

View File

@@ -579,16 +579,15 @@ static int st_filter(httrackp *opt, int argc, char **argv) {
int matched;
(void) opt;
if (argc < 1) {
if (argc < 2) {
fprintf(stderr, "filter: needs a filter pattern and a string\n");
return 1;
}
/* exact-size heap copies so a sanitizer traps an over-read; a missing
subject means "" (not reachable as a CLI arg) */
str = strdupt(argc >= 2 ? argv[1] : "");
/* exact-size heap copies so a sanitizer traps any over-read of the pattern */
str = strdupt(argv[1]);
pat = strdupt(argv[0]);
matched = strjoker(str, pat, NULL, NULL) != NULL;
printf("%s does %s %s\n", str, matched ? "match" : "NOT match", argv[0]);
printf("%s does %s %s\n", argv[1], matched ? "match" : "NOT match", argv[0]);
freet(str);
freet(pat);
return 0;
@@ -1095,33 +1094,6 @@ static int st_resolve(httrackp *opt, int argc, char **argv) {
return 0;
}
/* Split a URL into (adr, fil), or print "error" if rejected. A second arg pads
the URL with that many 'a's to reach lengths a CLI arg can't. */
static int st_identurl(httrackp *opt, int argc, char **argv) {
lien_adrfil af;
char *url;
size_t len, pad = 0;
(void) opt;
if (argc < 1) {
fprintf(stderr, "identurl: needs a URL\n");
return 1;
}
if (argc >= 2)
pad = (size_t) atoi(argv[1]);
len = strlen(argv[0]);
url = malloct(len + pad + 1);
memcpy(url, argv[0], len);
memset(url + len, 'a', pad);
url[len + pad] = '\0';
if (ident_url_absolute(url, &af) >= 0)
printf("adr=%s fil=%s\n", af.adr, af.fil);
else
printf("error\n");
freet(url);
return 0;
}
/* Extra args are key=value: adr= cdispo= statuscode= status= strip= urlhack=
no-www= no-slash= no-query= n83= type=, plus repeatable prior=adr|fil|sav
registering an already-crawled link (dedup/collision paths). */
@@ -2160,7 +2132,6 @@ static const struct selftest_entry {
st_relative},
{"resolve", "<link> <adr> <fil>", "resolve a link against an origin",
st_resolve},
{"identurl", "<url>", "split an absolute URL into (adr, fil)", st_identurl},
{"header", "<raw-header-line> ...", "response header-line parsing",
st_header},
{"savename", "<fil> <content-type> [key=value ...]",

View File

@@ -12,11 +12,6 @@ match() {
nomatch() {
test "$(httrack -O /dev/null -#test=filter "$1" "$2")" == "$2 does NOT match $1" || exit 1
}
# single-arg call means an empty subject (unreachable as a CLI arg); '*(' used
# to force max=1 and over-read past it.
nomatch_empty() {
test "$(httrack -O /dev/null -#test=filter "$1")" == " does NOT match $1" || exit 1
}
# bare star matches everything
match '*' 'anything/at/all'
@@ -127,7 +122,3 @@ nomatch '*[file]end' 'foo?xend'
nomatch '*[name]X' 'abc?X'
match '*[file]' 'foo?x=1' # trailing query: tolerated, as for *.aspx
match '*.aspx' 'page.aspx?y=2'
# empty subject against a unique-match allow-all pattern (heap over-read regress)
nomatch_empty '*(('
nomatch_empty '**(('

View File

@@ -1,27 +0,0 @@
#!/bin/bash
#
set -euo pipefail
# ident_url_absolute splits a raw URL into (adr, fil), the first parser to touch
# it. -#test=identurl <url> [pad] prints "adr=.. fil=.." or "error"; pad appends
# N 'a's, reaching lengths a CLI arg can't.
split() {
test "$(httrack -O /dev/null -#test=identurl "$1")" == "$2" || exit 1
}
split 'http://www.example.com/a/b/../c.html' 'adr=www.example.com fil=/a/c.html'
split 'ftp://ftp.example.com/pub/file.txt' 'adr=ftp://ftp.example.com fil=/pub/file.txt'
split 'file:///etc/hostname' 'adr=file:// fil=/etc/hostname'
# empty-path file:// used to read one byte past the URL (p[1] with *p=0)
split 'file://' 'adr=file:// fil=//'
# a root-relative path is copied whole into fil[HTS_URLMAXSIZE*2], so a URL at
# the buffer size is the tightest overflow; it must be rejected, not abort.
split_pad() {
test "$(httrack -O /dev/null -#test=identurl "$1" "$2")" == "$3" || exit 1
}
split_pad '/' 2047 'error' # 1 + 2047 = 2048 = HTS_URLMAXSIZE*2
split_pad 'http://h/' 3000 'error'

View File

@@ -8,8 +8,8 @@ set -euo pipefail
enc() { test "$(httrack -O /dev/null -#test=idna-encode "$1")" == "$2" || exit 1; }
dec() { test "$(httrack -O /dev/null -#test=idna-decode "$1")" == "$2" || exit 1; }
# a malformed encode input must be rejected (empty output), not encoded or leaked.
enc_bad() { test -z "$(httrack -O /dev/null -#test=idna-encode "$1" 2>/dev/null)" || exit 1; }
# crash probe: malformed ACE input must exit cleanly, not abort.
runs() { httrack -O /dev/null -#test=idna-decode "$1" >/dev/null 2>&1 || exit 1; }
# encode
enc 'www.café.com' 'www.xn--caf-dma.com'
@@ -33,9 +33,6 @@ enc 'xn--already-encoded.com' 'xn--already-encoded.com'
# an empty punycode payload decodes back to the bare xn-- label
dec 'xn--' 'xn--'
# malformed ACE payloads decode to a stable (garbage) string, not a crash
dec 'xn--!!!' '㚯'
dec 'xn--already-encoded.com' 'ǮalǭǮreaǭǫdy.com'
# second label has a truncated UTF-8 sequence: used to leak the segment buffer.
enc_bad "$(printf 'b\xc3\xbcchev.\xe4\xbe\x8b\xe5\xad\x62\xc3\xbccheple')"
# malformed ACE payloads (invalid base-36, garbage) must not crash
runs 'xn--!!!'
runs 'xn--already-encoded.com'

View File

@@ -40,7 +40,6 @@ TESTS = \
01_engine-hashtable.test \
01_engine-header.test \
01_engine-idna.test \
01_engine-identurl.test \
01_engine-escape-room.test \
01_engine-inplace-escape.test \
01_engine-java.test \