Compare commits
145 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77d03052a6 | ||
|
|
628fc70727 | ||
|
|
7ff60e9de7 | ||
|
|
4588831dcd | ||
|
|
adbc46a5b8 | ||
|
|
249b96b975 | ||
|
|
d8402d7ad2 | ||
|
|
b268caa220 | ||
|
|
fb59dd6aba | ||
|
|
ef100363a7 | ||
|
|
c3e1a202c1 | ||
|
|
f55f68c94e | ||
|
|
749de004c7 | ||
|
|
09e3e1f62b | ||
|
|
4364e6c93e | ||
|
|
35319c05be | ||
|
|
e4fbe856e5 | ||
|
|
4f49eec86b | ||
|
|
f8ed3e771f | ||
|
|
4231a141d3 | ||
|
|
314ee45350 | ||
|
|
54d93200a4 | ||
|
|
6e98e33495 | ||
|
|
67c4668a3b | ||
|
|
e6015e29bb | ||
|
|
ba53bca32e | ||
|
|
5b59cdb159 | ||
|
|
c520d81f6b | ||
|
|
0748fa44e9 | ||
|
|
0ced83ccfc | ||
|
|
171ffb0754 | ||
|
|
e12fe63246 | ||
|
|
ff266a0e61 | ||
|
|
dfc0efff3a | ||
|
|
a0622bcd04 | ||
|
|
f5fbd1a82e | ||
|
|
496e85a3ac | ||
|
|
d4b77e53dc | ||
|
|
507f3565e8 | ||
|
|
4df1434b56 | ||
|
|
d85d91f8c6 | ||
|
|
b16ffc7be2 | ||
|
|
defd6735f3 | ||
|
|
178f9156e5 | ||
|
|
ee5db0a9e6 | ||
|
|
edeada647c | ||
|
|
562f6790ec | ||
|
|
cbb2257847 | ||
|
|
0e95c58865 | ||
|
|
8184b45696 | ||
|
|
62ca6e087a | ||
|
|
7c6e5c3018 | ||
|
|
1878595043 | ||
|
|
057648e335 | ||
|
|
7a7206d7f1 | ||
|
|
e4df3b387c | ||
|
|
58ddc5a6b1 | ||
|
|
fb01ad6f65 | ||
|
|
1a211555d0 | ||
|
|
f2abfc36ef | ||
|
|
b2cd2a51d2 | ||
|
|
562cd1c867 | ||
|
|
a2a20ef684 | ||
|
|
bfe0a4a7f7 | ||
|
|
03c30e17ce | ||
|
|
1a45e0237b | ||
|
|
2a44dc1728 | ||
|
|
23e182281c | ||
|
|
3426ea35ea | ||
|
|
0274e016af | ||
|
|
22fcf9ffff | ||
|
|
8d7c9caf61 | ||
|
|
a7201b5d22 | ||
|
|
77182813a5 | ||
|
|
e2a57d6c07 | ||
|
|
502ce78413 | ||
|
|
a3e1d3dd40 | ||
|
|
8fcc9d8cae | ||
|
|
38eb901cea | ||
|
|
fbd825d4dd | ||
|
|
c36a5428d7 | ||
|
|
2945f0a5e4 | ||
|
|
2312d711e6 | ||
|
|
7bff8133bb | ||
|
|
e5985903e3 | ||
|
|
ed8a376278 | ||
|
|
10fa9315b3 | ||
|
|
67afcef6c1 | ||
|
|
8f453a4597 | ||
|
|
8f0489accd | ||
|
|
5ab645e370 | ||
|
|
a8712be127 | ||
|
|
c5cd0cc4c2 | ||
|
|
c553099b6d | ||
|
|
2d582348da | ||
|
|
f937b4a4ec | ||
|
|
e810fc79d0 | ||
|
|
c13c56d8bb | ||
|
|
73c99ac3a0 | ||
|
|
5bd0bba4e0 | ||
|
|
fa490d96da | ||
|
|
17128490f9 | ||
|
|
cf830dd5d3 | ||
|
|
1e3d51276f | ||
|
|
f1c3e1f5ef | ||
|
|
57b22af27a | ||
|
|
3db75afde4 | ||
|
|
103874dcd8 | ||
|
|
f546fc4ddf | ||
|
|
420cfdfd1d | ||
|
|
895049bfe1 | ||
|
|
9308adc16e | ||
|
|
ab3ccc4d66 | ||
|
|
12a1629bab | ||
|
|
602bdb0065 | ||
|
|
191b35106a | ||
|
|
fb786b0501 | ||
|
|
50282e52fa | ||
|
|
fd745e3f23 | ||
|
|
df11ef6bf3 | ||
|
|
4f4699b12b | ||
|
|
6de2187ee6 | ||
|
|
69c8069573 | ||
|
|
5ec25f3713 | ||
|
|
12039c54d4 | ||
|
|
c7767990cd | ||
|
|
0a1a4379c2 | ||
|
|
9479913232 | ||
|
|
8168aa3a45 | ||
|
|
72fa732f7e | ||
|
|
5a38473343 | ||
|
|
6745ec9842 | ||
|
|
eb4c1fe64c | ||
|
|
2d041866ed | ||
|
|
5f52c3d942 | ||
|
|
592f3dd154 | ||
|
|
620418a9c6 | ||
|
|
f3fa3a8b98 | ||
|
|
311b99afd4 | ||
|
|
ef81f5b488 | ||
|
|
22c506944d | ||
|
|
b127323a68 | ||
|
|
fac60dff4a | ||
|
|
264478c846 | ||
|
|
8f383f4caf |
3
.gitattributes
vendored
@@ -6,6 +6,3 @@
|
||||
# bash die on $'\r' on every line of them.
|
||||
*.test text eol=lf
|
||||
*.sh text eol=lf
|
||||
|
||||
# Scoped to this file so a union can never touch build logic.
|
||||
tests/tests-list.mk merge=union
|
||||
|
||||
34
.github/workflows/appstream-network.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# The per-PR lint runs --no-net so an httrack.com outage can't red an unrelated
|
||||
# PR; that also blinds it to a broken screenshot URL, which this job catches.
|
||||
name: appstream metainfo (networked)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "12 6 * * 1"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: appstreamcli validate (network)
|
||||
# Scheduled workflows run per-fork independently; skip anywhere but upstream.
|
||||
if: github.repository == 'xroche/httrack'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Install appstreamcli
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends appstream
|
||||
appstreamcli --version
|
||||
|
||||
# appstreamcli exits 3 on a warning, so a dead screenshot fails the job.
|
||||
- name: AppStream metainfo validation (network)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
appstreamcli validate --explain \
|
||||
html/server/div/com.httrack.WebHTTrack.metainfo.xml
|
||||
308
.github/workflows/ci.yml
vendored
@@ -38,10 +38,11 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential clang autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev \
|
||||
appstream appstream-util
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
@@ -79,6 +80,27 @@ jobs:
|
||||
- name: Build
|
||||
run: make -j"$(nproc)"
|
||||
|
||||
# FTP_PASV is 1 in every build, so #if !FTP_PASV never reaches a compiler
|
||||
# and rots unnoticed (#1091). Compiling is all this proves; nothing runs it.
|
||||
- name: Compile the FTP active-mode branch
|
||||
run: |
|
||||
set -euo pipefail
|
||||
objs="src/libhttrack_la-htsftp.lo src/libhttrack_la-htsftp.o src/.libs/libhttrack_la-htsftp.o"
|
||||
# accept() marks active-mode code: absent from the object Build made,
|
||||
# present below. One-sided, it passes on a file that ignored the define.
|
||||
syms=$(nm --undefined-only src/.libs/libhttrack_la-htsftp.o)
|
||||
if grep -qw accept <<<"$syms"; then
|
||||
echo "::error::accept() is reachable with FTP_PASV=1; the marker no longer discriminates"
|
||||
exit 1
|
||||
fi
|
||||
rm -f $objs
|
||||
# Through CC: overriding CPPFLAGS would drop configure's
|
||||
# -D_FORTIFY_SOURCE and the object-size warnings that come with it.
|
||||
make -C src libhttrack_la-htsftp.lo CC="$CC -DFTP_PASV=0 -Werror"
|
||||
syms=$(nm --undefined-only src/.libs/libhttrack_la-htsftp.o)
|
||||
grep -qw accept <<<"$syms" || { echo "::error::-DFTP_PASV=0 built no active-mode code"; exit 1; }
|
||||
rm -f $objs
|
||||
|
||||
# A backstop only: tests/test-timeout.sh bounds each test, and a healthy run
|
||||
# is a minute here, two on macOS. Without it a stall ran to the job's 6h default.
|
||||
- name: Test
|
||||
@@ -107,7 +129,7 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
@@ -137,13 +159,115 @@ jobs:
|
||||
if: failure()
|
||||
run: cat tests/test-suite.log 2>/dev/null || true
|
||||
|
||||
# Reproduces the buildds that refuse TEST-NET-1 instead of dropping it, where
|
||||
# every fixture needing a stalled connect must skip rather than fail (#1108).
|
||||
hostile-network:
|
||||
name: build (network refuses TEST-NET-1)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
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 autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev iproute2
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
set -euo pipefail
|
||||
autoreconf -fi
|
||||
./configure
|
||||
|
||||
- name: Build
|
||||
run: make -j"$(nproc)"
|
||||
|
||||
- name: Test on a network that refuses TEST-NET-1
|
||||
timeout-minutes: 20
|
||||
run: |
|
||||
set -euo pipefail
|
||||
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||
tools/hostile-net.sh make check -j"$jobs"
|
||||
# A refusal landing before connect() returns skips on the older probe
|
||||
# instead, leaving the settle this leg exists to guard unrun.
|
||||
cat tests/246_engine-connect-stop.log
|
||||
grep -q 'within 500 ms' tests/246_engine-connect-stop.log
|
||||
|
||||
- name: Print the test log on failure
|
||||
if: failure()
|
||||
run: cat tests/test-suite.log 2>/dev/null || true
|
||||
|
||||
# The Ubuntu buildds run a development release every runner above is well behind.
|
||||
# That gap is what shipped 3.49.18 broken on every Ubuntu architecture but
|
||||
# riscv64, when 25.10 made uutils the default coreutils (#1042).
|
||||
ubuntu-devel:
|
||||
name: build (Ubuntu devel, uutils coreutils)
|
||||
runs-on: ubuntu-24.04
|
||||
container: ubuntu:devel
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
# Before checkout: the container has no git, so submodules would be lost.
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev \
|
||||
git ca-certificates python3 procps
|
||||
|
||||
- name: Assert the coreutils dispatch on argv[0]
|
||||
# The property #1042 broke on, not the version banner, which uutils has
|
||||
# already reworded once. Without it the job quietly becomes a slower copy
|
||||
# of the one above.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ln -s "$(command -v sleep)" /tmp/not-a-coreutil
|
||||
if /tmp/not-a-coreutil 0; then
|
||||
echo "::error::coreutils here take any argv[0]; this image no longer guards uutils" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
set -euo pipefail
|
||||
autoreconf -fi
|
||||
./configure
|
||||
# A renamed dev package would disable a codec or TLS here, and the tests
|
||||
# that cover them would SKIP rather than fail.
|
||||
grep -q "define HTS_USEBROTLI 1" config.h
|
||||
grep -q "define HTS_USEZSTD 1" config.h
|
||||
grep -q "define HTS_USEOPENSSL 1" config.h
|
||||
|
||||
- name: Build
|
||||
run: make -j"$(nproc)"
|
||||
|
||||
- name: Test
|
||||
timeout-minutes: 25
|
||||
run: |
|
||||
set -euo pipefail
|
||||
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||
make check -j"$jobs"
|
||||
|
||||
- name: Print the test log on failure
|
||||
if: failure()
|
||||
run: cat tests/test-suite.log 2>/dev/null || true
|
||||
|
||||
# Portability: build and test on macOS (Darwin/clang) on a native runner --
|
||||
# no VM. The tree has no __APPLE__ branches, so Darwin exercises the
|
||||
# generic-Unix path on a second libc and kernel. brew's openssl@3 is keg-only,
|
||||
# so point configure at it; everything else is in the SDK or default paths.
|
||||
macos:
|
||||
name: build (macOS arm64, clang)
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
@@ -191,7 +315,7 @@ jobs:
|
||||
# temp prefix, then check webhttrack brings up htsserver and serves the UI.
|
||||
webhttrack-macos:
|
||||
name: webhttrack smoke (macOS arm64)
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
@@ -217,6 +341,112 @@ jobs:
|
||||
- name: Smoke-test webhttrack
|
||||
run: bash tests/webhttrack-smoke.sh "$RUNNER_TEMP/inst"
|
||||
|
||||
# Same smoke on the platform that ships webhttrack as a package: the install layout
|
||||
# it asserts (a relative data symlink, #885) is what Debian consumes, and the macOS
|
||||
# job alone left that untested on Linux.
|
||||
webhttrack-linux:
|
||||
name: webhttrack smoke (Linux x86-64)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
|
||||
- name: Build and install into a temp prefix
|
||||
run: |
|
||||
set -euo pipefail
|
||||
./bootstrap
|
||||
./configure --prefix="$RUNNER_TEMP/inst"
|
||||
make -j"$(nproc)"
|
||||
make install
|
||||
|
||||
- name: Smoke-test webhttrack
|
||||
run: bash tests/webhttrack-smoke.sh "$RUNNER_TEMP/inst"
|
||||
|
||||
# The macOS app bundle (#886): assemble it, then prove it still works after being
|
||||
# moved, which is the only thing a .app has to survive that a prefix install does not.
|
||||
macos-app:
|
||||
name: macOS app bundle (arm64)
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
brew install autoconf automake libtool autoconf-archive brotli zstd
|
||||
|
||||
# --disable-shared keeps libhttrack inside the binaries, so the bundle carries no
|
||||
# absolute dylib path back to the staging prefix.
|
||||
- name: Build and install into a temp prefix
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ssl="$(brew --prefix openssl@3)"
|
||||
brewp="$(brew --prefix)"
|
||||
./bootstrap
|
||||
./configure CPPFLAGS="-I${ssl}/include -I${brewp}/include" \
|
||||
LDFLAGS="-L${ssl}/lib -L${brewp}/lib" \
|
||||
--prefix="$RUNNER_TEMP/inst" --disable-shared
|
||||
make -j"$(sysctl -n hw.ncpu)"
|
||||
make install
|
||||
|
||||
- name: Assemble HTTrack.app
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make macos-app APP_FLAGS="--prefix $RUNNER_TEMP/inst --out $RUNNER_TEMP"
|
||||
plutil -lint "$RUNNER_TEMP/HTTrack.app/Contents/Info.plist"
|
||||
|
||||
- name: Run it through the bundle stub
|
||||
run: |
|
||||
set -euo pipefail
|
||||
app="$RUNNER_TEMP/HTTrack.app"
|
||||
bash tests/webhttrack-smoke.sh "$app/Contents/Resources" "$app/Contents/MacOS/HTTrack"
|
||||
|
||||
- name: Run it again after moving it
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$RUNNER_TEMP/moved"
|
||||
mv "$RUNNER_TEMP/HTTrack.app" "$RUNNER_TEMP/moved/"
|
||||
rm -rf "$RUNNER_TEMP/inst"
|
||||
app="$RUNNER_TEMP/moved/HTTrack.app"
|
||||
bash tests/webhttrack-smoke.sh "$app/Contents/Resources" "$app/Contents/MacOS/HTTrack"
|
||||
|
||||
# The load-command check cannot fail while the loader can still reach Homebrew (#901).
|
||||
- name: Run it with Homebrew's libraries out of reach
|
||||
run: |
|
||||
set -euo pipefail
|
||||
app="$RUNNER_TEMP/moved/HTTrack.app"
|
||||
# Without this the hiding below proves nothing: an empty Frameworks passes it.
|
||||
ls "$app/Contents/Frameworks"/libssl.*.dylib >/dev/null
|
||||
# The kegs, not just the opt symlinks: a source build records the Cellar path.
|
||||
hidden=""
|
||||
for keg in openssl@3 brotli zstd; do
|
||||
for d in "$(brew --prefix)/opt/$keg" "$(brew --prefix)/Cellar/$keg"; do
|
||||
if [ -e "$d" ]; then sudo mv "$d" "$d.hidden"; hidden="$hidden $d"; fi
|
||||
done
|
||||
done
|
||||
trap 'for d in $hidden; do sudo mv "$d.hidden" "$d"; done' EXIT
|
||||
test -n "$hidden"
|
||||
bash tests/webhttrack-smoke.sh "$app/Contents/Resources" "$app/Contents/MacOS/HTTrack"
|
||||
|
||||
# The release path (macos-release.yml) minus Apple, so a bundle that cannot be
|
||||
# signed or packed fails on the PR rather than on release day.
|
||||
- name: Sign and pack the bundle, ad hoc
|
||||
run: |
|
||||
set -euo pipefail
|
||||
bash tools/macos-release.sh --app "$RUNNER_TEMP/moved/HTTrack.app" \
|
||||
--identity - --skip-notarize
|
||||
|
||||
# Portability/hardening: 32-bit (i386) build on the x86-64 runner via multilib
|
||||
# -- no extra hardware. Exercises the 32-bit size_t/pointer ABI, where size
|
||||
# and bounds math can truncate or wrap in ways 64-bit never reveals (the axis
|
||||
@@ -234,7 +464,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential gcc-multilib autoconf automake libtool \
|
||||
autoconf-archive zlib1g-dev:i386 libssl-dev:i386 \
|
||||
@@ -277,7 +507,7 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
@@ -332,7 +562,7 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential clang autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev
|
||||
@@ -381,7 +611,7 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential clang autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
@@ -404,6 +634,33 @@ jobs:
|
||||
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
|
||||
run: bash fuzz/run-fuzzers.sh fuzz check
|
||||
|
||||
# Catches #1030: the job above links ASan, whose runtime already defines the
|
||||
# sancov hooks the instrumentation calls, hiding a program left without one.
|
||||
fuzz-no-sanitizer:
|
||||
name: build (fuzzers, no sanitizer runtime, clang)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential clang autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
|
||||
- name: Configure (fuzzers, static)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
autoreconf -fi
|
||||
./configure CC=clang --enable-fuzzers --disable-shared
|
||||
|
||||
- name: Build
|
||||
run: make -j"$(nproc)"
|
||||
|
||||
# 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
|
||||
@@ -420,7 +677,7 @@ jobs:
|
||||
- name: Install build dependencies (no libssl)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive zlib1g-dev
|
||||
|
||||
@@ -457,7 +714,7 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
@@ -536,7 +793,7 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
@@ -593,21 +850,23 @@ jobs:
|
||||
man/makeman.sh
|
||||
src/htsbasiccharsets.sh
|
||||
src/htsentities.sh
|
||||
src/webhttrack
|
||||
src/webhttrack.in
|
||||
tests/*.sh
|
||||
tests/*.test
|
||||
tools/mkdeb.sh
|
||||
tools/*.sh
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Install linters
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
# noble ships shfmt 3.8.0 (universe), matching the pinned local dev
|
||||
# version; use it rather than fetching a release binary from github.com.
|
||||
sudo apt-get install -y --no-install-recommends shellcheck shfmt
|
||||
sudo apt-get install -y --no-install-recommends shellcheck shfmt appstream \
|
||||
appstream-util
|
||||
shfmt --version
|
||||
appstreamcli --version
|
||||
|
||||
- name: shellcheck
|
||||
run: shellcheck $SHELL_SCRIPTS
|
||||
@@ -615,6 +874,11 @@ jobs:
|
||||
- name: shfmt
|
||||
run: shfmt -d -i 4 $SHELL_SCRIPTS
|
||||
|
||||
# A misnamed test falls outside the glob "make check" runs, so it goes
|
||||
# missing without failing anything.
|
||||
- name: test file names
|
||||
run: bash tests/check-test-names.sh
|
||||
|
||||
# MSBuild rejects a malformed .vcxproj with a bare MSB4025 and no build, so
|
||||
# catch it here in seconds rather than on a Windows runner minutes in.
|
||||
- name: XML well-formedness (MSBuild project files)
|
||||
@@ -625,6 +889,16 @@ jobs:
|
||||
echo "ok $f"
|
||||
done
|
||||
|
||||
# A software centre quietly ignores a metainfo it cannot parse. Errors and
|
||||
# warnings fail; --no-net so the gate is on the file, not httrack.com's uptime.
|
||||
- name: AppStream metainfo validation
|
||||
run: |
|
||||
set -euo pipefail
|
||||
appstreamcli validate --no-net --explain \
|
||||
html/server/div/com.httrack.WebHTTrack.metainfo.xml
|
||||
appstream-util validate-relax --nonet \
|
||||
html/server/div/com.httrack.WebHTTrack.metainfo.xml
|
||||
|
||||
# Check clang-format on CHANGED LINES ONLY. The engine predates clang-format
|
||||
# (it was shaped by an old Visual Studio formatter) and does not round-trip,
|
||||
# so we never reformat the whole tree -- only the lines a PR touches.
|
||||
@@ -645,7 +919,7 @@ jobs:
|
||||
| sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc >/dev/null
|
||||
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" \
|
||||
| sudo tee /etc/apt/sources.list.d/llvm-19.list >/dev/null
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends clang-format-19
|
||||
# The clang-format-19 package ships the git-clang-format driver;
|
||||
# expose it unsuffixed so "git clang-format" finds it.
|
||||
|
||||
6
.github/workflows/codeql.yml
vendored
@@ -33,12 +33,12 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev
|
||||
|
||||
- uses: github/codeql-action/init@v4
|
||||
- uses: github/codeql-action/init@v4.37.4
|
||||
with:
|
||||
languages: c-cpp
|
||||
build-mode: manual
|
||||
@@ -67,6 +67,6 @@ jobs:
|
||||
./configure
|
||||
make -j"$(nproc)"
|
||||
|
||||
- uses: github/codeql-action/analyze@v4
|
||||
- uses: github/codeql-action/analyze@v4.37.4
|
||||
with:
|
||||
category: "/language:c-cpp"
|
||||
|
||||
116
.github/workflows/cross-arch.yml
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
# Cross-compiles for the Debian architectures no GitHub runner exists for.
|
||||
# 3.49.17 failed on four of them at once and every failure was a compile or
|
||||
# assemble error that x86-64 and arm64 cannot produce, so the buildd was the
|
||||
# first thing to see the code.
|
||||
name: Cross-arch
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
# Least privilege: the workflow only needs to read the repo.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Cancel superseded runs on the same branch or PR.
|
||||
concurrency:
|
||||
group: cross-arch-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
cross:
|
||||
name: cross (${{ matrix.arch }})
|
||||
runs-on: ubuntu-24.04
|
||||
# sid, not stable: the point is to predict what the sid buildds will say.
|
||||
container: debian:sid
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# arch selects the hardening flags, triplet is the toolchain prefix.
|
||||
# The first four are 3.49.17's failures.
|
||||
- { arch: armhf, triplet: arm-linux-gnueabihf }
|
||||
- { arch: powerpc, triplet: powerpc-linux-gnu }
|
||||
- { arch: hppa, triplet: hppa-linux-gnu }
|
||||
- { arch: loong64, triplet: loongarch64-linux-gnu }
|
||||
- { arch: sh4, triplet: sh4-linux-gnu }
|
||||
- { arch: m68k, triplet: m68k-linux-gnu }
|
||||
- { arch: sparc64, triplet: sparc64-linux-gnu }
|
||||
- { arch: riscv64, triplet: riscv64-linux-gnu }
|
||||
- { arch: s390x, triplet: s390x-linux-gnu }
|
||||
env:
|
||||
DEB_HOST_ARCH: ${{ matrix.arch }}
|
||||
TRIPLET: ${{ matrix.triplet }}
|
||||
ZPREFIX: /tmp/zlib-${{ matrix.arch }}
|
||||
steps:
|
||||
- name: Install the toolchain
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# deb-src, so zlib below comes from the archive and not a pinned URL.
|
||||
# In place: a second stanza has to repeat Signed-By, and apt rejects
|
||||
# the same source carrying two spellings of the keyring.
|
||||
sed -i 's/^Types: deb$/Types: deb deb-src/' \
|
||||
/etc/apt/sources.list.d/debian.sources
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
dpkg-dev git ca-certificates \
|
||||
"gcc-$TRIPLET" "libc6-dev-$DEB_HOST_ARCH-cross"
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cross-build zlib
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Mandatory, and no ports arch has a zlib1g-dev:<arch> to
|
||||
# multiarch-install. -fPIC because libhttrack.so links it.
|
||||
mkdir -p /tmp/zsrc && cd /tmp/zsrc
|
||||
# Unpatched: Debian's arch-specific patches expect its own rules to
|
||||
# build them (s390x's vector CRC pulls a header they add), and we only
|
||||
# need something to link -lz against.
|
||||
apt-get source --download-only zlib1g
|
||||
dpkg-source --skip-patches -x ./*.dsc src
|
||||
cd src
|
||||
CHOST="$TRIPLET" CC="$TRIPLET-gcc" CFLAGS="-O2 -fPIC" \
|
||||
./configure --prefix="$ZPREFIX" --static
|
||||
# configure detects s390x's vector CRC, whose sources live in the
|
||||
# contrib/ the .dfsg repack drops: drop the define and the object it
|
||||
# would build. Nothing here needs a fast CRC.
|
||||
sed -i -E 's/(-DHAVE_S390X_VX|crc32_vx\.l?o)//g' Makefile
|
||||
make -j"$(nproc)"
|
||||
make install
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
set -euo pipefail
|
||||
autoreconf -fi
|
||||
mkdir -p /tmp/bld && cd /tmp/bld
|
||||
# The buildd's own per-arch flags: -D_FILE_OFFSET_BITS=64 is the shim
|
||||
# hazard, and -fstack-clash-protection is not offered everywhere.
|
||||
eval "$(dpkg-buildflags --export=sh)"
|
||||
# A cross AC_TRY_RUN answers "cross", which would swap in the bundled
|
||||
# snprintf that no buildd ever builds. Every glibc passes these.
|
||||
# --disable-https: no ports arch has a cross libssl, so the TLS paths
|
||||
# are the one part of the tree this matrix does not compile.
|
||||
"$GITHUB_WORKSPACE/configure" --host="$TRIPLET" \
|
||||
--build="$(dpkg-architecture -qDEB_BUILD_GNU_TYPE)" --disable-https \
|
||||
ac_cv_have_working_snprintf=yes ac_cv_have_working_vsnprintf=yes \
|
||||
CPPFLAGS="${CPPFLAGS:-} -I$ZPREFIX/include" \
|
||||
LDFLAGS="${LDFLAGS:-} -L$ZPREFIX/lib"
|
||||
|
||||
- name: Build
|
||||
run: make -C /tmp/bld -j"$(nproc)"
|
||||
|
||||
- name: Build the test artifacts
|
||||
# Nothing runs here, but the shims are where three of the four 3.49.17
|
||||
# failures were: they only build under `check`. Asserted, because an
|
||||
# empty TESTS= would otherwise pass having built nothing.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -C /tmp/bld -j"$(nproc)" check TESTS=
|
||||
test -f /tmp/bld/tests/.libs/libaltstackprobe.so
|
||||
162
.github/workflows/macos-release.yml
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
# Signed, notarized HTTrack.dmg (#901). Its own workflow because a fork's pull request
|
||||
# never gets the Developer ID secrets, and each run spends two notarization submissions.
|
||||
name: macOS release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["[0-9]*"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dmg:
|
||||
name: signed DMG (macOS arm64)
|
||||
runs-on: macos-15
|
||||
permissions:
|
||||
contents: write # attach the DMG to the release the tag belongs to
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
# Notarization is minutes in; a missing secret should not surface there.
|
||||
- name: Check the signing secrets are present
|
||||
env:
|
||||
MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
|
||||
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
|
||||
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
|
||||
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
|
||||
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
hint="see secrets/apple/README.md in httrack-works"
|
||||
: "${MACOS_CERT_P12:?unset repository secret ($hint)}"
|
||||
: "${MACOS_CERT_PASSWORD:?unset repository secret ($hint)}"
|
||||
: "${MACOS_NOTARY_KEY:?unset repository secret ($hint)}"
|
||||
: "${MACOS_NOTARY_KEY_ID:?unset repository secret ($hint)}"
|
||||
: "${MACOS_NOTARY_ISSUER_ID:?unset repository secret ($hint)}"
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
brew install autoconf automake libtool autoconf-archive brotli zstd
|
||||
|
||||
# --disable-shared keeps libhttrack inside the binaries.
|
||||
- name: Build and install into a temp prefix
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ssl="$(brew --prefix openssl@3)"
|
||||
brewp="$(brew --prefix)"
|
||||
./bootstrap
|
||||
./configure CPPFLAGS="-I${ssl}/include -I${brewp}/include" \
|
||||
LDFLAGS="-L${ssl}/lib -L${brewp}/lib" \
|
||||
--prefix="$RUNNER_TEMP/inst" --disable-shared
|
||||
make -j"$(sysctl -n hw.ncpu)"
|
||||
make install
|
||||
|
||||
- name: Assemble HTTrack.app
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make macos-app APP_FLAGS="--prefix $RUNNER_TEMP/inst --out $RUNNER_TEMP"
|
||||
plutil -lint "$RUNNER_TEMP/HTTrack.app/Contents/Info.plist"
|
||||
|
||||
- name: Import the Developer ID certificate
|
||||
env:
|
||||
CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
|
||||
CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
kc="$RUNNER_TEMP/signing.keychain-db"
|
||||
kcpass="$(openssl rand -base64 24)"
|
||||
echo "::add-mask::$kcpass"
|
||||
security create-keychain -p "$kcpass" "$kc"
|
||||
# Notarization holds the job well past the five-minute default lock.
|
||||
security set-keychain-settings -lut 21600 "$kc"
|
||||
security unlock-keychain -p "$kcpass" "$kc"
|
||||
# Armed before the file exists: a failed import must not leave the key on a
|
||||
# disk that later steps run repository code against.
|
||||
trap 'rm -f "$RUNNER_TEMP/cert.p12"' EXIT HUP INT TERM
|
||||
# openssl, not base64: macOS spells the decode flag -D and GNU spells it -d.
|
||||
printf '%s' "$CERT_P12" | openssl base64 -d -A -out "$RUNNER_TEMP/cert.p12"
|
||||
security import "$RUNNER_TEMP/cert.p12" -k "$kc" -P "$CERT_PASSWORD" \
|
||||
-T /usr/bin/codesign
|
||||
# Without this codesign blocks on a UI prompt no runner can answer.
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: \
|
||||
-s -k "$kcpass" "$kc" >/dev/null
|
||||
security list-keychains -d user -s "$kc"
|
||||
id="$(security find-identity -v -p codesigning "$kc" |
|
||||
awk '/Developer ID Application/ {print $2; exit}')"
|
||||
test -n "$id" || {
|
||||
security find-identity -v -p codesigning "$kc" >&2
|
||||
echo "the .p12 holds no Developer ID Application identity" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "SIGN_IDENTITY=$id" >>"$GITHUB_ENV"
|
||||
|
||||
- name: Sign, notarize and pack the DMG
|
||||
env:
|
||||
NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
|
||||
NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
|
||||
NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
key="$RUNNER_TEMP/notary.p8"
|
||||
trap 'rm -f "$key"' EXIT HUP INT TERM
|
||||
printf '%s' "$NOTARY_KEY" | openssl base64 -d -A -out "$key"
|
||||
bash tools/macos-release.sh --app "$RUNNER_TEMP/HTTrack.app" \
|
||||
--identity "$SIGN_IDENTITY" --out "$RUNNER_TEMP" \
|
||||
--notary-key "$key" --notary-key-id "$NOTARY_KEY_ID" \
|
||||
--notary-issuer "$NOTARY_ISSUER_ID"
|
||||
|
||||
# The DMG round-trip is the one thing that can strip the stapled ticket, so assess
|
||||
# the copy that came out of it rather than the app the signing step still holds.
|
||||
- name: Assess a quarantined copy out of the DMG
|
||||
run: |
|
||||
set -euo pipefail
|
||||
dmg="$(echo "$RUNNER_TEMP"/HTTrack-*.dmg)"
|
||||
test -f "$dmg"
|
||||
hdiutil attach -nobrowse -readonly -mountpoint "$RUNNER_TEMP/mnt" "$dmg"
|
||||
trap 'hdiutil detach "$RUNNER_TEMP/mnt" >/dev/null || true' EXIT
|
||||
app="$RUNNER_TEMP/quarantined/HTTrack.app"
|
||||
ditto "$RUNNER_TEMP/mnt/HTTrack.app" "$app"
|
||||
# On the root only, as a real download lands it; -r would also chase symlinks.
|
||||
xattr -w com.apple.quarantine "0083;00000000;Safari;" "$app"
|
||||
# --no-cache, or the verdict already cached for this cdhash answers instead.
|
||||
log="$RUNNER_TEMP/assess.log"
|
||||
spctl --assess --type exec --ignore-cache --no-cache -vv "$app" >"$log" 2>&1 || {
|
||||
cat "$log" >&2
|
||||
exit 1
|
||||
}
|
||||
cat "$log"
|
||||
grep -q "source=Notarized Developer ID" "$log"
|
||||
# spctl alone can be answered online; this is the offline-launch proof.
|
||||
xcrun stapler validate "$app"
|
||||
# Not a Gatekeeper check: the stub is a script, so nothing here goes through
|
||||
# LaunchServices. It proves the hardened runtime did not break the dylib loads.
|
||||
bash tests/webhttrack-smoke.sh "$app/Contents/Resources" "$app/Contents/MacOS/HTTrack"
|
||||
|
||||
- name: Upload the DMG
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: HTTrack-macos-arm64-dmg
|
||||
path: ${{ runner.temp }}/HTTrack-*.dmg
|
||||
if-no-files-found: error
|
||||
|
||||
# Releases are cut by hand, so a tag can land before one exists.
|
||||
- name: Attach the DMG to the release
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
|
||||
gh release upload "$GITHUB_REF_NAME" "$RUNNER_TEMP"/HTTrack-*.dmg --clobber
|
||||
else
|
||||
echo "no release $GITHUB_REF_NAME yet -- the DMG is on this run's artifacts"
|
||||
fi
|
||||
|
||||
- name: Delete the signing keychain
|
||||
if: always()
|
||||
run: security delete-keychain "$RUNNER_TEMP/signing.keychain-db" || true
|
||||
12
.github/workflows/screenshots.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get update || true # a third-party source in the runner image can 403 (#1097)
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool autoconf-archive \
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||
@@ -52,6 +52,15 @@ jobs:
|
||||
pip install --quiet playwright
|
||||
playwright install --with-deps chromium
|
||||
|
||||
# The address is on screen in the wizard panes and names the mirror folder,
|
||||
# so the crawl needs a presentable host rather than 127.0.0.1 and a random
|
||||
# port. example.com is reserved for documentation (RFC 2606).
|
||||
- name: Let the crawl address a named site on port 80
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "127.0.0.1 www.example.com" | sudo tee -a /etc/hosts
|
||||
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80 # bind 80 unprivileged
|
||||
|
||||
- name: Capture
|
||||
env:
|
||||
LANGN: ${{ inputs.lang || '1' }}
|
||||
@@ -61,6 +70,7 @@ jobs:
|
||||
# --root is the dist root; the source tree already holds every piece
|
||||
# htsserver reads, so this needs no install.
|
||||
python3 tools/screenshot-walk.py --htsserver src/htsserver --root . \
|
||||
--site-host www.example.com --site-port 80 \
|
||||
--lang "$LANGN" --scale "$SCALE" --out shots
|
||||
|
||||
- name: Upload the screens
|
||||
|
||||
147
.github/workflows/windows-build.yml
vendored
@@ -14,6 +14,14 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# The suite watchdog reports as a commit status, the only channel that
|
||||
# outlives the runner it is reporting on (#795).
|
||||
statuses: write
|
||||
|
||||
# Cancel superseded runs on the same branch or PR.
|
||||
concurrency:
|
||||
group: windows-build-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
libhttrack:
|
||||
@@ -32,6 +40,9 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive # coucal lives in src/coucal
|
||||
# Or the job token stays in .git/config, where every test the suite
|
||||
# runs can read it.
|
||||
persist-credentials: false
|
||||
|
||||
# Located through vswhere rather than microsoft/setup-msbuild: the repo
|
||||
# only allows GitHub-owned actions.
|
||||
@@ -166,133 +177,17 @@ jobs:
|
||||
shell: bash
|
||||
working-directory: tests
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
# Through the environment, never argv, which the process list exposes.
|
||||
WATCHDOG_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WATCHDOG_REPO: ${{ github.repository }}
|
||||
# github.sha here is the PR's merge commit, so statuses posted against it stay out of the PR's checks UI.
|
||||
WATCHDOG_SHA: ${{ github.sha }}
|
||||
WATCHDOG_CONTEXT: windows-suite (${{ matrix.platform }}, ${{ matrix.configuration }})
|
||||
WATCHDOG_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
set -u
|
||||
bin="$(cygpath -u "$GITHUB_WORKSPACE")/src/${{ matrix.platform }}/${{ matrix.configuration }}"
|
||||
export PATH="$bin:$PATH"
|
||||
command -v httrack >/dev/null || { echo "::error::no httrack.exe in $bin"; exit 1; }
|
||||
|
||||
# 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.
|
||||
. ./testlib.sh
|
||||
per_test=600
|
||||
|
||||
# The whole suite must give up before the step timeout above. A cancelled
|
||||
# step keeps neither its log nor the artifacts the later if:always()
|
||||
# steps would upload, so an overrun that ends in a cancel tells us
|
||||
# nothing; failing on our own terms keeps both. Healthy runs take 8-9
|
||||
# min. The check sits between tests, so the step can still reach 25 min
|
||||
# plus one per-test budget, and that worst case stays inside the 45.
|
||||
suite_deadline=1500
|
||||
started=$SECONDS
|
||||
|
||||
# Survives into the artifact even if the tail of the step log does not.
|
||||
progress=suite-progress.log
|
||||
: >"$progress"
|
||||
|
||||
pass=0 fail=0 skip=0 failed="" skipped="" deadline=0
|
||||
# Globbed, not enumerated: a new NNN_engine-*.test or NNN_local-*.test
|
||||
# is picked up automatically instead of silently getting zero coverage.
|
||||
for t in 00_runnable.test *_engine-*.test *_zlib-*.test \
|
||||
*_local-*.test *_watchdog*.test *_crawl_proxy_https.test \
|
||||
*_crawl-log-salvage.test; 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"
|
||||
rc=0
|
||||
# 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 bash ./test-timeout.sh "$t" >"$t.log" 2>&1 || rc=$?
|
||||
case "$rc" in
|
||||
0) pass=$((pass + 1)); echo "PASS $t" ;;
|
||||
77) skip=$((skip + 1)) skipped="$skipped $t"; echo "SKIP $t" ;;
|
||||
124)
|
||||
fail=$((fail + 1)) failed="$failed $t"
|
||||
# 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/^/ /'
|
||||
;;
|
||||
*)
|
||||
fail=$((fail + 1)) failed="$failed $t"
|
||||
echo "FAIL $t (exit $rc)"
|
||||
# These assert with `test "$(...)" == "..." || exit 1`, which
|
||||
# says nothing at all on failure. Re-run traced, still bounded.
|
||||
run_with_timeout "$per_test" bash -x "$t" >>"$t.log" 2>&1 || true
|
||||
tail -n 25 "$t.log" | sed 's/^/ /'
|
||||
;;
|
||||
esac
|
||||
echo "$rc $t" >>"$progress"
|
||||
# An orphaned native httrack.exe spins and starves the runner, which
|
||||
# is how this job dies with "lost communication" rather than a plain
|
||||
# timeout. Clear them between tests and name whoever leaked them.
|
||||
reap_leftover_processes "$t" | tee -a "$progress"
|
||||
done
|
||||
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);
|
||||
# crange pending #581;
|
||||
# webdav-default and webdav-mime need a reapable background listener, which MSYS cannot give them;
|
||||
# badmtime needs a filesystem that stores an mtime past gmtime's range;
|
||||
# single-file ends on a GUI half needing htsserver, which this job does not build;
|
||||
# update-304-leak needs a LeakSanitizer build, which MSVC has no equivalent of;
|
||||
# crash-symbolize needs backtrace(), which Windows has no equivalent of.
|
||||
expected_skips="01_engine-footer-overflow.test
|
||||
100_local-purge-longpath.test
|
||||
114_local-update-304-leak.test
|
||||
120_local-proxytrack-webdav-default.test
|
||||
48_local-crange-memresume.test
|
||||
71_local-crange-repaircache.test
|
||||
79_local-proxytrack-webdav-mime.test
|
||||
80_engine-crash-symbolize.test
|
||||
88_local-proxytrack-badmtime.test
|
||||
94_local-single-file.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.
|
||||
got=$(printf '%s\n' $skipped | sort)
|
||||
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; }
|
||||
bash ./ci-windows-suite.sh \
|
||||
"$(cygpath -u "$GITHUB_WORKSPACE")/src/${{ matrix.platform }}/${{ matrix.configuration }}"
|
||||
|
||||
- name: Upload the test logs
|
||||
if: always()
|
||||
|
||||
13
.gitignore
vendored
@@ -24,8 +24,12 @@ Makefile.in
|
||||
/config.log
|
||||
/config.status
|
||||
/stamp-h1
|
||||
# src/webhttrack.in is the source; an in-tree build generates this one (#887).
|
||||
/src/webhttrack
|
||||
/src/libhttrack.pc
|
||||
Makefile
|
||||
.deps/
|
||||
.dirstamp
|
||||
.libs/
|
||||
*.o
|
||||
*.lo
|
||||
@@ -34,6 +38,15 @@ Makefile
|
||||
*.so.*
|
||||
*.a
|
||||
|
||||
# Built into the checkout by an in-tree "make" / "make check".
|
||||
/src/httrack
|
||||
/src/htsserver
|
||||
/src/proxytrack
|
||||
/tools/Info.plist
|
||||
/tests/stringoom
|
||||
/tests/*.log
|
||||
/tests/*.trs
|
||||
|
||||
# make dist output; dist/ holds httrack-gh-release staging artifacts.
|
||||
/httrack-*.tar.gz
|
||||
/dist/
|
||||
|
||||
18
AGENTS.md
@@ -19,8 +19,12 @@ the operational checklist: toolchain, invariants, and how to ship a change.
|
||||
(`request_queue_size`) so macOS/BSD don't drop connections under a parallel
|
||||
`-c16` bigcrawl the way Python's default backlog of 5 did.
|
||||
Or run `sh build.sh` to do bootstrap + configure + make in one shot.
|
||||
- A `tests/NN_*.test` runs only if listed in `tests/tests-list.mk`; an
|
||||
unregistered file is silently skipped.
|
||||
- `configure` globs `TESTS` from `tests/[0-9]*_*.test`, so a new test needs no
|
||||
registration, but an existing build dir keeps the list it was configured with:
|
||||
`231_test-names.test` goes red until you reconfigure. It also compares the glob
|
||||
against `git ls-files`, so a test you forgot to `git add` fails there instead of
|
||||
quietly shrinking CI's suite. Name one outside the pattern and it never runs;
|
||||
`tests/check-test-names.sh` (also a CI lint) rejects that.
|
||||
- `make check` prepends the build's `src/` to `PATH`, but a hand-run `.test` does
|
||||
not — an installed `/usr/bin/httrack` then shadows your build. Run via `make
|
||||
check`, or `PATH="<bld>/src:$PATH"` for a manual run.
|
||||
@@ -38,6 +42,16 @@ the operational checklist: toolchain, invariants, and how to ship a change.
|
||||
match that is not on the last line is exposed. Capture the reply, assert the
|
||||
status line it must carry (an empty, truncated or redirected one is
|
||||
marker-free too), then match with a here-string: `grep -q M <<<"$reply"`.
|
||||
`head -c N` and `head -n N` end the same way, and there the reds are
|
||||
platform-specific: GNU `tail | head -c 3` survives, the uutils coreutils leg
|
||||
turns the same line into exit 141 with no output at all. Let the reader seek
|
||||
instead: `od -An -c -j <skip> -N <len> file`.
|
||||
- Never assert a fault by signal *number*: SIGBUS is 7 on x86, arm, powerpc and
|
||||
s390x but 10 on hppa, alpha, mips and sparc. Map it with `kill -l "$n"`.
|
||||
- A fixture that needs a host to stay silent must settle (500ms), re-probe every
|
||||
socket, and SKIP when one answered: the powerpc and ppc64 buildds refuse
|
||||
TEST-NET-1 milliseconds after `connect()` where runners drop it.
|
||||
`tools/hostile-net.sh` runs a command on such a network.
|
||||
|
||||
## Hard invariants
|
||||
- **Generated autotools files are NOT in git.** `configure`, every
|
||||
|
||||
24
Makefile.am
@@ -6,13 +6,33 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = INSTALL.Linux \
|
||||
gpl-fr.txt license.txt greetings.txt history.txt \
|
||||
httrack-doc.html lang.def README.md tools/mkdeb.sh \
|
||||
tools/macos-app.sh tools/macos-bundle.sh tools/macos-release.sh \
|
||||
tools/httrack-launcher.c \
|
||||
tools/Info.plist.in tools/HTTrack.icns \
|
||||
bootstrap build.sh
|
||||
|
||||
# Build the signed Debian packages from a clean source export. Pass the signing
|
||||
# key and other options through DEB_FLAGS, e.g.:
|
||||
# make deb DEB_FLAGS="--key BB71C7E6CB1AD8FAF53FE42A60C3AA7180598EFB"
|
||||
# See tools/mkdeb.sh --help for all options.
|
||||
# See tools/mkdeb.sh --help for all options. Not $(SHELL): mkdeb.sh is bash, and dash chokes (#891).
|
||||
DEB_FLAGS =
|
||||
deb:
|
||||
$(SHELL) $(top_srcdir)/tools/mkdeb.sh $(DEB_FLAGS)
|
||||
$(BASH_SHELL) $(top_srcdir)/tools/mkdeb.sh $(DEB_FLAGS)
|
||||
.PHONY: deb
|
||||
|
||||
# Assemble the macOS application bundle from an installed prefix, e.g.
|
||||
# make macos-app APP_FLAGS="--prefix /tmp/inst --out /tmp"
|
||||
APP_FLAGS =
|
||||
macos-app:
|
||||
$(SHELL) $(top_srcdir)/tools/macos-app.sh --plist tools/Info.plist \
|
||||
--icon $(top_srcdir)/tools/HTTrack.icns $(APP_FLAGS)
|
||||
.PHONY: macos-app
|
||||
|
||||
# Sign, notarize and pack that bundle into the DMG we publish, e.g.
|
||||
# make macos-release RELEASE_FLAGS="--app /tmp/HTTrack.app --identity ABCD1234 \
|
||||
# --notary-key AuthKey.p8 --notary-key-id KEYID --notary-issuer ISSUERID"
|
||||
# See tools/macos-release.sh for the rest; .github/workflows/macos-release.yml runs it.
|
||||
RELEASE_FLAGS =
|
||||
macos-release:
|
||||
$(SHELL) $(top_srcdir)/tools/macos-release.sh $(RELEASE_FLAGS)
|
||||
.PHONY: macos-release
|
||||
|
||||
294
configure.ac
@@ -1,6 +1,6 @@
|
||||
AC_PREREQ([2.71])
|
||||
|
||||
AC_INIT([httrack], [3.49.15], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
|
||||
AC_INIT([httrack], [3.49.20], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
|
||||
AC_COPYRIGHT([
|
||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||
Copyright (C) 1998-2015 Xavier Roche and other contributors
|
||||
@@ -29,15 +29,89 @@ AC_CONFIG_SRCDIR(src/httrack.c)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
# 3:13:0: revision-only bump. htsstrings.h's StringRoomTotal grew saturation in
|
||||
# its macro body; no installed struct moved and no export came or went.
|
||||
# 3:12:0: revision-only bump. httrackp gained a tail field (singlefile_state) and
|
||||
# htsopt.h added volatile qualifiers; no layout moved, nothing went away.
|
||||
# 3:11:0: revision-only bump. #1001 moved SOCaddr_inetntoa_ out of htsnet.h, adding
|
||||
# an export where callers had an inline; nothing changed or went away.
|
||||
# 3:10:0: revision-only bump; only the version macro moved, the engine is untouched.
|
||||
# 3:9:0: revision-only bump. #991 and #1005 each added an export
|
||||
# (hts_set_thread_hooks, escape_control_url); nothing changed or went away.
|
||||
# 3:8:0: revision-only bump, no ABI change.
|
||||
# 3:7:0: htsblk gained a tail field and lien_back embeds it by value, so
|
||||
# lien_back.is_update and everything after it shift +8 (httrackp's own tail growth
|
||||
# moves nothing). Soname stays .so.3: HTTrackQt is the only consumer of the installed
|
||||
# headers, so a libhttrack4 rename isn't worth it.
|
||||
# (3:0:0 was the htsblk mime-buffer widening, the ABI break that moved .so.2 -> .so.3.)
|
||||
VERSION_INFO="3:7:0"
|
||||
VERSION_INFO="3:13:0"
|
||||
AM_MAINTAINER_MODE
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
# A real bash, for "make deb" and the test harness. Not searched into BASH: bash presets
|
||||
# that to its own path, and macOS /bin/sh is a bash, so the macro never searches (#895).
|
||||
# BASH_SHELL isn't preset the way BASH is, so AC_ARG_VAR needs no guard. Kept ahead of the
|
||||
# compiler probes so a bad override dies before them.
|
||||
AC_ARG_VAR([BASH_SHELL], [path to a real (non-POSIX-mode) bash])
|
||||
# AC_PATH_PROGS drops a relative override and searches instead, which loses the user's intent.
|
||||
# Nothing quotes $(BASH_SHELL) in the Makefiles, and quoting could not save it anyway: make
|
||||
# splits on whitespace, expands '$' and treats '#' as a comment before any shell sees it.
|
||||
case $BASH_SHELL in
|
||||
*[[[:space:]]]* | *'#'* | *'$'* | *'`'* | *'\'* | *'"'* | *"'"* | *';'* | *'&'* | *'|'* | \
|
||||
*'<'* | *'>'* | *'('* | *')'* | *'*'* | *'?'* | *'@<:@'* | *'@:>@'* | *'{'* | *'}'*)
|
||||
AC_MSG_ERROR([BASH_SHELL must not contain shell or make metacharacters, got: $BASH_SHELL]) ;;
|
||||
'' | [[\\/]]* | ?:[[\\/]]*) ;;
|
||||
*) AC_MSG_ERROR([BASH_SHELL must be an absolute path, got: $BASH_SHELL]) ;;
|
||||
esac
|
||||
hts_bash_override=$BASH_SHELL
|
||||
AC_PATH_PROGS([BASH_SHELL], [bash], [/bin/bash])
|
||||
|
||||
# An absolute override is taken verbatim, so BASH_SHELL=/bin/sh would put #895 back and only
|
||||
# surface at "make check" or "make deb" (#908). What we found ourselves is only a warning:
|
||||
# a box with no bash still builds, it just cannot run those two.
|
||||
AC_MSG_CHECKING([whether $BASH_SHELL is a bash outside POSIX mode])
|
||||
hts_bash_why=
|
||||
hts_bash_env=no
|
||||
# AS_EXECUTABLE_P, not "test -x": the PATH search above already demands a regular file, and
|
||||
# bash blocks forever reading a FIFO it failed to exec, so -x alone hangs configure (#922).
|
||||
if ! AS_EXECUTABLE_P(["$BASH_SHELL"]); then
|
||||
hts_bash_why="not an executable regular file"
|
||||
elif test -z "$("$BASH_SHELL" -c 'echo "${BASH_VERSINFO[[0]]}"' 2>/dev/null)"; then
|
||||
# Not BASH_VERSION: that is an ordinary variable, so any shell echoes back a spoofed one.
|
||||
hts_bash_why="not a bash: it reports no BASH_VERSINFO"
|
||||
else
|
||||
# sh-mode bash reports a version too, so only SHELLOPTS tells the two apart.
|
||||
case $("$BASH_SHELL" -c 'echo ":$SHELLOPTS:"' 2>/dev/null) in
|
||||
*:posix:*)
|
||||
hts_bash_why="a bash in POSIX sh-mode"
|
||||
# POSIXLY_CORRECT and an exported SHELLOPTS do that to every bash on the box, so no path
|
||||
# can pass and blaming this one would send the user hunting for another. Reading them
|
||||
# here would not do: configure puts its own shell in posix mode, which sets both.
|
||||
case $(env -u POSIXLY_CORRECT -u SHELLOPTS "$BASH_SHELL" -c 'echo ":$SHELLOPTS:"' 2>/dev/null) in
|
||||
'' | *:posix:*) ;; # no "env -u", or posix whatever the environment: blame the path
|
||||
*) hts_bash_env=yes ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test -z "$hts_bash_why"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
hts_bash_msg="POSIXLY_CORRECT or SHELLOPTS forces every bash into POSIX sh-mode, $BASH_SHELL included. Clear them for configure and for make, which hands them to make check and make deb: env -u POSIXLY_CORRECT -u SHELLOPTS ..."
|
||||
if test "$hts_bash_env" = yes; then
|
||||
if test -n "$hts_bash_override"; then
|
||||
AC_MSG_ERROR([$hts_bash_msg])
|
||||
fi
|
||||
AC_MSG_WARN([$hts_bash_msg])
|
||||
else
|
||||
if test -n "$hts_bash_override"; then
|
||||
AC_MSG_ERROR([BASH_SHELL=$BASH_SHELL is $hts_bash_why])
|
||||
fi
|
||||
AC_MSG_WARN([no usable bash found: $BASH_SHELL is $hts_bash_why. "make check" and "make deb" need one; pass BASH_SHELL=/path/to/bash])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
m4_warn([obsolete],
|
||||
@@ -48,14 +122,13 @@ m4_warn([obsolete],
|
||||
# script's behavior did not change. They are probably safe to remove.
|
||||
AC_CHECK_INCLUDES_DEFAULT
|
||||
AC_PROG_EGREP
|
||||
# $(SED) substitutes $(datadir) into src/webhttrack
|
||||
AC_PROG_SED
|
||||
|
||||
LT_INIT
|
||||
AC_PROG_LN_S
|
||||
LT_INIT
|
||||
|
||||
# bash, used to run the test scripts (see tests/Makefile.am TEST_LOG_COMPILER)
|
||||
AC_PATH_PROGS([BASH], [bash], [/bin/bash])
|
||||
|
||||
# Export LD_LIBRARY_PATH name or equivalent.
|
||||
AC_SUBST(SHLIBPATH_VAR,$shlibpath_var)
|
||||
|
||||
@@ -100,6 +173,9 @@ AX_CHECK_COMPILE_FLAG([-fstack-protector-strong], [DEFAULT_CFLAGS="$DEFAULT_CFLA
|
||||
[AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"], [], [-Werror])], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"], [], [-Werror])
|
||||
# backtrace() unwinds through these; armhf, unlike amd64/arm64, defaults them off
|
||||
# and printed frameless crash reports.
|
||||
AX_CHECK_COMPILE_FLAG([-fasynchronous-unwind-tables], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fasynchronous-unwind-tables"], [], [-Werror])
|
||||
# No --discard-all: it drops the local symbols naming every static function, so
|
||||
# a trace misattributes them to the nearest surviving global. Costs 0.6% size.
|
||||
AX_CHECK_LINK_FLAG([-Wl,--no-undefined], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--no-undefined"])
|
||||
@@ -131,6 +207,156 @@ AC_SUBST([LDFLAGS_PIE])
|
||||
# Ties a crash trace from a stripped build back to its separate debug symbols.
|
||||
AX_CHECK_LINK_FLAG([-Wl,--build-id], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--build-id"])
|
||||
|
||||
# tools/macos-app.sh rewrites load commands to @rpath, which needs header room ld64 does
|
||||
# not leave by default; the probe fails on GNU ld, so this self-gates on Darwin.
|
||||
AX_CHECK_LINK_FLAG([-Wl,-headerpad_max_install_names],
|
||||
[DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-headerpad_max_install_names"])
|
||||
|
||||
### Relocatable install (#906, #978)
|
||||
# libtool records the configured libdir as an absolute rpath, so a copied tree
|
||||
# cannot find libhttrack. A binary-relative rpath fixes that where the loader
|
||||
# expands the token, which the BSDs disagree on: probe by running one.
|
||||
AC_ARG_ENABLE([origin-rpath],
|
||||
AS_HELP_STRING([--disable-origin-rpath],
|
||||
[link the binaries without a binary-relative rpath]),
|
||||
[hts_origin_asked=yes], [enable_origin_rpath=yes; hts_origin_asked=no])
|
||||
|
||||
# hts_origin_ref is the raw token the loader expands; hts_origin_ref_make is the
|
||||
# spelling that survives make's expansion and libtool's eval of the link line.
|
||||
AS_CASE([$host_os],
|
||||
[darwin*], [hts_origin_darwin=yes
|
||||
hts_origin_ref='@loader_path'
|
||||
hts_origin_ref_make='@loader_path'],
|
||||
[hts_origin_darwin=no
|
||||
hts_origin_ref='$ORIGIN'
|
||||
hts_origin_ref_make='\$$ORIGIN'])
|
||||
|
||||
hts_save_prefix=$prefix
|
||||
hts_save_exec_prefix=$exec_prefix
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
test "x$exec_prefix" = xNONE && exec_prefix=$prefix
|
||||
eval hts_libdir=\"$libdir\"
|
||||
eval hts_libdir=\"$hts_libdir\"
|
||||
prefix=$hts_save_prefix
|
||||
exec_prefix=$hts_save_exec_prefix
|
||||
|
||||
# Enumerated, not read from libtool's sys_lib_dlsearch_path_spec: that one is
|
||||
# only augmented when /etc/ld.so.conf exists, so a sysroot or minimal container
|
||||
# would let a distribution libdir through. Spelled out rather than globbed as
|
||||
# /lib*, which would swallow /libfoo and /usr/libexec.
|
||||
AS_CASE([$hts_libdir],
|
||||
[/lib | /lib/* | /lib32 | /lib32/* | /lib64 | /lib64/* | /libx32 | /libx32/*], [hts_origin_sysdir=yes],
|
||||
[/usr/lib | /usr/lib/* | /usr/lib32 | /usr/lib32/* | /usr/lib64 | /usr/lib64/* | /usr/libx32 | /usr/libx32/*], [hts_origin_sysdir=yes],
|
||||
[hts_origin_sysdir=no])
|
||||
|
||||
# dyld follows LC_RPATH only for a load path spelled @rpath/..., so Darwin also
|
||||
# needs libhttrack's own id. That comes from libtool's archive_cmds template and
|
||||
# not from LDFLAGS, so rewrite it; an unrecognised template leaves the gate off.
|
||||
hts_origin_id=no
|
||||
if test "x$hts_origin_darwin" = xyes; then
|
||||
hts_origin_subst='s|-install_name $rpath/|-install_name @rpath/|'
|
||||
hts_origin_archive=`printf '%s\n' "$archive_cmds" | $SED "$hts_origin_subst"`
|
||||
hts_origin_expsym=`printf '%s\n' "$archive_expsym_cmds" | $SED "$hts_origin_subst"`
|
||||
# Both templates or neither: should they ever diverge, the -export-symbols
|
||||
# path would keep stamping the absolute id the rpath cannot answer.
|
||||
if test "x$hts_origin_archive" != "x$archive_cmds" &&
|
||||
test "x$hts_origin_expsym" != "x$archive_expsym_cmds"; then
|
||||
hts_origin_id=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
ORIGIN_RPATH=no
|
||||
RPATH_ORIGIN_LDFLAGS=""
|
||||
if test "x$enable_origin_rpath" = xno; then
|
||||
AC_MSG_NOTICE([binary-relative rpath disabled by request])
|
||||
elif test "x$hts_origin_darwin" = xyes && test "x$hts_origin_id" = xno; then
|
||||
AC_MSG_NOTICE([binary-relative rpath not used: unrecognised install_name in libtool archive_cmds])
|
||||
elif test "x$enable_shared" = xno; then
|
||||
AC_MSG_NOTICE([binary-relative rpath not needed: no shared libraries])
|
||||
elif test "x$hts_origin_sysdir" = xyes; then
|
||||
# A distribution libdir is already searched, and an rpath there is a lintian tag.
|
||||
AC_MSG_NOTICE([binary-relative rpath not used: $hts_libdir is a system libdir])
|
||||
elif test "x$cross_compiling" = xyes && test "x$hts_origin_asked" = xno; then
|
||||
AC_MSG_NOTICE([binary-relative rpath not probed: cross compiling, pass --enable-origin-rpath to force it])
|
||||
else
|
||||
AC_MSG_CHECKING([whether the loader honours a binary-relative rpath])
|
||||
AC_CACHE_VAL([hts_cv_origin_rpath], [
|
||||
hts_cv_origin_rpath=no
|
||||
# Cross compiling cannot run the probe, so take the stricter spelling first.
|
||||
hts_origin_cands="none origin"
|
||||
test "x$cross_compiling" = xyes && hts_origin_cands="origin none"
|
||||
test "x$hts_origin_darwin" = xyes && hts_origin_cands=loader_path
|
||||
rm -rf conftest.origin
|
||||
AS_MKDIR_P([conftest.origin/bin])
|
||||
AS_MKDIR_P([conftest.origin/lib])
|
||||
AS_MKDIR_P([conftest.origin/run])
|
||||
cat >conftest.origin/lib.c <<_ACEOF
|
||||
int hts_origin_probe(void);
|
||||
int hts_origin_probe(void) { return 42; }
|
||||
_ACEOF
|
||||
cat >conftest.origin/main.c <<_ACEOF
|
||||
int hts_origin_probe(void);
|
||||
int main(void) { return hts_origin_probe() == 42 ? 0 : 1; }
|
||||
_ACEOF
|
||||
if test "x$hts_origin_darwin" = xyes; then
|
||||
# The same @rpath id, so a dead LC_RPATH cannot pass for a live one.
|
||||
hts_origin_mklib="$CC $CFLAGS -dynamiclib -install_name @rpath/libhtsorigin.dylib -o conftest.origin/lib/libhtsorigin.dylib conftest.origin/lib.c"
|
||||
else
|
||||
hts_origin_mklib="$CC $CFLAGS -fPIC -shared -o conftest.origin/lib/libhtsorigin.so conftest.origin/lib.c"
|
||||
fi
|
||||
hts_origin_link="-Lconftest.origin/lib -lhtsorigin"
|
||||
if $hts_origin_mklib >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
for hts_origin_cand in $hts_origin_cands; do
|
||||
# Solaris and the older BSDs expand the token only with -z origin.
|
||||
hts_origin_try=
|
||||
test "x$hts_origin_cand" = xorigin && hts_origin_try=-Wl,-z,origin
|
||||
$CC $CFLAGS $LDFLAGS -o conftest.origin/bin/probe conftest.origin/main.c \
|
||||
$hts_origin_link $hts_origin_try "-Wl,-rpath,$hts_origin_ref/../lib" \
|
||||
>&AS_MESSAGE_LOG_FD 2>&1 || continue
|
||||
# From an unrelated cwd, so a loader taking the token literally fails.
|
||||
if test "x$cross_compiling" = xyes ||
|
||||
(unset LD_LIBRARY_PATH DYLD_LIBRARY_PATH
|
||||
cd conftest.origin/run && ../bin/probe) >&AS_MESSAGE_LOG_FD 2>&1; then
|
||||
hts_cv_origin_rpath=$hts_origin_cand
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
rm -rf conftest.origin
|
||||
])
|
||||
AS_CASE([$hts_cv_origin_rpath],
|
||||
[no], [AC_MSG_RESULT([no])],
|
||||
[
|
||||
# $(libdir) first, so the token only answers once the configured
|
||||
# libdir is gone: $(bindir)/../lib is a different directory under a
|
||||
# lib64 or split-bindir layout and must not shadow it.
|
||||
RPATH_ORIGIN_LDFLAGS='-Wl,-rpath,$(libdir)'
|
||||
test "x$hts_cv_origin_rpath" = xorigin && RPATH_ORIGIN_LDFLAGS="$RPATH_ORIGIN_LDFLAGS -Wl,-z,origin"
|
||||
RPATH_ORIGIN_LDFLAGS="$RPATH_ORIGIN_LDFLAGS -Wl,-rpath,$hts_origin_ref_make/../lib"
|
||||
if test "x$hts_origin_darwin" = xyes; then
|
||||
archive_cmds=$hts_origin_archive
|
||||
archive_expsym_cmds=$hts_origin_expsym
|
||||
fi
|
||||
ORIGIN_RPATH=yes
|
||||
AC_MSG_RESULT([yes ($hts_origin_ref/../lib)])
|
||||
])
|
||||
fi
|
||||
AC_SUBST([ORIGIN_RPATH])
|
||||
AC_SUBST([RPATH_ORIGIN_LDFLAGS])
|
||||
|
||||
# The @rpath id is only safe for a consumer carrying its own LC_RPATH, so
|
||||
# libhttrack.pc hands one out -- under the gates the executables' own rpath
|
||||
# respects, so that --disable-origin-rpath and an archive-only build stay
|
||||
# rpath-free too. ${libdir} is pkg-config's own variable, expanded on query.
|
||||
PKGCONFIG_RPATH=no
|
||||
PKGCONFIG_RPATH_LDFLAG=
|
||||
AS_IF([test "x$enable_origin_rpath" != xno && test "x$enable_shared" != xno &&
|
||||
test "x$hts_origin_sysdir" = xno],
|
||||
[PKGCONFIG_RPATH=yes
|
||||
PKGCONFIG_RPATH_LDFLAG=' -Wl,-rpath,${libdir}'])
|
||||
AC_SUBST([PKGCONFIG_RPATH])
|
||||
AC_SUBST([PKGCONFIG_RPATH_LDFLAG])
|
||||
|
||||
### Check for -fvisibility=hidden support
|
||||
gl_VISIBILITY
|
||||
AM_CFLAGS="$AM_CFLAGS $CFLAG_VISIBILITY"
|
||||
@@ -173,7 +399,10 @@ AC_CHECK_TYPE(sa_family_t, [], [AC_DEFINE([sa_family_t], [uint16_t], [sa_family_
|
||||
AX_CHECK_ALIGNED_ACCESS_REQUIRED
|
||||
|
||||
# check for various headers
|
||||
AC_CHECK_HEADERS([execinfo.h sys/ioctl.h])
|
||||
AC_CHECK_HEADERS([execinfo.h sys/ioctl.h sys/random.h])
|
||||
|
||||
## CSPRNG for the --single-file mark; /dev/urandom is the fallback
|
||||
AC_CHECK_FUNCS([getrandom])
|
||||
|
||||
### zlib (mandatory)
|
||||
CHECK_ZLIB()
|
||||
@@ -217,7 +446,8 @@ AC_CHECK_LIB(crypto, EVP_get_digestbyname,
|
||||
LIBS="$LIBS $OPENSSL_LIBS"
|
||||
AC_CHECK_LIB(ssl, SSL_CTX_new,
|
||||
[
|
||||
OPENSSL_LIBS="$OPENSSL_LIBS -lssl"
|
||||
# -lssl first: an archive link needs it ahead of the -lcrypto it uses.
|
||||
OPENSSL_LIBS="-lssl $OPENSSL_LIBS"
|
||||
AC_DEFINE(HTS_USEOPENSSL, 1, [Check for OpenSSL])
|
||||
],
|
||||
[
|
||||
@@ -285,6 +515,34 @@ AC_DEFINE(DLLIB, 1,[Check for dlopen in c])], AC_MSG_WARN([*** not found * this
|
||||
AC_SUBST(DL_LIBS)
|
||||
fi
|
||||
|
||||
### What libhttrack.pc tells a consumer about its private dependencies
|
||||
# A static link needs each library ahead of the ones it uses, which only a
|
||||
# dependency's own .pc gets right (and which alone carries the -L an
|
||||
# out-of-the-way prefix needs), so name the module wherever one is installed.
|
||||
# Dependents first: pkg-config emits Requires.private after Libs.private.
|
||||
AC_ARG_VAR([PKG_CONFIG], [path to the pkg-config utility])
|
||||
AC_PATH_TOOL([PKG_CONFIG], [pkg-config], [false])
|
||||
PKGCONFIG_REQUIRES_PRIVATE=
|
||||
PKGCONFIG_LIBS_PRIVATE=
|
||||
hts_pc_dep() { # hts_pc_dep <module or empty> <link line>
|
||||
test -n "$2" || return 0
|
||||
if test -n "$1" && $PKG_CONFIG --exists "$1" 2>/dev/null; then
|
||||
PKGCONFIG_REQUIRES_PRIVATE="${PKGCONFIG_REQUIRES_PRIVATE:+$PKGCONFIG_REQUIRES_PRIVATE }$1"
|
||||
else
|
||||
PKGCONFIG_LIBS_PRIVATE="${PKGCONFIG_LIBS_PRIVATE:+$PKGCONFIG_LIBS_PRIVATE }$2"
|
||||
fi
|
||||
}
|
||||
# Whichever half of OpenSSL was actually found; https=auto can settle for libcrypto.
|
||||
AS_CASE([" $OPENSSL_LIBS "],
|
||||
[*" -lssl "*], [hts_pc_openssl=openssl],
|
||||
[*" -lcrypto "*], [hts_pc_openssl=libcrypto],
|
||||
[hts_pc_openssl=])
|
||||
hts_pc_dep "$hts_pc_openssl" "$OPENSSL_LIBS"
|
||||
hts_pc_dep libbrotlidec "$BROTLI_LIBS"
|
||||
hts_pc_dep libzstd "$ZSTD_LIBS"
|
||||
AC_SUBST([PKGCONFIG_REQUIRES_PRIVATE])
|
||||
AC_SUBST([PKGCONFIG_LIBS_PRIVATE])
|
||||
|
||||
### Check for setuid
|
||||
AC_CHECK_LIB(c, setuid, [
|
||||
AC_DEFINE(SETUID, 1,[Check for setuid])], AC_MSG_RESULT([not found]))
|
||||
@@ -299,7 +557,7 @@ AC_DEFINE(HAVE_STRNLEN, 1,[Check for strnlen])], AC_MSG_RESULT([not found]))
|
||||
## Online unit tests
|
||||
AC_MSG_CHECKING(whether to enable online unit tests)
|
||||
AC_ARG_ENABLE([online-unit-tests],
|
||||
[AS_HELP_STRING([--enable-online-unit-tests=@<:@yes/no/auto@:>@],[Enable online-unit-tests @<:@default=yes@:>@])],
|
||||
[AS_HELP_STRING([--enable-online-unit-tests=@<:@yes/no/auto@:>@],[Enable online-unit-tests @<:@default=no@:>@])],
|
||||
[
|
||||
case "${enableval}" in
|
||||
no|yes|auto)
|
||||
@@ -341,6 +599,10 @@ if test x"$fuzzers" = x"yes"; then
|
||||
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)])])
|
||||
# Ordinary programs are instrumented too, so they need that runtime at link.
|
||||
AX_CHECK_LINK_FLAG([-fsanitize=fuzzer-no-link],
|
||||
[DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -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])
|
||||
@@ -348,10 +610,25 @@ if test x"$fuzzers" = x"yes"; then
|
||||
fi
|
||||
AM_CONDITIONAL([FUZZERS], [test x"$fuzzers" = x"yes"])
|
||||
|
||||
# tests/Makefile.am takes its TESTS from here instead of a checked-in list,
|
||||
# which made every pair of test-adding PRs conflict on the forge (#844).
|
||||
AC_MSG_CHECKING([for test scripts])
|
||||
TESTS_LIST=
|
||||
hts_ntests=0
|
||||
for hts_t in "$srcdir"/tests/[[0-9]]*_*.test; do
|
||||
test -f "$hts_t" || continue
|
||||
TESTS_LIST="$TESTS_LIST `echo "$hts_t" | sed 's|.*/||'`"
|
||||
hts_ntests=`expr $hts_ntests + 1`
|
||||
done
|
||||
AC_SUBST([TESTS_LIST])
|
||||
AC_MSG_RESULT([$hts_ntests])
|
||||
test "$hts_ntests" -gt 0 || AC_MSG_ERROR([no test script matched tests/[[0-9]]*_*.test])
|
||||
|
||||
# Final output
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
src/libhttrack.pc
|
||||
man/Makefile
|
||||
m4/Makefile
|
||||
templates/Makefile
|
||||
@@ -360,5 +637,6 @@ html/Makefile
|
||||
libtest/Makefile
|
||||
tests/Makefile
|
||||
fuzz/Makefile
|
||||
tools/Info.plist
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
59
debian/changelog
vendored
@@ -1,3 +1,62 @@
|
||||
httrack (3.49.20-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release: an off-site link that looked like a file could pull
|
||||
in the whole foreign site, and a mirror asked to stop while receiving over
|
||||
FTP hung; full list in history.txt. The documentation was also refreshed.
|
||||
* debian/copyright: record the League Spartan webfont the documentation now
|
||||
bundles (OFL-1.1).
|
||||
|
||||
-- Xavier Roche <xavier@debian.org> Mon, 10 Aug 2026 21:08:40 +0200
|
||||
|
||||
httrack (3.49.19-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release: mostly FTP fixes, plus stack-overflow, mirror
|
||||
interruption and --update data-loss fixes; full list in history.txt. Two
|
||||
of them matter to the build: the test suite no longer assumes GNU
|
||||
coreutils, and the AppStream metainfo no longer declares a non-stock icon
|
||||
name that appstream-util rejects.
|
||||
|
||||
-- Xavier Roche <xavier@debian.org> Sat, 08 Aug 2026 21:29:56 +0200
|
||||
|
||||
httrack (3.49.18-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release, fixing the 3.49.17-1 build failures on armhf,
|
||||
powerpc, hppa and loong64: the test suite's mmap interposer did not
|
||||
compile on the first three, and the alternate-stack test insisted on a
|
||||
longer backtrace than loong64's unwinder produces. Nothing in the engine
|
||||
changed. Upstream now cross-builds the test shims for the ports
|
||||
architectures on every push, so the next such break surfaces before the
|
||||
buildds do.
|
||||
|
||||
-- Xavier Roche <xavier@debian.org> Wed, 05 Aug 2026 23:00:24 +0200
|
||||
|
||||
httrack (3.49.17-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release: security fixes in the FTP and HTTP request paths and
|
||||
in both WebHTTrack interfaces, where a crawled page could reach the control
|
||||
panel, plus crash-report and stack-diagnostic fixes; full list in
|
||||
history.txt. Also fixes the 3.49.16-1 build failures on armhf, loong64 and
|
||||
hppa, both in the crash-report test's unwinding assumptions and in the
|
||||
per-test time budget.
|
||||
* libhttrack-dev ships $(libdir)/pkgconfig/libhttrack.pc, and so now depends
|
||||
on libhttrack3 and on the -dev packages whose modules that file names:
|
||||
libssl-dev, libbrotli-dev and libzstd-dev.
|
||||
* Build with --disable-online-unit-tests. Policy 4.9 forbids network access
|
||||
during a build, and the previous "auto" probe found one on hurd-i386, whose
|
||||
crawl tests then failed on DNS.
|
||||
|
||||
-- Xavier Roche <xavier@debian.org> Wed, 05 Aug 2026 12:28:23 +0200
|
||||
|
||||
httrack (3.49.16-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release: a stack overflow in the cache header writer, which a
|
||||
server's response headers could trigger in httrack and libhttrack3 as well
|
||||
as in proxytrack, and a ProxyTrack DAV buffer overflow; chunked trailer
|
||||
handling, relocatable installs, crash-report backtraces on armhf, a hicolor
|
||||
icon theme and translation fixes; full list in history.txt.
|
||||
|
||||
-- Xavier Roche <xavier@debian.org> Tue, 04 Aug 2026 18:32:40 +0200
|
||||
|
||||
httrack (3.49.15-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release: single-file mirrors with inlined assets, sitemap
|
||||
|
||||
5
debian/control
vendored
@@ -72,7 +72,10 @@ Package: libhttrack-dev
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Section: libdevel
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}, zlib1g-dev
|
||||
# libhttrack3: what the .so symlink and libhttrack.pc's -lhttrack resolve onto. The
|
||||
# other -dev packages: libhttrack.pc names their modules in Requires.private, and
|
||||
# pkg-config fails outright when one of those .pc files is missing.
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}, libhttrack3 (= ${binary:Version}), zlib1g-dev, libssl-dev, libbrotli-dev, libzstd-dev
|
||||
Description: Httrack website copier includes and development files
|
||||
This package adds supplemental files for using the httrack website copier
|
||||
library
|
||||
|
||||
95
debian/copyright
vendored
@@ -44,6 +44,13 @@ License: FSFAP
|
||||
permitted in any medium without royalty provided the copyright notice and
|
||||
this notice are preserved. This file is offered as-is, without any warranty.
|
||||
|
||||
Files: html/fonts/*
|
||||
Copyright: 2020 The League Spartan Project Authors
|
||||
License: OFL-1.1
|
||||
Comment:
|
||||
The woff2 is the latin subset at weight 700, as served by Google Fonts.
|
||||
Upstream declares no Reserved Font Name, so the subset keeps the family name.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2002-2026 Xavier Roche <xavier@debian.org>
|
||||
License: GPL-3+
|
||||
@@ -106,3 +113,91 @@ License: BSD-3-clause
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
License: OFL-1.1
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
.
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
.
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
.
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
.
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
.
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
.
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
.
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
.
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
.
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
.
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
.
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
.
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
.
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
.
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
.
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
1
debian/libhttrack-dev.files
vendored
@@ -1,4 +1,5 @@
|
||||
usr/include/httrack
|
||||
usr/lib/*/libhttrack.{so}
|
||||
usr/lib/*/pkgconfig/libhttrack.pc
|
||||
usr/share/httrack/libtest
|
||||
usr/lib/*/httrack/libtest
|
||||
|
||||
4
debian/rules
vendored
@@ -34,7 +34,9 @@ configure-stamp:
|
||||
|
||||
dh_autoreconf
|
||||
# note: dpkg-buildflags to be removed when compat=9
|
||||
dh_auto_configure -- --enable-online-unit-tests=auto $(shell dpkg-buildflags --export=configure)
|
||||
# Policy 4.9 forbids network access during a build, and "auto" made it a lottery:
|
||||
# hurd-i386 FTBFS'd on a crawl whose DNS went away after the probe had said yes.
|
||||
dh_auto_configure -- --disable-online-unit-tests $(shell dpkg-buildflags --export=configure)
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
|
||||
14
fuzz/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Anchored: a glob like /fuzz-* would also swallow the tracked fuzz-*.c sources.
|
||||
/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
|
||||
@@ -2,7 +2,7 @@
|
||||
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-htsparse fuzz-singlefile fuzz-sitemap fuzz-arc
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
@@ -30,6 +30,11 @@ 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 \
|
||||
@@ -53,6 +58,10 @@ EXTRA_DIST = README.md run-fuzzers.sh \
|
||||
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/many-attrs.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/sitemap/truncated.xml corpus/sitemap/urlset.xml.gz \
|
||||
corpus/arc/roundtrip.arc corpus/arc/truncated.arc \
|
||||
corpus/arc/regress-null-body.arc
|
||||
|
||||
@@ -13,3 +13,5 @@ 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`.
|
||||
|
||||
`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.
|
||||
|
||||
9
fuzz/corpus/arc/regress-null-body.arc
Normal file
@@ -0,0 +1,9 @@
|
||||
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
|
||||
|
||||
11
fuzz/corpus/arc/roundtrip.arc
Normal file
@@ -0,0 +1,11 @@
|
||||
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
|
||||
|
||||
BODYMARKER
|
||||
9
fuzz/corpus/arc/truncated.arc
Normal file
@@ -0,0 +1,9 @@
|
||||
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
|
||||
|
||||
HI
|
||||
@@ -1,3 +1,4 @@
|
||||
<img src="a.png">
|
||||
<img src=big.png alt=over-cap>
|
||||
<img src="../escape.png"><img src="/abs.png"><img src="data:,x">
|
||||
<img src="a.png">
|
||||
<img src=big.png alt=over-cap>
|
||||
<img src="../escape.png"><img src="/abs.png">
|
||||
<img src="data:,x">
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<link rel="stylesheet" href="s.css">
|
||||
<link rel=icon href=a.png>
|
||||
<link rel="next" href="p2.html">
|
||||
<link rel="preload" href="j.js">
|
||||
<link rel="stylesheet" href="s.css">
|
||||
<link rel="icon" href="a.png">
|
||||
<link rel="canonical" href="other.html">
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
<img src="unterminated.png
|
||||
<div style="background:url(a.png">
|
||||
<style>@import url(
|
||||
<!-- unterminated comment
|
||||
<a href=
|
||||
<p a=1 b=2 c=3 d=4 e=5 f=6 g=7 h=8 i=9 j=10 title="> <img src=a.png>">x</p>
|
||||
<!--><img src="a.png">
|
||||
<img src="a.png" >
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<img src="a.png" a0="v" a1="v" a2="v" a3="v" a4="v" a5="v" a6="v" a7="v" a8="v" a9="v" a10="v" a11="v" a12="v" a13="v" a14="v" a15="v" a16="v" a17="v" a18="v" a19="v" a20="v" a21="v" a22="v" a23="v" a24="v" a25="v" a26="v" a27="v" a28="v" a29="v" a30="v" a31="v" a32="v" a33="v" a34="v" a35="v" a36="v" a37="v" a38="v" a39="v" a40="v" a41="v" a42="v" a43="v" a44="v" a45="v" a46="v" a47="v" a48="v" a49="v" a50="v" a51="v" a52="v" a53="v" a54="v" a55="v" a56="v" a57="v" a58="v" a59="v" a60="v" a61="v" a62="v" a63="v" a64="v" a65="v" a66="v" a67="v" a68="v" a69="v">
|
||||
1
fuzz/corpus/singlefile/mark-at-eof.html
Normal file
@@ -0,0 +1 @@
|
||||
a.png
|
||||
5
fuzz/corpus/singlefile/mark-degenerate.html
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
==
|
||||
""
|
||||
a.png#!htsinlin
|
||||
#!htsinlin
|
||||
1
fuzz/corpus/singlefile/mark-only.html
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<script>var s="</scripting>"; if(a</b) x=1;</script>
|
||||
<script src="j.js"></script>
|
||||
<textarea></textareas></textarea>
|
||||
<title></titles></title>
|
||||
<script src="j.js"></script>
|
||||
<script>var u="a.png";</script>
|
||||
<textarea>a.png</textarea>
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
<img srcset="a.png 1x, big.png 2x, a.png 100w">
|
||||
<source srcset="a.png,, a.png 2x," src="a.png">
|
||||
<img srcset="a.png 1x, big.png 2x, a.png 480w">
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
<div style="background:url(a.png);list-style:url('a.png')"></div>
|
||||
<p style='background:url("a.png")'>x</p>
|
||||
<div style="background:url(a.png)"></div>
|
||||
<div style='background:url("a.png")'></div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<style>@import "s.css";
|
||||
@import url(sub/b.css);
|
||||
div{background:url(a.png)}
|
||||
/* url(a.png) */ p:after{content:"url(a.png)"}
|
||||
<style>@import "s.css";
|
||||
@import url(sub/b.css);
|
||||
div{background:url(a.png)}
|
||||
</style>
|
||||
|
||||
4
fuzz/corpus/singlefile/traversal.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<img src="../../../../etc/passwd">
|
||||
<img src="a.png#frag?q=1">
|
||||
<img src="sub/../a.png">
|
||||
<img src="./a.png">
|
||||
106
fuzz/fuzz-arc.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
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 <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 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -60,6 +60,10 @@ static void sf_cleanup(void) {
|
||||
(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];
|
||||
@@ -76,6 +80,48 @@ 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<ref>\002 in an input becomes <ref> 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";
|
||||
@@ -83,6 +129,9 @@ static void sf_init(void) {
|
||||
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)
|
||||
@@ -95,37 +144,50 @@ static void sf_init(void) {
|
||||
sf_write("a.png", png, sizeof(png) - 1);
|
||||
sf_write("big.png", big, sizeof(big));
|
||||
sf_text("j.js", "var x=1;\n");
|
||||
/* @import plus a url(), so an inlined stylesheet recurses and its own
|
||||
relative reference is rebased. */
|
||||
sf_text("s.css", "@import url(sub/b.css);\ndiv{background:url(a.png)}\n");
|
||||
sf_text("sub/b.css", "p{background:url(../a.png)}\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;
|
||||
httrackp *opt;
|
||||
/* Exact-length, unterminated: the rewriter is span-based, so ASan bounds a
|
||||
read past html_len instead of it landing on a terminator. */
|
||||
char *html = malloct(size != 0 ? size : 1);
|
||||
String in = STRING_EMPTY;
|
||||
char *html;
|
||||
size_t html_len;
|
||||
|
||||
if (!inited) {
|
||||
sf_init();
|
||||
inited = 1;
|
||||
}
|
||||
memcpy(html, data, size);
|
||||
|
||||
opt = hts_create_opt();
|
||||
opt->log = opt->errlog = NULL;
|
||||
opt->single_file_max_size = FUZZ_SF_CAP;
|
||||
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(opt, sf_root, sf_page, html, size,
|
||||
(void) singlefile_rewrite_html(sf_opt, sf_root, sf_page, html, html_len,
|
||||
SINGLEFILE_MAX_PAGE_SIZE, &out);
|
||||
|
||||
StringFree(out);
|
||||
freet(html);
|
||||
hts_free_opt(opt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ Please visit our Website: http://www.httrack.com
|
||||
#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) {
|
||||
HTS_UNUSED static char *fuzz_strdup(const uint8_t *data, size_t size) {
|
||||
char *s = malloct(size + 1);
|
||||
|
||||
memcpy(s, data, size);
|
||||
|
||||
83
history.txt
@@ -4,6 +4,87 @@ HTTrack Website Copier release history:
|
||||
|
||||
This file lists all changes and fixes that have been made for HTTrack
|
||||
|
||||
3.49-20
|
||||
+ Fixed: a link to another host whose name looked like a file was scanned as a page, so one link could mirror the whole foreign site on the referring page's depth budget (#121)
|
||||
+ Fixed: a size-bounded filter built both of its filter URLs wrong when the path had no leading slash (#1095)
|
||||
+ Fixed: a mirror told to quit while an FTP file was being received announced the exit and then waited forever on that slot (#1106)
|
||||
+ Fixed: stopping an FTP transfer closed its data socket twice, so a threaded crawl could lose another worker's connection (#1090)
|
||||
+ Fixed: WebHTTrack's welcome page opened its language menu blank instead of marking the language in use (#1084)
|
||||
+ Fixed: two suite tests failed on the hppa, powerpc and ppc64 Debian buildds, holding the package back on those ports (#1108)
|
||||
+ Fixed: a growable string could wrap its capacity to zero instead of saturating (#1062)
|
||||
+ Changed: the macOS disk image carries its architecture in its name, so an Intel user can tell before downloading that the build is for Apple Silicon (#1083)
|
||||
+ Changed: refreshed the GUI guide, its screenshots, the documentation typography and the footer contrast
|
||||
+ Changed: settled on one spelling of the product name across the docs and the site
|
||||
+ Changed: multiple internal hardening, build, test and CI improvements
|
||||
|
||||
3.49-19
|
||||
+ Fixed: an over-long user name in an ftp:// URL was truncated at the credential boundary, so the login went to a different account (#1032)
|
||||
+ Fixed: an over-long FTP path or host name aborted the process instead of failing that one link (#1019)
|
||||
+ Fixed: an FTP crawl ignored --timeout and --max-time, so a server that went quiet held a slot for five minutes (#1039)
|
||||
+ Fixed: an FTP crawl of a dead host took two minutes to give up, and no signal could shorten it (#1059)
|
||||
+ Fixed: the engine released the transfer slots while an FTP thread was still writing to one, crashing a mirror that hit its size or time limit (#1051)
|
||||
+ Fixed: Ctrl-C did not shorten a connection or a name lookup already in flight, so ending a crawl against an unreachable host took minutes (#1073)
|
||||
+ Fixed: a crawl that gave up mid-loop, on the link limit or an abort, lost its WARC archive and its change report, and a WARC written past teardown was stranded in a .tmp file (#1061, #1060)
|
||||
+ Fixed: a crawl that rolled back for want of data still replaced the previous WARC archive, stranding its temporary and never writing its index; a stale or unwritable index is now reported rather than left silently in place (#1053)
|
||||
+ Fixed: a resume the server answered with an unusable Content-Range deleted the partial file and never fetched it again; the restart no longer spends the retry budget, and is latched to one per link (#581, #1052)
|
||||
+ Fixed: a long argument to -n or -O smashed the stack through an unbounded panic message, and the growable arrays could wrap their capacity to zero (#1040)
|
||||
+ Fixed: --single-file could write a reference mark longer than it reads back, leaving it in the delivered page as visible text (#1054, #1069)
|
||||
+ Fixed: on a terminal with no input left, a crawl toggled between the spinner and the full panel on every pass (#1072)
|
||||
+ Fixed: -%v1 ended each line with a carriage return, so the lines overwrote each other and a redirected log was unreadable; -%v2 now paints its panel only on a terminal
|
||||
+ Fixed: the installed socket headers did not compile under -std=c99 without _POSIX_C_SOURCE (#1001)
|
||||
+ Fixed: the 16 px application icon rendered every stem as grey (#938)
|
||||
+ Fixed: the desktop files installed outside the data directory, and the AppStream metainfo declared an icon name that is not a stock one
|
||||
+ Fixed: the build failed on distributions whose coreutils are not GNU's (#1042)
|
||||
+ Changed: --single-file drops its own HTML and CSS scanner and reuses the crawler's parser, so it follows the same references the mirror does (#749)
|
||||
+ Changed: updated Turkish translation, and repaired two mangled Polish strings (#306)
|
||||
+ Changed: multiple internal hardening, build, test and CI improvements
|
||||
|
||||
3.49-18
|
||||
+ Fixed: the 3.49.17 package build failed on four architectures: the test suite's mmap interposer did not compile on armhf, powerpc or hppa, and the alternate-stack test rejected loong64's shorter backtrace (#1023)
|
||||
+ Fixed: the test suite failed on a host with no ps command, such as a Fedora build root; its hang diagnostics now read /proc directly (#1021)
|
||||
+ Changed: multiple internal test and CI improvements, including a cross-compile matrix covering the Debian ports architectures
|
||||
|
||||
3.49-17
|
||||
+ New: a pkg-config file, libhttrack.pc, ships with the development headers (#1018)
|
||||
+ Fixed: a crawled page could read the WebHTTrack session id and drive the control panel; the id is now unguessable and cross-origin commands are refused (#877)
|
||||
+ Fixed: an ftp:// link carrying encoded line breaks could append commands to the FTP control channel, and an unquoted LIST argument let a path holding a space list something else (#1010)
|
||||
+ Fixed: a crawled link could inject header lines into the requests HTTrack sends (#1008)
|
||||
+ Fixed: a control byte in a link made the crawler fetch a URL the page never wrote, and stripping one left the original tail glued to the result (#982, #974)
|
||||
+ Fixed: the WebHTTrack progress panel rendered crawled URLs into HTML and JavaScript unescaped (#973)
|
||||
+ Fixed: the WebHTTrack command box rendered its settings unescaped, so a posted value could break out of the box it was shown in (#998)
|
||||
+ Fixed: the WebHTTrack settings pages interpolated values into attributes unescaped, lost a value containing a quote, and mangled a Windows path such as C:\ab (#989)
|
||||
+ Fixed: a worker thread exhausting its stack died with no diagnostic (#969)
|
||||
+ Fixed: a crash report named no frame of the executable on a non-PIE build, and named the dynamic loader rather than the program when launched through it (#995, #996)
|
||||
+ Fixed: the crash report could hang, its symbolizer being forked from the signal handler (#968)
|
||||
+ Fixed: the installed headers declared symbols the library does not export, and scoped struct addrinfo inside a parameter list (#977, #987)
|
||||
+ Fixed: an install moved away from its configured prefix could not find libhttrack on macOS (#978)
|
||||
+ Fixed: 3.49.16 did not build on armhf, loong64, hppa or hurd-i386 (#1015)
|
||||
+ Changed: mirrored pages are served sandboxed, so a saved page can no longer script the WebHTTrack panel, and loses cookies, storage and cross-frame access (#877)
|
||||
+ Changed: htsserver exits with a diagnostic rather than fall back to a guessable session id when no entropy source answers (#877)
|
||||
+ Changed: an FTP file whose name contains a tab is no longer fetched (#1010)
|
||||
+ Changed: on macOS, libhttrack records @rpath/libhttrack.3.dylib, so anything linked against it afterwards supplies its own rpath (#978)
|
||||
+ Changed: multiple internal hardening, build, test and CI improvements
|
||||
|
||||
3.49-16
|
||||
+ New: macOS ships a signed and notarized HTTrack.app with its own icon, bundling the OpenSSL it needs so a downloaded copy launches (#890, #900, #901, #950)
|
||||
+ New: the desktop icons install into the hicolor theme, scalable SVG included, so Icon=httrack resolves in a launcher (#932, #933)
|
||||
+ Fixed: an unauthenticated PROPFIND overflowed the ProxyTrack DAV item buffer (#836)
|
||||
+ Fixed: response headers from the server overflowed the stack buffer holding the cache header block, in both httrack and ProxyTrack (#841)
|
||||
+ Fixed: a chunked response carrying trailers was rejected as "Invalid chunk" (#855)
|
||||
+ Fixed: an over-long URL aborted the whole mirror inside the cache instead of reading as a miss (#935, #936)
|
||||
+ Fixed: ProxyTrack could not re-read the .arc it writes, and crashed on a record whose body it could not read (#834, #929, #931)
|
||||
+ Fixed: ProxyTrack logged a hashtable stats line and every PROPFIND body to stderr (#911, #918)
|
||||
+ Fixed: the frozen-slot spool was written inside the mirror namespace, so it landed in the mirrored tree (#859)
|
||||
+ Fixed: a stack overflow killed httrack with no diagnostic, crash reports named no frame of the executable, and on armhf they had no frames at all (#866, #889, #892)
|
||||
+ Fixed: an install moved away from its configured prefix could not find its data directory, its shared library, or the html symlink (#885, #887, #894, #906)
|
||||
+ Fixed: tooltips in the web GUI broke on a translation containing an apostrophe; the escaping now also covers quotes, backslashes, markup and DBCS lead bytes (#864)
|
||||
+ Fixed: nine strings of the Windows GUI's option dialogs were untranslated in 26 of the 30 language files, and six language files disagreed with their own declared charset (#863, #963)
|
||||
+ Fixed: the AppStream metainfo still advertised WebHTTrack 3.49.8 (#884)
|
||||
+ Fixed: the installed development headers did not compile standalone (#943)
|
||||
+ Fixed: configure discarded a user-supplied BASH_SHELL, resolved bash to /bin/sh on macOS, and hung on one pointing at a FIFO (#891, #895, #908, #922)
|
||||
+ Changed: the masthead wordmark and the rings background are SVG, so they stay sharp on a hi-DPI screen (#910, #916)
|
||||
+ Changed: multiple internal hardening, build, test and CI improvements
|
||||
|
||||
3.49-15
|
||||
+ New: --single-file rewrites each saved page with its assets inlined as data: URIs (#713)
|
||||
+ New: --changes reports what a crawl added, updated or removed against the previous mirror (#714)
|
||||
@@ -128,7 +209,7 @@ This file lists all changes and fixes that have been made for HTTrack
|
||||
+ Fixed: report why a -%L URL list could not be loaded (#49)
|
||||
+ Changed: multiple internal hardening, build and CI improvements
|
||||
|
||||
.49-9
|
||||
3.49-9
|
||||
+ Fixed: file-type detection from the Content-Type header: trust a declared type over a binary URL extension, honor --assume under the delayed type check, and keep a known extension against a bogus or empty Content-Type (#267, #29, #56)
|
||||
+ Fixed: an uninitialized-buffer read when the Content-Type is empty (#411)
|
||||
+ Fixed: restored C++ source-compatibility of the installed headers so reverse dependencies (httraqt) build again (#413)
|
||||
|
||||
@@ -4,6 +4,7 @@ HelpHtmldir = $(htmldir)
|
||||
HelpHtmlimgdir = $(HelpHtmldir)/img
|
||||
HelpHtmldivdir = $(HelpHtmldir)/div
|
||||
HelpHtmlimagesdir = $(HelpHtmldir)/images
|
||||
HelpHtmlfontsdir = $(HelpHtmldir)/fonts
|
||||
HelpHtmlTxtdir = $(HelpHtmldir)
|
||||
WebHtmldir = $(HelpHtmldir)/server
|
||||
WebHtmlimagesdir = $(HelpHtmldir)/server/images
|
||||
@@ -11,7 +12,11 @@ WebPixmapdir = $(datadir)/pixmaps
|
||||
WebIcon16x16dir = $(datadir)/icons/hicolor/16x16/apps
|
||||
WebIcon32x32dir = $(datadir)/icons/hicolor/32x32/apps
|
||||
WebIcon48x48dir = $(datadir)/icons/hicolor/48x48/apps
|
||||
VFolderEntrydir = $(prefix)/share/applications
|
||||
WebIcon64x64dir = $(datadir)/icons/hicolor/64x64/apps
|
||||
WebIcon128x128dir = $(datadir)/icons/hicolor/128x128/apps
|
||||
WebIcon256x256dir = $(datadir)/icons/hicolor/256x256/apps
|
||||
WebIconScalabledir = $(datadir)/icons/hicolor/scalable/apps
|
||||
VFolderEntrydir = $(datadir)/applications
|
||||
MetaInfodir = $(datadir)/metainfo
|
||||
|
||||
# Wildcards are globbed against $(srcdir): a bare "*.html" is resolved against
|
||||
@@ -23,27 +28,28 @@ HelpHtml_DATA = $(srcdir)/*.html $(srcdir)/*.js $(srcdir)/*.css
|
||||
HelpHtmldiv_DATA = div/search.sh
|
||||
HelpHtmlimg_DATA = $(srcdir)/img/*
|
||||
HelpHtmlimages_DATA = $(srcdir)/images/*
|
||||
# doc.css reaches the woff2 by a relative URL, so it installs beside the pages.
|
||||
HelpHtmlfonts_DATA = $(srcdir)/fonts/*
|
||||
HelpHtmlTxt_DATA = ../greetings.txt ../history.txt ../license.txt
|
||||
WebHtml_DATA = $(srcdir)/server/*.html $(srcdir)/server/*.js $(srcdir)/server/*.css
|
||||
WebHtmlimages_DATA = $(srcdir)/server/images/*
|
||||
# note: converted & normalized by
|
||||
# ico2xpm favicon.ico -o httrack.xpm
|
||||
# mogrify -format xpm -map /usr/share/doc/menu/examples/cmap.xpm httrack.xpm
|
||||
# Generated from the brand master by gen/export.py. Asserted by tests/160.
|
||||
# httrack.xpm duplicates the 32x32 one under the bare basename the .desktop
|
||||
# Icon= key falls back to here when no icon theme is installed (#932).
|
||||
WebPixmap_DATA = $(srcdir)/server/div/*.xpm
|
||||
WebIcon16x16_DATA = $(srcdir)/server/div/16x16/*.png
|
||||
WebIcon32x32_DATA = $(srcdir)/server/div/32x32/*.png
|
||||
WebIcon48x48_DATA = $(srcdir)/server/div/48x48/*.png
|
||||
WebIcon64x64_DATA = $(srcdir)/server/div/64x64/*.png
|
||||
WebIcon128x128_DATA = $(srcdir)/server/div/128x128/*.png
|
||||
WebIcon256x256_DATA = $(srcdir)/server/div/256x256/*.png
|
||||
WebIconScalable_DATA = $(srcdir)/server/div/scalable/*.svg
|
||||
VFolderEntry_DATA = $(srcdir)/server/div/*.desktop
|
||||
MetaInfo_DATA = $(srcdir)/server/div/*.metainfo.xml
|
||||
|
||||
EXTRA_DIST = $(HelpHtml_DATA) $(HelpHtmlimg_DATA) $(HelpHtmlimages_DATA) \
|
||||
$(HelpHtmlfonts_DATA) \
|
||||
$(HelpHtmldiv_DATA) $(WebHtml_DATA) $(WebHtmlimages_DATA) \
|
||||
$(WebPixmap_DATA) $(WebIcon16x16_DATA) $(WebIcon32x32_DATA) $(WebIcon48x48_DATA) \
|
||||
$(VFolderEntry_DATA) $(MetaInfo_DATA)
|
||||
|
||||
install-data-hook:
|
||||
if test ! -L $(DESTDIR)$(prefix)/share/httrack/html ; then \
|
||||
( cd $(DESTDIR)$(prefix)/share/httrack \
|
||||
&& $(LN_S) $(htmldir) html \
|
||||
) \
|
||||
fi
|
||||
$(WebIcon64x64_DATA) $(WebIcon128x128_DATA) $(WebIcon256x256_DATA) \
|
||||
$(WebIconScalable_DATA) $(VFolderEntry_DATA) $(MetaInfo_DATA)
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
@@ -155,6 +155,8 @@ rather than on <tt>url</tt> when a mirror is known to carry legacy-charset URLs.
|
||||
|
||||
<h3 id="example">Example</h3>
|
||||
|
||||
One captured run; <tt>generator</tt> and <tt>date</tt> will read differently in yours.
|
||||
|
||||
<pre>
|
||||
{
|
||||
"schema": 1,
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
40
html/doc.css
@@ -32,6 +32,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Additions stay out of the palette block above: it is kept byte-identical with the website's. */
|
||||
:root {
|
||||
--body-font: system-ui, -apple-system, "Segoe UI", Roboto, "Trebuchet MS", Verdana, sans-serif;
|
||||
}
|
||||
|
||||
/* Relative URL: the docs are read from an installed directory too. */
|
||||
@font-face {
|
||||
font-family: "League Spartan";
|
||||
src: url(fonts/league-spartan-700-latin.woff2) format("woff2");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
/* The plain declaration before each var() is what IE11 gets: it drops the
|
||||
@@ -44,6 +58,7 @@ body {
|
||||
color: #111;
|
||||
color: var(--ink);
|
||||
font: 1em/1.6 "Trebuchet MS", Verdana, system-ui, -apple-system, "Segoe UI", sans-serif;
|
||||
font-family: var(--body-font);
|
||||
}
|
||||
|
||||
/* ---- page frame ---- */
|
||||
@@ -57,14 +72,21 @@ body {
|
||||
padding: .6rem 0 0;
|
||||
}
|
||||
|
||||
.masthead img { display: block; max-width: 100%; height: auto; }
|
||||
/* Take back the whitespace the SVG carries around the letters, restoring the old bitmap's spacing. */
|
||||
.masthead img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: -1.7px 0 -1.1px;
|
||||
}
|
||||
|
||||
.masthead .tagline {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
padding: .25rem .4rem;
|
||||
margin-top: .4rem;
|
||||
/* A one-line label has no use for the body's prose leading. */
|
||||
line-height: 1;
|
||||
padding: .3rem .4rem;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
@@ -72,14 +94,14 @@ body {
|
||||
background: var(--panel);
|
||||
border-bottom: 6px solid #000;
|
||||
padding: 1.5rem;
|
||||
/* The rings the 2007 pages carried. The image has the light panel colour baked
|
||||
into it, so it is dropped rather than inverted in dark mode. */
|
||||
background-image: url(images/bg_rings.gif);
|
||||
/* The rings the 2007 pages carried. Transparent, so it rides on --panel. */
|
||||
background-image: url(images/bg_rings.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: top right;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
/* Rings dropped, not inverted: their lavender is a light-panel tone. */
|
||||
.wrap { background-image: none; }
|
||||
|
||||
/* The wordmark is black on transparent, and all but vanishes on the dark field. */
|
||||
@@ -98,10 +120,11 @@ body {
|
||||
.wrap.solo { display: block; }
|
||||
}
|
||||
|
||||
/* Colour inherited: nothing lighter than --ink reaches 4.5:1 on the --field
|
||||
this sits on, and at .8em it is small text. */
|
||||
footer {
|
||||
max-width: 68rem;
|
||||
margin: .5rem auto 0;
|
||||
color: #eef;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
@@ -113,6 +136,9 @@ footer {
|
||||
|
||||
h2, h3 { scroll-margin-top: 1rem; }
|
||||
|
||||
/* Top two levels only: a display face reads worse than the system font over prose. */
|
||||
h1, h2 { font-family: "League Spartan", var(--body-font); font-weight: 700; }
|
||||
|
||||
h1 { font-size: 1.9em; margin: 0 0 .3em; line-height: 1.2; }
|
||||
h2 { font-size: 1.45em; margin: 2.5em 0 .5em; padding-bottom: .2em; border-bottom: 2px solid var(--rule); }
|
||||
h3 { font-size: 1.15em; margin: 2em 0 .4em; }
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
93
html/fonts/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The League Spartan Project Authors (https://github.com/theleagueof/league-spartan)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
html/fonts/league-spartan-700-latin.woff2
Normal file
@@ -13,12 +13,14 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- doc-chrome:masthead -->
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="masthead">
|
||||
<img src="images/header_title_4.gif" width="400" height="34" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Open Source offline browser</div>
|
||||
<img src="images/wordmark.svg" width="400" height="36" alt="HTTrack Website Copier">
|
||||
<div class="tagline">Free software offline browser</div>
|
||||
</header>
|
||||
<!-- /doc-chrome:masthead -->
|
||||
|
||||
<div class="wrap">
|
||||
|
||||
@@ -58,6 +60,9 @@
|
||||
|
||||
<main id="main">
|
||||
|
||||
<!-- Section ids are link API: the redirect stubs and the Android app's contextual help
|
||||
hardcode them, and an app release outlives its engine pin. -->
|
||||
|
||||
<h1>The HTTrack interface, step by step</h1>
|
||||
|
||||
<p class="lede">HTTrack copies a website to your disk so you can read it offline. The same
|
||||
@@ -66,7 +71,7 @@ the screenshots and notes follow along.</p>
|
||||
|
||||
<div class="platforms" role="group" aria-label="Choose your version">
|
||||
<button type="button" data-platform="win" aria-pressed="false">WinHTTrack <small>Windows</small></button>
|
||||
<button type="button" data-platform="web" aria-pressed="false">WebHTTrack <small>Linux and Unix</small></button>
|
||||
<button type="button" data-platform="web" aria-pressed="false">WebHTTrack <small>Linux, macOS and Unix</small></button>
|
||||
<button type="button" data-platform="droid" aria-pressed="false">HTTrack <small>Android</small></button>
|
||||
</div>
|
||||
|
||||
@@ -88,7 +93,7 @@ itself down once those pings stop.</p>
|
||||
<p>Each option also lists its command-line equivalent, so anything you set here can later be
|
||||
scripted. The <a href="cmdguide.html">command-line guide</a> covers that side.</p>
|
||||
|
||||
<div class="note" data-for="droid">
|
||||
<div class="note" data-for="droid" id="droid-first-launch">
|
||||
<p><b>First launch.</b> Android asks for permission to store mirrors on your device. Without
|
||||
it the app cannot save anything, so tap <b>Allow</b>.</p>
|
||||
<figure>
|
||||
@@ -117,13 +122,18 @@ data-for="droid">Tap <b>Next</b></span> to create a project, or open one you alr
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-start.png" alt="WinHTTrack welcome pane" width="1040" height="744">
|
||||
<img data-for="web" src="img/guide-web-start.png" alt="WebHTTrack welcome page" width="1024" height="388">
|
||||
<img data-for="web" src="img/guide-web-start.png" alt="WebHTTrack welcome page" width="1024" height="387">
|
||||
<img data-for="droid" src="img/guide-droid-start.png" alt="HTTrack for Android welcome screen" width="600" height="1300">
|
||||
<figcaption>The welcome screen.</figcaption>
|
||||
</figure>
|
||||
|
||||
<p class="note" data-for="web">The language dropdown starts blank on purpose: its first entry
|
||||
means "leave the interface as it is". Pick a language only if you want to change it.</p>
|
||||
<p class="note" data-for="web">The dropdown shows the language the interface is already in.
|
||||
Picking another one reloads the page in it.</p>
|
||||
|
||||
<p class="note" data-for="web">On macOS, <code>brew install httrack</code> installs WebHTTrack
|
||||
alongside the command line tool. Open <b>HTTrack.app</b> if you have it, or run
|
||||
<code>webhttrack</code> in a terminal; either way the interface opens in your browser and
|
||||
behaves exactly as described here.</p>
|
||||
|
||||
<h2 id="step-project">2. Name the project</h2>
|
||||
|
||||
@@ -133,7 +143,7 @@ together in the list.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-project-name.png" alt="WinHTTrack project name, category and base path" width="1040" height="744">
|
||||
<img data-for="web" src="img/guide-web-project-name.png" alt="WebHTTrack project name, category and base path" width="1024" height="346">
|
||||
<img data-for="web" src="img/guide-web-project-name.png" alt="WebHTTrack project name, category and base path" width="1024" height="345">
|
||||
<img data-for="droid" src="img/guide-droid-project-name.png" alt="Android project name, category and base path" width="600" height="1300">
|
||||
<figcaption>Project name, category, and where the files go.</figcaption>
|
||||
</figure>
|
||||
@@ -152,7 +162,7 @@ keep their links to each other.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-project-setup.png" alt="WinHTTrack action and web addresses" width="1040" height="744">
|
||||
<img data-for="web" src="img/guide-web-project-setup.png" alt="WebHTTrack action and web addresses" width="1024" height="496">
|
||||
<img data-for="web" src="img/guide-web-project-setup.png" alt="WebHTTrack action and web addresses" width="1024" height="495">
|
||||
<img data-for="droid" src="img/guide-droid-project-setup.png" alt="Android web address and action" width="600" height="1300">
|
||||
<figcaption>The addresses to copy, and what to do with them.</figcaption>
|
||||
</figure>
|
||||
@@ -207,7 +217,7 @@ port, you point your browser at it as a proxy and click the link or the submit b
|
||||
usual, and the address the browser asks for is added to the project.</p>
|
||||
|
||||
<figure data-for="web">
|
||||
<img data-for="web" src="img/guide-web-add-url.png" alt="WebHTTrack add-a-URL dialog" width="1024" height="634">
|
||||
<img data-for="web" src="img/guide-web-add-url.png" alt="WebHTTrack add-a-URL dialog" width="1024" height="600">
|
||||
<figcaption>Adding a single address, with an optional login.</figcaption>
|
||||
</figure>
|
||||
|
||||
@@ -236,7 +246,7 @@ mirror straight away.</p>
|
||||
|
||||
<figure data-for="win web">
|
||||
<img data-for="win" src="img/guide-win-ready.png" alt="WinHTTrack connection settings before starting" width="1040" height="744">
|
||||
<img data-for="web" src="img/guide-web-ready.png" alt="WebHTTrack ready to start" width="1024" height="508">
|
||||
<img data-for="web" src="img/guide-web-ready.png" alt="WebHTTrack ready to start" width="1024" height="489">
|
||||
<figcaption>The last screen before the mirror runs.</figcaption>
|
||||
</figure>
|
||||
|
||||
@@ -269,7 +279,7 @@ mirrored pages are rewritten to point at each other, so it browses offline in an
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-finished.png" alt="WinHTTrack mirror complete" width="1040" height="744">
|
||||
<img data-for="web" src="img/guide-web-finished.png" alt="WebHTTrack mirror complete" width="1024" height="487">
|
||||
<img data-for="web" src="img/guide-web-finished.png" alt="WebHTTrack mirror complete" width="1024" height="486">
|
||||
<img data-for="droid" src="img/guide-droid-finished.png" alt="Android mirror complete" width="600" height="1300">
|
||||
<figcaption>Done.</figcaption>
|
||||
</figure>
|
||||
@@ -282,7 +292,7 @@ usual causes.</p>
|
||||
<p data-for="win web">The files sit under the base path you chose, in a folder named after the
|
||||
project. Opening <code>index.html</code> there browses the mirror without HTTrack.</p>
|
||||
|
||||
<p data-for="droid">Mirrors are written to
|
||||
<p data-for="droid" id="droid-storage-location">Mirrors are written to
|
||||
<code>/storage/emulated/0/HTTrack/Websites</code>, in a folder named after the project. That is
|
||||
shared storage, so a file manager or a USB cable can reach it, and opening
|
||||
<code>index.html</code> there browses the mirror without the app.</p>
|
||||
@@ -433,7 +443,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-flow-control.png" alt="WinHTTrack Flow Control tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-flow-control.png" alt="WebHTTrack Flow Control tab" width="1024" height="910">
|
||||
<img data-for="web" src="img/guide-web-opt-flow-control.png" alt="WebHTTrack Flow Control tab" width="1024" height="862">
|
||||
<img data-for="droid" src="img/guide-droid-opt-flow-control.png" alt="Android Flow Control tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
@@ -476,7 +486,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-links.png" alt="WinHTTrack Links tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-links.png" alt="WebHTTrack Links tab" width="1024" height="781">
|
||||
<img data-for="web" src="img/guide-web-opt-links.png" alt="WebHTTrack Links tab" width="1024" height="749">
|
||||
<img data-for="droid" src="img/guide-droid-opt-links.png" alt="Android Links tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
@@ -513,7 +523,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-build.png" alt="WinHTTrack Build tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-build.png" alt="WebHTTrack Build tab" width="1024" height="986">
|
||||
<img data-for="web" src="img/guide-web-opt-build.png" alt="WebHTTrack Build tab" width="1024" height="976">
|
||||
<img data-for="droid" src="img/guide-droid-opt-build.png" alt="Android Build tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
@@ -579,7 +589,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-browser-id.png" alt="WinHTTrack Browser ID tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-browser-id.png" alt="WebHTTrack Browser ID tab" width="1024" height="706">
|
||||
<img data-for="web" src="img/guide-web-opt-browser-id.png" alt="WebHTTrack Browser ID tab" width="1024" height="654">
|
||||
<img data-for="droid" src="img/guide-droid-opt-browser-id.png" alt="Android Browser ID tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
@@ -619,7 +629,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-spider.png" alt="WinHTTrack Spider tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-spider.png" alt="WebHTTrack Spider tab" width="1024" height="1557">
|
||||
<img data-for="web" src="img/guide-web-opt-spider.png" alt="WebHTTrack Spider tab" width="1024" height="1541">
|
||||
<img data-for="droid" src="img/guide-droid-opt-spider.png" alt="Android Spider tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
@@ -706,7 +716,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-proxy.png" alt="WinHTTrack Proxy tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-proxy.png" alt="WebHTTrack Proxy tab" width="1024" height="762">
|
||||
<img data-for="web" src="img/guide-web-opt-proxy.png" alt="WebHTTrack Proxy tab" width="1024" height="760">
|
||||
<img data-for="droid" src="img/guide-droid-opt-proxy.png" alt="Android Proxy tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
@@ -743,7 +753,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-log-index-cache.png" alt="WinHTTrack Log, Index, Cache tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-log-index-cache.png" alt="WebHTTrack Log, Index, Cache tab" width="1024" height="1278">
|
||||
<img data-for="web" src="img/guide-web-opt-log-index-cache.png" alt="WebHTTrack Log, Index, Cache tab" width="1024" height="1266">
|
||||
<img data-for="droid" src="img/guide-droid-opt-log-index-cache.png" alt="Android Log, Index, Cache tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
@@ -842,7 +852,7 @@ bottom are the ones that keep you welcome.</p>
|
||||
|
||||
<figure>
|
||||
<img data-for="win" src="img/guide-win-opt-experts-only.png" alt="WinHTTrack Experts Only tab" width="524" height="448">
|
||||
<img data-for="web" src="img/guide-web-opt-experts-only.png" alt="WebHTTrack Experts Only tab" width="1024" height="1088">
|
||||
<img data-for="web" src="img/guide-web-opt-experts-only.png" alt="WebHTTrack Experts Only tab" width="1024" height="1085">
|
||||
<img data-for="droid" src="img/guide-droid-opt-experts-only.png" alt="Android Experts Only tab" width="600" height="1300">
|
||||
</figure>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ a:active { text-decoration: underline; }
|
||||
border-bottom: 6px solid #000;
|
||||
padding: 10px; padding-top: 20px;
|
||||
line-height: 1.65em;
|
||||
background-image: url(images/bg_rings.gif);
|
||||
background-image: url(images/bg_rings.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: top right;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
8
html/images/bg_rings.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="501" height="456" viewBox="0 0 501 456">
|
||||
<title>HTTrack rings</title>
|
||||
<!-- Transparent, unlike the GIF this replaces: the panel's own #ccd shows through. -->
|
||||
<g fill="#b9b9d0" fill-rule="evenodd">
|
||||
<path d="M614.59 346.3A323.36 197.55 21.16 1 0 11.46 112.89A323.36 197.55 21.16 1 0 614.59 346.3 ZM590.57 315.66A262.58 160.99 22.18 1 0 104.26 117.43A262.58 160.99 22.18 1 0 590.57 315.66 Z"/>
|
||||
<path d="M578.08 292.16A185.6 113.57 21.23 1 0 232.08 157.73A185.6 113.57 21.23 1 0 578.08 292.16 ZM564.4 274.56A150.77 92.55 22.26 1 0 285.34 160.32A150.77 92.55 22.26 1 0 564.4 274.56 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 641 B |
|
Before Width: | Height: | Size: 1.9 KiB |
1
html/images/wordmark.svg
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 9.0 KiB |