mirror of
https://github.com/xroche/httrack.git
synced 2026-07-15 13:21:14 +03:00
Compare commits
75 Commits
wait-socke
...
proxy-modu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ab3726508 | ||
|
|
573e62e08c | ||
|
|
1fa0184468 | ||
|
|
79e46eeceb | ||
|
|
436ac53793 | ||
|
|
bc4b2c7b8e | ||
|
|
4fafe283b4 | ||
|
|
9ec5a3a067 | ||
|
|
cd38e6e68d | ||
|
|
e692e56592 | ||
|
|
7d9d4ed890 | ||
|
|
573167e8dd | ||
|
|
e26a5f5c6a | ||
|
|
627ae2b043 | ||
|
|
71ab3574ef | ||
|
|
076127ddea | ||
|
|
dced0208e1 | ||
|
|
6e34c30a7c | ||
|
|
eac13ea248 | ||
|
|
dc3e485f92 | ||
|
|
fac84f1631 | ||
|
|
c32d286938 | ||
|
|
5a7ab7a653 | ||
|
|
5756a9830c | ||
|
|
28c11d55eb | ||
|
|
b5f28f6eb5 | ||
|
|
3d65bb2e3b | ||
|
|
68897b09ce | ||
|
|
e8d1bf9c19 | ||
|
|
ef40277c24 | ||
|
|
797acecfd2 | ||
|
|
8237c3ed2b | ||
|
|
75b815e1fb | ||
|
|
8d02e60907 | ||
|
|
e70607e70c | ||
|
|
cada6a1ae3 | ||
|
|
145ea4769f | ||
|
|
c5da5a2f2e | ||
|
|
6eaefe6233 | ||
|
|
33249be5a0 | ||
|
|
167ede32c0 | ||
|
|
c8b7c63c9b | ||
|
|
04f37b2094 | ||
|
|
c07b19bc3d | ||
|
|
04bbb489cf | ||
|
|
a24b1d3c9f | ||
|
|
1abf867333 | ||
|
|
771d11326e | ||
|
|
7faceaf7d2 | ||
|
|
9105732112 | ||
|
|
9c01812141 | ||
|
|
7a02d5e411 | ||
|
|
3c7e9fa46d | ||
|
|
a707d4b845 | ||
|
|
65c1016a4e | ||
|
|
fd2252dc8c | ||
|
|
53a257448f | ||
|
|
8ba3cb6c03 | ||
|
|
b9afe755bd | ||
|
|
407916e3f6 | ||
|
|
15021cd470 | ||
|
|
5f7045c3a4 | ||
|
|
f66ec195aa | ||
|
|
7928db5729 | ||
|
|
20be48d56c | ||
|
|
484fc47eab | ||
|
|
abaf9b69a2 | ||
|
|
b0466b1d7b | ||
|
|
f785286c87 | ||
|
|
440a8603a9 | ||
|
|
4979e58dc0 | ||
|
|
894cf5a8d2 | ||
|
|
0c1aa51385 | ||
|
|
fb4267c6d7 | ||
|
|
f0b044c2f3 |
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Resource scripts are Windows tooling input and must stay CRLF: the engine has no
|
||||||
|
# encoding guard, so an autocrlf checkout could otherwise flatten them silently.
|
||||||
|
*.rc text eol=crlf
|
||||||
138
.github/workflows/ci.yml
vendored
138
.github/workflows/ci.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends \
|
sudo apt-get install -y --no-install-recommends \
|
||||||
build-essential clang autoconf automake libtool autoconf-archive \
|
build-essential clang autoconf automake libtool autoconf-archive \
|
||||||
zlib1g-dev libssl-dev
|
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
@@ -50,12 +50,17 @@ jobs:
|
|||||||
# committed generated files already let a plain checkout build.
|
# committed generated files already let a plain checkout build.
|
||||||
autoreconf -fi
|
autoreconf -fi
|
||||||
./configure
|
./configure
|
||||||
|
# a missing decoder would silently drop the coding from Accept-Encoding
|
||||||
|
grep -q "define HTS_USEBROTLI 1" config.h
|
||||||
|
grep -q "define HTS_USEZSTD 1" config.h
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make -j"$(nproc)"
|
run: make -j"$(nproc)"
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make check
|
run: |
|
||||||
|
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||||
|
make check -j"$jobs"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
@@ -80,7 +85,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends \
|
sudo apt-get install -y --no-install-recommends \
|
||||||
build-essential autoconf automake libtool autoconf-archive \
|
build-essential autoconf automake libtool autoconf-archive \
|
||||||
zlib1g-dev libssl-dev
|
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
@@ -99,7 +104,8 @@ jobs:
|
|||||||
sudo find /usr/bin /usr/local/bin -maxdepth 1 -name 'python3*' \
|
sudo find /usr/bin /usr/local/bin -maxdepth 1 -name 'python3*' \
|
||||||
-exec mv {} {}.hidden \;
|
-exec mv {} {}.hidden \;
|
||||||
! command -v python3
|
! command -v python3
|
||||||
make check
|
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||||
|
make check -j"$jobs"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
@@ -120,25 +126,70 @@ jobs:
|
|||||||
- name: Install build dependencies
|
- name: Install build dependencies
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
brew install autoconf automake libtool autoconf-archive
|
brew install autoconf automake libtool autoconf-archive brotli zstd
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
ssl="$(brew --prefix openssl@3)"
|
ssl="$(brew --prefix openssl@3)"
|
||||||
|
brewp="$(brew --prefix)"
|
||||||
autoreconf -fi
|
autoreconf -fi
|
||||||
./configure CPPFLAGS="-I${ssl}/include" LDFLAGS="-L${ssl}/lib"
|
./configure CPPFLAGS="-I${ssl}/include -I${brewp}/include" \
|
||||||
|
LDFLAGS="-L${ssl}/lib -L${brewp}/lib"
|
||||||
|
grep -q "define HTS_USEBROTLI 1" config.h
|
||||||
|
grep -q "define HTS_USEZSTD 1" config.h
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make -j"$(sysctl -n hw.ncpu)"
|
run: make -j"$(sysctl -n hw.ncpu)"
|
||||||
|
|
||||||
|
- name: Add loopback aliases (macOS lacks 127.0.0.2/.3)
|
||||||
|
# 19_local-connect-fallback needs the dead 127.0.0.2/.3 to refuse
|
||||||
|
# instantly like Linux; alias them onto lo0 so they don't stall to timeout.
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
sudo ifconfig lo0 alias 127.0.0.2 up
|
||||||
|
sudo ifconfig lo0 alias 127.0.0.3 up
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make check
|
run: |
|
||||||
|
jobs=$(( $(sysctl -n hw.ncpu) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||||
|
make check -j"$jobs"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
run: cat tests/test-suite.log 2>/dev/null || true
|
run: cat tests/test-suite.log 2>/dev/null || true
|
||||||
|
|
||||||
|
# Runtime smoke of the WebHTTrack launcher on macOS: it carries a Darwin-only
|
||||||
|
# browser path (open -W) and nothing else exercises htsserver. Install into a
|
||||||
|
# temp prefix, then check webhttrack brings up htsserver and serves the UI.
|
||||||
|
webhttrack-macos:
|
||||||
|
name: webhttrack smoke (macOS arm64)
|
||||||
|
runs-on: macos-14
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
brew install autoconf automake libtool autoconf-archive brotli zstd
|
||||||
|
|
||||||
|
- name: Build and install into a temp prefix
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
ssl="$(brew --prefix openssl@3)"
|
||||||
|
brewp="$(brew --prefix)"
|
||||||
|
autoreconf -fi
|
||||||
|
./configure CPPFLAGS="-I${ssl}/include -I${brewp}/include" \
|
||||||
|
LDFLAGS="-L${ssl}/lib -L${brewp}/lib" \
|
||||||
|
--prefix="$RUNNER_TEMP/inst"
|
||||||
|
make -j"$(sysctl -n hw.ncpu)"
|
||||||
|
make install
|
||||||
|
|
||||||
|
- name: Smoke-test webhttrack
|
||||||
|
run: bash tests/webhttrack-smoke.sh "$RUNNER_TEMP/inst"
|
||||||
|
|
||||||
# Portability/hardening: 32-bit (i386) build on the x86-64 runner via multilib
|
# 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
|
# -- 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
|
# and bounds math can truncate or wrap in ways 64-bit never reveals (the axis
|
||||||
@@ -159,7 +210,8 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends \
|
sudo apt-get install -y --no-install-recommends \
|
||||||
build-essential gcc-multilib autoconf automake libtool \
|
build-essential gcc-multilib autoconf automake libtool \
|
||||||
autoconf-archive zlib1g-dev:i386 libssl-dev:i386
|
autoconf-archive zlib1g-dev:i386 libssl-dev:i386 \
|
||||||
|
libbrotli-dev:i386 libzstd-dev:i386
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
@@ -171,7 +223,9 @@ jobs:
|
|||||||
run: make -j"$(nproc)"
|
run: make -j"$(nproc)"
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make check
|
run: |
|
||||||
|
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||||
|
make check -j"$jobs"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
@@ -198,7 +252,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends \
|
sudo apt-get install -y --no-install-recommends \
|
||||||
build-essential autoconf automake libtool autoconf-archive \
|
build-essential autoconf automake libtool autoconf-archive \
|
||||||
zlib1g-dev libssl-dev
|
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||||
|
|
||||||
- name: Configure (sanitized)
|
- name: Configure (sanitized)
|
||||||
run: |
|
run: |
|
||||||
@@ -226,7 +280,9 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
ASAN_OPTIONS: detect_leaks=0:abort_on_error=1:halt_on_error=1:strict_string_checks=1:malloc_fill_byte=202:max_malloc_fill_size=2147483647:free_fill_byte=203:max_free_fill_size=2147483647
|
ASAN_OPTIONS: detect_leaks=0:abort_on_error=1:halt_on_error=1:strict_string_checks=1:malloc_fill_byte=202:max_malloc_fill_size=2147483647:free_fill_byte=203:max_free_fill_size=2147483647
|
||||||
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
|
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
|
||||||
run: make check
|
run: |
|
||||||
|
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||||
|
make check -j"$jobs"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
@@ -272,12 +328,52 @@ jobs:
|
|||||||
# 01_engine-* only; zlib-dependent self-tests are named 01_zlib-* and
|
# 01_engine-* only; zlib-dependent self-tests are named 01_zlib-* and
|
||||||
# skipped here (uninstrumented libz floods MSan with false positives).
|
# skipped here (uninstrumented libz floods MSan with false positives).
|
||||||
tests="$(cd tests && ls 01_engine-*.test | tr '\n' ' ')"
|
tests="$(cd tests && ls 01_engine-*.test | tr '\n' ' ')"
|
||||||
make check TESTS="$tests"
|
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||||
|
make check -j"$jobs" TESTS="$tests"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
run: cat tests/test-suite.log 2>/dev/null || true
|
run: cat tests/test-suite.log 2>/dev/null || true
|
||||||
|
|
||||||
|
# libFuzzer smoke: build the fuzz/ harnesses over the pure hostile-input
|
||||||
|
# parsers and replay each seed corpus under ASan+UBSan+LeakSanitizer. Replay
|
||||||
|
# (not open-ended mutation) keeps CI deterministic -- it can't hit strjoker's
|
||||||
|
# catastrophic backtracking -- and pins the regression seeds for the bugs the
|
||||||
|
# fuzzers found. Deep discovery is a maintainer / OSS-Fuzz activity.
|
||||||
|
fuzz:
|
||||||
|
name: fuzz (libFuzzer corpus replay, clang)
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
build-essential clang autoconf automake libtool autoconf-archive \
|
||||||
|
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||||
|
|
||||||
|
- name: Configure (fuzzers, static)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
autoreconf -fi
|
||||||
|
./configure CC=clang \
|
||||||
|
CFLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g -O1 -fno-omit-frame-pointer" \
|
||||||
|
LDFLAGS="-fsanitize=address,undefined" \
|
||||||
|
--enable-fuzzers --disable-shared
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make -j"$(nproc)"
|
||||||
|
|
||||||
|
- name: Replay corpora
|
||||||
|
env:
|
||||||
|
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1:halt_on_error=1
|
||||||
|
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
|
||||||
|
run: bash fuzz/run-fuzzers.sh fuzz check
|
||||||
|
|
||||||
# Optional-dependency build: compile and test with HTTPS/OpenSSL disabled --
|
# Optional-dependency build: compile and test with HTTPS/OpenSSL disabled --
|
||||||
# the configuration users on minimal systems build, and one libssl is not even
|
# 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
|
# installed here so configure cannot silently re-enable it. The matrix above
|
||||||
@@ -308,7 +404,9 @@ jobs:
|
|||||||
run: make -j"$(nproc)"
|
run: make -j"$(nproc)"
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make check
|
run: |
|
||||||
|
jobs=$(( $(nproc) * 2 )); [ "$jobs" -le 16 ] || jobs=16
|
||||||
|
make check -j"$jobs"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
@@ -336,7 +434,7 @@ jobs:
|
|||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
ca-certificates git \
|
ca-certificates git \
|
||||||
build-essential autoconf automake libtool autoconf-archive \
|
build-essential autoconf automake libtool autoconf-archive \
|
||||||
zlib1g-dev libssl-dev \
|
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev \
|
||||||
debhelper devscripts lintian fakeroot
|
debhelper devscripts lintian fakeroot
|
||||||
|
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
@@ -380,7 +478,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends \
|
sudo apt-get install -y --no-install-recommends \
|
||||||
build-essential autoconf automake libtool autoconf-archive \
|
build-essential autoconf automake libtool autoconf-archive \
|
||||||
zlib1g-dev libssl-dev
|
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev
|
||||||
|
|
||||||
- name: distcheck
|
- name: distcheck
|
||||||
run: |
|
run: |
|
||||||
@@ -456,6 +554,16 @@ jobs:
|
|||||||
- name: shfmt
|
- name: shfmt
|
||||||
run: shfmt -d -i 4 $SHELL_SCRIPTS
|
run: shfmt -d -i 4 $SHELL_SCRIPTS
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
for f in src/*.vcxproj; do
|
||||||
|
python3 -c "import sys,xml.dom.minidom; xml.dom.minidom.parse(sys.argv[1])" "$f"
|
||||||
|
echo "ok $f"
|
||||||
|
done
|
||||||
|
|
||||||
# Check clang-format on CHANGED LINES ONLY. The engine predates clang-format
|
# 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,
|
# (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.
|
# so we never reformat the whole tree -- only the lines a PR touches.
|
||||||
|
|||||||
63
.github/workflows/codeql.yml
vendored
Normal file
63
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# CodeQL static analysis (C). The security-extended suite covers the classes
|
||||||
|
# this codebase actually fights: overflows, tainted-size allocs, format bugs.
|
||||||
|
name: CodeQL
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
# Weekly re-scan of master so new/updated queries land without a push.
|
||||||
|
- cron: "17 4 * * 1"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: codeql-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: analyze (c-cpp)
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
# Upload findings to the repo's code-scanning dashboard.
|
||||||
|
security-events: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
build-essential autoconf automake libtool autoconf-archive \
|
||||||
|
zlib1g-dev libssl-dev
|
||||||
|
|
||||||
|
- uses: github/codeql-action/init@v4
|
||||||
|
with:
|
||||||
|
languages: c-cpp
|
||||||
|
build-mode: manual
|
||||||
|
queries: security-extended
|
||||||
|
# fopen's umask-controlled 0666 is intended for mirror/cache/log
|
||||||
|
# output; the one credential file (cookies.txt) is kept 0600 on Unix.
|
||||||
|
config: |
|
||||||
|
query-filters:
|
||||||
|
- exclude:
|
||||||
|
id: cpp/world-writable-file-creation
|
||||||
|
|
||||||
|
# Manual build: CodeQL traces the compiler, so build exactly what ships.
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
autoreconf -fi
|
||||||
|
./configure
|
||||||
|
make -j"$(nproc)"
|
||||||
|
|
||||||
|
- uses: github/codeql-action/analyze@v4
|
||||||
|
with:
|
||||||
|
category: "/language:c-cpp"
|
||||||
145
.github/workflows/windows-build.yml
vendored
Normal file
145
.github/workflows/windows-build.yml
vendored
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Windows build of the engine (VS2022 v143 + vcpkg): libhttrack, the CLI,
|
||||||
|
# webhttrack, proxytrack.
|
||||||
|
#
|
||||||
|
# The autotools CI covers the unix builds; this covers the MSVC one, which had
|
||||||
|
# no coverage at all and had drifted (the old .vcproj pinned OpenSSL 1.0.1j).
|
||||||
|
# libhttrack.dll is what the WinHTTrack GUI links against.
|
||||||
|
name: windows-build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
libhttrack:
|
||||||
|
runs-on: windows-2022
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
platform: [x64, Win32]
|
||||||
|
configuration: [Release]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive # coucal lives in src/coucal
|
||||||
|
|
||||||
|
# Located through vswhere rather than microsoft/setup-msbuild: the repo
|
||||||
|
# only allows GitHub-owned actions.
|
||||||
|
- name: Find MSBuild
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||||
|
$msbuild = & $vswhere -latest -products * -requires Microsoft.Component.MSBuild `
|
||||||
|
-find MSBuild\**\Bin\MSBuild.exe | Select-Object -First 1
|
||||||
|
if (-not $msbuild) { throw "MSBuild not found" }
|
||||||
|
Write-Host "MSBuild: $msbuild"
|
||||||
|
"MSBUILD=$msbuild" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
|
||||||
|
- name: Enable vcpkg MSBuild integration
|
||||||
|
shell: pwsh
|
||||||
|
run: vcpkg integrate install
|
||||||
|
|
||||||
|
# httrack and webhttrack carry a ProjectReference to libhttrack, so building
|
||||||
|
# them builds it first; proxytrack is standalone.
|
||||||
|
- name: Build
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
foreach ($proj in @("libhttrack", "httrack", "webhttrack", "proxytrack")) {
|
||||||
|
& $env:MSBUILD "src\$proj.vcxproj" `
|
||||||
|
/m `
|
||||||
|
/p:Configuration=${{ matrix.configuration }} `
|
||||||
|
/p:Platform=${{ matrix.platform }} `
|
||||||
|
/p:VcpkgEnableManifest=true `
|
||||||
|
/flp:LogFile=msbuild-$proj.log`;Verbosity=normal
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "$proj failed" }
|
||||||
|
}
|
||||||
|
|
||||||
|
# WinHTTrack links src\$(Platform)\$(Configuration)\libhttrack.lib, so the
|
||||||
|
# import lib and the DLL both have to land there under that exact name.
|
||||||
|
- name: Check the binaries landed where they are expected
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$dir = "src\${{ matrix.platform }}\${{ matrix.configuration }}"
|
||||||
|
$want = @("libhttrack.dll", "libhttrack.lib", "httrack.exe",
|
||||||
|
"webhttrack.exe", "proxytrack.exe")
|
||||||
|
foreach ($f in $want) {
|
||||||
|
if (-not (Test-Path "$dir\$f")) { throw "missing $dir\$f" }
|
||||||
|
Write-Host "found $dir\$f"
|
||||||
|
}
|
||||||
|
|
||||||
|
# A CRT split across the exe/DLL boundary links fine and crashes on the
|
||||||
|
# first cross-heap free, so assert both sides import the *same* vcruntime.
|
||||||
|
# Also assert the machine type: Test-Path alone would accept an x64 binary
|
||||||
|
# sitting in the Win32 output dir.
|
||||||
|
- name: Check the CRT is shared across the boundary
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$dir = "src\${{ matrix.platform }}\${{ matrix.configuration }}"
|
||||||
|
$dumpbin = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" `
|
||||||
|
-latest -find VC\Tools\MSVC\**\bin\Host*\*\dumpbin.exe | Select-Object -First 1
|
||||||
|
if (-not $dumpbin) { throw "dumpbin not found" }
|
||||||
|
$wantMachine = if ("${{ matrix.platform }}" -eq "x64") { "x64" } else { "x86" }
|
||||||
|
|
||||||
|
function Get-Crt($path) {
|
||||||
|
$out = & $dumpbin /dependents /headers $path
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "dumpbin failed on $path" }
|
||||||
|
,@($out | Select-String -Pattern '^\s*(vcruntime\d+d?\.dll)$' |
|
||||||
|
ForEach-Object { $_.Matches[0].Groups[1].Value.ToLower() })
|
||||||
|
}
|
||||||
|
|
||||||
|
# Negative control: cmd.exe links the old msvcrt, not vcruntime140. If
|
||||||
|
# this came back non-empty the detector would match anything, and the
|
||||||
|
# assertion below would pass on a mismatched CRT too.
|
||||||
|
if ((Get-Crt "$env:SystemRoot\System32\cmd.exe").Count -ne 0) {
|
||||||
|
throw "negative control failed: the vcruntime detector matches anything"
|
||||||
|
}
|
||||||
|
|
||||||
|
$crts = @{}
|
||||||
|
foreach ($f in @("libhttrack.dll", "httrack.exe")) {
|
||||||
|
$crt = Get-Crt "$dir\$f"
|
||||||
|
if ($crt.Count -eq 0) { throw "$f imports no vcruntime: static or mismatched CRT" }
|
||||||
|
$crts[$f] = $crt
|
||||||
|
|
||||||
|
$hdr = & $dumpbin /headers "$dir\$f"
|
||||||
|
if (-not ($hdr | Select-String -SimpleMatch "machine ($wantMachine)")) {
|
||||||
|
throw "$f is not $wantMachine"
|
||||||
|
}
|
||||||
|
Write-Host "$f -> $($crt -join ',') ($wantMachine)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$a = $crts["libhttrack.dll"] | Sort-Object
|
||||||
|
$b = $crts["httrack.exe"] | Sort-Object
|
||||||
|
if (Compare-Object $a $b) {
|
||||||
|
throw "CRT mismatch across the boundary: libhttrack.dll=$a httrack.exe=$b"
|
||||||
|
}
|
||||||
|
|
||||||
|
# The engine self-tests exercise the codecs the DLL was linked with: a
|
||||||
|
# missing brotli/zstd decoder shows up here, not just at link time.
|
||||||
|
- name: Run the content-coding self-tests
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$exe = "src\${{ matrix.platform }}\${{ matrix.configuration }}\httrack.exe"
|
||||||
|
$tmp = New-Item -ItemType Directory -Path (Join-Path $env:RUNNER_TEMP "st")
|
||||||
|
foreach ($t in @("acceptencoding", "contentcodings")) {
|
||||||
|
$out = & $exe -O NUL "-#test=$t" $tmp.FullName run
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "$t failed" }
|
||||||
|
if (-not ($out | Select-String -SimpleMatch "$t self-test OK")) {
|
||||||
|
throw "$t did not report OK: $out"
|
||||||
|
}
|
||||||
|
Write-Host ($out -join "`n")
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Upload MSBuild logs
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: msbuild-${{ matrix.platform }}-${{ matrix.configuration }}
|
||||||
|
path: msbuild-*.log
|
||||||
|
if-no-files-found: ignore
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -34,8 +34,12 @@ Makefile
|
|||||||
*.so.*
|
*.so.*
|
||||||
*.a
|
*.a
|
||||||
|
|
||||||
# make dist output.
|
# make dist output; dist/ holds httrack-gh-release staging artifacts.
|
||||||
/httrack-*.tar.gz
|
/httrack-*.tar.gz
|
||||||
|
/dist/
|
||||||
|
|
||||||
# Editor / autotools backup files.
|
# Editor / autotools backup files.
|
||||||
*~
|
*~
|
||||||
|
|
||||||
|
# Python bytecode (tests/local-server.py).
|
||||||
|
__pycache__/
|
||||||
|
|||||||
15
AGENTS.md
15
AGENTS.md
@@ -6,8 +6,19 @@ the operational checklist: toolchain, invariants, and how to ship a change.
|
|||||||
## Build & test
|
## Build & test
|
||||||
- Fresh clone first: `git submodule update --init src/coucal`
|
- Fresh clone first: `git submodule update --init src/coucal`
|
||||||
- `./bootstrap` (regenerates `configure` via `autoreconf`; needs autoconf,
|
- `./bootstrap` (regenerates `configure` via `autoreconf`; needs autoconf,
|
||||||
automake, libtool), then `bash configure && make && make check`. Or run
|
automake, libtool), then `bash configure && make -j"$(nproc)" && make check
|
||||||
`sh build.sh` to do bootstrap + configure + make in one shot.
|
-j"$(nproc)"`. Always pass `-j` to `make check`: the suite runs under
|
||||||
|
automake's parallel harness and each crawl test binds its own ephemeral-port
|
||||||
|
server, so `-j` never contends and a multi-minute serial run drops to
|
||||||
|
seconds. A new `.test` added to `$(TESTS)` is scheduled onto a free worker
|
||||||
|
automatically; only a test slower than the current longest raises the floor.
|
||||||
|
On a few-core Linux box, `-j` at 2x the core count is faster still: the tests
|
||||||
|
spend much of their wall time asleep (server trickles, httrack self-pacing),
|
||||||
|
so an idle core covers a sleeping one. CI uses `min(2*cores, 16)` on every
|
||||||
|
platform, macOS included: the test server raises its listen backlog
|
||||||
|
(`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.
|
||||||
|
|
||||||
## Hard invariants
|
## Hard invariants
|
||||||
- **Generated autotools files are NOT in git.** `configure`, every
|
- **Generated autotools files are NOT in git.** `configure`, every
|
||||||
|
|||||||
1
CLAUDE.local.md
Symbolic link
1
CLAUDE.local.md
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/home/roche/git/httrack-works/CLAUDE.httrack.local.md
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
SUBDIRS = src man m4 libtest templates lang html tests
|
SUBDIRS = src man m4 libtest templates lang html tests fuzz
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
|||||||
1
README
1
README
@@ -40,7 +40,6 @@ These are the principals limits of HTTrack for that moment. Note that we did not
|
|||||||
that would have solved them.
|
that would have solved them.
|
||||||
|
|
||||||
- Several scripts generating complex filenames may not find them (ex: img.src='image'+a+Mobj.dst+'.gif')
|
- Several scripts generating complex filenames may not find them (ex: img.src='image'+a+Mobj.dst+'.gif')
|
||||||
- Some java classes may not find some files on them (class included)
|
|
||||||
- Cgi-bin links may not work properly in some cases (parameters needed). To avoid them: use filters like -*cgi-bin*
|
- Cgi-bin links may not work properly in some cases (parameters needed). To avoid them: use filters like -*cgi-bin*
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
69
configure.ac
69
configure.ac
@@ -1,6 +1,6 @@
|
|||||||
AC_PREREQ([2.71])
|
AC_PREREQ([2.71])
|
||||||
|
|
||||||
AC_INIT([httrack], [3.49.10], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
|
AC_INIT([httrack], [3.49.12], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
|
||||||
AC_COPYRIGHT([
|
AC_COPYRIGHT([
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
Copyright (C) 1998-2015 Xavier Roche and other contributors
|
Copyright (C) 1998-2015 Xavier Roche and other contributors
|
||||||
@@ -29,10 +29,11 @@ AC_CONFIG_SRCDIR(src/httrack.c)
|
|||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
AM_INIT_AUTOMAKE([subdir-objects])
|
AM_INIT_AUTOMAKE([subdir-objects])
|
||||||
# 3:2:0: 3.49.10 only appends tail fields to the options struct (no existing
|
# 3:4:0: 3.49.12 tail-appends one field (why_url) to httrackp and otherwise only
|
||||||
# symbol or offset changed vs 3.49.9), so it stays soname .so.3; bump revision.
|
# deletes dead comments; no struct layout or exported signature broke vs 3.49.11,
|
||||||
|
# so it stays soname .so.3; bump revision.
|
||||||
# (3:0:0 was the htsblk mime-buffer widening, the ABI break that moved .so.2 -> .so.3.)
|
# (3:0:0 was the htsblk mime-buffer widening, the ABI break that moved .so.2 -> .so.3.)
|
||||||
VERSION_INFO="3:2:0"
|
VERSION_INFO="3:4:0"
|
||||||
AM_MAINTAINER_MODE
|
AM_MAINTAINER_MODE
|
||||||
AC_USE_SYSTEM_EXTENSIONS
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
|
|
||||||
@@ -63,16 +64,6 @@ AC_SUBST(LT_CV_OBJDIR,$lt_cv_objdir)
|
|||||||
# Export version info
|
# Export version info
|
||||||
AC_SUBST(VERSION_INFO)
|
AC_SUBST(VERSION_INFO)
|
||||||
|
|
||||||
# Versioned plugin name for dlopen() in hts_create_opt(); soname major is
|
|
||||||
# libtool's current - age, so this tracks VERSION_INFO bumps automatically.
|
|
||||||
HTS_SONAME_MAJOR=$((${VERSION_INFO%%:*} - ${VERSION_INFO##*:}))
|
|
||||||
case "$host_os" in
|
|
||||||
darwin*) HTS_LIBHTSJAVA_NAME="libhtsjava.$HTS_SONAME_MAJOR.dylib" ;;
|
|
||||||
*) HTS_LIBHTSJAVA_NAME="libhtsjava.so.$HTS_SONAME_MAJOR" ;;
|
|
||||||
esac
|
|
||||||
AC_DEFINE_UNQUOTED([HTS_LIBHTSJAVA_NAME], ["$HTS_LIBHTSJAVA_NAME"],
|
|
||||||
[Versioned libhtsjava runtime name, derived from VERSION_INFO])
|
|
||||||
|
|
||||||
### Default CFLAGS
|
### Default CFLAGS
|
||||||
DEFAULT_CFLAGS="-Wall -Wformat -Wformat-security \
|
DEFAULT_CFLAGS="-Wall -Wformat -Wformat-security \
|
||||||
-Wmultichar -Wwrite-strings -Wcast-qual -Wcast-align \
|
-Wmultichar -Wwrite-strings -Wcast-qual -Wcast-align \
|
||||||
@@ -101,7 +92,8 @@ AX_CHECK_COMPILE_FLAG([-Wignored-qualifiers], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -
|
|||||||
AX_CHECK_COMPILE_FLAG([-Werror=attribute-warning], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=attribute-warning"])
|
AX_CHECK_COMPILE_FLAG([-Werror=attribute-warning], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=attribute-warning"])
|
||||||
AX_CHECK_COMPILE_FLAG([-Werror=user-defined-warnings], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=user-defined-warnings"])
|
AX_CHECK_COMPILE_FLAG([-Werror=user-defined-warnings], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=user-defined-warnings"])
|
||||||
AX_CHECK_COMPILE_FLAG([-fstrict-aliasing -Wstrict-aliasing], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstrict-aliasing -Wstrict-aliasing"])
|
AX_CHECK_COMPILE_FLAG([-fstrict-aliasing -Wstrict-aliasing], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstrict-aliasing -Wstrict-aliasing"])
|
||||||
AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"])
|
AX_CHECK_COMPILE_FLAG([-fstack-protector-strong], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector-strong"],
|
||||||
|
[AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"])])
|
||||||
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"])
|
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"])
|
||||||
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"])
|
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"])
|
||||||
AX_CHECK_LINK_FLAG([-Wl,--discard-all], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--discard-all"])
|
AX_CHECK_LINK_FLAG([-Wl,--discard-all], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--discard-all"])
|
||||||
@@ -109,9 +101,16 @@ AX_CHECK_LINK_FLAG([-Wl,--no-undefined], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,
|
|||||||
AX_CHECK_LINK_FLAG([-Wl,-z,relro,-z,now], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,relro,-z,now"])
|
AX_CHECK_LINK_FLAG([-Wl,-z,relro,-z,now], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,relro,-z,now"])
|
||||||
AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,noexecstack"])
|
AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,noexecstack"])
|
||||||
|
|
||||||
|
# Fortify libc calls (=3, else =2) unless the toolchain predefines it; skip
|
||||||
|
# sanitizer builds, whose interceptors want the unfortified calls.
|
||||||
|
case "$CFLAGS" in
|
||||||
|
*-fsanitize=*) ;;
|
||||||
|
*) AX_ADD_FORTIFY_SOURCE ;;
|
||||||
|
esac
|
||||||
|
|
||||||
# Force libc back into DT_NEEDED for libraries that reach it only through
|
# Force libc back into DT_NEEDED for libraries that reach it only through
|
||||||
# libhttrack (libhtsjava, the libtest callbacks), but only with a GNU-style
|
# libhttrack (the libtest callbacks), but only with a GNU-style linker; Apple
|
||||||
# linker; Apple ld rejects these flags and links libSystem unconditionally.
|
# ld rejects these flags and links libSystem unconditionally.
|
||||||
AX_CHECK_LINK_FLAG([-Wl,--push-state,--no-as-needed,-lc,--pop-state],
|
AX_CHECK_LINK_FLAG([-Wl,--push-state,--no-as-needed,-lc,--pop-state],
|
||||||
[LIBC_FORCE_LINK="-Wl,--push-state,--no-as-needed,-lc,--pop-state"])
|
[LIBC_FORCE_LINK="-Wl,--push-state,--no-as-needed,-lc,--pop-state"])
|
||||||
AC_SUBST([LIBC_FORCE_LINK])
|
AC_SUBST([LIBC_FORCE_LINK])
|
||||||
@@ -174,6 +173,10 @@ AC_CHECK_HEADERS([execinfo.h])
|
|||||||
### zlib
|
### zlib
|
||||||
CHECK_ZLIB()
|
CHECK_ZLIB()
|
||||||
|
|
||||||
|
### brotli and zstd content codings (optional)
|
||||||
|
CHECK_BROTLI()
|
||||||
|
CHECK_ZSTD()
|
||||||
|
|
||||||
### OpenSSL is explicitly enabled/disabled ?
|
### OpenSSL is explicitly enabled/disabled ?
|
||||||
AC_MSG_CHECKING(whether to enable https support)
|
AC_MSG_CHECKING(whether to enable https support)
|
||||||
AC_ARG_ENABLE([https],
|
AC_ARG_ENABLE([https],
|
||||||
@@ -309,6 +312,37 @@ AC_ARG_ENABLE([online-unit-tests],
|
|||||||
])
|
])
|
||||||
AC_SUBST(ONLINE_UNIT_TESTS,$online_unit_tests)
|
AC_SUBST(ONLINE_UNIT_TESTS,$online_unit_tests)
|
||||||
|
|
||||||
|
## libFuzzer harnesses (fuzz/); requires clang
|
||||||
|
AC_MSG_CHECKING(whether to build fuzzers)
|
||||||
|
AC_ARG_ENABLE([fuzzers],
|
||||||
|
[AS_HELP_STRING([--enable-fuzzers],[Build libFuzzer harnesses in fuzz/ (requires clang) @<:@default=no@:>@])],
|
||||||
|
[
|
||||||
|
case "${enableval}" in
|
||||||
|
no|yes)
|
||||||
|
fuzzers=$enableval
|
||||||
|
AC_MSG_RESULT($enableval)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(bad value for fuzzers, expected yes/no)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
],
|
||||||
|
[
|
||||||
|
fuzzers=no
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
if test x"$fuzzers" = x"yes"; then
|
||||||
|
# Instrument the whole build for coverage; harnesses link -fsanitize=fuzzer.
|
||||||
|
AX_CHECK_COMPILE_FLAG([-fsanitize=fuzzer-no-link],
|
||||||
|
[DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fsanitize=fuzzer-no-link"],
|
||||||
|
[AC_MSG_ERROR([--enable-fuzzers requires libFuzzer support (clang)])])
|
||||||
|
# clang's static sanitizer runtimes clash with -Wl,--no-undefined on the .so.
|
||||||
|
if test x"$enable_shared" != x"no"; then
|
||||||
|
AC_MSG_ERROR([--enable-fuzzers requires --disable-shared])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL([FUZZERS], [test x"$fuzzers" = x"yes"])
|
||||||
|
|
||||||
# Final output
|
# Final output
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
Makefile
|
Makefile
|
||||||
@@ -320,5 +354,6 @@ lang/Makefile
|
|||||||
html/Makefile
|
html/Makefile
|
||||||
libtest/Makefile
|
libtest/Makefile
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
|
fuzz/Makefile
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
31
debian/changelog
vendored
31
debian/changelog
vendored
@@ -1,3 +1,34 @@
|
|||||||
|
httrack (3.49.12-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* New upstream release: security and crawl-correctness fixes (remote stack
|
||||||
|
overflow in Content-Type/-Encoding parsing, fuzzer-found parser over-reads,
|
||||||
|
world-readable cookies.txt, filter-pattern denial of service) plus a new
|
||||||
|
--why filter diagnostic; full list in history.txt.
|
||||||
|
* Build with _FORTIFY_SOURCE and -fstack-protector-strong.
|
||||||
|
|
||||||
|
-- Xavier Roche <xavier@debian.org> Fri, 10 Jul 2026 21:11:09 +0200
|
||||||
|
|
||||||
|
httrack (3.49.11-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* New upstream release: crawl correctness and security fixes (network-facing
|
||||||
|
buffer overflows, file-type detection, redirect handling) and modernized
|
||||||
|
web defaults; full list in history.txt.
|
||||||
|
* Add DEP-12 upstream metadata (#466).
|
||||||
|
* Bump debhelper compat to 14 (#466).
|
||||||
|
* Drop the redundant Priority field and update the NMU lintian override to
|
||||||
|
the current tag names (#466).
|
||||||
|
|
||||||
|
-- Xavier Roche <xavier@debian.org> Sun, 05 Jul 2026 00:03:18 +0200
|
||||||
|
|
||||||
|
httrack (3.49.10-2) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Fix FTBFS: tests/28_local-pause failed instead of skipping when python3 is
|
||||||
|
absent (the local-server tests need python3, which the buildds lack). Add
|
||||||
|
patches/skip-local-pause-test-without-python3.patch to guard the test on
|
||||||
|
python3 up front, like its siblings, so it skips cleanly.
|
||||||
|
|
||||||
|
-- Xavier Roche <xavier@debian.org> Sun, 28 Jun 2026 20:18:46 +0200
|
||||||
|
|
||||||
httrack (3.49.10-1) unstable; urgency=medium
|
httrack (3.49.10-1) unstable; urgency=medium
|
||||||
|
|
||||||
* New upstream release: new download-pacing and URL-handling options plus a
|
* New upstream release: new download-pacing and URL-handling options plus a
|
||||||
|
|||||||
2
debian/control
vendored
2
debian/control
vendored
@@ -2,7 +2,7 @@ Source: httrack
|
|||||||
Section: web
|
Section: web
|
||||||
Maintainer: Xavier Roche <roche@httrack.com>
|
Maintainer: Xavier Roche <roche@httrack.com>
|
||||||
Standards-Version: 4.7.4
|
Standards-Version: 4.7.4
|
||||||
Build-Depends: debhelper-compat (= 14), autoconf, autoconf-archive, automake, libtool, zlib1g-dev, libssl-dev
|
Build-Depends: debhelper-compat (= 14), autoconf, autoconf-archive, automake, libtool, zlib1g-dev, libssl-dev, libbrotli-dev, libzstd-dev
|
||||||
Rules-Requires-Root: no
|
Rules-Requires-Root: no
|
||||||
Homepage: http://www.httrack.com
|
Homepage: http://www.httrack.com
|
||||||
Vcs-Git: https://github.com/xroche/httrack.git
|
Vcs-Git: https://github.com/xroche/httrack.git
|
||||||
|
|||||||
5
debian/copyright
vendored
5
debian/copyright
vendored
@@ -7,9 +7,8 @@ Files: *
|
|||||||
Copyright: 1998-2026 Xavier Roche and other contributors
|
Copyright: 1998-2026 Xavier Roche and other contributors
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
Comment:
|
Comment:
|
||||||
The engine includes contributions from Yann Philippot (src/htsjava.c,
|
htsbasenet.h links against the system OpenSSL library (originally by Eric
|
||||||
src/htsjava.h). htsbasenet.h links against the system OpenSSL library
|
Young); no OpenSSL/SSLeay code is bundled here.
|
||||||
(originally by Eric Young); no OpenSSL/SSLeay code is bundled here.
|
|
||||||
|
|
||||||
Files: src/minizip/*
|
Files: src/minizip/*
|
||||||
Copyright: 1998-2010 Gilles Vollant
|
Copyright: 1998-2010 Gilles Vollant
|
||||||
|
|||||||
1
debian/libhttrack-dev.files
vendored
1
debian/libhttrack-dev.files
vendored
@@ -1,5 +1,4 @@
|
|||||||
usr/include/httrack
|
usr/include/httrack
|
||||||
usr/lib/*/libhttrack.{so}
|
usr/lib/*/libhttrack.{so}
|
||||||
usr/lib/*/libhtsjava.{so}
|
|
||||||
usr/share/httrack/libtest
|
usr/share/httrack/libtest
|
||||||
usr/lib/*/httrack/libtest
|
usr/lib/*/httrack/libtest
|
||||||
|
|||||||
1
debian/libhttrack3.files
vendored
1
debian/libhttrack3.files
vendored
@@ -1,3 +1,2 @@
|
|||||||
usr/lib/*/libhttrack.so.3*
|
usr/lib/*/libhttrack.so.3*
|
||||||
usr/lib/*/libhtsjava.so.3*
|
|
||||||
usr/share/httrack/templates
|
usr/share/httrack/templates
|
||||||
|
|||||||
45
fuzz/Makefile.am
Normal file
45
fuzz/Makefile.am
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# libFuzzer harnesses; built only with --enable-fuzzers (requires clang).
|
||||||
|
if FUZZERS
|
||||||
|
noinst_PROGRAMS = fuzz-charset fuzz-meta fuzz-idna fuzz-entities \
|
||||||
|
fuzz-unescape fuzz-filters fuzz-url fuzz-header fuzz-cachendx
|
||||||
|
endif
|
||||||
|
|
||||||
|
AM_CPPFLAGS = \
|
||||||
|
@DEFAULT_CFLAGS@ \
|
||||||
|
@THREADS_CFLAGS@ \
|
||||||
|
@V6_FLAG@ \
|
||||||
|
@LFS_FLAG@ \
|
||||||
|
-I$(top_srcdir)/src \
|
||||||
|
-I$(top_srcdir)/src/coucal
|
||||||
|
|
||||||
|
# Static-link libhttrack.la: the internal symbols are hidden in the .so.
|
||||||
|
AM_LDFLAGS = @DEFAULT_LDFLAGS@ -fsanitize=fuzzer -static-libtool-libs
|
||||||
|
LDADD = $(top_builddir)/src/libhttrack.la $(THREADS_LIBS)
|
||||||
|
|
||||||
|
fuzz_charset_SOURCES = fuzz-charset.c fuzz.h
|
||||||
|
fuzz_meta_SOURCES = fuzz-meta.c fuzz.h
|
||||||
|
fuzz_idna_SOURCES = fuzz-idna.c fuzz.h
|
||||||
|
fuzz_entities_SOURCES = fuzz-entities.c fuzz.h
|
||||||
|
fuzz_unescape_SOURCES = fuzz-unescape.c fuzz.h
|
||||||
|
fuzz_filters_SOURCES = fuzz-filters.c fuzz.h
|
||||||
|
fuzz_url_SOURCES = fuzz-url.c fuzz.h
|
||||||
|
fuzz_header_SOURCES = fuzz-header.c fuzz.h
|
||||||
|
fuzz_cachendx_SOURCES = fuzz-cachendx.c fuzz.h
|
||||||
|
|
||||||
|
# List corpus files explicitly: automake does not expand EXTRA_DIST globs.
|
||||||
|
EXTRA_DIST = README.md run-fuzzers.sh \
|
||||||
|
corpus/charset/utf8.txt corpus/charset/latin1.txt corpus/charset/sjis.txt \
|
||||||
|
corpus/meta/meta-charset.html corpus/meta/meta-http-equiv.html \
|
||||||
|
corpus/idna/idna.txt corpus/idna/unicode.txt \
|
||||||
|
corpus/idna/regress-multilabel-leak.txt \
|
||||||
|
corpus/entities/entities.txt \
|
||||||
|
corpus/unescape/percent.txt \
|
||||||
|
corpus/filters/filter.bin corpus/filters/filter-size.bin \
|
||||||
|
corpus/filters/regress-empty-subject-unique.bin \
|
||||||
|
corpus/filters/redos-star-classes.bin \
|
||||||
|
corpus/url/http-url.txt corpus/url/relative-path.txt \
|
||||||
|
corpus/url/regress-file-empty-path.txt corpus/url/regress-long-path-abort.txt \
|
||||||
|
corpus/header/full-response.txt corpus/header/redirect.txt \
|
||||||
|
corpus/cachendx/new-format.txt corpus/cachendx/old-format.txt \
|
||||||
|
corpus/cachendx/regress-overadvance.bin \
|
||||||
|
corpus/cachendx/regress-truncated-entry.bin
|
||||||
15
fuzz/README.md
Normal file
15
fuzz/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Fuzzing httrack
|
||||||
|
|
||||||
|
libFuzzer harnesses for the pure hostile-input parsers (charset/UTF-8/IDNA codecs, entity and percent decoders, wildcard filters, URL splitter). Off by default; needs clang.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./bootstrap
|
||||||
|
mkdir /var/tmp/bld-fuzz && cd /var/tmp/bld-fuzz
|
||||||
|
CC=clang CFLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g -O1" \
|
||||||
|
LDFLAGS="-fsanitize=address,undefined" \
|
||||||
|
bash /path/to/httrack/configure --enable-fuzzers --disable-shared
|
||||||
|
make
|
||||||
|
bash /path/to/httrack/fuzz/run-fuzzers.sh fuzz 60 # 60s per target
|
||||||
|
```
|
||||||
|
|
||||||
|
Run one target by hand: `fuzz/fuzz-url -max_total_time=300 corpusdir fuzz/corpus/url`. Seed corpora live in `corpus/<target>/`; a crash reproducer is replayed with `fuzz/fuzz-url crash-file`.
|
||||||
7
fuzz/corpus/cachendx/new-format.txt
Normal file
7
fuzz/corpus/cachendx/new-format.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
8
|
||||||
|
CACHE-1.1
|
||||||
|
28
|
||||||
|
Mon, 01 Jan 2024 00:00:00 GMT
|
||||||
|
www.example.com
|
||||||
|
/index.html
|
||||||
|
123
|
||||||
5
fuzz/corpus/cachendx/old-format.txt
Normal file
5
fuzz/corpus/cachendx/old-format.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
3
|
||||||
|
1.0
|
||||||
|
www.example.com
|
||||||
|
/page
|
||||||
|
5
|
||||||
2
fuzz/corpus/cachendx/regress-overadvance.bin
Normal file
2
fuzz/corpus/cachendx/regress-overadvance.bin
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
32768
|
||||||
|
CACHE-1.1
|
||||||
5
fuzz/corpus/cachendx/regress-truncated-entry.bin
Normal file
5
fuzz/corpus/cachendx/regress-truncated-entry.bin
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
8
|
||||||
|
CACHE-1.1
|
||||||
|
1
|
||||||
|
x
|
||||||
|
www.example.com
|
||||||
1
fuzz/corpus/charset/latin1.txt
Normal file
1
fuzz/corpus/charset/latin1.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
café naďve ¤
|
||||||
1
fuzz/corpus/charset/sjis.txt
Normal file
1
fuzz/corpus/charset/sjis.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
コンピュータ
|
||||||
BIN
fuzz/corpus/charset/utf8.txt
Normal file
BIN
fuzz/corpus/charset/utf8.txt
Normal file
Binary file not shown.
1
fuzz/corpus/entities/entities.txt
Normal file
1
fuzz/corpus/entities/entities.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
&<>A☃é¬arealentity;�
|
||||||
BIN
fuzz/corpus/filters/filter-size.bin
Normal file
BIN
fuzz/corpus/filters/filter-size.bin
Normal file
Binary file not shown.
BIN
fuzz/corpus/filters/filter.bin
Normal file
BIN
fuzz/corpus/filters/filter.bin
Normal file
Binary file not shown.
BIN
fuzz/corpus/filters/redos-star-classes.bin
Normal file
BIN
fuzz/corpus/filters/redos-star-classes.bin
Normal file
Binary file not shown.
1
fuzz/corpus/filters/regress-empty-subject-unique.bin
Normal file
1
fuzz/corpus/filters/regress-empty-subject-unique.bin
Normal file
@@ -0,0 +1 @@
|
|||||||
|
**((
|
||||||
10
fuzz/corpus/header/full-response.txt
Normal file
10
fuzz/corpus/header/full-response.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Content-Length: 1234
|
||||||
|
Content-Encoding: gzip
|
||||||
|
Last-Modified: Mon, 01 Jan 2024 00:00:00 GMT
|
||||||
|
Etag: "abc"
|
||||||
|
Location: http://example.com/x
|
||||||
|
Set-Cookie: ID=42; path=/; domain=.example.com
|
||||||
|
Content-Range: bytes 0-99/100
|
||||||
|
Transfer-Encoding: chunked
|
||||||
3
fuzz/corpus/header/redirect.txt
Normal file
3
fuzz/corpus/header/redirect.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
HTTP/1.0 301 Moved
|
||||||
|
Location: /elsewhere
|
||||||
|
Content-Disposition: attachment; filename="a.pdf"
|
||||||
1
fuzz/corpus/idna/idna.txt
Normal file
1
fuzz/corpus/idna/idna.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
xn--bcher-kva.example.com
|
||||||
1
fuzz/corpus/idna/regress-multilabel-leak.txt
Normal file
1
fuzz/corpus/idna/regress-multilabel-leak.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
büchev.例åbücheple
|
||||||
1
fuzz/corpus/idna/unicode.txt
Normal file
1
fuzz/corpus/idna/unicode.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
bücher.例子.example
|
||||||
1
fuzz/corpus/meta/meta-charset.html
Normal file
1
fuzz/corpus/meta/meta-charset.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<html><head><meta charset="utf-8"></head><body>x</body></html>
|
||||||
1
fuzz/corpus/meta/meta-content-first.html
Normal file
1
fuzz/corpus/meta/meta-content-first.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<meta content="text/html; charset=gb2312" http-equiv="content-type">
|
||||||
1
fuzz/corpus/meta/meta-http-equiv.html
Normal file
1
fuzz/corpus/meta/meta-http-equiv.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
1
fuzz/corpus/meta/meta-truncated.html
Normal file
1
fuzz/corpus/meta/meta-truncated.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<meta charset='utf-8
|
||||||
1
fuzz/corpus/meta/meta-unquoted.html
Normal file
1
fuzz/corpus/meta/meta-unquoted.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<meta charset = utf-8 />
|
||||||
1
fuzz/corpus/unescape/percent.txt
Normal file
1
fuzz/corpus/unescape/percent.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
%41%zz%%20%c3%a9+%2e%2e%2f
|
||||||
1
fuzz/corpus/url/http-url.txt
Normal file
1
fuzz/corpus/url/http-url.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
http://user:pass@www.example.com:8080/a/b/../c/./d.html?q=1#frag
|
||||||
1
fuzz/corpus/url/regress-file-empty-path.txt
Normal file
1
fuzz/corpus/url/regress-file-empty-path.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
file://
|
||||||
1
fuzz/corpus/url/regress-long-path-abort.txt
Normal file
1
fuzz/corpus/url/regress-long-path-abort.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ftpumŠ[/../e0O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._f9O_i../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/i<>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_im<69>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/9O_imÙ<6D>Š<EFBFBD>W/../O/../
|
||||||
1
fuzz/corpus/url/relative-path.txt
Normal file
1
fuzz/corpus/url/relative-path.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ftp://ftp.example.com/pub/../file.txt
|
||||||
65
fuzz/fuzz-cachendx.c
Normal file
65
fuzz/fuzz-cachendx.c
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
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 the cache-index (.ndx) parser: a corrupt or truncated index must not
|
||||||
|
walk the length-prefixed cache_brstr/cache_binput scan past the buffer.
|
||||||
|
Mirrors the -#C cache-listing scan (htscoremain.c). */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htscache.h"
|
||||||
|
#include "htslib.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
char *buf = fuzz_strdup(data, size);
|
||||||
|
const char *const end = buf + size;
|
||||||
|
char firstline[256];
|
||||||
|
char *a = buf;
|
||||||
|
|
||||||
|
/* header: two length-prefixed fields (version, last-modified) */
|
||||||
|
a += cache_brstr(a, firstline, sizeof(firstline));
|
||||||
|
a += cache_brstr(a, firstline, sizeof(firstline));
|
||||||
|
|
||||||
|
/* body: newline-delimited host/file/position triples; the length-prefixed
|
||||||
|
scan must stay inside the buffer */
|
||||||
|
while (a != NULL && a < end) {
|
||||||
|
char BIGSTK line[HTS_URLMAXSIZE * 2];
|
||||||
|
char linepos[256];
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
a = strchr(a + 1, '\n');
|
||||||
|
if (a == NULL)
|
||||||
|
break;
|
||||||
|
a++;
|
||||||
|
a += cache_binput(a, end, line, HTS_URLMAXSIZE);
|
||||||
|
a += cache_binput(a, end, line + strlen(line), HTS_URLMAXSIZE);
|
||||||
|
a += cache_binput(a, end, linepos, 200);
|
||||||
|
sscanf(linepos, "%d", &pos);
|
||||||
|
(void) pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
freet(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
84
fuzz/fuzz-charset.c
Normal file
84
fuzz/fuzz-charset.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
|
Copyright (C) 1998 Xavier Roche and other contributors
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||||
|
addresses or to collect any other private information about people. Doing so
|
||||||
|
would dishonor our work and waste the many hours we have spent on it.
|
||||||
|
|
||||||
|
Please visit our Website: http://www.httrack.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fuzz the charset codecs: hts_convertStringToUTF8/FromUTF8 and the
|
||||||
|
UTF-8/UCS4 primitives (htscharset.c). First input byte picks the charset. */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htscharset.h"
|
||||||
|
|
||||||
|
static const char *const charsets[] = {
|
||||||
|
"utf-8", "iso-8859-1", "iso-8859-2", "iso-8859-15", "windows-1252",
|
||||||
|
"us-ascii", "shift_jis", "euc-jp", "iso-2022-jp", "gb2312",
|
||||||
|
"big5", "euc-kr", "koi8-r", "utf-16", "unknown-charset",
|
||||||
|
};
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
const char *charset;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
charset = charsets[data[0] % (sizeof(charsets) / sizeof(charsets[0]))];
|
||||||
|
data++, size--;
|
||||||
|
s = fuzz_strdup(data, size);
|
||||||
|
|
||||||
|
{
|
||||||
|
char *utf8 = hts_convertStringToUTF8(s, size, charset);
|
||||||
|
freet(utf8);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char *enc = hts_convertStringFromUTF8(s, size, charset);
|
||||||
|
freet(enc);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
size_t nChars = 0;
|
||||||
|
hts_UCS4 *ucs = hts_convertUTF8StringToUCS4(s, size, &nChars);
|
||||||
|
|
||||||
|
if (ucs != NULL) {
|
||||||
|
char *back = hts_convertUCS4StringToUTF8(ucs, nChars);
|
||||||
|
freet(back);
|
||||||
|
freet(ucs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (i < size) {
|
||||||
|
hts_UCS4 uc = 0;
|
||||||
|
const size_t nr = hts_readUTF8(s + i, size - i, &uc);
|
||||||
|
char out[8];
|
||||||
|
|
||||||
|
if (nr == 0)
|
||||||
|
break;
|
||||||
|
hts_writeUTF8(uc, out, sizeof(out));
|
||||||
|
i += nr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freet(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
51
fuzz/fuzz-entities.c
Normal file
51
fuzz/fuzz-entities.c
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
|
Copyright (C) 1998 Xavier Roche and other contributors
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||||
|
addresses or to collect any other private information about people. Doing so
|
||||||
|
would dishonor our work and waste the many hours we have spent on it.
|
||||||
|
|
||||||
|
Please visit our Website: http://www.httrack.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fuzz the HTML entity decoder (htsencoding.c). First input byte picks the
|
||||||
|
destination size, so truncation bounds get exercised too. */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htsencoding.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
static const size_t dsizes[] = {1, 2, 8, 64, 4096};
|
||||||
|
size_t dsize;
|
||||||
|
char *src, *dest;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
dsize = dsizes[data[0] % (sizeof(dsizes) / sizeof(dsizes[0]))];
|
||||||
|
data++, size--;
|
||||||
|
src = fuzz_strdup(data, size);
|
||||||
|
dest = malloct(dsize);
|
||||||
|
|
||||||
|
(void) hts_unescapeEntities(src, dest, dsize);
|
||||||
|
(void) hts_unescapeEntitiesWithCharset(src, dest, dsize, "iso-8859-1");
|
||||||
|
|
||||||
|
freet(dest);
|
||||||
|
freet(src);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
65
fuzz/fuzz-filters.c
Normal file
65
fuzz/fuzz-filters.c
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
|
Copyright (C) 1998 Xavier Roche and other contributors
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||||
|
addresses or to collect any other private information about people. Doing so
|
||||||
|
would dishonor our work and waste the many hours we have spent on it.
|
||||||
|
|
||||||
|
Please visit our Website: http://www.httrack.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fuzz the wildcard filter matcher (htsfilters.c; #148 bracket-range OOB was
|
||||||
|
here). Input splits on the first NUL: pattern, then subject string. */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htsfilters.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
char *buf = fuzz_strdup(data, size);
|
||||||
|
const char *joker = buf;
|
||||||
|
const uint8_t *sep = memchr(data, '\0', size);
|
||||||
|
/* subject in its own allocation so ASan bounds it apart from the pattern */
|
||||||
|
char *nom = sep != NULL ? fuzz_strdup(sep + 1, (data + size) - (sep + 1))
|
||||||
|
: fuzz_strdup(data + size, 0);
|
||||||
|
|
||||||
|
(void) strjoker(nom, joker, NULL, NULL);
|
||||||
|
{
|
||||||
|
LLint sz = (LLint) size;
|
||||||
|
int size_flag = 0;
|
||||||
|
|
||||||
|
(void) strjoker(nom, joker, &sz, &size_flag);
|
||||||
|
}
|
||||||
|
(void) strjokerfind(nom, joker);
|
||||||
|
{
|
||||||
|
char *filter = malloct(strlen(joker) + 2);
|
||||||
|
char *filters[1];
|
||||||
|
LLint sz = (LLint) size;
|
||||||
|
int size_flag = 0, depth = 0;
|
||||||
|
|
||||||
|
filter[0] = '-';
|
||||||
|
memcpy(filter + 1, joker, strlen(joker) + 1);
|
||||||
|
filters[0] = filter;
|
||||||
|
(void) fa_strjoker(0, filters, 1, nom, &sz, &size_flag, &depth);
|
||||||
|
freet(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
freet(nom);
|
||||||
|
freet(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
74
fuzz/fuzz-header.c
Normal file
74
fuzz/fuzz-header.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
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 the HTTP response-header parser (htslib.c): treatfirstline on the
|
||||||
|
status line, treathead on each following header. Both consume raw bytes
|
||||||
|
off the wire and copy fields into fixed htsblk buffers; treathead also
|
||||||
|
mutates its line in place and drives cookie parsing. */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htslib.h"
|
||||||
|
#include "htsbauth.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
char *buf = fuzz_strdup(data, size);
|
||||||
|
htsblk r;
|
||||||
|
t_cookie *cookie = calloct(1, sizeof(*cookie));
|
||||||
|
char *line = malloct(size + 1);
|
||||||
|
char *p = buf;
|
||||||
|
int first = 1;
|
||||||
|
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
cookie->max_len = (int) sizeof(cookie->data);
|
||||||
|
r.location = malloct(HTS_URLMAXSIZE * 2);
|
||||||
|
r.location[0] = '\0';
|
||||||
|
|
||||||
|
/* feed one header line at a time, as the receive loop does */
|
||||||
|
while (p != NULL && *p != '\0') {
|
||||||
|
char *nl = strchr(p, '\n');
|
||||||
|
size_t n = (nl != NULL) ? (size_t) (nl - p) : strlen(p);
|
||||||
|
size_t i, len = 0;
|
||||||
|
|
||||||
|
/* binput drops every '\r' on the wire; mirror it */
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
if (p[i] != '\r')
|
||||||
|
line[len++] = p[i];
|
||||||
|
line[len] = '\0';
|
||||||
|
if (first) {
|
||||||
|
treatfirstline(&r, line);
|
||||||
|
first = 0;
|
||||||
|
} else {
|
||||||
|
treathead(cookie, "www.example.com", "/", &r, line);
|
||||||
|
}
|
||||||
|
p = (nl != NULL) ? nl + 1 : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
freet(r.location);
|
||||||
|
freet(line);
|
||||||
|
freet(cookie);
|
||||||
|
freet(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
47
fuzz/fuzz-idna.c
Normal file
47
fuzz/fuzz-idna.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
|
Copyright (C) 1998 Xavier Roche and other contributors
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||||
|
addresses or to collect any other private information about people. Doing so
|
||||||
|
would dishonor our work and waste the many hours we have spent on it.
|
||||||
|
|
||||||
|
Please visit our Website: http://www.httrack.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fuzz the IDNA/punycode codec (htscharset.c, CVE-prone lineage). */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htscharset.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
char *s = fuzz_strdup(data, size);
|
||||||
|
|
||||||
|
{
|
||||||
|
char *idna = hts_convertStringUTF8ToIDNA(s, size);
|
||||||
|
freet(idna);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char *utf8 = hts_convertStringIDNAToUTF8(s, size);
|
||||||
|
freet(utf8);
|
||||||
|
}
|
||||||
|
(void) hts_isStringIDNA(s, size);
|
||||||
|
|
||||||
|
freet(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
40
fuzz/fuzz-meta.c
Normal file
40
fuzz/fuzz-meta.c
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
|
Copyright (C) 1998 Xavier Roche and other contributors
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||||
|
addresses or to collect any other private information about people. Doing so
|
||||||
|
would dishonor our work and waste the many hours we have spent on it.
|
||||||
|
|
||||||
|
Please visit our Website: http://www.httrack.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fuzz hts_getCharsetFromMeta (htscharset.c): scans raw attacker HTML for a
|
||||||
|
<meta> charset declaration. */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htscharset.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
char *html = fuzz_strdup(data, size);
|
||||||
|
char *charset = hts_getCharsetFromMeta(html, size);
|
||||||
|
|
||||||
|
freet(charset);
|
||||||
|
freet(html);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
53
fuzz/fuzz-unescape.c
Normal file
53
fuzz/fuzz-unescape.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
|
Copyright (C) 1998 Xavier Roche and other contributors
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||||
|
addresses or to collect any other private information about people. Doing so
|
||||||
|
would dishonor our work and waste the many hours we have spent on it.
|
||||||
|
|
||||||
|
Please visit our Website: http://www.httrack.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fuzz the URL percent-decoders (htslib.c). First input byte picks the
|
||||||
|
output buffer size, so the bounded-copy contract is exercised. */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "httrack-library.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
static const size_t bsizes[] = {1, 2, 16, 256, 8192};
|
||||||
|
size_t bsize;
|
||||||
|
char *s, *catbuff;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
bsize = bsizes[data[0] % (sizeof(bsizes) / sizeof(bsizes[0]))];
|
||||||
|
data++, size--;
|
||||||
|
s = fuzz_strdup(data, size);
|
||||||
|
catbuff = malloct(bsize);
|
||||||
|
|
||||||
|
(void) unescape_http(catbuff, bsize, s);
|
||||||
|
(void) unescape_http_unharm(catbuff, bsize, s, 0);
|
||||||
|
(void) unescape_http_unharm(catbuff, bsize, s, 1);
|
||||||
|
unescape_amp(s);
|
||||||
|
|
||||||
|
freet(catbuff);
|
||||||
|
freet(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
49
fuzz/fuzz-url.c
Normal file
49
fuzz/fuzz-url.c
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
|
Copyright (C) 1998 Xavier Roche and other contributors
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||||
|
addresses or to collect any other private information about people. Doing so
|
||||||
|
would dishonor our work and waste the many hours we have spent on it.
|
||||||
|
|
||||||
|
Please visit our Website: http://www.httrack.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fuzz the URL splitter and path normalizer (htslib.c): ident_url_absolute
|
||||||
|
is the first parser to touch a raw URL; fil_simplifie collapses ./ and ../
|
||||||
|
in place. */
|
||||||
|
#include "fuzz.h"
|
||||||
|
#include "htscore.h"
|
||||||
|
#include "htslib.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
char *s = fuzz_strdup(data, size);
|
||||||
|
lien_adrfil *af = calloct(1, sizeof(*af));
|
||||||
|
/* fil_simplifie rewrites in place and may grow an empty path to "./" */
|
||||||
|
char *path = malloct(size + 3);
|
||||||
|
|
||||||
|
(void) ident_url_absolute(s, af);
|
||||||
|
memcpy(path, s, size + 1);
|
||||||
|
fil_simplifie(path);
|
||||||
|
|
||||||
|
freet(path);
|
||||||
|
freet(af);
|
||||||
|
freet(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -25,46 +25,27 @@ would dishonor our work and waste the many hours we have spent on it.
|
|||||||
Please visit our Website: http://www.httrack.com
|
Please visit our Website: http://www.httrack.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* Shared helpers for the libFuzzer harnesses. */
|
||||||
/* File: Java classes parser .h */
|
#ifndef FUZZ_H
|
||||||
/* Author: Yann Philippot */
|
#define FUZZ_H
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
|
|
||||||
#ifndef HTSJAVA_DEFH
|
#define HTS_INTERNAL_BYTECODE
|
||||||
#define HTSJAVA_DEFH
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef HTS_DEF_FWSTRUCT_JAVA_HEADER
|
#include "htsbase.h"
|
||||||
#define HTS_DEF_FWSTRUCT_JAVA_HEADER
|
|
||||||
typedef struct JAVA_HEADER JAVA_HEADER;
|
|
||||||
#endif
|
|
||||||
/* 10-byte on-disk .class header image, fread() directly: fields need exact
|
|
||||||
widths (LP64's 8-byte 'unsigned long' magic never matched 0xCAFEBABE). */
|
|
||||||
struct JAVA_HEADER {
|
|
||||||
uint32_t magic;
|
|
||||||
uint16_t minor;
|
|
||||||
uint16_t major;
|
|
||||||
uint16_t count;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef HTS_DEF_FWSTRUCT_RESP_STRUCT
|
/* Heap NUL-terminated copy of the fuzzer input, so ASan bounds every read. */
|
||||||
#define HTS_DEF_FWSTRUCT_RESP_STRUCT
|
static char *fuzz_strdup(const uint8_t *data, size_t size) {
|
||||||
typedef struct RESP_STRUCT RESP_STRUCT;
|
char *s = malloct(size + 1);
|
||||||
#endif
|
|
||||||
struct RESP_STRUCT {
|
|
||||||
int file_position;
|
|
||||||
//
|
|
||||||
unsigned int index1;
|
|
||||||
unsigned int type;
|
|
||||||
char name[1024];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Library internal definictions */
|
memcpy(s, data, size);
|
||||||
#ifdef HTS_INTERNAL_BYTECODE
|
s[size] = '\0';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
EXTERNAL_FUNCTION int hts_plug_java(httrackp * opt, const char *argv);
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
41
fuzz/run-fuzzers.sh
Executable file
41
fuzz/run-fuzzers.sh
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Drive every built harness against its seed corpus.
|
||||||
|
# run-fuzzers.sh <build-fuzz-dir> check deterministic replay (CI smoke)
|
||||||
|
# run-fuzzers.sh <build-fuzz-dir> [seconds] timed mutation run (discovery)
|
||||||
|
# Replay is crash/leak-only and never mutates; the per-unit -timeout guards
|
||||||
|
# both modes against pathological slowdowns (e.g. pre-#501 strjoker).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
srcdir=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
bld=${1:?usage: run-fuzzers.sh <build-fuzz-dir> [check|seconds]}
|
||||||
|
mode=${2:-20}
|
||||||
|
|
||||||
|
status=0
|
||||||
|
for f in "$bld"/fuzz-*; do
|
||||||
|
if [ ! -f "$f" ] || [ ! -r "$f" ]; then continue; fi
|
||||||
|
case "$f" in *.o | *.c | *.dSYM) continue ;; esac
|
||||||
|
name=$(basename "$f")
|
||||||
|
corpus="$srcdir/corpus/${name#fuzz-}"
|
||||||
|
if [ "$mode" = "check" ]; then
|
||||||
|
echo "=== $name (replay) ==="
|
||||||
|
[ -d "$corpus" ] || continue
|
||||||
|
if ! "$f" -runs=0 -timeout=25 -rss_limit_mb=2048 "$corpus"; then
|
||||||
|
echo "*** $name FAILED on its corpus" >&2
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
work=$(mktemp -d)
|
||||||
|
args=("$work")
|
||||||
|
[ -d "$corpus" ] && args+=("$corpus")
|
||||||
|
echo "=== $name (${mode}s) ==="
|
||||||
|
if ! "$f" -max_total_time="$mode" -timeout=25 -rss_limit_mb=2048 \
|
||||||
|
-artifact_prefix="$work/" -print_final_stats=1 "${args[@]}"; then
|
||||||
|
echo "*** $name FAILED; artifacts:" >&2
|
||||||
|
ls -l "$work" >&2
|
||||||
|
status=1
|
||||||
|
else
|
||||||
|
rm -rf "$work"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit $status
|
||||||
34
history.txt
34
history.txt
@@ -4,6 +4,40 @@ HTTrack Website Copier release history:
|
|||||||
|
|
||||||
This file lists all changes and fixes that have been made for HTTrack
|
This file lists all changes and fixes that have been made for HTTrack
|
||||||
|
|
||||||
|
3.49-12
|
||||||
|
+ New: --why explains which filter rule accepts or rejects a given URL, then exits (#505)
|
||||||
|
+ Fixed: links carrying raw UTF-8 bytes were fetched double-encoded and 404'd (#516)
|
||||||
|
+ Fixed: an uncompressed body mislabeled as gzip no longer loses the page (#515)
|
||||||
|
+ Fixed: remote stack overflow and uninitialized read in Content-Type/-Encoding parsing (#506)
|
||||||
|
+ Fixed: several over-reads and a leak in the filter, URL and IDNA parsers (#499)
|
||||||
|
+ Fixed: bound the cache-index (.ndx) parser to its buffer (#507)
|
||||||
|
+ Fixed: catastrophic backtracking on '*'-heavy filter patterns (#513)
|
||||||
|
+ Fixed: cookies.txt was created world-readable (#511)
|
||||||
|
+ Fixed: a single corrupt cache entry no longer aborts the whole mirror (#494)
|
||||||
|
+ Fixed: cache-reconcile policy was broken for zip caches (#491, #493, #495)
|
||||||
|
+ Fixed: cancelling a crawl mid type-check no longer orphans .delayed placeholders (#496)
|
||||||
|
+ Fixed: detect URLs after the first inline script and in mid-tag attributes (#497)
|
||||||
|
+ Changed: build with _FORTIFY_SOURCE and -fstack-protector-strong (#504)
|
||||||
|
+ Changed: removed the pre-3.31 (.dat/.ndx) cache import (#512)
|
||||||
|
+ Changed: multiple internal hardening and build improvements (libFuzzer harnesses, CodeQL, dead-code removal)
|
||||||
|
|
||||||
|
3.49-11
|
||||||
|
+ New: parse robots.txt Allow rules and path wildcards per RFC 9309 (#452)
|
||||||
|
+ New: advertise deflate in Accept-Encoding and decode deflate responses (#450)
|
||||||
|
+ New: follow <source> and <track> media elements as embedded links (#451)
|
||||||
|
+ New: added modern web MIME types to the type/extension table (#448)
|
||||||
|
+ Fixed: enforce the -E time limit during a slow transfer instead of only between files (#481)
|
||||||
|
+ Fixed: sniff the leading bytes of a download so a misdeclared Content-Type no longer renames a correct URL extension
|
||||||
|
+ Fixed: fast transfers could be saved under their temporary .delayed placeholder name (#5, #107)
|
||||||
|
+ Fixed: follow a redirect that maps to the same saved file instead of writing a self-pointing stub (#159)
|
||||||
|
+ Fixed: several network-facing buffer overflows in the FTP, Java and HTML parsers
|
||||||
|
+ Fixed: the htsjava plugin could not be loaded (hidden entry points, stale library name)
|
||||||
|
+ Fixed: HTML-escape truncation and a cache-buffer leak in the parser
|
||||||
|
+ Changed: modernized the default User-Agent to an honest HTTrack identifier (#449)
|
||||||
|
+ Changed: decode the full WHATWG set of HTML named character references (#443)
|
||||||
|
+ Changed: refreshed stale HTTP status, proxy-port and TLS-floor constants (#453)
|
||||||
|
+ Changed: multiple internal hardening, build, test and CI improvements
|
||||||
|
|
||||||
3.49-10
|
3.49-10
|
||||||
+ New: --cookies-file to preload a Netscape cookies.txt before crawling (#215)
|
+ New: --cookies-file to preload a Netscape cookies.txt before crawling (#215)
|
||||||
+ New: --pause to space out file downloads by a random delay (#185)
|
+ New: --pause to space out file downloads by a random delay (#185)
|
||||||
|
|||||||
@@ -609,10 +609,9 @@ most mirrors do work. We still are working to improve the mirror quality of HTTr
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
</a><a NAME="Q2b">Q: <strong>Some Java applets do not work properly!</strong><br>
|
</a><a NAME="Q2b">Q: <strong>Some Java applets do not work properly!</strong><br>
|
||||||
A: <em>Java applets may not work in some cases, for example if HTTrack failed to detect all included classes
|
A: <em>Java applets may not work in some cases, because HTTrack does not parse compiled class files to find
|
||||||
or files called within the class file. Sometimes, Java applets need to be online, because remote files are
|
the resources they load. Java applets often need to be online anyway, since remote files are fetched directly
|
||||||
directly caught. Finally, the site structure can be incompatible with the class (always try to keep the original site structure
|
at runtime.<br>
|
||||||
when you want to get Java classes)<br>
|
|
||||||
If there is no way to make some classes work properly, you can exclude them with the filters.
|
If there is no way to make some classes work properly, you can exclude them with the filters.
|
||||||
They will be available, but only online.
|
They will be available, but only online.
|
||||||
</em>
|
</em>
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ Build options:
|
|||||||
Spider options:
|
Spider options:
|
||||||
bN accept cookies in cookies.txt (0=do not accept,* 1=accept) (--cookies[=N])
|
bN accept cookies in cookies.txt (0=do not accept,* 1=accept) (--cookies[=N])
|
||||||
u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always) (--check-type[=N])
|
u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always) (--check-type[=N])
|
||||||
j *parse Java Classes (j0 don't parse) (--parse-java[=N])
|
j *parse scripts (j0 don't parse) (--parse-java[=N])
|
||||||
sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always) (--robots[=N])
|
sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always) (--robots[=N])
|
||||||
%h force HTTP/1.0 requests (reduce update features, only for old servers or proxies) (--http-10)
|
%h force HTTP/1.0 requests (reduce update features, only for old servers or proxies) (--http-10)
|
||||||
%B tolerant requests (accept bogus responses on some servers, but not standard!) (--tolerant)
|
%B tolerant requests (accept bogus responses on some servers, but not standard!) (--tolerant)
|
||||||
@@ -417,7 +417,7 @@ site. Specifically, the defauls are:
|
|||||||
X *purge old files after update (X0 keep delete)
|
X *purge old files after update (X0 keep delete)
|
||||||
bN accept cookies in cookies.txt (0=do not accept,* 1=accept)
|
bN accept cookies in cookies.txt (0=do not accept,* 1=accept)
|
||||||
u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always)
|
u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always)
|
||||||
j *parse Java Classes (j0 don't parse)
|
j *parse scripts (j0 don't parse)
|
||||||
sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always)
|
sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always)
|
||||||
C create/use a cache for updates and retries (C0 no cache,C1 cache is prioritary,* C2 test update before)
|
C create/use a cache for updates and retries (C0 no cache,C1 cache is prioritary,* C2 test update before)
|
||||||
f *log file mode
|
f *log file mode
|
||||||
@@ -497,9 +497,9 @@ about your browser retaining them.
|
|||||||
<p align=justify> This causes different document types to be analyzed
|
<p align=justify> This causes different document types to be analyzed
|
||||||
differently.
|
differently.
|
||||||
|
|
||||||
<pre><b><i> j *parse Java Classes (j0 don't parse) </i></b></pre>
|
<pre><b><i> j *parse scripts (j0 don't parse) </i></b></pre>
|
||||||
|
|
||||||
<p align=justify> This causes Java class files to be parsed looking for
|
<p align=justify> This causes scripts to be parsed looking for
|
||||||
URLs.
|
URLs.
|
||||||
|
|
||||||
<pre><b><i> sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always) </i></b></pre>
|
<pre><b><i> sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always) </i></b></pre>
|
||||||
@@ -1178,7 +1178,7 @@ accepted and sent back in order to allow access.
|
|||||||
Spider options:
|
Spider options:
|
||||||
bN accept cookies in cookies.txt (0=do not accept,* 1=accept)
|
bN accept cookies in cookies.txt (0=do not accept,* 1=accept)
|
||||||
u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always)
|
u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always)
|
||||||
j *parse Java Classes (j0 don't parse)
|
j *parse scripts (j0 don't parse)
|
||||||
sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always)
|
sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always)
|
||||||
%h force HTTP/1.0 requests (reduce update features, only for old servers or proxies)
|
%h force HTTP/1.0 requests (reduce update features, only for old servers or proxies)
|
||||||
%B tolerant requests (accept bogus responses on some servers, but not standard!)
|
%B tolerant requests (accept bogus responses on some servers, but not standard!)
|
||||||
@@ -2451,12 +2451,10 @@ work. We still are working to improve the mirror quality of HTTrack.
|
|||||||
|
|
||||||
<p align=justify><b>Q: Some Java applets do not work properly! </b>
|
<p align=justify><b>Q: Some Java applets do not work properly! </b>
|
||||||
|
|
||||||
<p align=justify> A: Java applets may not work in some cases, for
|
<p align=justify> A: Java applets may not work in some cases, because
|
||||||
example if HTTrack failed to detect all included classes or files called
|
HTTrack does not parse compiled class files to find the resources they
|
||||||
within the class file. Sometimes, Java applets need to be online,
|
load. Java applets often need to be online anyway, since remote files
|
||||||
because remote files are directly caught. Finally, the site structure
|
are fetched directly at runtime.
|
||||||
can be incompatible with the class (always try to keep the original site
|
|
||||||
structure when you want to get Java classes)
|
|
||||||
|
|
||||||
<p align=justify> If there is no way to make some classes work properly,
|
<p align=justify> If there is no way to make some classes work properly,
|
||||||
you can exclude them with the filters. They will be available, but only
|
you can exclude them with the filters. They will be available, but only
|
||||||
|
|||||||
@@ -764,9 +764,9 @@ check, * u1 check but /, u2 check always)
|
|||||||
<td width="78%">
|
<td width="78%">
|
||||||
|
|
||||||
|
|
||||||
<p>*parse Java Classes (j0 don t parse, bitmask: |1 parse
|
<p>*parse scripts (j0 don t parse, bitmask: |1 parse
|
||||||
default, |2 don t parse .class |4 don t parse .js |8 don t
|
default, |4 don t parse .js |8 don t be aggressive)
|
||||||
be aggressive) (--parse-java[=N])</p></td></tr>
|
(--parse-java[=N])</p></td></tr>
|
||||||
<tr valign="top" align="left">
|
<tr valign="top" align="left">
|
||||||
<td width="11%"></td>
|
<td width="11%"></td>
|
||||||
<td width="6%">
|
<td width="6%">
|
||||||
@@ -889,8 +889,8 @@ only) (--protocol[=N])</p></td></tr>
|
|||||||
<td width="78%">
|
<td width="78%">
|
||||||
|
|
||||||
|
|
||||||
<p>disable a specific external mime module (-%w htsswf -%w
|
<p>disable a specific external mime module (-%w
|
||||||
htsjava) (--disable-module <param>)</p></td></tr>
|
httrack-plugin) (--disable-module <param>)</p></td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p style="margin-left:11%; margin-top: 1em"><b>Browser
|
<p style="margin-left:11%; margin-top: 1em"><b>Browser
|
||||||
@@ -2175,10 +2175,6 @@ Several scripts generating complex filenames may not find
|
|||||||
them (ex:
|
them (ex:
|
||||||
img.src=’image’+a+Mobj.dst+’.gif’)</small></p>
|
img.src=’image’+a+Mobj.dst+’.gif’)</small></p>
|
||||||
|
|
||||||
<p style="margin-left:11%; margin-top: 1em"><small>- Some
|
|
||||||
java classes may not find some files on them (class
|
|
||||||
included)</small></p>
|
|
||||||
|
|
||||||
<p style="margin-left:11%; margin-top: 1em"><small>-
|
<p style="margin-left:11%; margin-top: 1em"><small>-
|
||||||
Cgi-bin links may not work properly in some cases
|
Cgi-bin links may not work properly in some cases
|
||||||
(parameters needed). To avoid them: use filters like
|
(parameters needed). To avoid them: use filters like
|
||||||
|
|||||||
@@ -288,8 +288,8 @@ This option define whether the engine has to abandon a host if a timeout/"too sl
|
|||||||
&P extended parsing, attempt to parse all links (even in unknown tags or Javascript)
|
&P extended parsing, attempt to parse all links (even in unknown tags or Javascript)
|
||||||
This option activates the extended parsing, that attempt to find links in unknown Html code/javascript
|
This option activates the extended parsing, that attempt to find links in unknown Html code/javascript
|
||||||
|
|
||||||
j *parse Java Classes (j0 don't parse)
|
j *parse scripts (j0 don't parse)
|
||||||
This option define whether the engine has to parse java files or not to catch included files
|
This option defines whether the engine has to parse scripts or not to catch included files
|
||||||
|
|
||||||
I *make an index (I0 don't make)
|
I *make an index (I0 don't make)
|
||||||
This option define whether the engine has to generate an index.html on the top directory
|
This option define whether the engine has to generate an index.html on the top directory
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ Note: the <i>Initialization</i>, <i>Main functions</i>, <i>Options handling</i>
|
|||||||
<li>the <tt>htsdefines.h</tt> prototype file, which describes callback function prototypes</li>
|
<li>the <tt>htsdefines.h</tt> prototype file, which describes callback function prototypes</li>
|
||||||
<li>the <tt>htsopt.h</tt> prototype file, which describes the full httrackp* structure</li>
|
<li>the <tt>htsopt.h</tt> prototype file, which describes the full httrackp* structure</li>
|
||||||
<li>the <tt>callbacks-example*.c</tt> files given in the httrack archive</li>
|
<li>the <tt>callbacks-example*.c</tt> files given in the httrack archive</li>
|
||||||
<li>the <tt>htsjava.c</tt> source file (the java class plugin ; overrides 'detect' and 'parse')</li>
|
|
||||||
<li>the example given at the end of this document</li>
|
<li>the example given at the end of this document</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ h4 { margin: 0; font-weight: bold; font-size: 1.18em; }
|
|||||||
<br>Avoid "never", because the local mirror could be bogus
|
<br>Avoid "never", because the local mirror could be bogus
|
||||||
</small><br><br>
|
</small><br><br>
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<li>Parse java files</li>
|
<li>Parse scripts</li>
|
||||||
<br><small>Must the engine parse .java files (java classes) to seek included filenames?
|
<br><small>Must the engine parse scripts to seek included filenames?
|
||||||
<br>It is checked by default
|
<br>It is checked by default
|
||||||
</small><br><br>
|
</small><br><br>
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|||||||
119
m4/ax_add_fortify_source.m4
Normal file
119
m4/ax_add_fortify_source.m4
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# ===========================================================================
|
||||||
|
# https://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_ADD_FORTIFY_SOURCE
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# Check whether -D_FORTIFY_SOURCE=2 can be added to CPPFLAGS without macro
|
||||||
|
# redefinition warnings, other cpp warnings or linker. Some distributions
|
||||||
|
# (such as Ubuntu or Gentoo Linux) enable _FORTIFY_SOURCE globally in
|
||||||
|
# their compilers, leading to unnecessary warnings in the form of
|
||||||
|
#
|
||||||
|
# <command-line>:0:0: error: "_FORTIFY_SOURCE" redefined [-Werror]
|
||||||
|
# <built-in>: note: this is the location of the previous definition
|
||||||
|
#
|
||||||
|
# which is a problem if -Werror is enabled. This macro checks whether
|
||||||
|
# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2
|
||||||
|
# to CPPFLAGS.
|
||||||
|
#
|
||||||
|
# Newer mingw-w64 msys2 package comes with a bug in
|
||||||
|
# headers-git-7.0.0.5546.d200317d-1. It broke -D_FORTIFY_SOURCE support,
|
||||||
|
# and would need -lssp or -fstack-protector. See
|
||||||
|
# https://github.com/msys2/MINGW-packages/issues/5803. Try to actually
|
||||||
|
# link it.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 David Seifert <soap@gentoo.org>
|
||||||
|
# Copyright (c) 2019, 2023 Reini Urban <rurban@cpan.org>
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice
|
||||||
|
# and this notice are preserved. This file is offered as-is, without any
|
||||||
|
# warranty.
|
||||||
|
|
||||||
|
#serial 10
|
||||||
|
|
||||||
|
AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[
|
||||||
|
ac_save_cflags=$CFLAGS
|
||||||
|
ac_cwerror_flag=yes
|
||||||
|
AX_CHECK_COMPILE_FLAG([-Werror],[CFLAGS="$CFLAGS -Werror"])
|
||||||
|
ax_add_fortify_3_failed=
|
||||||
|
AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=3 to CPPFLAGS])
|
||||||
|
AC_LINK_IFELSE([
|
||||||
|
AC_LANG_PROGRAM([],
|
||||||
|
[[
|
||||||
|
#ifndef _FORTIFY_SOURCE
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
_FORTIFY_SOURCE_already_defined;
|
||||||
|
#endif
|
||||||
|
]]
|
||||||
|
)],
|
||||||
|
AC_LINK_IFELSE([
|
||||||
|
AC_LANG_SOURCE([[
|
||||||
|
#define _FORTIFY_SOURCE 3
|
||||||
|
#include <string.h>
|
||||||
|
int main(void) {
|
||||||
|
char *s = " ";
|
||||||
|
strcpy(s, "x");
|
||||||
|
return strlen(s)-1;
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
)],
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
CFLAGS=$ac_save_cflags
|
||||||
|
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=3"
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
ax_add_fortify_3_failed=1
|
||||||
|
],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
ax_add_fortify_3_failed=1
|
||||||
|
])
|
||||||
|
if test -n "$ax_add_fortify_3_failed"
|
||||||
|
then
|
||||||
|
AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CPPFLAGS])
|
||||||
|
AC_LINK_IFELSE([
|
||||||
|
AC_LANG_PROGRAM([],
|
||||||
|
[[
|
||||||
|
#ifndef _FORTIFY_SOURCE
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
_FORTIFY_SOURCE_already_defined;
|
||||||
|
#endif
|
||||||
|
]]
|
||||||
|
)],
|
||||||
|
AC_LINK_IFELSE([
|
||||||
|
AC_LANG_SOURCE([[
|
||||||
|
#define _FORTIFY_SOURCE 2
|
||||||
|
#include <string.h>
|
||||||
|
int main(void) {
|
||||||
|
char *s = " ";
|
||||||
|
strcpy(s, "x");
|
||||||
|
return strlen(s)-1;
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
)],
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
CFLAGS=$ac_save_cflags
|
||||||
|
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2"
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
CFLAGS=$ac_save_cflags
|
||||||
|
],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
CFLAGS=$ac_save_cflags
|
||||||
|
])
|
||||||
|
fi
|
||||||
|
])
|
||||||
66
m4/check_codecs.m4
Normal file
66
m4/check_codecs.m4
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
dnl @synopsis CHECK_BROTLI()
|
||||||
|
dnl @synopsis CHECK_ZSTD()
|
||||||
|
dnl
|
||||||
|
dnl Look for libbrotlidec and libzstd, the decoders for the "br" and "zstd"
|
||||||
|
dnl HTTP content codings. Both are optional: a missing library only drops the
|
||||||
|
dnl coding from Accept-Encoding. --with-brotli=DIR / --with-zstd=DIR point at a
|
||||||
|
dnl prefix; --without-brotli / --without-zstd disable the coding; the default
|
||||||
|
dnl is to use the library when it is found.
|
||||||
|
dnl
|
||||||
|
dnl Define HTS_USEBROTLI / HTS_USEZSTD to 1 or 0, and substitute BROTLI_LIBS /
|
||||||
|
dnl ZSTD_LIBS.
|
||||||
|
|
||||||
|
dnl CHECK_CODEC(name, NAME, header, library, symbol, companion-libs)
|
||||||
|
AC_DEFUN([CHECK_CODEC], [
|
||||||
|
AC_ARG_WITH([$1],
|
||||||
|
[AS_HELP_STRING([--with-$1@<:@=DIR@:>@],[Enable the $1 content coding @<:@default=auto@:>@])],
|
||||||
|
[codec_want=$withval], [codec_want=auto])
|
||||||
|
$2_LIBS=""
|
||||||
|
codec_have=no
|
||||||
|
if test "$codec_want" != "no"; then
|
||||||
|
codec_old_cppflags="$CPPFLAGS"
|
||||||
|
codec_old_ldflags="$LDFLAGS"
|
||||||
|
codec_dir=no
|
||||||
|
if test "$codec_want" != "yes" -a "$codec_want" != "auto"; then
|
||||||
|
codec_dir=yes
|
||||||
|
# An explicit prefix is authoritative: if the header is not under
|
||||||
|
# it, error rather than silently pick a system copy.
|
||||||
|
if test ! -f "$codec_want/include/$3"; then
|
||||||
|
AC_MSG_ERROR([$1 requested at $codec_want but $codec_want/include/$3 is missing])
|
||||||
|
fi
|
||||||
|
CPPFLAGS="$CPPFLAGS -I$codec_want/include"
|
||||||
|
LDFLAGS="$LDFLAGS -L$codec_want/lib"
|
||||||
|
fi
|
||||||
|
AC_CHECK_HEADER([$3], [codec_h=yes], [codec_h=no])
|
||||||
|
AC_CHECK_LIB([$4], [$5], [codec_lib=yes], [codec_lib=no], [$6])
|
||||||
|
CPPFLAGS="$codec_old_cppflags"
|
||||||
|
LDFLAGS="$codec_old_ldflags"
|
||||||
|
if test "$codec_h" = "yes" -a "$codec_lib" = "yes"; then
|
||||||
|
codec_have=yes
|
||||||
|
$2_LIBS="-l$4 $6"
|
||||||
|
if test "$codec_dir" = "yes"; then
|
||||||
|
$2_LIBS="-L$codec_want/lib -l$4 $6"
|
||||||
|
# The rest of configure still needs the header path.
|
||||||
|
CPPFLAGS="$CPPFLAGS -I$codec_want/include"
|
||||||
|
fi
|
||||||
|
elif test "$codec_want" != "auto"; then
|
||||||
|
AC_MSG_ERROR([$1 requested but lib$4/$3 not found])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_MSG_CHECKING([whether to enable the $1 content coding])
|
||||||
|
AC_MSG_RESULT([$codec_have])
|
||||||
|
if test "$codec_have" = "yes"; then
|
||||||
|
AC_DEFINE([HTS_USE$2], [1], [Define to 1 to decode the $1 content coding])
|
||||||
|
else
|
||||||
|
AC_DEFINE([HTS_USE$2], [0], [Define to 1 to decode the $1 content coding])
|
||||||
|
fi
|
||||||
|
AC_SUBST([$2_LIBS])
|
||||||
|
AC_SUBST([$2_ENABLED], [$codec_have])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl brotlidec needs brotlicommon (the static dictionary) for a fully-static link.
|
||||||
|
AC_DEFUN([CHECK_BROTLI],
|
||||||
|
[CHECK_CODEC([brotli], [BROTLI], [brotli/decode.h], [brotlidec], [BrotliDecoderDecompressStream], [-lbrotlicommon])])
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_ZSTD],
|
||||||
|
[CHECK_CODEC([zstd], [ZSTD], [zstd.h], [zstd], [ZSTD_decompressStream], [])])
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is generated by man/makeman.sh; do not edit by hand.
|
.\" This file is generated by man/makeman.sh; do not edit by hand.
|
||||||
.\" SPDX-License-Identifier: GPL-3.0-or-later
|
.\" SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
.TH httrack 1 "27 June 2026" "httrack website copier"
|
.TH httrack 1 "14 July 2026" "httrack website copier"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
httrack \- offline browser : copy websites to a local directory
|
httrack \- offline browser : copy websites to a local directory
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -51,6 +51,7 @@ httrack \- offline browser : copy websites to a local directory
|
|||||||
[ \fB\-%T, \-\-utf8\-conversion\fR ]
|
[ \fB\-%T, \-\-utf8\-conversion\fR ]
|
||||||
[ \fB\-bN, \-\-cookies[=N]\fR ]
|
[ \fB\-bN, \-\-cookies[=N]\fR ]
|
||||||
[ \fB\-%K, \-\-cookies\-file\fR ]
|
[ \fB\-%K, \-\-cookies\-file\fR ]
|
||||||
|
[ \fB\-%Y, \-\-why\fR ]
|
||||||
[ \fB\-u, \-\-check\-type[=N]\fR ]
|
[ \fB\-u, \-\-check\-type[=N]\fR ]
|
||||||
[ \fB\-j, \-\-parse\-java[=N]\fR ]
|
[ \fB\-j, \-\-parse\-java[=N]\fR ]
|
||||||
[ \fB\-sN, \-\-robots[=N]\fR ]
|
[ \fB\-sN, \-\-robots[=N]\fR ]
|
||||||
@@ -134,7 +135,7 @@ continue an interrupted mirror using the cache (\-\-continue)
|
|||||||
mirror ALL links located in the first level pages (mirror links) (\-\-mirrorlinks)
|
mirror ALL links located in the first level pages (mirror links) (\-\-mirrorlinks)
|
||||||
.SS Proxy options:
|
.SS Proxy options:
|
||||||
.IP \-P
|
.IP \-P
|
||||||
proxy use (\-P proxy:port or \-P user:pass@proxy:port) (\-\-proxy <param>)
|
proxy use (\-P [socks5://][user:pass@]proxy:port) (\-\-proxy <param>)
|
||||||
.IP \-%f
|
.IP \-%f
|
||||||
*use proxy for ftp (f0 don't use) (\-\-httpproxy\-ftp[=N])
|
*use proxy for ftp (f0 don't use) (\-\-httpproxy\-ftp[=N])
|
||||||
.IP \-%b
|
.IP \-%b
|
||||||
@@ -218,10 +219,12 @@ links conversion to UTF\-8 (\-\-utf8\-conversion)
|
|||||||
accept cookies in cookies.txt (0=do not accept,* 1=accept) (\-\-cookies[=N])
|
accept cookies in cookies.txt (0=do not accept,* 1=accept) (\-\-cookies[=N])
|
||||||
.IP \-%K
|
.IP \-%K
|
||||||
load extra cookies from a Netscape cookies.txt (\-\-cookies\-file <param>)
|
load extra cookies from a Netscape cookies.txt (\-\-cookies\-file <param>)
|
||||||
|
.IP \-%Y
|
||||||
|
explain which filter rule accepts or rejects a URL, then exit (\-\-why <param>)
|
||||||
.IP \-u
|
.IP \-u
|
||||||
check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always) (\-\-check\-type[=N])
|
check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always) (\-\-check\-type[=N])
|
||||||
.IP \-j
|
.IP \-j
|
||||||
*parse Java Classes (j0 don't parse, bitmask: |1 parse default, |2 don't parse .class |4 don't parse .js |8 don't be aggressive) (\-\-parse\-java[=N])
|
*parse scripts (j0 don't parse, bitmask: |1 parse default, |4 don't parse .js |8 don't be aggressive) (\-\-parse\-java[=N])
|
||||||
.IP \-sN
|
.IP \-sN
|
||||||
follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always, 3=always (even strict rules)) (\-\-robots[=N])
|
follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always, 3=always (even strict rules)) (\-\-robots[=N])
|
||||||
.IP \-%h
|
.IP \-%h
|
||||||
@@ -245,7 +248,7 @@ can also be used to force a specific file type: \-\-assume foo.cgi=text/html
|
|||||||
.IP \-@iN
|
.IP \-@iN
|
||||||
internet protocol (0=both ipv6+ipv4, 4=ipv4 only, 6=ipv6 only) (\-\-protocol[=N])
|
internet protocol (0=both ipv6+ipv4, 4=ipv4 only, 6=ipv6 only) (\-\-protocol[=N])
|
||||||
.IP \-%w
|
.IP \-%w
|
||||||
disable a specific external mime module (\-%w htsswf \-%w htsjava) (\-\-disable\-module <param>)
|
disable a specific external mime module (\-%w httrack\-plugin) (\-\-disable\-module <param>)
|
||||||
.SS Browser ID:
|
.SS Browser ID:
|
||||||
.IP \-F
|
.IP \-F
|
||||||
user\-agent field sent in HTTP headers (\-F "user\-agent name") (\-\-user\-agent <param>)
|
user\-agent field sent in HTTP headers (\-F "user\-agent name") (\-\-user\-agent <param>)
|
||||||
@@ -511,8 +514,6 @@ that would have solved them.
|
|||||||
.SM
|
.SM
|
||||||
\- Several scripts generating complex filenames may not find them (ex: img.src='image'+a+Mobj.dst+'.gif')
|
\- Several scripts generating complex filenames may not find them (ex: img.src='image'+a+Mobj.dst+'.gif')
|
||||||
.SM
|
.SM
|
||||||
\- Some java classes may not find some files on them (class included)
|
|
||||||
.SM
|
|
||||||
\- Cgi\-bin links may not work properly in some cases (parameters needed). To avoid them: use filters like \-*cgi\-bin*
|
\- Cgi\-bin links may not work properly in some cases (parameters needed). To avoid them: use filters like \-*cgi\-bin*
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
Please reports bugs to
|
Please reports bugs to
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ httrack_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_PIE)
|
|||||||
proxytrack_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_PIE)
|
proxytrack_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_PIE)
|
||||||
htsserver_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_PIE)
|
htsserver_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_PIE)
|
||||||
|
|
||||||
lib_LTLIBRARIES = libhttrack.la libhtsjava.la
|
lib_LTLIBRARIES = libhttrack.la
|
||||||
|
|
||||||
htsserver_SOURCES = htsserver.c htsserver.h htsweb.c htsweb.h
|
htsserver_SOURCES = htsserver.c htsserver.h htsweb.c htsweb.h
|
||||||
proxytrack_SOURCES = proxy/main.c \
|
proxytrack_SOURCES = proxy/main.c \
|
||||||
@@ -61,7 +61,7 @@ libhttrack_la_SOURCES = htscore.c htsparse.c htsback.c htscache.c \
|
|||||||
htshelp.c htslib.c htscoremain.c \
|
htshelp.c htslib.c htscoremain.c \
|
||||||
htsname.c htsrobots.c htstools.c htswizard.c \
|
htsname.c htsrobots.c htstools.c htswizard.c \
|
||||||
htsalias.c htsthread.c htsindex.c htsbauth.c \
|
htsalias.c htsthread.c htsindex.c htsbauth.c \
|
||||||
htsmd5.c htszlib.c htswrap.c htsconcat.c \
|
htsmd5.c htscodec.c htsproxy.c htszlib.c htswrap.c htsconcat.c \
|
||||||
htsmodules.c htscharset.c punycode.c htsencoding.c htssniff.c \
|
htsmodules.c htscharset.c punycode.c htsencoding.c htssniff.c \
|
||||||
md5.c \
|
md5.c \
|
||||||
minizip/ioapi.c minizip/mztools.c minizip/unzip.c minizip/zip.c \
|
minizip/ioapi.c minizip/mztools.c minizip/unzip.c minizip/zip.c \
|
||||||
@@ -72,25 +72,20 @@ libhttrack_la_SOURCES = htscore.c htsparse.c htsback.c htscache.c \
|
|||||||
htshelp.h htsindex.h htslib.h htsmd5.h \
|
htshelp.h htsindex.h htslib.h htsmd5.h \
|
||||||
htsmodules.h htsname.h htsnet.h htssniff.h \
|
htsmodules.h htsname.h htsnet.h htssniff.h \
|
||||||
htsopt.h htsrobots.h htsthread.h \
|
htsopt.h htsrobots.h htsthread.h \
|
||||||
htstools.h htswizard.h htswrap.h htszlib.h \
|
htstools.h htswizard.h htswrap.h htscodec.h htsproxy.h htszlib.h \
|
||||||
htsstrings.h htsarrays.h httrack-library.h \
|
htsstrings.h htsarrays.h httrack-library.h \
|
||||||
htscharset.h punycode.h htsencoding.h \
|
htscharset.h punycode.h htsencoding.h \
|
||||||
htsentities.h htsentities.sh htsbasiccharsets.sh htscodepages.h \
|
htsentities.h htsentities.sh htsbasiccharsets.sh htscodepages.h \
|
||||||
md5.h coucal/murmurhash3.h \
|
md5.h coucal/murmurhash3.h \
|
||||||
minizip/crypt.h minizip/ioapi.h minizip/mztools.h minizip/unzip.h minizip/zip.h
|
minizip/crypt.h minizip/ioapi.h minizip/mztools.h minizip/unzip.h minizip/zip.h
|
||||||
libhttrack_la_LIBADD = $(THREADS_LIBS) $(ZLIB_LIBS) $(OPENSSL_LIBS) $(DL_LIBS) $(SOCKET_LIBS) $(ICONV_LIBS)
|
libhttrack_la_LIBADD = $(THREADS_LIBS) $(ZLIB_LIBS) $(BROTLI_LIBS) $(ZSTD_LIBS) $(OPENSSL_LIBS) $(DL_LIBS) $(SOCKET_LIBS) $(ICONV_LIBS)
|
||||||
libhttrack_la_CFLAGS = $(AM_CFLAGS) -DLIBHTTRACK_EXPORTS -DZLIB_CONST
|
libhttrack_la_CFLAGS = $(AM_CFLAGS) -DLIBHTTRACK_EXPORTS -DZLIB_CONST
|
||||||
libhttrack_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(VERSION_INFO)
|
libhttrack_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(VERSION_INFO)
|
||||||
|
|
||||||
libhtsjava_la_SOURCES = htsjava.c htsjava.h
|
|
||||||
libhtsjava_la_LIBADD = $(THREADS_LIBS) $(DL_LIBS) libhttrack.la
|
|
||||||
# This thin JNI wrapper reaches libc only through libhttrack, so the direct
|
|
||||||
# libc edge is dropped from DT_NEEDED (library-not-linked-against-libc). Force
|
|
||||||
# libc back as a dependency; configure gates the flag since only a GNU-style
|
|
||||||
# linker accepts it (LIBC_FORCE_LINK is empty on e.g. macOS).
|
|
||||||
libhtsjava_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(VERSION_INFO) $(LIBC_FORCE_LINK)
|
|
||||||
|
|
||||||
EXTRA_DIST = httrack.h webhttrack \
|
EXTRA_DIST = httrack.h webhttrack \
|
||||||
|
version.rc \
|
||||||
|
libhttrack.rc \
|
||||||
|
httrack.rc \
|
||||||
coucal/murmurhash3.h.diff \
|
coucal/murmurhash3.h.diff \
|
||||||
coucal/murmurhash3.h.orig \
|
coucal/murmurhash3.h.orig \
|
||||||
minizip/iowin32.c \
|
minizip/iowin32.c \
|
||||||
@@ -113,13 +108,13 @@ EXTRA_DIST = httrack.h webhttrack \
|
|||||||
proxy/proxystrings.h \
|
proxy/proxystrings.h \
|
||||||
proxy/proxytrack.h \
|
proxy/proxytrack.h \
|
||||||
proxy/store.h \
|
proxy/store.h \
|
||||||
proxy/proxytrack.vcproj \
|
|
||||||
coucal/LICENSE \
|
coucal/LICENSE \
|
||||||
coucal/Makefile \
|
coucal/Makefile \
|
||||||
coucal/README.md \
|
coucal/README.md \
|
||||||
coucal/sample.c \
|
coucal/sample.c \
|
||||||
coucal/tests.c \
|
coucal/tests.c \
|
||||||
htsjava.vcproj \
|
vcpkg.json \
|
||||||
httrack.dsp httrack.dsw httrack.vcproj \
|
httrack.vcxproj \
|
||||||
libhttrack.dsp libhttrack.dsw libhttrack.vcproj \
|
libhttrack.vcxproj \
|
||||||
webhttrack.dsp webhttrack.dsw webhttrack.vcproj
|
proxytrack.vcxproj \
|
||||||
|
webhttrack.vcxproj
|
||||||
|
|||||||
@@ -114,6 +114,8 @@ const char *hts_optalias[][4] = {
|
|||||||
"strip [host/pattern=]key1,key2,... from URLs"},
|
"strip [host/pattern=]key1,key2,... from URLs"},
|
||||||
{"cookies-file", "-%K", "param1",
|
{"cookies-file", "-%K", "param1",
|
||||||
"load extra cookies from a Netscape cookies.txt"},
|
"load extra cookies from a Netscape cookies.txt"},
|
||||||
|
{"why", "-%Y", "param1",
|
||||||
|
"explain which filter rule accepts or rejects a URL, then exit"},
|
||||||
{"pause", "-%G", "param1",
|
{"pause", "-%G", "param1",
|
||||||
"random pause of MIN[:MAX] seconds between files"},
|
"random pause of MIN[:MAX] seconds between files"},
|
||||||
{"generate-errors", "-o", "single", ""},
|
{"generate-errors", "-o", "single", ""},
|
||||||
@@ -283,7 +285,6 @@ int optalias_check(int argc, const char *const *argv, int n_arg,
|
|||||||
char *position;
|
char *position;
|
||||||
int need_param = 1;
|
int need_param = 1;
|
||||||
|
|
||||||
//int return_param=0;
|
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
command[0] = param[0] = addcommand[0] = '\0';
|
command[0] = param[0] = addcommand[0] = '\0';
|
||||||
@@ -361,7 +362,6 @@ int optalias_check(int argc, const char *const *argv, int n_arg,
|
|||||||
strlcatbuff(return_argv[0], "0", return_argv_size);
|
strlcatbuff(return_argv[0], "0", return_argv_size);
|
||||||
else if (strcmp(param, "on") == 0) {
|
else if (strcmp(param, "on") == 0) {
|
||||||
// on is the default
|
// on is the default
|
||||||
// strcatbuff(return_argv[0],"1");
|
|
||||||
} else
|
} else
|
||||||
strlcatbuff(return_argv[0], param, return_argv_size);
|
strlcatbuff(return_argv[0], param, return_argv_size);
|
||||||
}
|
}
|
||||||
|
|||||||
723
src/htsback.c
723
src/htsback.c
File diff suppressed because it is too large
Load Diff
@@ -113,6 +113,12 @@ void back_set_locked(struct_back * sback, const int p);
|
|||||||
void back_set_unlocked(struct_back * sback, const int p);
|
void back_set_unlocked(struct_back * sback, const int p);
|
||||||
int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
||||||
const int p);
|
const int p);
|
||||||
|
/* Discard back's on-disk .delayed placeholder and its refname. */
|
||||||
|
void back_delayed_discard(httrackp *opt, lien_back *back);
|
||||||
|
/* Move back's .delayed placeholder (and open stream) to newname;
|
||||||
|
HTS_FALSE = file lost, slot flagged in error. */
|
||||||
|
hts_boolean back_delayed_rename(httrackp *opt, lien_back *back,
|
||||||
|
const char *newname);
|
||||||
void back_index_unlock(struct_back * sback, const int p);
|
void back_index_unlock(struct_back * sback, const int p);
|
||||||
int back_clear_entry(lien_back * back);
|
int back_clear_entry(lien_back * back);
|
||||||
int back_flush_output(httrackp * opt, cache_back * cache, struct_back * sback,
|
int back_flush_output(httrackp * opt, cache_back * cache, struct_back * sback,
|
||||||
@@ -132,12 +138,11 @@ LLint back_transferred(LLint add, struct_back * sback);
|
|||||||
|
|
||||||
// hostback
|
// hostback
|
||||||
#if HTS_XGETHOST
|
#if HTS_XGETHOST
|
||||||
void back_solve(httrackp * opt, lien_back * sback);
|
|
||||||
int host_wait(httrackp * opt, lien_back * sback);
|
int host_wait(httrackp * opt, lien_back * sback);
|
||||||
#endif
|
#endif
|
||||||
int back_checksize(httrackp * opt, lien_back * eback, int check_only_totalsize);
|
int back_checksize(httrackp * opt, lien_back * eback, int check_only_totalsize);
|
||||||
/* Enforce -M/-E quotas: requests a smooth stop when reached; returns 0 once
|
/* Enforce -M/-E quotas: smooth-stops when reached; returns 0 once the -M cap
|
||||||
the -E deadline overran its grace period (callers must stop waiting). */
|
or -E deadline overruns its grace period (callers must stop waiting). */
|
||||||
int back_checkmirror(httrackp * opt);
|
int back_checkmirror(httrackp * opt);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -55,8 +55,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// inline function in Wspiapi.h.
|
// inline function in Wspiapi.h.
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#include <Wspiapi.h>
|
#include <Wspiapi.h>
|
||||||
// #include <winsock2.h>
|
|
||||||
// #include <tpipv6.h>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,6 @@ int cookie_add(t_cookie * cookie, const char *cook_name, const char *cook_value,
|
|||||||
#if DEBUG_COOK
|
#if DEBUG_COOK
|
||||||
printf("add_new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",
|
printf("add_new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",
|
||||||
cook_name, cook_value, domain, path);
|
cook_name, cook_value, domain, path);
|
||||||
//printf(">>>cook: %s<<<\n",cookie->data);
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -208,8 +207,6 @@ int cookie_load(t_cookie * cookie, const char *fpath, const char *name) {
|
|||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
char buffer[8192];
|
char buffer[8192];
|
||||||
|
|
||||||
// cookie->data[0]='\0';
|
|
||||||
|
|
||||||
// Fusionner d'abord les éventuels cookies IE
|
// Fusionner d'abord les éventuels cookies IE
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
{
|
{
|
||||||
@@ -310,14 +307,25 @@ int cookie_load(t_cookie * cookie, const char *fpath, const char *name) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// écrire cookies.txt
|
/* Write cookies.txt; returns 0 on success. The jar holds live session
|
||||||
// !=0 : erreur
|
cookies, so keep it owner-only on Unix (Windows inherits folder ACLs). */
|
||||||
int cookie_save(t_cookie * cookie, const char *name) {
|
int cookie_save(t_cookie * cookie, const char *name) {
|
||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
|
|
||||||
if (strnotempty(cookie->data)) {
|
if (strnotempty(cookie->data)) {
|
||||||
char BIGSTK line[8192];
|
char BIGSTK line[8192];
|
||||||
|
#ifdef _WIN32
|
||||||
FILE *fp = fopen(fconv(catbuff, sizeof(catbuff), name), "wb");
|
FILE *fp = fopen(fconv(catbuff, sizeof(catbuff), name), "wb");
|
||||||
|
#else
|
||||||
|
const int fd = open(fconv(catbuff, sizeof(catbuff), name),
|
||||||
|
O_WRONLY | O_CREAT | O_TRUNC, HTS_PROTECT_FILE);
|
||||||
|
FILE *fp = fd != -1 ? fdopen(fd, "wb") : NULL;
|
||||||
|
|
||||||
|
if (fd != -1 && fp == NULL)
|
||||||
|
close(fd); /* fdopen failed: don't leak the descriptor */
|
||||||
|
if (fp != NULL) /* O_CREAT's mode skips pre-existing jars: tighten those */
|
||||||
|
(void) fchmod(fd, HTS_PROTECT_FILE);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fp) {
|
if (fp) {
|
||||||
char *a = cookie->data;
|
char *a = cookie->data;
|
||||||
|
|||||||
1157
src/htscache.c
1157
src/htscache.c
File diff suppressed because it is too large
Load Diff
@@ -78,14 +78,22 @@ htsblk *cache_header(httrackp * opt, cache_back * cache, const char *adr,
|
|||||||
const char *fil, htsblk * r);
|
const char *fil, htsblk * r);
|
||||||
void cache_init(cache_back * cache, httrackp * opt);
|
void cache_init(cache_back * cache, httrackp * opt);
|
||||||
|
|
||||||
int cache_writedata(FILE * cache_ndx, FILE * cache_dat, const char *str1,
|
/* Which hts-cache/ generation (new.* vs old.*) is authoritative. */
|
||||||
const char *str2, char *outbuff, int len);
|
typedef enum {
|
||||||
int cache_readdata(cache_back * cache, const char *str1, const char *str2,
|
CACHE_RECONCILE_PROMOTE, /* no new cache: promote the old generation */
|
||||||
char **inbuff, int *len);
|
CACHE_RECONCILE_INTERRUPTED, /* aborted run: keep the larger generation */
|
||||||
|
CACHE_RECONCILE_ROLLBACK /* nothing transferred: restore the old one */
|
||||||
|
} hts_cache_reconcile_mode;
|
||||||
|
|
||||||
|
/* Reconcile the on-disk cache generations according to mode; a no-op when
|
||||||
|
the involved files are absent. */
|
||||||
|
void hts_cache_reconcile(httrackp *opt, hts_cache_reconcile_mode mode);
|
||||||
|
|
||||||
void cache_rstr(FILE *fp, char *s, size_t s_size);
|
void cache_rstr(FILE *fp, char *s, size_t s_size);
|
||||||
char *cache_rstr_addr(FILE * fp);
|
char *cache_rstr_addr(FILE * fp);
|
||||||
int cache_brstr(char *adr, char *s, size_t s_size);
|
int cache_brstr(char *adr, char *s, size_t s_size);
|
||||||
|
/* binput over a NUL-terminated buffer, bounded: no read starts at/past end. */
|
||||||
|
int cache_binput(char *adr, const char *end, char *s, int max);
|
||||||
int cache_brint(char *adr, int *i);
|
int cache_brint(char *adr, int *i);
|
||||||
void cache_rint(FILE * fp, int *i);
|
void cache_rint(FILE * fp, int *i);
|
||||||
void cache_rLLint(FILE * fp, LLint * i);
|
void cache_rLLint(FILE * fp, LLint * i);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -77,14 +78,6 @@ static void selftest_open_for_read(cache_back *cache, httrackp *opt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void selftest_close(cache_back *cache) {
|
static void selftest_close(cache_back *cache) {
|
||||||
if (cache->dat != NULL) {
|
|
||||||
fclose(cache->dat);
|
|
||||||
cache->dat = NULL;
|
|
||||||
}
|
|
||||||
if (cache->ndx != NULL) {
|
|
||||||
fclose(cache->ndx);
|
|
||||||
cache->ndx = NULL;
|
|
||||||
}
|
|
||||||
if (cache->zipOutput != NULL) {
|
if (cache->zipOutput != NULL) {
|
||||||
zipClose(cache->zipOutput,
|
zipClose(cache->zipOutput,
|
||||||
"Created by HTTrack Website Copier (cache self-test)");
|
"Created by HTTrack Website Copier (cache self-test)");
|
||||||
@@ -239,11 +232,10 @@ static int disk_fallback_selftest(httrackp *opt) {
|
|||||||
static const char body[] = "BINARY-on-disk-body-0123456789-no-trailing-nul";
|
static const char body[] = "BINARY-on-disk-body-0123456789-no-trailing-nul";
|
||||||
const size_t body_len = sizeof(body) - 1;
|
const size_t body_len = sizeof(body) - 1;
|
||||||
|
|
||||||
/* X-Save must start with path_html_utf8 so the reader resolves it verbatim
|
/* a DOS-ified X-Save loses the path_html_utf8 prefix the reader matches on,
|
||||||
(otherwise it re-roots it as a pre-3.40 relative path); then the body we
|
and gets re-rooted as a pre-3.40 relative path; fconv() only on access */
|
||||||
create at fconv(save) is exactly where cache_readex looks for it. */
|
concat(save, sizeof(save), StringBuff(opt->path_html_utf8),
|
||||||
fconcat(save, sizeof(save), StringBuff(opt->path_html_utf8),
|
"example.com/blob.bin");
|
||||||
"example.com/blob.bin");
|
|
||||||
|
|
||||||
/* write only the header (X-In-Cache: 0); the body stays on disk */
|
/* write only the header (X-In-Cache: 0); the body stays on disk */
|
||||||
selftest_open_for_write(&cache, opt);
|
selftest_open_for_write(&cache, opt);
|
||||||
@@ -321,6 +313,7 @@ typedef struct {
|
|||||||
size_t budget; /**< bytes allowed through before writes start failing */
|
size_t budget; /**< bytes allowed through before writes start failing */
|
||||||
int fail_errno; /**< errno set on the failing write (ENOSPC, EIO, ...) */
|
int fail_errno; /**< errno set on the failing write (ENOSPC, EIO, ...) */
|
||||||
int writes; /**< zwrite call count, to detect re-entry into the stream */
|
int writes; /**< zwrite call count, to detect re-entry into the stream */
|
||||||
|
int fail_once; /**< recover (unlimited budget) after the first failure */
|
||||||
} writefail_inject;
|
} writefail_inject;
|
||||||
|
|
||||||
/* zwrite that copies until the budget runs out, then fails with inj->fail_errno
|
/* zwrite that copies until the budget runs out, then fails with inj->fail_errno
|
||||||
@@ -335,6 +328,8 @@ static uLong selftest_failing_zwrite(voidpf opaque, voidpf stream,
|
|||||||
inj->budget -= (size_t) size;
|
inj->budget -= (size_t) size;
|
||||||
return (uLong) fwrite(buf, 1, (size_t) size, (FILE *) stream);
|
return (uLong) fwrite(buf, 1, (size_t) size, (FILE *) stream);
|
||||||
}
|
}
|
||||||
|
if (inj->fail_once)
|
||||||
|
inj->budget = (size_t) -1; /* the backend recovers after this failure */
|
||||||
errno = inj->fail_errno;
|
errno = inj->fail_errno;
|
||||||
return 0; /* short write -> the minizip op returns an error */
|
return 0; /* short write -> the minizip op returns an error */
|
||||||
}
|
}
|
||||||
@@ -373,9 +368,50 @@ static void writefail_store(httrackp *opt, cache_back *cache, const char *fil,
|
|||||||
freet(bodycopy);
|
freet(bodycopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #174/#219: a failing cache write used to crash via assertf(); it must instead
|
/* Store an entry claiming a >2GB body; the degrade path never reads data. */
|
||||||
stop the mirror (exit_xh = -1) without crashing. Assert that, plus the cache
|
static void writefail_store_oversized(httrackp *opt, cache_back *cache,
|
||||||
is flagged and a sibling write doesn't re-enter the broken stream. */
|
const char *fil, int is_write) {
|
||||||
|
htsblk r;
|
||||||
|
char locbuf[4];
|
||||||
|
|
||||||
|
hts_init_htsblk(&r);
|
||||||
|
r.statuscode = 200;
|
||||||
|
r.size = (LLint) INT_MAX + 1;
|
||||||
|
strcpybuff(r.msg, "OK");
|
||||||
|
strcpybuff(r.contenttype, "application/octet-stream");
|
||||||
|
locbuf[0] = '\0';
|
||||||
|
r.location = locbuf;
|
||||||
|
r.is_write = (short int) is_write;
|
||||||
|
cache_add(opt, cache, &r, "example.com", fil, "example.com/big.bin", 1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read back `entryname`: extra field (cached headers) and body. Returns the
|
||||||
|
body length, or -1 if the entry is absent or unreadable. */
|
||||||
|
static int writefail_read_entry(const char *path, const char *entryname,
|
||||||
|
char *extra, size_t extralen, char *body,
|
||||||
|
size_t bodylen) {
|
||||||
|
unzFile z = unzOpen(path);
|
||||||
|
int n = -1;
|
||||||
|
|
||||||
|
if (z == NULL)
|
||||||
|
return -1;
|
||||||
|
if (unzLocateFile(z, entryname, 1) == UNZ_OK &&
|
||||||
|
unzOpenCurrentFile(z) == UNZ_OK) {
|
||||||
|
const int elen = unzGetLocalExtrafield(z, extra, (unsigned) (extralen - 1));
|
||||||
|
|
||||||
|
if (elen >= 0) {
|
||||||
|
extra[elen] = '\0';
|
||||||
|
n = unzReadCurrentFile(z, body, (unsigned) bodylen);
|
||||||
|
}
|
||||||
|
unzCloseCurrentFile(z);
|
||||||
|
}
|
||||||
|
unzClose(z);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache write-failure policy (#174/#219): fatal errno or a failure streak
|
||||||
|
stops the mirror (exit_xh=-1, no crash); isolated/oversized drops the entry.
|
||||||
|
*/
|
||||||
int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
char path[HTS_URLMAXSIZE];
|
char path[HTS_URLMAXSIZE];
|
||||||
@@ -388,9 +424,8 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
gen_body(body, body_len, 1 /* incompressible */);
|
gen_body(body, body_len, 1 /* incompressible */);
|
||||||
fconcat(path, sizeof(path), dir, "/wfail.zip");
|
fconcat(path, sizeof(path), dir, "/wfail.zip");
|
||||||
|
|
||||||
/* phase 0: fail on the body write, fatal errno (ENOSPC, the disk-full
|
/* phase 0: fatal errno (ENOSPC) aborts at once; phase 1: persistent EIO
|
||||||
branch). phase 1: fail on the open, non-fatal errno (EIO, dropped-share
|
drops entries until the streak caps out, then aborts. */
|
||||||
branch). Both must abort the mirror. */
|
|
||||||
for (phase = 0; phase < 2; phase++) {
|
for (phase = 0; phase < 2; phase++) {
|
||||||
cache_back cache;
|
cache_back cache;
|
||||||
writefail_inject inj;
|
writefail_inject inj;
|
||||||
@@ -399,6 +434,7 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
inj.budget = (phase == 0) ? 4096 : 0;
|
inj.budget = (phase == 0) ? 4096 : 0;
|
||||||
inj.fail_errno = (phase == 0) ? ENOSPC : EIO;
|
inj.fail_errno = (phase == 0) ? ENOSPC : EIO;
|
||||||
inj.writes = 0;
|
inj.writes = 0;
|
||||||
|
inj.fail_once = 0;
|
||||||
memset(&cache, 0, sizeof(cache));
|
memset(&cache, 0, sizeof(cache));
|
||||||
cache.type = 1;
|
cache.type = 1;
|
||||||
cache.log = stderr;
|
cache.log = stderr;
|
||||||
@@ -412,7 +448,25 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opt->state.exit_xh = 0; /* clear; the failing write must set it to -1 */
|
opt->state.exit_xh = 0; /* clear; the failing write must set it to -1 */
|
||||||
writefail_store(opt, &cache, "/blob.bin", body, body_len);
|
if (phase == 0) {
|
||||||
|
writefail_store(opt, &cache, "/blob.bin", body, body_len);
|
||||||
|
} else {
|
||||||
|
/* the abort must land exactly on the 8th consecutive failure */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++) {
|
||||||
|
char fil[32];
|
||||||
|
|
||||||
|
snprintf(fil, sizeof(fil), "/b%d.bin", i);
|
||||||
|
writefail_store(opt, &cache, fil, body, 16);
|
||||||
|
}
|
||||||
|
if (cache.zipWriteFailed) {
|
||||||
|
fprintf(stderr, "cache-writefail: phase 1: aborted before the "
|
||||||
|
"8th consecutive failure\n");
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
writefail_store(opt, &cache, "/b7.bin", body, 16);
|
||||||
|
}
|
||||||
if (!cache.zipWriteFailed) {
|
if (!cache.zipWriteFailed) {
|
||||||
fprintf(stderr, "cache-writefail: phase %d: write error not caught\n",
|
fprintf(stderr, "cache-writefail: phase %d: write error not caught\n",
|
||||||
phase);
|
phase);
|
||||||
@@ -443,6 +497,136 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* failures with successes in between reset the streak: never aborts */
|
||||||
|
{
|
||||||
|
cache_back cache;
|
||||||
|
writefail_inject inj;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
inj.budget = (size_t) -1;
|
||||||
|
inj.fail_errno = EIO;
|
||||||
|
inj.writes = 0;
|
||||||
|
inj.fail_once = 0;
|
||||||
|
memset(&cache, 0, sizeof(cache));
|
||||||
|
cache.type = 1;
|
||||||
|
cache.log = stderr;
|
||||||
|
cache.errlog = stderr;
|
||||||
|
cache.hashtable = coucal_new(0);
|
||||||
|
cache.zipOutput = selftest_open_failing_zip(path, &inj);
|
||||||
|
opt->state.exit_xh = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
char fil[32];
|
||||||
|
|
||||||
|
inj.budget = 0; /* this store fails */
|
||||||
|
snprintf(fil, sizeof(fil), "/s%d.bin", i);
|
||||||
|
writefail_store(opt, &cache, fil, body, 16);
|
||||||
|
inj.budget = (size_t) -1; /* this one succeeds and resets the streak */
|
||||||
|
snprintf(fil, sizeof(fil), "/ok%d.bin", i);
|
||||||
|
writefail_store(opt, &cache, fil, body, 16);
|
||||||
|
}
|
||||||
|
if (cache.zipWriteFailed || opt->state.exit_xh != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"cache-writefail: scattered: non-consecutive failures aborted "
|
||||||
|
"the mirror (flagged=%d, exit_xh=%d)\n",
|
||||||
|
(int) cache.zipWriteFailed, opt->state.exit_xh);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
zipClose(cache.zipOutput, NULL);
|
||||||
|
cache.zipOutput = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* isolated failure: only that entry drops; a later sibling round-trips */
|
||||||
|
{
|
||||||
|
cache_back cache;
|
||||||
|
writefail_inject inj;
|
||||||
|
char extra[8192];
|
||||||
|
char rbody[64];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
inj.budget = 4096;
|
||||||
|
inj.fail_errno = EIO;
|
||||||
|
inj.writes = 0;
|
||||||
|
inj.fail_once = 1;
|
||||||
|
memset(&cache, 0, sizeof(cache));
|
||||||
|
cache.type = 1;
|
||||||
|
cache.log = stderr;
|
||||||
|
cache.errlog = stderr;
|
||||||
|
cache.hashtable = coucal_new(0);
|
||||||
|
cache.zipOutput = selftest_open_failing_zip(path, &inj);
|
||||||
|
opt->state.exit_xh = 0;
|
||||||
|
|
||||||
|
writefail_store(opt, &cache, "/blob.bin", body, body_len);
|
||||||
|
if (cache.zipWriteFailed || opt->state.exit_xh != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"cache-writefail: skip: isolated failure aborted the mirror "
|
||||||
|
"(flagged=%d, exit_xh=%d)\n",
|
||||||
|
(int) cache.zipWriteFailed, opt->state.exit_xh);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
writefail_store(opt, &cache, "/blob2.bin", body, 16);
|
||||||
|
zipClose(cache.zipOutput, NULL);
|
||||||
|
cache.zipOutput = NULL;
|
||||||
|
n = writefail_read_entry(path, "http://example.com/blob2.bin", extra,
|
||||||
|
sizeof(extra), rbody, sizeof(rbody));
|
||||||
|
if (n != 16 || memcmp(rbody, body, 16) != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"cache-writefail: skip: sibling entry lost after a skipped "
|
||||||
|
"entry (%d)\n",
|
||||||
|
n);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* >2GB bodies: in-memory drops the entry, on-disk degrades to headers-only */
|
||||||
|
{
|
||||||
|
cache_back cache;
|
||||||
|
writefail_inject inj;
|
||||||
|
char extra[8192];
|
||||||
|
char rbody[64];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
inj.budget = (size_t) -1; /* no injected failure */
|
||||||
|
inj.fail_errno = 0;
|
||||||
|
inj.writes = 0;
|
||||||
|
inj.fail_once = 0;
|
||||||
|
memset(&cache, 0, sizeof(cache));
|
||||||
|
cache.type = 1;
|
||||||
|
cache.log = stderr;
|
||||||
|
cache.errlog = stderr;
|
||||||
|
cache.hashtable = coucal_new(0);
|
||||||
|
cache.zipOutput = selftest_open_failing_zip(path, &inj);
|
||||||
|
opt->state.exit_xh = 0;
|
||||||
|
|
||||||
|
writefail_store_oversized(opt, &cache, "/bigmem.bin", 0 /* in-memory */);
|
||||||
|
writefail_store_oversized(opt, &cache, "/bigdisk.bin", 1 /* on-disk */);
|
||||||
|
zipClose(cache.zipOutput, NULL);
|
||||||
|
cache.zipOutput = NULL;
|
||||||
|
|
||||||
|
if (cache.zipWriteFailed || opt->state.exit_xh != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"cache-writefail: oversize: mirror aborted (flagged=%d, "
|
||||||
|
"exit_xh=%d)\n",
|
||||||
|
(int) cache.zipWriteFailed, opt->state.exit_xh);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
if (writefail_read_entry(path, "http://example.com/bigmem.bin", extra,
|
||||||
|
sizeof(extra), rbody, sizeof(rbody)) >= 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"cache-writefail: oversize: in-memory entry was stored\n");
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
n = writefail_read_entry(path, "http://example.com/bigdisk.bin", extra,
|
||||||
|
sizeof(extra), rbody, sizeof(rbody));
|
||||||
|
if (n != 0 || strstr(extra, "X-In-Cache: 0") == NULL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"cache-writefail: oversize: on-disk entry not stored "
|
||||||
|
"headers-only (%d)\n",
|
||||||
|
n);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
freet(body);
|
freet(body);
|
||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
@@ -716,3 +900,584 @@ int cache_golden_selftest(httrackp *opt, const char *dir, int regen) {
|
|||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- hts_cache_reconcile() policies -------------------------------------- */
|
||||||
|
|
||||||
|
/* All reconcile inputs/outputs, wiped between cases. */
|
||||||
|
static const char *const reconcile_files[] = {
|
||||||
|
"hts-cache/new.zip", "hts-cache/old.zip", "hts-cache/new.dat",
|
||||||
|
"hts-cache/old.dat", "hts-cache/new.ndx", "hts-cache/old.ndx",
|
||||||
|
"hts-cache/new.lst", "hts-cache/old.lst", "hts-cache/new.txt",
|
||||||
|
"hts-cache/old.txt", "hts-in_progress.lock"};
|
||||||
|
|
||||||
|
static char *reconcile_st_path(httrackp *opt, const char *name) {
|
||||||
|
return fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reconcile_wipe(httrackp *opt) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(reconcile_files) / sizeof(reconcile_files[0]); i++)
|
||||||
|
remove(reconcile_st_path(opt, reconcile_files[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a filler file of exactly `size` bytes. */
|
||||||
|
static void reconcile_put(httrackp *opt, const char *name, size_t size) {
|
||||||
|
FILE *const fp = fopen(reconcile_st_path(opt, name), "wb");
|
||||||
|
static const char filler[1024] = {'x'};
|
||||||
|
|
||||||
|
assertf(fp != NULL);
|
||||||
|
while (size > 0) {
|
||||||
|
const size_t n = size > sizeof(filler) ? sizeof(filler) : size;
|
||||||
|
|
||||||
|
assertf(fwrite(filler, 1, n, fp) == n);
|
||||||
|
size -= n;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expect `name` to weigh `size` bytes, or be absent when size == -1. */
|
||||||
|
static int reconcile_expect(httrackp *opt, const char *name, off_t size,
|
||||||
|
const char *what) {
|
||||||
|
const off_t got = fsize(reconcile_st_path(opt, name));
|
||||||
|
|
||||||
|
if (got != size) {
|
||||||
|
fprintf(stderr, "cache-reconcile: %s: %s is %d bytes, expected %d\n", what,
|
||||||
|
name, (int) got, (int) size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cache_reconcile_selftest(httrackp *opt, const char *dir) {
|
||||||
|
int failures = 0;
|
||||||
|
|
||||||
|
/* around the interrupted-run thresholds (new < 32768, old > 65536) */
|
||||||
|
static const off_t TINY = 1024, MID = 40000, SOLID = 131072;
|
||||||
|
|
||||||
|
golden_setup(opt, dir);
|
||||||
|
#ifdef _WIN32
|
||||||
|
mkdir(reconcile_st_path(opt, "hts-cache"));
|
||||||
|
#else
|
||||||
|
mkdir(reconcile_st_path(opt, "hts-cache"), HTS_PROTECT_FOLDER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* PROMOTE: a zip old generation replaces a missing new one */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.zip", SOLID, "promote-zip");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/old.zip", -1, "promote-zip");
|
||||||
|
|
||||||
|
/* PROMOTE: an existing new.zip is left alone */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.zip", TINY, "promote-zip-noop");
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/old.zip", SOLID, "promote-zip-noop");
|
||||||
|
|
||||||
|
/* PROMOTE: the removed pre-3.31 legacy pair is left alone */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/old.dat", SOLID);
|
||||||
|
reconcile_put(opt, "hts-cache/old.ndx", TINY);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.dat", -1, "promote-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.ndx", -1, "promote-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/old.dat", SOLID, "promote-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/old.ndx", TINY, "promote-dat");
|
||||||
|
|
||||||
|
/* INTERRUPTED: no lock file, no action */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.zip", TINY, "interrupted-nolock");
|
||||||
|
|
||||||
|
/* INTERRUPTED: an absent new.zip must NOT promote old.zip (fsize(-1) would
|
||||||
|
spuriously pass "< TINY"); leave the solid old generation for ROLLBACK */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-in_progress.lock", 0);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.zip", -1, "interrupted-nonew");
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/old.zip", SOLID, "interrupted-nonew");
|
||||||
|
|
||||||
|
/* INTERRUPTED: stalled tiny new.zip loses to a solid old.zip (was dead for
|
||||||
|
zip caches: the arm was gated on a legacy new.dat) */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-in_progress.lock", 0);
|
||||||
|
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.zip", SOLID, "interrupted-zip");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/old.zip", -1, "interrupted-zip");
|
||||||
|
|
||||||
|
/* INTERRUPTED: old below the confidence threshold, keep new */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-in_progress.lock", 0);
|
||||||
|
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", MID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.zip", TINY, "interrupted-smallold");
|
||||||
|
|
||||||
|
/* INTERRUPTED: new big enough to trust, keep it */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-in_progress.lock", 0);
|
||||||
|
reconcile_put(opt, "hts-cache/new.zip", MID);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.zip", MID, "interrupted-bignew");
|
||||||
|
|
||||||
|
/* INTERRUPTED: the removed pre-3.31 legacy pair is left alone */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-in_progress.lock", 0);
|
||||||
|
reconcile_put(opt, "hts-cache/new.dat", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/new.ndx", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.dat", SOLID);
|
||||||
|
reconcile_put(opt, "hts-cache/old.ndx", MID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.dat", TINY, "interrupted-dat");
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/new.ndx", TINY, "interrupted-dat");
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/old.dat", SOLID, "interrupted-dat");
|
||||||
|
failures +=
|
||||||
|
reconcile_expect(opt, "hts-cache/old.ndx", MID, "interrupted-dat");
|
||||||
|
|
||||||
|
/* ROLLBACK: the old zip generation is restored (a zip cache used to lose
|
||||||
|
its only good generation here) */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.zip", SOLID, "rollback-zip");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/old.zip", -1, "rollback-zip");
|
||||||
|
|
||||||
|
/* ROLLBACK: sidecars are restored regardless of format */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/new.lst", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.lst", MID);
|
||||||
|
reconcile_put(opt, "hts-cache/old.txt", MID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.lst", MID, "rollback-lst");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.txt", MID, "rollback-txt");
|
||||||
|
|
||||||
|
/* ROLLBACK: sidecars restored, the removed pre-3.31 pair left alone */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/new.dat", TINY);
|
||||||
|
reconcile_put(opt, "hts-cache/old.dat", SOLID);
|
||||||
|
reconcile_put(opt, "hts-cache/old.ndx", MID);
|
||||||
|
reconcile_put(opt, "hts-cache/old.lst", MID);
|
||||||
|
reconcile_put(opt, "hts-cache/old.txt", MID);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.dat", TINY, "rollback-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.ndx", -1, "rollback-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/old.dat", SOLID, "rollback-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/old.ndx", MID, "rollback-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.lst", MID, "rollback-dat");
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.txt", MID, "rollback-dat");
|
||||||
|
|
||||||
|
/* ROLLBACK: nothing to restore, the new generation stays */
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
||||||
|
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
||||||
|
failures += reconcile_expect(opt, "hts-cache/new.zip", TINY, "rollback-noop");
|
||||||
|
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The pre-3.31 .dat/.ndx import was removed: cache_init must refuse the
|
||||||
|
legacy pair, leave the files in place, and not flag an update run. */
|
||||||
|
int cache_legacy_refused_selftest(httrackp *opt, const char *dir) {
|
||||||
|
int failures = 0;
|
||||||
|
int variant;
|
||||||
|
|
||||||
|
selftest_tag = "cache-legacy";
|
||||||
|
golden_setup(opt, dir);
|
||||||
|
#ifdef _WIN32
|
||||||
|
mkdir(reconcile_st_path(opt, "hts-cache"));
|
||||||
|
#else
|
||||||
|
mkdir(reconcile_st_path(opt, "hts-cache"), HTS_PROTECT_FOLDER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* variant 0: old.dat/old.ndx (--update layout); 1: new.dat/new.ndx (ro) */
|
||||||
|
for (variant = 0; variant < 2; variant++) {
|
||||||
|
cache_back cache;
|
||||||
|
const char *const dat =
|
||||||
|
variant == 0 ? "hts-cache/old.dat" : "hts-cache/new.dat";
|
||||||
|
const char *const ndx =
|
||||||
|
variant == 0 ? "hts-cache/old.ndx" : "hts-cache/new.ndx";
|
||||||
|
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
reconcile_put(opt, dat, 4096);
|
||||||
|
reconcile_put(opt, ndx, 4096);
|
||||||
|
opt->is_update = 0;
|
||||||
|
selftest_open(&cache, opt, /*ro*/ variant == 1);
|
||||||
|
if (cache_readable(&cache)) {
|
||||||
|
printf("cache-legacy: variant %d imported a removed format\n", variant);
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
if (coucal_nitems(cache.hashtable) != 0) { /* no phantom index entries */
|
||||||
|
printf("cache-legacy: variant %d imported index entries\n", variant);
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
if (opt->is_update) {
|
||||||
|
printf("cache-legacy: variant %d flagged an update\n", variant);
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
if (fsize(reconcile_st_path(opt, dat)) != 4096 ||
|
||||||
|
fsize(reconcile_st_path(opt, ndx)) != 4096) {
|
||||||
|
printf("cache-legacy: variant %d touched the legacy files\n", variant);
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
if (cache.lst != NULL) {
|
||||||
|
fclose(cache.lst);
|
||||||
|
cache.lst = NULL;
|
||||||
|
}
|
||||||
|
if (cache.txt != NULL) {
|
||||||
|
fclose(cache.txt);
|
||||||
|
cache.txt = NULL;
|
||||||
|
}
|
||||||
|
selftest_close(&cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a healthy zip must win over stray legacy files, with no refusal */
|
||||||
|
{
|
||||||
|
cache_back cache;
|
||||||
|
const char *const body = "<html>zip wins</html>";
|
||||||
|
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
selftest_open_for_write(&cache, opt);
|
||||||
|
store_entry(opt, &cache, "example.com", "/", "example.com/index.html", 200,
|
||||||
|
"OK", "text/html", "utf-8", "", "", "", "", body, strlen(body));
|
||||||
|
selftest_close(&cache);
|
||||||
|
reconcile_put(opt, "hts-cache/old.ndx", 4096);
|
||||||
|
reconcile_put(opt, "hts-cache/old.dat", 4096);
|
||||||
|
selftest_open_for_read(&cache, opt);
|
||||||
|
if (!cache_readable(&cache)) {
|
||||||
|
printf("cache-legacy: stray legacy files shadowed the zip cache\n");
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
failures +=
|
||||||
|
check_entry(opt, &cache, "example.com", "/", 200, "OK", "text/html",
|
||||||
|
"utf-8", "", "", "", "", body, strlen(body));
|
||||||
|
if (fsize(reconcile_st_path(opt, "hts-cache/old.ndx")) != 4096 ||
|
||||||
|
fsize(reconcile_st_path(opt, "hts-cache/old.dat")) != 4096) {
|
||||||
|
printf("cache-legacy: zip-wins pass touched the legacy files\n");
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
if (cache.lst != NULL) {
|
||||||
|
fclose(cache.lst);
|
||||||
|
cache.lst = NULL;
|
||||||
|
}
|
||||||
|
if (cache.txt != NULL) {
|
||||||
|
fclose(cache.txt);
|
||||||
|
cache.txt = NULL;
|
||||||
|
}
|
||||||
|
selftest_close(&cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
reconcile_wipe(opt);
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- read-side corruption injection --------------------------------------- */
|
||||||
|
|
||||||
|
/* canary read back intact after each corruption; victim gets the byte surgery
|
||||||
|
*/
|
||||||
|
#define CORRUPT_ADR "corrupt.example.com"
|
||||||
|
static char corrupt_body_a[33 + 1];
|
||||||
|
static char corrupt_body_b[44 + 1];
|
||||||
|
|
||||||
|
/* Write a fresh two-entry cache: /canary.html then /victim.html. */
|
||||||
|
static void corrupt_build(httrackp *opt) {
|
||||||
|
cache_back cache;
|
||||||
|
|
||||||
|
memset(corrupt_body_a, 'a', sizeof(corrupt_body_a) - 1);
|
||||||
|
memset(corrupt_body_b, 'b', sizeof(corrupt_body_b) - 1);
|
||||||
|
remove(reconcile_st_path(opt, "hts-cache/new.zip"));
|
||||||
|
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
||||||
|
selftest_open_for_write(&cache, opt);
|
||||||
|
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
||||||
|
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
||||||
|
strlen(corrupt_body_a));
|
||||||
|
store_entry(opt, &cache, CORRUPT_ADR, "/victim.html", "victim.html", 200,
|
||||||
|
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_b,
|
||||||
|
strlen(corrupt_body_b));
|
||||||
|
selftest_close(&cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like corrupt_build, but the victim carries a 20-char Etag whose header line
|
||||||
|
is later overwritten with a forged oversized X-Size (same byte length). */
|
||||||
|
static void corrupt_build_etag(httrackp *opt) {
|
||||||
|
cache_back cache;
|
||||||
|
|
||||||
|
memset(corrupt_body_a, 'a', sizeof(corrupt_body_a) - 1);
|
||||||
|
memset(corrupt_body_b, 'b', sizeof(corrupt_body_b) - 1);
|
||||||
|
remove(reconcile_st_path(opt, "hts-cache/new.zip"));
|
||||||
|
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
||||||
|
selftest_open_for_write(&cache, opt);
|
||||||
|
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
||||||
|
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
||||||
|
strlen(corrupt_body_a));
|
||||||
|
store_entry(opt, &cache, CORRUPT_ADR, "/victim.html", "victim.html", 200,
|
||||||
|
"OK", "text/html", "utf-8", "", "AAAAAAAAAAAAAAAAAAAA", "", "",
|
||||||
|
corrupt_body_b, strlen(corrupt_body_b));
|
||||||
|
selftest_close(&cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like corrupt_build_etag, but the victim is headers-only (X-In-Cache: 0,
|
||||||
|
body on disk): the shape every non-html file is stored with. */
|
||||||
|
static void corrupt_build_disk(httrackp *opt) {
|
||||||
|
cache_back cache;
|
||||||
|
htsblk w;
|
||||||
|
char locw[4];
|
||||||
|
char BIGSTK save[HTS_URLMAXSIZE * 2];
|
||||||
|
char BIGSTK catbuff[HTS_URLMAXSIZE * 2];
|
||||||
|
char *path;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
memset(corrupt_body_a, 'a', sizeof(corrupt_body_a) - 1);
|
||||||
|
remove(reconcile_st_path(opt, "hts-cache/new.zip"));
|
||||||
|
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
||||||
|
/* X-Save stored verbatim: see disk_fallback_selftest */
|
||||||
|
concat(save, sizeof(save), StringBuff(opt->path_html_utf8),
|
||||||
|
CORRUPT_ADR "/victim.bin");
|
||||||
|
selftest_open_for_write(&cache, opt);
|
||||||
|
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
||||||
|
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
||||||
|
strlen(corrupt_body_a));
|
||||||
|
hts_init_htsblk(&w);
|
||||||
|
w.statuscode = 200;
|
||||||
|
w.size = (LLint) sizeof(corrupt_body_b) - 1;
|
||||||
|
strcpybuff(w.msg, "OK");
|
||||||
|
strcpybuff(w.contenttype, "application/octet-stream");
|
||||||
|
strcpybuff(w.etag, "AAAAAAAAAAAAAAAAAAAA");
|
||||||
|
locw[0] = '\0';
|
||||||
|
w.location = locw;
|
||||||
|
w.is_write = 0;
|
||||||
|
cache_add(opt, &cache, &w, CORRUPT_ADR, "/victim.bin", save,
|
||||||
|
0 /* all_in_cache */, NULL);
|
||||||
|
selftest_close(&cache);
|
||||||
|
/* the reader only checks this file exists; it never reads it here */
|
||||||
|
path = fconv(catbuff, sizeof(catbuff), save);
|
||||||
|
(void) structcheck(path);
|
||||||
|
fp = FOPEN(path, "wb");
|
||||||
|
assertf(fp != NULL);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Patch the nth of total occurrences of pat (same-length rep) in new.zip. */
|
||||||
|
static void corrupt_patch(httrackp *opt, const char *pat, size_t patlen,
|
||||||
|
const char *rep, size_t nth, size_t total) {
|
||||||
|
LLint fsz = 0;
|
||||||
|
char *data = readfile2(reconcile_st_path(opt, "hts-cache/new.zip"), &fsz);
|
||||||
|
const size_t n = (size_t) fsz;
|
||||||
|
size_t k, hits = 0, at = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
assertf(data != NULL);
|
||||||
|
for (k = 0; k + patlen <= n; k++) {
|
||||||
|
if (memcmp(data + k, pat, patlen) == 0) {
|
||||||
|
hits++;
|
||||||
|
if (hits == nth)
|
||||||
|
at = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertf(hits == total);
|
||||||
|
memcpy(data + at, rep, patlen);
|
||||||
|
fp = fopen(reconcile_st_path(opt, "hts-cache/new.zip"), "wb");
|
||||||
|
assertf(fp != NULL);
|
||||||
|
assertf(fwrite(data, 1, n, fp) == n);
|
||||||
|
fclose(fp);
|
||||||
|
freet(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Garbage the first bytes of the victim's deflated data (2nd local header). */
|
||||||
|
static void corrupt_victim_body(httrackp *opt) {
|
||||||
|
LLint fsz = 0;
|
||||||
|
char *data = readfile2(reconcile_st_path(opt, "hts-cache/new.zip"), &fsz);
|
||||||
|
const size_t n = (size_t) fsz;
|
||||||
|
size_t k, hits = 0, off = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
assertf(data != NULL);
|
||||||
|
for (k = 0; k + 4 <= n; k++) {
|
||||||
|
if (memcmp(data + k, "PK\x03\x04", 4) == 0 && ++hits == 2) {
|
||||||
|
const size_t namelen =
|
||||||
|
(unsigned char) data[k + 26] | ((unsigned char) data[k + 27] << 8);
|
||||||
|
const size_t extralen =
|
||||||
|
(unsigned char) data[k + 28] | ((unsigned char) data[k + 29] << 8);
|
||||||
|
|
||||||
|
off = k + 30 + namelen + extralen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertf(hits == 2);
|
||||||
|
assertf(off != 0 && off + 4 <= n);
|
||||||
|
memset(data + off, 0xFF, 4);
|
||||||
|
fp = fopen(reconcile_st_path(opt, "hts-cache/new.zip"), "wb");
|
||||||
|
assertf(fp != NULL);
|
||||||
|
assertf(fwrite(data, 1, n, fp) == n);
|
||||||
|
fclose(fp);
|
||||||
|
freet(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the corrupt /victim.html and, in the SAME read session, the intact
|
||||||
|
/canary.html: the victim must be rejected (wantmsg pins which path) and the
|
||||||
|
canary must still decode byte-exact, proving one bad entry never taints a
|
||||||
|
sibling read. */
|
||||||
|
static int corrupt_expect_victim_fil(httrackp *opt, const char *fil,
|
||||||
|
const char *wantmsg, const char *what) {
|
||||||
|
cache_back cache;
|
||||||
|
htsblk v, c;
|
||||||
|
char BIGSTK lv[HTS_URLMAXSIZE * 2];
|
||||||
|
char BIGSTK lc[HTS_URLMAXSIZE * 2];
|
||||||
|
int fail = 0;
|
||||||
|
|
||||||
|
selftest_open_for_read(&cache, opt);
|
||||||
|
lv[0] = lc[0] = '\0';
|
||||||
|
v = cache_readex(opt, &cache, CORRUPT_ADR, fil, "", lv, NULL, 1);
|
||||||
|
if (v.statuscode != STATUSCODE_INVALID) {
|
||||||
|
fprintf(stderr, "%s: %s: victim: statuscode is %d, expected %d\n",
|
||||||
|
selftest_tag, what, v.statuscode, STATUSCODE_INVALID);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
if (wantmsg != NULL && strcmp(v.msg, wantmsg) != 0) {
|
||||||
|
fprintf(stderr, "%s: %s: victim: msg is '%s', expected '%s'\n",
|
||||||
|
selftest_tag, what, v.msg, wantmsg);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
c = cache_readex(opt, &cache, CORRUPT_ADR, "/canary.html", "", lc, NULL, 1);
|
||||||
|
if (c.statuscode != 200 || c.adr == NULL ||
|
||||||
|
c.size != (LLint) strlen(corrupt_body_a) ||
|
||||||
|
memcmp(c.adr, corrupt_body_a, strlen(corrupt_body_a)) != 0) {
|
||||||
|
fprintf(stderr, "%s: %s: canary tainted (status %d)\n", selftest_tag, what,
|
||||||
|
c.statuscode);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
if (v.adr != NULL)
|
||||||
|
freet(v.adr);
|
||||||
|
if (c.adr != NULL)
|
||||||
|
freet(c.adr);
|
||||||
|
selftest_close(&cache);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int corrupt_expect_victim(httrackp *opt, const char *wantmsg,
|
||||||
|
const char *what) {
|
||||||
|
return corrupt_expect_victim_fil(opt, "/victim.html", wantmsg, what);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headers-only probe of the disk victim: must parse OK with the size kept. */
|
||||||
|
static int corrupt_expect_disk_header(httrackp *opt, LLint wantsize,
|
||||||
|
const char *what) {
|
||||||
|
cache_back cache;
|
||||||
|
htsblk v;
|
||||||
|
char BIGSTK lv[HTS_URLMAXSIZE * 2];
|
||||||
|
int fail = 0;
|
||||||
|
|
||||||
|
selftest_open_for_read(&cache, opt);
|
||||||
|
lv[0] = '\0';
|
||||||
|
v = cache_readex(opt, &cache, CORRUPT_ADR, "/victim.bin", NULL, lv, NULL, 1);
|
||||||
|
if (v.statuscode != 200 || v.size != wantsize) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: %s: statuscode %d size " LLintP ", expected 200/" LLintP "\n",
|
||||||
|
selftest_tag, what, v.statuscode, (LLint) v.size, wantsize);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
if (v.adr != NULL)
|
||||||
|
freet(v.adr);
|
||||||
|
selftest_close(&cache);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One zip corruption case: build, patch, then check victim+canary in-session.
|
||||||
|
*/
|
||||||
|
static int corrupt_case_zip(httrackp *opt, const char *pat, const char *rep,
|
||||||
|
size_t nth, size_t total, const char *wantmsg,
|
||||||
|
const char *what) {
|
||||||
|
corrupt_build(opt);
|
||||||
|
corrupt_patch(opt, pat, strlen(pat), rep, nth, total);
|
||||||
|
return corrupt_expect_victim(opt, wantmsg, what);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cache_corruption_selftest(httrackp *opt, const char *dir) {
|
||||||
|
int failures = 0;
|
||||||
|
|
||||||
|
selftest_tag = "cache-corrupt";
|
||||||
|
golden_setup(opt, dir);
|
||||||
|
|
||||||
|
failures +=
|
||||||
|
corrupt_case_zip(opt, "X-Size: 44", "X-Size: 99", 1, 1,
|
||||||
|
"Cache Read Error : Read Data", "oversized X-Size");
|
||||||
|
failures +=
|
||||||
|
corrupt_case_zip(opt, "X-Size: 44", "X-Size: -4", 1, 1,
|
||||||
|
"Cache Read Error : Bad Size", "negative X-Size");
|
||||||
|
/* both entries carry the line; the victim's is the second */
|
||||||
|
failures += corrupt_case_zip(opt, "X-In-Cache: 1", "X-In-Cache: 0", 2, 2,
|
||||||
|
"Previous cache file not found (empty filename)",
|
||||||
|
"blanked X-In-Cache");
|
||||||
|
/* smashed local file header: the entry is dropped at index load */
|
||||||
|
failures +=
|
||||||
|
corrupt_case_zip(opt, "PK\x03\x04", "XK\x03\x04", 2, 2,
|
||||||
|
"File Cache Entry Not Found", "smashed local header");
|
||||||
|
|
||||||
|
corrupt_build(opt);
|
||||||
|
corrupt_victim_body(opt);
|
||||||
|
failures += corrupt_expect_victim(opt, "Cache Read Error : Read Data",
|
||||||
|
"garbled deflate stream");
|
||||||
|
|
||||||
|
/* An X-Size above INT_MAX is positive as int64 (slips a bare sign check) but
|
||||||
|
truncates negative in the (int) cast the malloc uses: a wraparound alloc.
|
||||||
|
cache_add asserts size fits an int, so such a value only reaches the reader
|
||||||
|
from a corrupt/foreign cache; inject it by overwriting the victim's long
|
||||||
|
Etag line with a same-length forged X-Size line (the parser keeps the last
|
||||||
|
X-Size it sees), keeping the zip byte-length and offsets intact. */
|
||||||
|
corrupt_build_etag(opt);
|
||||||
|
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
||||||
|
"X-Size: 2147483648AAAAAAAA", 1, 1);
|
||||||
|
failures += corrupt_expect_victim(opt, "Cache Read Error : Bad Size",
|
||||||
|
"X-Size above INT_MAX");
|
||||||
|
|
||||||
|
/* A headers-only entry (X-In-Cache: 0) may carry an X-Size >= INT_MAX: that
|
||||||
|
is how every >2GB non-html file is stored. It must survive a header probe
|
||||||
|
(or every update re-fetches the file); an in-memory read still rejects. */
|
||||||
|
corrupt_build_disk(opt);
|
||||||
|
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
||||||
|
"X-Size: 2147483648AAAAAAAA", 1, 1);
|
||||||
|
failures += corrupt_expect_disk_header(opt, (LLint) 2147483648LL,
|
||||||
|
"headers-only X-Size above INT_MAX");
|
||||||
|
failures += corrupt_expect_victim_fil(opt, "/victim.bin",
|
||||||
|
"Cache Read Error : Bad Size",
|
||||||
|
"in-memory X-Size above INT_MAX");
|
||||||
|
|
||||||
|
/* exactly INT_MAX pins the >= boundary: (int) r.size + 1 would overflow */
|
||||||
|
corrupt_build_disk(opt);
|
||||||
|
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
||||||
|
"X-Size: 2147483647AAAAAAAA", 1, 1);
|
||||||
|
failures += corrupt_expect_victim_fil(opt, "/victim.bin",
|
||||||
|
"Cache Read Error : Bad Size",
|
||||||
|
"in-memory X-Size at INT_MAX");
|
||||||
|
|
||||||
|
/* the negative check must stay global, headers-only included */
|
||||||
|
corrupt_build_disk(opt);
|
||||||
|
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
||||||
|
"X-Size: -2147483648AAAAAAA", 1, 1);
|
||||||
|
failures += corrupt_expect_victim_fil(opt, "/victim.bin",
|
||||||
|
"Cache Read Error : Bad Size",
|
||||||
|
"headers-only negative X-Size");
|
||||||
|
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,10 +52,23 @@ int cache_selftests(httrackp *opt, const char *dir);
|
|||||||
committed file, never by the test). Returns the failed-check count. */
|
committed file, never by the test). Returns the failed-check count. */
|
||||||
int cache_golden_selftest(httrackp *opt, const char *dir, int regen);
|
int cache_golden_selftest(httrackp *opt, const char *dir, int regen);
|
||||||
|
|
||||||
/* #174/#219: assert a failing cache write aborts the mirror cleanly instead of
|
/* Cache write-failure policy (#174/#219): abort on fatal errno or a streak,
|
||||||
crashing. Returns the failed-check count. */
|
drop just the entry otherwise. Returns the failed-check count. */
|
||||||
int cache_write_failure_selftest(httrackp *opt, const char *dir);
|
int cache_write_failure_selftest(httrackp *opt, const char *dir);
|
||||||
|
|
||||||
|
/* Exercise the hts_cache_reconcile() generation policies on file fixtures
|
||||||
|
under <dir>. Returns the failed-check count. */
|
||||||
|
int cache_reconcile_selftest(httrackp *opt, const char *dir);
|
||||||
|
|
||||||
|
/* Verify cache_init refuses a pre-3.31 .dat/.ndx cache without touching it.
|
||||||
|
Returns the number of failed checks (0 = pass). */
|
||||||
|
int cache_legacy_refused_selftest(httrackp *opt, const char *dir);
|
||||||
|
|
||||||
|
/* Inject read-side corruption (zip byte surgery: bad size, header, deflate)
|
||||||
|
under <dir> and assert every case degrades to STATUSCODE_INVALID without
|
||||||
|
tainting a sibling entry. */
|
||||||
|
int cache_corruption_selftest(httrackp *opt, const char *dir);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -197,7 +197,6 @@ HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
|
|||||||
htsblk blkretour;
|
htsblk blkretour;
|
||||||
|
|
||||||
hts_init_htsblk(&blkretour);
|
hts_init_htsblk(&blkretour);
|
||||||
//memset(&blkretour, 0, sizeof(htsblk)); // effacer
|
|
||||||
blkretour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
blkretour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
||||||
// Lire en têtes restants
|
// Lire en têtes restants
|
||||||
sprintf(data, "%s %s %s\r\n", method, af.fil, protocol);
|
sprintf(data, "%s %s %s\r\n", method, af.fil, protocol);
|
||||||
@@ -207,8 +206,8 @@ HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
|
|||||||
strlcatbuff(data, line, CATCH_URL_DATA_SIZE);
|
strlcatbuff(data, line, CATCH_URL_DATA_SIZE);
|
||||||
strlcatbuff(data, "\r\n", CATCH_URL_DATA_SIZE);
|
strlcatbuff(data, "\r\n", CATCH_URL_DATA_SIZE);
|
||||||
}
|
}
|
||||||
// CR/LF final de l'en tête inutile car déja placé via la ligne vide juste au dessus
|
// CR/LF final de l'en tête inutile car déja placé via la ligne vide
|
||||||
//strcatbuff(data,"\r\n");
|
// juste au dessus
|
||||||
if (blkretour.totalsize > 0) {
|
if (blkretour.totalsize > 0) {
|
||||||
int len = (int) min(blkretour.totalsize, 32000);
|
int len = (int) min(blkretour.totalsize, 32000);
|
||||||
int pos = (int) strlen(data);
|
int pos = (int) strlen(data);
|
||||||
|
|||||||
309
src/htscharset.c
309
src/htscharset.c
@@ -84,7 +84,7 @@ static int hts_equalsAlphanum(const char *a, const char *b) {
|
|||||||
|
|
||||||
/* Copy the memory region [s .. s + size - 1 ] as a \0-terminated string. */
|
/* Copy the memory region [s .. s + size - 1 ] as a \0-terminated string. */
|
||||||
static char *hts_stringMemCopy(const char *s, size_t size) {
|
static char *hts_stringMemCopy(const char *s, size_t size) {
|
||||||
char *dest = malloc(size + 1);
|
char *dest = malloct(size + 1);
|
||||||
|
|
||||||
if (dest != NULL) {
|
if (dest != NULL) {
|
||||||
memcpy(dest, s, size);
|
memcpy(dest, s, size);
|
||||||
@@ -549,42 +549,6 @@ char *hts_convertStringFromUTF8(const char *s, size_t size, const char *charset)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HTS_STATIC char *hts_getCharsetFromContentType(const char *mime) {
|
|
||||||
/* text/html; charset=utf-8 */
|
|
||||||
const char *const charset = "charset";
|
|
||||||
char *pos = strstr(mime, charset);
|
|
||||||
|
|
||||||
if (pos != NULL) {
|
|
||||||
/* Skip spaces */
|
|
||||||
int eq = 0;
|
|
||||||
|
|
||||||
for(pos += strlen(charset);
|
|
||||||
*pos == ' ' || *pos == '=' || *pos == '"' || *pos == '\''; pos++) {
|
|
||||||
if (*pos == '=') {
|
|
||||||
eq = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (eq == 1) {
|
|
||||||
int len;
|
|
||||||
|
|
||||||
for(len = 0;
|
|
||||||
pos[len] == ' ' || pos[len] == ';' || pos[len] == '"' || *pos == '\'';
|
|
||||||
pos++) ;
|
|
||||||
if (len != 0) {
|
|
||||||
char *const s = malloc(len + 1);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < len; i++) {
|
|
||||||
s[i] = pos[i];
|
|
||||||
}
|
|
||||||
s[len] = '\0';
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define strcasecmp(a,b) stricmp(a,b)
|
#define strcasecmp(a,b) stricmp(a,b)
|
||||||
#define strncasecmp(a,b,n) strnicmp(a,b,n)
|
#define strncasecmp(a,b,n) strnicmp(a,b,n)
|
||||||
@@ -644,58 +608,106 @@ int hts_isCharsetUTF8(const char *charset) {
|
|||||||
|| strcasecmp(charset, "utf8") == 0 );
|
|| strcasecmp(charset, "utf8") == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Extract X from a "text/html; charset=X" content= attribute value. */
|
||||||
|
static char *charset_from_content(const char *s, size_t len) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i + 7 < len; i++) {
|
||||||
|
if ((i == 0 || is_space(s[i - 1]) || s[i - 1] == ';') &&
|
||||||
|
strncasecmp(&s[i], "charset", 7) == 0 && is_space_or_equal(s[i + 7])) {
|
||||||
|
size_t j, val;
|
||||||
|
|
||||||
|
for (j = i + 7; j < len && is_space_or_equal_or_quote(s[j]); j++)
|
||||||
|
;
|
||||||
|
for (val = j; j < len && s[j] != '"' && s[j] != '\'' && s[j] != ';' &&
|
||||||
|
!is_space(s[j]);
|
||||||
|
j++)
|
||||||
|
;
|
||||||
|
if (j != val) {
|
||||||
|
return hts_stringMemCopy(&s[val], j - val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
char *hts_getCharsetFromMeta(const char *html, size_t size) {
|
char *hts_getCharsetFromMeta(const char *html, size_t size) {
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
/* <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8" > */
|
/* HTML5 <meta charset=X> or legacy
|
||||||
for(i = 0; i < size; i++) {
|
<meta http-equiv="Content-Type" content="text/html; charset=X">,
|
||||||
if (html[i] == '<' && strncasecmp(&html[i + 1], "meta", 4) == 0
|
attributes in any order; first resolvable tag wins. */
|
||||||
&& is_space(html[i + 5])) {
|
for (i = 0; i + 6 < size; i++) {
|
||||||
/* Skip spaces */
|
size_t j;
|
||||||
for(i += 5; is_space(html[i]); i++) ;
|
const char *equiv = NULL, *content = NULL;
|
||||||
if (strncasecmp(&html[i], "HTTP-EQUIV", 10) == 0
|
size_t equiv_len = 0, content_len = 0;
|
||||||
&& is_space_or_equal(html[i + 10])) {
|
|
||||||
for(i += 10; is_space_or_equal_or_quote(html[i]); i++) ;
|
|
||||||
if (strncasecmp(&html[i], "CONTENT-TYPE", 12) == 0) {
|
|
||||||
for(i += 12; is_space_or_equal_or_quote(html[i]); i++) ;
|
|
||||||
if (strncasecmp(&html[i], "CONTENT", 7) == 0
|
|
||||||
&& is_space_or_equal(html[i + 7])) {
|
|
||||||
for(i += 7; is_space_or_equal_or_quote(html[i]); i++) ;
|
|
||||||
/* Skip content-type */
|
|
||||||
for(;
|
|
||||||
i < size && html[i] != ';' && html[i] != '"' && html[i] != '\'';
|
|
||||||
i++) ;
|
|
||||||
/* Expect charset attribute here */
|
|
||||||
if (html[i] == ';') {
|
|
||||||
for(i++; is_space(html[i]); i++) ;
|
|
||||||
/* Look for charset */
|
|
||||||
if (strncasecmp(&html[i], "charset", 7) == 0
|
|
||||||
&& is_space_or_equal(html[i + 7])) {
|
|
||||||
int len;
|
|
||||||
|
|
||||||
for(i += 7; is_space_or_equal(html[i]) || html[i] == '\'';
|
if (html[i] != '<' || strncasecmp(&html[i + 1], "meta", 4) != 0 ||
|
||||||
i++) ;
|
!is_space(html[i + 5])) {
|
||||||
/* Charset */
|
continue;
|
||||||
for(len = 0;
|
}
|
||||||
i + len < size && html[i + len] != '"'
|
/* Attribute scan, strictly bounded by size. */
|
||||||
&& html[i + len] != '\'' && html[i + len] != ' '; len++) ;
|
for (j = i + 6; j < size && html[j] != '>';) {
|
||||||
/* No error ? */
|
size_t name, name_len, val = 0, val_len = 0;
|
||||||
if (len != 0 && i < size) {
|
|
||||||
char *const s = malloc(len + 1);
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for(j = 0; j < len; j++) {
|
if (is_space(html[j]) || html[j] == '/') {
|
||||||
s[j] = html[i + j];
|
j++;
|
||||||
}
|
continue;
|
||||||
s[len] = '\0';
|
}
|
||||||
return s;
|
for (name = j; j < size && html[j] != '=' && html[j] != '>' &&
|
||||||
}
|
html[j] != '/' && !is_space(html[j]);
|
||||||
}
|
j++)
|
||||||
}
|
;
|
||||||
|
name_len = j - name;
|
||||||
|
for (; j < size && is_space(html[j]); j++)
|
||||||
|
;
|
||||||
|
if (j < size && html[j] == '=') {
|
||||||
|
for (j++; j < size && is_space(html[j]); j++)
|
||||||
|
;
|
||||||
|
if (j < size && (html[j] == '"' || html[j] == '\'')) {
|
||||||
|
const char quote = html[j++];
|
||||||
|
|
||||||
|
for (val = j; j < size && html[j] != quote; j++)
|
||||||
|
;
|
||||||
|
if (j >= size) /* unterminated quote: drop the tag */
|
||||||
|
break;
|
||||||
|
val_len = j++ - val;
|
||||||
|
} else {
|
||||||
|
/* unquoted: ends at whitespace or '>' only (HTML5 prescan); '/'
|
||||||
|
belongs to the value except as the tail of a self-close */
|
||||||
|
for (val = j; j < size && !is_space(html[j]) && html[j] != '>'; j++)
|
||||||
|
;
|
||||||
|
val_len = j - val;
|
||||||
|
if (val_len != 0 && j < size && html[j] == '>' &&
|
||||||
|
html[val + val_len - 1] == '/') {
|
||||||
|
val_len--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* first occurrence of each attribute wins, as in browsers */
|
||||||
|
if (val_len != 0) {
|
||||||
|
if (name_len == 7 && strncasecmp(&html[name], "charset", 7) == 0) {
|
||||||
|
return hts_stringMemCopy(&html[val], val_len);
|
||||||
|
} else if (equiv == NULL && name_len == 10 &&
|
||||||
|
strncasecmp(&html[name], "http-equiv", 10) == 0) {
|
||||||
|
equiv = &html[val];
|
||||||
|
equiv_len = val_len;
|
||||||
|
} else if (content == NULL && name_len == 7 &&
|
||||||
|
strncasecmp(&html[name], "content", 7) == 0) {
|
||||||
|
content = &html[val];
|
||||||
|
content_len = val_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (equiv_len == 12 && strncasecmp(equiv, "content-type", 12) == 0 &&
|
||||||
|
content != NULL) {
|
||||||
|
char *const s = charset_from_content(content, content_len);
|
||||||
|
|
||||||
|
if (s != NULL) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = j;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -841,71 +853,6 @@ static unsigned int nlz8(unsigned char x) {
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/* Sample. */
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
int i;
|
|
||||||
int hex = 0;
|
|
||||||
|
|
||||||
#define READ_INT(DEST) \
|
|
||||||
( ( !hex && sscanf(argv[i], "%d", &(DEST)) == 1) \
|
|
||||||
|| (hex && sscanf(argv[i], "%x", &(DEST)) == 1 ) )
|
|
||||||
|
|
||||||
for(i = 1 ; i < argc ; i++) {
|
|
||||||
unsigned int uc, from, to;
|
|
||||||
|
|
||||||
if (strcmp(argv[i], "--hex") == 0) {
|
|
||||||
hex = 1;
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "--decimal") == 0) {
|
|
||||||
hex = 0;
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "--decode") == 0) {
|
|
||||||
#define RD fgetc_unlocked(stdin)
|
|
||||||
#define WR(C) do { \
|
|
||||||
if (C != -1) { \
|
|
||||||
printf("%04x\n", C); \
|
|
||||||
} else if (!feof(stdin)) { \
|
|
||||||
fprintf(stderr, "read error\n"); \
|
|
||||||
exit(EXIT_FAILURE); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
while(!feof(stdin)) {
|
|
||||||
READ_UNICODE(RD, WR);
|
|
||||||
}
|
|
||||||
#undef RD
|
|
||||||
#undef WR
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "-range") == 0
|
|
||||||
&& i + 2 < argc
|
|
||||||
&& (++i, 1)
|
|
||||||
&& READ_INT(from)
|
|
||||||
&& (++i, 1)
|
|
||||||
&& READ_INT(to)
|
|
||||||
) {
|
|
||||||
unsigned int i;
|
|
||||||
for(i = from ; i < to ; i++) {
|
|
||||||
#define EM(C) fputc_unlocked(C, stdout)
|
|
||||||
EMIT_UNICODE(i, EM);
|
|
||||||
#undef EM
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (READ_INT(uc)) {
|
|
||||||
#define EM(C) fputc_unlocked(C, stdout)
|
|
||||||
EMIT_UNICODE(uc, EM);
|
|
||||||
#undef EM
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* IDNA helpers. */
|
/* IDNA helpers. */
|
||||||
#undef ADD_BYTE
|
#undef ADD_BYTE
|
||||||
#undef INCREASE_CAPA
|
#undef INCREASE_CAPA
|
||||||
@@ -975,19 +922,19 @@ char *hts_convertStringUTF8ToIDNA(const char *s, size_t size) {
|
|||||||
/* Reader: can read bytes up to j */
|
/* Reader: can read bytes up to j */
|
||||||
#define RD ( utfSeq < j ? segData[utfSeq++] : -1 )
|
#define RD ( utfSeq < j ? segData[utfSeq++] : -1 )
|
||||||
|
|
||||||
/* Writer: upon error, return FFFD (replacement character) */
|
/* Writer: a malformed sequence abandons the encode (NULL) */
|
||||||
#define WR(C) do { \
|
#define WR(C) \
|
||||||
if ((C) != -1) { \
|
do { \
|
||||||
/* copy character */ \
|
if ((C) != -1) { \
|
||||||
assertf(segOutputSize < segSize); \
|
/* copy character */ \
|
||||||
segInt[segOutputSize++] = (C); \
|
assertf(segOutputSize < segSize); \
|
||||||
} \
|
segInt[segOutputSize++] = (C); \
|
||||||
/* In case of error, abort. */ \
|
} else { \
|
||||||
else { \
|
freet(segInt); \
|
||||||
FREE_BUFFER(); \
|
FREE_BUFFER(); \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/* Read/Write Unicode character. */
|
/* Read/Write Unicode character. */
|
||||||
READ_UNICODE(RD, WR);
|
READ_UNICODE(RD, WR);
|
||||||
@@ -1205,17 +1152,45 @@ int hts_isStringUTF8(const char *s, size_t size) {
|
|||||||
const unsigned char *const data = (const unsigned char*) s;
|
const unsigned char *const data = (const unsigned char*) s;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
/* Strict RFC 3629: reject overlongs, surrogates, > U+10FFFF, 5/6-byte. */
|
||||||
for(i = 0 ; i < size ; ) {
|
for(i = 0 ; i < size ; ) {
|
||||||
/* Reader: can read bytes up to j */
|
const unsigned char c = data[i];
|
||||||
#define RD ( i < size ? data[i++] : -1 )
|
size_t len, k;
|
||||||
|
hts_UCS4 uc, min;
|
||||||
|
|
||||||
/* Writer: upon error, return FFFD (replacement character) */
|
if (c < 0x80) {
|
||||||
#define WR(C) if ((C) == -1) { return 0; }
|
i++;
|
||||||
|
continue;
|
||||||
|
} else if (c >= 0xc2 && c <= 0xdf) {
|
||||||
|
len = 2;
|
||||||
|
min = 0x80;
|
||||||
|
uc = c & 0x1f;
|
||||||
|
} else if (c >= 0xe0 && c <= 0xef) {
|
||||||
|
len = 3;
|
||||||
|
min = 0x800;
|
||||||
|
uc = c & 0x0f;
|
||||||
|
} else if (c >= 0xf0 && c <= 0xf4) {
|
||||||
|
len = 4;
|
||||||
|
min = 0x10000;
|
||||||
|
uc = c & 0x07;
|
||||||
|
} else { /* continuation byte, overlong C0/C1, or F5..FF lead */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (size - i < len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (k = 1; k < len; k++) {
|
||||||
|
const unsigned char cc = data[i + k];
|
||||||
|
|
||||||
/* Read Unicode character. */
|
if ((cc & 0xc0) != 0x80) {
|
||||||
READ_UNICODE(RD, WR);
|
return 0;
|
||||||
#undef RD
|
}
|
||||||
#undef WR
|
uc = (uc << 6) | (cc & 0x3f);
|
||||||
|
}
|
||||||
|
if (uc < min || uc > 0x10FFFF || (uc >= 0xD800 && uc <= 0xDFFF)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
i += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ extern char *hts_convertStringIDNAToUTF8(const char *s, size_t size);
|
|||||||
extern int hts_isStringIDNA(const char *s, size_t size);
|
extern int hts_isStringIDNA(const char *s, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the charset from the HTML buffer "html"
|
* Extract the <meta> charset from the HTML buffer "html" (HTML5 charset= or
|
||||||
|
* legacy http-equiv form). Returns a malloc'ed string, or NULL if none.
|
||||||
**/
|
**/
|
||||||
extern char *hts_getCharsetFromMeta(const char *html, size_t size);
|
extern char *hts_getCharsetFromMeta(const char *html, size_t size);
|
||||||
|
|
||||||
@@ -86,7 +87,8 @@ extern char *hts_getCharsetFromMeta(const char *html, size_t size);
|
|||||||
extern int hts_isStringAscii(const char *s, size_t size);
|
extern int hts_isStringAscii(const char *s, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the given string an UTF-8 string ?
|
* Is the given string valid UTF-8 ? Strict RFC 3629: overlong forms,
|
||||||
|
* surrogates, codepoints above U+10FFFF and 5/6-byte sequences are rejected.
|
||||||
**/
|
**/
|
||||||
extern int hts_isStringUTF8(const char *s, size_t size);
|
extern int hts_isStringUTF8(const char *s, size_t size);
|
||||||
|
|
||||||
|
|||||||
366
src/htscodec.c
Normal file
366
src/htscodec.c
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* File: HTTP content codings (gzip/deflate, brotli, zstd) */
|
||||||
|
/* Author: Xavier Roche */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* Internal engine bytecode */
|
||||||
|
#define HTS_INTERNAL_BYTECODE
|
||||||
|
|
||||||
|
#include "htsbase.h"
|
||||||
|
#include "htscore.h"
|
||||||
|
#include "htscodec.h"
|
||||||
|
#include "htszlib.h"
|
||||||
|
|
||||||
|
#if HTS_USEBROTLI
|
||||||
|
#include <brotli/decode.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HTS_USEZSTD
|
||||||
|
#include <zstd.h>
|
||||||
|
/* 8 MB, the window an HTTP zstd decoder must honor (RFC 9659); libzstd
|
||||||
|
defaults to 128 MB. */
|
||||||
|
#define HTS_ZSTD_WINDOWLOG_MAX 23
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Decoded-size budget, bounding a bomb: brotli and zstd reach a million to one.
|
||||||
|
Deflate cannot pass 1032x, so it only meets this at the 2 GiB ceiling. */
|
||||||
|
#define HTS_CODEC_MAX_RATIO 4096
|
||||||
|
#define HTS_CODEC_MIN_MAXOUT (1024 * 1024)
|
||||||
|
|
||||||
|
LLint hts_codec_maxout(LLint in_size) {
|
||||||
|
LLint maxout;
|
||||||
|
|
||||||
|
if (in_size <= 0 || in_size > INT_MAX / HTS_CODEC_MAX_RATIO)
|
||||||
|
maxout = INT_MAX;
|
||||||
|
else
|
||||||
|
maxout = in_size * HTS_CODEC_MAX_RATIO;
|
||||||
|
if (maxout < HTS_CODEC_MIN_MAXOUT)
|
||||||
|
maxout = HTS_CODEC_MIN_MAXOUT;
|
||||||
|
return maxout;
|
||||||
|
}
|
||||||
|
|
||||||
|
hts_codec hts_codec_parse(const char *encoding) {
|
||||||
|
if (encoding == NULL || encoding[0] == '\0' ||
|
||||||
|
strfield2(encoding, "identity"))
|
||||||
|
return HTS_CODEC_IDENTITY;
|
||||||
|
if (strfield2(encoding, "gzip") || strfield2(encoding, "x-gzip") ||
|
||||||
|
strfield2(encoding, "deflate") || strfield2(encoding, "x-deflate"))
|
||||||
|
return HTS_USEZLIB ? HTS_CODEC_DEFLATE : HTS_CODEC_UNSUPPORTED;
|
||||||
|
if (strfield2(encoding, "br"))
|
||||||
|
return HTS_USEBROTLI ? HTS_CODEC_BROTLI : HTS_CODEC_UNSUPPORTED;
|
||||||
|
if (strfield2(encoding, "zstd"))
|
||||||
|
return HTS_USEZSTD ? HTS_CODEC_ZSTD : HTS_CODEC_UNSUPPORTED;
|
||||||
|
if (strfield2(encoding, "compress") || strfield2(encoding, "x-compress"))
|
||||||
|
return HTS_CODEC_UNSUPPORTED; /* LZW: never advertised, no decoder here */
|
||||||
|
/* Not a coding at all: broken servers put charsets and the like here, and
|
||||||
|
the plain body they sent must survive it. */
|
||||||
|
return HTS_CODEC_IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HTS_USEBROTLI
|
||||||
|
#define HTS_AE_BROTLI ", br"
|
||||||
|
#else
|
||||||
|
#define HTS_AE_BROTLI ""
|
||||||
|
#endif
|
||||||
|
#if HTS_USEZSTD
|
||||||
|
#define HTS_AE_ZSTD ", zstd"
|
||||||
|
#else
|
||||||
|
#define HTS_AE_ZSTD ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *hts_acceptencoding(hts_boolean compressible, hts_boolean secure) {
|
||||||
|
if (!compressible)
|
||||||
|
return "identity";
|
||||||
|
#if HTS_USEZLIB
|
||||||
|
/* br and zstd over TLS only, as browsers do: a cleartext intermediary that
|
||||||
|
rewrites a coding it can not read would corrupt the mirror. */
|
||||||
|
if (secure)
|
||||||
|
return "gzip, deflate" HTS_AE_BROTLI HTS_AE_ZSTD ", identity;q=0.9";
|
||||||
|
return "gzip, deflate, identity;q=0.9";
|
||||||
|
#else
|
||||||
|
(void) secure;
|
||||||
|
return "identity";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
hts_boolean hts_codec_is_archive_ext(hts_codec codec, const char *ext) {
|
||||||
|
if (ext == NULL || ext[0] == '\0')
|
||||||
|
return HTS_FALSE;
|
||||||
|
switch (codec) {
|
||||||
|
case HTS_CODEC_DEFLATE:
|
||||||
|
return strfield2(ext, "gz") || strfield2(ext, "tgz") ? HTS_TRUE : HTS_FALSE;
|
||||||
|
case HTS_CODEC_BROTLI:
|
||||||
|
return strfield2(ext, "br") ? HTS_TRUE : HTS_FALSE;
|
||||||
|
case HTS_CODEC_ZSTD:
|
||||||
|
return strfield2(ext, "zst") || strfield2(ext, "tzst") ? HTS_TRUE
|
||||||
|
: HTS_FALSE;
|
||||||
|
default:
|
||||||
|
return HTS_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HTS_USEBROTLI || HTS_USEZSTD
|
||||||
|
/* Append produced bytes to out under the decoded-size budget, advancing *total.
|
||||||
|
HTS_FALSE on a short write or once the budget is exceeded (a bomb); the
|
||||||
|
over-budget bytes are never written. */
|
||||||
|
static hts_boolean codec_sink(FILE *out, const void *buf, size_t produced,
|
||||||
|
LLint *total, LLint maxout) {
|
||||||
|
if (produced == 0)
|
||||||
|
return HTS_TRUE;
|
||||||
|
*total += (LLint) produced;
|
||||||
|
if (*total > maxout)
|
||||||
|
return HTS_FALSE;
|
||||||
|
return fwrite(buf, 1, produced, out) == produced ? HTS_TRUE : HTS_FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HTS_USEBROTLI
|
||||||
|
static int codec_unpack_brotli(FILE *in, FILE *out, LLint maxout) {
|
||||||
|
BrotliDecoderState *const state =
|
||||||
|
BrotliDecoderCreateInstance(NULL, NULL, NULL);
|
||||||
|
hts_boolean ok = HTS_TRUE, done = HTS_FALSE;
|
||||||
|
LLint total = 0;
|
||||||
|
|
||||||
|
if (state == NULL)
|
||||||
|
return -1;
|
||||||
|
while (ok && !done) {
|
||||||
|
unsigned char BIGSTK inbuf[8192];
|
||||||
|
size_t avail_in = fread(inbuf, 1, sizeof(inbuf), in);
|
||||||
|
const uint8_t *next_in = inbuf;
|
||||||
|
|
||||||
|
if (avail_in == 0)
|
||||||
|
break; /* EOF; a stream still hungry for input is truncated */
|
||||||
|
for (;;) {
|
||||||
|
unsigned char BIGSTK outbuf[8192];
|
||||||
|
uint8_t *next_out = outbuf;
|
||||||
|
size_t avail_out = sizeof(outbuf);
|
||||||
|
size_t produced;
|
||||||
|
BrotliDecoderResult res;
|
||||||
|
|
||||||
|
res = BrotliDecoderDecompressStream(state, &avail_in, &next_in,
|
||||||
|
&avail_out, &next_out, NULL);
|
||||||
|
produced = sizeof(outbuf) - avail_out;
|
||||||
|
if (!codec_sink(out, outbuf, produced, &total, maxout)) {
|
||||||
|
ok = HTS_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (res == BROTLI_DECODER_RESULT_ERROR) {
|
||||||
|
ok = HTS_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (res == BROTLI_DECODER_RESULT_SUCCESS) {
|
||||||
|
done = HTS_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ferror(in))
|
||||||
|
ok = HTS_FALSE;
|
||||||
|
}
|
||||||
|
BrotliDecoderDestroyInstance(state);
|
||||||
|
return (ok && done && !ferror(in)) ? (int) total : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t codec_head_brotli(const void *in, size_t in_len, void *out,
|
||||||
|
size_t out_len) {
|
||||||
|
BrotliDecoderState *const state =
|
||||||
|
BrotliDecoderCreateInstance(NULL, NULL, NULL);
|
||||||
|
const uint8_t *next_in = (const uint8_t *) in;
|
||||||
|
uint8_t *next_out = (uint8_t *) out;
|
||||||
|
size_t avail_in = in_len, avail_out = out_len;
|
||||||
|
BrotliDecoderResult res;
|
||||||
|
|
||||||
|
if (state == NULL)
|
||||||
|
return 0;
|
||||||
|
res = BrotliDecoderDecompressStream(state, &avail_in, &next_in, &avail_out,
|
||||||
|
&next_out, NULL);
|
||||||
|
BrotliDecoderDestroyInstance(state);
|
||||||
|
return (res != BROTLI_DECODER_RESULT_ERROR) ? out_len - avail_out : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HTS_USEZSTD
|
||||||
|
static int codec_unpack_zstd(FILE *in, FILE *out, LLint maxout) {
|
||||||
|
ZSTD_DStream *const zds = ZSTD_createDStream();
|
||||||
|
hts_boolean ok = HTS_TRUE, eof = HTS_FALSE;
|
||||||
|
size_t zret = 1; /* 0 once a frame is fully flushed */
|
||||||
|
LLint total = 0;
|
||||||
|
|
||||||
|
if (zds == NULL)
|
||||||
|
return -1;
|
||||||
|
if (ZSTD_isError(ZSTD_DCtx_setParameter(zds, ZSTD_d_windowLogMax,
|
||||||
|
HTS_ZSTD_WINDOWLOG_MAX))) {
|
||||||
|
ZSTD_freeDStream(zds);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while (ok && !eof) {
|
||||||
|
unsigned char BIGSTK inbuf[8192];
|
||||||
|
ZSTD_inBuffer input;
|
||||||
|
|
||||||
|
input.src = inbuf;
|
||||||
|
input.size = fread(inbuf, 1, sizeof(inbuf), in);
|
||||||
|
input.pos = 0;
|
||||||
|
if (input.size == 0) {
|
||||||
|
eof = HTS_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (input.pos < input.size) {
|
||||||
|
unsigned char BIGSTK outbuf[8192];
|
||||||
|
ZSTD_outBuffer output;
|
||||||
|
|
||||||
|
output.dst = outbuf;
|
||||||
|
output.size = sizeof(outbuf);
|
||||||
|
output.pos = 0;
|
||||||
|
zret = ZSTD_decompressStream(zds, &output, &input);
|
||||||
|
if (ZSTD_isError(zret)) {
|
||||||
|
ok = HTS_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!codec_sink(out, outbuf, output.pos, &total, maxout)) {
|
||||||
|
ok = HTS_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ferror(in))
|
||||||
|
ok = HTS_FALSE;
|
||||||
|
}
|
||||||
|
ZSTD_freeDStream(zds);
|
||||||
|
/* zret != 0 at EOF: the last frame never completed */
|
||||||
|
return (ok && zret == 0 && !ferror(in)) ? (int) total : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t codec_head_zstd(const void *in, size_t in_len, void *out,
|
||||||
|
size_t out_len) {
|
||||||
|
ZSTD_DStream *const zds = ZSTD_createDStream();
|
||||||
|
ZSTD_inBuffer input;
|
||||||
|
ZSTD_outBuffer output;
|
||||||
|
size_t zret;
|
||||||
|
|
||||||
|
if (zds == NULL)
|
||||||
|
return 0;
|
||||||
|
if (ZSTD_isError(ZSTD_DCtx_setParameter(zds, ZSTD_d_windowLogMax,
|
||||||
|
HTS_ZSTD_WINDOWLOG_MAX))) {
|
||||||
|
ZSTD_freeDStream(zds);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
input.src = in;
|
||||||
|
input.size = in_len;
|
||||||
|
input.pos = 0;
|
||||||
|
output.dst = out;
|
||||||
|
output.size = out_len;
|
||||||
|
output.pos = 0;
|
||||||
|
zret = ZSTD_decompressStream(zds, &output, &input);
|
||||||
|
ZSTD_freeDStream(zds);
|
||||||
|
return ZSTD_isError(zret) ? 0 : output.pos;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LLint hts_codec_coded_size(FILE *in) {
|
||||||
|
long size;
|
||||||
|
|
||||||
|
if (fseek(in, 0, SEEK_END) != 0)
|
||||||
|
return -1;
|
||||||
|
size = ftell(in);
|
||||||
|
if (size < 0 || fseek(in, 0, SEEK_SET) != 0)
|
||||||
|
return -1;
|
||||||
|
return (LLint) size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hts_codec_unpack(hts_codec codec, const char *filename,
|
||||||
|
const char *newfile) {
|
||||||
|
if (filename == NULL || newfile == NULL || !filename[0] || !newfile[0])
|
||||||
|
return -1;
|
||||||
|
switch (codec) {
|
||||||
|
case HTS_CODEC_DEFLATE:
|
||||||
|
#if HTS_USEZLIB
|
||||||
|
return hts_zunpack(filename, newfile);
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
case HTS_CODEC_BROTLI:
|
||||||
|
case HTS_CODEC_ZSTD:
|
||||||
|
break;
|
||||||
|
default: /* IDENTITY never reaches the unpacker; UNSUPPORTED must fail */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#if HTS_USEBROTLI || HTS_USEZSTD
|
||||||
|
{
|
||||||
|
char catbuff[CATBUFF_SIZE];
|
||||||
|
FILE *out, *in = FOPEN(fconv(catbuff, sizeof(catbuff), filename), "rb");
|
||||||
|
LLint maxout;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (in == NULL)
|
||||||
|
return -1;
|
||||||
|
maxout = hts_codec_maxout(hts_codec_coded_size(in));
|
||||||
|
out = FOPEN(fconv(catbuff, sizeof(catbuff), newfile), "wb");
|
||||||
|
if (out == NULL) {
|
||||||
|
fclose(in);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#if HTS_USEBROTLI
|
||||||
|
if (codec == HTS_CODEC_BROTLI)
|
||||||
|
ret = codec_unpack_brotli(in, out, maxout);
|
||||||
|
#endif
|
||||||
|
#if HTS_USEZSTD
|
||||||
|
if (codec == HTS_CODEC_ZSTD)
|
||||||
|
ret = codec_unpack_zstd(in, out, maxout);
|
||||||
|
#endif
|
||||||
|
fclose(out);
|
||||||
|
fclose(in);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hts_codec_head(hts_codec codec, const void *in, size_t in_len, void *out,
|
||||||
|
size_t out_len) {
|
||||||
|
if (in == NULL || in_len == 0 || out == NULL || out_len == 0)
|
||||||
|
return 0;
|
||||||
|
switch (codec) {
|
||||||
|
#if HTS_USEZLIB
|
||||||
|
case HTS_CODEC_DEFLATE:
|
||||||
|
return hts_zhead(in, in_len, out, out_len);
|
||||||
|
#endif
|
||||||
|
#if HTS_USEBROTLI
|
||||||
|
case HTS_CODEC_BROTLI:
|
||||||
|
return codec_head_brotli(in, in_len, out, out_len);
|
||||||
|
#endif
|
||||||
|
#if HTS_USEZSTD
|
||||||
|
case HTS_CODEC_ZSTD:
|
||||||
|
return codec_head_zstd(in, in_len, out, out_len);
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/htscodec.h
Normal file
79
src/htscodec.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* File: HTTP content codings (gzip/deflate, brotli, zstd) */
|
||||||
|
/* Author: Xavier Roche */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#ifndef HTS_DEFCODEC
|
||||||
|
#define HTS_DEFCODEC
|
||||||
|
|
||||||
|
#include "htsglobal.h"
|
||||||
|
|
||||||
|
/* Content codings we may meet in a Content-Encoding header. */
|
||||||
|
typedef enum {
|
||||||
|
HTS_CODEC_IDENTITY = 0, /**< no coding, or a token we treat as none */
|
||||||
|
HTS_CODEC_DEFLATE, /**< gzip, x-gzip, deflate, x-deflate */
|
||||||
|
HTS_CODEC_BROTLI, /**< br */
|
||||||
|
HTS_CODEC_ZSTD, /**< zstd */
|
||||||
|
HTS_CODEC_UNSUPPORTED /**< a real coding we can not decode */
|
||||||
|
} hts_codec;
|
||||||
|
|
||||||
|
#ifdef HTS_INTERNAL_BYTECODE
|
||||||
|
|
||||||
|
/* Codec for a Content-Encoding token. A known coding we can not decode is
|
||||||
|
UNSUPPORTED; an unrecognized token is IDENTITY (servers do emit junk). */
|
||||||
|
extern hts_codec hts_codec_parse(const char *encoding);
|
||||||
|
|
||||||
|
/* Accept-Encoding value to advertise; secure (TLS) also offers br and zstd. */
|
||||||
|
extern const char *hts_acceptencoding(hts_boolean compressible,
|
||||||
|
hts_boolean secure);
|
||||||
|
|
||||||
|
/* HTS_TRUE if ext is the codec's own archive extension: a foo.gz served as
|
||||||
|
Content-Encoding: gzip stays packed on disk. */
|
||||||
|
extern hts_boolean hts_codec_is_archive_ext(hts_codec codec, const char *ext);
|
||||||
|
|
||||||
|
/* Decode filename into newfile. Returns the decoded size, or -1 on a truncated
|
||||||
|
or corrupt stream, an unsupported coding, a bomb over the budget, or I/O. */
|
||||||
|
extern int hts_codec_unpack(hts_codec codec, const char *filename,
|
||||||
|
const char *newfile);
|
||||||
|
|
||||||
|
/* Decode up to out_len leading bytes of a coded body for the MIME sniffer;
|
||||||
|
0 when nothing could be decoded. */
|
||||||
|
extern size_t hts_codec_head(hts_codec codec, const void *in, size_t in_len,
|
||||||
|
void *out, size_t out_len);
|
||||||
|
|
||||||
|
/* Ceiling on the decoded size of a body of in_size coded bytes. */
|
||||||
|
extern LLint hts_codec_maxout(LLint in_size);
|
||||||
|
|
||||||
|
/* Coded size of an open stream, left rewound; -1 if unknown. */
|
||||||
|
extern LLint hts_codec_coded_size(FILE *in);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -54,10 +54,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// extension par défaut pour fichiers n'en ayant pas
|
// extension par défaut pour fichiers n'en ayant pas
|
||||||
#define DEFAULT_EXT ".html"
|
#define DEFAULT_EXT ".html"
|
||||||
#define DEFAULT_EXT_SHORT ".htm"
|
#define DEFAULT_EXT_SHORT ".htm"
|
||||||
// #define DEFAULT_BIN_EXT ".bin"
|
|
||||||
// #define DEFAULT_BIN_EXT_SHORT ".bin"
|
|
||||||
// #define DEFAULT_EXT ".txt"
|
|
||||||
// #define DEFAULT_EXT_SHORT ".txt"
|
|
||||||
|
|
||||||
// éviter les /nul, /con..
|
// éviter les /nul, /con..
|
||||||
#define HTS_OVERRIDE_DOS_FOLDERS 1
|
#define HTS_OVERRIDE_DOS_FOLDERS 1
|
||||||
@@ -80,13 +76,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// always direct-to-disk (0/1)
|
// always direct-to-disk (0/1)
|
||||||
#define HTS_DIRECTDISK_ALWAYS 1
|
#define HTS_DIRECTDISK_ALWAYS 1
|
||||||
|
|
||||||
// gérer une table de hachage?
|
|
||||||
// REMOVED
|
|
||||||
// #define HTS_HASH 1
|
|
||||||
|
|
||||||
// fast cache (build hash table)
|
|
||||||
#define HTS_FAST_CACHE 1
|
|
||||||
|
|
||||||
// le > peut être considéré comme un tag de fermeture de commentaire (<!-- > est
|
// le > peut être considéré comme un tag de fermeture de commentaire (<!-- > est
|
||||||
// valide)
|
// valide)
|
||||||
#define GT_ENDS_COMMENT 1
|
#define GT_ENDS_COMMENT 1
|
||||||
@@ -97,27 +86,10 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// always transform a '//' into a sigle '/'
|
// always transform a '//' into a sigle '/'
|
||||||
#define HTS_STRIP_DOUBLE_SLASH 0
|
#define HTS_STRIP_DOUBLE_SLASH 0
|
||||||
|
|
||||||
// case-sensitive pour les dossiers et fichiers (0/1)
|
|
||||||
// [normalement 1, mais pose des problèmes (url malformée par exemple) et n'est
|
|
||||||
// pas très utile..
|
|
||||||
// ..et pas bcp respecté]
|
|
||||||
// REMOVED
|
|
||||||
// #define HTS_CASSE 0
|
|
||||||
|
|
||||||
// Un fichier ayant une taille différente du content-length doit il être annulé?
|
|
||||||
// SEE opt.tolerant and opt.http10
|
|
||||||
// #define HTS_CL_IS_FATAL 0
|
|
||||||
|
|
||||||
// une erreur supprime le fichier sur disque
|
// une erreur supprime le fichier sur disque
|
||||||
// (non fixé pour cause de retry)
|
// (non fixé pour cause de retry)
|
||||||
#define HTS_REMOVE_BAD_FILES 0
|
#define HTS_REMOVE_BAD_FILES 0
|
||||||
|
|
||||||
// en cas de Range: xx- donnant un Content-length: xx
|
|
||||||
// alors skipper le fichier, considéré comme transmis
|
|
||||||
// #define HTS_SKIP_FULL_RANGE 1
|
|
||||||
|
|
||||||
// nombre max de filtres que l'utilisateur peut fixer
|
|
||||||
// #define HTS_FILTERSMAX 10000
|
|
||||||
#define HTS_FILTERSINC 1000
|
#define HTS_FILTERSINC 1000
|
||||||
|
|
||||||
// connect non bloquant? (poll sur write)
|
// connect non bloquant? (poll sur write)
|
||||||
|
|||||||
508
src/htscore.c
508
src/htscore.c
@@ -119,46 +119,77 @@ hts_log_print(opt, LOG_INFO, "engine: end"); \
|
|||||||
RUN_CALLBACK0(opt, end); \
|
RUN_CALLBACK0(opt, end); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define XH_extuninit do { \
|
#define XH_extuninit \
|
||||||
HTMLCHECK_UNINIT \
|
do { \
|
||||||
hts_record_free(opt); \
|
HTMLCHECK_UNINIT \
|
||||||
if (filters && filters[0]) { \
|
hts_record_free(opt); \
|
||||||
freet(filters[0]); filters[0]=NULL; \
|
if (filters && filters[0]) { \
|
||||||
} \
|
freet(filters[0]); \
|
||||||
if (filters) { \
|
filters[0] = NULL; \
|
||||||
freet(filters); filters=NULL; \
|
} \
|
||||||
} \
|
if (filters) { \
|
||||||
back_delete_all(opt,&cache,sback); \
|
freet(filters); \
|
||||||
back_free(&sback); \
|
filters = NULL; \
|
||||||
checkrobots_free(&robots);\
|
} \
|
||||||
if (cache.use) { freet(cache.use); cache.use=NULL; } \
|
back_delete_all(opt, &cache, sback); \
|
||||||
if (cache.dat) { fclose(cache.dat); cache.dat=NULL; } \
|
back_free(&sback); \
|
||||||
if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
|
checkrobots_free(&robots); \
|
||||||
if (cache.zipOutput) { \
|
if (cache.zipOutput) { \
|
||||||
zipClose(cache.zipOutput, "Created by HTTrack Website Copier/"HTTRACK_VERSION); \
|
zipClose(cache.zipOutput, \
|
||||||
cache.zipOutput = NULL; \
|
"Created by HTTrack Website Copier/" HTTRACK_VERSION); \
|
||||||
} \
|
cache.zipOutput = NULL; \
|
||||||
if (cache.zipInput) { \
|
} \
|
||||||
unzClose(cache.zipInput); \
|
if (cache.zipInput) { \
|
||||||
cache.zipInput = NULL; \
|
unzClose(cache.zipInput); \
|
||||||
} \
|
cache.zipInput = NULL; \
|
||||||
if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
|
} \
|
||||||
if (cache.lst) { fclose(cache.lst); cache.lst=opt->state.strc.lst=NULL; } \
|
if (cache.lst) { \
|
||||||
if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
|
fclose(cache.lst); \
|
||||||
if (opt->log != NULL) fflush(opt->log); \
|
cache.lst = opt->state.strc.lst = NULL; \
|
||||||
if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
|
} \
|
||||||
if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
|
if (cache.txt) { \
|
||||||
if (opt->accept_cookie) cookie_save(opt->cookie,fconcat(OPT_GET_BUFF(opt),OPT_GET_BUFF_SIZE(opt),StringBuff(opt->path_log),"cookies.txt")); \
|
fclose(cache.txt); \
|
||||||
if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
|
cache.txt = NULL; \
|
||||||
if (cache_hashtable) { coucal_delete(&cache_hashtable); } \
|
} \
|
||||||
if (cache_tests) { coucal_delete(&cache_tests); } \
|
if (opt->log != NULL) \
|
||||||
if (template_header) { freet(template_header); template_header=NULL; } \
|
fflush(opt->log); \
|
||||||
if (template_body) { freet(template_body); template_body=NULL; } \
|
if (makestat_fp) { \
|
||||||
if (template_footer) { freet(template_footer); template_footer=NULL; } \
|
fclose(makestat_fp); \
|
||||||
hash_free(&hash); \
|
makestat_fp = NULL; \
|
||||||
clearCallbacks(&opt->state.callbacks); \
|
} \
|
||||||
/*structcheck_init(-1);*/ \
|
if (maketrack_fp) { \
|
||||||
} while(0)
|
fclose(maketrack_fp); \
|
||||||
|
maketrack_fp = NULL; \
|
||||||
|
} \
|
||||||
|
if (opt->accept_cookie) \
|
||||||
|
cookie_save(opt->cookie, \
|
||||||
|
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), \
|
||||||
|
StringBuff(opt->path_log), "cookies.txt")); \
|
||||||
|
if (makeindex_fp) { \
|
||||||
|
fclose(makeindex_fp); \
|
||||||
|
makeindex_fp = NULL; \
|
||||||
|
} \
|
||||||
|
if (cache_hashtable) { \
|
||||||
|
coucal_delete(&cache_hashtable); \
|
||||||
|
} \
|
||||||
|
if (cache_tests) { \
|
||||||
|
coucal_delete(&cache_tests); \
|
||||||
|
} \
|
||||||
|
if (template_header) { \
|
||||||
|
freet(template_header); \
|
||||||
|
template_header = NULL; \
|
||||||
|
} \
|
||||||
|
if (template_body) { \
|
||||||
|
freet(template_body); \
|
||||||
|
template_body = NULL; \
|
||||||
|
} \
|
||||||
|
if (template_footer) { \
|
||||||
|
freet(template_footer); \
|
||||||
|
template_footer = NULL; \
|
||||||
|
} \
|
||||||
|
hash_free(&hash); \
|
||||||
|
clearCallbacks(&opt->state.callbacks); \
|
||||||
|
} while (0)
|
||||||
#define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
|
#define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
|
||||||
|
|
||||||
struct lien_buffers {
|
struct lien_buffers {
|
||||||
@@ -441,32 +472,11 @@ void hts_finish_makeindex(httrackp *opt, int *makeindex_done,
|
|||||||
*makeindex_done = 1;
|
*makeindex_done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flush the parsed HTML output buffer to disk, skipping the rewrite when the
|
/* Flush the parsed HTML output buffer to disk. */
|
||||||
* on-disk MD5 is unchanged. */
|
|
||||||
void hts_finish_html_file(httrackp *opt, cache_back *cache, htsblk *r,
|
void hts_finish_html_file(httrackp *opt, cache_back *cache, htsblk *r,
|
||||||
FILE **fp, const char *ht_buff, size_t ht_len,
|
FILE **fp, const char *ht_buff, size_t ht_len,
|
||||||
const char *adr, const char *fil, const char *save) {
|
const char *adr, const char *fil, const char *save) {
|
||||||
char digest[32 + 2];
|
{
|
||||||
off_t fsize_old =
|
|
||||||
fsize(fconv(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), save));
|
|
||||||
int ok = 0;
|
|
||||||
|
|
||||||
digest[0] = '\0';
|
|
||||||
domd5mem(ht_buff, ht_len, digest, 1);
|
|
||||||
if (fsize_old == (off_t) ht_len) {
|
|
||||||
int mlen = 0;
|
|
||||||
char *mbuff;
|
|
||||||
|
|
||||||
cache_readdata(cache, "//[HTML-MD5]//", save, &mbuff, &mlen);
|
|
||||||
if (mlen)
|
|
||||||
mbuff[mlen] = '\0';
|
|
||||||
if ((mlen == 32) && (strcmp(((mbuff != NULL) ? mbuff : ""), digest) == 0)) {
|
|
||||||
ok = 1;
|
|
||||||
hts_log_print(opt, LOG_DEBUG, "File not re-written (md5): %s", save);
|
|
||||||
}
|
|
||||||
freet(mbuff);
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
file_notify(opt, adr, fil, save, 1, 1, r->notmodified);
|
file_notify(opt, adr, fil, save, 1, 1, r->notmodified);
|
||||||
*fp = filecreate(&opt->state.strc, save);
|
*fp = filecreate(&opt->state.strc, save);
|
||||||
if (*fp) {
|
if (*fp) {
|
||||||
@@ -498,13 +508,7 @@ void hts_finish_html_file(httrackp *opt, cache_back *cache, htsblk *r,
|
|||||||
if (fcheck)
|
if (fcheck)
|
||||||
hts_log_print(opt, LOG_ERROR, "* * Fatal write error, giving up");
|
hts_log_print(opt, LOG_ERROR, "* * Fatal write error, giving up");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
file_notify(opt, adr, fil, save, 0, 0, r->notmodified);
|
|
||||||
filenote(&opt->state.strc, save, NULL);
|
|
||||||
}
|
}
|
||||||
if (cache->ndx)
|
|
||||||
cache_writedata(cache->ndx, cache->dat, "//[HTML-MD5]//", save, digest,
|
|
||||||
(int) strlen(digest));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* does it look like XML ? (SVG et al.) */
|
/* does it look like XML ? (SVG et al.) */
|
||||||
@@ -523,7 +527,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
hash_struct *const hashptr = &hash;
|
hash_struct *const hashptr = &hash;
|
||||||
t_cookie BIGSTK cookie; // gestion des cookies
|
t_cookie BIGSTK cookie; // gestion des cookies
|
||||||
|
|
||||||
//char* tab_alloc=NULL;
|
|
||||||
int ptr; // pointeur actuel sur les liens
|
int ptr; // pointeur actuel sur les liens
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -534,15 +537,12 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
// pour les stats, nombre de fichiers & octets écrits
|
// pour les stats, nombre de fichiers & octets écrits
|
||||||
LLint stat_fragment = 0; // pour la fragmentation
|
LLint stat_fragment = 0; // pour la fragmentation
|
||||||
|
|
||||||
//TStamp istat_timestart; // départ pour calcul instantanné
|
|
||||||
//
|
|
||||||
TStamp last_info_shell = 0;
|
TStamp last_info_shell = 0;
|
||||||
int info_shell = 0;
|
int info_shell = 0;
|
||||||
|
|
||||||
// filtres
|
// filtres
|
||||||
char **filters = NULL;
|
char **filters = NULL;
|
||||||
|
|
||||||
//int filter_max=0;
|
|
||||||
int filptr = 0;
|
int filptr = 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -582,7 +582,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
// noter heure actuelle de départ en secondes
|
// noter heure actuelle de départ en secondes
|
||||||
memset(&HTS_STAT, 0, sizeof(HTS_STAT));
|
memset(&HTS_STAT, 0, sizeof(HTS_STAT));
|
||||||
HTS_STAT.stat_timestart = time_local();
|
HTS_STAT.stat_timestart = time_local();
|
||||||
//istat_timestart=stat_timestart;
|
|
||||||
HTS_STAT.istat_timestart[0] = HTS_STAT.istat_timestart[1] = mtime_local();
|
HTS_STAT.istat_timestart[0] = HTS_STAT.istat_timestart[1] = mtime_local();
|
||||||
/* reset stats */
|
/* reset stats */
|
||||||
HTS_STAT.HTS_TOTAL_RECV = 0;
|
HTS_STAT.HTS_TOTAL_RECV = 0;
|
||||||
@@ -616,9 +615,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
// initialiser usercommand
|
// initialiser usercommand
|
||||||
usercommand(opt, opt->sys_com_exec, StringBuff(opt->sys_com), "", "", "");
|
usercommand(opt, opt->sys_com_exec, StringBuff(opt->sys_com), "", "", "");
|
||||||
|
|
||||||
// initialiser structcheck
|
|
||||||
// structcheck_init(1);
|
|
||||||
|
|
||||||
// initialiser verif_backblue
|
// initialiser verif_backblue
|
||||||
verif_backblue(opt, NULL);
|
verif_backblue(opt, NULL);
|
||||||
verif_external(opt, 0, 0);
|
verif_external(opt, 0, 0);
|
||||||
@@ -638,9 +634,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_bin),
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_bin),
|
||||||
"templates/index-footer.html"), HTS_INDEX_FOOTER);
|
"templates/index-footer.html"), HTS_INDEX_FOOTER);
|
||||||
|
|
||||||
// initialiser mimedefs
|
|
||||||
//get_userhttptype(opt,1,StringBuff(opt->mimedefs),NULL);
|
|
||||||
|
|
||||||
// Initialiser indexation
|
// Initialiser indexation
|
||||||
if (opt->kindex)
|
if (opt->kindex)
|
||||||
index_init(StringBuff(opt->path_html));
|
index_init(StringBuff(opt->path_html));
|
||||||
@@ -684,7 +677,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
opt->filters.filters = &filters;
|
opt->filters.filters = &filters;
|
||||||
//
|
//
|
||||||
opt->filters.filptr = &filptr;
|
opt->filters.filptr = &filptr;
|
||||||
//opt->filters.filter_max=&filter_max;
|
|
||||||
|
|
||||||
// hash table
|
// hash table
|
||||||
opt->hash = &hash;
|
opt->hash = &hash;
|
||||||
@@ -731,8 +723,7 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
else if (*a == '-')
|
else if (*a == '-')
|
||||||
joker = 1;
|
joker = 1;
|
||||||
|
|
||||||
if (joker) { // joker ou filters
|
if (joker) { // joker ou filters
|
||||||
//char* p;
|
|
||||||
char BIGSTK tempo[HTS_URLMAXSIZE * 2];
|
char BIGSTK tempo[HTS_URLMAXSIZE * 2];
|
||||||
int type;
|
int type;
|
||||||
int plus = 0;
|
int plus = 0;
|
||||||
@@ -787,12 +778,11 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
XH_extuninit;
|
XH_extuninit;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//opt->filters.filters=filters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // adresse normale
|
} else { // adresse normale
|
||||||
char BIGSTK url[HTS_URLMAXSIZE * 2];
|
char BIGSTK url[HTS_URLMAXSIZE * 2];
|
||||||
|
|
||||||
// prochaine adresse
|
// prochaine adresse
|
||||||
@@ -813,6 +803,52 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
} // while
|
} // while
|
||||||
|
|
||||||
|
/* --why: print which filter rule decides for this URL, then stop */
|
||||||
|
if (StringNotEmpty(opt->why_url)) {
|
||||||
|
char BIGSTK url[HTS_URLMAXSIZE * 2];
|
||||||
|
lien_adrfil af;
|
||||||
|
|
||||||
|
if (strstr(StringBuff(opt->why_url), ":/") == NULL)
|
||||||
|
snprintf(url, sizeof(url), "http://%s", StringBuff(opt->why_url));
|
||||||
|
else
|
||||||
|
strcpybuff(url, StringBuff(opt->why_url));
|
||||||
|
if (ident_url_absolute(url, &af) < 0) {
|
||||||
|
printf("--why: unable to parse URL %s" LF, StringBuff(opt->why_url));
|
||||||
|
} else {
|
||||||
|
char BIGSTK l[HTS_URLMAXSIZE * 2], lfull[HTS_URLMAXSIZE * 2];
|
||||||
|
int jok, jokDepth = 0;
|
||||||
|
|
||||||
|
/* the two forms the wizard tests */
|
||||||
|
strcpybuff(l, jump_identification_const(af.adr));
|
||||||
|
if (*af.fil != '/')
|
||||||
|
strcatbuff(l, "/");
|
||||||
|
strcatbuff(l, af.fil);
|
||||||
|
if (!link_has_authority(af.adr))
|
||||||
|
strcpybuff(lfull, "http://");
|
||||||
|
else
|
||||||
|
lfull[0] = '\0';
|
||||||
|
strcatbuff(lfull, af.adr);
|
||||||
|
if (*af.fil != '/')
|
||||||
|
strcatbuff(lfull, "/");
|
||||||
|
strcatbuff(lfull, af.fil);
|
||||||
|
jok = fa_strjoker_dual(/*url */ 0, filters, filptr, lfull, l, NULL,
|
||||||
|
NULL, &jokDepth);
|
||||||
|
if (jok > 0)
|
||||||
|
printf("%s: accepted by rule #%d (%s)" LF, url, jokDepth + 1,
|
||||||
|
filters[jokDepth]);
|
||||||
|
else if (jok < 0)
|
||||||
|
printf("%s: rejected by rule #%d (%s)" LF, url, jokDepth + 1,
|
||||||
|
filters[jokDepth]);
|
||||||
|
else
|
||||||
|
printf("%s: no filter rule matches; the wizard decides "
|
||||||
|
"(same-site links are followed by default)" LF,
|
||||||
|
url);
|
||||||
|
}
|
||||||
|
freet(primary);
|
||||||
|
XH_extuninit;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* load URL file list */
|
/* load URL file list */
|
||||||
/* OPTIMIZED for fast load */
|
/* OPTIMIZED for fast load */
|
||||||
if (StringNotEmpty(opt->filelist)) {
|
if (StringNotEmpty(opt->filelist)) {
|
||||||
@@ -867,7 +903,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
htsbuff_cat(&primarybuff, "\n");
|
htsbuff_cat(&primarybuff, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fclose(fp);
|
|
||||||
hts_log_print(opt, LOG_NOTICE, "%d links added from %s", n,
|
hts_log_print(opt, LOG_NOTICE, "%d links added from %s", n,
|
||||||
StringBuff(opt->filelist));
|
StringBuff(opt->filelist));
|
||||||
|
|
||||||
@@ -922,7 +957,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// backing
|
// backing
|
||||||
//soc_max=opt->maxsoc;
|
|
||||||
if (opt->maxsoc > 0) {
|
if (opt->maxsoc > 0) {
|
||||||
#if BDEBUG==2
|
#if BDEBUG==2
|
||||||
_CLRSCR;
|
_CLRSCR;
|
||||||
@@ -1236,15 +1270,10 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
// tester r.adr
|
// tester r.adr
|
||||||
if (!error) {
|
if (!error) {
|
||||||
// erreur, pas de fichier chargé:
|
// erreur, pas de fichier chargé:
|
||||||
if ((!r.adr) && (r.is_write == 0)
|
if ((!r.adr) && (r.is_write == 0) && (r.statuscode != 301) &&
|
||||||
&& (r.statuscode != 301)
|
(r.statuscode != 302) && (r.statuscode != 303) &&
|
||||||
&& (r.statuscode != 302)
|
(r.statuscode != 307) && (r.statuscode != 412) &&
|
||||||
&& (r.statuscode != 303)
|
(r.statuscode != 416)) {
|
||||||
&& (r.statuscode != 307)
|
|
||||||
&& (r.statuscode != 412)
|
|
||||||
&& (r.statuscode != 416)
|
|
||||||
) {
|
|
||||||
// error=1;
|
|
||||||
|
|
||||||
// peut être que le fichier était trop gros?
|
// peut être que le fichier était trop gros?
|
||||||
if ((istoobig
|
if ((istoobig
|
||||||
@@ -1326,30 +1355,8 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
||may_be_hypertext_mime(opt, r.contenttype, urlfil())) /* Is real media, .. */
|
||may_be_hypertext_mime(opt, r.contenttype, urlfil())) /* Is real media, .. */
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/* Convert charset to UTF-8 - NOT! (what about links ? remote server side will have troubles with converted names) */
|
/* Convert charset to UTF-8 - NOT! (what about links ? remote server
|
||||||
//if (r.adr != NULL && r.size != 0 && opt->convert_utf8) {
|
* side will have troubles with converted names) */
|
||||||
// char *charset;
|
|
||||||
// char *pos;
|
|
||||||
// if (r.charset[0] != '\0') {
|
|
||||||
// charset = strdup(r.charset);
|
|
||||||
// } else {
|
|
||||||
// charset = hts_getCharsetFromMeta(r.adr, r.size);
|
|
||||||
// }
|
|
||||||
// if (charset != NULL) {
|
|
||||||
// char *const utf8 = hts_convertStringToUTF8(r.adr, r.size, charset);
|
|
||||||
// /* Use new buffer */
|
|
||||||
// if (utf8 != NULL) {
|
|
||||||
// freet(r.adr);
|
|
||||||
// r.size = strlen(utf8);
|
|
||||||
// r.adr = utf8;
|
|
||||||
// /* New UTF-8 charset */
|
|
||||||
// r.charset[0] = '\0';
|
|
||||||
// strcpy(r.charset, "utf-8");
|
|
||||||
// }
|
|
||||||
// /* Free charset */
|
|
||||||
// free(charset);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
/* Check bogus chars */
|
/* Check bogus chars */
|
||||||
if ((r.adr) && (r.size)) {
|
if ((r.adr) && (r.size)) {
|
||||||
@@ -1490,50 +1497,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// MOVED IN back_finalize()
|
|
||||||
//
|
|
||||||
// --------------------
|
|
||||||
// REAL MEDIA HACK
|
|
||||||
// Check if we have to load locally the file
|
|
||||||
// --------------------
|
|
||||||
//if (!error) {
|
|
||||||
// if (r.statuscode == HTTP_OK) { // OK (ou 304 en backing)
|
|
||||||
// if (r.adr==NULL) { // Written file
|
|
||||||
// if (may_be_hypertext_mime(r.contenttype, urlfil())) { // to parse!
|
|
||||||
// LLint sz;
|
|
||||||
// sz=fsize_utf8(savename());
|
|
||||||
// if (sz>0) { // ok, exists!
|
|
||||||
// if (sz < 8192) { // ok, small file --> to parse!
|
|
||||||
// FILE* fp=FOPEN(savename(),"rb");
|
|
||||||
// if (fp) {
|
|
||||||
// r.adr=malloct(sz + 1);
|
|
||||||
// if (r.adr) {
|
|
||||||
// if (fread(r.adr,1,sz,fp) == sz) {
|
|
||||||
// r.size=sz;
|
|
||||||
// r.adr[sz] = '\0';
|
|
||||||
// r.is_write = 0;
|
|
||||||
// } else {
|
|
||||||
// freet(r.adr);
|
|
||||||
// r.size=0;
|
|
||||||
// r.adr = NULL;
|
|
||||||
// r.statuscode=STATUSCODE_INVALID;
|
|
||||||
// strcpybuff(r.msg, ".RAM read error");
|
|
||||||
// }
|
|
||||||
// fclose(fp);
|
|
||||||
// fp=NULL;
|
|
||||||
// // remove (temporary) file!
|
|
||||||
// remove(savename());
|
|
||||||
// }
|
|
||||||
// if (fp)
|
|
||||||
// fclose(fp);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
// EN OF REAL MEDIA HACK
|
|
||||||
|
|
||||||
// ---stockage en cache---
|
// ---stockage en cache---
|
||||||
// stocker dans le cache?
|
// stocker dans le cache?
|
||||||
@@ -1654,24 +1617,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* info: updated */
|
|
||||||
/*
|
|
||||||
if (ptr>0) {
|
|
||||||
// "mis à jour"
|
|
||||||
if ((!r.notmodified) && (opt->is_update) && (!store_errpage)) { // page modifiée
|
|
||||||
if (strnotempty(savename())) {
|
|
||||||
HTS_STAT.stat_updated_files++;
|
|
||||||
//if ((opt->debug>0) && (opt->log!=NULL)) {
|
|
||||||
hts_log_print(opt, LOG_INFO, "File updated: %s%s",urladr(),urlfil());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!store_errpage) {
|
|
||||||
hts_log_print(opt, LOG_INFO, "File recorded: %s%s",urladr(),urlfil());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// traitement (parsing)
|
// traitement (parsing)
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -1719,11 +1664,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
/* Could not detect charset: could it be UTF-8 ? */
|
/* Could not detect charset: could it be UTF-8 ? */
|
||||||
/* No, we can not do that: browsers do not do it
|
/* No, we can not do that: browsers do not do it
|
||||||
(and it would break links). */
|
(and it would break links). */
|
||||||
//if (page_charset[0] == '\0') {
|
|
||||||
// if (is_unicode_utf8(r.adr, r.size)) {
|
|
||||||
// strcpy(page_charset, "utf-8");
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
/* Could not detect charset */
|
/* Could not detect charset */
|
||||||
if (page_charset[0] == '\0') {
|
if (page_charset[0] == '\0') {
|
||||||
hts_log_print(opt, LOG_INFO,
|
hts_log_print(opt, LOG_INFO,
|
||||||
@@ -1801,10 +1741,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
XH_uninit;
|
XH_uninit;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// I'll have to segment this part
|
|
||||||
// #include "htsparse.c"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fin parsing HTML
|
// Fin parsing HTML
|
||||||
@@ -1900,7 +1836,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
HTS_STAT.stat_files++;
|
HTS_STAT.stat_files++;
|
||||||
HTS_STAT.stat_bytes+=r.size;
|
HTS_STAT.stat_bytes+=r.size;
|
||||||
*/
|
*/
|
||||||
//printf("ok......\n");
|
|
||||||
} else {
|
} else {
|
||||||
// Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
|
// Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
|
||||||
// récursion nous en empêche
|
// récursion nous en empêche
|
||||||
@@ -1969,10 +1904,11 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("extern=%s\n",r.contenttype);
|
|
||||||
|
|
||||||
// ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!
|
// ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!
|
||||||
if (r.adr != NULL || r.size == 0) {
|
// An empty body must not overwrite the file when the transfer failed
|
||||||
|
// (statuscode <= 0, e.g. an -M hard-stop): it would truncate a good
|
||||||
|
// copy to 0 (#77 follow-up).
|
||||||
|
if (r.adr != NULL || (r.size == 0 && r.statuscode > 0)) {
|
||||||
file_notify(opt, urladr(), urlfil(), savename(), 1, 1, r.notmodified);
|
file_notify(opt, urladr(), urlfil(), savename(), 1, 1, r.notmodified);
|
||||||
if (filesave(opt, r.adr, (int) r.size, savename(), urladr(), urlfil()) !=
|
if (filesave(opt, r.adr, (int) r.size, savename(), urladr(), urlfil()) !=
|
||||||
0) {
|
0) {
|
||||||
@@ -1993,7 +1929,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parsing of other media types (java, ram..) */
|
/* Parsing of other media types (java, ram..) */
|
||||||
@@ -2092,16 +2027,9 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
// prochain pass2
|
// prochain pass2
|
||||||
while((ptr < opt->lien_tot) ? (!heap(ptr)->pass2) : 0)
|
while((ptr < opt->lien_tot) ? (!heap(ptr)->pass2) : 0)
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
||||||
//printf("first link==%d\n");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// copy abort state if necessary from outside
|
|
||||||
//if (!exit_xh && opt->state.exit_xh) {
|
|
||||||
// exit_xh=opt->state.exit_xh;
|
|
||||||
//}
|
|
||||||
// a-t-on dépassé le quota?
|
// a-t-on dépassé le quota?
|
||||||
if (!back_checkmirror(opt)) {
|
if (!back_checkmirror(opt)) {
|
||||||
ptr = opt->lien_tot;
|
ptr = opt->lien_tot;
|
||||||
@@ -2137,47 +2065,7 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
hts_log_print(opt, LOG_NOTICE,
|
hts_log_print(opt, LOG_NOTICE,
|
||||||
"No data seems to have been transferred during this session! : restoring previous one!");
|
"No data seems to have been transferred during this session! : restoring previous one!");
|
||||||
XH_uninit;
|
XH_uninit;
|
||||||
if ((fexist
|
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/old.dat")))
|
|
||||||
&&
|
|
||||||
(fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.ndx")))) {
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"));
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx"));
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.lst"));
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.txt"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.dat"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.lst"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.lst"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.txt"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.txt"));
|
|
||||||
}
|
|
||||||
opt->state.exit_xh = 2; /* interrupted (no connection detected) */
|
opt->state.exit_xh = 2; /* interrupted (no connection detected) */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -2298,13 +2186,11 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
char BIGSTK htstime[256];
|
char BIGSTK htstime[256];
|
||||||
char BIGSTK infoupdated[256];
|
char BIGSTK infoupdated[256];
|
||||||
|
|
||||||
// int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
|
|
||||||
LLint n =
|
LLint n =
|
||||||
(LLint) (HTS_STAT.HTS_TOTAL_RECV /
|
(LLint) (HTS_STAT.HTS_TOTAL_RECV /
|
||||||
(max(1, time_local() - HTS_STAT.stat_timestart)));
|
(max(1, time_local() - HTS_STAT.stat_timestart)));
|
||||||
|
|
||||||
sec2str(htstime, time_local() - HTS_STAT.stat_timestart);
|
sec2str(htstime, time_local() - HTS_STAT.stat_timestart);
|
||||||
//sprintf(finalInfo + strlen(finalInfo),LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
|
|
||||||
infoupdated[0] = '\0';
|
infoupdated[0] = '\0';
|
||||||
if (opt->is_update) {
|
if (opt->is_update) {
|
||||||
if (HTS_STAT.stat_updated_files > 0) {
|
if (HTS_STAT.stat_updated_files > 0) {
|
||||||
@@ -2387,12 +2273,6 @@ int httpmirror(char *url1, httrackp * opt) {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
int engine_stats(void) {
|
int engine_stats(void) {
|
||||||
#if 0
|
|
||||||
static FILE *debug_fp = NULL; /* ok */
|
|
||||||
|
|
||||||
if (!debug_fp)
|
|
||||||
debug_fp = fopen("esstat.txt", "wb");
|
|
||||||
#endif
|
|
||||||
HTS_STAT.stat_nsocket = HTS_STAT.stat_errors = HTS_STAT.nbk = 0;
|
HTS_STAT.stat_nsocket = HTS_STAT.stat_errors = HTS_STAT.nbk = 0;
|
||||||
HTS_STAT.nb = 0;
|
HTS_STAT.nb = 0;
|
||||||
if (HTS_STAT.HTS_TOTAL_RECV > 2048) {
|
if (HTS_STAT.HTS_TOTAL_RECV > 2048) {
|
||||||
@@ -2403,10 +2283,6 @@ int engine_stats(void) {
|
|||||||
if ((cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
|
if ((cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
|
||||||
TStamp dif;
|
TStamp dif;
|
||||||
|
|
||||||
#if 0
|
|
||||||
fprintf(debug_fp, "set timer %d\n", i);
|
|
||||||
fflush(debug_fp);
|
|
||||||
#endif
|
|
||||||
dif = cdif - HTS_STAT.istat_timestart[i];
|
dif = cdif - HTS_STAT.istat_timestart[i];
|
||||||
if ((TStamp) (dif / 1000) > 0) {
|
if ((TStamp) (dif / 1000) > 0) {
|
||||||
LLint byt = (HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
|
LLint byt = (HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
|
||||||
@@ -2425,10 +2301,6 @@ int engine_stats(void) {
|
|||||||
// timer #0 resync timer #1 when reaching 1 second limit
|
// timer #0 resync timer #1 when reaching 1 second limit
|
||||||
if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
|
if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
|
||||||
if ((cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
|
if ((cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
|
||||||
#if 0
|
|
||||||
fprintf(debug_fp, "resync timer 1\n");
|
|
||||||
fflush(debug_fp);
|
|
||||||
#endif
|
|
||||||
HTS_STAT.istat_bytes[1] = HTS_STAT.HTS_TOTAL_RECV;
|
HTS_STAT.istat_bytes[1] = HTS_STAT.HTS_TOTAL_RECV;
|
||||||
HTS_STAT.istat_timestart[1] = cdif;
|
HTS_STAT.istat_timestart[1] = cdif;
|
||||||
HTS_STAT.istat_reference01 = HTS_STAT.istat_timestart[0];
|
HTS_STAT.istat_reference01 = HTS_STAT.istat_timestart[0];
|
||||||
@@ -2449,7 +2321,6 @@ void host_ban(httrackp * opt, int ptr,
|
|||||||
lien_back *const back = sback->lnk;
|
lien_back *const back = sback->lnk;
|
||||||
const int back_max = sback->count;
|
const int back_max = sback->count;
|
||||||
|
|
||||||
//int l;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (host[0] == '!')
|
if (host[0] == '!')
|
||||||
@@ -2506,9 +2377,7 @@ void host_ban(httrackp * opt, int ptr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// effacer liens
|
// effacer liens
|
||||||
//l=strlen(host);
|
for (i = 0; i < opt->lien_tot; i++) {
|
||||||
for(i = 0; i < opt->lien_tot; i++) {
|
|
||||||
//if (heap(i)->adr_len==l) { // même taille de chaîne
|
|
||||||
// Calcul de taille sécurisée
|
// Calcul de taille sécurisée
|
||||||
if (heap(i)) {
|
if (heap(i)) {
|
||||||
if (heap(i)->adr) {
|
if (heap(i)->adr) {
|
||||||
@@ -2547,7 +2416,6 @@ void host_ban(httrackp * opt, int ptr,
|
|||||||
"WARNING! HostCancel detected memory leaks [null at %d]",
|
"WARNING! HostCancel detected memory leaks [null at %d]",
|
||||||
i);
|
i);
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2892,6 +2760,9 @@ int check_fatal_io_errno(void) {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef EROFS
|
#ifdef EROFS
|
||||||
case EROFS: /* Read-only file system */
|
case EROFS: /* Read-only file system */
|
||||||
|
#endif
|
||||||
|
#ifdef EDQUOT
|
||||||
|
case EDQUOT: /* Disk quota exceeded */
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
@@ -2961,7 +2832,6 @@ FILE *fileappend(filenote_strc * strc, const char *s) {
|
|||||||
// noter lst
|
// noter lst
|
||||||
filenote(strc, s, NULL);
|
filenote(strc, s, NULL);
|
||||||
|
|
||||||
// if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s); // pas de / (root!!) // ** SIIIIIII!!! à cause de -O <path>
|
|
||||||
strcpybuff(fname, s);
|
strcpybuff(fname, s);
|
||||||
|
|
||||||
#if HTS_DOSNAME
|
#if HTS_DOSNAME
|
||||||
@@ -3005,7 +2875,6 @@ int filecreateempty(filenote_strc * strc, const char *filename) {
|
|||||||
int filenote(filenote_strc * strc, const char *s, filecreate_params * params) {
|
int filenote(filenote_strc * strc, const char *s, filecreate_params * params) {
|
||||||
// gestion du fichier liste liste
|
// gestion du fichier liste liste
|
||||||
if (params) {
|
if (params) {
|
||||||
//filecreate_params* p = (filecreate_params*) params;
|
|
||||||
strcpybuff(strc->path, params->path);
|
strcpybuff(strc->path, params->path);
|
||||||
strc->lst = params->lst;
|
strc->lst = params->lst;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3085,9 +2954,8 @@ void usercommand_exe(const char *cmd, const char *file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void postprocess_file(httrackp * opt, const char *save, const char *adr,
|
static void postprocess_file(httrackp *opt, const char *save, const char *adr,
|
||||||
const char *fil) {
|
const char *fil) {
|
||||||
//int first = 0;
|
|
||||||
/* MIME-html archive to build */
|
/* MIME-html archive to build */
|
||||||
if (opt != NULL && opt->mimehtml) {
|
if (opt != NULL && opt->mimehtml) {
|
||||||
if (adr != NULL && strcmp(adr, "primary") == 0) {
|
if (adr != NULL && strcmp(adr, "primary") == 0) {
|
||||||
@@ -3115,7 +2983,6 @@ static void postprocess_file(httrackp * opt, const char *save, const char *adr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!opt->state.mimehtml_created) {
|
if (!opt->state.mimehtml_created) {
|
||||||
//first = 1;
|
|
||||||
opt->state.mimefp =
|
opt->state.mimefp =
|
||||||
fopen(fconcat
|
fopen(fconcat
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
@@ -3259,28 +3126,6 @@ int fspc(httrackp * opt, FILE * fp, const char *type) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// vérifier taux de transfert
|
|
||||||
#if 0
|
|
||||||
void check_rate(TStamp stat_timestart, int maxrate) {
|
|
||||||
// vérifier taux de transfert (pas trop grand?)
|
|
||||||
/*
|
|
||||||
if (maxrate>0) {
|
|
||||||
int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart)); // taux actuel de transfert
|
|
||||||
HTS_STAT.HTS_TOTAL_RECV_STATE=0;
|
|
||||||
if (r>maxrate) { // taux>taux autorisé
|
|
||||||
int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
|
|
||||||
if (taux<15)
|
|
||||||
HTS_STAT.HTS_TOTAL_RECV_STATE=1; // ralentir un peu (<15% dépassement)
|
|
||||||
else if (taux<50)
|
|
||||||
HTS_STAT.HTS_TOTAL_RECV_STATE=2; // beaucoup (<50% dépassement)
|
|
||||||
else
|
|
||||||
HTS_STAT.HTS_TOTAL_RECV_STATE=3; // énormément (>50% dépassement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
// sous routines liées au moteur et au backing
|
// sous routines liées au moteur et au backing
|
||||||
|
|
||||||
@@ -3290,21 +3135,8 @@ int backlinks_done(const struct_back * sback,
|
|||||||
int ptr) {
|
int ptr) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
#if 0
|
|
||||||
int i;
|
|
||||||
|
|
||||||
//Links done and stored in cache
|
|
||||||
for(i = ptr + 1; i < lien_tot; i++) {
|
|
||||||
if (heap(i)) {
|
|
||||||
if (heap(i)->pass2 == -1) {
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// finalized in background
|
// finalized in background
|
||||||
n += HTS_STAT.stat_background;
|
n += HTS_STAT.stat_background;
|
||||||
#endif
|
|
||||||
n += back_done_incache(sback);
|
n += back_done_incache(sback);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -3371,6 +3203,41 @@ int back_pluggable_sockets_strict(struct_back * sback, httrackp * opt) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* One engine-loop tick: refresh the transfer stats and run the loop callback
|
||||||
|
for slot b (-1 = none). HTS_FALSE = the callback requested an abort. */
|
||||||
|
hts_boolean hts_loop_tick(struct_back *sback, httrackp *opt, int b, int ptr) {
|
||||||
|
engine_stats();
|
||||||
|
HTS_STAT.stat_nsocket = back_nsoc(sback);
|
||||||
|
HTS_STAT.stat_errors = fspc(opt, NULL, "error");
|
||||||
|
HTS_STAT.stat_warnings = fspc(opt, NULL, "warning");
|
||||||
|
HTS_STAT.stat_infos = fspc(opt, NULL, "info");
|
||||||
|
HTS_STAT.nbk = backlinks_done(sback, opt->liens, opt->lien_tot, ptr);
|
||||||
|
HTS_STAT.nb = back_transferred(HTS_STAT.stat_bytes, sback);
|
||||||
|
return RUN_CALLBACK7(
|
||||||
|
opt, loop, sback->lnk, sback->count, b, ptr, opt->lien_tot,
|
||||||
|
(int) (time_local() - HTS_STAT.stat_timestart), &HTS_STAT)
|
||||||
|
? HTS_TRUE
|
||||||
|
: HTS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single implementation of the historical WAIT_FOR_AVAILABLE_SOCKET macros. */
|
||||||
|
hts_boolean hts_wait_available_socket(struct_back *sback, httrackp *opt,
|
||||||
|
cache_back *cache, int ptr) {
|
||||||
|
const int prev = opt->state._hts_in_html_parsing;
|
||||||
|
|
||||||
|
while (back_pluggable_sockets_strict(sback, opt) <= 0) {
|
||||||
|
opt->state._hts_in_html_parsing = 6;
|
||||||
|
back_wait(sback, opt, cache, 0);
|
||||||
|
/* time limit (-E) exceeded: stop waiting for a socket (#481) */
|
||||||
|
if (!back_checkmirror(opt))
|
||||||
|
break;
|
||||||
|
if (!hts_loop_tick(sback, opt, -1, ptr))
|
||||||
|
return HTS_FALSE;
|
||||||
|
}
|
||||||
|
opt->state._hts_in_html_parsing = prev;
|
||||||
|
return HTS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
int back_pluggable_sockets(struct_back * sback, httrackp * opt) {
|
int back_pluggable_sockets(struct_back * sback, httrackp * opt) {
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@@ -3406,8 +3273,7 @@ int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
/* on a déja parcouru */
|
/* on a déja parcouru */
|
||||||
if (p < cache->ptr_ant)
|
if (p < cache->ptr_ant)
|
||||||
p = cache->ptr_ant;
|
p = cache->ptr_ant;
|
||||||
while(p < opt->lien_tot && n > 0 && back_checkmirror(opt)) {
|
while (p < opt->lien_tot && n > 0 && back_checkmirror(opt)) {
|
||||||
//while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
|
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
|
|
||||||
// on ne met pas le fichier en backing si il doit être traité après ou s'il a déja été traité
|
// on ne met pas le fichier en backing si il doit être traité après ou s'il a déja été traité
|
||||||
@@ -3419,12 +3285,6 @@ int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
ok = 0;
|
ok = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Why in hell did I do that ?
|
|
||||||
//if (ok && heap(p)->sav != NULL && heap(p)->sav[0] != '\0'
|
|
||||||
// && hash_read(opt->hash,heap(p)->sav,NULL,HASH_STRUCT_FILENAME ) >= 0) // lookup in liens_record
|
|
||||||
//{
|
|
||||||
// ok = 0;
|
|
||||||
//}
|
|
||||||
if (heap(p)->sav == NULL || heap(p)->sav[0] == '\0'
|
if (heap(p)->sav == NULL || heap(p)->sav[0] == '\0'
|
||||||
|| hash_read(opt->hash, heap(p)->sav, NULL, HASH_STRUCT_FILENAME ) < 0) {
|
|| hash_read(opt->hash, heap(p)->sav, NULL, HASH_STRUCT_FILENAME ) < 0) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
@@ -3453,7 +3313,7 @@ int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
} // while
|
} // while
|
||||||
/* sauver position dernière anticipation */
|
/* sauver position dernière anticipation */
|
||||||
cache->ptr_ant = p;
|
cache->ptr_ant = p;
|
||||||
cache->ptr_last = ptr;
|
cache->ptr_last = ptr;
|
||||||
@@ -3715,20 +3575,7 @@ HTSEXT_API hts_boolean hts_has_stopped(httrackp *opt) {
|
|||||||
return ended;
|
return ended;
|
||||||
}
|
}
|
||||||
|
|
||||||
// régler en cours de route les paramètres réglables..
|
|
||||||
// -1 : erreur
|
|
||||||
//HTSEXT_API int hts_setopt(httrackp* set_opt) {
|
|
||||||
// if (set_opt) {
|
|
||||||
// httrackp* engine_opt=hts_declareoptbuffer(NULL);
|
|
||||||
// if (engine_opt) {
|
|
||||||
// //_hts_setopt=opt;
|
|
||||||
// copy_htsopt(set_opt,engine_opt);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return 0;
|
|
||||||
//}
|
|
||||||
// ajout d'URL
|
// ajout d'URL
|
||||||
// -1 : erreur
|
|
||||||
HTSEXT_API hts_boolean hts_addurl(httrackp *opt, char **url) {
|
HTSEXT_API hts_boolean hts_addurl(httrackp *opt, char **url) {
|
||||||
if (url)
|
if (url)
|
||||||
opt->state._hts_addurl = url;
|
opt->state._hts_addurl = url;
|
||||||
@@ -3989,10 +3836,7 @@ int htsAddLink(htsmoduleStruct * str, char *link) {
|
|||||||
heap_top()->link_import = 0; // pas mode import
|
heap_top()->link_import = 0; // pas mode import
|
||||||
|
|
||||||
// écrire autres paramètres de la structure-lien
|
// écrire autres paramètres de la structure-lien
|
||||||
//if (meme_adresse)
|
|
||||||
heap_top()->premier = heap(ptr)->premier;
|
heap_top()->premier = heap(ptr)->premier;
|
||||||
//else // sinon l'objet père est le précédent lui même
|
|
||||||
// heap_top()->premier=ptr;
|
|
||||||
|
|
||||||
heap_top()->precedent = ptr;
|
heap_top()->precedent = ptr;
|
||||||
// noter la priorité
|
// noter la priorité
|
||||||
@@ -4003,9 +3847,6 @@ int htsAddLink(htsmoduleStruct * str, char *link) {
|
|||||||
heap_top()->pass2 = max(pass_fix, numero_passe);
|
heap_top()->pass2 = max(pass_fix, numero_passe);
|
||||||
heap_top()->retry = opt->retry;
|
heap_top()->retry = opt->retry;
|
||||||
|
|
||||||
//strcpybuff(heap_top()->adr,adr);
|
|
||||||
//strcpybuff(heap_top()->fil,fil);
|
|
||||||
//strcpybuff(heap_top()->sav,save);
|
|
||||||
hts_log_print(opt, LOG_DEBUG, "(module): OK, NOTE: %s%s -> %s",
|
hts_log_print(opt, LOG_DEBUG, "(module): OK, NOTE: %s%s -> %s",
|
||||||
heap_top()->adr, heap_top()->fil,
|
heap_top()->adr, heap_top()->fil,
|
||||||
heap_top()->sav);
|
heap_top()->sav);
|
||||||
@@ -4034,7 +3875,6 @@ void voidf(void) {
|
|||||||
a = "| HTTrack Website Copier |" CRLF;
|
a = "| HTTrack Website Copier |" CRLF;
|
||||||
a = "|Code: Windows Interface Xavier Roche |" CRLF;
|
a = "|Code: Windows Interface Xavier Roche |" CRLF;
|
||||||
a = "| HTS/HTTrack Xavier Roche |" CRLF;
|
a = "| HTS/HTTrack Xavier Roche |" CRLF;
|
||||||
a = "| .class Parser Yann Philippot |" CRLF;
|
|
||||||
a = "| |" CRLF;
|
a = "| |" CRLF;
|
||||||
a = "|Tested on: Windows95,98,NT,2K |" CRLF;
|
a = "|Tested on: Windows95,98,NT,2K |" CRLF;
|
||||||
a = "| Linux PC |" CRLF;
|
a = "| Linux PC |" CRLF;
|
||||||
|
|||||||
@@ -193,8 +193,7 @@ struct cache_back {
|
|||||||
/* */
|
/* */
|
||||||
int type;
|
int type;
|
||||||
int ro; /**< read-only: no new cache is written */
|
int ro; /**< read-only: no new cache is written */
|
||||||
FILE *dat, *ndx, *olddat; /**< new data, new index, old data files */
|
|
||||||
char *use; /**< in-memory list of cached adr+fil keys */
|
|
||||||
FILE *lst; /**< file list, used for purge */
|
FILE *lst; /**< file list, used for purge */
|
||||||
FILE *txt; /**< human-readable file list (info) */
|
FILE *txt; /**< human-readable file list (info) */
|
||||||
char lastmodified[256];
|
char lastmodified[256];
|
||||||
@@ -216,6 +215,7 @@ struct cache_back {
|
|||||||
int zipEntriesCapa;
|
int zipEntriesCapa;
|
||||||
hts_boolean
|
hts_boolean
|
||||||
zipWriteFailed; /**< a cache write failed; stop touching the stream */
|
zipWriteFailed; /**< a cache write failed; stop touching the stream */
|
||||||
|
int zipWriteFailures; /**< consecutive entry write failures; reset on store */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef HTS_DEF_FWSTRUCT_hash_struct
|
#ifndef HTS_DEF_FWSTRUCT_hash_struct
|
||||||
@@ -287,12 +287,12 @@ struct filecreate_params {
|
|||||||
|
|
||||||
/* True if a new cache is being written (plain or zip backend). */
|
/* True if a new cache is being written (plain or zip backend). */
|
||||||
HTS_STATIC int cache_writable(cache_back * cache) {
|
HTS_STATIC int cache_writable(cache_back * cache) {
|
||||||
return (cache != NULL && (cache->dat != NULL || cache->zipOutput != NULL));
|
return (cache != NULL && cache->zipOutput != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* True if an old cache is available to read (plain or zip backend). */
|
/* True if an old cache is available to read (plain or zip backend). */
|
||||||
HTS_STATIC int cache_readable(cache_back * cache) {
|
HTS_STATIC int cache_readable(cache_back * cache) {
|
||||||
return (cache != NULL && (cache->olddat != NULL || cache->zipInput != NULL));
|
return (cache != NULL && cache->zipInput != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -411,10 +411,6 @@ char *readfile_utf8(const char *fil);
|
|||||||
|
|
||||||
char *readfile_or(const char *fil, const char *defaultdata);
|
char *readfile_or(const char *fil, const char *defaultdata);
|
||||||
|
|
||||||
#if 0
|
|
||||||
void check_rate(TStamp stat_timestart, int maxrate);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Backing (download-slot) scheduler. Operate on the back[] ring (struct_back).
|
/* Backing (download-slot) scheduler. Operate on the back[] ring (struct_back).
|
||||||
Not thread-safe; call from the single crawl loop. */
|
Not thread-safe; call from the single crawl loop. */
|
||||||
|
|
||||||
@@ -432,6 +428,15 @@ int back_pluggable_sockets(struct_back * sback, httrackp * opt);
|
|||||||
|
|
||||||
int back_pluggable_sockets_strict(struct_back * sback, httrackp * opt);
|
int back_pluggable_sockets_strict(struct_back * sback, httrackp * opt);
|
||||||
|
|
||||||
|
/* One engine-loop tick: refresh the transfer stats and run the loop callback
|
||||||
|
for slot b (-1 = none). HTS_FALSE = the callback requested an abort. */
|
||||||
|
hts_boolean hts_loop_tick(struct_back *sback, httrackp *opt, int b, int ptr);
|
||||||
|
|
||||||
|
/* Wait until a test socket can be plugged, pumping transfers, stats and the
|
||||||
|
loop callback; gives up past the -E deadline. HTS_FALSE = callback abort. */
|
||||||
|
hts_boolean hts_wait_available_socket(struct_back *sback, httrackp *opt,
|
||||||
|
cache_back *cache, int ptr);
|
||||||
|
|
||||||
/* Randomized inter-file pause target in [min_ms,max_ms] (#185), derived from a
|
/* Randomized inter-file pause target in [min_ms,max_ms] (#185), derived from a
|
||||||
timestamp seed so it is stable within one gap and rerolls per launch. */
|
timestamp seed so it is stable within one gap and rerolls per launch. */
|
||||||
int hts_pause_target_ms(TStamp seed, int min_ms, int max_ms);
|
int hts_pause_target_ms(TStamp seed, int min_ms, int max_ms);
|
||||||
@@ -457,11 +462,6 @@ int ask_continue(httrackp * opt);
|
|||||||
/* Number of decimal digits in n. */
|
/* Number of decimal digits in n. */
|
||||||
int nombre_digit(int n);
|
int nombre_digit(int n);
|
||||||
|
|
||||||
// Java
|
|
||||||
#if 0
|
|
||||||
int hts_add_file(char *file, int file_position);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Polling
|
// Polling
|
||||||
#if HTS_POLL
|
#if HTS_POLL
|
||||||
int check_flot(T_SOC s);
|
int check_flot(T_SOC s);
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
char *url = NULL; // URLS séparées par un espace
|
char *url = NULL; // URLS séparées par un espace
|
||||||
int url_sz = 65535;
|
int url_sz = 65535;
|
||||||
|
|
||||||
//char url[65536]; // URLS séparées par un espace
|
|
||||||
// the parametres
|
// the parametres
|
||||||
int httrack_logmode = 3; // ONE log file
|
int httrack_logmode = 3; // ONE log file
|
||||||
|
|
||||||
@@ -290,12 +289,11 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
if (tmp_argc == 1) { /* pas -P & co */
|
if (tmp_argc == 1) { /* pas -P & co */
|
||||||
if (!cmdl_opt(tmp_argv[0])) { /* pas -c0 & co */
|
if (!cmdl_opt(tmp_argv[0])) { /* pas -c0 & co */
|
||||||
if (argv_url < 0)
|
if (argv_url < 0)
|
||||||
argv_url = 0; // -1==force -> 1=one url already detected, wipe all previous options
|
argv_url = 0; // -1==force -> 1=one url already detected, wipe all
|
||||||
//if (argv_url>=0) {
|
// previous options
|
||||||
argv_url++;
|
argv_url++;
|
||||||
if (!argv_firsturl)
|
if (!argv_firsturl)
|
||||||
argv_firsturl = x_argv[x_argc - 1];
|
argv_firsturl = x_argv[x_argc - 1];
|
||||||
//}
|
|
||||||
} else {
|
} else {
|
||||||
if (strcmp(tmp_argv[0], "-h") == 0) {
|
if (strcmp(tmp_argv[0], "-h") == 0) {
|
||||||
help(argv[0], !opt->quiet);
|
help(argv[0], !opt->quiet);
|
||||||
@@ -324,8 +322,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
} else if (tmp_argc == 2) {
|
} else if (tmp_argc == 2) {
|
||||||
if ((strcmp(tmp_argv[0], "-%L") == 0)) { // liste d'URLs
|
if ((strcmp(tmp_argv[0], "-%L") == 0)) { // liste d'URLs
|
||||||
if (argv_url < 0)
|
if (argv_url < 0)
|
||||||
argv_url = 0; // -1==force -> 1=one url already detected, wipe all previous options
|
argv_url = 0; // -1==force -> 1=one url already detected, wipe all
|
||||||
//if (argv_url>=0)
|
// previous options
|
||||||
argv_url++; /* forcer */
|
argv_url++; /* forcer */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,15 +401,11 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
else
|
else
|
||||||
inQuote = 1;
|
inQuote = 1;
|
||||||
} else if (!inQuote && !noDbl && argv[na][i] == ',') {
|
} else if (!inQuote && !noDbl && argv[na][i] == ',') {
|
||||||
//StringAddchar(path, '\0');
|
|
||||||
//j = 0;
|
|
||||||
path = &opt->path_log;
|
path = &opt->path_log;
|
||||||
} else {
|
} else {
|
||||||
StringAddchar(*path, argv[na][i]);
|
StringAddchar(*path, argv[na][i]);
|
||||||
//path[j++] = argv[na][i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//path[j++] = '\0';
|
|
||||||
if (StringLength(opt->path_log) == 0) {
|
if (StringLength(opt->path_log) == 0) {
|
||||||
StringCopyS(opt->path_log, opt->path_html);
|
StringCopyS(opt->path_log, opt->path_html);
|
||||||
}
|
}
|
||||||
@@ -420,7 +414,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
if (check_path(&opt->path_html, argv_firsturl)) {
|
if (check_path(&opt->path_html, argv_firsturl)) {
|
||||||
opt->dir_topindex = 1; // rebuilt top index
|
opt->dir_topindex = 1; // rebuilt top index
|
||||||
}
|
}
|
||||||
//printf("-->%s\n%s\n",StringBuff(opt->path_html),StringBuff(opt->path_log));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
@@ -539,74 +532,15 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
insert_after++;
|
insert_after++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(lastp != NULL);
|
} while (lastp != NULL);
|
||||||
//fclose(fp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Existence d'un cache - pas de new mais un old.. renommer
|
// No new cache but an old one? promote it
|
||||||
#if DEBUG_STEPS
|
#if DEBUG_STEPS
|
||||||
printf("Checking cache\n");
|
printf("Checking cache\n");
|
||||||
#endif
|
#endif
|
||||||
if (!fexist
|
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log), "hts-cache/new.zip"))) {
|
|
||||||
if (fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log), "hts-cache/old.zip"))) {
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.zip"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.zip"));
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
if ((!fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log), "hts-cache/new.dat")))
|
|
||||||
||
|
|
||||||
(!fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx")))) {
|
|
||||||
if ((fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log), "hts-cache/old.dat")))
|
|
||||||
&&
|
|
||||||
(fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.ndx")))) {
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"));
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx"));
|
|
||||||
//remove(fconcat(StringBuff(opt->path_log),"hts-cache/new.lst"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.dat"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx"));
|
|
||||||
//rename(fconcat(StringBuff(opt->path_log),"hts-cache/old.lst"),fconcat(StringBuff(opt->path_log),"hts-cache/new.lst"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interrupted mirror detected */
|
/* Interrupted mirror detected */
|
||||||
if (!opt->quiet) {
|
if (!opt->quiet) {
|
||||||
@@ -774,24 +708,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
HTS_PANIC_PRINTF(s);
|
HTS_PANIC_PRINTF(s);
|
||||||
htsmain_free();
|
htsmain_free();
|
||||||
return -1;
|
return -1;
|
||||||
#else
|
|
||||||
#if 0
|
|
||||||
char _args[8][256];
|
|
||||||
char *args[8];
|
|
||||||
|
|
||||||
printf("Cheking for updates...\n");
|
|
||||||
strcpybuff(_args[0], argv[0]);
|
|
||||||
strcpybuff(_args[1], "--get");
|
|
||||||
sprintf(_args[2], HTS_UPDATE_WEBSITE, 0, "");
|
|
||||||
strcpybuff(_args[3], "--quickinfo");
|
|
||||||
args[0] = _args[0];
|
|
||||||
args[1] = _args[1];
|
|
||||||
args[2] = _args[2];
|
|
||||||
args[3] = _args[3];
|
|
||||||
args[4] = NULL;
|
|
||||||
if (execvp(args[0], args) == -1) {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -809,103 +725,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compter urls/jokers
|
|
||||||
/*
|
|
||||||
if (argv_url<=0) {
|
|
||||||
int na;
|
|
||||||
argv_url=0;
|
|
||||||
for(na=1;na<argc;na++) {
|
|
||||||
if ( (strcmp(argv[na],"-P")==0) || (strcmp(argv[na],"-N")==0) || (strcmp(argv[na],"-F")==0) || (strcmp(argv[na],"-O")==0) || (strcmp(argv[na],"-V")==0) ) {
|
|
||||||
na++; // sauter nom de proxy
|
|
||||||
} else if (!cmdl_opt(argv[na])) {
|
|
||||||
argv_url++; // un de plus
|
|
||||||
} else if (strcmp(argv[na],"-h")==0) {
|
|
||||||
help(argv[0],!opt->quiet);
|
|
||||||
htsmain_free();
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
if ((strchr(argv[na],'q')!=NULL))
|
|
||||||
opt->quiet=1; // ne pas poser de questions! (nohup par exemple)
|
|
||||||
if ((strchr(argv[na],'i')!=NULL)) { // doit.log!
|
|
||||||
argv_url=0;
|
|
||||||
na=argc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Ici on ajoute les arguments qui ont été appelés avant au cas où on récupère une session
|
|
||||||
// Exemple: httrack www.truc.fr -L0 puis ^C puis httrack sans URL : ajouter URL précédente
|
|
||||||
/*
|
|
||||||
if (argv_url==0) {
|
|
||||||
//if ((fexist(fconcat(StringBuff(opt->path_log),"hts-cache/new.dat"))) && (fexist(fconcat(StringBuff(opt->path_log),"hts-cache/new.ndx")))) { // il existe déja un cache précédent.. renommer
|
|
||||||
if (fexist(fconcat(StringBuff(opt->path_log),"hts-cache/doit.log"))) { // un cache est présent
|
|
||||||
|
|
||||||
x_argvblk=(char*) calloct(32768,1);
|
|
||||||
|
|
||||||
if (x_argvblk!=NULL) {
|
|
||||||
FILE* fp;
|
|
||||||
int x_argc;
|
|
||||||
|
|
||||||
//strcpybuff(x_argvblk,"httrack ");
|
|
||||||
fp=fopen(fconcat(StringBuff(opt->path_log),"hts-cache/doit.log"),"rb");
|
|
||||||
if (fp) {
|
|
||||||
linput(fp,x_argvblk+strlen(x_argvblk),8192);
|
|
||||||
fclose(fp); fp=NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculer arguments selon derniers arguments
|
|
||||||
x_argv[0]=argv[0];
|
|
||||||
x_argc=1;
|
|
||||||
{
|
|
||||||
char* p=x_argvblk;
|
|
||||||
do {
|
|
||||||
x_argv[x_argc++]=p;
|
|
||||||
//p=strstr(p," ");
|
|
||||||
// exemple de chaine: "echo \"test\"" c:\a "\$0"
|
|
||||||
p=next_token(p,1); // prochain token
|
|
||||||
if (p) {
|
|
||||||
*p=0; // octet nul (tableau)
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
} while(p!=NULL);
|
|
||||||
}
|
|
||||||
// recopier arguments actuels (pointeurs uniquement)
|
|
||||||
{
|
|
||||||
int na;
|
|
||||||
for(na=1;na<argc;na++) {
|
|
||||||
if (strcmp(argv[na],"-O") != 0) // SAUF le path!
|
|
||||||
x_argv[x_argc++]=argv[na];
|
|
||||||
else
|
|
||||||
na++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argc=x_argc; // nouvel argc
|
|
||||||
argv=x_argv; // nouvel argv
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Vérifier quiet
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
int na;
|
|
||||||
for(na=1;na<argc;na++) {
|
|
||||||
if (!cmdl_opt(argv[na])) {
|
|
||||||
if ((strcmp(argv[na],"-P")==0) || (strcmp(argv[na],"-N")==0) || (strcmp(argv[na],"-F")==0) || (strcmp(argv[na],"-O")==0) || (strcmp(argv[na],"-V")==0))
|
|
||||||
na++; // sauter nom de proxy
|
|
||||||
} else {
|
|
||||||
if ((strchr(argv[na],'q')!=NULL) || (strchr(argv[na],'i')!=NULL))
|
|
||||||
opt->quiet=1; // ne pas poser de questions! (nohup par exemple)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Engine self-tests: -#test lists them, -#test=NAME [args] runs one. Handled
|
/* Engine self-tests: -#test lists them, -#test=NAME [args] runs one. Handled
|
||||||
here, ahead of the no-URL usage gate below, so they need no dummy URL. */
|
here, ahead of the no-URL usage gate below, so they need no dummy URL. */
|
||||||
{
|
{
|
||||||
@@ -1012,8 +831,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
} else { // plus de 2 paramètres
|
} else { // plus de 2 paramètres
|
||||||
// un fichier log existe?
|
// un fichier log existe?
|
||||||
if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
StringBuff(opt->path_log), "hts-in_progress.lock"))) { // fichier lock?
|
StringBuff(opt->path_log),
|
||||||
//char s[32];
|
"hts-in_progress.lock"))) { // fichier lock?
|
||||||
|
|
||||||
opt->cache = HTS_CACHE_PRIORITY; // cache prioritaire
|
opt->cache = HTS_CACHE_PRIORITY; // cache prioritaire
|
||||||
if (opt->quiet == 0) {
|
if (opt->quiet == 0) {
|
||||||
@@ -1044,11 +863,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
if (fexist
|
StringBuff(opt->path_html), "index.html"))) {
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_html), "index.html"))) {
|
|
||||||
//char s[32];
|
|
||||||
opt->cache = HTS_CACHE_TEST_UPDATE;
|
opt->cache = HTS_CACHE_TEST_UPDATE;
|
||||||
if (opt->quiet == 0) {
|
if (opt->quiet == 0) {
|
||||||
if ((fexist
|
if ((fexist
|
||||||
@@ -1143,7 +959,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
//
|
//
|
||||||
case 'g': // récupérer un (ou plusieurs) fichiers isolés
|
case 'g': // récupérer un (ou plusieurs) fichiers isolés
|
||||||
opt->wizard = HTS_WIZARD_AUTO;
|
opt->wizard = HTS_WIZARD_AUTO;
|
||||||
//opt->wizard=0; // pas de wizard
|
|
||||||
opt->cache = HTS_CACHE_NONE; // ni de cache
|
opt->cache = HTS_CACHE_NONE; // ni de cache
|
||||||
opt->makeindex = 0; // ni d'index
|
opt->makeindex = 0; // ni d'index
|
||||||
httrack_logmode = 1; // erreurs à l'écran
|
httrack_logmode = 1; // erreurs à l'écran
|
||||||
@@ -1243,9 +1058,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
while(isdigit((unsigned char) *(com + 1)))
|
while(isdigit((unsigned char) *(com + 1)))
|
||||||
com++;
|
com++;
|
||||||
break;
|
break;
|
||||||
//
|
|
||||||
//case 'A': opt->urlmode=1; break;
|
|
||||||
//case 'R': opt->urlmode=2; break;
|
|
||||||
case 'K':
|
case 'K':
|
||||||
opt->urlmode = HTS_URLMODE_ABSOLUTE;
|
opt->urlmode = HTS_URLMODE_ABSOLUTE;
|
||||||
if (isdigit((unsigned char) *(com + 1))) {
|
if (isdigit((unsigned char) *(com + 1))) {
|
||||||
@@ -1257,8 +1069,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
while(isdigit((unsigned char) *(com + 1)))
|
while(isdigit((unsigned char) *(com + 1)))
|
||||||
com++;
|
com++;
|
||||||
}
|
}
|
||||||
//if (*(com+1)=='0') { opt->urlmode=2; com++; } break;
|
|
||||||
//
|
|
||||||
case 'c':
|
case 'c':
|
||||||
if (isdigit((unsigned char) *(com + 1))) {
|
if (isdigit((unsigned char) *(com + 1))) {
|
||||||
sscanf(com + 1, "%d", &opt->maxsoc);
|
sscanf(com + 1, "%d", &opt->maxsoc);
|
||||||
@@ -1642,7 +1452,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
||||||
HTS_PANIC_PRINTF
|
HTS_PANIC_PRINTF
|
||||||
("Option %w needs to be followed by a blank space, and a module name");
|
("Option %w needs to be followed by a blank space, and a module name");
|
||||||
printf("Example: -%%w htsswf\n");
|
printf("Example: -%%w httrack-plugin\n");
|
||||||
htsmain_free();
|
htsmain_free();
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
@@ -1746,7 +1556,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
} else {
|
} else {
|
||||||
char *a;
|
char *a;
|
||||||
|
|
||||||
//char* b = StringBuff(opt->mimedefs) + StringLength(opt->mimedefs);
|
|
||||||
for(a = argv[na]; *a != '\0'; a++) {
|
for(a = argv[na]; *a != '\0'; a++) {
|
||||||
if (*a == ';') { /* next one */
|
if (*a == ';') { /* next one */
|
||||||
StringAddchar(opt->mimedefs, '\n');
|
StringAddchar(opt->mimedefs, '\n');
|
||||||
@@ -1994,6 +1803,23 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
StringCopy(opt->cookies_file, argv[na]);
|
StringCopy(opt->cookies_file, argv[na]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'Y': // why: explain the filter verdict for a URL, no crawl
|
||||||
|
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
||||||
|
HTS_PANIC_PRINTF("Option why needs a blank space and a URL");
|
||||||
|
printf(
|
||||||
|
"Example: --why \"http://www.example.com/file.zip\"\n");
|
||||||
|
htsmain_free();
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
na++;
|
||||||
|
if (strlen(argv[na]) >= HTS_URLMAXSIZE) {
|
||||||
|
HTS_PANIC_PRINTF("why URL too long");
|
||||||
|
htsmain_free();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
StringCopy(opt->why_url, argv[na]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'G': // pause: randomized inter-file delay MIN[:MAX] seconds
|
case 'G': // pause: randomized inter-file delay MIN[:MAX] seconds
|
||||||
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
||||||
HTS_PANIC_PRINTF("Option pause needs a blank space and a "
|
HTS_PANIC_PRINTF("Option pause needs a blank space and a "
|
||||||
@@ -2085,10 +1911,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
HTS_PANIC_PRINTF(s);
|
HTS_PANIC_PRINTF(s);
|
||||||
htsmain_free();
|
htsmain_free();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
|
|
||||||
//case 's': opt->sslengine=1; if (isdigit((unsigned char)*(com+1))) { sscanf(com+1,"%d",&opt->sslengine); while(isdigit((unsigned char)*(com+1))) com++; } break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2130,18 +1953,20 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
char BIGSTK url[HTS_URLMAXSIZE * 2];
|
char BIGSTK url[HTS_URLMAXSIZE * 2];
|
||||||
char linepos[256];
|
char linepos[256];
|
||||||
int pos;
|
int pos;
|
||||||
char *cacheNdx =
|
LLint cacheNdxLen = 0;
|
||||||
readfile(fconcat
|
char *cacheNdx = readfile2(
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
"hts-cache/new.ndx"));
|
StringBuff(opt->path_log), "hts-cache/new.ndx"),
|
||||||
|
&cacheNdxLen);
|
||||||
cache_init(&cache, opt); /* load cache */
|
cache_init(&cache, opt); /* load cache */
|
||||||
if (cacheNdx != NULL) {
|
if (cacheNdx != NULL) {
|
||||||
char firstline[256];
|
char firstline[256];
|
||||||
char *a = cacheNdx;
|
char *a = cacheNdx;
|
||||||
|
const char *const end = cacheNdx + cacheNdxLen;
|
||||||
|
|
||||||
a += cache_brstr(a, firstline, sizeof(firstline));
|
a += cache_brstr(a, firstline, sizeof(firstline));
|
||||||
a += cache_brstr(a, firstline, sizeof(firstline));
|
a += cache_brstr(a, firstline, sizeof(firstline));
|
||||||
while(a != NULL) {
|
while (a != NULL && a < end) {
|
||||||
a = strchr(a + 1, '\n'); /* start of line */
|
a = strchr(a + 1, '\n'); /* start of line */
|
||||||
if (a) {
|
if (a) {
|
||||||
htsblk r;
|
htsblk r;
|
||||||
@@ -2149,15 +1974,15 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
/* */
|
/* */
|
||||||
a++;
|
a++;
|
||||||
/* read "host/file" */
|
/* read "host/file" */
|
||||||
a += binput(a, afs.af.adr, HTS_URLMAXSIZE);
|
a += cache_binput(a, end, afs.af.adr, HTS_URLMAXSIZE);
|
||||||
a += binput(a, afs.af.fil, HTS_URLMAXSIZE);
|
a += cache_binput(a, end, afs.af.fil, HTS_URLMAXSIZE);
|
||||||
url[0] = '\0';
|
url[0] = '\0';
|
||||||
if (!link_has_authority(afs.af.adr))
|
if (!link_has_authority(afs.af.adr))
|
||||||
strcatbuff(url, "http://");
|
strcatbuff(url, "http://");
|
||||||
strcatbuff(url, afs.af.adr);
|
strcatbuff(url, afs.af.adr);
|
||||||
strcatbuff(url, afs.af.fil);
|
strcatbuff(url, afs.af.fil);
|
||||||
/* read position */
|
/* read position */
|
||||||
a += binput(a, linepos, 200);
|
a += cache_binput(a, end, linepos, 200);
|
||||||
sscanf(linepos, "%d", &pos);
|
sscanf(linepos, "%d", &pos);
|
||||||
if (!hasFilter
|
if (!hasFilter
|
||||||
|| (strjoker(url, filter, NULL, NULL) != NULL)
|
|| (strjoker(url, filter, NULL, NULL) != NULL)
|
||||||
@@ -2332,15 +2157,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case '~': /* internal lib test */
|
case '~': /* internal lib test */
|
||||||
HTS_PANIC_PRINTF
|
HTS_PANIC_PRINTF("Option #~ is disabled for security reasons");
|
||||||
("Option #~ is disabled for security reasons");
|
|
||||||
//Disabled because choke on GCC 4.3 (toni from links2linux.de)
|
|
||||||
//{
|
|
||||||
// char thisIsATestYouShouldSeeAnError[12];
|
|
||||||
// const char *const bufferOverflowTest = "0123456789012345678901234567890123456789";
|
|
||||||
// strcpybuff(thisIsATestYouShouldSeeAnError, bufferOverflowTest);
|
|
||||||
// return 0;
|
|
||||||
//}
|
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
opt->flush = 1;
|
opt->flush = 1;
|
||||||
@@ -2436,22 +2253,12 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
htsmain_free();
|
htsmain_free();
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
char *a;
|
char BIGSTK pname[HTS_URLMAXSIZE * 2];
|
||||||
|
|
||||||
na++;
|
na++;
|
||||||
opt->proxy.active = 1;
|
opt->proxy.active = 1;
|
||||||
// Rechercher MAIS en partant de la fin à cause de user:pass@proxy:port
|
hts_parse_proxy(argv[na], pname, sizeof(pname), &opt->proxy.port);
|
||||||
a = argv[na] + strlen(argv[na]) - 1;
|
StringCopy(opt->proxy.name, pname);
|
||||||
// a=strstr(argv[na],":"); // port
|
|
||||||
while((a > argv[na]) && (*a != ':') && (*a != '@'))
|
|
||||||
a--;
|
|
||||||
if (*a == ':') { // un port est présent, <proxy>:port
|
|
||||||
sscanf(a + 1, "%d", &opt->proxy.port);
|
|
||||||
StringCopyN(opt->proxy.name, argv[na], (int) (a - argv[na]));
|
|
||||||
} else { // <proxy>
|
|
||||||
opt->proxy.port = 8080;
|
|
||||||
StringCopy(opt->proxy.name, argv[na]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'F': // user-agent field
|
case 'F': // user-agent field
|
||||||
@@ -2547,116 +2354,14 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//printf("WARNING! This is *only* a beta-release of HTTrack\n");
|
|
||||||
io_flush;
|
io_flush;
|
||||||
|
|
||||||
#if DEBUG_STEPS
|
#if DEBUG_STEPS
|
||||||
printf("Cache & log settings\n");
|
printf("Cache & log settings\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// on utilise le cache..
|
// If both cache generations exist, keep the most complete one
|
||||||
// en cas de présence des deux versions, garder la version la plus avancée,
|
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
||||||
// cad la version contenant le plus de fichiers
|
|
||||||
if (opt->cache) {
|
|
||||||
if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-in_progress.lock"))) { // problemes..
|
|
||||||
if (fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"))) {
|
|
||||||
if (fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.zip"))) {
|
|
||||||
if (fsize
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.zip")) < 32768) {
|
|
||||||
if (fsize
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.zip")) > 65536) {
|
|
||||||
if (fsize
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.zip")) > fsize(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->
|
|
||||||
path_log),
|
|
||||||
"hts-cache/new.zip")))
|
|
||||||
{
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.zip"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.zip"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.zip"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
if (fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"))
|
|
||||||
&&
|
|
||||||
fexist(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx"))) {
|
|
||||||
if (fexist
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.dat"))
|
|
||||||
&&
|
|
||||||
fexist(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.ndx"))) {
|
|
||||||
// switcher si new<32Ko et old>65Ko (tailles arbitraires) ?
|
|
||||||
// ce cas est peut être une erreur ou un crash d'un miroir ancien, prendre
|
|
||||||
// alors l'ancien cache
|
|
||||||
if (fsize
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat")) < 32768) {
|
|
||||||
if (fsize
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.dat")) > 65536) {
|
|
||||||
if (fsize
|
|
||||||
(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.dat")) > fsize(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->
|
|
||||||
path_log),
|
|
||||||
"hts-cache/new.dat")))
|
|
||||||
{
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"));
|
|
||||||
remove(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.dat"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"));
|
|
||||||
rename(fconcat
|
|
||||||
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
|
||||||
"hts-cache/old.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx"));
|
|
||||||
//} else { // ne rien faire
|
|
||||||
// remove("hts-cache/old.dat");
|
|
||||||
// remove("hts-cache/old.ndx");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Débuggage des en têtes
|
// Débuggage des en têtes
|
||||||
if (_DEBUG_HEAD) {
|
if (_DEBUG_HEAD) {
|
||||||
ioinfo =
|
ioinfo =
|
||||||
@@ -2732,7 +2437,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
{
|
{
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
//int n=0;
|
|
||||||
char t[256];
|
char t[256];
|
||||||
|
|
||||||
time_local_rfc822(t); // faut bien que ca serve quelque part l'heure RFC1945 arf'
|
time_local_rfc822(t); // faut bien que ca serve quelque part l'heure RFC1945 arf'
|
||||||
@@ -2766,9 +2470,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
strcpybuff(n_lock,
|
strcpybuff(n_lock,
|
||||||
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
"hts-in_progress.lock"));
|
StringBuff(opt->path_log), "hts-in_progress.lock"));
|
||||||
//sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
|
|
||||||
/*do {
|
/*do {
|
||||||
if (!n)
|
if (!n)
|
||||||
sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
|
sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
|
||||||
@@ -2844,8 +2547,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
fprintf(fp, LF);
|
fprintf(fp, LF);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
//} else if (opt->debug>1) {
|
|
||||||
// printf("! FileOpen error, \"%s\"\n",strerror(errno));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// petit message dans le lock
|
// petit message dans le lock
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ typedef struct t_hts_callbackarg t_hts_callbackarg;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Marks a symbol an external wrapper module exports back to the engine.
|
/* Marks a symbol an external wrapper module exports back to the engine.
|
||||||
Must override -fvisibility=hidden on ELF, or dlopen()ed plugins (htsjava)
|
Must override -fvisibility=hidden on ELF, or dlopen()ed plugins
|
||||||
hide their own hts_plug()/hts_unplug() entry points. */
|
hide their own hts_plug()/hts_unplug() entry points. */
|
||||||
#ifndef EXTERNAL_FUNCTION
|
#ifndef EXTERNAL_FUNCTION
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@@ -133,9 +133,10 @@ static struct addrinfo *mock_mkai(const mock_addr *a) {
|
|||||||
return ai;
|
return ai;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mock_getaddrinfo(const char *node, const char *service,
|
static int HTS_RESOLVER_CALL mock_getaddrinfo(const char *node,
|
||||||
const struct addrinfo *hints,
|
const char *service,
|
||||||
struct addrinfo **res) {
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res) {
|
||||||
mock_host *const h = mock_find(node);
|
mock_host *const h = mock_find(node);
|
||||||
const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC;
|
const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC;
|
||||||
struct addrinfo *head = NULL, *tail = NULL;
|
struct addrinfo *head = NULL, *tail = NULL;
|
||||||
@@ -164,7 +165,7 @@ static int mock_getaddrinfo(const char *node, const char *service,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mock_freeaddrinfo(struct addrinfo *res) {
|
static void HTS_RESOLVER_CALL mock_freeaddrinfo(struct addrinfo *res) {
|
||||||
while (res != NULL) {
|
while (res != NULL) {
|
||||||
struct addrinfo *const next = res->ai_next;
|
struct addrinfo *const next = res->ai_next;
|
||||||
|
|
||||||
@@ -297,6 +298,26 @@ int dns_selftests(httrackp *opt) {
|
|||||||
IPV6_resolver = 0;
|
IPV6_resolver = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* "host:port" resolves as the bare host: the cache/connect path strips
|
||||||
|
":port" before both the backend and the cache key (#181). */
|
||||||
|
mock_reset_calls();
|
||||||
|
{
|
||||||
|
SOCaddr a;
|
||||||
|
char ip[64];
|
||||||
|
const char *err = NULL;
|
||||||
|
|
||||||
|
/* cache miss: the backend is hit with the stripped host, not "host:port" */
|
||||||
|
CHECK(hts_dns_resolve2(opt, "v6only.test:8080", &a, &err) != NULL);
|
||||||
|
CHECK(mock_find("v6only.test")->calls == 1);
|
||||||
|
/* the bare host shares that one cache entry (stripped key) */
|
||||||
|
CHECK(hts_dns_resolve2(opt, "v6only.test", &a, &err) != NULL);
|
||||||
|
CHECK(mock_find("v6only.test")->calls == 1);
|
||||||
|
/* a port variant of an already-cached host also hits, right address */
|
||||||
|
CHECK(hts_dns_resolve2(opt, "v4only.test:1234", &a, &err) != NULL);
|
||||||
|
SOCaddr_inetntoa(ip, sizeof(ip), a);
|
||||||
|
CHECK(strcmp(ip, "1.2.3.4") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* newhttp_addr() must connect to the addr_index-th address, not always the
|
/* newhttp_addr() must connect to the addr_index-th address, not always the
|
||||||
first: this is what back_connect_next relies on to reach the fallback. */
|
first: this is what back_connect_next relies on to reach the fallback. */
|
||||||
{
|
{
|
||||||
|
|||||||
170
src/htsfilters.c
170
src/htsfilters.c
@@ -48,6 +48,7 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htsbase.h"
|
#include "htsbase.h"
|
||||||
#include "htslib.h"
|
#include "htslib.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
/* END specific definitions */
|
/* END specific definitions */
|
||||||
|
|
||||||
// à partir d'un tableau de {"+*.toto","-*.zip","+*.tata"} définit si nom est autorisé
|
// à partir d'un tableau de {"+*.toto","-*.zip","+*.tata"} définit si nom est autorisé
|
||||||
@@ -94,17 +95,141 @@ int fa_strjoker(int type, char **filters, int nfil, const char *nom, LLint * siz
|
|||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
// supercomparateur joker (tm)
|
int fa_strjoker_dual(int type, char **filters, int nfil, const char *nom1,
|
||||||
// compare a et b (b=avec joker dedans), case insensitive [voir CI]
|
const char *nom2, LLint *size, int *size_flag,
|
||||||
// renvoi l'adresse de la première lettre de la chaine
|
int *depth) {
|
||||||
// (càd *[..]toto.. renvoi adresse de toto dans la chaine)
|
int depth1 = 0, depth2 = 0;
|
||||||
// accepte les délires du genre www.*.*/ * / * truc*.*
|
int flag1 = 0, flag2 = 0;
|
||||||
// cet algo est 'un peu' récursif mais ne consomme pas trop de tm
|
LLint sz1 = 0, sz2 = 0;
|
||||||
// * = toute lettre
|
int jok1, jok2, use1;
|
||||||
// --?-- : spécifique à HTTrack et aux ?
|
|
||||||
HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * size,
|
if (size) {
|
||||||
int *size_flag) {
|
sz1 = *size;
|
||||||
//int err=0;
|
sz2 = *size;
|
||||||
|
}
|
||||||
|
jok1 = fa_strjoker(type, filters, nfil, nom1, size ? &sz1 : NULL,
|
||||||
|
size_flag ? &flag1 : NULL, &depth1);
|
||||||
|
jok2 = fa_strjoker(type, filters, nfil, nom2, size ? &sz2 : NULL,
|
||||||
|
size_flag ? &flag2 : NULL, &depth2);
|
||||||
|
use1 = jok2 == 0 || (jok1 != 0 && depth1 >= depth2);
|
||||||
|
if (size)
|
||||||
|
*size = use1 ? sz1 : sz2;
|
||||||
|
if (size_flag)
|
||||||
|
*size_flag = use1 ? flag1 : flag2;
|
||||||
|
if (depth)
|
||||||
|
*depth = use1 ? depth1 : depth2;
|
||||||
|
return use1 ? jok1 : jok2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Real filters/URLs fit HTS_URLMAXSIZE*2; past it a hostile pattern recurses
|
||||||
|
O(len) deep or runs O(n^2*stars). Cap length (depth) and steps (work). */
|
||||||
|
#define STRJOKER_MAXLEN (HTS_URLMAXSIZE * 2)
|
||||||
|
#define STRJOKER_MAXSTEPS 2000000u
|
||||||
|
|
||||||
|
/* Failure memo for the recursive matcher: one bit per (chaine, joker) offset
|
||||||
|
pair keeps star-heavy patterns polynomial instead of exponential (#501). */
|
||||||
|
typedef struct strjoker_memo {
|
||||||
|
const char *chaine0, *joker0; /* offsets are relative to these bases */
|
||||||
|
size_t stride; /* strlen(joker0) + 1 */
|
||||||
|
unsigned char *failed; /* failed-pair bitmap; NULL: no memo */
|
||||||
|
size_t *nsteps; /* shared work counter; NULL: unbounded (oracle) */
|
||||||
|
} strjoker_memo;
|
||||||
|
|
||||||
|
static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine,
|
||||||
|
const char *joker, LLint *size,
|
||||||
|
int *size_flag);
|
||||||
|
|
||||||
|
/* A pair that failed once fails forever (*size is only written on the success
|
||||||
|
path), so record NULL results and cut the re-exploration. */
|
||||||
|
static const char *strjoker_rec(const strjoker_memo *memo, const char *chaine,
|
||||||
|
const char *joker, LLint *size,
|
||||||
|
int *size_flag) {
|
||||||
|
size_t bit = 0;
|
||||||
|
const char *adr;
|
||||||
|
|
||||||
|
if (memo->nsteps != NULL && ++*memo->nsteps > STRJOKER_MAXSTEPS)
|
||||||
|
return NULL; /* work budget spent: fail the match safely */
|
||||||
|
if (memo->failed) {
|
||||||
|
bit = (size_t) (chaine - memo->chaine0) * memo->stride +
|
||||||
|
(size_t) (joker - memo->joker0);
|
||||||
|
if (memo->failed[bit >> 3] & (unsigned char) (1u << (bit & 7)))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
adr = strjoker_impl(memo, chaine, joker, size, size_flag);
|
||||||
|
if (adr == NULL && memo->failed)
|
||||||
|
memo->failed[bit >> 3] |= (unsigned char) (1u << (bit & 7));
|
||||||
|
return adr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match chaine against joker with a shared work budget *nsteps (a strjokerfind
|
||||||
|
sweep passes one counter, bounding the whole scan). */
|
||||||
|
static const char *strjoker_bounded(const char *chaine, const char *joker,
|
||||||
|
LLint *size, int *size_flag,
|
||||||
|
size_t *nsteps) {
|
||||||
|
strjoker_memo memo = {chaine, joker, 0, NULL, nsteps};
|
||||||
|
unsigned char stackbits[2048];
|
||||||
|
hts_boolean onheap = HTS_FALSE;
|
||||||
|
const char *adr;
|
||||||
|
|
||||||
|
if (chaine != NULL && joker != NULL) {
|
||||||
|
const size_t l1 = strlen(chaine), l2 = strlen(joker);
|
||||||
|
|
||||||
|
if (l1 > STRJOKER_MAXLEN || l2 > STRJOKER_MAXLEN)
|
||||||
|
return NULL; /* beyond any real filter/URL: bound depth+work */
|
||||||
|
memo.stride = l2 + 1;
|
||||||
|
if (l1 + 1 <= (SIZE_MAX - 7) / memo.stride) { // overflow-safe bitmap size
|
||||||
|
const size_t bytes = ((l1 + 1) * memo.stride + 7) / 8;
|
||||||
|
|
||||||
|
if (bytes <= sizeof(stackbits)) {
|
||||||
|
memset(stackbits, 0, bytes);
|
||||||
|
memo.failed = stackbits;
|
||||||
|
} else {
|
||||||
|
memo.failed = (unsigned char *) calloct(bytes, 1);
|
||||||
|
onheap = memo.failed != NULL ? HTS_TRUE : HTS_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adr = strjoker_rec(&memo, chaine, joker, size, size_flag);
|
||||||
|
if (onheap)
|
||||||
|
freet(memo.failed);
|
||||||
|
return adr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wildcard comparator: match chaine against joker (pattern), case-insensitive
|
||||||
|
// returns the address of the first matched letter past any leading joker
|
||||||
|
// (ie. *[..]toto.. returns the address of toto within chaine), NULL on mismatch
|
||||||
|
HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
||||||
|
LLint *size, int *size_flag) {
|
||||||
|
size_t nsteps = 0;
|
||||||
|
|
||||||
|
return strjoker_bounded(chaine, joker, size, size_flag, &nsteps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test-only oracle: the same matcher without the failure memo. */
|
||||||
|
const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
|
||||||
|
int *size_flag) {
|
||||||
|
const strjoker_memo memo = {chaine, joker, 0, NULL};
|
||||||
|
|
||||||
|
return strjoker_rec(&memo, chaine, joker, size, size_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test-only: strjoker() reporting the work-budget steps spent and the cap, so a
|
||||||
|
self-test can prove the budget bounds a hostile pattern's work. */
|
||||||
|
const char *strjoker_steps(const char *chaine, const char *joker,
|
||||||
|
size_t *nsteps_out, size_t *maxsteps_out) {
|
||||||
|
size_t nsteps = 0;
|
||||||
|
const char *r = strjoker_bounded(chaine, joker, NULL, NULL, &nsteps);
|
||||||
|
|
||||||
|
if (nsteps_out != NULL)
|
||||||
|
*nsteps_out = nsteps;
|
||||||
|
if (maxsteps_out != NULL)
|
||||||
|
*maxsteps_out = STRJOKER_MAXSTEPS;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine,
|
||||||
|
const char *joker, LLint *size,
|
||||||
|
int *size_flag) {
|
||||||
if (strnotempty(joker) == 0) { // fin de chaine joker
|
if (strnotempty(joker) == 0) { // fin de chaine joker
|
||||||
if (strnotempty(chaine) == 0) // fin aussi pour la chaine: ok
|
if (strnotempty(chaine) == 0) // fin aussi pour la chaine: ok
|
||||||
return chaine;
|
return chaine;
|
||||||
@@ -236,9 +361,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
for(j = (int) (unsigned char) joker[i];
|
for(j = (int) (unsigned char) joker[i];
|
||||||
j <= (int) (unsigned char) joker[i + 2]; j++)
|
j <= (int) (unsigned char) joker[i + 2]; j++)
|
||||||
pass[j] = 1;
|
pass[j] = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
// else err=1;
|
|
||||||
i += 3;
|
i += 3;
|
||||||
} else { // 1 car, ex: *[ ]
|
} else { // 1 car, ex: *[ ]
|
||||||
pass[(int) (unsigned char) joker[i]] = 1;
|
pass[(int) (unsigned char) joker[i]] = 1;
|
||||||
@@ -262,7 +385,6 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
for(i = 0; i < 256; i++)
|
for(i = 0; i < 256; i++)
|
||||||
pass[i] = 1; // tout autoriser
|
pass[i] = 1; // tout autoriser
|
||||||
jmp = 1;
|
jmp = 1;
|
||||||
////if (joker[2]==LEFT) jmp=3; // permet de recher *<crochet ouvrant>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -281,7 +403,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
|
|
||||||
// tester sans le joker (pas ()+ mais ()*)
|
// tester sans le joker (pas ()+ mais ()*)
|
||||||
if (!unique) {
|
if (!unique) {
|
||||||
if ((adr = strjoker(chaine, joker + jmp, size, size_flag))) {
|
if ((adr = strjoker_rec(memo, chaine, joker + jmp, size, size_flag))) {
|
||||||
return adr;
|
return adr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,10 +412,11 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
if (!unique)
|
if (!unique)
|
||||||
max = (int) strlen(chaine);
|
max = (int) strlen(chaine);
|
||||||
else /* *(a) only match a (not aaaaa) */
|
else /* *(a) only match a (not aaaaa) */
|
||||||
max = 1;
|
max = strnotempty(chaine) ? 1 : 0; /* empty chaine: no char to eat */
|
||||||
while(i < (int) max) {
|
while(i < (int) max) {
|
||||||
if (pass[(int) (unsigned char) chaine[i]]) { // caractère autorisé
|
if (pass[(int) (unsigned char) chaine[i]]) { // caractère autorisé
|
||||||
if ((adr = strjoker(chaine + i + 1, joker + jmp, size, size_flag))) {
|
if ((adr = strjoker_rec(memo, chaine + i + 1, joker + jmp, size,
|
||||||
|
size_flag))) {
|
||||||
return adr;
|
return adr;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@@ -303,7 +426,8 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
|
|
||||||
// tester chaîne vide
|
// tester chaîne vide
|
||||||
if (i != max + 2) // avant c'est ok
|
if (i != max + 2) // avant c'est ok
|
||||||
if ((adr = strjoker(chaine + max, joker + jmp, size, size_flag)))
|
if ((adr = strjoker_rec(memo, chaine + max, joker + jmp, size,
|
||||||
|
size_flag)))
|
||||||
return adr;
|
return adr;
|
||||||
|
|
||||||
return NULL; // perdu
|
return NULL; // perdu
|
||||||
@@ -325,7 +449,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
// comparaison ok?
|
// comparaison ok?
|
||||||
if (ok) {
|
if (ok) {
|
||||||
// continuer la comparaison.
|
// continuer la comparaison.
|
||||||
if (strjoker(chaine + jmp, joker + jmp, size, size_flag))
|
if (strjoker_rec(memo, chaine + jmp, joker + jmp, size, size_flag))
|
||||||
return chaine; // retourner 1e lettre
|
return chaine; // retourner 1e lettre
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,12 +465,18 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
// d'un strcpy sur une variable ayant un nom en lettres et copiant une chaine de chiffres
|
// d'un strcpy sur une variable ayant un nom en lettres et copiant une chaine de chiffres
|
||||||
// ATTENTION!! Eviter les jokers en début, où gare au temps machine!
|
// ATTENTION!! Eviter les jokers en début, où gare au temps machine!
|
||||||
const char *strjokerfind(const char *chaine, const char *joker) {
|
const char *strjokerfind(const char *chaine, const char *joker) {
|
||||||
|
size_t nsteps = 0; /* one budget for the whole scan */
|
||||||
const char *adr;
|
const char *adr;
|
||||||
|
|
||||||
|
if (chaine != NULL && strlen(chaine) > STRJOKER_MAXLEN)
|
||||||
|
return NULL;
|
||||||
while(*chaine) {
|
while(*chaine) {
|
||||||
if ((adr = strjoker(chaine, joker, NULL, NULL))) { // ok trouvé
|
if ((adr = strjoker_bounded(chaine, joker, NULL, NULL,
|
||||||
|
&nsteps))) { // ok trouvé
|
||||||
return adr;
|
return adr;
|
||||||
}
|
}
|
||||||
|
if (nsteps > STRJOKER_MAXSTEPS) // scan budget spent: no match
|
||||||
|
return NULL;
|
||||||
chaine++;
|
chaine++;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -41,8 +41,21 @@ Please visit our Website: http://www.httrack.com
|
|||||||
|
|
||||||
int fa_strjoker(int type, char **filters, int nfil, const char *nom, LLint * size,
|
int fa_strjoker(int type, char **filters, int nfil, const char *nom, LLint * size,
|
||||||
int *size_flag, int *depth);
|
int *size_flag, int *depth);
|
||||||
|
/* fa_strjoker() on both URL forms the engine builds (nom1 full, nom2 without
|
||||||
|
scheme); the match latest in the list wins, a "don't know" verdict defers.
|
||||||
|
Returns the merged verdict; the out-params carry the winner's values. */
|
||||||
|
int fa_strjoker_dual(int type, char **filters, int nfil, const char *nom1,
|
||||||
|
const char *nom2, LLint *size, int *size_flag, int *depth);
|
||||||
HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * size,
|
HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * size,
|
||||||
int *size_flag);
|
int *size_flag);
|
||||||
|
/* strjoker() without the failure memo (exponential worst case); test-only
|
||||||
|
oracle for the memoized matcher. */
|
||||||
|
const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
|
||||||
|
int *size_flag);
|
||||||
|
/* strjoker() reporting the work-budget steps it spent and the cap; test-only,
|
||||||
|
lets a self-test assert the budget bounds a hostile pattern's work. */
|
||||||
|
const char *strjoker_steps(const char *chaine, const char *joker,
|
||||||
|
size_t *nsteps_out, size_t *maxsteps_out);
|
||||||
const char *strjokerfind(const char *chaine, const char *joker);
|
const char *strjokerfind(const char *chaine, const char *joker);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
135
src/htsftp.c
135
src/htsftp.c
@@ -54,15 +54,9 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ftp mode passif
|
// ftp mode passif
|
||||||
// #if HTS_INET6==0
|
|
||||||
#define FTP_PASV 1
|
#define FTP_PASV 1
|
||||||
// #else
|
|
||||||
// no passive mode for v6
|
|
||||||
// #define FTP_PASV 0
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
#define FTP_DEBUG 0
|
#define FTP_DEBUG 0
|
||||||
//#define FORK_DEBUG 0
|
|
||||||
|
|
||||||
#if USE_BEGINTHREAD
|
#if USE_BEGINTHREAD
|
||||||
|
|
||||||
@@ -206,20 +200,8 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
{
|
{
|
||||||
char *a;
|
char *a;
|
||||||
|
|
||||||
#if 0
|
|
||||||
a = back->url_fil + strlen(back->url_fil) - 1;
|
|
||||||
while((a > back->url_fil) && (*a != '/'))
|
|
||||||
a--;
|
|
||||||
if (*a != '/') {
|
|
||||||
a = NULL;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
a = back->url_fil;
|
a = back->url_fil;
|
||||||
#endif
|
|
||||||
if (a != NULL && *a != '\0') {
|
if (a != NULL && *a != '\0') {
|
||||||
#if 0
|
|
||||||
a++; // sauter /
|
|
||||||
#endif
|
|
||||||
ftp_filename = a;
|
ftp_filename = a;
|
||||||
if (strnotempty(a)) {
|
if (strnotempty(a)) {
|
||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
@@ -243,7 +225,6 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unexpected PORT error");
|
strcpybuff(back->r.msg, "Unexpected PORT error");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,7 +258,6 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
if (hts_dns_resolve2(opt, _adr, &server, &error) == NULL) {
|
if (hts_dns_resolve2(opt, _adr, &server, &error) == NULL) {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg),
|
snprintf(back->r.msg, sizeof(back->r.msg),
|
||||||
"Unable to get server's address: %s", error);
|
"Unable to get server's address: %s", error);
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_NON_FATAL;
|
back->r.statuscode = STATUSCODE_NON_FATAL;
|
||||||
_HALT_FTP return 0;
|
_HALT_FTP return 0;
|
||||||
}
|
}
|
||||||
@@ -290,20 +270,17 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
soc_ctl = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
|
soc_ctl = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
|
||||||
if (soc_ctl == INVALID_SOCKET) {
|
if (soc_ctl == INVALID_SOCKET) {
|
||||||
strcpybuff(back->r.msg, "Unable to create a socket");
|
strcpybuff(back->r.msg, "Unable to create a socket");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
_HALT_FTP return 0;
|
_HALT_FTP return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCaddr_initport(server, port);
|
SOCaddr_initport(server, port);
|
||||||
// server.sin_port = htons((unsigned short int) port);
|
|
||||||
|
|
||||||
// connexion (bloquante, on est en thread)
|
// connexion (bloquante, on est en thread)
|
||||||
strcpybuff(back->info, "connect");
|
strcpybuff(back->info, "connect");
|
||||||
|
|
||||||
if (connect(soc_ctl, &SOCaddr_sockaddr(server), SOCaddr_size(server)) != 0) {
|
if (connect(soc_ctl, &SOCaddr_sockaddr(server), SOCaddr_size(server)) != 0) {
|
||||||
strcpybuff(back->r.msg, "Unable to connect to the server");
|
strcpybuff(back->r.msg, "Unable to connect to the server");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
_HALT_FTP return 0;
|
_HALT_FTP return 0;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -345,64 +322,22 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "TYPE I error");
|
strcpybuff(back->r.msg, "TYPE I error");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
// --CWD--
|
|
||||||
char *a;
|
|
||||||
|
|
||||||
a = back->url_fil + strlen(back->url_fil) - 1;
|
|
||||||
while((a > back->url_fil) && (*a != '/'))
|
|
||||||
a--;
|
|
||||||
if (*a == '/') { // ok repéré
|
|
||||||
char BIGSTK target[1024];
|
|
||||||
|
|
||||||
target[0] = '\0';
|
|
||||||
strncatbuff(target, back->url_fil, (int) (a - back->url_fil));
|
|
||||||
if (strnotempty(target) == 0)
|
|
||||||
strcatbuff(target, "/");
|
|
||||||
strcpybuff(back->info, "cwd");
|
|
||||||
snprintf(line, sizeof(line), "CWD %s", target);
|
|
||||||
send_line(soc_ctl, line);
|
|
||||||
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
|
||||||
_CHECK_HALT_FTP;
|
|
||||||
if (line[0] == '2') {
|
|
||||||
send_line(soc_ctl, "TYPE I");
|
|
||||||
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
|
||||||
_CHECK_HALT_FTP;
|
|
||||||
if (line[0] == '2') {
|
|
||||||
// ok..
|
|
||||||
} else {
|
|
||||||
strcpybuff(back->r.msg, "TYPE I error");
|
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "CWD error: %s", linejmp(line));
|
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
|
||||||
} // sinon on est prêts
|
|
||||||
} else {
|
|
||||||
strcpybuff(back->r.msg, "Unexpected ftp error");
|
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Bad password: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "Bad password: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Bad user name: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "Bad user name: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Connection refused: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "Connection refused: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,8 +404,8 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
// -- fin analyse de l'adresse IP et du port --
|
// -- fin analyse de l'adresse IP et du port --
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
@@ -501,13 +436,13 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "EPSV incorrect: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "EPSV incorrect: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PASV/EPSV error: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "PASV/EPSV error: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
}
|
}
|
||||||
@@ -613,9 +548,8 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
deletesoc(soc_dat);
|
deletesoc(soc_dat);
|
||||||
soc_dat = INVALID_SOCKET;
|
soc_dat = INVALID_SOCKET;
|
||||||
//
|
//
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "RETR command error: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg),
|
||||||
linejmp(line));
|
"RETR command error: %s", linejmp(line));
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
@@ -626,23 +560,20 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
soc_dat = INVALID_SOCKET;
|
soc_dat = INVALID_SOCKET;
|
||||||
//
|
//
|
||||||
strcpybuff(back->r.msg, "Unable to connect");
|
strcpybuff(back->r.msg, "Unable to connect");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unable to create a socket");
|
strcpybuff(back->r.msg, "Unable to create a socket");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg),
|
snprintf(back->r.msg, sizeof(back->r.msg),
|
||||||
"Unable to resolve IP %s: %s", adr_ip, error);
|
"Unable to resolve IP %s: %s", adr_ip, error);
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
#else
|
#else
|
||||||
@@ -663,17 +594,16 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
//T_SOC soc_dat;
|
//T_SOC soc_dat;
|
||||||
if ((soc_dat = accept(soc_servdat, NULL, NULL)) == INVALID_SOCKET) {
|
if ((soc_dat = accept(soc_servdat, NULL, NULL)) == INVALID_SOCKET) {
|
||||||
strcpybuff(back->r.msg, "Unable to accept connection");
|
strcpybuff(back->r.msg, "Unable to accept connection");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "RETR command error: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg),
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
"RETR command error: %s", linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PORT command error: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "PORT command error: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -683,7 +613,6 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unable to listen to a port");
|
strcpybuff(back->r.msg, "Unable to listen to a port");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -707,21 +636,18 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
int len = 1;
|
int len = 1;
|
||||||
int read_len = 1024;
|
int read_len = 1024;
|
||||||
|
|
||||||
//HTS_TOTAL_RECV_CHECK(read_len); // Diminuer au besoin si trop de données reçues
|
|
||||||
|
|
||||||
while((len > 0) && (!stop_ftp(back))) {
|
while((len > 0) && (!stop_ftp(back))) {
|
||||||
// attendre les données
|
// attendre les données
|
||||||
len = 1; // pas d'erreur pour le moment
|
len = 1; // pas d'erreur pour le moment
|
||||||
switch (wait_socket_receive(soc_dat, timeout)) {
|
switch (wait_socket_receive(soc_dat, timeout)) {
|
||||||
case -1:
|
case -1:
|
||||||
strcpybuff(back->r.msg, "FTP read error");
|
strcpybuff(back->r.msg, "FTP read error");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
len = 0; // fin
|
len = 0; // fin
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Time out (%d)", timeout);
|
snprintf(back->r.msg, sizeof(back->r.msg), "Time out (%d)",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
timeout);
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
len = 0; // fin
|
len = 0; // fin
|
||||||
break;
|
break;
|
||||||
@@ -743,17 +669,14 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
strcpybuff(back->r.msg, "Write error");
|
strcpybuff(back->r.msg, "Write error");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
len = 0; // error
|
len = 0; // error
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unexpected write error");
|
strcpybuff(back->r.msg, "Unexpected write error");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else { // Erreur ou terminé
|
} else { // Erreur ou terminé
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = 0;
|
back->r.statuscode = 0;
|
||||||
if (back->r.totalsize > 0
|
if (back->r.totalsize > 0
|
||||||
&& back->r.size != back->r.totalsize) {
|
&& back->r.size != back->r.totalsize) {
|
||||||
@@ -762,7 +685,6 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_len = 1024;
|
read_len = 1024;
|
||||||
//HTS_TOTAL_RECV_CHECK(read_len); // Diminuer au besoin si trop de données reçues
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (back->r.fp) {
|
if (back->r.fp) {
|
||||||
@@ -771,7 +693,6 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unable to write file");
|
strcpybuff(back->r.msg, "Unable to write file");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -787,16 +708,14 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
||||||
if (line[0] == '2') { // OK
|
if (line[0] == '2') { // OK
|
||||||
strcpybuff(back->r.msg, "OK");
|
strcpybuff(back->r.msg, "OK");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = HTTP_OK;
|
back->r.statuscode = HTTP_OK;
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "RETR incorrect: %s", linejmp(line));
|
snprintf(back->r.msg, sizeof(back->r.msg), "RETR incorrect: %s",
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
linejmp(line));
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "FTP read error");
|
strcpybuff(back->r.msg, "FTP read error");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -822,7 +741,6 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
back->r.statuscode = HTTP_OK;
|
back->r.statuscode = HTTP_OK;
|
||||||
strcpybuff(back->r.msg, "OK");
|
strcpybuff(back->r.msg, "OK");
|
||||||
}
|
}
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,9 +907,7 @@ int get_ftp_line(T_SOC soc, char *ptrline, size_t line_size, int timeout) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//HTS_TOTAL_RECV_CHECK(dummy); // Diminuer au besoin si trop de données reçues
|
|
||||||
switch (recv(soc, &b, 1, 0)) {
|
switch (recv(soc, &b, 1, 0)) {
|
||||||
//case 0: break; // pas encore --> erreur (on attend)!
|
|
||||||
case 1:
|
case 1:
|
||||||
HTS_STAT.HTS_TOTAL_RECV += 1; // compter flux entrant
|
HTS_STAT.HTS_TOTAL_RECV += 1; // compter flux entrant
|
||||||
if ((b != 10) && (b != 13) && (i < (int) sizeof(data) - 1))
|
if ((b != 10) && (b != 13) && (i < (int) sizeof(data) - 1))
|
||||||
@@ -1118,7 +1034,6 @@ int wait_socket_receive(T_SOC soc, int timeout) {
|
|||||||
int stop_ftp(lien_back * back) {
|
int stop_ftp(lien_back * back) {
|
||||||
if (back->stop_ftp) {
|
if (back->stop_ftp) {
|
||||||
strcpybuff(back->r.msg, "Cancelled by User");
|
strcpybuff(back->r.msg, "Cancelled by User");
|
||||||
// back->status=STATUS_FTP_READY; // fini
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
103
src/htsglobal.h
103
src/htsglobal.h
@@ -43,8 +43,8 @@ Please visit our Website: http://www.httrack.com
|
|||||||
configure.ac, decoupled from these). VERSION is the display form, VERSIONID
|
configure.ac, decoupled from these). VERSION is the display form, VERSIONID
|
||||||
the dotted numeric form, AFF_VERSION the short form shown in footers,
|
the dotted numeric form, AFF_VERSION the short form shown in footers,
|
||||||
LIB_VERSION the data/cache format generation. */
|
LIB_VERSION the data/cache format generation. */
|
||||||
#define HTTRACK_VERSION "3.49-10"
|
#define HTTRACK_VERSION "3.49-12"
|
||||||
#define HTTRACK_VERSIONID "3.49.10"
|
#define HTTRACK_VERSIONID "3.49.12"
|
||||||
#define HTTRACK_AFF_VERSION "3.x"
|
#define HTTRACK_AFF_VERSION "3.x"
|
||||||
#define HTTRACK_LIB_VERSION "2.0"
|
#define HTTRACK_LIB_VERSION "2.0"
|
||||||
|
|
||||||
@@ -56,6 +56,10 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// Platform detection (sizes, feature macros)
|
// Platform detection (sizes, feature macros)
|
||||||
#include "htsconfig.h"
|
#include "htsconfig.h"
|
||||||
|
|
||||||
|
// Fixed-width integer types + PRI* format macros for the LLint/TStamp typedefs
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
// WIN32 types
|
// WIN32 types
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef SIZEOF_LONG
|
#ifndef SIZEOF_LONG
|
||||||
@@ -111,29 +115,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#define HTS_DO_NOT_USE_UID
|
#define HTS_DO_NOT_USE_UID
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HTS_LONGLONG
|
|
||||||
#ifdef SIZEOF_LONG_LONG
|
|
||||||
#if SIZEOF_LONG_LONG == 8
|
|
||||||
#define HTS_LONGLONG 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HTS_LONGLONG
|
|
||||||
#ifdef __sun
|
|
||||||
#define HTS_LONGLONG 0
|
|
||||||
#endif
|
|
||||||
#ifdef __osf__
|
|
||||||
#define HTS_LONGLONG 0
|
|
||||||
#endif
|
|
||||||
#ifdef __linux
|
|
||||||
#define HTS_LONGLONG 1
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define HTS_LONGLONG 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DLLIB
|
#ifdef DLLIB
|
||||||
#define HTS_DLOPEN 1
|
#define HTS_DLOPEN 1
|
||||||
#else
|
#else
|
||||||
@@ -159,6 +140,15 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#define HTS_USEZLIB 1
|
#define HTS_USEZLIB 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// brotli and zstd content codings; off unless the build opted in (configure,
|
||||||
|
// or the Visual Studio projects, which link the vcpkg libraries)
|
||||||
|
#ifndef HTS_USEBROTLI
|
||||||
|
#define HTS_USEBROTLI 0
|
||||||
|
#endif
|
||||||
|
#ifndef HTS_USEZSTD
|
||||||
|
#define HTS_USEZSTD 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HTS_INET6
|
#ifndef HTS_INET6
|
||||||
#define HTS_INET6 0
|
#define HTS_INET6 0
|
||||||
#endif
|
#endif
|
||||||
@@ -326,59 +316,11 @@ typedef int hts_tristate;
|
|||||||
#define HTS_DEPRECATED(msg)
|
#define HTS_DEPRECATED(msg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HTS_LONGLONG
|
/* LLint/TStamp: signed exact-width 64-bit; -1 is a sentinel engine-wide. */
|
||||||
#ifdef HTS_NO_64_BIT
|
typedef int64_t LLint;
|
||||||
#define HTS_LONGLONG 0
|
typedef int64_t TStamp;
|
||||||
#else
|
/* Full printf conversion, '%' included (PRId64 has none): "X: " LLintP. */
|
||||||
#define HTS_LONGLONG 1
|
#define LLintP "%" PRId64
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Wide integer types, chosen per platform.
|
|
||||||
LLint: signed 64-bit counter for byte counts and large sizes (falls back to
|
|
||||||
plain int where 64-bit is unavailable).
|
|
||||||
TStamp: timestamp/duration in the same width (a double in the no-64-bit
|
|
||||||
fallback).
|
|
||||||
LLintP: the printf conversion for an LLint. */
|
|
||||||
#if HTS_LONGLONG
|
|
||||||
#ifdef LLINT_FORMAT
|
|
||||||
typedef LLINT_TYPE LLint;
|
|
||||||
|
|
||||||
typedef LLINT_TYPE TStamp;
|
|
||||||
|
|
||||||
#define LLintP LLINT_FORMAT
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
typedef __int64 LLint;
|
|
||||||
|
|
||||||
typedef __int64 TStamp;
|
|
||||||
|
|
||||||
#define LLintP "%I64d"
|
|
||||||
#elif (defined(_LP64) || defined(__x86_64__) || defined(__powerpc64__) || \
|
|
||||||
defined(__64BIT__))
|
|
||||||
|
|
||||||
typedef long int LLint;
|
|
||||||
|
|
||||||
typedef long int TStamp;
|
|
||||||
|
|
||||||
#define LLintP "%ld"
|
|
||||||
#else
|
|
||||||
typedef long long int LLint;
|
|
||||||
|
|
||||||
typedef long long int TStamp;
|
|
||||||
|
|
||||||
#define LLintP "%lld"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* HTS_LONGLONG */
|
|
||||||
|
|
||||||
#else
|
|
||||||
typedef int LLint;
|
|
||||||
|
|
||||||
#define LLintP "%d"
|
|
||||||
typedef double TStamp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Integer type for file offsets/sizes passed to the C library. Widens to
|
/* Integer type for file offsets/sizes passed to the C library. Widens to
|
||||||
LLint (with HTS_FSEEKO for fseeko/ftello) under large-file support, plain
|
LLint (with HTS_FSEEKO for fseeko/ftello) under large-file support, plain
|
||||||
@@ -422,9 +364,10 @@ typedef int T_SOC;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Permission bits for created folders and files (mkdir and chmod).
|
/* Permission bits for created folders and files (mkdir and chmod).
|
||||||
PROTECT_FOLDER is owner-only. With HTS_ACCESS set (the default) the ACCESS_
|
PROTECT_FOLDER/FILE are owner-only. With HTS_ACCESS set (the default) the
|
||||||
modes also grant group/other read; otherwise they stay owner-only. */
|
ACCESS_ modes also grant group/other read; otherwise they stay owner-only. */
|
||||||
#define HTS_PROTECT_FOLDER (S_IRUSR | S_IWUSR | S_IXUSR)
|
#define HTS_PROTECT_FOLDER (S_IRUSR | S_IWUSR | S_IXUSR)
|
||||||
|
#define HTS_PROTECT_FILE (S_IRUSR | S_IWUSR)
|
||||||
|
|
||||||
#if HTS_ACCESS
|
#if HTS_ACCESS
|
||||||
#define HTS_ACCESS_FILE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
|
#define HTS_ACCESS_FILE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
|
||||||
|
|||||||
@@ -152,16 +152,6 @@ void help_wizard(httrackp * opt) {
|
|||||||
#define str (buffers->str)
|
#define str (buffers->str)
|
||||||
#define argv (buffers->argv)
|
#define argv (buffers->argv)
|
||||||
|
|
||||||
//char *urls = (char *) malloct(HTS_URLMAXSIZE * 2);
|
|
||||||
//char *mainpath = (char *) malloct(256);
|
|
||||||
//char *projname = (char *) malloct(256);
|
|
||||||
//char *stropt = (char *) malloct(2048); // options
|
|
||||||
//char *stropt2 = (char *) malloct(2048); // options longues
|
|
||||||
//char *strwild = (char *) malloct(2048); // wildcards
|
|
||||||
//char *cmd = (char *) malloct(4096);
|
|
||||||
//char *str = (char *) malloct(256);
|
|
||||||
//char **argv = (char **) malloct(256 * sizeof(char *));
|
|
||||||
|
|
||||||
//
|
//
|
||||||
char *a;
|
char *a;
|
||||||
|
|
||||||
@@ -227,8 +217,6 @@ void help_wizard(httrackp * opt) {
|
|||||||
strcatbuff(stropt2, str);
|
strcatbuff(stropt2, str);
|
||||||
strcatbuff(stropt2, projname);
|
strcatbuff(stropt2, projname);
|
||||||
strcatbuff(stropt2, "\" ");
|
strcatbuff(stropt2, "\" ");
|
||||||
// Créer si ce n'est fait un index.html 1er niveau
|
|
||||||
make_empty_index(str);
|
|
||||||
//
|
//
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Enter URLs (separated by commas or blank spaces) :");
|
printf("Enter URLs (separated by commas or blank spaces) :");
|
||||||
@@ -349,8 +337,6 @@ void help_wizard(httrackp * opt) {
|
|||||||
}
|
}
|
||||||
hts_main(argc, argv);
|
hts_main(argc, argv);
|
||||||
}
|
}
|
||||||
//} else {
|
|
||||||
// help("httrack",1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free buffers */
|
/* Free buffers */
|
||||||
@@ -455,23 +441,6 @@ void help_catchurl(const char *dest_path) {
|
|||||||
printf("Unable to create a temporary proxy (no remaining port)\n");
|
printf("Unable to create a temporary proxy (no remaining port)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Créer un index.html vide
|
|
||||||
void make_empty_index(const char *str) {
|
|
||||||
#if 0
|
|
||||||
if (!fexist(fconcat(str, "index.html"))) {
|
|
||||||
FILE *fp = fopen(fconcat(str, "index.html"), "wb");
|
|
||||||
|
|
||||||
if (fp) {
|
|
||||||
fprintf(fp, "<!-- " HTS_TOPINDEX " -->" CRLF);
|
|
||||||
fprintf(fp,
|
|
||||||
"<HTML><BODY>Index is empty!<BR>(File used to index all HTTrack projects)</BODY></HTML>"
|
|
||||||
CRLF);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// mini-aide (h: help)
|
// mini-aide (h: help)
|
||||||
// y
|
// y
|
||||||
void help(const char *app, int more) {
|
void help(const char *app, int more) {
|
||||||
@@ -508,7 +477,7 @@ void help(const char *app, int more) {
|
|||||||
(" Y mirror ALL links located in the first level pages (mirror links)");
|
(" Y mirror ALL links located in the first level pages (mirror links)");
|
||||||
infomsg("");
|
infomsg("");
|
||||||
infomsg("Proxy options:");
|
infomsg("Proxy options:");
|
||||||
infomsg(" P proxy use (-P proxy:port or -P user:pass@proxy:port)");
|
infomsg(" P proxy use (-P [socks5://][user:pass@]proxy:port)");
|
||||||
infomsg(" %f *use proxy for ftp (f0 don't use)");
|
infomsg(" %f *use proxy for ftp (f0 don't use)");
|
||||||
infomsg(" %b use this local hostname to make/send requests (-%b hostname)");
|
infomsg(" %b use this local hostname to make/send requests (-%b hostname)");
|
||||||
infomsg("");
|
infomsg("");
|
||||||
@@ -574,10 +543,11 @@ void help(const char *app, int more) {
|
|||||||
infomsg("Spider options:");
|
infomsg("Spider options:");
|
||||||
infomsg(" bN accept cookies in cookies.txt (0=do not accept,* 1=accept)");
|
infomsg(" bN accept cookies in cookies.txt (0=do not accept,* 1=accept)");
|
||||||
infomsg(" %K load extra cookies from a Netscape cookies.txt");
|
infomsg(" %K load extra cookies from a Netscape cookies.txt");
|
||||||
|
infomsg(" %Y explain which filter rule accepts or rejects a URL, then exit");
|
||||||
infomsg
|
infomsg
|
||||||
(" u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always)");
|
(" u check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always)");
|
||||||
infomsg
|
infomsg(" j *parse scripts (j0 don't parse, bitmask: |1 parse default, |4 "
|
||||||
(" j *parse Java Classes (j0 don't parse, bitmask: |1 parse default, |2 don't parse .class |4 don't parse .js |8 don't be aggressive)");
|
"don't parse .js |8 don't be aggressive)");
|
||||||
infomsg
|
infomsg
|
||||||
(" sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always, 3=always (even strict rules))");
|
(" sN follow robots.txt and meta robots tags (0=never,1=sometimes,* 2=always, 3=always (even strict rules))");
|
||||||
infomsg
|
infomsg
|
||||||
@@ -601,8 +571,7 @@ void help(const char *app, int more) {
|
|||||||
(" can also be used to force a specific file type: --assume foo.cgi=text/html");
|
(" can also be used to force a specific file type: --assume foo.cgi=text/html");
|
||||||
infomsg
|
infomsg
|
||||||
(" @iN internet protocol (0=both ipv6+ipv4, 4=ipv4 only, 6=ipv6 only)");
|
(" @iN internet protocol (0=both ipv6+ipv4, 4=ipv4 only, 6=ipv6 only)");
|
||||||
infomsg
|
infomsg(" %w disable a specific external mime module (-%w httrack-plugin)");
|
||||||
(" %w disable a specific external mime module (-%w htsswf -%w htsjava)");
|
|
||||||
infomsg("");
|
infomsg("");
|
||||||
infomsg("Browser ID:");
|
infomsg("Browser ID:");
|
||||||
infomsg
|
infomsg
|
||||||
@@ -808,7 +777,4 @@ void help(const char *app, int more) {
|
|||||||
infomsg("[compiled: " HTS_PLATFORM_NAME "]");
|
infomsg("[compiled: " HTS_PLATFORM_NAME "]");
|
||||||
#endif
|
#endif
|
||||||
infomsg(NULL);
|
infomsg(NULL);
|
||||||
|
|
||||||
// infomsg(" R *relative links (e.g ../link)\n");
|
|
||||||
// infomsg(" A absolute links (e.g /www.adr/link)\n");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ typedef struct httrackp httrackp;
|
|||||||
|
|
||||||
void infomsg(const char *msg);
|
void infomsg(const char *msg);
|
||||||
void help(const char *app, int more);
|
void help(const char *app, int more);
|
||||||
void make_empty_index(const char *str);
|
|
||||||
void help_wizard(httrackp * opt);
|
void help_wizard(httrackp * opt);
|
||||||
int help_query(const char *list, int def);
|
int help_query(const char *list, int def);
|
||||||
void help_catchurl(const char *dest_path);
|
void help_catchurl(const char *dest_path);
|
||||||
|
|||||||
@@ -142,8 +142,6 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
char keyword[KEYW_LEN + 32];
|
char keyword[KEYW_LEN + 32];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
//
|
|
||||||
//int WordIndexSize = 1024;
|
|
||||||
coucal WordIndexHash = NULL;
|
coucal WordIndexHash = NULL;
|
||||||
FILE *tmpfp = NULL;
|
FILE *tmpfp = NULL;
|
||||||
|
|
||||||
@@ -178,8 +176,6 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
|| (strfield2(mime, "text/css"))
|
|| (strfield2(mime, "text/css"))
|
||||||
) {
|
) {
|
||||||
inscript = 1;
|
inscript = 1;
|
||||||
//} else if (strfield2(mime, "text/vnd.wap.wml")) { // humm won't work in many cases
|
|
||||||
// inscript=0;
|
|
||||||
} else
|
} else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -275,8 +271,6 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
|
|
||||||
// Process indexing for this page
|
// Process indexing for this page
|
||||||
{
|
{
|
||||||
//FILE* fp=NULL;
|
|
||||||
//fp=fopen(concat(indexpath,"index.txt"),"ab");
|
|
||||||
if (fp_tmpproject) {
|
if (fp_tmpproject) {
|
||||||
while(!feof(tmpfp)) {
|
while(!feof(tmpfp)) {
|
||||||
char line[KEYW_LEN + 32];
|
char line[KEYW_LEN + 32];
|
||||||
@@ -286,7 +280,6 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
intptr_t e = 0;
|
intptr_t e = 0;
|
||||||
|
|
||||||
if (coucal_read(WordIndexHash, line, &e)) {
|
if (coucal_read(WordIndexHash, line, &e)) {
|
||||||
//if (e) {
|
|
||||||
char BIGSTK savelst[HTS_URLMAXSIZE * 2];
|
char BIGSTK savelst[HTS_URLMAXSIZE * 2];
|
||||||
|
|
||||||
e++; /* 0 means "once" */
|
e++; /* 0 means "once" */
|
||||||
@@ -300,11 +293,9 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
fprintf(fp_tmpproject, "%s %d %s\n", line,
|
fprintf(fp_tmpproject, "%s %d %s\n", line,
|
||||||
(int) (KEYW_SORT_MAXCOUNT - e), savelst);
|
(int) (KEYW_SORT_MAXCOUNT - e), savelst);
|
||||||
hts_primindex_size++;
|
hts_primindex_size++;
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//fclose(fp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +321,6 @@ void index_finish(const char *indexpath, int mode) {
|
|||||||
off_t size = fpsize(fp_tmpproject);
|
off_t size = fpsize(fp_tmpproject);
|
||||||
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
//FILE* fp=fopen(concat(indexpath,"index.txt"),"rb");
|
|
||||||
if (fp_tmpproject) {
|
if (fp_tmpproject) {
|
||||||
tab = (char **) malloct(sizeof(char *) * (hts_primindex_size + 2));
|
tab = (char **) malloct(sizeof(char *) * (hts_primindex_size + 2));
|
||||||
if (tab) {
|
if (tab) {
|
||||||
@@ -398,8 +388,6 @@ void index_finish(const char *indexpath, int mode) {
|
|||||||
if (total_hit) {
|
if (total_hit) {
|
||||||
if (mode == 1) // TEXT
|
if (mode == 1) // TEXT
|
||||||
fprintf(fp, "\t=%d\r\n", total_hit);
|
fprintf(fp, "\t=%d\r\n", total_hit);
|
||||||
//else // HTML
|
|
||||||
// fprintf(fp,"<br>(%d total hits)\r\n",total_hit);
|
|
||||||
if ((((total_hit * 1000) / hts_primindex_words) >=
|
if ((((total_hit * 1000) / hts_primindex_words) >=
|
||||||
KEYW_USELESS1K)
|
KEYW_USELESS1K)
|
||||||
|| (((total_line * 1000) / index) >=
|
|| (((total_line * 1000) / index) >=
|
||||||
@@ -416,8 +404,6 @@ void index_finish(const char *indexpath, int mode) {
|
|||||||
if (mode == 1) // TEXT
|
if (mode == 1) // TEXT
|
||||||
fprintf(fp, "\t(%d)\r\n",
|
fprintf(fp, "\t(%d)\r\n",
|
||||||
((total_hit * 1000) / hts_primindex_words));
|
((total_hit * 1000) / hts_primindex_words));
|
||||||
//else // HTML
|
|
||||||
// fprintf(fp,"(%d)\r\n",((total_hit*1000)/hts_primindex_words));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mode == 1) // TEXT
|
if (mode == 1) // TEXT
|
||||||
|
|||||||
528
src/htsjava.c
528
src/htsjava.c
@@ -1,528 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* File: Java classes parser */
|
|
||||||
/* Author: Yann Philippot */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
|
|
||||||
/* Version: Oct/2000 */
|
|
||||||
/* Fixed: problems with class structure (10/2000) */
|
|
||||||
|
|
||||||
// htsjava.c - Parseur de classes java
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#if ( defined(_WIN32) ||defined(HAVE_SYS_TYPES_H) )
|
|
||||||
#include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Standard httrack module includes */
|
|
||||||
#include "httrack-library.h"
|
|
||||||
#include "htsopt.h"
|
|
||||||
#include "htsdefines.h"
|
|
||||||
|
|
||||||
/* Module structures */
|
|
||||||
#include "htsmodules.h"
|
|
||||||
|
|
||||||
/* We link to libhttrack, we can use its functions */
|
|
||||||
#include "httrack-library.h"
|
|
||||||
|
|
||||||
/* This file */
|
|
||||||
#include "htsjava.h"
|
|
||||||
|
|
||||||
/* calloct/freet wrappers */
|
|
||||||
#include "htssafe.h"
|
|
||||||
|
|
||||||
static int reverse_endian(void) {
|
|
||||||
int endian = 1;
|
|
||||||
|
|
||||||
return (*((char *) &endian) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* big/little endian swap */
|
|
||||||
#define hts_swap16(A) ( (((A) & 0xFF)<<8) | (((A) & 0xFF00)>>8) )
|
|
||||||
#define hts_swap32(A) ( (( (hts_swap16(A)) & 0xFFFF)<<16) | (( (hts_swap16(A>>16)) & 0xFFFF)) )
|
|
||||||
|
|
||||||
/* Static definitions */
|
|
||||||
static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp, RESP_STRUCT,
|
|
||||||
int *);
|
|
||||||
static unsigned short int readshort(FILE * fp);
|
|
||||||
static int tris(httrackp * opt, char *);
|
|
||||||
static char *printname(char[1024], char[1024]);
|
|
||||||
|
|
||||||
// ** HTS_xx sinon pas pris par VC++
|
|
||||||
#define HTS_CLASS 7
|
|
||||||
#define HTS_FIELDREF 9
|
|
||||||
#define HTS_METHODREF 10
|
|
||||||
#define HTS_STRING 8
|
|
||||||
#define HTS_INTEGER 3
|
|
||||||
#define HTS_FLOAT 4
|
|
||||||
#define HTS_LONG 5
|
|
||||||
#define HTS_DOUBLE 6
|
|
||||||
#define HTS_INTERFACE 11
|
|
||||||
#define HTS_NAMEANDTYPE 12
|
|
||||||
#define HTS_ASCIZ 1
|
|
||||||
#define HTS_UNICODE 2
|
|
||||||
|
|
||||||
#define JAVADEBUG 0
|
|
||||||
|
|
||||||
static const char *libName = "htsjava";
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define strcasecmp(a,b) stricmp(a,b)
|
|
||||||
#define strncasecmp(a,b,n) strnicmp(a,b,n)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int detect_mime(htsmoduleStruct * str) {
|
|
||||||
const char *savename = str->filename;
|
|
||||||
|
|
||||||
if (savename) {
|
|
||||||
int len = (int) strlen(savename);
|
|
||||||
|
|
||||||
if (len > 6 && strcasecmp(savename + len - 6, ".class") == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hts_detect_java(t_hts_callbackarg * carg, httrackp * opt,
|
|
||||||
htsmoduleStruct * str) {
|
|
||||||
/* Call parent functions if multiple callbacks are chained. */
|
|
||||||
if (CALLBACKARG_PREV_FUN(carg, detect) != NULL) {
|
|
||||||
if (CALLBACKARG_PREV_FUN(carg, detect)
|
|
||||||
(CALLBACKARG_PREV_CARG(carg), opt, str)) {
|
|
||||||
return 1; /* Found before us, let them have the priority */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check MIME */
|
|
||||||
if (detect_mime(str)) {
|
|
||||||
str->wrapper_name = libName; /* Our ID */
|
|
||||||
return 1; /* Known format, we take it */
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; /* Unknown format */
|
|
||||||
}
|
|
||||||
|
|
||||||
static off_t fsize(const char *s) {
|
|
||||||
STRUCT_STAT st;
|
|
||||||
|
|
||||||
if (STAT(s, &st) == 0 && S_ISREG(st.st_mode)) {
|
|
||||||
return st.st_size;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
|
|
||||||
htsmoduleStruct * str) {
|
|
||||||
/* The wrapper_name memebr has changed: not for us anymore */
|
|
||||||
if (str->wrapper_name == NULL || strcmp(str->wrapper_name, libName) != 0) {
|
|
||||||
/* Call parent functions if multiple callbacks are chained. */
|
|
||||||
if (CALLBACKARG_PREV_FUN(carg, parse) != NULL) {
|
|
||||||
return CALLBACKARG_PREV_FUN(carg, parse) (CALLBACKARG_PREV_CARG(carg),
|
|
||||||
opt, str);
|
|
||||||
}
|
|
||||||
strcpy(str->err_msg,
|
|
||||||
"unexpected error: bad wrapper_name and no previous wrapper");
|
|
||||||
return 0; /* Unexpected error */
|
|
||||||
} else {
|
|
||||||
if (detect_mime(str)) {
|
|
||||||
|
|
||||||
/* (Legacy code) */
|
|
||||||
char catbuff[CATBUFF_SIZE];
|
|
||||||
FILE *fpout;
|
|
||||||
JAVA_HEADER header;
|
|
||||||
RESP_STRUCT *tab;
|
|
||||||
const char *file = str->filename;
|
|
||||||
|
|
||||||
str->relativeToHtmlLink = 1;
|
|
||||||
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("fopen\n");
|
|
||||||
#endif
|
|
||||||
if ((fpout = FOPEN(fconv(catbuff, sizeof(catbuff), file), "r+b")) == NULL) {
|
|
||||||
//fprintf(stderr, "Cannot open input file.\n");
|
|
||||||
sprintf(str->err_msg, "Unable to open file %s", file);
|
|
||||||
return 0; // une erreur..
|
|
||||||
}
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("fread\n");
|
|
||||||
#endif
|
|
||||||
//if (fread(&header,1,sizeof(JAVA_HEADER),fpout) != sizeof(JAVA_HEADER)) { // pas complet..
|
|
||||||
if (fread(&header, 1, 10, fpout) != 10) { // pas complet..
|
|
||||||
fclose(fpout);
|
|
||||||
sprintf(str->err_msg, "File header too small (file len = " LLintP ")",
|
|
||||||
(LLint) fsize(file));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("header\n");
|
|
||||||
#endif
|
|
||||||
// tester en tête
|
|
||||||
if (reverse_endian()) {
|
|
||||||
header.magic = hts_swap32(header.magic);
|
|
||||||
header.count = hts_swap16(header.count);
|
|
||||||
}
|
|
||||||
if (header.magic != 0xCAFEBABE) {
|
|
||||||
sprintf(str->err_msg, "non java file");
|
|
||||||
if (fpout) {
|
|
||||||
fclose(fpout);
|
|
||||||
fpout = NULL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A constant-pool entry is >= 1 byte on disk; reject a count exceeding
|
|
||||||
the file size (hostile .class ~68 MB alloc DoS). */
|
|
||||||
if (!hts_count_fits(header.count, (LLint) fsize(file))) {
|
|
||||||
fclose(fpout);
|
|
||||||
sprintf(str->err_msg,
|
|
||||||
"Invalid constant pool count %u (file len " LLintP ")",
|
|
||||||
(unsigned) header.count, (LLint) fsize(file));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
tab = (RESP_STRUCT *) calloct(header.count, sizeof(RESP_STRUCT));
|
|
||||||
if (!tab) {
|
|
||||||
sprintf(str->err_msg, "Unable to alloc %d bytes",
|
|
||||||
(int) sizeof(RESP_STRUCT));
|
|
||||||
if (fpout) {
|
|
||||||
fclose(fpout);
|
|
||||||
fpout = NULL;
|
|
||||||
}
|
|
||||||
return 0; // erreur..
|
|
||||||
}
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("calchead\n");
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 1; i < header.count; i++) {
|
|
||||||
int err = 0; // ++
|
|
||||||
|
|
||||||
tab[i] = readtable(str, fpout, tab[i], &err);
|
|
||||||
if (!err) {
|
|
||||||
if ((tab[i].type == HTS_LONG) || (tab[i].type == HTS_DOUBLE))
|
|
||||||
i++; //2 element si double ou float
|
|
||||||
} else { // ++ une erreur est survenue!
|
|
||||||
if (strnotempty(str->err_msg) == 0)
|
|
||||||
strcpy(str->err_msg, "Internal readtable error");
|
|
||||||
freet(tab);
|
|
||||||
if (fpout) {
|
|
||||||
fclose(fpout);
|
|
||||||
fpout = NULL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("addfiles\n");
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
//unsigned int acess;
|
|
||||||
unsigned int Class;
|
|
||||||
unsigned int SClass;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
//acess = readshort(fpout);
|
|
||||||
Class = readshort(fpout);
|
|
||||||
SClass = readshort(fpout);
|
|
||||||
|
|
||||||
for(i = 1; i < header.count; i++) {
|
|
||||||
|
|
||||||
if (tab[i].type == HTS_CLASS) {
|
|
||||||
|
|
||||||
if ((tab[i].index1 < header.count) && (tab[i].index1 >= 0)) {
|
|
||||||
|
|
||||||
if ((tab[i].index1 != SClass) && (tab[i].index1 != Class)
|
|
||||||
&& (tab[tab[i].index1].name[0] != '[')) {
|
|
||||||
|
|
||||||
if (!strstr(tab[tab[i].index1].name, "java/")) {
|
|
||||||
char BIGSTK tempo[1024];
|
|
||||||
|
|
||||||
tempo[0] = '\0';
|
|
||||||
|
|
||||||
snprintf(tempo, sizeof(tempo), "%s.class", tab[tab[i].index1].name);
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("add %s\n", tempo);
|
|
||||||
#endif
|
|
||||||
if (tab[tab[i].index1].file_position >= 0)
|
|
||||||
str->addLink(str, tempo); /* tab[tab[i].index1].file_position */
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i = header.count; // exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("end\n");
|
|
||||||
#endif
|
|
||||||
freet(tab);
|
|
||||||
if (fpout) {
|
|
||||||
fclose(fpout);
|
|
||||||
fpout = NULL;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
strcpy(str->err_msg, "bad MIME type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0; /* Error */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
module entry point
|
|
||||||
*/
|
|
||||||
EXTERNAL_FUNCTION int hts_plug(httrackp * opt, const char *argv);
|
|
||||||
EXTERNAL_FUNCTION int hts_plug(httrackp * opt, const char *argv) {
|
|
||||||
/* Plug callback functions */
|
|
||||||
CHAIN_FUNCTION(opt, detect, hts_detect_java, NULL);
|
|
||||||
CHAIN_FUNCTION(opt, parse, hts_parse_java, NULL);
|
|
||||||
|
|
||||||
return 1; /* success */
|
|
||||||
}
|
|
||||||
|
|
||||||
// error: !=0 si erreur fatale
|
|
||||||
static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp,
|
|
||||||
RESP_STRUCT trans, int *error) {
|
|
||||||
char rname[1024];
|
|
||||||
unsigned short int length;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
*error = 0; // pas d'erreur
|
|
||||||
trans.file_position = -1;
|
|
||||||
trans.type = (int) (unsigned char) fgetc(fp);
|
|
||||||
switch (trans.type) {
|
|
||||||
case HTS_CLASS:
|
|
||||||
strcpy(trans.name, "Class");
|
|
||||||
trans.index1 = readshort(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_FIELDREF:
|
|
||||||
strcpy(trans.name, "Field Reference");
|
|
||||||
trans.index1 = readshort(fp);
|
|
||||||
readshort(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_METHODREF:
|
|
||||||
strcpy(trans.name, "Method Reference");
|
|
||||||
trans.index1 = readshort(fp);
|
|
||||||
readshort(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_INTERFACE:
|
|
||||||
strcpy(trans.name, "Interface Method Reference");
|
|
||||||
trans.index1 = readshort(fp);
|
|
||||||
readshort(fp);
|
|
||||||
break;
|
|
||||||
case HTS_NAMEANDTYPE:
|
|
||||||
strcpy(trans.name, "Name and Type");
|
|
||||||
trans.index1 = readshort(fp);
|
|
||||||
readshort(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_STRING: // CONSTANT_String
|
|
||||||
strcpy(trans.name, "String");
|
|
||||||
trans.index1 = readshort(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_INTEGER:
|
|
||||||
strcpy(trans.name, "Integer");
|
|
||||||
for(j = 0; j < 4; j++)
|
|
||||||
fgetc(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_FLOAT:
|
|
||||||
strcpy(trans.name, "Float");
|
|
||||||
for(j = 0; j < 4; j++)
|
|
||||||
fgetc(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_LONG:
|
|
||||||
strcpy(trans.name, "Long");
|
|
||||||
for(j = 0; j < 8; j++)
|
|
||||||
fgetc(fp);
|
|
||||||
break;
|
|
||||||
case HTS_DOUBLE:
|
|
||||||
strcpy(trans.name, "Double");
|
|
||||||
for(j = 0; j < 8; j++)
|
|
||||||
fgetc(fp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTS_ASCIZ:
|
|
||||||
case HTS_UNICODE:
|
|
||||||
|
|
||||||
if (trans.type == HTS_ASCIZ)
|
|
||||||
strcpy(trans.name, "HTS_ASCIZ");
|
|
||||||
else
|
|
||||||
strcpy(trans.name, "HTS_UNICODE");
|
|
||||||
|
|
||||||
{
|
|
||||||
char BIGSTK buffer[1024];
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
p = &buffer[0];
|
|
||||||
|
|
||||||
//fflush(fp);
|
|
||||||
trans.file_position = ftell(fp);
|
|
||||||
length = readshort(fp);
|
|
||||||
if (length < HTS_URLMAXSIZE) {
|
|
||||||
// while ((length > 0) && (length<500)) {
|
|
||||||
while(length > 0) {
|
|
||||||
*p++ = fgetc(fp);
|
|
||||||
|
|
||||||
length--;
|
|
||||||
}
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
//#if JDEBUG
|
|
||||||
// if(tris(buffer)==1) printf("%s\n ",buffer);
|
|
||||||
// if(tris(buffer)==2) printf("%s\n ",printname(buffer));
|
|
||||||
//#endif
|
|
||||||
if (tris(str->opt, buffer) == 1)
|
|
||||||
str->addLink(str, buffer); /* trans.file_position */
|
|
||||||
else if (tris(str->opt, buffer) == 2)
|
|
||||||
str->addLink(str, printname(rname, buffer));
|
|
||||||
|
|
||||||
strcpy(trans.name, buffer);
|
|
||||||
} else { // gros pb
|
|
||||||
while((length > 0) && (!feof(fp))) {
|
|
||||||
fgetc(fp);
|
|
||||||
length--;
|
|
||||||
}
|
|
||||||
if (!feof(fp)) {
|
|
||||||
trans.type = -1;
|
|
||||||
} else {
|
|
||||||
sprintf(str->err_msg, "Internal structure error (ASCII)");
|
|
||||||
*error = 1;
|
|
||||||
}
|
|
||||||
return (trans);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// printf("Type inconnue\n");
|
|
||||||
// on arrête tout
|
|
||||||
sprintf(str->err_msg, "Internal structure unknown (type %d)", trans.type);
|
|
||||||
*error = 1;
|
|
||||||
return (trans);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned short int readshort(FILE * fp) {
|
|
||||||
unsigned short int valint;
|
|
||||||
|
|
||||||
if (fread(&valint, sizeof(valint), 1, fp) == 1) {
|
|
||||||
if (reverse_endian())
|
|
||||||
return hts_swap16(valint);
|
|
||||||
else
|
|
||||||
return valint;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tris(httrackp * opt, char *buffer) {
|
|
||||||
char catbuff[CATBUFF_SIZE];
|
|
||||||
|
|
||||||
//
|
|
||||||
// Java
|
|
||||||
if ((buffer[0] == '[') && buffer[1] == 'L' && (!strstr(buffer, "java/")))
|
|
||||||
return 2;
|
|
||||||
if (strstr(buffer, ".gif") || strstr(buffer, ".jpg")
|
|
||||||
|| strstr(buffer, ".jpeg") || strstr(buffer, ".au"))
|
|
||||||
return 1;
|
|
||||||
// Ajouts R.X: test type
|
|
||||||
// Autres fichiers
|
|
||||||
{
|
|
||||||
char type[256];
|
|
||||||
|
|
||||||
if (get_httptype_sized(opt, type, sizeof(type), buffer,
|
|
||||||
0)) // recognized type
|
|
||||||
return 1;
|
|
||||||
// ajout RX 05/2001
|
|
||||||
else if (is_dyntype(get_ext(catbuff, sizeof(catbuff), buffer))) // asp,cgi...
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *printname(char rname[1024], char name[1024]) {
|
|
||||||
char *p;
|
|
||||||
char *p1;
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
rname[0] = '\0';
|
|
||||||
//
|
|
||||||
|
|
||||||
p = &name[0];
|
|
||||||
|
|
||||||
if (*p != '[') {
|
|
||||||
return rname; // ""
|
|
||||||
}
|
|
||||||
p += 2;
|
|
||||||
//rname=(char*)calloct(strlen(name)+8,sizeof(char));
|
|
||||||
p1 = rname;
|
|
||||||
for(j = 0; name[j] != '\0'; j++, p++) {
|
|
||||||
if (*p == '/')
|
|
||||||
*p1 = '.';
|
|
||||||
if (*p == ';') {
|
|
||||||
*p1 = '\0';
|
|
||||||
strcat(rname, ".class");
|
|
||||||
return rname;
|
|
||||||
} else
|
|
||||||
*p1 = *p;
|
|
||||||
p1++;
|
|
||||||
}
|
|
||||||
p1 -= 3;
|
|
||||||
*p1 = '\0';
|
|
||||||
return rname;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="9,00"
|
|
||||||
Name="htsjava"
|
|
||||||
ProjectGUID="{2F353408-2C6C-4D31-9AC0-08BDC064DF64}"
|
|
||||||
RootNamespace="htsjava"
|
|
||||||
Keyword="Win32Proj"
|
|
||||||
TargetFrameworkVersion="131072"
|
|
||||||
>
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"
|
|
||||||
/>
|
|
||||||
<Platform
|
|
||||||
Name="x64"
|
|
||||||
/>
|
|
||||||
</Platforms>
|
|
||||||
<ToolFiles>
|
|
||||||
</ToolFiles>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory="C:\temp\htsjava\Debug"
|
|
||||||
IntermediateDirectory="C:\temp\htsjava\Debug"
|
|
||||||
ConfigurationType="2"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\openssl-1.0.1j\include"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
MinimalRebuild="true"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="1"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="4"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile="C:\temp\httrack\htsjava.dll"
|
|
||||||
LinkIncremental="2"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(OutDir)/htsjava.pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
ImportLibrary="$(OutDir)/htsjava.lib"
|
|
||||||
TargetMachine="1"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|x64"
|
|
||||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="2"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\openssl-1.0.1j\include"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
MinimalRebuild="true"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="1"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile="C:\temp\httrack64\htsjava.dll"
|
|
||||||
LinkIncremental="2"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(OutDir)/htsjava.pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
ImportLibrary="$(OutDir)/htsjava.lib"
|
|
||||||
TargetMachine="17"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory="C:\temp\htsjava\Release"
|
|
||||||
IntermediateDirectory="C:\temp\htsjava\Release"
|
|
||||||
ConfigurationType="2"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\openssl-1.0.1j\include"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
RuntimeLibrary="0"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile="O:\HTTrack\httrack\htsjava.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\htsjava.pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
ImportLibrary="$(OutDir)/htsjava.lib"
|
|
||||||
TargetMachine="1"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
CommandLine=""C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\signtool.exe" sign /f "Z:\Mes Documents\certificats\httrack-com\httrack-signing-certificate.pfx" /t http://timestamp.verisign.com/scripts/timstamp.dll $(TargetPath)
"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|x64"
|
|
||||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="2"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\openssl-1.0.1j\include"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
RuntimeLibrary="0"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile="O:\HTTrack\httrack\x64\htsjava.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\x64\htsjava.pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
ImportLibrary="$(OutDir)/htsjava.lib"
|
|
||||||
TargetMachine="17"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
CommandLine=""C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\signtool.exe" sign /f "Z:\Mes Documents\certificats\httrack-com\httrack-signing-certificate.pfx" /t http://timestamp.verisign.com/scripts/timstamp.dll $(TargetPath)
"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<Filter
|
|
||||||
Name="Source Files"
|
|
||||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
|
||||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="htsjava.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Header Files"
|
|
||||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
|
||||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="htsjava.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Resource Files"
|
|
||||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
|
||||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
|
||||||
>
|
|
||||||
</Filter>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
532
src/htslib.c
532
src/htslib.c
@@ -48,6 +48,7 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htsmodules.h"
|
#include "htsmodules.h"
|
||||||
#include "htscharset.h"
|
#include "htscharset.h"
|
||||||
#include "htsencoding.h"
|
#include "htsencoding.h"
|
||||||
|
#include "htscodec.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
@@ -598,56 +599,27 @@ static const char *hts_mime_modern[][2] = {
|
|||||||
|
|
||||||
// Reserved (RFC2396)
|
// Reserved (RFC2396)
|
||||||
#define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
|
#define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
|
||||||
#define CHAR_RESERVED(c) ( CIS(c,';') \
|
#define CHAR_RESERVED(c) \
|
||||||
|| CIS(c,'/') \
|
(CIS(c, ';') || CIS(c, '/') || CIS(c, '?') || CIS(c, ':') || CIS(c, '@') || \
|
||||||
|| CIS(c,'?') \
|
CIS(c, '&') || CIS(c, '=') || CIS(c, '+') || CIS(c, '$') || CIS(c, ','))
|
||||||
|| CIS(c,':') \
|
|
||||||
|| CIS(c,'@') \
|
|
||||||
|| CIS(c,'&') \
|
|
||||||
|| CIS(c,'=') \
|
|
||||||
|| CIS(c,'+') \
|
|
||||||
|| CIS(c,'$') \
|
|
||||||
|| CIS(c,',') )
|
|
||||||
//#define CHAR_RESERVED(c) ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
|
|
||||||
// Delimiters (RFC2396)
|
// Delimiters (RFC2396)
|
||||||
#define CHAR_DELIM(c) ( CIS(c,'<') \
|
#define CHAR_DELIM(c) \
|
||||||
|| CIS(c,'>') \
|
(CIS(c, '<') || CIS(c, '>') || CIS(c, '#') || CIS(c, '%') || CIS(c, '\"'))
|
||||||
|| CIS(c,'#') \
|
|
||||||
|| CIS(c,'%') \
|
|
||||||
|| CIS(c,'\"') )
|
|
||||||
//#define CHAR_DELIM(c) ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
|
|
||||||
// Unwise (RFC2396)
|
// Unwise (RFC2396)
|
||||||
#define CHAR_UNWISE(c) ( CIS(c,'{') \
|
#define CHAR_UNWISE(c) \
|
||||||
|| CIS(c,'}') \
|
(CIS(c, '{') || CIS(c, '}') || CIS(c, '|') || CIS(c, '\\') || CIS(c, '^') || \
|
||||||
|| CIS(c,'|') \
|
CIS(c, '[') || CIS(c, ']') || CIS(c, '`'))
|
||||||
|| CIS(c,'\\') \
|
|
||||||
|| CIS(c,'^') \
|
|
||||||
|| CIS(c,'[') \
|
|
||||||
|| CIS(c,']') \
|
|
||||||
|| CIS(c,'`') )
|
|
||||||
//#define CHAR_UNWISE(c) ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
|
|
||||||
// Special (escape chars) (RFC2396 + >127 )
|
// Special (escape chars) (RFC2396 + >127 )
|
||||||
#define CHAR_LOW(c) ( ((unsigned char)(c) <= 31) )
|
#define CHAR_LOW(c) ( ((unsigned char)(c) <= 31) )
|
||||||
#define CHAR_HIG(c) ( ((unsigned char)(c) >= 127) )
|
#define CHAR_HIG(c) ( ((unsigned char)(c) >= 127) )
|
||||||
#define CHAR_SPECIAL(c) ( CHAR_LOW(c) || CHAR_HIG(c) )
|
#define CHAR_SPECIAL(c) ( CHAR_LOW(c) || CHAR_HIG(c) )
|
||||||
// We try to avoid them and encode them instead
|
// We try to avoid them and encode them instead
|
||||||
#define CHAR_XXAVOID(c) ( CIS(c,' ') \
|
#define CHAR_XXAVOID(c) \
|
||||||
|| CIS(c,'*') \
|
(CIS(c, ' ') || CIS(c, '*') || CIS(c, '\'') || CIS(c, '\"') || \
|
||||||
|| CIS(c,'\'') \
|
CIS(c, '&') || CIS(c, '!'))
|
||||||
|| CIS(c,'\"') \
|
#define CHAR_MARK(c) \
|
||||||
|| CIS(c,'&') \
|
(CIS(c, '-') || CIS(c, '_') || CIS(c, '.') || CIS(c, '!') || CIS(c, '~') || \
|
||||||
|| CIS(c,'!') )
|
CIS(c, '*') || CIS(c, '\'') || CIS(c, '(') || CIS(c, ')'))
|
||||||
//#define CHAR_XXAVOID(c) ( strchr(" *'\"!",(unsigned char)(c)) != 0 )
|
|
||||||
#define CHAR_MARK(c) ( CIS(c,'-') \
|
|
||||||
|| CIS(c,'_') \
|
|
||||||
|| CIS(c,'.') \
|
|
||||||
|| CIS(c,'!') \
|
|
||||||
|| CIS(c,'~') \
|
|
||||||
|| CIS(c,'*') \
|
|
||||||
|| CIS(c,'\'') \
|
|
||||||
|| CIS(c,'(') \
|
|
||||||
|| CIS(c,')') )
|
|
||||||
//#define CHAR_MARK(c) ( strchr("-_.!~*'()",(unsigned char)(c)) != 0 )
|
|
||||||
|
|
||||||
// conversion éventuelle / vers antislash
|
// conversion éventuelle / vers antislash
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -677,179 +649,17 @@ T_SOC http_fopen(httrackp * opt, const char *adr, const char *fil, htsblk * reto
|
|||||||
return http_xfopen(opt, 0, 1, 1, NULL, adr, fil, retour);
|
return http_xfopen(opt, 0, 1, 1, NULL, adr, fil, retour);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a CRLF line from a non-blocking socket (waits up to timeout per recv).
|
|
||||||
// Returns the line length (0 = empty), or -1 on timeout/EOF/error.
|
|
||||||
static int proxy_getline(T_SOC soc, char *s, int max, int timeout) {
|
|
||||||
int j = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
unsigned char ch;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (!check_readinput_t(soc, timeout))
|
|
||||||
return -1; // timed out waiting for data
|
|
||||||
n = (int) recv(soc, &ch, 1, 0);
|
|
||||||
if (n == 1) {
|
|
||||||
if (ch == 13) // CR
|
|
||||||
continue;
|
|
||||||
if (ch == 10) // LF: end of line
|
|
||||||
break;
|
|
||||||
if (j >= max - 1)
|
|
||||||
return -1; // line too long: bound the read against a hostile proxy
|
|
||||||
s[j++] = (char) ch;
|
|
||||||
} else if (n == 0) {
|
|
||||||
return -1; // connection closed
|
|
||||||
} else {
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
|
||||||
continue;
|
|
||||||
#else
|
|
||||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
|
||||||
continue;
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s[j] = '\0';
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_proxy_tunnel(httrackp *opt, htsblk *retour, const char *adr,
|
|
||||||
int timeout) {
|
|
||||||
const T_SOC soc = retour->soc;
|
|
||||||
const char *const host = jump_identification_const(adr); // host[:port]
|
|
||||||
const char *const portsep = jump_toport_const(adr); // ":port" or NULL
|
|
||||||
char BIGSTK authority[HTS_URLMAXSIZE * 2];
|
|
||||||
char BIGSTK req[HTS_URLMAXSIZE * 4 + 1100];
|
|
||||||
char line[1024];
|
|
||||||
int code;
|
|
||||||
|
|
||||||
if (soc == INVALID_SOCKET)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// CONNECT needs an explicit host:port; default the https port
|
|
||||||
authority[0] = '\0';
|
|
||||||
if (portsep != NULL)
|
|
||||||
strlcatbuff(authority, host, sizeof(authority)); // already host:port
|
|
||||||
else
|
|
||||||
snprintf(authority, sizeof(authority), "%s:%d", host, 443);
|
|
||||||
|
|
||||||
// backstop: never let a stray CR/LF in the host smuggle a second line into
|
|
||||||
// the CONNECT request (the host is already sanitized upstream)
|
|
||||||
{
|
|
||||||
const char *c;
|
|
||||||
|
|
||||||
for (c = authority; *c != '\0'; c++) {
|
|
||||||
if ((unsigned char) *c < ' ') {
|
|
||||||
strcpybuff(retour->msg, "proxy CONNECT: invalid host");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(req, sizeof(req), "CONNECT %s HTTP/1.0" H_CRLF "Host: %s" H_CRLF,
|
|
||||||
authority, authority);
|
|
||||||
|
|
||||||
// creds go on the CONNECT, not the tunneled origin request
|
|
||||||
if (link_has_authorization(retour->req.proxy.name)) {
|
|
||||||
const char *a = jump_identification_const(retour->req.proxy.name);
|
|
||||||
const char *astart = jump_protocol_const(retour->req.proxy.name);
|
|
||||||
char autorisation[1100];
|
|
||||||
char user_pass[256];
|
|
||||||
|
|
||||||
autorisation[0] = user_pass[0] = '\0';
|
|
||||||
strncatbuff(user_pass, astart, (int) (a - astart) - 1);
|
|
||||||
strcpybuff(user_pass, unescape_http(OPT_GET_BUFF(opt),
|
|
||||||
OPT_GET_BUFF_SIZE(opt), user_pass));
|
|
||||||
code64((unsigned char *) user_pass, (int) strlen(user_pass),
|
|
||||||
(unsigned char *) autorisation, 0);
|
|
||||||
strlcatbuff(req, "Proxy-Authorization: Basic ", sizeof(req));
|
|
||||||
strlcatbuff(req, autorisation, sizeof(req));
|
|
||||||
strlcatbuff(req, H_CRLF, sizeof(req));
|
|
||||||
}
|
|
||||||
strlcatbuff(req, H_CRLF, sizeof(req)); // end of request headers
|
|
||||||
|
|
||||||
// raw send: ssl is set, so sendc() would route to TLS
|
|
||||||
{
|
|
||||||
const char *p = req;
|
|
||||||
size_t remain = strlen(req);
|
|
||||||
int stalls = 0;
|
|
||||||
|
|
||||||
while (remain > 0) {
|
|
||||||
const int n = (int) send(soc, p, (int) remain, 0);
|
|
||||||
|
|
||||||
if (n > 0) {
|
|
||||||
p += n;
|
|
||||||
remain -= (size_t) n;
|
|
||||||
stalls = 0;
|
|
||||||
} else {
|
|
||||||
#ifdef _WIN32
|
|
||||||
const int wouldblock = (WSAGetLastError() == WSAEWOULDBLOCK);
|
|
||||||
#else
|
|
||||||
const int wouldblock =
|
|
||||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR);
|
|
||||||
#endif
|
|
||||||
// don't spin forever on a fatal error or an unwritable socket
|
|
||||||
if (!wouldblock || !check_writeinput_t(soc, timeout) ||
|
|
||||||
++stalls > 100) {
|
|
||||||
strcpybuff(retour->msg, "proxy CONNECT: write error");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// proxy status line: "HTTP/1.x <code> ..."
|
|
||||||
if (proxy_getline(soc, line, sizeof(line), timeout) < 0) {
|
|
||||||
strcpybuff(retour->msg, "proxy CONNECT: no response");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sscanf(line, "HTTP/%*d.%*d %d", &code) < 1)
|
|
||||||
code = 0;
|
|
||||||
if (code < 200 || code >= 300) {
|
|
||||||
snprintf(retour->msg, sizeof(retour->msg), "proxy CONNECT refused: %s",
|
|
||||||
strnotempty(line) ? line : "(no status)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// drain headers to the blank line; cap the count so a flooding proxy can't
|
|
||||||
// stall the crawl
|
|
||||||
{
|
|
||||||
int headers = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
const int n = proxy_getline(soc, line, sizeof(line), timeout);
|
|
||||||
|
|
||||||
if (n < 0) {
|
|
||||||
strcpybuff(retour->msg, "proxy CONNECT: truncated response");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (n == 0)
|
|
||||||
break; // blank line: tunnel ready
|
|
||||||
if (++headers > 64) {
|
|
||||||
strcpybuff(retour->msg, "proxy CONNECT: too many response headers");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ouverture d'une liaison http, envoi d'une requète
|
// ouverture d'une liaison http, envoi d'une requète
|
||||||
// mode: 0 GET 1 HEAD [2 POST]
|
// mode: 0 GET 1 HEAD [2 POST]
|
||||||
// treat: traiter header?
|
// treat: traiter header?
|
||||||
// waitconnect: attendre le connect()
|
// waitconnect: attendre le connect()
|
||||||
// note: dans retour, on met les params du proxy
|
// note: dans retour, on met les params du proxy
|
||||||
T_SOC http_xfopen(httrackp * opt, int mode, int treat, int waitconnect,
|
T_SOC http_xfopen(httrackp *opt, int mode, int treat, int waitconnect,
|
||||||
const char *xsend, const char *adr, const char *fil, htsblk * retour) {
|
const char *xsend, const char *adr, const char *fil,
|
||||||
//htsblk retour;
|
htsblk *retour) {
|
||||||
//int bufl=TAILLE_BUFFER; // 8Ko de buffer
|
|
||||||
T_SOC soc = INVALID_SOCKET;
|
T_SOC soc = INVALID_SOCKET;
|
||||||
char BIGSTK tempo_fil[HTS_URLMAXSIZE * 2];
|
char BIGSTK tempo_fil[HTS_URLMAXSIZE * 2];
|
||||||
|
|
||||||
//char *p,*q;
|
|
||||||
|
|
||||||
// retour prédéfini: erreur
|
// retour prédéfini: erreur
|
||||||
if (retour) {
|
if (retour) {
|
||||||
retour->adr = NULL;
|
retour->adr = NULL;
|
||||||
@@ -934,7 +744,6 @@ T_SOC http_xfopen(httrackp * opt, int mode, int treat, int waitconnect,
|
|||||||
strcpybuff(retour->msg, "Unable to open local file");
|
strcpybuff(retour->msg, "Unable to open local file");
|
||||||
else {
|
else {
|
||||||
// Note: On passe par un FILE* (plus propre)
|
// Note: On passe par un FILE* (plus propre)
|
||||||
//soc=open(fil,O_RDONLY,0); // en lecture seule!
|
|
||||||
retour->fp = FOPEN(fconv(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
retour->fp = FOPEN(fconv(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
unescape_http(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), fil)), "rb"); // ouvrir
|
unescape_http(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), fil)), "rb"); // ouvrir
|
||||||
if (retour->fp == NULL)
|
if (retour->fp == NULL)
|
||||||
@@ -1011,17 +820,10 @@ T_SOC http_xfopen(httrackp * opt, int mode, int treat, int waitconnect,
|
|||||||
|
|
||||||
} while(strnotempty(rcvd));
|
} while(strnotempty(rcvd));
|
||||||
|
|
||||||
//rcvsize=-1; // forCER CHARGEMENT INCONNU
|
} else { // si GET, on recevra l'en tête APRES
|
||||||
|
|
||||||
//if (retour)
|
|
||||||
// retour->totalsize=rcvsize;
|
|
||||||
|
|
||||||
} else { // si GET, on recevra l'en tête APRES
|
|
||||||
//rcvsize=-1; // on ne connait pas la taille de l'en-tête
|
|
||||||
if (retour)
|
if (retour)
|
||||||
retour->totalsize = -1;
|
retour->totalsize = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1099,10 +901,10 @@ static int append_cookie_header(buff_struct *bstr, t_cookie *cookie,
|
|||||||
return cook;
|
return cook;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Self-test entry for append_cookie_header(): build the request Cookie line
|
/* Build the request Cookie line for domain/path into dst (always
|
||||||
into dst (always NUL-terminated). Returns the number of cookies emitted. */
|
NUL-terminated). Returns the number of cookies emitted. */
|
||||||
int http_cookie_header_selftest(t_cookie *cookie, const char *domain,
|
int http_cookie_header(t_cookie *cookie, const char *domain, const char *path,
|
||||||
const char *path, char *dst, size_t dst_size) {
|
char *dst, size_t dst_size) {
|
||||||
buff_struct bstr = {dst, dst_size, 0};
|
buff_struct bstr = {dst, dst_size, 0};
|
||||||
|
|
||||||
assertf(dst != NULL && dst_size > 0);
|
assertf(dst != NULL && dst_size > 0);
|
||||||
@@ -1118,19 +920,12 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
char BIGSTK buffer_head_request[16384];
|
char BIGSTK buffer_head_request[16384];
|
||||||
buff_struct bstr = { buffer_head_request, sizeof(buffer_head_request), 0 };
|
buff_struct bstr = { buffer_head_request, sizeof(buffer_head_request), 0 };
|
||||||
|
|
||||||
//int use_11=0; // HTTP 1.1 utilisé
|
|
||||||
int direct_url = 0; // ne pas analyser l'url (exemple: ftp://)
|
int direct_url = 0; // ne pas analyser l'url (exemple: ftp://)
|
||||||
const char *search_tag = NULL;
|
const char *search_tag = NULL;
|
||||||
|
|
||||||
// Initialize buffer
|
// Initialize buffer
|
||||||
buffer_head_request[0] = '\0';
|
buffer_head_request[0] = '\0';
|
||||||
|
|
||||||
// header Date
|
|
||||||
//strcatbuff(buff,"Date: ");
|
|
||||||
//time_gmt_rfc822(buff); // obtenir l'heure au format rfc822
|
|
||||||
//sendc("\n");
|
|
||||||
//strcatbuff(buff,buff);
|
|
||||||
|
|
||||||
// possibilité non documentée: >post: et >postfile:
|
// possibilité non documentée: >post: et >postfile:
|
||||||
// si présence d'un tag >post: alors executer un POST
|
// si présence d'un tag >post: alors executer un POST
|
||||||
// exemple: http://www.example.com/test.cgi?foo>post:posteddata=10&foo=5
|
// exemple: http://www.example.com/test.cgi?foo>post:posteddata=10&foo=5
|
||||||
@@ -1152,8 +947,9 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
/* widths bound method[256], url[HTS_URLMAXSIZE*2], protocol[256] */
|
/* widths bound method[256], url[HTS_URLMAXSIZE*2], protocol[256] */
|
||||||
if (sscanf(line, "%255s %2047s %255s", method, url, protocol) == 3) {
|
if (sscanf(line, "%255s %2047s %255s", method, url, protocol) == 3) {
|
||||||
size_t ret;
|
size_t ret;
|
||||||
// selon que l'on a ou pas un proxy
|
// absolute-URI for an http proxy; a socks tunnel takes origin-form
|
||||||
if (retour->req.proxy.active) {
|
if (retour->req.proxy.active &&
|
||||||
|
!hts_proxy_is_socks(retour->req.proxy.name)) {
|
||||||
print_buffer(&bstr,
|
print_buffer(&bstr,
|
||||||
"%s http://%s%s %s\r\n", method, adr, url,
|
"%s http://%s%s %s\r\n", method, adr, url,
|
||||||
protocol);
|
protocol);
|
||||||
@@ -1189,8 +985,10 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
print_buffer(&bstr, "HEAD ");
|
print_buffer(&bstr, "HEAD ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// si on gère un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
|
// an http proxy needs an absolute URI; a socks tunnel does not
|
||||||
if (retour->req.proxy.active && (strncmp(adr, "https://", 8) != 0)) {
|
if (retour->req.proxy.active &&
|
||||||
|
!hts_proxy_is_socks(retour->req.proxy.name) &&
|
||||||
|
(strncmp(adr, "https://", 8) != 0)) {
|
||||||
if (!link_has_authority(adr)) { // default http
|
if (!link_has_authority(adr)) { // default http
|
||||||
#if HDEBUG
|
#if HDEBUG
|
||||||
printf("Proxy Use: for %s%s proxy %d port %d\n", adr, fil,
|
printf("Proxy Use: for %s%s proxy %d port %d\n", adr, fil,
|
||||||
@@ -1224,11 +1022,9 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// protocole
|
// protocole
|
||||||
if (!retour->req.http11) { // forcer HTTP/1.0
|
if (!retour->req.http11) { // forcer HTTP/1.0
|
||||||
//use_11=0;
|
|
||||||
print_buffer(&bstr, " HTTP/1.0\x0d\x0a");
|
print_buffer(&bstr, " HTTP/1.0\x0d\x0a");
|
||||||
} else { // Requète 1.1
|
} else { // Requète 1.1
|
||||||
//use_11=1;
|
|
||||||
print_buffer(&bstr, " HTTP/1.1\x0d\x0a");
|
print_buffer(&bstr, " HTTP/1.1\x0d\x0a");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1236,8 +1032,11 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
if (xsend)
|
if (xsend)
|
||||||
print_buffer(&bstr, "%s", xsend); // éventuelles autres lignes
|
print_buffer(&bstr, "%s", xsend); // éventuelles autres lignes
|
||||||
|
|
||||||
// for https, auth rides the CONNECT (the tunneled GET would leak it)
|
// for https, auth rides the CONNECT (the tunneled GET would leak it); for
|
||||||
if (retour->req.proxy.active && strncmp(adr, "https://", 8) != 0) {
|
// socks, the handshake
|
||||||
|
if (retour->req.proxy.active &&
|
||||||
|
!hts_proxy_is_socks(retour->req.proxy.name) &&
|
||||||
|
strncmp(adr, "https://", 8) != 0) {
|
||||||
if (link_has_authorization(retour->req.proxy.name)) { // et hop, authentification proxy!
|
if (link_has_authorization(retour->req.proxy.name)) { // et hop, authentification proxy!
|
||||||
const char *a = jump_identification_const(retour->req.proxy.name);
|
const char *a = jump_identification_const(retour->req.proxy.name);
|
||||||
const char *astart = jump_protocol_const(retour->req.proxy.name);
|
const char *astart = jump_protocol_const(retour->req.proxy.name);
|
||||||
@@ -1328,11 +1127,16 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
// Compression accepted ?
|
// Compression accepted ?
|
||||||
if (retour->req.http11) {
|
if (retour->req.http11) {
|
||||||
hts_boolean compressible = HTS_FALSE;
|
hts_boolean compressible = HTS_FALSE;
|
||||||
|
hts_boolean secure = HTS_FALSE;
|
||||||
|
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
compressible = (!retour->req.range_used && !retour->req.nocompression);
|
compressible = (!retour->req.range_used && !retour->req.nocompression);
|
||||||
|
#endif
|
||||||
|
#if HTS_USEOPENSSL
|
||||||
|
secure = retour->ssl ? HTS_TRUE : HTS_FALSE;
|
||||||
#endif
|
#endif
|
||||||
print_buffer(&bstr, "Accept-Encoding: %s" H_CRLF,
|
print_buffer(&bstr, "Accept-Encoding: %s" H_CRLF,
|
||||||
hts_acceptencoding(compressible));
|
hts_acceptencoding(compressible, secure));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Authentification */
|
/* Authentification */
|
||||||
@@ -1364,9 +1168,7 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
print_buffer(&bstr, "Authorization: Basic %s"H_CRLF, autorisation);
|
print_buffer(&bstr, "Authorization: Basic %s"H_CRLF, autorisation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
|
|
||||||
|
|
||||||
// Custom header(s)
|
// Custom header(s)
|
||||||
if (strnotempty(retour->req.headers)) {
|
if (strnotempty(retour->req.headers)) {
|
||||||
@@ -1520,14 +1322,11 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
a += strlen("filename=");
|
a += strlen("filename=");
|
||||||
while(is_space(*a))
|
while(is_space(*a))
|
||||||
a++;
|
a++;
|
||||||
//a=strchr(a,'"');
|
|
||||||
if (a) {
|
if (a) {
|
||||||
char *c = NULL;
|
char *c = NULL;
|
||||||
|
|
||||||
//a++; /* jump " */
|
|
||||||
while((c = strchr(a, '/'))) /* skip all / (see RFC2616) */
|
while((c = strchr(a, '/'))) /* skip all / (see RFC2616) */
|
||||||
a = c + 1;
|
a = c + 1;
|
||||||
//b=strchr(a+1,'"');
|
|
||||||
b = a + strlen(a) - 1;
|
b = a + strlen(a) - 1;
|
||||||
while(is_space(*b))
|
while(is_space(*b))
|
||||||
b--;
|
b--;
|
||||||
@@ -1544,16 +1343,14 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
} else if ((p = strfield(rcvd, "Last-Modified:")) != 0) {
|
} else if ((p = strfield(rcvd, "Last-Modified:")) != 0) {
|
||||||
while(is_realspace(*(rcvd + p)))
|
while(is_realspace(*(rcvd + p)))
|
||||||
p++; // sauter espaces
|
p++; // sauter espaces
|
||||||
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
||||||
//struct tm* tm_time=convert_time_rfc822(rcvd+p);
|
|
||||||
strcpybuff(retour->lastmodified, rcvd + p);
|
strcpybuff(retour->lastmodified, rcvd + p);
|
||||||
}
|
}
|
||||||
} else if ((p = strfield(rcvd, "Date:")) != 0) {
|
} else if ((p = strfield(rcvd, "Date:")) != 0) {
|
||||||
if (strnotempty(retour->lastmodified) == 0) { /* pas encore de last-modified */
|
if (strnotempty(retour->lastmodified) == 0) { /* pas encore de last-modified */
|
||||||
while(is_realspace(*(rcvd + p)))
|
while(is_realspace(*(rcvd + p)))
|
||||||
p++; // sauter espaces
|
p++; // sauter espaces
|
||||||
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
||||||
//struct tm* tm_time=convert_time_rfc822(rcvd+p);
|
|
||||||
strcpybuff(retour->lastmodified, rcvd + p);
|
strcpybuff(retour->lastmodified, rcvd + p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1566,14 +1363,11 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
else // erreur.. ignorer
|
else // erreur.. ignorer
|
||||||
retour->etag[0] = '\0';
|
retour->etag[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
} else if ((p = strfield(rcvd, "Transfer-Encoding:")) != 0) { // chunk!
|
||||||
// else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) { // chunk!
|
|
||||||
else if ((p = strfield(rcvd, "Transfer-Encoding:")) != 0) { // chunk!
|
|
||||||
while(is_realspace(*(rcvd + p)))
|
while(is_realspace(*(rcvd + p)))
|
||||||
p++; // sauter espaces
|
p++; // sauter espaces
|
||||||
if (strfield(rcvd + p, "chunked")) {
|
if (strfield(rcvd + p, "chunked")) {
|
||||||
retour->is_chunk = 1; // chunked
|
retour->is_chunk = 1; // chunked
|
||||||
//retour->http11=2; // chunked
|
|
||||||
#if HDEBUG
|
#if HDEBUG
|
||||||
printf("ok, Transfer-Encoding: détecté\n");
|
printf("ok, Transfer-Encoding: détecté\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -1621,7 +1415,7 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
}
|
}
|
||||||
// An empty/whitespace Content-Type value yields no token: keep the
|
// An empty/whitespace Content-Type value yields no token: keep the
|
||||||
// sentinel default rather than reading an uninitialized tempo.
|
// sentinel default rather than reading an uninitialized tempo.
|
||||||
if (sscanf(rcvd + p, "%s", tempo) == 1) {
|
if (sscanf(rcvd + p, "%1099s", tempo) == 1) { // tempo[1100], server data
|
||||||
if (strlen(tempo) < sizeof(retour->contenttype) - 2) // pas trop long!!
|
if (strlen(tempo) < sizeof(retour->contenttype) - 2) // pas trop long!!
|
||||||
strcpybuff(retour->contenttype, tempo);
|
strcpybuff(retour->contenttype, tempo);
|
||||||
else
|
else
|
||||||
@@ -1645,7 +1439,7 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
a = strchr(rcvd + p, '/');
|
a = strchr(rcvd + p, '/');
|
||||||
if (a != NULL) {
|
if (a != NULL) {
|
||||||
a++;
|
a++;
|
||||||
if (sscanf(a, LLintP, &retour->crange) == 1) {
|
if (sscanf(a, LLintP, &retour->crange) == 1 && retour->crange >= 0) {
|
||||||
retour->crange_start = 0;
|
retour->crange_start = 0;
|
||||||
retour->crange_end = retour->crange - 1;
|
retour->crange_end = retour->crange - 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -1653,6 +1447,12 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// A valid Content-Range has no negative field; reject hostile values so
|
||||||
|
// the crange +/- 1 arithmetic downstream cannot sign-overflow (UB).
|
||||||
|
if (retour->crange_start < 0 || retour->crange_end < 0 ||
|
||||||
|
retour->crange < 0) {
|
||||||
|
retour->crange_start = retour->crange_end = retour->crange = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ((p = strfield(rcvd, "Connection:")) != 0) {
|
} else if ((p = strfield(rcvd, "Connection:")) != 0) {
|
||||||
char *a = rcvd + p;
|
char *a = rcvd + p;
|
||||||
@@ -1716,27 +1516,15 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
if (a)
|
if (a)
|
||||||
*a = '\0';
|
*a = '\0';
|
||||||
}
|
}
|
||||||
sscanf(a, "%s", tempo);
|
// Bound to tempo[1100]; no token => leave empty, don't read uninit tempo.
|
||||||
if (strlen(tempo) < 64) // pas trop long!!
|
if (sscanf(a, "%1099s", tempo) == 1 && strlen(tempo) < 64)
|
||||||
strcpybuff(retour->contentencoding, tempo);
|
strcpybuff(retour->contentencoding, tempo);
|
||||||
else
|
else
|
||||||
retour->contentencoding[0] = '\0'; // erreur
|
retour->contentencoding[0] = '\0';
|
||||||
#if HTS_USEZLIB
|
/* A coding to undo (or one we can not undo, which must fail the fetch
|
||||||
/* Check known encodings */
|
rather than save the coded bytes as the page) */
|
||||||
if (retour->contentencoding[0]) {
|
if (hts_codec_parse(retour->contentencoding) != HTS_CODEC_IDENTITY)
|
||||||
if ((strfield2(retour->contentencoding, "gzip"))
|
retour->compressed = 1;
|
||||||
|| (strfield2(retour->contentencoding, "x-gzip"))
|
|
||||||
/*
|
|
||||||
|| (strfield2(retour->contentencoding, "compress"))
|
|
||||||
|| (strfield2(retour->contentencoding, "x-compress"))
|
|
||||||
*/
|
|
||||||
|| (strfield2(retour->contentencoding, "deflate"))
|
|
||||||
|| (strfield2(retour->contentencoding, "x-deflate"))
|
|
||||||
) {
|
|
||||||
retour->compressed = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
} else if ((p = strfield(rcvd, "Location:")) != 0) {
|
} else if ((p = strfield(rcvd, "Location:")) != 0) {
|
||||||
if (retour) {
|
if (retour) {
|
||||||
@@ -1750,7 +1538,8 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
retour->location[0] = '\0';
|
retour->location[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (((p = strfield(rcvd, "Set-Cookie:")) != 0) && (cookie)) { // ohh un cookie
|
} else if (((p = strfield(rcvd, "Set-Cookie:")) != 0) &&
|
||||||
|
(cookie)) { // ohh un cookie
|
||||||
char *a = rcvd + p; // pointeur
|
char *a = rcvd + p; // pointeur
|
||||||
char domain[256]; // domaine cookie (.netscape.com)
|
char domain[256]; // domaine cookie (.netscape.com)
|
||||||
char path[256]; // chemin (/)
|
char path[256]; // chemin (/)
|
||||||
@@ -1760,6 +1549,9 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
#if DEBUG_COOK
|
#if DEBUG_COOK
|
||||||
printf("set-cookie detected\n");
|
printf("set-cookie detected\n");
|
||||||
#endif
|
#endif
|
||||||
|
/* Over-long host overflows the fail-safe domain[] copy (abort); drop it. */
|
||||||
|
if (adr && strlen(jump_identification_const(adr)) >= sizeof(domain))
|
||||||
|
return;
|
||||||
while(*a) {
|
while(*a) {
|
||||||
char *token_st, *token_end;
|
char *token_st, *token_end;
|
||||||
char *value_st, *value_end;
|
char *value_st, *value_end;
|
||||||
@@ -1794,10 +1586,8 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
a++; // sauter espaces
|
a++; // sauter espaces
|
||||||
value_st = a;
|
value_st = a;
|
||||||
while((*a != ';') && (*a))
|
while((*a != ';') && (*a))
|
||||||
a++; // prochain ;
|
a++; // prochain ;
|
||||||
//while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++; // prochain " (et pas \")
|
|
||||||
value_end = a;
|
value_end = a;
|
||||||
//if (*a==';') { // finit par un ;
|
|
||||||
// vérifier débordements
|
// vérifier débordements
|
||||||
if ((((int) (token_end - token_st)) < 200)
|
if ((((int) (token_end - token_st)) < 200)
|
||||||
&& (((int) (value_end - value_st)) < 8000)
|
&& (((int) (value_end - value_st)) < 8000)
|
||||||
@@ -2058,6 +1848,15 @@ LLint http_xfread1(htsblk * r, int bufl) {
|
|||||||
|
|
||||||
if (bufl > 0) {
|
if (bufl > 0) {
|
||||||
if (!r->is_write) { // stocker en mémoire
|
if (!r->is_write) { // stocker en mémoire
|
||||||
|
// In-memory content must fit a 32-bit index (allocs below add 1, reads
|
||||||
|
// use int offsets): reject a hostile Content-Length or endless stream.
|
||||||
|
const LLint inmem_want =
|
||||||
|
(r->totalsize >= 0) ? r->totalsize : (r->size + bufl);
|
||||||
|
if (inmem_want >= INT32_MAX) {
|
||||||
|
r->statuscode = STATUSCODE_INVALID;
|
||||||
|
strcpybuff(r->msg, "In-memory content too large");
|
||||||
|
return READ_ERROR;
|
||||||
|
}
|
||||||
if (r->totalsize >= 0) { // totalsize déterminé ET ALLOUE
|
if (r->totalsize >= 0) { // totalsize déterminé ET ALLOUE
|
||||||
if (r->adr == NULL) {
|
if (r->adr == NULL) {
|
||||||
r->adr = (char *) malloct((size_t) r->totalsize + 1);
|
r->adr = (char *) malloct((size_t) r->totalsize + 1);
|
||||||
@@ -2139,8 +1938,6 @@ LLint http_xfread1(htsblk * r, int bufl) {
|
|||||||
nl = READ_ERROR;
|
nl = READ_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
|
|
||||||
// nl=-1; // break
|
|
||||||
|
|
||||||
// libérer bloc tempo
|
// libérer bloc tempo
|
||||||
freet(buff);
|
freet(buff);
|
||||||
@@ -2228,9 +2025,6 @@ htsblk http_test(httrackp * opt, const char *adr, const char *fil, char *loc) {
|
|||||||
T_SOC soc;
|
T_SOC soc;
|
||||||
htsblk retour;
|
htsblk retour;
|
||||||
|
|
||||||
//int rcvsize=-1;
|
|
||||||
//char* rcv=NULL; // adresse de retour
|
|
||||||
//int bufl=TAILLE_BUFFER; // 8Ko de buffer
|
|
||||||
TStamp tl;
|
TStamp tl;
|
||||||
int timeout = 30; // timeout pour un check (arbitraire) // **
|
int timeout = 30; // timeout pour un check (arbitraire) // **
|
||||||
|
|
||||||
@@ -2239,11 +2033,8 @@ htsblk http_test(httrackp * opt, const char *adr, const char *fil, char *loc) {
|
|||||||
|
|
||||||
loc[0] = '\0';
|
loc[0] = '\0';
|
||||||
hts_init_htsblk(&retour);
|
hts_init_htsblk(&retour);
|
||||||
//memset(&retour, 0, sizeof(htsblk)); // effacer
|
|
||||||
retour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
retour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
||||||
|
|
||||||
//soc=http_fopen(adr,fil,&retour,NULL); // ouvrir, + header
|
|
||||||
|
|
||||||
// on ouvre en head, et on traite l'en tête
|
// on ouvre en head, et on traite l'en tête
|
||||||
soc = http_xfopen(opt, 1, 0, 1, NULL, adr, fil, &retour); // ouvrir HEAD, + envoi header
|
soc = http_xfopen(opt, 1, 0, 1, NULL, adr, fil, &retour); // ouvrir HEAD, + envoi header
|
||||||
|
|
||||||
@@ -2565,6 +2356,10 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
|
|||||||
// effacer adrfil->adr et adrfil->fil
|
// effacer adrfil->adr et adrfil->fil
|
||||||
adrfil->adr[0] = adrfil->fil[0] = '\0';
|
adrfil->adr[0] = adrfil->fil[0] = '\0';
|
||||||
|
|
||||||
|
// Reject an over-long URL: a root-relative path is copied whole into fil[].
|
||||||
|
if (strlen(url) >= HTS_URLMAXSIZE * 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
#if HDEBUG
|
#if HDEBUG
|
||||||
printf("protocol: %s\n", url);
|
printf("protocol: %s\n", url);
|
||||||
#endif
|
#endif
|
||||||
@@ -2619,12 +2414,16 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
|
|||||||
|
|
||||||
// chemin www... trop long!!
|
// chemin www... trop long!!
|
||||||
if ((((int) (q - p))) > HTS_URLMAXSIZE) {
|
if ((((int) (q - p))) > HTS_URLMAXSIZE) {
|
||||||
//strcpybuff(retour.msg,"Path too long");
|
|
||||||
return -1; // erreur
|
return -1; // erreur
|
||||||
}
|
}
|
||||||
// recopier adrfil->adresse www..
|
// recopier adrfil->adresse www..
|
||||||
strncatbuff(adrfil->adr, p, ((int) (q - p)));
|
strncatbuff(adrfil->adr, p, ((int) (q - p)));
|
||||||
// *( adrfil->adr+( ((int) q) - ((int) p) ) )=0; // faut arrêter la fumette!
|
// *( adrfil->adr+( ((int) q) - ((int) p) ) )=0; // faut arrêter la fumette!
|
||||||
|
|
||||||
|
// fil[] holds the path plus a possible leading '/' the top strlen() misses.
|
||||||
|
if (strlen(q) >= sizeof(adrfil->fil) - (q[0] != '/' ? 1 : 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
// recopier chemin /pub/..
|
// recopier chemin /pub/..
|
||||||
if (q[0] != '/') // page par défaut (/)
|
if (q[0] != '/') // page par défaut (/)
|
||||||
strcatbuff(adrfil->fil, "/");
|
strcatbuff(adrfil->fil, "/");
|
||||||
@@ -2641,7 +2440,7 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
|
|||||||
if (*p == '/' || *p == '\\') { /* adrfil->file:///.. */
|
if (*p == '/' || *p == '\\') { /* adrfil->file:///.. */
|
||||||
strcatbuff(adrfil->fil, p); // fichier local ; adrfil->adr="#"
|
strcatbuff(adrfil->fil, p); // fichier local ; adrfil->adr="#"
|
||||||
} else {
|
} else {
|
||||||
if (p[1] != ':') {
|
if (*p == '\0' || p[1] != ':') { /* empty path: not a DOS drive letter */
|
||||||
strcatbuff(adrfil->fil, "//"); /* adrfil->file://server/foo */
|
strcatbuff(adrfil->fil, "//"); /* adrfil->file://server/foo */
|
||||||
strcatbuff(adrfil->fil, p);
|
strcatbuff(adrfil->fil, p);
|
||||||
} else {
|
} else {
|
||||||
@@ -2805,7 +2604,6 @@ void deletesoc_r(htsblk * r) {
|
|||||||
#if HTS_USEOPENSSL
|
#if HTS_USEOPENSSL
|
||||||
if (r->ssl_con) {
|
if (r->ssl_con) {
|
||||||
SSL_shutdown(r->ssl_con);
|
SSL_shutdown(r->ssl_con);
|
||||||
// SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
|
|
||||||
SSL_free(r->ssl_con);
|
SSL_free(r->ssl_con);
|
||||||
r->ssl_con = NULL;
|
r->ssl_con = NULL;
|
||||||
}
|
}
|
||||||
@@ -3104,12 +2902,11 @@ HTSEXT_API char *int2char(strc_int2bytes2 * strc, int n) {
|
|||||||
/* See http://physics.nist.gov/cuu/Units/binary.html */
|
/* See http://physics.nist.gov/cuu/Units/binary.html */
|
||||||
#define ToLLint(a) ((LLint)(a))
|
#define ToLLint(a) ((LLint)(a))
|
||||||
#define ToLLintKiB (ToLLint(1024))
|
#define ToLLintKiB (ToLLint(1024))
|
||||||
#define ToLLintMiB (ToLLintKiB*ToLLintKiB)
|
#define ToLLintMiB (ToLLintKiB * ToLLintKiB)
|
||||||
#ifdef HTS_LONGLONG
|
#define ToLLintGiB (ToLLintKiB * ToLLintKiB * ToLLintKiB)
|
||||||
#define ToLLintGiB (ToLLintKiB*ToLLintKiB*ToLLintKiB)
|
#define ToLLintTiB (ToLLintKiB * ToLLintKiB * ToLLintKiB * ToLLintKiB)
|
||||||
#define ToLLintTiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
|
#define ToLLintPiB \
|
||||||
#define ToLLintPiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
|
(ToLLintKiB * ToLLintKiB * ToLLintKiB * ToLLintKiB * ToLLintKiB)
|
||||||
#endif
|
|
||||||
HTSEXT_API char **int2bytes2(strc_int2bytes2 * strc, LLint n) {
|
HTSEXT_API char **int2bytes2(strc_int2bytes2 * strc, LLint n) {
|
||||||
if (n < ToLLintKiB) {
|
if (n < ToLLintKiB) {
|
||||||
sprintf(strc->buff1, "%d", (int) (LLint) n);
|
sprintf(strc->buff1, "%d", (int) (LLint) n);
|
||||||
@@ -3118,9 +2915,7 @@ HTSEXT_API char **int2bytes2(strc_int2bytes2 * strc, LLint n) {
|
|||||||
sprintf(strc->buff1, "%d,%02d", (int) ((LLint) (n / ToLLintKiB)),
|
sprintf(strc->buff1, "%d,%02d", (int) ((LLint) (n / ToLLintKiB)),
|
||||||
(int) ((LLint) ((n % ToLLintKiB) * 100) / ToLLintKiB));
|
(int) ((LLint) ((n % ToLLintKiB) * 100) / ToLLintKiB));
|
||||||
strcpybuff(strc->buff2, "KiB");
|
strcpybuff(strc->buff2, "KiB");
|
||||||
}
|
} else if (n < ToLLintGiB) {
|
||||||
#ifdef HTS_LONGLONG
|
|
||||||
else if (n < ToLLintGiB) {
|
|
||||||
sprintf(strc->buff1, "%d,%02d", (int) ((LLint) (n / (ToLLintMiB))),
|
sprintf(strc->buff1, "%d,%02d", (int) ((LLint) (n / (ToLLintMiB))),
|
||||||
(int) ((LLint) (((n % (ToLLintMiB)) * 100) / (ToLLintMiB))));
|
(int) ((LLint) (((n % (ToLLintMiB)) * 100) / (ToLLintMiB))));
|
||||||
strcpybuff(strc->buff2, "MiB");
|
strcpybuff(strc->buff2, "MiB");
|
||||||
@@ -3137,13 +2932,6 @@ HTSEXT_API char **int2bytes2(strc_int2bytes2 * strc, LLint n) {
|
|||||||
(int) ((LLint) (((n % (ToLLintPiB)) * 100) / (ToLLintPiB))));
|
(int) ((LLint) (((n % (ToLLintPiB)) * 100) / (ToLLintPiB))));
|
||||||
strcpybuff(strc->buff2, "PiB");
|
strcpybuff(strc->buff2, "PiB");
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
else {
|
|
||||||
sprintf(strc->buff1, "%d,%02d", (int) ((LLint) (n / (ToLLintMiB))),
|
|
||||||
(int) ((LLint) (((n % (ToLLintMiB)) * 100) / (ToLLintMiB))));
|
|
||||||
strcpybuff(strc->buff2, "MiB");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
strc->buffadr[0] = strc->buff1;
|
strc->buffadr[0] = strc->buff1;
|
||||||
strc->buffadr[1] = strc->buff2;
|
strc->buffadr[1] = strc->buff2;
|
||||||
return strc->buffadr;
|
return strc->buffadr;
|
||||||
@@ -3194,7 +2982,6 @@ int finput(T_SOC fd, char *s, int max) {
|
|||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
//c=fgetc(fp);
|
|
||||||
if (read((int) fd, &c, 1) <= 0) {
|
if (read((int) fd, &c, 1) <= 0) {
|
||||||
c = 0;
|
c = 0;
|
||||||
}
|
}
|
||||||
@@ -3210,7 +2997,7 @@ int finput(T_SOC fd, char *s, int max) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while((c != 0) && (j < max - 1));
|
} while ((c != 0) && (j < max - 1));
|
||||||
s[j] = '\0';
|
s[j] = '\0';
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
@@ -3926,6 +3713,10 @@ const char *jump_protocol_const(const char *source) {
|
|||||||
source += p;
|
source += p;
|
||||||
else if ((p = strfield(source, "file:")))
|
else if ((p = strfield(source, "file:")))
|
||||||
source += p;
|
source += p;
|
||||||
|
else if ((p = strfield(source, "socks5h:")))
|
||||||
|
source += p;
|
||||||
|
else if ((p = strfield(source, "socks5:")))
|
||||||
|
source += p;
|
||||||
// net_path
|
// net_path
|
||||||
if (strncmp(source, "//", 2) == 0)
|
if (strncmp(source, "//", 2) == 0)
|
||||||
source += 2;
|
source += 2;
|
||||||
@@ -3934,6 +3725,48 @@ const char *jump_protocol_const(const char *source) {
|
|||||||
|
|
||||||
DECLARE_NON_CONST_VERSION(jump_protocol)
|
DECLARE_NON_CONST_VERSION(jump_protocol)
|
||||||
|
|
||||||
|
hts_boolean hts_proxy_is_socks(const char *name) {
|
||||||
|
if (name == NULL)
|
||||||
|
return HTS_FALSE;
|
||||||
|
return (strfield(name, "socks5h:") || strfield(name, "socks5:")) ? HTS_TRUE
|
||||||
|
: HTS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default proxy port for a -P argument, keyed on the scheme
|
||||||
|
static int proxy_default_port(const char *arg) {
|
||||||
|
return hts_proxy_is_socks(arg) ? 1080 : 8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hts_parse_proxy(const char *arg, char *name, size_t name_size, int *port) {
|
||||||
|
const char *authority = strstr(arg, "://");
|
||||||
|
const char *a;
|
||||||
|
size_t namelen;
|
||||||
|
|
||||||
|
if (name_size == 0)
|
||||||
|
return;
|
||||||
|
// scan back to the port ':' (or userinfo '@'), but never past the authority,
|
||||||
|
// so a scheme's own colon is not read as a port separator; inspect a[-1] from
|
||||||
|
// one-past-end so no pointer below the string is ever formed
|
||||||
|
authority = (authority != NULL) ? authority + 3 : arg;
|
||||||
|
a = arg + strlen(arg);
|
||||||
|
while (a > authority && a[-1] != ':' && a[-1] != '@')
|
||||||
|
a--;
|
||||||
|
if (a > authority && a[-1] == ':') {
|
||||||
|
int p = -1;
|
||||||
|
|
||||||
|
sscanf(a, "%d", &p);
|
||||||
|
*port = (p > 0) ? p : proxy_default_port(arg);
|
||||||
|
namelen = (size_t) (a - 1 - arg);
|
||||||
|
} else {
|
||||||
|
*port = proxy_default_port(arg);
|
||||||
|
namelen = strlen(arg);
|
||||||
|
}
|
||||||
|
if (namelen >= name_size) // arg is user-controlled: truncate, don't overflow
|
||||||
|
namelen = name_size - 1;
|
||||||
|
memcpy(name, arg, namelen);
|
||||||
|
name[namelen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// codage base 64 a vers b
|
// codage base 64 a vers b
|
||||||
void code64(unsigned char *a, int size_a, unsigned char *b, int crlf) {
|
void code64(unsigned char *a, int size_a, unsigned char *b, int crlf) {
|
||||||
int i1 = 0, i2 = 0, i3 = 0, i4 = 0;
|
int i1 = 0, i2 = 0, i3 = 0, i4 = 0;
|
||||||
@@ -4419,11 +4252,6 @@ HTSEXT_API void get_httptype(httrackp *opt, char *s, const char *fil,
|
|||||||
(void) get_httptype_sized(opt, s, HTS_MIMETYPE_SIZE, fil, flag);
|
(void) get_httptype_sized(opt, s, HTS_MIMETYPE_SIZE, fil, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advertised Accept-Encoding; gzip and deflate both decode via hts_zunpack */
|
|
||||||
const char *hts_acceptencoding(hts_boolean compressible) {
|
|
||||||
return compressible ? "gzip, deflate, identity;q=0.9" : "identity";
|
|
||||||
}
|
|
||||||
|
|
||||||
// get type of fil (php)
|
// get type of fil (php)
|
||||||
// s: buffer (text/html) or NULL
|
// s: buffer (text/html) or NULL
|
||||||
// return: 1 if known by user
|
// return: 1 if known by user
|
||||||
@@ -4869,7 +4697,6 @@ LLint check_downloadable_bytes(int rate) {
|
|||||||
|
|
||||||
time_now = mtime_local();
|
time_now = mtime_local();
|
||||||
elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
|
elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
|
||||||
// NO totally stupid - elapsed_useconds+=1000; // for the next second, too
|
|
||||||
bytes_transferred_during_period =
|
bytes_transferred_during_period =
|
||||||
(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[id_timer]);
|
(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[id_timer]);
|
||||||
|
|
||||||
@@ -4882,32 +4709,6 @@ LLint check_downloadable_bytes(int rate) {
|
|||||||
return TAILLE_BUFFER;
|
return TAILLE_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// 0 : OK
|
|
||||||
// 1 : slow down
|
|
||||||
#if 0
|
|
||||||
int HTS_TOTAL_RECV_CHECK(int var) {
|
|
||||||
if (HTS_STAT.HTS_TOTAL_RECV_STATE)
|
|
||||||
return 1;
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) {
|
|
||||||
var = min(var,32);
|
|
||||||
Sleep(250);
|
|
||||||
} else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) {
|
|
||||||
var = min(var,256);
|
|
||||||
Sleep(100);
|
|
||||||
} else {
|
|
||||||
var/=2;
|
|
||||||
if (var<=0) var=1;
|
|
||||||
Sleep(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
|
// Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
|
||||||
// returns:
|
// returns:
|
||||||
// >0 : data received
|
// >0 : data received
|
||||||
@@ -4916,7 +4717,6 @@ int HTS_TOTAL_RECV_CHECK(int var) {
|
|||||||
int hts_read(htsblk * r, char *buff, int size) {
|
int hts_read(htsblk * r, char *buff, int size) {
|
||||||
int retour;
|
int retour;
|
||||||
|
|
||||||
// return read(soc,buff,size);
|
|
||||||
if (r->is_file) {
|
if (r->is_file) {
|
||||||
#if HTS_WIDE_DEBUG
|
#if HTS_WIDE_DEBUG
|
||||||
DEBUG_W("read(%p, %d, %d)\n" _(void *)buff _(int) size _(int) r->fp);
|
DEBUG_W("read(%p, %d, %d)\n" _(void *)buff _(int) size _(int) r->fp);
|
||||||
@@ -4934,7 +4734,6 @@ int hts_read(htsblk * r, char *buff, int size) {
|
|||||||
if (r->soc == INVALID_SOCKET)
|
if (r->soc == INVALID_SOCKET)
|
||||||
printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
|
printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
|
||||||
#endif
|
#endif
|
||||||
//HTS_TOTAL_RECV_CHECK(size); // Diminuer au besoin si trop de données reçues
|
|
||||||
#if HTS_USEOPENSSL
|
#if HTS_USEOPENSSL
|
||||||
if (r->ssl) {
|
if (r->ssl) {
|
||||||
retour = SSL_read(r->ssl_con, buff, size);
|
retour = SSL_read(r->ssl_con, buff, size);
|
||||||
@@ -5101,7 +4900,7 @@ static struct addrinfo *resolver_make_ai(const char *ip, int want_family) {
|
|||||||
return ai;
|
return ai;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void override_freeaddrinfo(struct addrinfo *res) {
|
static void HTS_RESOLVER_CALL override_freeaddrinfo(struct addrinfo *res) {
|
||||||
while (res != NULL) {
|
while (res != NULL) {
|
||||||
struct addrinfo *const next = res->ai_next;
|
struct addrinfo *const next = res->ai_next;
|
||||||
|
|
||||||
@@ -5111,9 +4910,10 @@ static void override_freeaddrinfo(struct addrinfo *res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int override_getaddrinfo(const char *node, const char *service,
|
static int HTS_RESOLVER_CALL override_getaddrinfo(const char *node,
|
||||||
const struct addrinfo *hints,
|
const char *service,
|
||||||
struct addrinfo **res) {
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res) {
|
||||||
const char *const spec = getenv("HTTRACK_DEBUG_RESOLVE");
|
const char *const spec = getenv("HTTRACK_DEBUG_RESOLVE");
|
||||||
const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC;
|
const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC;
|
||||||
const char *colon;
|
const char *colon;
|
||||||
@@ -5369,18 +5169,13 @@ SOCaddr* hts_dns_resolve(httrackp * opt, const char *_iadr, SOCaddr *const addr)
|
|||||||
|
|
||||||
// --- Tracage des mallocs() ---
|
// --- Tracage des mallocs() ---
|
||||||
#ifdef HTS_TRACE_MALLOC
|
#ifdef HTS_TRACE_MALLOC
|
||||||
//#define htsLocker(A, N) htsLocker(A, N)
|
|
||||||
#define htsLocker(A, N) do {} while(0)
|
#define htsLocker(A, N) do {} while(0)
|
||||||
static mlink trmalloc = { NULL, 0, 0, NULL };
|
static mlink trmalloc = { NULL, 0, 0, NULL };
|
||||||
|
|
||||||
static int trmalloc_id = 0;
|
static int trmalloc_id = 0;
|
||||||
static htsmutex *mallocMutex = NULL;
|
static htsmutex *mallocMutex = NULL;
|
||||||
static void hts_meminit(void) {
|
|
||||||
//if (mallocMutex == NULL) {
|
static void hts_meminit(void) {}
|
||||||
// mallocMutex = calloc(sizeof(*mallocMutex), 1);
|
|
||||||
// htsLocker(mallocMutex, -999);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
void *hts_malloc(size_t len) {
|
void *hts_malloc(size_t len) {
|
||||||
void *adr;
|
void *adr;
|
||||||
|
|
||||||
@@ -5464,7 +5259,6 @@ void hts_free(void *adr) {
|
|||||||
htsboundary);
|
htsboundary);
|
||||||
lnk->next = lnk->next->next;
|
lnk->next = lnk->next->next;
|
||||||
free((void *) blk_free);
|
free((void *) blk_free);
|
||||||
//blk_free->id=-1;
|
|
||||||
free((char *) adr - bsize);
|
free((char *) adr - bsize);
|
||||||
htsLocker(mallocMutex, 0);
|
htsLocker(mallocMutex, 0);
|
||||||
return;
|
return;
|
||||||
@@ -5533,7 +5327,6 @@ mlink *hts_find(char *adr) {
|
|||||||
|
|
||||||
if (depl < 0)
|
if (depl < 0)
|
||||||
depl = -depl;
|
depl = -depl;
|
||||||
//assertf(depl < 512000); /* near the stack frame.. doesn't look like malloc but stack variable */
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5589,8 +5382,7 @@ int ftp_available(void) {
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int ftp_available(void) {
|
int ftp_available(void) {
|
||||||
return 1; // ok!
|
return 1; // ok!
|
||||||
//return 0; // SOUS UNIX, PROBLEMESs
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -5804,7 +5596,6 @@ HTSEXT_API int hts_init(void) {
|
|||||||
assertf("OpenSSL version seems vulnerable to heartbleed bug (CVE-2014-0160)" == NULL);
|
assertf("OpenSSL version seems vulnerable to heartbleed bug (CVE-2014-0160)" == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenSSL_add_all_algorithms();
|
|
||||||
openssl_ctx = SSL_CTX_new(method);
|
openssl_ctx = SSL_CTX_new(method);
|
||||||
if (!openssl_ctx) {
|
if (!openssl_ctx) {
|
||||||
fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new()\n");
|
fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new()\n");
|
||||||
@@ -6018,17 +5809,7 @@ int multipleStringMatch(const char *s, const char *match) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HTSEXT_API httrackp *hts_create_opt(void) {
|
HTSEXT_API httrackp *hts_create_opt(void) {
|
||||||
#if ( defined(_WIN32) || defined(__ANDROID__) )
|
static const char *defaultModules[] = {"httrack-plugin", NULL};
|
||||||
static const char *defaultModules[] = {
|
|
||||||
"htsswf", "htsjava", "httrack-plugin", NULL
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
#ifndef HTS_LIBHTSJAVA_NAME
|
|
||||||
#define HTS_LIBHTSJAVA_NAME "libhtsjava.so" /* non-autoconf fallback */
|
|
||||||
#endif
|
|
||||||
static const char *defaultModules[] = {"libhtsswf.so.1", HTS_LIBHTSJAVA_NAME,
|
|
||||||
"httrack-plugin", NULL};
|
|
||||||
#endif
|
|
||||||
httrackp *opt = malloc(sizeof(httrackp));
|
httrackp *opt = malloc(sizeof(httrackp));
|
||||||
|
|
||||||
/* default options */
|
/* default options */
|
||||||
@@ -6111,6 +5892,7 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
StringCopy(opt->footer, HTS_DEFAULT_FOOTER);
|
StringCopy(opt->footer, HTS_DEFAULT_FOOTER);
|
||||||
StringCopy(opt->strip_query, "");
|
StringCopy(opt->strip_query, "");
|
||||||
StringCopy(opt->cookies_file, "");
|
StringCopy(opt->cookies_file, "");
|
||||||
|
StringCopy(opt->why_url, "");
|
||||||
opt->pause_min_ms = 0;
|
opt->pause_min_ms = 0;
|
||||||
opt->pause_max_ms = 0;
|
opt->pause_max_ms = 0;
|
||||||
opt->ftp_proxy = HTS_TRUE;
|
opt->ftp_proxy = HTS_TRUE;
|
||||||
@@ -6126,7 +5908,6 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
opt->log = stdout;
|
opt->log = stdout;
|
||||||
opt->errlog = stderr;
|
opt->errlog = stderr;
|
||||||
opt->flush = HTS_TRUE;
|
opt->flush = HTS_TRUE;
|
||||||
// opt->aff_progress=0;
|
|
||||||
opt->keyboard = HTS_FALSE;
|
opt->keyboard = HTS_FALSE;
|
||||||
//
|
//
|
||||||
StringCopy(opt->path_html, "");
|
StringCopy(opt->path_html, "");
|
||||||
@@ -6136,8 +5917,8 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
//
|
//
|
||||||
opt->maxlink = 100000; // 100,000 liens max par défaut
|
opt->maxlink = 100000; // 100,000 liens max par défaut
|
||||||
opt->maxfilter = 200; // 200 filtres max par défaut
|
opt->maxfilter = 200; // 200 filtres max par défaut
|
||||||
opt->maxcache = 1048576 * 32; // a peu près 32Mo en cache max -- OPTION NON PARAMETRABLE POUR L'INSTANT --
|
opt->maxcache = 1048576 * 32; // a peu près 32Mo en cache max -- OPTION NON
|
||||||
//opt->maxcache_anticipate=256; // maximum de liens à anticiper
|
// PARAMETRABLE POUR L'INSTANT --
|
||||||
opt->maxtime = -1; // temps max en secondes
|
opt->maxtime = -1; // temps max en secondes
|
||||||
opt->maxrate = 100000; // taux maxi
|
opt->maxrate = 100000; // taux maxi
|
||||||
opt->maxconn = 5.0; // nombre connexions/s
|
opt->maxconn = 5.0; // nombre connexions/s
|
||||||
@@ -6259,6 +6040,7 @@ HTSEXT_API void hts_free_opt(httrackp * opt) {
|
|||||||
StringFree(opt->mod_blacklist);
|
StringFree(opt->mod_blacklist);
|
||||||
StringFree(opt->strip_query);
|
StringFree(opt->strip_query);
|
||||||
StringFree(opt->cookies_file);
|
StringFree(opt->cookies_file);
|
||||||
|
StringFree(opt->why_url);
|
||||||
|
|
||||||
StringFree(opt->path_html);
|
StringFree(opt->path_html);
|
||||||
StringFree(opt->path_html_utf8);
|
StringFree(opt->path_html_utf8);
|
||||||
@@ -6290,11 +6072,9 @@ const hts_stat_struct* hts_get_stats(httrackp * opt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// defaut wrappers
|
// defaut wrappers
|
||||||
static void __cdecl htsdefault_init(t_hts_callbackarg * carg) {
|
static void __cdecl htsdefault_init(t_hts_callbackarg *carg) {}
|
||||||
}
|
|
||||||
static void __cdecl htsdefault_uninit(t_hts_callbackarg * carg) {
|
static void __cdecl htsdefault_uninit(t_hts_callbackarg *carg) {}
|
||||||
// hts_freevar();
|
|
||||||
}
|
|
||||||
static int __cdecl htsdefault_start(t_hts_callbackarg * carg, httrackp * opt) {
|
static int __cdecl htsdefault_start(t_hts_callbackarg * carg, httrackp * opt) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/htslib.h
39
src/htslib.h
@@ -171,7 +171,6 @@ HTSEXT_API const char* hts_version(void);
|
|||||||
// fonctions unix/winsock
|
// fonctions unix/winsock
|
||||||
int hts_read(htsblk * r, char *buff, int size);
|
int hts_read(htsblk * r, char *buff, int size);
|
||||||
|
|
||||||
//int HTS_TOTAL_RECV_CHECK(int var);
|
|
||||||
LLint check_downloadable_bytes(int rate);
|
LLint check_downloadable_bytes(int rate);
|
||||||
|
|
||||||
HTSEXT_API int hts_uninit_module(void);
|
HTSEXT_API int hts_uninit_module(void);
|
||||||
@@ -185,12 +184,11 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode, const char *xsend
|
|||||||
const char *referer_adr, const char *referer_fil,
|
const char *referer_adr, const char *referer_fil,
|
||||||
htsblk * retour);
|
htsblk * retour);
|
||||||
/* Build the request "Cookie:" header line for stored cookies matching
|
/* Build the request "Cookie:" header line for stored cookies matching
|
||||||
domain/path into dst (NUL-terminated). Exposed for the -#Q self-test;
|
domain/path into dst (NUL-terminated), wrapping the logic http_sendhead()
|
||||||
wraps the same logic http_sendhead() uses. Returns cookies emitted. */
|
uses. Returns cookies emitted. */
|
||||||
int http_cookie_header_selftest(t_cookie *cookie, const char *domain,
|
int http_cookie_header(t_cookie *cookie, const char *domain, const char *path,
|
||||||
const char *path, char *dst, size_t dst_size);
|
char *dst, size_t dst_size);
|
||||||
|
|
||||||
//int newhttp(char* iadr,char* err=NULL);
|
|
||||||
T_SOC newhttp(httrackp * opt, const char *iadr, htsblk * retour, int port,
|
T_SOC newhttp(httrackp * opt, const char *iadr, htsblk * retour, int port,
|
||||||
int waitconnect);
|
int waitconnect);
|
||||||
/* Like newhttp(), but connect to the addr_index-th resolved address of the host
|
/* Like newhttp(), but connect to the addr_index-th resolved address of the host
|
||||||
@@ -209,15 +207,9 @@ int check_readinput(htsblk * r);
|
|||||||
int check_readinput_t(T_SOC soc, int timeout);
|
int check_readinput_t(T_SOC soc, int timeout);
|
||||||
int check_writeinput_t(T_SOC soc, int timeout);
|
int check_writeinput_t(T_SOC soc, int timeout);
|
||||||
|
|
||||||
/* Open an HTTP CONNECT tunnel through the active proxy for an https request:
|
/* TRUE if this -P proxy name (which keeps its scheme) is a SOCKS5 proxy. */
|
||||||
`retour->soc` must already be TCP-connected to the proxy, and `adr` is the
|
hts_boolean hts_proxy_is_socks(const char *name);
|
||||||
origin authority (url_adr, e.g. "https://host:port"). Sends the CONNECT
|
|
||||||
request (with Proxy-Authorization when the proxy carries credentials) and
|
|
||||||
reads the proxy's status line, so the caller's TLS handshake then runs
|
|
||||||
end-to-end with the origin. Blocks up to `timeout` seconds. Returns 1 on a
|
|
||||||
2xx tunnel, 0 on failure (retour->msg/statuscode set). */
|
|
||||||
int http_proxy_tunnel(httrackp *opt, htsblk *retour, const char *adr,
|
|
||||||
int timeout);
|
|
||||||
void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * retour,
|
void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * retour,
|
||||||
char *rcvd);
|
char *rcvd);
|
||||||
void treatfirstline(htsblk * retour, const char *rcvd);
|
void treatfirstline(htsblk * retour, const char *rcvd);
|
||||||
@@ -285,15 +277,18 @@ int ishttperror(int err);
|
|||||||
int get_userhttptype(httrackp * opt, char *s, const char *fil);
|
int get_userhttptype(httrackp * opt, char *s, const char *fil);
|
||||||
int give_mimext(char *s, size_t ssize, const char *st);
|
int give_mimext(char *s, size_t ssize, const char *st);
|
||||||
|
|
||||||
/* Advertised Accept-Encoding value (no header name/CRLF); see htslib.c. */
|
|
||||||
const char *hts_acceptencoding(hts_boolean compressible);
|
|
||||||
|
|
||||||
int may_bogus_multiple(httrackp * opt, const char *mime, const char *filename);
|
int may_bogus_multiple(httrackp * opt, const char *mime, const char *filename);
|
||||||
int may_unknown2(httrackp * opt, const char *mime, const char *filename);
|
int may_unknown2(httrackp * opt, const char *mime, const char *filename);
|
||||||
|
|
||||||
const char *strrchr_limit(const char *s, char c, const char *limit);
|
const char *strrchr_limit(const char *s, char c, const char *limit);
|
||||||
char *jump_protocol(char *source);
|
char *jump_protocol(char *source);
|
||||||
const char *jump_protocol_const(const char *source);
|
const char *jump_protocol_const(const char *source);
|
||||||
|
|
||||||
|
/* Split a -P proxy argument "[scheme://][user:pass@]host[:port]" into the proxy
|
||||||
|
host string (scheme and any user:pass kept, for later stripping and auth),
|
||||||
|
written NUL-terminated into name[name_size] (truncated to fit), and the port
|
||||||
|
in *port. The port defaults by scheme: 1080 for socks5/socks5h, else 8080. */
|
||||||
|
void hts_parse_proxy(const char *arg, char *name, size_t name_size, int *port);
|
||||||
void code64(unsigned char *a, int size_a, unsigned char *b, int crlf);
|
void code64(unsigned char *a, int size_a, unsigned char *b, int crlf);
|
||||||
|
|
||||||
#define copychar(catbuff,a) concat(catbuff,(a),NULL)
|
#define copychar(catbuff,a) concat(catbuff,(a),NULL)
|
||||||
@@ -495,6 +490,14 @@ HTS_STATIC int strcmpnocase(const char *a, const char *b) {
|
|||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* MSVC ships these POSIX functions under other names. Kept out of the installed
|
||||||
|
headers: they would rewrite the same identifiers in a consumer's own code. */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define fseeko _fseeki64
|
||||||
|
#define ftello _ftelli64
|
||||||
|
#define timegm _mkgmtime
|
||||||
|
#endif
|
||||||
|
|
||||||
#define strfield2(f,s) ( (strlen(f)!=strlen(s)) ? 0 : (strfield(f,s)) )
|
#define strfield2(f,s) ( (strlen(f)!=strlen(s)) ? 0 : (strfield(f,s)) )
|
||||||
|
|
||||||
// is this MIME an hypertext MIME (text/html), html/js-style or other script/text type?
|
// is this MIME an hypertext MIME (text/html), html/js-style or other script/text type?
|
||||||
|
|||||||
@@ -55,12 +55,6 @@ extern int fspc(httrackp * opt, FILE * fp, const char *type);
|
|||||||
|
|
||||||
/* >>> Put all modules variables here */
|
/* >>> Put all modules variables here */
|
||||||
|
|
||||||
#if 0
|
|
||||||
t_gzopen gzopen = NULL;
|
|
||||||
t_gzread gzread = NULL;
|
|
||||||
t_gzclose gzclose = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int V6_is_available = HTS_INET6;
|
int V6_is_available = HTS_INET6;
|
||||||
|
|
||||||
static char WHAT_is_available[64] = "";
|
static char WHAT_is_available[64] = "";
|
||||||
@@ -112,18 +106,6 @@ int hts_parse_externals(htsmoduleStruct * str) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//static void addCallback(htscallbacks* chain, void* moduleHandle, htscallbacksfncptr exitFnc) {
|
|
||||||
// while(chain->next != NULL) {
|
|
||||||
// chain = chain->next;
|
|
||||||
// }
|
|
||||||
// chain->next = calloct(1, sizeof(htscallbacks));
|
|
||||||
// assertf(chain->next != NULL);
|
|
||||||
// chain = chain->next;
|
|
||||||
// memset(chain, 0, sizeof(*chain));
|
|
||||||
// chain->exitFnc = exitFnc;
|
|
||||||
// chain->moduleHandle = moduleHandle;
|
|
||||||
//}
|
|
||||||
|
|
||||||
void clearCallbacks(htscallbacks * chain_);
|
void clearCallbacks(htscallbacks * chain_);
|
||||||
void clearCallbacks(htscallbacks * chain_) {
|
void clearCallbacks(htscallbacks * chain_) {
|
||||||
htscallbacks *chain;
|
htscallbacks *chain;
|
||||||
|
|||||||
118
src/htsname.c
118
src/htsname.c
@@ -42,6 +42,7 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htscharset.h"
|
#include "htscharset.h"
|
||||||
#include "htsencoding.h"
|
#include "htsencoding.h"
|
||||||
#include "htssniff.h"
|
#include "htssniff.h"
|
||||||
|
#include "htscodec.h"
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -74,37 +75,6 @@ static const char *hts_tbdev[] = {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
#define URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET() \
|
|
||||||
do { \
|
|
||||||
int prev = opt->state._hts_in_html_parsing; \
|
|
||||||
while (back_pluggable_sockets_strict(sback, opt) <= 0) { \
|
|
||||||
opt->state._hts_in_html_parsing = 6; \
|
|
||||||
/* Wait .. */ \
|
|
||||||
back_wait(sback, opt, cache, 0); \
|
|
||||||
/* time limit (-E) exceeded: stop waiting for a socket (#481) */ \
|
|
||||||
if (!back_checkmirror(opt)) \
|
|
||||||
break; \
|
|
||||||
/* Transfer rate */ \
|
|
||||||
engine_stats(); \
|
|
||||||
/* Refresh various stats */ \
|
|
||||||
HTS_STAT.stat_nsocket = back_nsoc(sback); \
|
|
||||||
HTS_STAT.stat_errors = fspc(opt, NULL, "error"); \
|
|
||||||
HTS_STAT.stat_warnings = fspc(opt, NULL, "warning"); \
|
|
||||||
HTS_STAT.stat_infos = fspc(opt, NULL, "info"); \
|
|
||||||
HTS_STAT.nbk = backlinks_done(sback, opt->liens, opt->lien_tot, ptr); \
|
|
||||||
HTS_STAT.nb = back_transferred(HTS_STAT.stat_bytes, sback); \
|
|
||||||
/* Check */ \
|
|
||||||
{ \
|
|
||||||
if (!RUN_CALLBACK7( \
|
|
||||||
opt, loop, sback->lnk, sback->count, -1, ptr, opt->lien_tot, \
|
|
||||||
(int) (time_local() - HTS_STAT.stat_timestart), &HTS_STAT)) { \
|
|
||||||
return -1; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
opt->state._hts_in_html_parsing = prev; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Strip all // */
|
/* Strip all // */
|
||||||
static void cleanDoubleSlash(char *s) {
|
static void cleanDoubleSlash(char *s) {
|
||||||
int i, j;
|
int i, j;
|
||||||
@@ -182,29 +152,6 @@ typedef struct sniff_src {
|
|||||||
const char *prev_save; /* previous run's save name (cache X-Save) */
|
const char *prev_save; /* previous run's save name (cache X-Save) */
|
||||||
} sniff_src;
|
} sniff_src;
|
||||||
|
|
||||||
#if HTS_USEZLIB
|
|
||||||
/* Inflate the head of a gzip/zlib stream; 0 when undecodable. */
|
|
||||||
static size_t sniff_inflate_head(const void *in, size_t in_len, void *out,
|
|
||||||
size_t out_len) {
|
|
||||||
z_stream zs;
|
|
||||||
size_t n = 0;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&zs, 0, sizeof(zs));
|
|
||||||
if (inflateInit2(&zs, 47) != Z_OK) /* 47: gzip or zlib, autodetected */
|
|
||||||
return 0;
|
|
||||||
zs.next_in = (const Bytef *) in;
|
|
||||||
zs.avail_in = (uInt) in_len;
|
|
||||||
zs.next_out = (Bytef *) out;
|
|
||||||
zs.avail_out = (uInt) out_len;
|
|
||||||
err = inflate(&zs, Z_SYNC_FLUSH);
|
|
||||||
if (err == Z_OK || err == Z_STREAM_END || err == Z_BUF_ERROR)
|
|
||||||
n = out_len - zs.avail_out;
|
|
||||||
inflateEnd(&zs);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static size_t sniff_read_head(const char *path, void *buf, size_t len) {
|
static size_t sniff_read_head(const char *path, void *buf, size_t len) {
|
||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
FILE *const fp = FOPEN(fconv(catbuff, sizeof(catbuff), path), "rb");
|
FILE *const fp = FOPEN(fconv(catbuff, sizeof(catbuff), path), "rb");
|
||||||
@@ -236,16 +183,12 @@ static size_t sniff_slot_head(const lien_back *slot, void *buf, size_t len) {
|
|||||||
n = sniff_read_head(slot->tmpfile, buf, len);
|
n = sniff_read_head(slot->tmpfile, buf, len);
|
||||||
}
|
}
|
||||||
if (n > 0 && r->compressed) {
|
if (n > 0 && r->compressed) {
|
||||||
#if HTS_USEZLIB
|
|
||||||
unsigned char raw[HTS_SNIFF_LEN];
|
unsigned char raw[HTS_SNIFF_LEN];
|
||||||
|
|
||||||
if (n > sizeof(raw))
|
if (n > sizeof(raw))
|
||||||
n = sizeof(raw);
|
n = sizeof(raw);
|
||||||
memcpy(raw, buf, n);
|
memcpy(raw, buf, n);
|
||||||
n = sniff_inflate_head(raw, n, buf, len);
|
n = hts_codec_head(hts_codec_parse(r->contentencoding), raw, n, buf, len);
|
||||||
#else
|
|
||||||
n = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -658,11 +601,10 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
int has_been_moved = 0;
|
int has_been_moved = 0;
|
||||||
lien_adrfil current;
|
lien_adrfil current;
|
||||||
|
|
||||||
/* Ensure we don't use too many sockets by using a "testing" one
|
/* Wait for an available test slot, honoring the connection limits
|
||||||
If we have only 1 simultaneous connection authorized, wait for pending download
|
|
||||||
Wait for an available slot
|
|
||||||
*/
|
*/
|
||||||
URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
|
if (!hts_wait_available_socket(sback, opt, cache, ptr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* Rock'in */
|
/* Rock'in */
|
||||||
current.adr[0] = current.fil[0] = '\0';
|
current.adr[0] = current.fil[0] = '\0';
|
||||||
@@ -692,24 +634,11 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
if (ptr >= 0) {
|
if (ptr >= 0) {
|
||||||
back_fillmax(sback, opt, cache, ptr, numero_passe);
|
back_fillmax(sback, opt, cache, ptr, numero_passe);
|
||||||
}
|
}
|
||||||
// on est obligé d'appeler le shell pour le refresh..
|
if (!hts_loop_tick(sback, opt, b, ptr)) {
|
||||||
// Transfer rate
|
|
||||||
engine_stats();
|
|
||||||
|
|
||||||
// Refresh various stats
|
|
||||||
HTS_STAT.stat_nsocket = back_nsoc(sback);
|
|
||||||
HTS_STAT.stat_errors = fspc(opt, NULL, "error");
|
|
||||||
HTS_STAT.stat_warnings = fspc(opt, NULL, "warning");
|
|
||||||
HTS_STAT.stat_infos = fspc(opt, NULL, "info");
|
|
||||||
HTS_STAT.nbk = backlinks_done(sback, opt->liens, opt->lien_tot, ptr);
|
|
||||||
HTS_STAT.nb = back_transferred(HTS_STAT.stat_bytes, sback);
|
|
||||||
|
|
||||||
if (!RUN_CALLBACK7
|
|
||||||
(opt, loop, sback->lnk, sback->count, b, ptr, opt->lien_tot,
|
|
||||||
(int) (time_local() - HTS_STAT.stat_timestart),
|
|
||||||
&HTS_STAT)) {
|
|
||||||
return -1;
|
return -1;
|
||||||
} else if (opt->state._hts_cancel || !back_checkmirror(opt)) { // cancel 2 ou 1 (cancel parsing)
|
} else if (opt->state._hts_cancel ||
|
||||||
|
!back_checkmirror(
|
||||||
|
opt)) { // cancel level 2 or 1 (cancel parsing)
|
||||||
back_delete(opt, cache, sback, b); // cancel test
|
back_delete(opt, cache, sback, b); // cancel test
|
||||||
stop_looping = 1;
|
stop_looping = 1;
|
||||||
}
|
}
|
||||||
@@ -774,8 +703,9 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
"Loop with HEAD request (during prefetch) at %s%s",
|
"Loop with HEAD request (during prefetch) at %s%s",
|
||||||
current.adr, current.fil);
|
current.adr, current.fil);
|
||||||
}
|
}
|
||||||
// Ajouter
|
if (!hts_wait_available_socket(sback, opt,
|
||||||
URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
|
cache, ptr))
|
||||||
|
return -1;
|
||||||
if (back_add(sback, opt, cache, moved.adr, moved.fil, methode, referer_adr, referer_fil, 1) != -1) { // OK
|
if (back_add(sback, opt, cache, moved.adr, moved.fil, methode, referer_adr, referer_fil, 1) != -1) { // OK
|
||||||
hts_log_print(opt, LOG_DEBUG,
|
hts_log_print(opt, LOG_DEBUG,
|
||||||
"(during prefetch) %s (%d) to link %s at %s%s",
|
"(during prefetch) %s (%d) to link %s at %s%s",
|
||||||
@@ -1376,8 +1306,7 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
|
|
||||||
while((a > afs->save) && (*a != '.') && (*a != '/'))
|
while((a > afs->save) && (*a != '.') && (*a != '/'))
|
||||||
a--;
|
a--;
|
||||||
if (*a != '.') { // agh pas de point
|
if (*a != '.') { // agh pas de point
|
||||||
//strcatbuff(save,".none"); // a éviter
|
|
||||||
strcatbuff(afs->save, ".html"); // préférable!
|
strcatbuff(afs->save, ".html"); // préférable!
|
||||||
hts_log_print(opt, LOG_DEBUG, "Default HTML type set for %s%s => %s",
|
hts_log_print(opt, LOG_DEBUG, "Default HTML type set for %s%s => %s",
|
||||||
adr_complete, fil_complete, afs->save);
|
adr_complete, fil_complete, afs->save);
|
||||||
@@ -1515,17 +1444,6 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
fil_simplifie(afs->save);
|
fil_simplifie(afs->save);
|
||||||
|
|
||||||
/* convert name to UTF-8 ? Note: already done while parsing. */
|
/* convert name to UTF-8 ? Note: already done while parsing. */
|
||||||
//if (charset != NULL && charset[0] != '\0') {
|
|
||||||
// char *const s = hts_convertStringToUTF8(save, (int) strlen(save), charset);
|
|
||||||
|
|
||||||
// if (s != NULL) {
|
|
||||||
// hts_log_print(opt, LOG_DEBUG,
|
|
||||||
// "engine: save-name: charset conversion from '%s' to '%s' using charset '%s'",
|
|
||||||
// save, s, charset);
|
|
||||||
// strcpybuff(save, s);
|
|
||||||
// free(s);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
/* callback */
|
/* callback */
|
||||||
RUN_CALLBACK5(opt, savename, adr_complete, fil_complete, referer_adr,
|
RUN_CALLBACK5(opt, savename, adr_complete, fil_complete, referer_adr,
|
||||||
@@ -1673,10 +1591,6 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
int sameAdr = (strfield2(heap(i)->adr, normadr) != 0);
|
int sameAdr = (strfield2(heap(i)->adr, normadr) != 0);
|
||||||
int sameFil;
|
int sameFil;
|
||||||
|
|
||||||
// NO - URL hack is only for stripping // and www.
|
|
||||||
//if (opt->urlhack != 0)
|
|
||||||
// sameFil = ( strfield2(heap(i)->fil, normfil) != 0);
|
|
||||||
//else
|
|
||||||
sameFil = (strcmp(heap(i)->fil, normfil) == 0);
|
sameFil = (strcmp(heap(i)->fil, normfil) == 0);
|
||||||
if (sameAdr && sameFil) { // ok c'est le même lien, adresse déja définie
|
if (sameAdr && sameFil) { // ok c'est le même lien, adresse déja définie
|
||||||
/* Take the existing name not to screw up with cAsE sEnSiTiViTy of Linux/Unix */
|
/* Take the existing name not to screw up with cAsE sEnSiTiViTy of Linux/Unix */
|
||||||
@@ -1742,17 +1656,13 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
|
|
||||||
strcpybuff(afs->save, tempo);
|
strcpybuff(afs->save, tempo);
|
||||||
|
|
||||||
//printf("switched: %s\n",save);
|
|
||||||
|
|
||||||
} // if
|
} // if
|
||||||
}
|
}
|
||||||
#if DEBUG_SAVENAME
|
#if DEBUG_SAVENAME
|
||||||
printf("\nEnd search, %s\n", fil_complete);
|
printf("\nEnd search, %s\n", fil_complete);
|
||||||
#endif
|
#endif
|
||||||
} while(!nom_ok);
|
} while (!nom_ok);
|
||||||
|
|
||||||
}
|
}
|
||||||
//printf("'%s' %s %s\n",save,adr,fil);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/htsnet.h
15
src/htsnet.h
@@ -309,10 +309,19 @@ typedef socklen_t SOClen;
|
|||||||
self-test can script DNS answers (families, multiplicity, errors)
|
self-test can script DNS answers (families, multiplicity, errors)
|
||||||
in-process. The free function must match its getaddrinfo (a fake allocates
|
in-process. The free function must match its getaddrinfo (a fake allocates
|
||||||
its own chain), hence the pair. */
|
its own chain), hence the pair. */
|
||||||
|
/* Winsock's resolver is __stdcall; a plain pointer only compiles on x64, where
|
||||||
|
there is one convention. Backend implementations must carry this too. */
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define HTS_RESOLVER_CALL WSAAPI
|
||||||
|
#else
|
||||||
|
#define HTS_RESOLVER_CALL
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct hts_resolver_backend {
|
typedef struct hts_resolver_backend {
|
||||||
int (*getaddrinfo)(const char *node, const char *service,
|
int(HTS_RESOLVER_CALL *getaddrinfo)(const char *node, const char *service,
|
||||||
const struct addrinfo *hints, struct addrinfo **res);
|
const struct addrinfo *hints,
|
||||||
void (*freeaddrinfo)(struct addrinfo *res);
|
struct addrinfo **res);
|
||||||
|
void(HTS_RESOLVER_CALL *freeaddrinfo)(struct addrinfo *res);
|
||||||
} hts_resolver_backend;
|
} hts_resolver_backend;
|
||||||
|
|
||||||
/** Install a resolver backend for the process; NULL restores the libc default.
|
/** Install a resolver backend for the process; NULL restores the libc default.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user