mirror of
https://github.com/xroche/httrack.git
synced 2026-07-16 22:00:45 +03:00
Compare commits
37 Commits
ci-paralle
...
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 |
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
|
||||||
101
.github/workflows/ci.yml
vendored
101
.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,7 +328,8 @@ 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()
|
||||||
@@ -297,7 +354,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 (fuzzers, static)
|
- name: Configure (fuzzers, static)
|
||||||
run: |
|
run: |
|
||||||
@@ -347,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()
|
||||||
@@ -375,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
|
||||||
@@ -419,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: |
|
||||||
@@ -495,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.
|
||||||
|
|||||||
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
|
||||||
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
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*
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
18
configure.ac
18
configure.ac
@@ -64,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 \
|
||||||
@@ -119,8 +109,8 @@ case "$CFLAGS" in
|
|||||||
esac
|
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])
|
||||||
@@ -183,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],
|
||||||
|
|||||||
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
|
||||||
|
|||||||
@@ -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>
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|||||||
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 "07 July 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
|
||||||
@@ -135,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
|
||||||
@@ -224,7 +224,7 @@ 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
|
||||||
@@ -248,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>)
|
||||||
@@ -514,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
|
||||||
|
|||||||
193
src/htsback.c
193
src/htsback.c
@@ -44,6 +44,8 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htsback.h"
|
#include "htsback.h"
|
||||||
|
|
||||||
#include "htsftp.h"
|
#include "htsftp.h"
|
||||||
|
#include "htscodec.h"
|
||||||
|
#include "htsproxy.h"
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
#else
|
#else
|
||||||
@@ -556,6 +558,14 @@ static int create_back_tmpfile(httrackp *opt, lien_back *const back,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Move src onto dst; RENAME does not clobber an existing target on Windows. */
|
||||||
|
static hts_boolean replace_file(const char *src, const char *dst) {
|
||||||
|
if (RENAME(src, dst) == 0)
|
||||||
|
return HTS_TRUE;
|
||||||
|
(void) UNLINK(dst);
|
||||||
|
return RENAME(src, dst) == 0 ? HTS_TRUE : HTS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Commit or restore a re-fetch backup (#77 follow-up): a re-fetch over an
|
/* Commit or restore a re-fetch backup (#77 follow-up): a re-fetch over an
|
||||||
existing file moved the good copy to back->tmpfile before truncating url_sav.
|
existing file moved the good copy to back->tmpfile before truncating url_sav.
|
||||||
commit keeps the new file and drops the backup; else restore it so an aborted
|
commit keeps the new file and drops the backup; else restore it so an aborted
|
||||||
@@ -571,10 +581,9 @@ static void back_finalize_backup(httrackp *opt, lien_back *const back,
|
|||||||
fclose(back->r.out);
|
fclose(back->r.out);
|
||||||
back->r.out = NULL;
|
back->r.out = NULL;
|
||||||
}
|
}
|
||||||
(void) UNLINK(back->url_sav); /* drop the failed partial */
|
/* On failure keep the backup: an orphaned temp beats losing the good copy.
|
||||||
/* On rename failure keep the backup: it still holds the good copy, so
|
*/
|
||||||
losing it would be worse than an orphaned temp. */
|
if (!replace_file(back->tmpfile, back->url_sav))
|
||||||
if (RENAME(back->tmpfile, back->url_sav) != 0)
|
|
||||||
hts_log_print(opt, LOG_WARNING | LOG_ERRNO,
|
hts_log_print(opt, LOG_WARNING | LOG_ERRNO,
|
||||||
"could not restore %s; previous copy kept as %s",
|
"could not restore %s; previous copy kept as %s",
|
||||||
back->url_sav, back->tmpfile);
|
back->url_sav, back->tmpfile);
|
||||||
@@ -627,8 +636,7 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
if (!back[p].testmode) { // not test mode
|
if (!back[p].testmode) { // not test mode
|
||||||
const char *state = "unknown";
|
const char *state = "unknown";
|
||||||
|
|
||||||
/* décompression */
|
/* Undo the content coding */
|
||||||
#if HTS_USEZLIB
|
|
||||||
if (back[p].r.compressed) {
|
if (back[p].r.compressed) {
|
||||||
if (back[p].r.size > 0) {
|
if (back[p].r.size > 0) {
|
||||||
// stats
|
// stats
|
||||||
@@ -674,28 +682,67 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
// décompression
|
// décompression
|
||||||
if (back[p].tmpfile != NULL) {
|
if (back[p].tmpfile != NULL) {
|
||||||
if (back[p].url_sav[0]) {
|
if (back[p].url_sav[0]) {
|
||||||
|
const hts_codec codec =
|
||||||
|
hts_codec_parse(back[p].r.contentencoding);
|
||||||
|
/* Never decode over url_sav: a failed decode would destroy the
|
||||||
|
copy an --update re-fetch is supposed to refresh (#557). */
|
||||||
|
char BIGSTK unpacked[HTS_URLMAXSIZE * 2 + 4]; // room for ".u"
|
||||||
LLint size;
|
LLint size;
|
||||||
|
|
||||||
file_notify(opt, back[p].url_adr, back[p].url_fil,
|
snprintf(unpacked, sizeof(unpacked), "%s.u", back[p].url_sav);
|
||||||
back[p].url_sav, 1, 1, back[p].r.notmodified);
|
if ((size = hts_codec_unpack(codec, back[p].tmpfile,
|
||||||
filecreateempty(&opt->state.strc, back[p].url_sav); // filenote & co
|
unpacked)) >= 0) {
|
||||||
if ((size = hts_zunpack(back[p].tmpfile, back[p].url_sav)) >= 0) {
|
|
||||||
back[p].r.size = back[p].r.totalsize = size;
|
back[p].r.size = back[p].r.totalsize = size;
|
||||||
// fichier -> mémoire
|
|
||||||
if (!back[p].r.is_write) {
|
if (!back[p].r.is_write) {
|
||||||
|
// fichier -> mémoire ; le fichier est écrit plus tard
|
||||||
deleteaddr(&back[p].r);
|
deleteaddr(&back[p].r);
|
||||||
back[p].r.adr = readfile_utf8(back[p].url_sav);
|
back[p].r.adr = readfile_utf8(unpacked);
|
||||||
if (!back[p].r.adr) {
|
if (!back[p].r.adr) {
|
||||||
back[p].r.statuscode = STATUSCODE_INVALID;
|
back[p].r.statuscode = STATUSCODE_INVALID;
|
||||||
strcpybuff(back[p].r.msg,
|
strcpybuff(back[p].r.msg,
|
||||||
"Read error when decompressing");
|
"Read error when decompressing");
|
||||||
}
|
}
|
||||||
UNLINK(back[p].url_sav);
|
UNLINK(unpacked);
|
||||||
|
} else if (replace_file(unpacked, back[p].url_sav)) {
|
||||||
|
/* The temp bypassed filecreate(), which is what chmods. */
|
||||||
|
#ifndef _WIN32
|
||||||
|
chmod(back[p].url_sav, HTS_ACCESS_FILE);
|
||||||
|
#endif
|
||||||
|
file_notify(opt, back[p].url_adr, back[p].url_fil,
|
||||||
|
back[p].url_sav, 1, 1, back[p].r.notmodified);
|
||||||
|
filenote(&opt->state.strc, back[p].url_sav, NULL);
|
||||||
|
} else {
|
||||||
|
back[p].r.statuscode = STATUSCODE_INVALID;
|
||||||
|
strcpybuff(back[p].r.msg,
|
||||||
|
"Write error when decompressing (can not rename "
|
||||||
|
"the temporary file)");
|
||||||
|
/* Keep the decoded body: the failed replace may have
|
||||||
|
removed the previous copy, leaving this as the only one.
|
||||||
|
*/
|
||||||
|
hts_log_print(
|
||||||
|
opt, LOG_WARNING | LOG_ERRNO,
|
||||||
|
"could not replace %s; decoded copy kept as %s",
|
||||||
|
back[p].url_sav, unpacked);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
back[p].r.statuscode = STATUSCODE_INVALID;
|
back[p].r.statuscode = STATUSCODE_INVALID;
|
||||||
strcpybuff(back[p].r.msg, "Error when decompressing");
|
snprintf(back[p].r.msg, sizeof(back[p].r.msg),
|
||||||
|
codec == HTS_CODEC_UNSUPPORTED
|
||||||
|
? "Unsupported Content-Encoding (%s)"
|
||||||
|
: "Error when decompressing (%s)",
|
||||||
|
back[p].r.contentencoding);
|
||||||
|
/* Drop the undecoded body so the writer can't commit the
|
||||||
|
coded bytes as the page; url_sav is left untouched. */
|
||||||
|
if (!back[p].r.is_write)
|
||||||
|
deleteaddr(&back[p].r);
|
||||||
|
UNLINK(unpacked);
|
||||||
}
|
}
|
||||||
|
/* A failed decode keeps the previously-mirrored copy: note it,
|
||||||
|
or the update purge (in old.lst, absent from new.lst) would
|
||||||
|
delete what we just took care not to overwrite. */
|
||||||
|
if (back[p].r.statuscode == STATUSCODE_INVALID &&
|
||||||
|
fexist_utf8(back[p].url_sav))
|
||||||
|
filenote(&opt->state.strc, back[p].url_sav, NULL);
|
||||||
}
|
}
|
||||||
/* ensure that no remaining temporary file exists */
|
/* ensure that no remaining temporary file exists */
|
||||||
unlink(back[p].tmpfile);
|
unlink(back[p].tmpfile);
|
||||||
@@ -708,7 +755,6 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
// unflag
|
// unflag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
/* Body fully received: keep the freshly written url_sav, drop the
|
/* Body fully received: keep the freshly written url_sav, drop the
|
||||||
backup of the previous copy. */
|
backup of the previous copy. */
|
||||||
back_finalize_backup(opt, &back[p], HTS_TRUE);
|
back_finalize_backup(opt, &back[p], HTS_TRUE);
|
||||||
@@ -807,7 +853,7 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
else
|
else
|
||||||
strcatbuff(flags, "-");
|
strcatbuff(flags, "-");
|
||||||
if (back[p].r.compressed)
|
if (back[p].r.compressed)
|
||||||
strcatbuff(flags, "Z"); // gzip
|
strcatbuff(flags, "Z"); // content coding
|
||||||
else
|
else
|
||||||
strcatbuff(flags, "-");
|
strcatbuff(flags, "-");
|
||||||
/* Err I had to split these.. */
|
/* Err I had to split these.. */
|
||||||
@@ -816,9 +862,7 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
fprintf(cache->txt, LLintP, (LLint) back[p].r.totalsize);
|
fprintf(cache->txt, LLintP, (LLint) back[p].r.totalsize);
|
||||||
fprintf(cache->txt, "\t%s\t", flags);
|
fprintf(cache->txt, "\t%s\t", flags);
|
||||||
}
|
}
|
||||||
#if HTS_USEZLIB
|
|
||||||
back[p].r.compressed = 0;
|
back[p].r.compressed = 0;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (back[p].r.statuscode == HTTP_OK) {
|
if (back[p].r.statuscode == HTTP_OK) {
|
||||||
if (back[p].r.size >= 0) {
|
if (back[p].r.size >= 0) {
|
||||||
@@ -2068,6 +2112,17 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
"error: forbidden test with ftp link for back_add");
|
"error: forbidden test with ftp link for back_add");
|
||||||
return -1; // erreur pas de test permis
|
return -1; // erreur pas de test permis
|
||||||
}
|
}
|
||||||
|
// the ftp client dials the origin itself: over socks that would bypass
|
||||||
|
// the proxy, so fail the link rather than leak the connection (#563)
|
||||||
|
if (back[p].r.req.proxy.active &&
|
||||||
|
hts_proxy_is_socks(back[p].r.req.proxy.name)) {
|
||||||
|
back[p].r.statuscode = STATUSCODE_NON_FATAL;
|
||||||
|
strcpybuff(back[p].r.msg,
|
||||||
|
"ftp:// is not supported over a SOCKS proxy");
|
||||||
|
back[p].status = STATUS_READY;
|
||||||
|
back_set_finished(sback, p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gérée en thread
|
if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gérée en thread
|
||||||
FTPDownloadStruct *str =
|
FTPDownloadStruct *str =
|
||||||
(FTPDownloadStruct *) malloc(sizeof(FTPDownloadStruct));
|
(FTPDownloadStruct *) malloc(sizeof(FTPDownloadStruct));
|
||||||
@@ -2670,13 +2725,40 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
}
|
}
|
||||||
busy_state = 1;
|
busy_state = 1;
|
||||||
|
|
||||||
|
// socks5: tunnel to the origin before anything is written, for http
|
||||||
|
// as well as https. Skip on a reused keep-alive socket (already
|
||||||
|
// tunneled) and on the post-TLS re-entry (ssl_con set) (#563).
|
||||||
|
if (back[i].r.req.proxy.active &&
|
||||||
|
hts_proxy_is_socks(back[i].r.req.proxy.name) &&
|
||||||
|
!back[i].r.keep_alive
|
||||||
|
#if HTS_USEOPENSSL
|
||||||
|
&& back[i].r.ssl_con == NULL
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
const int timeout = back[i].timeout > 0 ? back[i].timeout : 30;
|
||||||
|
|
||||||
|
if (!socks5_handshake(opt, &back[i].r, back[i].url_adr, timeout)) {
|
||||||
|
if (!strnotempty(back[i].r.msg))
|
||||||
|
strcpybuff(back[i].r.msg, "SOCKS5 handshake failed");
|
||||||
|
deletehttp(&back[i].r);
|
||||||
|
back[i].r.soc = INVALID_SOCKET;
|
||||||
|
back[i].r.statuscode = STATUSCODE_NON_FATAL;
|
||||||
|
back[i].status = STATUS_READY;
|
||||||
|
back_set_finished(sback, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if HTS_USEOPENSSL
|
#if HTS_USEOPENSSL
|
||||||
/* SSL mode */
|
/* SSL mode */
|
||||||
if (back[i].r.ssl) {
|
if (back[i].r.ssl) {
|
||||||
int tunnel_ok = 1;
|
int tunnel_ok = 1;
|
||||||
|
|
||||||
// https via proxy: CONNECT-tunnel before TLS (#85)
|
// https via an http proxy: CONNECT-tunnel before TLS (#85); socks
|
||||||
if (back[i].r.req.proxy.active && back[i].r.ssl_con == NULL) {
|
// already carries the origin connection
|
||||||
|
if (back[i].r.req.proxy.active &&
|
||||||
|
!hts_proxy_is_socks(back[i].r.req.proxy.name) &&
|
||||||
|
back[i].r.ssl_con == NULL) {
|
||||||
const int timeout = back[i].timeout > 0 ? back[i].timeout : 30;
|
const int timeout = back[i].timeout > 0 ? back[i].timeout : 30;
|
||||||
|
|
||||||
tunnel_ok =
|
tunnel_ok =
|
||||||
@@ -2941,11 +3023,13 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
int last_errno = 0;
|
int last_errno = 0;
|
||||||
|
|
||||||
back[i].r.is_write = 1; // écrire
|
back[i].r.is_write = 1; // écrire
|
||||||
|
/* a .gz/.br/.zst saved under its own coding stays
|
||||||
|
packed on disk */
|
||||||
if (back[i].r.compressed &&
|
if (back[i].r.compressed &&
|
||||||
/* .gz are *NOT* depacked!! */
|
!hts_codec_is_archive_ext(
|
||||||
strfield(get_ext(catbuff, sizeof(catbuff), back[i].url_sav), "gz") == 0
|
hts_codec_parse(back[i].r.contentencoding),
|
||||||
&& strfield(get_ext(catbuff, sizeof(catbuff), back[i].url_sav), "tgz") == 0
|
get_ext(catbuff, sizeof(catbuff),
|
||||||
) {
|
back[i].url_sav))) {
|
||||||
if (create_back_tmpfile(opt, &back[i], "z") ==
|
if (create_back_tmpfile(opt, &back[i], "z") ==
|
||||||
0) {
|
0) {
|
||||||
assertf(back[i].tmpfile != NULL);
|
assertf(back[i].tmpfile != NULL);
|
||||||
@@ -3512,6 +3596,11 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The server really sent 304 here; the *-hacks below force
|
||||||
|
// NOT_MODIFIED only after confirming the file is complete.
|
||||||
|
const hts_boolean server_sent_304 =
|
||||||
|
(back[i].r.statuscode == HTTP_NOT_MODIFIED);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Solve "false" 416 problems
|
Solve "false" 416 problems
|
||||||
*/
|
*/
|
||||||
@@ -3606,7 +3695,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
if (back[i].r.statuscode == HTTP_OK && !back[i].testmode) { // 'OK'
|
if (back[i].r.statuscode == HTTP_OK && !back[i].testmode) { // 'OK'
|
||||||
if (!is_hypertext_mime(opt, back[i].r.contenttype, back[i].url_fil)) { // not HTML
|
if (!is_hypertext_mime(opt, back[i].r.contenttype, back[i].url_fil)) { // not HTML
|
||||||
if (strnotempty(back[i].url_sav)) { // target found
|
if (strnotempty(back[i].url_sav)) { // target found
|
||||||
int size = fsize_utf8(back[i].url_sav); // target size
|
off_t size = fsize_utf8(back[i].url_sav);
|
||||||
|
|
||||||
if (size >= 0) {
|
if (size >= 0) {
|
||||||
if (back[i].r.totalsize == size) { // same size!
|
if (back[i].r.totalsize == size) { // same size!
|
||||||
@@ -3701,6 +3790,21 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Out-of-protocol 304 to a Range resume: the file is still
|
||||||
|
// partial, so drop it and refetch instead of trusting it.
|
||||||
|
if (server_sent_304 && back[i].range_req_size > 0) {
|
||||||
|
url_savename_refname_remove(opt, back[i].url_adr,
|
||||||
|
back[i].url_fil);
|
||||||
|
UNLINK(back[i].url_sav);
|
||||||
|
deletehttp(&back[i].r);
|
||||||
|
back[i].r.soc = INVALID_SOCKET;
|
||||||
|
back[i].r.statuscode = STATUSCODE_NON_FATAL;
|
||||||
|
strcpybuff(back[i].r.msg,
|
||||||
|
"Bogus 304 on resume, restarting");
|
||||||
|
back[i].status = STATUS_READY;
|
||||||
|
back_set_finished(sback, i);
|
||||||
|
}
|
||||||
|
|
||||||
/* sinon, continuer */
|
/* sinon, continuer */
|
||||||
/* if (back[i].r.soc!=INVALID_SOCKET) { // ok récupérer body? */
|
/* if (back[i].r.soc!=INVALID_SOCKET) { // ok récupérer body? */
|
||||||
// head: terminé
|
// head: terminé
|
||||||
@@ -3819,7 +3923,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
const hts_boolean range_ok =
|
const hts_boolean range_ok =
|
||||||
back[i].r.crange > 0 && resume >= 0 &&
|
back[i].r.crange > 0 && resume >= 0 &&
|
||||||
resume <= (LLint) sz &&
|
resume <= (LLint) sz &&
|
||||||
back[i].r.crange_end + 1 == back[i].r.crange &&
|
back[i].r.crange_end == back[i].r.crange - 1 &&
|
||||||
(back[i].r.totalsize < 0 ||
|
(back[i].r.totalsize < 0 ||
|
||||||
back[i].r.totalsize ==
|
back[i].r.totalsize ==
|
||||||
back[i].r.crange_end - resume + 1);
|
back[i].r.crange_end - resume + 1);
|
||||||
@@ -3848,8 +3952,9 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
// drop bytes past the resume point; a silent
|
// drop bytes past the resume point; a silent
|
||||||
// failure could leave a stale tail, so on error
|
// failure could leave a stale tail, so on error
|
||||||
// drop the partial and refetch the whole file
|
// drop the partial and refetch the whole file
|
||||||
if (HTS_FTRUNCATE(back[i].r.out,
|
/* not (off_t): 32-bit on MSVC, wrapping a resume
|
||||||
(off_t) resume) != 0) {
|
past 2GB */
|
||||||
|
if (HTS_FTRUNCATE(back[i].r.out, resume) != 0) {
|
||||||
fclose(back[i].r.out);
|
fclose(back[i].r.out);
|
||||||
back[i].r.out = NULL;
|
back[i].r.out = NULL;
|
||||||
url_savename_refname_remove(
|
url_savename_refname_remove(
|
||||||
@@ -3861,7 +3966,9 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
"Can not truncate partial file, "
|
"Can not truncate partial file, "
|
||||||
"restarting");
|
"restarting");
|
||||||
} else {
|
} else {
|
||||||
fseeko(back[i].r.out, (off_t) resume, SEEK_SET);
|
/* not (off_t): 32-bit on MSVC, truncating a
|
||||||
|
resume past 2GB */
|
||||||
|
fseeko(back[i].r.out, resume, SEEK_SET);
|
||||||
/* create a temporary reference file in case of
|
/* create a temporary reference file in case of
|
||||||
* broken mirror */
|
* broken mirror */
|
||||||
if (back_serialize_ref(opt, &back[i]) != 0) {
|
if (back_serialize_ref(opt, &back[i]) != 0) {
|
||||||
@@ -3888,11 +3995,20 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
if (fp) {
|
if (fp) {
|
||||||
LLint alloc_mem = resume + 1;
|
LLint alloc_mem = resume + 1;
|
||||||
|
|
||||||
if (back[i].r.totalsize >= 0)
|
// Bound the in-memory buffer to a 32-bit size (real
|
||||||
|
// in-RAM resources are far smaller); a hostile
|
||||||
|
// Content-Length that would overflow the add or the
|
||||||
|
// (size_t) cast is dropped and refetched instead.
|
||||||
|
if (back[i].r.totalsize > INT32_MAX - alloc_mem) {
|
||||||
|
url_savename_refname_remove(opt, back[i].url_adr,
|
||||||
|
back[i].url_fil);
|
||||||
|
UNLINK(back[i].url_sav);
|
||||||
|
alloc_mem = -1;
|
||||||
|
} else if (back[i].r.totalsize >= 0)
|
||||||
alloc_mem += back[i].r.totalsize; // AJOUTER RESTANT!
|
alloc_mem += back[i].r.totalsize; // AJOUTER RESTANT!
|
||||||
if (deleteaddr(&back[i].r)
|
if (alloc_mem >= 0 && deleteaddr(&back[i].r) &&
|
||||||
&& (back[i].r.adr =
|
(back[i].r.adr =
|
||||||
(char *) malloct((size_t) alloc_mem))) {
|
(char *) malloct((size_t) alloc_mem))) {
|
||||||
back[i].r.size = resume;
|
back[i].r.size = resume;
|
||||||
if (back[i].r.totalsize >= 0)
|
if (back[i].r.totalsize >= 0)
|
||||||
back[i].r.totalsize += resume; // -> full size
|
back[i].r.totalsize += resume; // -> full size
|
||||||
@@ -4178,10 +4294,13 @@ static int back_maxtime_grace(const int maxtime) {
|
|||||||
No floor (unlike the time grace): a size overrun should abort promptly. */
|
No floor (unlike the time grace): a size overrun should abort promptly. */
|
||||||
static LLint back_maxsize_grace(const LLint maxsite) { return maxsite / 10; }
|
static LLint back_maxsize_grace(const LLint maxsite) { return maxsite / 10; }
|
||||||
|
|
||||||
/* Which cap has overrun its grace and must hard-stop the mirror (#77, #481). */
|
/* Which cap has overrun its grace and must hard-stop the mirror (#77, #481).
|
||||||
|
-M measures received volume (HTS_TOTAL_RECV), not saved 200-only stat_bytes
|
||||||
|
which undercounts redirect/error-heavy crawls (#520). */
|
||||||
static hts_mirror_limit back_mirror_limit(httrackp *opt) {
|
static hts_mirror_limit back_mirror_limit(httrackp *opt) {
|
||||||
if (opt->maxsite > 0 && HTS_STAT.stat_bytes >= opt->maxsite &&
|
if (opt->maxsite > 0 && HTS_STAT.HTS_TOTAL_RECV >= opt->maxsite &&
|
||||||
HTS_STAT.stat_bytes - opt->maxsite >= back_maxsize_grace(opt->maxsite))
|
HTS_STAT.HTS_TOTAL_RECV - opt->maxsite >=
|
||||||
|
back_maxsize_grace(opt->maxsite))
|
||||||
return HTS_MIRROR_LIMIT_SIZE;
|
return HTS_MIRROR_LIMIT_SIZE;
|
||||||
if (opt->maxtime > 0) {
|
if (opt->maxtime > 0) {
|
||||||
const TStamp elapsed = time_local() - HTS_STAT.stat_timestart;
|
const TStamp elapsed = time_local() - HTS_STAT.stat_timestart;
|
||||||
@@ -4195,7 +4314,7 @@ static hts_mirror_limit back_mirror_limit(httrackp *opt) {
|
|||||||
|
|
||||||
int back_checkmirror(httrackp *opt) {
|
int back_checkmirror(httrackp *opt) {
|
||||||
/* request a smooth stop the first time each cap is reached */
|
/* request a smooth stop the first time each cap is reached */
|
||||||
if (opt->maxsite > 0 && HTS_STAT.stat_bytes >= opt->maxsite &&
|
if (opt->maxsite > 0 && HTS_STAT.HTS_TOTAL_RECV >= opt->maxsite &&
|
||||||
!opt->state.stop) {
|
!opt->state.stop) {
|
||||||
hts_log_print(opt, LOG_ERROR,
|
hts_log_print(opt, LOG_ERROR,
|
||||||
"More than " LLintP
|
"More than " LLintP
|
||||||
|
|||||||
@@ -232,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);
|
||||||
@@ -1253,8 +1252,9 @@ static void corrupt_build_disk(httrackp *opt) {
|
|||||||
memset(corrupt_body_a, 'a', sizeof(corrupt_body_a) - 1);
|
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/new.zip"));
|
||||||
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
||||||
fconcat(save, sizeof(save), StringBuff(opt->path_html_utf8),
|
/* X-Save stored verbatim: see disk_fallback_selftest */
|
||||||
CORRUPT_ADR "/victim.bin");
|
concat(save, sizeof(save), StringBuff(opt->path_html_utf8),
|
||||||
|
CORRUPT_ADR "/victim.bin");
|
||||||
selftest_open_for_write(&cache, opt);
|
selftest_open_for_write(&cache, opt);
|
||||||
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
||||||
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
||||||
|
|||||||
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
|
||||||
@@ -3875,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;
|
||||||
|
|||||||
@@ -1452,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 {
|
||||||
@@ -2253,21 +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);
|
||||||
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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -121,12 +121,18 @@ int fa_strjoker_dual(int type, char **filters, int nfil, const char *nom1,
|
|||||||
return use1 ? jok1 : jok2;
|
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
|
/* Failure memo for the recursive matcher: one bit per (chaine, joker) offset
|
||||||
pair keeps star-heavy patterns polynomial instead of exponential (#501). */
|
pair keeps star-heavy patterns polynomial instead of exponential (#501). */
|
||||||
typedef struct strjoker_memo {
|
typedef struct strjoker_memo {
|
||||||
const char *chaine0, *joker0; /* offsets are relative to these bases */
|
const char *chaine0, *joker0; /* offsets are relative to these bases */
|
||||||
size_t stride; /* strlen(joker0) + 1 */
|
size_t stride; /* strlen(joker0) + 1 */
|
||||||
unsigned char *failed; /* failed-pair bitmap; NULL: no memo */
|
unsigned char *failed; /* failed-pair bitmap; NULL: no memo */
|
||||||
|
size_t *nsteps; /* shared work counter; NULL: unbounded (oracle) */
|
||||||
} strjoker_memo;
|
} strjoker_memo;
|
||||||
|
|
||||||
static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine,
|
static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine,
|
||||||
@@ -141,6 +147,8 @@ static const char *strjoker_rec(const strjoker_memo *memo, const char *chaine,
|
|||||||
size_t bit = 0;
|
size_t bit = 0;
|
||||||
const char *adr;
|
const char *adr;
|
||||||
|
|
||||||
|
if (memo->nsteps != NULL && ++*memo->nsteps > STRJOKER_MAXSTEPS)
|
||||||
|
return NULL; /* work budget spent: fail the match safely */
|
||||||
if (memo->failed) {
|
if (memo->failed) {
|
||||||
bit = (size_t) (chaine - memo->chaine0) * memo->stride +
|
bit = (size_t) (chaine - memo->chaine0) * memo->stride +
|
||||||
(size_t) (joker - memo->joker0);
|
(size_t) (joker - memo->joker0);
|
||||||
@@ -153,22 +161,24 @@ static const char *strjoker_rec(const strjoker_memo *memo, const char *chaine,
|
|||||||
return adr;
|
return adr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wildcard comparator: match chaine against joker (pattern), case-insensitive
|
/* Match chaine against joker with a shared work budget *nsteps (a strjokerfind
|
||||||
// returns the address of the first matched letter past any leading joker
|
sweep passes one counter, bounding the whole scan). */
|
||||||
// (ie. *[..]toto.. returns the address of toto within chaine), NULL on mismatch
|
static const char *strjoker_bounded(const char *chaine, const char *joker,
|
||||||
HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
LLint *size, int *size_flag,
|
||||||
LLint *size, int *size_flag) {
|
size_t *nsteps) {
|
||||||
strjoker_memo memo = {chaine, joker, 0, NULL};
|
strjoker_memo memo = {chaine, joker, 0, NULL, nsteps};
|
||||||
unsigned char stackbits[2048];
|
unsigned char stackbits[2048];
|
||||||
hts_boolean onheap = HTS_FALSE;
|
hts_boolean onheap = HTS_FALSE;
|
||||||
const char *adr;
|
const char *adr;
|
||||||
|
|
||||||
if (chaine != NULL && joker != NULL) {
|
if (chaine != NULL && joker != NULL) {
|
||||||
const size_t n1 = strlen(chaine) + 1;
|
const size_t l1 = strlen(chaine), l2 = strlen(joker);
|
||||||
|
|
||||||
memo.stride = strlen(joker) + 1;
|
if (l1 > STRJOKER_MAXLEN || l2 > STRJOKER_MAXLEN)
|
||||||
if (n1 <= (SIZE_MAX - 7) / memo.stride) { // overflow-safe bitmap size
|
return NULL; /* beyond any real filter/URL: bound depth+work */
|
||||||
const size_t bytes = (n1 * memo.stride + 7) / 8;
|
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)) {
|
if (bytes <= sizeof(stackbits)) {
|
||||||
memset(stackbits, 0, bytes);
|
memset(stackbits, 0, bytes);
|
||||||
@@ -185,6 +195,16 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
|||||||
return adr;
|
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. */
|
/* Test-only oracle: the same matcher without the failure memo. */
|
||||||
const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
|
const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
|
||||||
int *size_flag) {
|
int *size_flag) {
|
||||||
@@ -193,6 +213,20 @@ const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
|
|||||||
return strjoker_rec(&memo, chaine, joker, size, size_flag);
|
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,
|
static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine,
|
||||||
const char *joker, LLint *size,
|
const char *joker, LLint *size,
|
||||||
int *size_flag) {
|
int *size_flag) {
|
||||||
@@ -431,12 +465,18 @@ static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine,
|
|||||||
// 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;
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
|
|||||||
oracle for the memoized matcher. */
|
oracle for the memoized matcher. */
|
||||||
const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
|
const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
|
||||||
int *size_flag);
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -140,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
|
||||||
|
|||||||
@@ -477,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("");
|
||||||
@@ -546,8 +546,8 @@ void help(const char *app, int more) {
|
|||||||
infomsg(" %Y explain which filter rule accepts or rejects a URL, then exit");
|
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
|
||||||
@@ -571,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
|
||||||
|
|||||||
517
src/htsjava.c
517
src/htsjava.c
@@ -1,517 +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) {
|
|
||||||
sprintf(str->err_msg, "Unable to open file %s", file);
|
|
||||||
return 0; // une erreur..
|
|
||||||
}
|
|
||||||
#if JAVADEBUG
|
|
||||||
printf("fread\n");
|
|
||||||
#endif
|
|
||||||
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 Class;
|
|
||||||
unsigned int SClass;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
trans.file_position = ftell(fp);
|
|
||||||
length = readshort(fp);
|
|
||||||
if (length < HTS_URLMAXSIZE) {
|
|
||||||
while(length > 0) {
|
|
||||||
*p++ = fgetc(fp);
|
|
||||||
|
|
||||||
length--;
|
|
||||||
}
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
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:
|
|
||||||
// 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;
|
|
||||||
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,70 +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 .h */
|
|
||||||
/* Author: Yann Philippot */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
|
|
||||||
#ifndef HTSJAVA_DEFH
|
|
||||||
#define HTSJAVA_DEFH
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifndef HTS_DEF_FWSTRUCT_JAVA_HEADER
|
|
||||||
#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
|
|
||||||
#define HTS_DEF_FWSTRUCT_RESP_STRUCT
|
|
||||||
typedef struct RESP_STRUCT RESP_STRUCT;
|
|
||||||
#endif
|
|
||||||
struct RESP_STRUCT {
|
|
||||||
int file_position;
|
|
||||||
//
|
|
||||||
unsigned int index1;
|
|
||||||
unsigned int type;
|
|
||||||
char name[1024];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Library internal definictions */
|
|
||||||
#ifdef HTS_INTERNAL_BYTECODE
|
|
||||||
|
|
||||||
EXTERNAL_FUNCTION int hts_plug_java(httrackp * opt, const char *argv);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -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>
|
|
||||||
310
src/htslib.c
310
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>
|
||||||
@@ -648,165 +649,6 @@ 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?
|
||||||
@@ -1059,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);
|
||||||
@@ -1105,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);
|
||||||
@@ -1142,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,
|
||||||
@@ -1187,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);
|
||||||
@@ -1279,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 */
|
||||||
@@ -1586,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 {
|
||||||
@@ -1594,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;
|
||||||
@@ -1662,22 +1521,10 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
strcpybuff(retour->contentencoding, tempo);
|
strcpybuff(retour->contentencoding, tempo);
|
||||||
else
|
else
|
||||||
retour->contentencoding[0] = '\0';
|
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) {
|
||||||
@@ -1702,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;
|
||||||
@@ -1998,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);
|
||||||
@@ -2560,6 +2419,11 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
|
|||||||
// 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, "/");
|
||||||
@@ -3849,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;
|
||||||
@@ -3857,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;
|
||||||
@@ -4342,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
|
||||||
@@ -4995,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;
|
||||||
|
|
||||||
@@ -5005,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;
|
||||||
@@ -5903,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 */
|
||||||
|
|||||||
37
src/htslib.h
37
src/htslib.h
@@ -184,10 +184,10 @@ 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);
|
||||||
|
|
||||||
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);
|
||||||
@@ -207,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);
|
||||||
@@ -283,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)
|
||||||
@@ -493,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?
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -151,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");
|
||||||
@@ -205,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;
|
||||||
}
|
}
|
||||||
|
|||||||
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.
|
||||||
|
|||||||
@@ -328,8 +328,8 @@ typedef enum hts_wizard {
|
|||||||
|
|
||||||
typedef enum hts_robots {
|
typedef enum hts_robots {
|
||||||
HTS_ROBOTS_NEVER = 0, /**< ignore robots rules */
|
HTS_ROBOTS_NEVER = 0, /**< ignore robots rules */
|
||||||
HTS_ROBOTS_SOMETIMES = 1, /**< partial obedience (default) */
|
HTS_ROBOTS_SOMETIMES = 1, /**< partial obedience, set by -s */
|
||||||
HTS_ROBOTS_ALWAYS = 2, /**< obey robots rules */
|
HTS_ROBOTS_ALWAYS = 2, /**< obey robots rules (default) */
|
||||||
HTS_ROBOTS_ALWAYS_STRICT = 3 /**< obey even strict rules */
|
HTS_ROBOTS_ALWAYS_STRICT = 3 /**< obey even strict rules */
|
||||||
} hts_robots;
|
} hts_robots;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4311,6 +4311,8 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
|
|||||||
*forbidden_url == 0 && IS_DELAYED_EXT(afs->save) && !opt->state.stop) {
|
*forbidden_url == 0 && IS_DELAYED_EXT(afs->save) && !opt->state.stop) {
|
||||||
int loops;
|
int loops;
|
||||||
int continue_loop;
|
int continue_loop;
|
||||||
|
char BIGSTK
|
||||||
|
cookie_before[16384]; /* #15: this URL's Cookie header, pre-request */
|
||||||
|
|
||||||
hts_log_print(opt, LOG_DEBUG, "Waiting for type to be known: %s%s", afs->af.adr,
|
hts_log_print(opt, LOG_DEBUG, "Waiting for type to be known: %s%s", afs->af.adr,
|
||||||
afs->af.fil);
|
afs->af.fil);
|
||||||
@@ -4319,6 +4321,12 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
|
|||||||
for(loops = 0, continue_loop = 1;
|
for(loops = 0, continue_loop = 1;
|
||||||
IS_DELAYED_EXT(afs->save) && continue_loop && loops < 7; loops++) {
|
IS_DELAYED_EXT(afs->save) && continue_loop && loops < 7; loops++) {
|
||||||
continue_loop = 0;
|
continue_loop = 0;
|
||||||
|
/* #15: snapshot the Cookie header THIS url would send, so only its own
|
||||||
|
self-redirect Set-Cookie trips the retry, not a concurrent slot's. */
|
||||||
|
cookie_before[0] = '\0';
|
||||||
|
if (opt->accept_cookie && opt->cookie != NULL)
|
||||||
|
http_cookie_header(opt->cookie, jump_identification_const(afs->af.adr),
|
||||||
|
afs->af.fil, cookie_before, sizeof(cookie_before));
|
||||||
|
|
||||||
/* Wait for an available slot */
|
/* Wait for an available slot */
|
||||||
if (!hts_wait_available_socket(sback, opt, cache, ptr))
|
if (!hts_wait_available_socket(sback, opt, cache, ptr))
|
||||||
@@ -4516,6 +4524,17 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
|
|||||||
/* Moved! */
|
/* Moved! */
|
||||||
else if (HTTP_IS_REDIRECT(back[b].r.statuscode)) {
|
else if (HTTP_IS_REDIRECT(back[b].r.statuscode)) {
|
||||||
char BIGSTK mov_url[HTS_URLMAXSIZE * 2];
|
char BIGSTK mov_url[HTS_URLMAXSIZE * 2];
|
||||||
|
char BIGSTK cookie_after[16384];
|
||||||
|
hts_boolean cookies_changed;
|
||||||
|
|
||||||
|
/* #15: cookie-wall signal: this URL's own Cookie header changed
|
||||||
|
across its self-redirect (a Set-Cookie it just set). */
|
||||||
|
cookie_after[0] = '\0';
|
||||||
|
if (opt->accept_cookie && opt->cookie != NULL)
|
||||||
|
http_cookie_header(
|
||||||
|
opt->cookie, jump_identification_const(afs->af.adr),
|
||||||
|
afs->af.fil, cookie_after, sizeof(cookie_after));
|
||||||
|
cookies_changed = strcmp(cookie_before, cookie_after) != 0;
|
||||||
|
|
||||||
mov_url[0] = '\0';
|
mov_url[0] = '\0';
|
||||||
strcpybuff(mov_url, back[b].r.location); // copier URL
|
strcpybuff(mov_url, back[b].r.location); // copier URL
|
||||||
@@ -4585,11 +4604,24 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
|
|||||||
url_savename(afs, former, heap(ptr)->adr, heap(ptr)->fil,
|
url_savename(afs, former, heap(ptr)->adr, heap(ptr)->fil,
|
||||||
opt, sback, cache, hash, ptr, numero_passe,
|
opt, sback, cache, hash, ptr, numero_passe,
|
||||||
&delayed_back);
|
&delayed_back);
|
||||||
|
} else if (cookies_changed) {
|
||||||
|
// #15: cookie-wall self-redirect; evict the cached
|
||||||
|
// fast-header so the re-issue refetches with the cookie.
|
||||||
|
if (cache->cached_tests != NULL)
|
||||||
|
coucal_remove(cache->cached_tests,
|
||||||
|
concat(OPT_GET_BUFF(opt),
|
||||||
|
OPT_GET_BUFF_SIZE(opt), afs->af.adr,
|
||||||
|
afs->af.fil));
|
||||||
|
afs->save[0] = '\0';
|
||||||
|
url_savename(afs, former, heap(ptr)->adr, heap(ptr)->fil, opt,
|
||||||
|
sback, cache, hash, ptr, numero_passe,
|
||||||
|
&delayed_back);
|
||||||
|
continue_loop = 1;
|
||||||
} else {
|
} else {
|
||||||
hts_log_print(opt, LOG_WARNING,
|
hts_log_print(opt, LOG_WARNING,
|
||||||
"Unable to test %s%s (loop to same filename)",
|
"Unable to test %s%s (loop to same filename)",
|
||||||
afs->af.adr, afs->af.fil);
|
afs->af.adr, afs->af.fil);
|
||||||
} // loop to same location
|
} // loop to same location
|
||||||
} // ident_url_relatif()
|
} // ident_url_relatif()
|
||||||
} // location
|
} // location
|
||||||
} // redirect
|
} // redirect
|
||||||
|
|||||||
539
src/htsproxy.c
Normal file
539
src/htsproxy.c
Normal file
@@ -0,0 +1,539 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
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: Proxy tunneling (HTTP CONNECT, SOCKS5) */
|
||||||
|
/* Author: Xavier Roche */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* Internal engine bytecode */
|
||||||
|
#define HTS_INTERNAL_BYTECODE
|
||||||
|
|
||||||
|
#include "htscore.h"
|
||||||
|
|
||||||
|
#include "htslib.h"
|
||||||
|
#include "htsproxy.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SOCKS5 client (RFC 1928, RFC 1929 auth), hostname mode only: the proxy
|
||||||
|
resolves the origin name (remote DNS, curl's socks5h). The stream is the
|
||||||
|
proxy socket, or a scripted buffer under -#test=socks5. */
|
||||||
|
|
||||||
|
#define SOCKS5_VERSION 0x05
|
||||||
|
#define SOCKS5_AUTH_VERSION 0x01
|
||||||
|
#define SOCKS5_METHOD_NONE 0x00
|
||||||
|
#define SOCKS5_METHOD_USERPASS 0x02
|
||||||
|
#define SOCKS5_METHOD_NOACCEPTABLE 0xFF
|
||||||
|
#define SOCKS5_CMD_CONNECT 0x01
|
||||||
|
#define SOCKS5_ATYP_IPV4 0x01
|
||||||
|
#define SOCKS5_ATYP_DOMAIN 0x03
|
||||||
|
#define SOCKS5_ATYP_IPV6 0x04
|
||||||
|
#define SOCKS5_MAXFIELD 255 /* one length byte: host, user and password */
|
||||||
|
|
||||||
|
typedef struct socks5_stream {
|
||||||
|
T_SOC soc; /* INVALID_SOCKET when scripted (self-test) */
|
||||||
|
int timeout;
|
||||||
|
socks5_test_io *io;
|
||||||
|
} socks5_stream;
|
||||||
|
|
||||||
|
static int socks5_fail(char *msg, size_t msgsize, const char *text) {
|
||||||
|
if (msgsize != 0)
|
||||||
|
strlcpybuff(msg, text, msgsize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read exactly n bytes, or fail: SOCKS frames are not self-delimiting, so a
|
||||||
|
short read would desync the stream shared with the origin traffic. */
|
||||||
|
static int socks5_read_n(socks5_stream *st, unsigned char *buf, size_t n) {
|
||||||
|
size_t got = 0;
|
||||||
|
int stalls = 0;
|
||||||
|
|
||||||
|
if (st->soc == INVALID_SOCKET) { /* scripted */
|
||||||
|
socks5_test_io *const io = st->io;
|
||||||
|
|
||||||
|
if (n > io->reply_len - io->consumed)
|
||||||
|
return 0;
|
||||||
|
memcpy(buf, io->reply + io->consumed, n);
|
||||||
|
io->consumed += n;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
while (got < n) {
|
||||||
|
const int r = (int) recv(st->soc, (char *) buf + got, (int) (n - got), 0);
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
got += (size_t) r;
|
||||||
|
stalls = 0;
|
||||||
|
} else if (r == 0) {
|
||||||
|
return 0; // proxy closed mid-frame
|
||||||
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
const int wouldblock = (WSAGetLastError() == WSAEWOULDBLOCK);
|
||||||
|
#else
|
||||||
|
const int wouldblock =
|
||||||
|
(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR);
|
||||||
|
#endif
|
||||||
|
if (!wouldblock || !check_readinput_t(st->soc, st->timeout) ||
|
||||||
|
++stalls > 100)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int socks5_write_all(socks5_stream *st, const unsigned char *buf,
|
||||||
|
size_t len) {
|
||||||
|
size_t remain = len;
|
||||||
|
int stalls = 0;
|
||||||
|
|
||||||
|
if (st->soc == INVALID_SOCKET) { /* scripted */
|
||||||
|
socks5_test_io *const io = st->io;
|
||||||
|
|
||||||
|
if (len > sizeof(io->sent) - io->sent_len)
|
||||||
|
return 0;
|
||||||
|
memcpy(io->sent + io->sent_len, buf, len);
|
||||||
|
io->sent_len += len;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
while (remain > 0) {
|
||||||
|
// raw send: the socket is still plain here, sendc() would route to TLS
|
||||||
|
const int n = (int) send(st->soc, (const char *) buf, (int) remain, 0);
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
buf += 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
|
||||||
|
if (!wouldblock || !check_writeinput_t(st->soc, st->timeout) ||
|
||||||
|
++stalls > 100)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *socks5_rep_message(unsigned char rep) {
|
||||||
|
switch (rep) {
|
||||||
|
case 0x01:
|
||||||
|
return "general failure";
|
||||||
|
case 0x02:
|
||||||
|
return "connection not allowed by ruleset";
|
||||||
|
case 0x03:
|
||||||
|
return "network unreachable";
|
||||||
|
case 0x04:
|
||||||
|
return "host unreachable";
|
||||||
|
case 0x05:
|
||||||
|
return "connection refused";
|
||||||
|
case 0x06:
|
||||||
|
return "TTL expired";
|
||||||
|
case 0x07:
|
||||||
|
return "command not supported";
|
||||||
|
case 0x08:
|
||||||
|
return "address type not supported";
|
||||||
|
default:
|
||||||
|
return "unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The reply's BND.ADDR is variable-length: consume exactly what ATYP says, or
|
||||||
|
the leftover bytes prepend to the first origin (or TLS) read. */
|
||||||
|
static int socks5_read_reply(socks5_stream *st, char *msg, size_t msgsize) {
|
||||||
|
unsigned char head[4];
|
||||||
|
unsigned char addr[SOCKS5_MAXFIELD + 2];
|
||||||
|
size_t addrlen;
|
||||||
|
|
||||||
|
if (!socks5_read_n(st, head, sizeof(head)))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: no reply from proxy");
|
||||||
|
if (head[0] != SOCKS5_VERSION)
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: bad version in reply");
|
||||||
|
if (head[1] != 0x00) {
|
||||||
|
snprintf(msg, msgsize, "SOCKS5 connect failed: %s",
|
||||||
|
socks5_rep_message(head[1]));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
switch (head[3]) {
|
||||||
|
case SOCKS5_ATYP_IPV4:
|
||||||
|
addrlen = 4;
|
||||||
|
break;
|
||||||
|
case SOCKS5_ATYP_IPV6:
|
||||||
|
addrlen = 16;
|
||||||
|
break;
|
||||||
|
case SOCKS5_ATYP_DOMAIN: {
|
||||||
|
unsigned char len;
|
||||||
|
|
||||||
|
if (!socks5_read_n(st, &len, 1))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: truncated reply");
|
||||||
|
addrlen = len; // <= 255, always fits addr[]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: // unknown length: the stream cannot be resynchronized
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: unknown address type in reply");
|
||||||
|
}
|
||||||
|
if (addrlen != 0 && !socks5_read_n(st, addr, addrlen))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: truncated reply address");
|
||||||
|
if (!socks5_read_n(st, addr, 2)) // BND.PORT, unused
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: truncated reply port");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int socks5_negotiate(socks5_stream *st, const char *host, size_t hostlen,
|
||||||
|
int port, const char *user, size_t userlen,
|
||||||
|
const char *pass, size_t passlen, int want_auth,
|
||||||
|
char *msg, size_t msgsize) {
|
||||||
|
unsigned char frame[3 + SOCKS5_MAXFIELD + SOCKS5_MAXFIELD];
|
||||||
|
unsigned char rep[2];
|
||||||
|
|
||||||
|
/* greeting */
|
||||||
|
frame[0] = SOCKS5_VERSION;
|
||||||
|
frame[1] = (unsigned char) (want_auth ? 2 : 1);
|
||||||
|
frame[2] = SOCKS5_METHOD_NONE;
|
||||||
|
frame[3] = SOCKS5_METHOD_USERPASS;
|
||||||
|
if (!socks5_write_all(st, frame, (size_t) 2 + frame[1]))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: write error");
|
||||||
|
if (!socks5_read_n(st, rep, sizeof(rep)))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: no method reply from proxy");
|
||||||
|
if (rep[0] != SOCKS5_VERSION)
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: bad version in method reply");
|
||||||
|
switch (rep[1]) {
|
||||||
|
case SOCKS5_METHOD_NONE:
|
||||||
|
break;
|
||||||
|
case SOCKS5_METHOD_USERPASS:
|
||||||
|
if (!want_auth)
|
||||||
|
return socks5_fail(msg, msgsize,
|
||||||
|
"SOCKS5: proxy requires authentication, none given");
|
||||||
|
/* RFC 1929 sub-negotiation; its version byte is 0x01, not 0x05 */
|
||||||
|
frame[0] = SOCKS5_AUTH_VERSION;
|
||||||
|
frame[1] = (unsigned char) userlen;
|
||||||
|
memcpy(frame + 2, user, userlen);
|
||||||
|
frame[2 + userlen] = (unsigned char) passlen;
|
||||||
|
memcpy(frame + 3 + userlen, pass, passlen);
|
||||||
|
if (!socks5_write_all(st, frame, 3 + userlen + passlen))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: write error");
|
||||||
|
if (!socks5_read_n(st, rep, sizeof(rep)))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: no authentication reply");
|
||||||
|
if (rep[1] != 0x00)
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: authentication failed");
|
||||||
|
break;
|
||||||
|
case SOCKS5_METHOD_NOACCEPTABLE:
|
||||||
|
return socks5_fail(
|
||||||
|
msg, msgsize,
|
||||||
|
"SOCKS5: proxy accepts no authentication method we offer");
|
||||||
|
default:
|
||||||
|
return socks5_fail(msg, msgsize,
|
||||||
|
"SOCKS5: proxy selected an unknown method");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CONNECT to the origin, by name */
|
||||||
|
frame[0] = SOCKS5_VERSION;
|
||||||
|
frame[1] = SOCKS5_CMD_CONNECT;
|
||||||
|
frame[2] = 0x00; // RSV
|
||||||
|
frame[3] = SOCKS5_ATYP_DOMAIN;
|
||||||
|
frame[4] = (unsigned char) hostlen;
|
||||||
|
memcpy(frame + 5, host, hostlen);
|
||||||
|
frame[5 + hostlen] = (unsigned char) (port >> 8);
|
||||||
|
frame[6 + hostlen] = (unsigned char) (port & 0xFF);
|
||||||
|
if (!socks5_write_all(st, frame, 7 + hostlen))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: write error");
|
||||||
|
|
||||||
|
return socks5_read_reply(st, msg, msgsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode the proxy userinfo into the two RFC 1929 fields. Split on the first
|
||||||
|
colon of the still-escaped string, so a %3A stays inside the username. */
|
||||||
|
static int socks5_credentials(httrackp *opt, const char *proxy_name, char *user,
|
||||||
|
size_t user_size, size_t *userlen, char *pass,
|
||||||
|
size_t pass_size, size_t *passlen, char *msg,
|
||||||
|
size_t msgsize) {
|
||||||
|
const char *const a = jump_identification_const(proxy_name); // past the '@'
|
||||||
|
const char *const astart = jump_protocol_const(proxy_name);
|
||||||
|
char userinfo[1024];
|
||||||
|
char *colon;
|
||||||
|
|
||||||
|
if (a <= astart || (size_t) (a - astart) - 1 >= sizeof(userinfo))
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: credentials too long");
|
||||||
|
userinfo[0] = '\0';
|
||||||
|
strncatbuff(userinfo, astart, (int) (a - astart) - 1);
|
||||||
|
colon = strchr(userinfo, ':');
|
||||||
|
if (colon != NULL)
|
||||||
|
*colon++ = '\0';
|
||||||
|
strlcpybuff(
|
||||||
|
user, unescape_http(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), userinfo),
|
||||||
|
user_size);
|
||||||
|
strlcpybuff(pass,
|
||||||
|
colon != NULL ? unescape_http(OPT_GET_BUFF(opt),
|
||||||
|
OPT_GET_BUFF_SIZE(opt), colon)
|
||||||
|
: "",
|
||||||
|
pass_size);
|
||||||
|
*userlen = strlen(user);
|
||||||
|
*passlen = strlen(pass);
|
||||||
|
// reject, never truncate: a clipped secret would authenticate as another one
|
||||||
|
if (*userlen > SOCKS5_MAXFIELD || *passlen > SOCKS5_MAXFIELD)
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: credentials too long");
|
||||||
|
if (*userlen == 0)
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: empty proxy username");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int socks5_handshake_stream(httrackp *opt, socks5_stream *st,
|
||||||
|
const char *adr, const char *proxy_name,
|
||||||
|
int ssl, char *msg, size_t msgsize) {
|
||||||
|
const char *const host = jump_identification_const(adr);
|
||||||
|
const char *const portsep = jump_toport_const(adr);
|
||||||
|
const size_t hostlen =
|
||||||
|
portsep != NULL ? (size_t) (portsep - host) : strlen(host);
|
||||||
|
// sized for the whole userinfo: decoding shrinks, so an over-long credential
|
||||||
|
// lands intact and is rejected below rather than silently clipped
|
||||||
|
char user[1024];
|
||||||
|
char pass[1024];
|
||||||
|
size_t userlen = 0, passlen = 0;
|
||||||
|
int want_auth = 0;
|
||||||
|
int port = ssl ? 443 : 80;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (hostlen == 0 || hostlen > SOCKS5_MAXFIELD)
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: invalid origin host");
|
||||||
|
if (host[0] == '[') // ATYP=domain cannot carry an IPv6 literal
|
||||||
|
return socks5_fail(msg, msgsize,
|
||||||
|
"SOCKS5: IPv6 literal origin is not supported");
|
||||||
|
for (i = 0; i < hostlen; i++) {
|
||||||
|
if ((unsigned char) host[i] < ' ')
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: invalid origin host");
|
||||||
|
}
|
||||||
|
if (portsep != NULL) {
|
||||||
|
int p = -1;
|
||||||
|
|
||||||
|
sscanf(portsep + 1, "%d", &p);
|
||||||
|
if (p <= 0 || p > 65535)
|
||||||
|
return socks5_fail(msg, msgsize, "SOCKS5: invalid origin port");
|
||||||
|
port = p;
|
||||||
|
}
|
||||||
|
if (link_has_authorization(proxy_name)) {
|
||||||
|
if (!socks5_credentials(opt, proxy_name, user, sizeof(user), &userlen, pass,
|
||||||
|
sizeof(pass), &passlen, msg, msgsize))
|
||||||
|
return 0;
|
||||||
|
want_auth = 1;
|
||||||
|
}
|
||||||
|
return socks5_negotiate(st, host, hostlen, port, user, userlen, pass, passlen,
|
||||||
|
want_auth, msg, msgsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int socks5_handshake(httrackp *opt, htsblk *retour, const char *adr,
|
||||||
|
int timeout) {
|
||||||
|
socks5_stream st;
|
||||||
|
#if HTS_USEOPENSSL
|
||||||
|
const int ssl = retour->ssl;
|
||||||
|
#else
|
||||||
|
const int ssl = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (retour->soc == INVALID_SOCKET)
|
||||||
|
return 0;
|
||||||
|
st.soc = retour->soc;
|
||||||
|
st.timeout = timeout;
|
||||||
|
st.io = NULL;
|
||||||
|
return socks5_handshake_stream(opt, &st, adr, retour->req.proxy.name, ssl,
|
||||||
|
retour->msg, sizeof(retour->msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
int socks5_handshake_scripted(httrackp *opt, const char *adr,
|
||||||
|
const char *proxy_name, socks5_test_io *io) {
|
||||||
|
socks5_stream st;
|
||||||
|
|
||||||
|
st.soc = INVALID_SOCKET;
|
||||||
|
st.timeout = 0;
|
||||||
|
st.io = io;
|
||||||
|
io->consumed = 0;
|
||||||
|
io->sent_len = 0;
|
||||||
|
io->msg[0] = '\0';
|
||||||
|
return socks5_handshake_stream(opt, &st, adr, proxy_name, 0, io->msg,
|
||||||
|
sizeof(io->msg));
|
||||||
|
}
|
||||||
82
src/htsproxy.h
Normal file
82
src/htsproxy.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/*
|
||||||
|
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: Proxy tunneling (HTTP CONNECT, SOCKS5) .h */
|
||||||
|
/* Author: Xavier Roche */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#ifndef HTS_DEFPROXY
|
||||||
|
#define HTS_DEFPROXY
|
||||||
|
|
||||||
|
#include "htsglobal.h"
|
||||||
|
|
||||||
|
/* Forward definitions */
|
||||||
|
#ifndef HTS_DEF_FWSTRUCT_httrackp
|
||||||
|
#define HTS_DEF_FWSTRUCT_httrackp
|
||||||
|
typedef struct httrackp httrackp;
|
||||||
|
#endif
|
||||||
|
#ifndef HTS_DEF_FWSTRUCT_htsblk
|
||||||
|
#define HTS_DEF_FWSTRUCT_htsblk
|
||||||
|
typedef struct htsblk htsblk;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Open an HTTP CONNECT tunnel through the active proxy for an https request:
|
||||||
|
`retour->soc` must already be TCP-connected to the proxy, and `adr` is the
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* SOCKS5 (RFC 1928, RFC 1929 auth) handshake on the raw proxy socket, before
|
||||||
|
any TLS: `retour->soc` must be TCP-connected to the proxy and `adr` is the
|
||||||
|
origin (url_adr). The origin name is sent verbatim (ATYP=domain), so the
|
||||||
|
proxy resolves it; a bracketed IPv6 literal origin is rejected. Blocks up to
|
||||||
|
`timeout` seconds. Returns 1 with the stream positioned on the first origin
|
||||||
|
byte, 0 on failure (retour->msg set). */
|
||||||
|
int socks5_handshake(httrackp *opt, htsblk *retour, const char *adr,
|
||||||
|
int timeout);
|
||||||
|
|
||||||
|
/* Self-test hook (-#test=socks5): run the handshake against `reply`, a scripted
|
||||||
|
server byte stream, instead of a socket. `sent` captures the client frames,
|
||||||
|
`consumed` the reply bytes eaten (the frame-desync guard). */
|
||||||
|
typedef struct socks5_test_io {
|
||||||
|
const unsigned char *reply;
|
||||||
|
size_t reply_len;
|
||||||
|
size_t consumed;
|
||||||
|
unsigned char sent[1024];
|
||||||
|
size_t sent_len;
|
||||||
|
char msg[256];
|
||||||
|
} socks5_test_io;
|
||||||
|
|
||||||
|
int socks5_handshake_scripted(httrackp *opt, const char *adr,
|
||||||
|
const char *proxy_name, socks5_test_io *io);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -456,13 +456,6 @@ static HTS_INLINE HTS_UNUSED const char *htsbuff_str(const htsbuff *b) {
|
|||||||
return b->buf;
|
return b->buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** True if 'count' records of >= 1 byte each fit in 'available' bytes; guards
|
|
||||||
an attacker-controlled count driving a large allocation. */
|
|
||||||
static HTS_INLINE HTS_UNUSED hts_boolean hts_count_fits(size_t count,
|
|
||||||
LLint available) {
|
|
||||||
return (available >= 0 && (LLint) count <= available) ? HTS_TRUE : HTS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thin aliases over the libc allocator/memcpy (historical "t" suffix); no
|
/* Thin aliases over the libc allocator/memcpy (historical "t" suffix); no
|
||||||
added bounds checking. freet() also NULLs the freed pointer and tolerates
|
added bounds checking. freet() also NULLs the freed pointer and tolerates
|
||||||
NULL. memcpybuff() despite the name is a raw memcpy: the caller owns the
|
NULL. memcpybuff() despite the name is a raw memcpy: the caller owns the
|
||||||
|
|||||||
@@ -54,9 +54,14 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htsftp.h"
|
#include "htsftp.h"
|
||||||
#include "htsmd5.h"
|
#include "htsmd5.h"
|
||||||
#include "htssniff.h"
|
#include "htssniff.h"
|
||||||
|
#include "htscodec.h"
|
||||||
|
#include "htsproxy.h"
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if HTS_USEZSTD
|
||||||
|
#include <zstd.h>
|
||||||
|
#endif
|
||||||
#include "coucal/coucal.h"
|
#include "coucal/coucal.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -740,6 +745,44 @@ static int st_filterdual(httrackp *opt, int argc, char **argv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Length/work caps stop a hostile pattern stack-overflowing or hanging the
|
||||||
|
process (OSS-Fuzz 5060751291908096 / 5745936014573568). */
|
||||||
|
static int st_filterbounds(httrackp *opt, int argc, char **argv) {
|
||||||
|
const size_t big = 100000; /* well past the length cap */
|
||||||
|
const size_t stars = 1023; /* pattern len 2047, under the length cap */
|
||||||
|
const size_t subjlen = 2048;
|
||||||
|
char *subj = malloct(big + 1);
|
||||||
|
char *pat = malloct(2 * stars + 2);
|
||||||
|
size_t steps = 0, maxsteps = 0, i;
|
||||||
|
|
||||||
|
(void) opt;
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
memset(subj, 'a', big);
|
||||||
|
subj[big] = '\0';
|
||||||
|
/* '*' matches anything, but an over-length subject trips the length cap */
|
||||||
|
assertf(strjoker(subj, "*", NULL, NULL) == NULL);
|
||||||
|
assertf(strjokerfind(subj, "*") == NULL);
|
||||||
|
/* Star-heavy dead-end at the length cap: unbounded it runs ~1.26e9 memo-steps
|
||||||
|
(~6s). */
|
||||||
|
for (i = 0; i < stars; i++) {
|
||||||
|
pat[2 * i] = '*';
|
||||||
|
pat[2 * i + 1] = 'a';
|
||||||
|
}
|
||||||
|
pat[2 * stars] = 'b'; /* never matches an all-'a' subject */
|
||||||
|
pat[2 * stars + 1] = '\0';
|
||||||
|
subj[subjlen] = '\0';
|
||||||
|
/* Budget must fire and hold: steps > cap (deleting the budget zeroes the
|
||||||
|
counter that is the enforcement), steps < 10*cap (unbudgeted ~1.26e9). */
|
||||||
|
assertf(strjoker_steps(subj, pat, &steps, &maxsteps) == NULL);
|
||||||
|
assertf(steps > maxsteps && steps < 10 * maxsteps);
|
||||||
|
assertf(strjokerfind(subj, pat) == NULL);
|
||||||
|
freet(pat);
|
||||||
|
freet(subj);
|
||||||
|
printf("filterbounds: OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int st_simplify(httrackp *opt, int argc, char **argv) {
|
static int st_simplify(httrackp *opt, int argc, char **argv) {
|
||||||
(void) opt;
|
(void) opt;
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
@@ -1266,6 +1309,186 @@ static int st_identurl(httrackp *opt, int argc, char **argv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int st_proxyurl(httrackp *opt, int argc, char **argv) {
|
||||||
|
char BIGSTK name[HTS_URLMAXSIZE * 2];
|
||||||
|
int port = -1;
|
||||||
|
|
||||||
|
(void) opt;
|
||||||
|
if (argc < 1) {
|
||||||
|
fprintf(stderr, "proxyurl: needs a proxy argument\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
hts_parse_proxy(argv[0], name, sizeof(name), &port);
|
||||||
|
// host= is what the connect actually resolves (scheme + user:pass stripped)
|
||||||
|
printf("name=%s port=%d host=%s\n", name, port,
|
||||||
|
jump_identification_const(name));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scripted SOCKS5 server: no-auth method reply, then a success CONNECT reply
|
||||||
|
carrying the given ATYP address, then a sentinel origin byte the handshake
|
||||||
|
must leave unread (an off-by-one in the reply framing eats it). */
|
||||||
|
static size_t socks5_reply(unsigned char *buf, unsigned char atyp,
|
||||||
|
const unsigned char *addr, size_t addrlen) {
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
buf[n++] = 0x05;
|
||||||
|
buf[n++] = 0x00; /* method: no authentication */
|
||||||
|
buf[n++] = 0x05;
|
||||||
|
buf[n++] = 0x00; /* REP: succeeded */
|
||||||
|
buf[n++] = 0x00;
|
||||||
|
buf[n++] = atyp;
|
||||||
|
memcpy(buf + n, addr, addrlen);
|
||||||
|
n += addrlen;
|
||||||
|
buf[n++] = 0x1f;
|
||||||
|
buf[n++] = 0x90; /* BND.PORT */
|
||||||
|
buf[n++] = 0xAA; /* sentinel */
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SOCKS5_SENTINEL_LEFT(io, len) ((io).consumed == (len) - 1)
|
||||||
|
|
||||||
|
static int st_socks5(httrackp *opt, int argc, char **argv) {
|
||||||
|
static const unsigned char v4[4] = {127, 0, 0, 1};
|
||||||
|
static const unsigned char v6[16] = {0};
|
||||||
|
static const unsigned char domain[6] = {5, 'p', 'r', 'o', 'x', 'y'};
|
||||||
|
const char *const proxy = "socks5://127.0.0.1";
|
||||||
|
unsigned char script[64];
|
||||||
|
socks5_test_io io;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
|
||||||
|
/* each reply address type is drained exactly, sentinel untouched */
|
||||||
|
len = socks5_reply(script, 0x01, v4, sizeof(v4));
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 1);
|
||||||
|
assertf(SOCKS5_SENTINEL_LEFT(io, len));
|
||||||
|
/* the greeting offers no-auth only, and the origin goes out by name, port 80
|
||||||
|
*/
|
||||||
|
assertf(io.sent_len == 3 + 7 + 11);
|
||||||
|
assertf(memcmp(io.sent, "\x05\x01\x00", 3) == 0);
|
||||||
|
assertf(memcmp(io.sent + 3, "\x05\x01\x00\x03\x0borigin.test\x00\x50", 18) ==
|
||||||
|
0);
|
||||||
|
|
||||||
|
len = socks5_reply(script, 0x04, v6, sizeof(v6));
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 1);
|
||||||
|
assertf(SOCKS5_SENTINEL_LEFT(io, len));
|
||||||
|
|
||||||
|
len = socks5_reply(script, 0x03, domain, sizeof(domain));
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 1);
|
||||||
|
assertf(SOCKS5_SENTINEL_LEFT(io, len));
|
||||||
|
|
||||||
|
/* an unknown address type has no known length: fail, never guess */
|
||||||
|
len = socks5_reply(script, 0x02, v4, sizeof(v4));
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 0);
|
||||||
|
|
||||||
|
/* truncated frames (here: no BND.PORT) fail instead of over-reading */
|
||||||
|
len = socks5_reply(script, 0x01, v4, sizeof(v4)) - 3;
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 0);
|
||||||
|
|
||||||
|
/* explicit origin port is encoded big-endian (8443 = 0x20fb) */
|
||||||
|
len = socks5_reply(script, 0x01, v4, sizeof(v4));
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test:8443", proxy, &io) == 1);
|
||||||
|
assertf(memcmp(io.sent + io.sent_len - 2, "\x20\xfb", 2) == 0);
|
||||||
|
|
||||||
|
/* credentials: split on the first colon of the escaped userinfo, so %3a stays
|
||||||
|
inside the username and a colon in the password is not a delimiter */
|
||||||
|
{
|
||||||
|
static const unsigned char auth_script[] = {
|
||||||
|
0x05, 0x02, /* method: user/pass */
|
||||||
|
0x01, 0x00, /* auth: success */
|
||||||
|
0x05, 0x00, 0x00, 0x01, /* REP: succeeded, ATYP ipv4 */
|
||||||
|
127, 0, 0, 1, 0x1f, 0x90, 0xAA};
|
||||||
|
|
||||||
|
io.reply = auth_script;
|
||||||
|
io.reply_len = sizeof(auth_script);
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test",
|
||||||
|
"socks5://us%3aer:p:ass@127.0.0.1",
|
||||||
|
&io) == 1);
|
||||||
|
assertf(SOCKS5_SENTINEL_LEFT(io, sizeof(auth_script)));
|
||||||
|
assertf(memcmp(io.sent, "\x05\x02\x00\x02", 4) == 0);
|
||||||
|
assertf(memcmp(io.sent + 4, "\x01\x05us:er\x05p:ass", 13) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a proxy demanding auth we cannot provide, and one refusing every method */
|
||||||
|
io.reply = (const unsigned char *) "\x05\x02";
|
||||||
|
io.reply_len = 2;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 0);
|
||||||
|
io.reply = (const unsigned char *) "\x05\xff";
|
||||||
|
io.reply_len = 2;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 0);
|
||||||
|
|
||||||
|
/* a refused CONNECT is an error, not a tunnel */
|
||||||
|
io.reply = (const unsigned char
|
||||||
|
*) "\x05\x00\x05\x05\x00\x01\x7f\x00\x00\x01\x1f\x90";
|
||||||
|
io.reply_len = 12;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", proxy, &io) == 0);
|
||||||
|
|
||||||
|
/* over-long host or credentials are rejected before anything is sent */
|
||||||
|
{
|
||||||
|
char host[512];
|
||||||
|
char name[1024];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
host[0] = '\0';
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
strcatbuff(host, "a");
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, host, proxy, &io) == 0);
|
||||||
|
assertf(io.sent_len == 0);
|
||||||
|
|
||||||
|
strcpybuff(name, "socks5://user:");
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
strcatbuff(name, "p");
|
||||||
|
strcatbuff(name, "@127.0.0.1");
|
||||||
|
io.reply = script;
|
||||||
|
io.reply_len = len;
|
||||||
|
assertf(socks5_handshake_scripted(opt, "origin.test", name, &io) == 0);
|
||||||
|
assertf(io.sent_len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("socks5 self-test OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regression for the one-byte fil[] overflow: a 2047-byte hostless "?"-URL used
|
||||||
|
to abort in strncat_safe_ when the missing leading '/' pushed fil to 2048. */
|
||||||
|
static int st_identabs(httrackp *opt, int argc, char **argv) {
|
||||||
|
lien_adrfil af;
|
||||||
|
const size_t len =
|
||||||
|
sizeof(af.fil) - 1; /* 2047: max URL the top guard admits */
|
||||||
|
char *url = malloct(len + 1);
|
||||||
|
|
||||||
|
(void) opt;
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
url[0] = '?';
|
||||||
|
memset(url + 1, 'a', len - 1);
|
||||||
|
url[len] = '\0';
|
||||||
|
assertf(ident_url_absolute(url, &af) == -1);
|
||||||
|
freet(url);
|
||||||
|
/* valid URLs still parse, so the guard is not over-rejecting */
|
||||||
|
assertf(ident_url_absolute("http://www.example.com/a/b/c.html?x=1", &af) ==
|
||||||
|
0);
|
||||||
|
assertf(ident_url_absolute("www.foo.com?bar=1", &af) == 0);
|
||||||
|
printf("identabs self-test OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Extra args are key=value: adr= cdispo= statuscode= status= strip= urlhack=
|
/* Extra args are key=value: adr= cdispo= statuscode= status= strip= urlhack=
|
||||||
no-www= no-slash= no-query= n83= type=, plus repeatable prior=adr|fil|sav
|
no-www= no-slash= no-query= n83= type=, plus repeatable prior=adr|fil|sav
|
||||||
registering an already-crawled link (dedup/collision paths). */
|
registering an already-crawled link (dedup/collision paths). */
|
||||||
@@ -1310,6 +1533,82 @@ static int st_headerlong(httrackp *opt, int argc, char **argv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* http_xfread1 must refuse an in-memory buffer whose size would exceed a 32-bit
|
||||||
|
index (hostile Content-Length or endless stream) rather than allocate it.
|
||||||
|
The guard returns before any socket read, so no real connection is needed. */
|
||||||
|
static int st_xfread_limit(httrackp *opt, int argc, char **argv) {
|
||||||
|
htsblk r;
|
||||||
|
|
||||||
|
(void) opt;
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
|
||||||
|
// Content-Length just over 2 GiB.
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
r.soc = INVALID_SOCKET;
|
||||||
|
r.totalsize = (LLint) INT32_MAX + 1;
|
||||||
|
printf("bylen: refused=%d adr=%s msg=%s\n",
|
||||||
|
http_xfread1(&r, 8192) == READ_ERROR, r.adr != NULL ? "alloc" : "null",
|
||||||
|
r.msg);
|
||||||
|
if (r.adr != NULL)
|
||||||
|
freet(r.adr);
|
||||||
|
|
||||||
|
// Unknown length, buffer already at the limit: the next read would exceed it.
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
r.soc = INVALID_SOCKET;
|
||||||
|
r.totalsize = -1;
|
||||||
|
r.size = (LLint) INT32_MAX;
|
||||||
|
printf("bygrow: refused=%d adr=%s msg=%s\n",
|
||||||
|
http_xfread1(&r, 8192) == READ_ERROR, r.adr != NULL ? "alloc" : "null",
|
||||||
|
r.msg);
|
||||||
|
if (r.adr != NULL)
|
||||||
|
freet(r.adr);
|
||||||
|
|
||||||
|
// Exactly at the 2 GiB index (size + bufl == INT32_MAX): must also be
|
||||||
|
// refused, since the reallocs below add 1 (a `> INT32_MAX` check would let
|
||||||
|
// this through and overflow the int realloc size).
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
r.soc = INVALID_SOCKET;
|
||||||
|
r.totalsize = -1;
|
||||||
|
r.size = (LLint) INT32_MAX - 8192;
|
||||||
|
http_xfread1(&r, 8192);
|
||||||
|
printf("boundary: msg=%s\n", r.msg);
|
||||||
|
|
||||||
|
// A legitimate small size must NOT be refused by the guard (the read then
|
||||||
|
// fails on the invalid socket, but the size-too-large msg must not be set).
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
r.soc = INVALID_SOCKET;
|
||||||
|
r.totalsize = 1000;
|
||||||
|
http_xfread1(&r, 8192);
|
||||||
|
printf("accept: msg=%s\n", r.msg);
|
||||||
|
if (r.adr != NULL)
|
||||||
|
freet(r.adr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a Content-Range header and print the sanitized triple. A hostile value
|
||||||
|
(negative or INT64 extreme) must clamp to 0 without signed-overflow UB. */
|
||||||
|
static int st_crange(httrackp *opt, int argc, char **argv) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
(void) opt;
|
||||||
|
if (argc < 1) {
|
||||||
|
fprintf(stderr, "crange: needs at least one raw Content-Range line\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
htsblk r;
|
||||||
|
char BIGSTK line[HTS_URLMAXSIZE * 2];
|
||||||
|
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
strcpybuff(line, argv[i]);
|
||||||
|
treathead(NULL, "www.example.com", "/", &r, line);
|
||||||
|
printf("crange_start=" LLintP " crange_end=" LLintP " crange=" LLintP "\n",
|
||||||
|
(LLint) r.crange_start, (LLint) r.crange_end, (LLint) r.crange);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Decode a body argument ("hex:FFD8.." or literal text) into buf. */
|
/* Decode a body argument ("hex:FFD8.." or literal text) into buf. */
|
||||||
static size_t st_decode_body(const char *arg, char *buf, size_t size) {
|
static size_t st_decode_body(const char *arg, char *buf, size_t size) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
@@ -1679,9 +1978,30 @@ static int st_cookies(httrackp *opt, int argc, char **argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
http_cookie_header_selftest(&cookie, dom, "/", hdr, sizeof(hdr));
|
http_cookie_header(&cookie, dom, "/", hdr, sizeof(hdr));
|
||||||
if (strcmp(hdr, expected) != 0)
|
if (strcmp(hdr, expected) != 0)
|
||||||
err = 1;
|
err = 1;
|
||||||
|
|
||||||
|
/* A hostile over-long request host must not overflow domain[256] in
|
||||||
|
treathead's default-domain copy (that would abort the mirror). */
|
||||||
|
{
|
||||||
|
static t_cookie ck2;
|
||||||
|
htsblk r;
|
||||||
|
char host[600];
|
||||||
|
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
memset(host, 'a', sizeof(host) - 1);
|
||||||
|
host[sizeof(host) - 1] = '\0';
|
||||||
|
ck2.max_len = (int) sizeof(ck2.data);
|
||||||
|
ck2.data[0] = '\0';
|
||||||
|
treathead(&ck2, host, "/", &r, "Set-Cookie: SID=1; path=/");
|
||||||
|
if (strnotempty(ck2.data)) // oversize-host cookie was not dropped
|
||||||
|
err = 1;
|
||||||
|
/* control: a normal host still yields a cookie through treathead */
|
||||||
|
treathead(&ck2, dom, "/", &r, "Set-Cookie: SID=1; path=/");
|
||||||
|
if (strstr(ck2.data, "SID") == NULL) // guard wrongly dropped a valid cookie
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
if (strstr(hdr, "$Version") != NULL || strstr(hdr, "$Path") != NULL)
|
if (strstr(hdr, "$Version") != NULL || strstr(hdr, "$Path") != NULL)
|
||||||
err = 1;
|
err = 1;
|
||||||
if (strstr(hdr, "junk") != NULL) // wrong-domain cookie leaked
|
if (strstr(hdr, "junk") != NULL) // wrong-domain cookie leaked
|
||||||
@@ -2146,6 +2466,7 @@ static int ae_write_collision(const char *path, const unsigned char *src,
|
|||||||
freet(buf);
|
freet(buf);
|
||||||
return ok ? 0 : 1;
|
return ok ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Write src[0..len) to path as-is; 0 on success. */
|
/* Write src[0..len) to path as-is; 0 on success. */
|
||||||
static int ae_write_raw(const char *path, const unsigned char *src,
|
static int ae_write_raw(const char *path, const unsigned char *src,
|
||||||
@@ -2179,17 +2500,22 @@ static int ae_check_decoded(const char *path, const unsigned char *expect,
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
return (off == len) ? 0 : 1;
|
return (off == len) ? 0 : 1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Accept-Encoding (#450): advertise gzip+deflate; both decode (hts_zunpack) */
|
/* Accept-Encoding (#450): advertise gzip+deflate; both decode (hts_zunpack) */
|
||||||
static int st_acceptencoding(httrackp *opt, int argc, char **argv) {
|
static int st_acceptencoding(httrackp *opt, int argc, char **argv) {
|
||||||
const char *off = hts_acceptencoding(HTS_FALSE);
|
const char *off = hts_acceptencoding(HTS_FALSE, HTS_TRUE);
|
||||||
const char *on = hts_acceptencoding(HTS_TRUE);
|
const char *on = hts_acceptencoding(HTS_TRUE, HTS_FALSE);
|
||||||
|
const char *tls = hts_acceptencoding(HTS_TRUE, HTS_TRUE);
|
||||||
|
|
||||||
(void) opt;
|
(void) opt;
|
||||||
assertf(strcmp(off, "identity") == 0);
|
assertf(strcmp(off, "identity") == 0);
|
||||||
assertf(strstr(on, "gzip") != NULL);
|
assertf(strstr(on, "gzip") != NULL);
|
||||||
assertf(strstr(on, "deflate") != NULL); /* fails on the old gzip-only list */
|
assertf(strstr(on, "deflate") != NULL); /* fails on the old gzip-only list */
|
||||||
|
/* br and zstd ride on TLS only, so a cleartext proxy can not be handed a
|
||||||
|
coding it may try to rewrite */
|
||||||
|
assertf(strstr(on, "br") == NULL && strstr(on, "zstd") == NULL);
|
||||||
|
assertf((strstr(tls, ", br") != NULL) == (HTS_USEBROTLI != 0));
|
||||||
|
assertf((strstr(tls, "zstd") != NULL) == (HTS_USEZSTD != 0));
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
if (argc >= 1) {
|
if (argc >= 1) {
|
||||||
static const int windowBits[] = {16 + MAX_WBITS, MAX_WBITS, -MAX_WBITS};
|
static const int windowBits[] = {16 + MAX_WBITS, MAX_WBITS, -MAX_WBITS};
|
||||||
@@ -2277,6 +2603,115 @@ static int st_acceptencoding(httrackp *opt, int argc, char **argv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HTS_USEBROTLI
|
||||||
|
/* No brotli encoder is linked, so the coded bytes are canned: brotli quality 9
|
||||||
|
over cc_text, and over 4 MiB of 'A' (14 bytes, ~300000x). */
|
||||||
|
static const unsigned char cc_br_text[] = {
|
||||||
|
0x1b, 0x43, 0x00, 0x00, 0x44, 0xdd, 0x96, 0xea, 0xe8, 0x22, 0xdd, 0x90,
|
||||||
|
0xa4, 0x1b, 0x8a, 0xf7, 0x47, 0x0e, 0xc2, 0xc5, 0x3d, 0x09, 0x1b, 0x70,
|
||||||
|
0xe0, 0x1e, 0x60, 0xa0, 0x8b, 0xcc, 0xbe, 0xcb, 0xb0, 0x31, 0x76, 0x9e,
|
||||||
|
0xcf, 0x6e, 0x41, 0xb5, 0xe8, 0x2e, 0x56, 0x78, 0x08, 0x1b, 0xfa, 0x08,
|
||||||
|
0x8a, 0x50, 0x83, 0x4e, 0x62, 0x7f, 0xbf, 0x05, 0xf2, 0x22, 0x8f, 0xdf,
|
||||||
|
0x28, 0xdc, 0x9f, 0xa9, 0x90, 0x50, 0x37, 0x62, 0x56, 0x4f, 0xa8};
|
||||||
|
static const unsigned char cc_br_bomb[] = {0x9b, 0xff, 0xff, 0x3f, 0x00,
|
||||||
|
0x24, 0x82, 0xe2, 0xb1, 0x40,
|
||||||
|
0x72, 0xef, 0x7f, 0x00};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const unsigned char cc_text[] =
|
||||||
|
"content codings: HTTrack decodes gzip, brotli and zstd bodies alike.";
|
||||||
|
|
||||||
|
/* Content codings: br and zstd decode, junk tokens stay identity, a coding we
|
||||||
|
can not undo fails the fetch, and a bomb never lands on disk. */
|
||||||
|
static int st_contentcodings(httrackp *opt, int argc, char **argv) {
|
||||||
|
const size_t tlen = sizeof(cc_text) - 1;
|
||||||
|
char inpath[HTS_URLMAXSIZE], outpath[HTS_URLMAXSIZE];
|
||||||
|
|
||||||
|
(void) opt;
|
||||||
|
assertf(hts_codec_parse("gzip") == HTS_CODEC_DEFLATE);
|
||||||
|
assertf(hts_codec_parse("x-deflate") == HTS_CODEC_DEFLATE);
|
||||||
|
assertf(hts_codec_parse("") == HTS_CODEC_IDENTITY);
|
||||||
|
assertf(hts_codec_parse("identity") == HTS_CODEC_IDENTITY);
|
||||||
|
/* servers do label plain bodies with junk; the page must survive that */
|
||||||
|
assertf(hts_codec_parse("utf-8") == HTS_CODEC_IDENTITY);
|
||||||
|
/* a real coding with no decoder here: fail, never save the coded bytes */
|
||||||
|
assertf(hts_codec_parse("compress") == HTS_CODEC_UNSUPPORTED);
|
||||||
|
assertf(hts_codec_parse("br") ==
|
||||||
|
(HTS_USEBROTLI ? HTS_CODEC_BROTLI : HTS_CODEC_UNSUPPORTED));
|
||||||
|
assertf(hts_codec_parse("zstd") ==
|
||||||
|
(HTS_USEZSTD ? HTS_CODEC_ZSTD : HTS_CODEC_UNSUPPORTED));
|
||||||
|
assertf(hts_codec_is_archive_ext(HTS_CODEC_DEFLATE, "tgz"));
|
||||||
|
assertf(!hts_codec_is_archive_ext(HTS_CODEC_DEFLATE, "html"));
|
||||||
|
assertf(hts_codec_is_archive_ext(HTS_CODEC_BROTLI, "br"));
|
||||||
|
assertf(hts_codec_is_archive_ext(HTS_CODEC_ZSTD, "zst"));
|
||||||
|
/* decoded-size budget: 4096x, floor 1 MiB, ceiling INT_MAX */
|
||||||
|
assertf(hts_codec_maxout(1) == 1024 * 1024);
|
||||||
|
assertf(hts_codec_maxout(1024) == 4096 * 1024);
|
||||||
|
assertf(hts_codec_maxout(1024 * 1024) == INT_MAX);
|
||||||
|
|
||||||
|
if (argc >= 1) {
|
||||||
|
snprintf(inpath, sizeof(inpath), "%s/cc-in", argv[0]);
|
||||||
|
snprintf(outpath, sizeof(outpath), "%s/cc-out", argv[0]);
|
||||||
|
#if HTS_USEBROTLI
|
||||||
|
{
|
||||||
|
unsigned char head[16];
|
||||||
|
|
||||||
|
assertf(ae_write_raw(inpath, cc_br_text, sizeof(cc_br_text)) == 0);
|
||||||
|
assertf(hts_codec_unpack(HTS_CODEC_BROTLI, inpath, outpath) ==
|
||||||
|
(int) tlen);
|
||||||
|
assertf(ae_check_decoded(outpath, cc_text, tlen) == 0);
|
||||||
|
assertf(hts_codec_head(HTS_CODEC_BROTLI, cc_br_text, sizeof(cc_br_text),
|
||||||
|
head, sizeof(head)) == sizeof(head));
|
||||||
|
assertf(memcmp(head, cc_text, sizeof(head)) == 0);
|
||||||
|
/* truncated: must fail, not fall back to a verbatim copy */
|
||||||
|
assertf(ae_write_raw(inpath, cc_br_text, sizeof(cc_br_text) - 4) == 0);
|
||||||
|
assertf(hts_codec_unpack(HTS_CODEC_BROTLI, inpath, outpath) < 0);
|
||||||
|
/* cc_br_bomb is a valid stream that expands to 4 MiB; the budget, not a
|
||||||
|
corrupt frame, is what must reject it. */
|
||||||
|
assertf((LLint) (4 * 1024 * 1024) >
|
||||||
|
hts_codec_maxout((LLint) sizeof(cc_br_bomb)));
|
||||||
|
assertf(ae_write_raw(inpath, cc_br_bomb, sizeof(cc_br_bomb)) == 0);
|
||||||
|
assertf(hts_codec_unpack(HTS_CODEC_BROTLI, inpath, outpath) < 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if HTS_USEZSTD
|
||||||
|
{
|
||||||
|
const size_t bomblen = 4 * 1024 * 1024;
|
||||||
|
const size_t bound = ZSTD_compressBound(bomblen);
|
||||||
|
unsigned char *bomb = malloct(bomblen);
|
||||||
|
unsigned char *zbuf = malloct(bound);
|
||||||
|
unsigned char head[16];
|
||||||
|
size_t zlen;
|
||||||
|
|
||||||
|
assertf(bomb != NULL && zbuf != NULL);
|
||||||
|
zlen = ZSTD_compress(zbuf, bound, cc_text, tlen, 6);
|
||||||
|
assertf(!ZSTD_isError(zlen));
|
||||||
|
assertf(ae_write_raw(inpath, zbuf, zlen) == 0);
|
||||||
|
assertf(hts_codec_unpack(HTS_CODEC_ZSTD, inpath, outpath) == (int) tlen);
|
||||||
|
assertf(ae_check_decoded(outpath, cc_text, tlen) == 0);
|
||||||
|
assertf(hts_codec_head(HTS_CODEC_ZSTD, zbuf, zlen, head, sizeof(head)) ==
|
||||||
|
sizeof(head));
|
||||||
|
assertf(memcmp(head, cc_text, sizeof(head)) == 0);
|
||||||
|
assertf(ae_write_raw(inpath, zbuf, zlen - 4) == 0);
|
||||||
|
assertf(hts_codec_unpack(HTS_CODEC_ZSTD, inpath, outpath) < 0);
|
||||||
|
memset(bomb, 'A', bomblen);
|
||||||
|
zlen = ZSTD_compress(zbuf, bound, bomb, bomblen, 6);
|
||||||
|
assertf(!ZSTD_isError(zlen));
|
||||||
|
/* the fixture must really be past the budget, whatever the ratio is */
|
||||||
|
assertf((LLint) bomblen > hts_codec_maxout((LLint) zlen));
|
||||||
|
assertf(ae_write_raw(inpath, zbuf, zlen) == 0);
|
||||||
|
assertf(hts_codec_unpack(HTS_CODEC_ZSTD, inpath, outpath) < 0);
|
||||||
|
freet(bomb);
|
||||||
|
freet(zbuf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* a coding we can not undo yields no file at all */
|
||||||
|
assertf(hts_codec_unpack(HTS_CODEC_UNSUPPORTED, inpath, outpath) < 0);
|
||||||
|
}
|
||||||
|
printf("contentcodings self-test OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Each call parses `txt` under a fresh host, then checkrobots() for `path`. */
|
/* Each call parses `txt` under a fresh host, then checkrobots() for `path`. */
|
||||||
static int rb_decide(robots_wizard *r, const char *txt, const char *path) {
|
static int rb_decide(robots_wizard *r, const char *txt, const char *path) {
|
||||||
static int n = 0;
|
static int n = 0;
|
||||||
@@ -2425,21 +2860,6 @@ static int st_ftpuser(httrackp *opt, int argc, char **argv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hts_count_fits caps the .class constant-pool entry count to the file size,
|
|
||||||
rejecting the ~68 MB-per-file calloc DoS. */
|
|
||||||
static int st_java(httrackp *opt, int argc, char **argv) {
|
|
||||||
(void) opt;
|
|
||||||
(void) argc;
|
|
||||||
(void) argv;
|
|
||||||
assertf(hts_count_fits(10, 1000) == HTS_TRUE);
|
|
||||||
assertf(hts_count_fits(0, 10) == HTS_TRUE);
|
|
||||||
assertf(hts_count_fits(65535, 10) == HTS_FALSE);
|
|
||||||
assertf(hts_count_fits(1, 0) == HTS_FALSE);
|
|
||||||
assertf(hts_count_fits(1, -1) == HTS_FALSE);
|
|
||||||
printf("java constant-pool cap self-test OK\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* Registry: name -> handler, with a usage hint and a one-line description. */
|
/* Registry: name -> handler, with a usage hint and a one-line description. */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@@ -2461,6 +2881,8 @@ static const struct selftest_entry {
|
|||||||
"memoized vs unmemoized matcher differential", st_filtermemo},
|
"memoized vs unmemoized matcher differential", st_filtermemo},
|
||||||
{"filterdual", "<string1> <string2> <filter>...",
|
{"filterdual", "<string1> <string2> <filter>...",
|
||||||
"merged two-form filter verdict (fa_strjoker_dual)", st_filterdual},
|
"merged two-form filter verdict (fa_strjoker_dual)", st_filterdual},
|
||||||
|
{"filterbounds", "", "matcher length/work caps reject hostile patterns",
|
||||||
|
st_filterbounds},
|
||||||
{"simplify", "<path>", "collapse ./ and ../ in a path", st_simplify},
|
{"simplify", "<path>", "collapse ./ and ../ in a path", st_simplify},
|
||||||
{"stripquery", "", "--strip-query pattern/key stripping self-test",
|
{"stripquery", "", "--strip-query pattern/key stripping self-test",
|
||||||
st_stripquery},
|
st_stripquery},
|
||||||
@@ -2491,11 +2913,21 @@ static const struct selftest_entry {
|
|||||||
{"resolve", "<link> <adr> <fil>", "resolve a link against an origin",
|
{"resolve", "<link> <adr> <fil>", "resolve a link against an origin",
|
||||||
st_resolve},
|
st_resolve},
|
||||||
{"identurl", "<url>", "split an absolute URL into (adr, fil)", st_identurl},
|
{"identurl", "<url>", "split an absolute URL into (adr, fil)", st_identurl},
|
||||||
|
{"proxyurl", "<proxy-arg>", "parse a -P proxy URL into host/port",
|
||||||
|
st_proxyurl},
|
||||||
|
{"socks5", "", "SOCKS5 handshake framing and credential self-test",
|
||||||
|
st_socks5},
|
||||||
|
{"identabs", "", "ident_url_absolute one-byte fil[] overflow self-test",
|
||||||
|
st_identabs},
|
||||||
{"header", "<raw-header-line> ...", "response header-line parsing",
|
{"header", "<raw-header-line> ...", "response header-line parsing",
|
||||||
st_header},
|
st_header},
|
||||||
{"headerlong", "[header-name:]",
|
{"headerlong", "[header-name:]",
|
||||||
"over-long header value must not overflow the parse scratch",
|
"over-long header value must not overflow the parse scratch",
|
||||||
st_headerlong},
|
st_headerlong},
|
||||||
|
{"crange", "<raw-content-range-line> ...",
|
||||||
|
"Content-Range parse integer safety", st_crange},
|
||||||
|
{"xfread-limit", "", "in-memory receive buffer size bound",
|
||||||
|
st_xfread_limit},
|
||||||
{"savename", "<fil> <content-type> [key=value ...]",
|
{"savename", "<fil> <content-type> [key=value ...]",
|
||||||
"local save-name for a URL", st_savename},
|
"local save-name for a URL", st_savename},
|
||||||
{"sniff", "<content-type> <hex:..|text>", "MIME magic consistency",
|
{"sniff", "<content-type> <hex:..|text>", "MIME magic consistency",
|
||||||
@@ -2525,6 +2957,9 @@ static const struct selftest_entry {
|
|||||||
{"status", "", "HTTP status code -> reason phrase self-test", st_status},
|
{"status", "", "HTTP status code -> reason phrase self-test", st_status},
|
||||||
{"acceptencoding", "[dir]",
|
{"acceptencoding", "[dir]",
|
||||||
"Accept-Encoding advertises gzip+deflate, both decode", st_acceptencoding},
|
"Accept-Encoding advertises gzip+deflate, both decode", st_acceptencoding},
|
||||||
|
{"contentcodings", "[dir]",
|
||||||
|
"brotli and zstd bodies decode; bombs and unknown codings are refused",
|
||||||
|
st_contentcodings},
|
||||||
{"robots", "", "robots.txt RFC 9309 Allow/Disallow precedence self-test",
|
{"robots", "", "robots.txt RFC 9309 Allow/Disallow precedence self-test",
|
||||||
st_robots},
|
st_robots},
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@@ -2532,7 +2967,6 @@ static const struct selftest_entry {
|
|||||||
st_ftpline},
|
st_ftpline},
|
||||||
#endif
|
#endif
|
||||||
{"ftp-userpass", "", "ftp_split_userpass bounds URL userinfo", st_ftpuser},
|
{"ftp-userpass", "", "ftp_split_userpass bounds URL userinfo", st_ftpuser},
|
||||||
{"java", "", "java .class constant-pool count cap self-test", st_java},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void list_selftests(void) {
|
static void list_selftests(void) {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ Please visit our Website: http://www.httrack.com
|
|||||||
/* specific definitions */
|
/* specific definitions */
|
||||||
#include "htsbase.h"
|
#include "htsbase.h"
|
||||||
#include "htscore.h"
|
#include "htscore.h"
|
||||||
|
#include "htscodec.h"
|
||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
|
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
@@ -46,13 +47,8 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
Unpack file into a new file (gzip, zlib RFC1950 or raw deflate RFC1951).
|
|
||||||
A body provably in no deflate framing is copied verbatim (identity).
|
|
||||||
Return value: size of the new file, or -1 if an error occurred
|
|
||||||
*/
|
|
||||||
/* Note: utf-8 */
|
/* Note: utf-8 */
|
||||||
int hts_zunpack(char *filename, char *newfile) {
|
int hts_zunpack(const char *filename, const char *newfile) {
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (filename != NULL && newfile != NULL && filename[0] && newfile[0]) {
|
if (filename != NULL && newfile != NULL && filename[0] && newfile[0]) {
|
||||||
@@ -61,6 +57,7 @@ int hts_zunpack(char *filename, char *newfile) {
|
|||||||
|
|
||||||
if (in != NULL) {
|
if (in != NULL) {
|
||||||
unsigned char BIGSTK inbuf[8192];
|
unsigned char BIGSTK inbuf[8192];
|
||||||
|
const LLint maxout = hts_codec_maxout(hts_codec_coded_size(in));
|
||||||
size_t navail = fread(inbuf, 1, sizeof(inbuf), in);
|
size_t navail = fread(inbuf, 1, sizeof(inbuf), in);
|
||||||
/* gzip/zlib headers -> +32 windowBits; else raw deflate (RFC1951) */
|
/* gzip/zlib headers -> +32 windowBits; else raw deflate (RFC1951) */
|
||||||
const hts_boolean wrapped =
|
const hts_boolean wrapped =
|
||||||
@@ -73,9 +70,10 @@ int hts_zunpack(char *filename, char *newfile) {
|
|||||||
deflate framing at all. env_error: local I/O or memory failure. */
|
deflate framing at all. env_error: local I/O or memory failure. */
|
||||||
hts_boolean not_deflate = HTS_FALSE;
|
hts_boolean not_deflate = HTS_FALSE;
|
||||||
hts_boolean env_error = HTS_FALSE;
|
hts_boolean env_error = HTS_FALSE;
|
||||||
|
hts_boolean bomb = HTS_FALSE;
|
||||||
|
|
||||||
/* deflate is ambiguous; on failure retry with the other windowBits */
|
/* deflate is ambiguous; on failure retry with the other windowBits */
|
||||||
for (attempt = 0; attempt < 2 && ret < 0; attempt++) {
|
for (attempt = 0; attempt < 2 && ret < 0 && !bomb; attempt++) {
|
||||||
const int windowBits =
|
const int windowBits =
|
||||||
(attempt == 0 ? wrapped : !wrapped) ? (32 + MAX_WBITS) : -MAX_WBITS;
|
(attempt == 0 ? wrapped : !wrapped) ? (32 + MAX_WBITS) : -MAX_WBITS;
|
||||||
FILE *fpout;
|
FILE *fpout;
|
||||||
@@ -102,7 +100,7 @@ int hts_zunpack(char *filename, char *newfile) {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
hts_boolean ok = HTS_TRUE;
|
hts_boolean ok = HTS_TRUE;
|
||||||
int size = 0;
|
LLint size = 0;
|
||||||
int zerr = Z_OK;
|
int zerr = Z_OK;
|
||||||
|
|
||||||
/* chunked inflate; first chunk in inbuf, single member */
|
/* chunked inflate; first chunk in inbuf, single member */
|
||||||
@@ -126,27 +124,33 @@ int hts_zunpack(char *filename, char *newfile) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
produced = sizeof(outbuf) - strm.avail_out;
|
produced = sizeof(outbuf) - strm.avail_out;
|
||||||
|
size += (LLint) produced;
|
||||||
|
if (size > maxout) { /* decompression bomb: no retry, no copy */
|
||||||
|
bomb = HTS_TRUE;
|
||||||
|
ok = HTS_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (produced > 0 &&
|
if (produced > 0 &&
|
||||||
fwrite(outbuf, 1, produced, fpout) != produced) {
|
fwrite(outbuf, 1, produced, fpout) != produced) {
|
||||||
env_error = HTS_TRUE;
|
env_error = HTS_TRUE;
|
||||||
ok = HTS_FALSE;
|
ok = HTS_FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
size += (int) produced;
|
|
||||||
} while (strm.avail_out == 0);
|
} while (strm.avail_out == 0);
|
||||||
if (!ok || zerr == Z_STREAM_END)
|
if (!ok || zerr == Z_STREAM_END)
|
||||||
break;
|
break;
|
||||||
navail = fread(inbuf, 1, sizeof(inbuf), in);
|
navail = fread(inbuf, 1, sizeof(inbuf), in);
|
||||||
} while (navail > 0);
|
} while (navail > 0);
|
||||||
if (ok && zerr == Z_STREAM_END)
|
if (ok && zerr == Z_STREAM_END)
|
||||||
ret = size;
|
ret = (int) size;
|
||||||
}
|
}
|
||||||
inflateEnd(&strm);
|
inflateEnd(&strm);
|
||||||
fclose(fpout);
|
fclose(fpout);
|
||||||
}
|
}
|
||||||
/* keep a mislabeled identity body verbatim only when provably not
|
/* keep a mislabeled identity body verbatim only when provably not
|
||||||
deflate; truncation or a local failure must keep failing (#47) */
|
deflate; truncation or a local failure must keep failing (#47) */
|
||||||
if (ret < 0 && !wrapped && not_deflate && !env_error && !ferror(in)) {
|
if (ret < 0 && !bomb && !wrapped && not_deflate && !env_error &&
|
||||||
|
!ferror(in)) {
|
||||||
FILE *const fpout =
|
FILE *const fpout =
|
||||||
FOPEN(fconv(catbuff, sizeof(catbuff), newfile), "wb");
|
FOPEN(fconv(catbuff, sizeof(catbuff), newfile), "wb");
|
||||||
|
|
||||||
@@ -172,6 +176,25 @@ int hts_zunpack(char *filename, char *newfile) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t hts_zhead(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;
|
||||||
|
}
|
||||||
|
|
||||||
int hts_extract_meta(const char *path) {
|
int hts_extract_meta(const char *path) {
|
||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
unzFile zFile = unzOpen(fconcat(catbuff, sizeof(catbuff), path, "hts-cache/new.zip"));
|
unzFile zFile = unzOpen(fconcat(catbuff, sizeof(catbuff), path, "hts-cache/new.zip"));
|
||||||
|
|||||||
@@ -44,7 +44,13 @@ Please visit our Website: http://www.httrack.com
|
|||||||
|
|
||||||
/* Library internal definictions */
|
/* Library internal definictions */
|
||||||
#ifdef HTS_INTERNAL_BYTECODE
|
#ifdef HTS_INTERNAL_BYTECODE
|
||||||
extern int hts_zunpack(char *filename, char *newfile);
|
/* Inflate filename into newfile (gzip, zlib or raw deflate); decoded size, or
|
||||||
|
-1 on a corrupt/truncated stream, an over-budget body, or an I/O failure. A
|
||||||
|
body provably in no deflate framing is copied verbatim. */
|
||||||
|
extern int hts_zunpack(const char *filename, const char *newfile);
|
||||||
|
/* Inflate the head of a gzip/zlib stream, out_len max; 0 if undecodable */
|
||||||
|
extern size_t hts_zhead(const void *in, size_t in_len, void *out,
|
||||||
|
size_t out_len);
|
||||||
extern int hts_extract_meta(const char *path);
|
extern int hts_extract_meta(const char *path);
|
||||||
extern const char *hts_get_zerror(int err);
|
extern const char *hts_get_zerror(int err);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -919,9 +919,6 @@ static void signal_handlers(void) {
|
|||||||
#ifdef SIGSEGV
|
#ifdef SIGSEGV
|
||||||
signal(SIGSEGV, sig_fatal); // segmentation violation
|
signal(SIGSEGV, sig_fatal); // segmentation violation
|
||||||
#endif
|
#endif
|
||||||
#ifdef SIGSTKFLT
|
|
||||||
signal(SIGSTKFLT, sig_fatal); // stack fault
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fin routines de détournement de SIGHUP & co
|
// fin routines de détournement de SIGHUP & co
|
||||||
|
|||||||
127
src/httrack.dsp
127
src/httrack.dsp
@@ -1,127 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="httrack" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
|
||||||
|
|
||||||
CFG=httrack - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "httrack.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "httrack.mak" CFG="httrack - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "httrack - Win32 Release" (based on "Win32 (x86) Console Application")
|
|
||||||
!MESSAGE "httrack - Win32 Debug" (based on "Win32 (x86) Console Application")
|
|
||||||
!MESSAGE "httrack - Win32 Release avec debug" (based on "Win32 (x86) Console Application")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "httrack - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "c:\temp\vcpp"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MD /W3 /Gi /O2 /Op /Ob2 /I "C:\Dev\IPv6Kit\inc\\" /I "C:\Dev\zlib\\" /I "C:\Dev\openssl\include" /I "C:\Dev\Winhttrack" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HTS_ANALYSTE_CONSOLE" /YX /FD /Zm200 /c
|
|
||||||
# SUBTRACT CPP /Fr
|
|
||||||
# ADD BASE RSC /l 0x40c /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
|
||||||
# ADD LINK32 wsock32.lib libhttrack.lib /nologo /subsystem:console /machine:I386 /out:"L:\HTTrack\httrack\httrack.exe" /libpath:"C:\Dev\openssl\lib" /libpath:"C:\Dev\zlib\dll32" /libpath:"C:\Dev\openssl\lib\out32dll" /libpath:"C:\temp\Releaselib"
|
|
||||||
# SUBTRACT LINK32 /verbose
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "httrack - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "c:\temp\vcpp"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MDd /W3 /Gm /GR /ZI /Od /I "C:\Dev\IPv6Kit\inc\\" /I "C:\Dev\zlib\\" /I "C:\Dev\openssl\include" /I "C:\Dev\Winhttrack" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HTS_ANALYSTE_CONSOLE" /FAcs /Fr /FD /Zm200 /c
|
|
||||||
# ADD BASE RSC /l 0x40c /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 wsock32.lib libhttrack.lib /nologo /subsystem:console /debug /debugtype:both /machine:I386 /out:"C:\temp\httrack.exe" /pdbtype:sept /libpath:"C:\Dev\openssl\lib" /libpath:"C:\Dev\zlib\dll32" /libpath:"C:\Dev\openssl\lib\out32dll" /libpath:"C:\temp\Debuglib"
|
|
||||||
# SUBTRACT LINK32 /profile /map
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "httrack - Win32 Release avec debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "httrack___Win32_Release_avec_debug"
|
|
||||||
# PROP BASE Intermediate_Dir "httrack___Win32_Release_avec_debug"
|
|
||||||
# PROP BASE Ignore_Export_Lib 0
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release_avec_debug"
|
|
||||||
# PROP Intermediate_Dir "c:\temp\vcpp"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MT /W3 /GX /Ot /Oi /Oy /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
|
||||||
# SUBTRACT BASE CPP /Ox /Oa /Ow /Og /Os
|
|
||||||
# ADD CPP /nologo /MD /W3 /GX /Zi /Ot /Oi /Oy /Ob2 /I "C:\Dev\IPv6Kit\inc\\" /I "C:\Dev\zlib\\" /I "C:\Dev\openssl\include" /I "C:\Dev\Winhttrack" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HTS_ANALYSTE_CONSOLE" /FAcs /FR /YX /FD /Zm200 /c
|
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 wsock32.lib /nologo /subsystem:console /machine:I386 /out:"c:\temp\httrack.exe"
|
|
||||||
# SUBTRACT BASE LINK32 /verbose
|
|
||||||
# ADD LINK32 wsock32.lib libhttrack.lib /nologo /subsystem:console /debug /machine:I386 /out:"L:\HTTrack\httrack\httrack.exe" /libpath:"C:\Dev\openssl\lib" /libpath:"C:\Dev\zlib\dll32" /libpath:"C:\Dev\openssl\lib\out32dll"
|
|
||||||
# SUBTRACT LINK32 /verbose
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "httrack - Win32 Release"
|
|
||||||
# Name "httrack - Win32 Debug"
|
|
||||||
# Name "httrack - Win32 Release avec debug"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=httrack.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=httrack.h
|
|
||||||
# End Source File
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
|
||||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "httrack"=.\httrack.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name libhttrack
|
|
||||||
End Project Dependency
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "libhttrack"=.\libhttrack\libhttrack.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Global:
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<3>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
5
src/httrack.rc
Normal file
5
src/httrack.rc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// Version resource for httrack.exe, the command line program. See version.rc.
|
||||||
|
#define VER_FILE_DESCRIPTION "HTTrack Website Copier (command line)"
|
||||||
|
#define VER_ORIGINAL_FILENAME "httrack.exe"
|
||||||
|
#define VER_FILETYPE VFT_APP
|
||||||
|
#include "version.rc"
|
||||||
@@ -1,677 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="9,00"
|
|
||||||
Name="httrack"
|
|
||||||
ProjectGUID="{D0E894E7-F64C-4722-9807-9ABB1054D43A}"
|
|
||||||
RootNamespace="httrack"
|
|
||||||
TargetFrameworkVersion="131072"
|
|
||||||
>
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"
|
|
||||||
/>
|
|
||||||
<Platform
|
|
||||||
Name="x64"
|
|
||||||
/>
|
|
||||||
</Platforms>
|
|
||||||
<ToolFiles>
|
|
||||||
</ToolFiles>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Release avec debug|Win32"
|
|
||||||
OutputDirectory=".\Release_avec_debug"
|
|
||||||
IntermediateDirectory="c:\temp\vcpp"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TypeLibraryName=".\Release_avec_debug/httrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalOptions="/Zm200 "
|
|
||||||
Optimization="4"
|
|
||||||
InlineFunctionExpansion="2"
|
|
||||||
EnableIntrinsicFunctions="true"
|
|
||||||
FavorSizeOrSpeed="1"
|
|
||||||
OmitFramePointers="true"
|
|
||||||
AdditionalIncludeDirectories=""C:\Dev\zlib-1.2.8\";"C:\Dev\openssl-1.0.1j\include";coucal"
|
|
||||||
PreprocessorDefinitions="WIN32;_CONSOLE;HTS_ANALYSTE_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderFile="c:\temp\vcpp/httrack.pch"
|
|
||||||
AssemblerOutput="2"
|
|
||||||
AssemblerListingLocation="c:\temp\vcpp/"
|
|
||||||
ObjectFile="c:\temp\vcpp/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\vcpp/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\httrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib,C:\Dev\zlib\dll32,C:\Dev\openssl\lib\out32dll"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile=".\Release_avec_debug/httrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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="Release avec debug|x64"
|
|
||||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
TypeLibraryName=".\Release_avec_debug/httrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalOptions="/Zm200 "
|
|
||||||
Optimization="4"
|
|
||||||
InlineFunctionExpansion="2"
|
|
||||||
EnableIntrinsicFunctions="true"
|
|
||||||
FavorSizeOrSpeed="1"
|
|
||||||
OmitFramePointers="true"
|
|
||||||
AdditionalIncludeDirectories=""C:\Dev\zlib-1.2.8\";"C:\Dev\openssl-1.0.1j\include";coucal"
|
|
||||||
PreprocessorDefinitions="WIN32;_CONSOLE;HTS_ANALYSTE_CONSOLE"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderFile="c:\temp\vcpp/httrack.pch"
|
|
||||||
AssemblerOutput="2"
|
|
||||||
AssemblerListingLocation="c:\temp\vcpp/"
|
|
||||||
ObjectFile="c:\temp\vcpp/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\vcpp/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\httrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib,C:\Dev\zlib\dll32,C:\Dev\openssl\lib\out32dll"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile=".\Release_avec_debug/httrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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="Debug|Win32"
|
|
||||||
OutputDirectory="C:\temp\httrackcmd\Debug"
|
|
||||||
IntermediateDirectory="C:\temp\httrackcmd\Debug"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TypeLibraryName=".\Debug/httrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalOptions="/Zm200 "
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""C:\Dev\zlib-1.2.8\";"C:\Dev\openssl-1.0.1j\include";coucal"
|
|
||||||
PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;HTS_ANALYSTE_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
BufferSecurityCheck="true"
|
|
||||||
RuntimeTypeInfo="true"
|
|
||||||
PrecompiledHeaderFile="c:\temp\vcpp/httrack.pch"
|
|
||||||
AssemblerOutput="2"
|
|
||||||
AssemblerListingLocation="c:\temp\vcpp/"
|
|
||||||
ObjectFile="c:\temp\vcpp/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\vcpp/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
BrowseInformationFile="c:\temp\vcpp/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="4"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="C:\temp\httrack\httrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib;C:\temp\release_libz;C:\Dev\openssl\lib\out32dll;C:\temp\Debuglib"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile=".\Debug/httrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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="C:\temp\httrackcmd\Debug"
|
|
||||||
IntermediateDirectory="C:\temp\httrackcmd\Debug"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
TypeLibraryName=".\Debug/httrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalOptions="/Zm200 "
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""C:\Dev\zlib-1.2.8\";"C:\Dev\openssl-1.0.1j\include";coucal"
|
|
||||||
PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;HTS_ANALYSTE_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
BufferSecurityCheck="true"
|
|
||||||
RuntimeTypeInfo="true"
|
|
||||||
PrecompiledHeaderFile="c:\temp\vcpp/httrack.pch"
|
|
||||||
AssemblerOutput="2"
|
|
||||||
AssemblerListingLocation="c:\temp\vcpp/"
|
|
||||||
ObjectFile="c:\temp\vcpp/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\vcpp/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
BrowseInformationFile="c:\temp\vcpp/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="C:\temp\httrack64\httrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib,C:\temp\zlib,C:\Dev\openssl\lib\out32dll,C:\temp\Debuglib"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile=".\Debug/httrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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\httrackcmd\Release"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TypeLibraryName=".\Release/httrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalOptions="/Zm200 "
|
|
||||||
Optimization="3"
|
|
||||||
InlineFunctionExpansion="2"
|
|
||||||
AdditionalIncludeDirectories=""C:\Dev\zlib-1.2.8\";"C:\Dev\openssl-1.0.1j\include";coucal"
|
|
||||||
PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;HTS_ANALYSTE_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
StringPooling="true"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
EnableFunctionLevelLinking="true"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderFile="c:\temp\vcpp/httrack.pch"
|
|
||||||
AssemblerListingLocation="c:\temp\vcpp/"
|
|
||||||
ObjectFile="c:\temp\vcpp/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\vcpp/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\httrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib,C:\temp\zlib,C:\Dev\openssl\lib\out32dll,C:\temp\Releaselib"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\httrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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="Release|x64"
|
|
||||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
TypeLibraryName=".\Release/httrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalOptions="/Zm200 "
|
|
||||||
Optimization="3"
|
|
||||||
InlineFunctionExpansion="2"
|
|
||||||
AdditionalIncludeDirectories=""C:\Dev\zlib-1.2.8\";"C:\Dev\openssl-1.0.1j\include";coucal"
|
|
||||||
PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;HTS_ANALYSTE_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
StringPooling="true"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
EnableFunctionLevelLinking="true"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderFile="c:\temp\vcpp/httrack.pch"
|
|
||||||
AssemblerListingLocation="c:\temp\vcpp64/"
|
|
||||||
ObjectFile="c:\temp\vcpp64/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\vcpp64/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\x64\httrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib,C:\temp\zlib,C:\Dev\openssl\lib\out32dll,C:\temp\Releaselib"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\x64\httrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
TargetMachine="17"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<File
|
|
||||||
RelativePath="httrack.c"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release avec debug|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BrowseInformation="1"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release avec debug|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BrowseInformation="1"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BrowseInformation="1"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BrowseInformation="1"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\httrack.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
116
src/httrack.vcxproj
Normal file
116
src/httrack.vcxproj
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{2F9E0E4C-2B5B-4B2E-9F6D-1C0A5E7B3D01}</ProjectGuid>
|
||||||
|
<RootNamespace>httrack</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)'==''">10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- No direct vcpkg dependency, but the triplet drives applocal deployment:
|
||||||
|
without it the OpenSSL and zlib DLLs libhttrack needs never land beside
|
||||||
|
httrack.exe. -->
|
||||||
|
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows</VcpkgTriplet>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows</VcpkgTriplet>
|
||||||
|
<OutDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\obj\httrack\</IntDir>
|
||||||
|
<TargetName>httrack</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<!-- No LIBHTTRACK_EXPORTS: HTSEXT_API is dllimport on this side. -->
|
||||||
|
<PreprocessorDefinitions>WIN32;_CONSOLE;_MBCS;WINVER=0x0601;_WIN32_WINNT=0x0601;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);$(MSBuildThisFileDirectory)coucal;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<!-- main() calls WSAStartup/WSACleanup itself. -->
|
||||||
|
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="httrack.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Pulls in libhttrack.lib and builds it first. -->
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="libhttrack.vcxproj">
|
||||||
|
<Project>{e76ad871-54c1-45e8-a657-6117adeffb46}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="httrack.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
</Project>
|
||||||
@@ -1,406 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="libhttrack" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
|
||||||
|
|
||||||
CFG=libhttrack - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "libhttrack.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "libhttrack.mak" CFG="libhttrack - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "libhttrack - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE "libhttrack - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
MTL=midl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "libhttrack - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "C:\temp\Releaselib"
|
|
||||||
# PROP Intermediate_Dir "C:\temp\Releaselib"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBHTTRACK_EXPORTS" /Yu"stdafx.h" /FD /c
|
|
||||||
# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "C:\Dev\IPv6Kit\inc" /I "C:\Dev\zlib\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBHTTRACK_EXPORTS" /D "ZLIB_DLL" /FD /c
|
|
||||||
# SUBTRACT CPP /YX /Yc /Yu
|
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x40c /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x40c /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
|
||||||
# ADD LINK32 wsock32.lib zdll.lib /nologo /dll /map /machine:I386 /out:"L:\HTTrack\httrack\libhttrack.dll" /libpath:"C:\Dev\zlib\lib"
|
|
||||||
# SUBTRACT LINK32 /pdb:none
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "libhttrack - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "C:\temp\Debuglib"
|
|
||||||
# PROP Intermediate_Dir "C:\temp\Debuglib"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBHTTRACK_EXPORTS" /Yu"stdafx.h" /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "C:\Dev\IPv6Kit\inc" /I "C:\Dev\zlib\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBHTTRACK_EXPORTS" /D "ZLIB_DLL" /FD /GZ /c
|
|
||||||
# SUBTRACT CPP /YX /Yc /Yu
|
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x40c /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x40c /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 wsock32.lib zdll.lib /nologo /dll /map /debug /machine:I386 /out:"C:\temp\libhttrack.dll" /pdbtype:sept /libpath:"C:\Dev\zlib\lib"
|
|
||||||
# SUBTRACT LINK32 /pdb:none
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "libhttrack - Win32 Release"
|
|
||||||
# Name "libhttrack - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\crypt.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE="hts-indextmpl.h"
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsalias.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsalias.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsback.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsback.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsbase.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsbasenet.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsbauth.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsbauth.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscache.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscache.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscatchurl.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscatchurl.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsconfig.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscore.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscore.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscoremain.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htscoremain.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsdefines.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsfilters.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsfilters.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsftp.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsftp.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsglobal.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htshash.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htshash.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htshelp.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htshelp.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsindex.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsindex.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsinthash.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsjava.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsjava.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htslib.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htslib.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsmd5.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsmd5.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsmodules.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsmodules.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsname.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsname.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsnet.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsnostatic.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsnostatic.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsopt.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsparse.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsparse.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsrobots.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsrobots.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsstrings.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htssystem.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsthread.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htsthread.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htstools.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htstools.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htswizard.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htswizard.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htswrap.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htswrap.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htszlib.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=htszlib.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\ioapi.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\ioapi.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\iowin32.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\iowin32.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=md5.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=md5.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\mztools.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\mztools.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\unzip.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\unzip.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\zip.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=minizip\zip.h
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\ReadMe.txt
|
|
||||||
# End Source File
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
|
||||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "libhttrack"=.\libhttrack.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Global:
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<3>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
5
src/libhttrack.rc
Normal file
5
src/libhttrack.rc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// Version resource for libhttrack.dll. See version.rc.
|
||||||
|
#define VER_FILE_DESCRIPTION "HTTrack Website Copier engine"
|
||||||
|
#define VER_ORIGINAL_FILENAME "libhttrack.dll"
|
||||||
|
#define VER_FILETYPE VFT_DLL
|
||||||
|
#include "version.rc"
|
||||||
File diff suppressed because it is too large
Load Diff
150
src/libhttrack.vcxproj
Normal file
150
src/libhttrack.vcxproj
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{E76AD871-54C1-45E8-A657-6117ADEFFB46}</ProjectGuid>
|
||||||
|
<RootNamespace>libhttrack</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)'==''">10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
|
||||||
|
<!-- OpenSSL 3.x and zlib come from vcpkg. Dynamic triplets: the DLLs ship with
|
||||||
|
the app, so an OpenSSL CVE is a DLL swap rather than a rebuild. -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows</VcpkgTriplet>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows</VcpkgTriplet>
|
||||||
|
<!-- WinHTTrack links ..\httrack\src\$(Platform)\$(Configuration)\libhttrack.lib -->
|
||||||
|
<OutDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\obj\</IntDir>
|
||||||
|
<TargetName>libhttrack</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<!-- LIBHTTRACK_EXPORTS turns HTSEXT_API into __declspec(dllexport); ZLIB_DLL
|
||||||
|
imports zlib from its DLL. HTS_USEBROTLI/HTS_USEZSTD enable the br and
|
||||||
|
zstd content codings. Windows 7 floor, matching WinHTTrack. -->
|
||||||
|
<PreprocessorDefinitions>WIN32;_WINDOWS;_MBCS;_USRDLL;LIBHTTRACK_EXPORTS;ZLIB_DLL;HTS_USEBROTLI=1;HTS_USEZSTD=1;WINVER=0x0601;_WIN32_WINNT=0x0601;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);$(MSBuildThisFileDirectory)coucal;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<!-- vcpkg auto-links libssl/libcrypto/zlib/brotli/zstd; only the OS import
|
||||||
|
lib is explicit. -->
|
||||||
|
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="coucal\coucal.c" />
|
||||||
|
<ClCompile Include="htsalias.c" />
|
||||||
|
<ClCompile Include="htsback.c" />
|
||||||
|
<ClCompile Include="htsbauth.c" />
|
||||||
|
<ClCompile Include="htscache.c" />
|
||||||
|
<ClCompile Include="htscache_selftest.c" />
|
||||||
|
<ClCompile Include="htscatchurl.c" />
|
||||||
|
<ClCompile Include="htscharset.c" />
|
||||||
|
<ClCompile Include="htscodec.c" />
|
||||||
|
<ClCompile Include="htsconcat.c" />
|
||||||
|
<ClCompile Include="htscore.c" />
|
||||||
|
<ClCompile Include="htscoremain.c" />
|
||||||
|
<ClCompile Include="htsdns_selftest.c" />
|
||||||
|
<ClCompile Include="htsencoding.c" />
|
||||||
|
<ClCompile Include="htsfilters.c" />
|
||||||
|
<ClCompile Include="htsftp.c" />
|
||||||
|
<ClCompile Include="htshash.c" />
|
||||||
|
<ClCompile Include="htshelp.c" />
|
||||||
|
<ClCompile Include="htsindex.c" />
|
||||||
|
<ClCompile Include="htslib.c" />
|
||||||
|
<ClCompile Include="htsmd5.c" />
|
||||||
|
<ClCompile Include="htsmodules.c" />
|
||||||
|
<ClCompile Include="htsname.c" />
|
||||||
|
<ClCompile Include="htsparse.c" />
|
||||||
|
<ClCompile Include="htsproxy.c" />
|
||||||
|
<ClCompile Include="htsrobots.c" />
|
||||||
|
<ClCompile Include="htsselftest.c" />
|
||||||
|
<ClCompile Include="htssniff.c" />
|
||||||
|
<ClCompile Include="htsthread.c" />
|
||||||
|
<ClCompile Include="htstools.c" />
|
||||||
|
<ClCompile Include="htswizard.c" />
|
||||||
|
<ClCompile Include="htswrap.c" />
|
||||||
|
<ClCompile Include="htszlib.c" />
|
||||||
|
<ClCompile Include="md5.c" />
|
||||||
|
<ClCompile Include="minizip\ioapi.c" />
|
||||||
|
<ClCompile Include="minizip\iowin32.c" />
|
||||||
|
<ClCompile Include="minizip\mztools.c" />
|
||||||
|
<ClCompile Include="minizip\unzip.c" />
|
||||||
|
<ClCompile Include="minizip\zip.c" />
|
||||||
|
<ClCompile Include="punycode.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="libhttrack.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
</Project>
|
||||||
@@ -1,438 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="9,00"
|
|
||||||
Name="proxytrack"
|
|
||||||
ProjectGUID="{4C31F79A-9DAB-44CE-88D6-0FF961599AAB}"
|
|
||||||
RootNamespace="proxytrack"
|
|
||||||
Keyword="Win32Proj"
|
|
||||||
TargetFrameworkVersion="131072"
|
|
||||||
>
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"
|
|
||||||
/>
|
|
||||||
<Platform
|
|
||||||
Name="x64"
|
|
||||||
/>
|
|
||||||
</Platforms>
|
|
||||||
<ToolFiles>
|
|
||||||
</ToolFiles>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory="C:\temp\proxytrack\Debug"
|
|
||||||
IntermediateDirectory="C:\temp\proxytrack\Debug\int"
|
|
||||||
ConfigurationType="1"
|
|
||||||
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\httrack\src;"C:\Dev\zlib-1.2.8";C:\Dev\minizip;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="NO_MALLOCT;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
MinimalRebuild="true"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
BufferSecurityCheck="true"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="4"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib zlib1.lib"
|
|
||||||
OutputFile="c:\temp\httrack\proxytrack.exe"
|
|
||||||
LinkIncremental="2"
|
|
||||||
AdditionalLibraryDirectories="C:\temp\debug_libz"
|
|
||||||
IgnoreAllDefaultLibraries="false"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(OutDir)/proxytrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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="1"
|
|
||||||
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\httrack\src;"C:\Dev\zlib-1.2.8";C:\Dev\minizip;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="NO_MALLOCT;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
MinimalRebuild="true"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
BufferSecurityCheck="true"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib zlib1.lib"
|
|
||||||
OutputFile="c:\temp\httrack64\proxytrack.exe"
|
|
||||||
LinkIncremental="2"
|
|
||||||
AdditionalLibraryDirectories="C:\temp\debug_libz64"
|
|
||||||
IgnoreAllDefaultLibraries="false"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(OutDir)/proxytrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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\proxytrack\Release"
|
|
||||||
IntermediateDirectory="C:\temp\proxytrack\Release\int"
|
|
||||||
ConfigurationType="1"
|
|
||||||
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\httrack\src;"C:\Dev\zlib-1.2.8";C:\Dev\minizip;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="NO_MALLOCT;_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"
|
|
||||||
AdditionalDependencies="Ws2_32.lib zlib1.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\proxytrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories="C:\temp\release_libz;C:\temp\Releaselib"
|
|
||||||
IgnoreAllDefaultLibraries="false"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\proxytrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
OptimizeForWindows98="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
TargetMachine="1"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
Description="Copying proxytrack to separate package"
|
|
||||||
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)
copy /Y "O:\HTTrack\httrack\proxytrack.exe" "O:\ProxyTrack\proxytrack\proxytrack.exe"
copy /Y "C:\Dev\httrack\src\proxy\*.c" "O:\ProxyTrack\proxytrack\src\"
copy /Y "C:\Dev\httrack\src\proxy\*.h" "O:\ProxyTrack\proxytrack\src\"
copy /Y "C:\Dev\httrack\src\proxy\*.vcproj" "O:\ProxyTrack\proxytrack\src\"
copy /Y "C:\Dev\httrack\src\proxy\*.txt" "O:\ProxyTrack\proxytrack\src\"
"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|x64"
|
|
||||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="1"
|
|
||||||
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\httrack\src;"C:\Dev\zlib-1.2.8";C:\Dev\minizip;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="NO_MALLOCT;_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"
|
|
||||||
AdditionalDependencies="Ws2_32.lib zlib1.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\x64\proxytrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories="C:\temp\release_libz64;C:\temp\Releaselib64"
|
|
||||||
IgnoreAllDefaultLibraries="false"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\x64\proxytrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
TargetMachine="17"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
Description="Copying proxytrack to separate package"
|
|
||||||
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)
copy /Y "O:\HTTrack\httrack\proxytrack.exe" "O:\ProxyTrack\proxytrack\proxytrack.exe"
copy /Y "C:\Dev\httrack\src\proxy\*.c" "O:\ProxyTrack\proxytrack\src\"
copy /Y "C:\Dev\httrack\src\proxy\*.h" "O:\ProxyTrack\proxytrack\src\"
copy /Y "C:\Dev\httrack\src\proxy\*.vcproj" "O:\ProxyTrack\proxytrack\src\"
copy /Y "C:\Dev\httrack\src\proxy\*.txt" "O:\ProxyTrack\proxytrack\src\"
"
|
|
||||||
/>
|
|
||||||
</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="..\coucal\coucal.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\htsmd5.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\minizip\ioapi.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\minizip\iowin32.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="main.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\md5.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\minizip\mztools.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="proxytrack.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="store.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\minizip\unzip.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\minizip\zip.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Header Files"
|
|
||||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
|
||||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="proxystrings.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="proxytrack.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="store.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}"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\changelog.txt"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
@@ -1938,6 +1938,9 @@ static time_t getGMT(struct tm *tm) { /* hey, time_t is local! */
|
|||||||
#if (defined(BSD) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD_kernel__))
|
#if (defined(BSD) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD_kernel__))
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
time_t timezone = -localtime(&now)->tm_gmtoff;
|
time_t timezone = -localtime(&now)->tm_gmtoff;
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
/* MSVC spells it _timezone */
|
||||||
|
const time_t timezone = _timezone;
|
||||||
#endif
|
#endif
|
||||||
return (time_t) (t - timezone);
|
return (time_t) (t - timezone);
|
||||||
}
|
}
|
||||||
|
|||||||
113
src/proxytrack.vcxproj
Normal file
113
src/proxytrack.vcxproj
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{2F9E0E4C-2B5B-4B2E-9F6D-1C0A5E7B3D03}</ProjectGuid>
|
||||||
|
<RootNamespace>proxytrack</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)'==''">10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows</VcpkgTriplet>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows</VcpkgTriplet>
|
||||||
|
<OutDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\obj\proxytrack\</IntDir>
|
||||||
|
<TargetName>proxytrack</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<!-- Matches proxytrack_CFLAGS in Makefile.am. Standalone: it does not link
|
||||||
|
libhttrack, it only borrows headers (hts_effective_mime is a macro). -->
|
||||||
|
<PreprocessorDefinitions>WIN32;_CONSOLE;_MBCS;NO_MALLOCT;ZLIB_CONST;HTS_INTHASH_USES_MD5;ZLIB_DLL;WINVER=0x0601;_WIN32_WINNT=0x0601;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);$(MSBuildThisFileDirectory)coucal;$(MSBuildThisFileDirectory)proxy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="proxy\main.c" />
|
||||||
|
<ClCompile Include="proxy\proxytrack.c" />
|
||||||
|
<ClCompile Include="proxy\store.c" />
|
||||||
|
<ClCompile Include="coucal\coucal.c" />
|
||||||
|
<ClCompile Include="htsmd5.c" />
|
||||||
|
<ClCompile Include="md5.c" />
|
||||||
|
<ClCompile Include="minizip\ioapi.c" />
|
||||||
|
<ClCompile Include="minizip\iowin32.c" />
|
||||||
|
<ClCompile Include="minizip\mztools.c" />
|
||||||
|
<ClCompile Include="minizip\unzip.c" />
|
||||||
|
<ClCompile Include="minizip\zip.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
</Project>
|
||||||
12
src/vcpkg.json
Normal file
12
src/vcpkg.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"$schema":
|
||||||
|
"https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
|
||||||
|
"name": "libhttrack",
|
||||||
|
"version-string": "3.49",
|
||||||
|
"dependencies": [
|
||||||
|
"brotli",
|
||||||
|
"openssl",
|
||||||
|
"zlib",
|
||||||
|
"zstd"
|
||||||
|
]
|
||||||
|
}
|
||||||
50
src/version.rc
Normal file
50
src/version.rc
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Version resource for libhttrack.dll and httrack.exe. Signing enforces that every
|
||||||
|
// binary in a release names the same product and version, so both need one.
|
||||||
|
// Spelled out here because a VERSIONINFO cannot take a version string apart;
|
||||||
|
// tests/01_engine-version-macros.test fails if this drifts from htsglobal.h.
|
||||||
|
// The per-binary parts come from libhttrack.rc / httrack.rc.
|
||||||
|
|
||||||
|
#include <winver.h>
|
||||||
|
|
||||||
|
#ifndef VER_FILE_DESCRIPTION
|
||||||
|
#define VER_FILE_DESCRIPTION "HTTrack Website Copier"
|
||||||
|
#endif
|
||||||
|
#ifndef VER_ORIGINAL_FILENAME
|
||||||
|
#define VER_ORIGINAL_FILENAME ""
|
||||||
|
#endif
|
||||||
|
#ifndef VER_FILETYPE
|
||||||
|
#define VER_FILETYPE VFT_APP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 3, 49, 12, 0
|
||||||
|
PRODUCTVERSION 3, 49, 12, 0
|
||||||
|
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS VS_FF_DEBUG
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS VOS_NT_WINDOWS32
|
||||||
|
FILETYPE VER_FILETYPE
|
||||||
|
FILESUBTYPE VFT2_UNKNOWN
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0" // U.S. English, Unicode
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "Xavier Roche"
|
||||||
|
VALUE "FileDescription", VER_FILE_DESCRIPTION
|
||||||
|
VALUE "FileVersion", "3.49.12"
|
||||||
|
VALUE "InternalName", VER_ORIGINAL_FILENAME
|
||||||
|
VALUE "LegalCopyright", "Copyright (C) 1998-2026 Xavier Roche and other contributors. GNU GPL v3 or later."
|
||||||
|
VALUE "OriginalFilename", VER_ORIGINAL_FILENAME
|
||||||
|
VALUE "ProductName", "HTTrack Website Copier"
|
||||||
|
VALUE "ProductVersion", "3.49-12"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
@@ -12,10 +12,9 @@ if test -n "${BROWSER}"; then
|
|||||||
fi
|
fi
|
||||||
# Patch for Darwin/Mac by Ross Williams
|
# Patch for Darwin/Mac by Ross Williams
|
||||||
if test "$(uname -s)" == "Darwin"; then
|
if test "$(uname -s)" == "Darwin"; then
|
||||||
# Darwin/Mac OS X uses a system 'open' command to find
|
# Darwin's 'open -W' launches the default browser and waits for it to quit.
|
||||||
# the default browser. The -W flag causes it to wait for
|
# Keep it only as a fallback so a configured $BROWSER still wins the search.
|
||||||
# the browser to exit
|
BROWSEREXEFALLBACK="/usr/bin/open -W"
|
||||||
BROWSEREXE="/usr/bin/open -W"
|
|
||||||
fi
|
fi
|
||||||
BINWD=$(dirname "$0")
|
BINWD=$(dirname "$0")
|
||||||
SRCHPATH=("$BINWD" /usr/local/bin /usr/share/bin /usr/bin /usr/lib/httrack /usr/local/lib/httrack /usr/local/share/httrack /opt/local/bin /sw/bin "${HOME}/usr/bin" "${HOME}/bin")
|
SRCHPATH=("$BINWD" /usr/local/bin /usr/share/bin /usr/bin /usr/lib/httrack /usr/local/lib/httrack /usr/local/share/httrack /opt/local/bin /sw/bin "${HOME}/usr/bin" "${HOME}/bin")
|
||||||
@@ -81,6 +80,7 @@ for i in "${SRCHBROWSEREXE[@]}"; do
|
|||||||
done
|
done
|
||||||
test -n "$BROWSEREXE" && break
|
test -n "$BROWSEREXE" && break
|
||||||
done
|
done
|
||||||
|
test -n "$BROWSEREXE" || BROWSEREXE="${BROWSEREXEFALLBACK}"
|
||||||
test -n "$BROWSEREXE" || ! log "Could not find any suitable browser" || exit 1
|
test -n "$BROWSEREXE" || ! log "Could not find any suitable browser" || exit 1
|
||||||
|
|
||||||
# "browse" command
|
# "browse" command
|
||||||
@@ -132,12 +132,12 @@ function cleanup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Cleanup in case of emergency
|
# Cleanup in case of emergency
|
||||||
trap "cleanup now; exit" HUP INT QUIT ILL TRAP ABRT BUS FPE SEGV PIPE ALRM TERM STKFLT XCPU XFSZ
|
trap "cleanup now; exit" HUP INT QUIT PIPE TERM
|
||||||
|
|
||||||
# Got SRVURL, launch browser
|
# Got SRVURL, launch browser
|
||||||
launch_browser "${BROWSEREXE}" "${SRVURL}"
|
launch_browser "${BROWSEREXE}" "${SRVURL}"
|
||||||
|
|
||||||
# That's all, folks!
|
# That's all, folks!
|
||||||
trap "" HUP INT QUIT ILL TRAP ABRT BUS FPE SEGV PIPE ALRM TERM STKFLT XCPU XFSZ
|
trap "" HUP INT QUIT PIPE TERM
|
||||||
cleanup
|
cleanup
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="webhttrack" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
|
||||||
|
|
||||||
CFG=webhttrack - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "webhttrack.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "webhttrack.mak" CFG="webhttrack - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "webhttrack - Win32 Release" (based on "Win32 (x86) Console Application")
|
|
||||||
!MESSAGE "webhttrack - Win32 Debug" (based on "Win32 (x86) Console Application")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "webhttrack - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
|
|
||||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "C:\Dev\\" /I "C:\Dev\IPv6Kit\inc\\" /I "C:\Dev\zlib\\" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c
|
|
||||||
# SUBTRACT CPP /YX /Yc /Yu
|
|
||||||
# ADD BASE RSC /l 0x40c /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x40c /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
|
||||||
# ADD LINK32 wsock32.lib libhttrack.lib /nologo /subsystem:console /pdb:none /machine:I386 /force /out:"L:\HTTrack\httrack\webhttrack.exe" /libpath:"C:\Dev\openssl\lib" /libpath:"C:\Dev\zlib\dll32" /libpath:"C:\Dev\openssl\lib\out32dll" /libpath:"C:\temp\Releaselib"
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "webhttrack - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "C:\Dev\\" /I "C:\Dev\IPv6Kit\inc\\" /I "C:\Dev\zlib\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FAcs /FR /FD /GZ /c
|
|
||||||
# SUBTRACT CPP /YX /Yc /Yu
|
|
||||||
# ADD BASE RSC /l 0x40c /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x40c /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 wsock32.lib libhttrack.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\temp\webhttrack.exe" /pdbtype:sept /libpath:"C:\Dev\openssl\lib" /libpath:"C:\Dev\zlib\dll32" /libpath:"C:\Dev\openssl\lib\out32dll" /libpath:"C:\temp\Releaselib"
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "webhttrack - Win32 Release"
|
|
||||||
# Name "webhttrack - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\htsserver.c
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\htsweb.c
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\htsserver.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\htsweb.h
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Resource Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\ReadMe.txt
|
|
||||||
# End Source File
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
|
||||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "libhttrack"=..\libhttrack\libhttrack.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "webhttrack"=.\webhttrack.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name libhttrack
|
|
||||||
End Project Dependency
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Global:
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<3>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
@@ -1,443 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="9,00"
|
|
||||||
Name="webhttrack"
|
|
||||||
ProjectGUID="{B2A68D1B-3EB3-4B16-B634-8D36AC4266EC}"
|
|
||||||
RootNamespace="webhttrack"
|
|
||||||
TargetFrameworkVersion="131072"
|
|
||||||
>
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"
|
|
||||||
/>
|
|
||||||
<Platform
|
|
||||||
Name="x64"
|
|
||||||
/>
|
|
||||||
</Platforms>
|
|
||||||
<ToolFiles>
|
|
||||||
</ToolFiles>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory="C:\temp\webhttrack\Debug"
|
|
||||||
IntermediateDirectory="C:\temp\webhttrack\Debug"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TypeLibraryName=".\Debug/webhttrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\httrack\src;C:\Dev\zlib\;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
BufferSecurityCheck="true"
|
|
||||||
RuntimeTypeInfo="true"
|
|
||||||
PrecompiledHeaderFile=".\Debug/webhttrack.pch"
|
|
||||||
AssemblerOutput="2"
|
|
||||||
AssemblerListingLocation=".\Debug/"
|
|
||||||
ObjectFile=".\Debug/"
|
|
||||||
ProgramDataBaseFileName=".\Debug/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="4"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
Culture="1036"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="C:\temp\httrack\webhttrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib;C:\temp\debug_libz;C:\Dev\openssl\lib\out32dll;C:\temp\Debuglib"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile=".\Debug/webhttrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
TypeLibraryName=".\Debug/webhttrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\httrack\src;C:\Dev\zlib\;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
BufferSecurityCheck="true"
|
|
||||||
RuntimeTypeInfo="true"
|
|
||||||
PrecompiledHeaderFile=".\Debug/webhttrack.pch"
|
|
||||||
AssemblerOutput="2"
|
|
||||||
AssemblerListingLocation=".\Debug/"
|
|
||||||
ObjectFile=".\Debug/"
|
|
||||||
ProgramDataBaseFileName=".\Debug/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
Culture="1036"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="C:\temp\httrack64\webhttrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib;C:\temp\debug_libz64;C:\Dev\openssl\lib\out32dll;C:\temp\Debuglib"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile=".\Debug/webhttrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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\webhttrack\Release"
|
|
||||||
IntermediateDirectory="C:\temp\webhttrack\Release"
|
|
||||||
ConfigurationType="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TypeLibraryName=".\Release/webhttrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="3"
|
|
||||||
InlineFunctionExpansion="1"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\httrack\src;C:\Dev\zlib\;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
StringPooling="true"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
EnableFunctionLevelLinking="true"
|
|
||||||
PrecompiledHeaderFile=".\Release/webhttrack.pch"
|
|
||||||
AssemblerListingLocation="c:\temp\VCRelease/"
|
|
||||||
ObjectFile="c:\temp\VCRelease/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\VCRelease/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1036"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\webhttrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib;C:\temp\release_libz;C:\Dev\openssl\lib\out32dll;C:\temp\Releaselib"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\webhttrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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="1"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
TypeLibraryName=".\Release/webhttrack.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="3"
|
|
||||||
InlineFunctionExpansion="1"
|
|
||||||
AdditionalIncludeDirectories="C:\Dev\httrack\src;C:\Dev\zlib\;"C:\Dev\openssl-1.0.1j\include";C:\Dev\httrack\src\coucal"
|
|
||||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
|
|
||||||
StringPooling="true"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
EnableFunctionLevelLinking="true"
|
|
||||||
PrecompiledHeaderFile=".\Release/webhttrack.pch"
|
|
||||||
AssemblerListingLocation="c:\temp\VCRelease64/"
|
|
||||||
ObjectFile="c:\temp\VCRelease64/"
|
|
||||||
ProgramDataBaseFileName="c:\temp\VCRelease64/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
Detect64BitPortabilityProblems="true"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1036"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="Ws2_32.lib libhttrack.lib"
|
|
||||||
OutputFile="O:\HTTrack\httrack\x64\webhttrack.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
AdditionalLibraryDirectories="C:\Dev\openssl\lib;C:\temp\release_libz64;C:\Dev\openssl\lib\out32dll;C:\temp\Releaselib64"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="O:\HTTrack\httrack\x64\webhttrack.pdb"
|
|
||||||
SubSystem="1"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
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;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="htsserver.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="htsweb.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Header Files"
|
|
||||||
Filter="h;hpp;hxx;hm;inl"
|
|
||||||
>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Resource Files"
|
|
||||||
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="htsserver.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="htsweb.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<File
|
|
||||||
RelativePath="ReadMe.txt"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
109
src/webhttrack.vcxproj
Normal file
109
src/webhttrack.vcxproj
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{2F9E0E4C-2B5B-4B2E-9F6D-1C0A5E7B3D02}</ProjectGuid>
|
||||||
|
<RootNamespace>webhttrack</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)'==''">10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows</VcpkgTriplet>
|
||||||
|
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows</VcpkgTriplet>
|
||||||
|
<OutDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\obj\webhttrack\</IntDir>
|
||||||
|
<TargetName>webhttrack</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<!-- Matches htsserver_CFLAGS in Makefile.am. -->
|
||||||
|
<PreprocessorDefinitions>WIN32;_CONSOLE;_MBCS;ZLIB_CONST;HTS_INTHASH_USES_MD5;WINVER=0x0601;_WIN32_WINNT=0x0601;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);$(MSBuildThisFileDirectory)coucal;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="htsserver.c" />
|
||||||
|
<ClCompile Include="htsweb.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="libhttrack.vcxproj">
|
||||||
|
<Project>{e76ad871-54c1-45e8-a657-6117adeffb46}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
</Project>
|
||||||
34
tests/01_engine-crange.test
Executable file
34
tests/01_engine-crange.test
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Content-Range parse (treathead via -#test=crange). Hostile values must clamp
|
||||||
|
# to 0, and the crange +/- 1 arithmetic must not sign-overflow (UBSan aborts on
|
||||||
|
# the pre-fix binary at the INT64_MIN cases).
|
||||||
|
|
||||||
|
cr() {
|
||||||
|
local want="$1"
|
||||||
|
shift
|
||||||
|
out="$(httrack -O /dev/null -#test=crange "$@")"
|
||||||
|
test "$out" == "$want" || {
|
||||||
|
echo "FAIL: $* -> '$out' (want '$want')"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Normal range and the '*/N' fallback both parse through unchanged.
|
||||||
|
cr 'crange_start=0 crange_end=70870 crange=70871' 'Content-Range: bytes 0-70870/70871'
|
||||||
|
cr 'crange_start=0 crange_end=70870 crange=70871' 'Content-Range: bytes */70871'
|
||||||
|
|
||||||
|
# INT64_MIN total in the fallback would make crange-1 overflow: clamp to 0.
|
||||||
|
cr 'crange_start=0 crange_end=0 crange=0' 'Content-Range: bytes */-9223372036854775808'
|
||||||
|
|
||||||
|
# Any negative field in the 3-field form clamps the whole triple to 0 (each
|
||||||
|
# field independently: a leading negative start/end alone still zeroes all).
|
||||||
|
cr 'crange_start=0 crange_end=0 crange=0' 'Content-Range: bytes -1--1/-1'
|
||||||
|
cr 'crange_start=0 crange_end=0 crange=0' 'Content-Range: bytes -5-10/20'
|
||||||
|
|
||||||
|
# INT64_MAX is non-negative: it passes through, the parse must not mangle it.
|
||||||
|
cr 'crange_start=0 crange_end=9223372036854775807 crange=9223372036854775807' \
|
||||||
|
'Content-Range: bytes 0-9223372036854775807/9223372036854775807'
|
||||||
@@ -192,3 +192,6 @@ test "$(with_timeout httrack -O /dev/null -#test=filter "$pat" "$subj")" == "$su
|
|||||||
# (guards against a single-backtrack-point matcher rewrite)
|
# (guards against a single-backtrack-point matcher rewrite)
|
||||||
match '*[aX]X*[a]Y' 'aXaXaY'
|
match '*[aX]X*[a]Y' 'aXaXaY'
|
||||||
nomatch '*[aX]X*[a]Y' 'aXbXaY'
|
nomatch '*[aX]X*[a]Y' 'aXbXaY'
|
||||||
|
|
||||||
|
# hostile patterns must not stack-overflow or hang: length + work caps
|
||||||
|
test "$(with_timeout httrack -O /dev/null -#test=filterbounds)" == "filterbounds: OK" || exit 1
|
||||||
|
|||||||
8
tests/01_engine-identabs.test
Executable file
8
tests/01_engine-identabs.test
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# A 2047-byte hostless "?"-URL used to overflow fil[] by one byte and abort in
|
||||||
|
# strncat_safe_; the guard now returns -1 while valid URLs still parse.
|
||||||
|
test "$(httrack -O /dev/null -#test=identabs)" == "identabs self-test OK" || exit 1
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# .class constant-pool count is capped to the file size (calloc DoS).
|
|
||||||
httrack -O /dev/null -#test=java run | grep -q "java constant-pool cap self-test OK"
|
|
||||||
44
tests/01_engine-proxyurl.test
Executable file
44
tests/01_engine-proxyurl.test
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# hts_parse_proxy splits a -P argument "[scheme://][user:pass@]host[:port]" into
|
||||||
|
# the proxy host string and port. -#test=proxyurl <arg> prints
|
||||||
|
# "name=.. port=.. host=..", where host= is what the connect resolves.
|
||||||
|
|
||||||
|
p() {
|
||||||
|
test "$(httrack -O /dev/null -#test=proxyurl "$1")" == "$2" || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# bare host, with and without an explicit port
|
||||||
|
p 'proxy.example.com:8080' 'name=proxy.example.com port=8080 host=proxy.example.com'
|
||||||
|
p 'proxy.example.com' 'name=proxy.example.com port=8080 host=proxy.example.com'
|
||||||
|
|
||||||
|
# user:pass@ is kept in name (for proxy auth) and stripped from host
|
||||||
|
p 'user:pass@proxy:3128' 'name=user:pass@proxy port=3128 host=proxy'
|
||||||
|
p 'user:pass@proxy' 'name=user:pass@proxy port=8080 host=proxy'
|
||||||
|
|
||||||
|
# a scheme colon must not be read as a port: http://host with no port used to
|
||||||
|
# parse to name=http with a garbage port
|
||||||
|
p 'http://proxy:8080' 'name=http://proxy port=8080 host=proxy'
|
||||||
|
p 'http://proxy' 'name=http://proxy port=8080 host=proxy'
|
||||||
|
|
||||||
|
# socks5/socks5h default to 1080 and resolve to the bare host
|
||||||
|
p 'socks5://host:1080' 'name=socks5://host port=1080 host=host'
|
||||||
|
p 'socks5://host' 'name=socks5://host port=1080 host=host'
|
||||||
|
p 'socks5h://host' 'name=socks5h://host port=1080 host=host'
|
||||||
|
# explicit port wins over the 1080 default, with and without userinfo
|
||||||
|
p 'socks5://host:9050' 'name=socks5://host port=9050 host=host'
|
||||||
|
p 'socks5://user:pass@host:9050' 'name=socks5://user:pass@host port=9050 host=host'
|
||||||
|
|
||||||
|
# the split is byte-transparent: percent-escapes stay encoded (decoded later at
|
||||||
|
# auth time), only structural ASCII ':'/'@' delimit, and the last '@' ends the
|
||||||
|
# userinfo. So %40/%3A and UTF-8 bytes never mis-split host or port.
|
||||||
|
p 'socks5://user:p%40ss@host:1080' 'name=socks5://user:p%40ss@host port=1080 host=host'
|
||||||
|
p 'socks5://us%3Aer:pass@host:1080' 'name=socks5://us%3Aer:pass@host port=1080 host=host'
|
||||||
|
p 'socks5://a@b:c@host:1080' 'name=socks5://a@b:c@host port=1080 host=host'
|
||||||
|
p 'socks5://naïve:pass@héllo:1080' 'name=socks5://naïve:pass@héllo port=1080 host=héllo'
|
||||||
|
|
||||||
|
# a lone ':' must not underflow the backward scan
|
||||||
|
p ':' 'name= port=8080 host='
|
||||||
@@ -35,7 +35,8 @@ chk image/avif hex:0000001C6674797061766966 "$yes"
|
|||||||
chk image/avif hex:0000001C6674797068656963 "$no" # heic brand is not avif
|
chk image/avif hex:0000001C6674797068656963 "$no" # heic brand is not avif
|
||||||
chk image/heic hex:0000001C6674797068656963 "$yes"
|
chk image/heic hex:0000001C6674797068656963 "$yes"
|
||||||
chk image/svg+xml '<svg xmlns="x">' "$yes"
|
chk image/svg+xml '<svg xmlns="x">' "$yes"
|
||||||
chk image/svg+xml $'\xef\xbb\xbf <?xml version="1.0"?>' "$yes" # BOM+ws skip
|
# BOM+ws skip; hex, as Windows argv cannot carry the raw BOM through the ANSI codepage
|
||||||
|
chk image/svg+xml hex:EFBBBF20203C3F786D6C2076657273696F6E3D22312E30223F3E "$yes"
|
||||||
|
|
||||||
# audio / video
|
# audio / video
|
||||||
chk audio/mpeg 'ID3xxx' "$yes"
|
chk audio/mpeg 'ID3xxx' "$yes"
|
||||||
|
|||||||
9
tests/01_engine-socks5.test
Normal file
9
tests/01_engine-socks5.test
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# The SOCKS5 handshake framing and credential split, driven against scripted
|
||||||
|
# server replies (frame draining, oversize rejects, RFC 1929 fields).
|
||||||
|
|
||||||
|
httrack -O /dev/null '-#test=socks5' | grep -q "socks5 self-test OK"
|
||||||
64
tests/01_engine-version-macros.test
Executable file
64
tests/01_engine-version-macros.test
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# version.rc repeats the version that htsglobal.h declares. Signing enforces that
|
||||||
|
# every binary in a release reports the same one, so a drift fails the signing
|
||||||
|
# request on release day rather than the build. Assert the two agree.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
src="${top_srcdir:-..}/src"
|
||||||
|
h="$src/htsglobal.h"
|
||||||
|
rc="$src/version.rc"
|
||||||
|
for f in "$h" "$rc"; do
|
||||||
|
[ -f "$f" ] || {
|
||||||
|
echo "cannot find $f"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
# 3.49-12 (display) and 3.49.12 (dotted).
|
||||||
|
version=$(sed -n 's/^#define HTTRACK_VERSION[[:space:]][[:space:]]*"\([^"]*\)".*/\1/p' "$h")
|
||||||
|
versionid=$(sed -n 's/^#define HTTRACK_VERSIONID[[:space:]][[:space:]]*"\([^"]*\)".*/\1/p' "$h")
|
||||||
|
if [ -z "$version" ] || [ -z "$versionid" ]; then
|
||||||
|
echo "could not read the version from $h"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The same version, as version.rc states it.
|
||||||
|
fileversion=$(sed -n 's/^[[:space:]]*FILEVERSION[[:space:]][[:space:]]*\(.*\)$/\1/p' "$rc" | tr -d ' \r')
|
||||||
|
productversion=$(sed -n 's/^[[:space:]]*PRODUCTVERSION[[:space:]][[:space:]]*\(.*\)$/\1/p' "$rc" | tr -d ' \r')
|
||||||
|
rc_fileversion=$(sed -n 's/.*VALUE "FileVersion",[[:space:]]*"\([^"]*\)".*/\1/p' "$rc")
|
||||||
|
rc_productversion=$(sed -n 's/.*VALUE "ProductVersion",[[:space:]]*"\([^"]*\)".*/\1/p' "$rc")
|
||||||
|
rc_productname=$(sed -n 's/.*VALUE "ProductName",[[:space:]]*"\([^"]*\)".*/\1/p' "$rc")
|
||||||
|
|
||||||
|
# 3.49.12 -> 3,49,12,0
|
||||||
|
expected_numeric="$(echo "$versionid" | tr '.' ','),0"
|
||||||
|
|
||||||
|
fail=0
|
||||||
|
check() { # what expected actual
|
||||||
|
if [ "$2" != "$3" ]; then
|
||||||
|
echo "version.rc $1 is \"$3\", but htsglobal.h says it should be \"$2\""
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
check FILEVERSION "$expected_numeric" "$fileversion"
|
||||||
|
check PRODUCTVERSION "$expected_numeric" "$productversion"
|
||||||
|
check FileVersion "$versionid" "$rc_fileversion"
|
||||||
|
check ProductVersion "$version" "$rc_productversion"
|
||||||
|
|
||||||
|
# Signing pins the product name too.
|
||||||
|
check ProductName "HTTrack Website Copier" "$rc_productname"
|
||||||
|
|
||||||
|
[ "$fail" -eq 0 ] || exit 1
|
||||||
|
|
||||||
|
# And the shipped binary must agree with the header it was built from.
|
||||||
|
out=$(httrack --version)
|
||||||
|
case "$out" in
|
||||||
|
*"$version"*) ;;
|
||||||
|
*)
|
||||||
|
echo "httrack --version says \"$out\", which does not mention $version"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "version resource agrees with htsglobal.h: $version ($expected_numeric)"
|
||||||
29
tests/01_engine-xfread.test
Executable file
29
tests/01_engine-xfread.test
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# http_xfread1 must refuse an in-memory receive buffer that would exceed a
|
||||||
|
# 32-bit index (hostile Content-Length, or an endless stream) rather than
|
||||||
|
# allocate it, while still accepting a normal small size. -#test=xfread-limit
|
||||||
|
# drives both refusal paths and the accept path.
|
||||||
|
|
||||||
|
out="$(httrack -O /dev/null -#test=xfread-limit)"
|
||||||
|
for case in bylen bygrow; do
|
||||||
|
echo "$out" | grep -q "${case}: refused=1 adr=null msg=In-memory content too large" || {
|
||||||
|
echo "FAIL ${case}: $out"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
# Exactly INT32_MAX must be refused too (the reallocs add 1).
|
||||||
|
echo "$out" | grep -q 'boundary: msg=In-memory content too large' || {
|
||||||
|
echo "FAIL boundary: $out"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# The guard must NOT fire for a legitimate small size.
|
||||||
|
if echo "$out" | grep -q 'accept: msg=In-memory content too large'; then
|
||||||
|
echo "FAIL accept (guard fired on a legit size): $out"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
11
tests/01_zlib-contentcodings.test
Executable file
11
tests/01_zlib-contentcodings.test
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# brotli/zstd decode, unknown codings, and the decoded-size budget.
|
||||||
|
dir=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$dir"' EXIT
|
||||||
|
|
||||||
|
httrack -O /dev/null -#test=contentcodings "$dir" run |
|
||||||
|
grep -q "contentcodings self-test OK"
|
||||||
@@ -66,9 +66,12 @@ test -n "$port" || {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out="$tmpdir/crawl"
|
out="$tmpdir/crawl"
|
||||||
|
# macOS has only 127.0.0.1, so the dead 127.0.0.x connects block to the timeout
|
||||||
|
# instead of refusing instantly (as on Linux); a small --timeout + --retries=0
|
||||||
|
# bound the stall without changing what the fallback exercises.
|
||||||
HTTRACK_DEBUG_RESOLVE="deadhost:127.0.0.2,127.0.0.1" \
|
HTTRACK_DEBUG_RESOLVE="deadhost:127.0.0.2,127.0.0.1" \
|
||||||
httrack "http://deadhost:$port/simple/basic.html" -O "$out" \
|
httrack "http://deadhost:$port/simple/basic.html" -O "$out" \
|
||||||
-c1 --robots=0 --timeout=30 --quiet -Z >"$tmpdir/log" 2>&1
|
-c1 --robots=0 --timeout=5 --retries=0 --quiet -Z >"$tmpdir/log" 2>&1
|
||||||
|
|
||||||
log="$out/hts-log.txt"
|
log="$out/hts-log.txt"
|
||||||
|
|
||||||
@@ -92,12 +95,12 @@ test -f "$out/deadhost_$port/simple/basic.html" || {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# every address refused: the slot exhausts the list, then errors out (the
|
# every address dead: the slot exhausts the list, then errors out (the harness
|
||||||
# harness timeout would catch a hang/loop; refused connects are instant)
|
# timeout would catch a hang/loop)
|
||||||
out2="$tmpdir/crawl2"
|
out2="$tmpdir/crawl2"
|
||||||
HTTRACK_DEBUG_RESOLVE="alldead:127.0.0.2,127.0.0.3" \
|
HTTRACK_DEBUG_RESOLVE="alldead:127.0.0.2,127.0.0.3" \
|
||||||
httrack "http://alldead:$port/simple/basic.html" -O "$out2" \
|
httrack "http://alldead:$port/simple/basic.html" -O "$out2" \
|
||||||
-c1 --robots=0 --timeout=30 --quiet -Z >"$tmpdir/log2" 2>&1
|
-c1 --robots=0 --timeout=5 --retries=0 --quiet -Z >"$tmpdir/log2" 2>&1
|
||||||
log2="$out2/hts-log.txt"
|
log2="$out2/hts-log.txt"
|
||||||
|
|
||||||
grep -q "trying next address" "$log2" || {
|
grep -q "trying next address" "$log2" || {
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# The java plugin must load (versioned dlopen name) and parse a .class
|
|
||||||
# constant pool: a resource named only inside Foo.class gets crawled.
|
|
||||||
set -e
|
|
||||||
|
|
||||||
: "${top_srcdir:=..}"
|
|
||||||
|
|
||||||
tmproot=$(mktemp -d)
|
|
||||||
trap 'rm -rf "$tmproot"' EXIT
|
|
||||||
mkdir "$tmproot/javaclass"
|
|
||||||
|
|
||||||
cat >"$tmproot/javaclass/index.html" <<'EOF'
|
|
||||||
<html><body><a href="Foo.class">applet</a></body></html>
|
|
||||||
EOF
|
|
||||||
printf 'GIF89a' >"$tmproot/javaclass/hello.gif"
|
|
||||||
# magic/minor/major, count=2, one CONSTANT_Utf8 "hello.gif", class/superclass
|
|
||||||
printf '\xCA\xFE\xBA\xBE\x00\x00\x00\x32\x00\x02\x01\x00\x09hello.gif\x00\x00\x00\x00' \
|
|
||||||
>"$tmproot/javaclass/Foo.class"
|
|
||||||
|
|
||||||
bash "$top_srcdir/tests/local-crawl.sh" --root "$tmproot" --errors 0 \
|
|
||||||
--found 'javaclass/Foo.class' \
|
|
||||||
--found 'javaclass/hello.gif' \
|
|
||||||
httrack 'BASEURL/javaclass/index.html'
|
|
||||||
@@ -53,4 +53,4 @@ bash "$top_srcdir/tests/local-crawl.sh" --rerun \
|
|||||||
--log-found ', no files updated' \
|
--log-found ', no files updated' \
|
||||||
--max-mirror-bytes 700000 \
|
--max-mirror-bytes 700000 \
|
||||||
--min-mirror-bytes 500000 \
|
--min-mirror-bytes 500000 \
|
||||||
httrack 'BASEURL/big/index.html' --retries=0 -c8 -%c100 -A100000000
|
httrack 'BASEURL/big/index.html' --retries=0 -c16 -%c100 -A100000000
|
||||||
|
|||||||
16
tests/45_local-maxsize-recv.test
Executable file
16
tests/45_local-maxsize-recv.test
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# -M caps received volume, not saved 200-only bytes (#520): links to large 404
|
||||||
|
# bodies pump received >> saved; the cap must trip though little lands on disk.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
|
||||||
|
# The mirror bound is the load-bearing half: it fires while <100 KB is saved,
|
||||||
|
# so the cap can only have tripped on received volume, not saved bytes (which
|
||||||
|
# would exceed the cap and fetch all 16 links).
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" \
|
||||||
|
--log-found 'More than 500000 bytes have been transferred.. giving up' \
|
||||||
|
--max-mirror-bytes 100000 \
|
||||||
|
httrack 'BASEURL/maxrecv/index.html' -M500000 -c4
|
||||||
118
tests/46_local-update-304-resume.test
Executable file
118
tests/46_local-update-304-resume.test
Executable file
@@ -0,0 +1,118 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# C7: a server 304 answering a resume's Range request is out of protocol; httrack
|
||||||
|
# must drop the partial and refetch, not finalize it as complete at the partial
|
||||||
|
# byte count. Pass 1 leaves a partial + temp-ref; pass 2 resumes, gets a bogus
|
||||||
|
# 304, and must recover the whole file.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
testdir=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
server="${testdir}/local-server.py"
|
||||||
|
|
||||||
|
command -v python3 >/dev/null || ! echo "python3 not found; skipping" || exit 77
|
||||||
|
|
||||||
|
tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/httrack_c7.XXXXXX") || exit 1
|
||||||
|
serverpid=
|
||||||
|
crawlpid=
|
||||||
|
cleanup() {
|
||||||
|
test -n "$crawlpid" && kill -9 "$crawlpid" 2>/dev/null
|
||||||
|
if test -n "$serverpid"; then
|
||||||
|
kill "$serverpid" 2>/dev/null
|
||||||
|
wait "$serverpid" 2>/dev/null
|
||||||
|
fi
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT QUIT PIPE TERM
|
||||||
|
|
||||||
|
serverlog="${tmpdir}/server.log"
|
||||||
|
counter="${tmpdir}/reqcount"
|
||||||
|
mark="${tmpdir}/got304"
|
||||||
|
RESUME304_COUNTER="$counter" RESUME304_MARK="$mark" python3 "$server" --root "${testdir}/server-root" >"$serverlog" 2>&1 &
|
||||||
|
serverpid=$!
|
||||||
|
port=
|
||||||
|
for _ in $(seq 1 50); do
|
||||||
|
line=$(head -n1 "$serverlog" 2>/dev/null)
|
||||||
|
if test "${line%% *}" == "PORT"; then
|
||||||
|
port="${line#PORT }"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
kill -0 "$serverpid" 2>/dev/null || {
|
||||||
|
echo "server exited early: $(cat "$serverlog")"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
test -n "$port" || {
|
||||||
|
echo "could not discover server port"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
base="http://127.0.0.1:${port}"
|
||||||
|
|
||||||
|
which httrack >/dev/null || {
|
||||||
|
echo "could not find httrack"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
out="${tmpdir}/crawl"
|
||||||
|
mkdir "$out"
|
||||||
|
common=(-O "$out" --quiet --disable-security-limits --robots=0 --timeout=30 --retries=1 -c1)
|
||||||
|
refdir="${out}/hts-cache/ref"
|
||||||
|
|
||||||
|
# --- pass 1: crawl, interrupt once the blob download is underway -------------
|
||||||
|
printf '[pass 1: interrupt mid-download] ..\t'
|
||||||
|
httrack "${common[@]}" "${base}/resume304/index.html" >"${tmpdir}/log1" 2>&1 &
|
||||||
|
crawlpid=$!
|
||||||
|
for _ in $(seq 1 300); do
|
||||||
|
test -s "$counter" && break
|
||||||
|
kill -0 "$crawlpid" 2>/dev/null || break
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
sleep 0.5
|
||||||
|
kill -TERM "$crawlpid" 2>/dev/null
|
||||||
|
wait "$crawlpid" 2>/dev/null
|
||||||
|
crawlpid=
|
||||||
|
test -n "$(find "$refdir" -name '*.ref' 2>/dev/null)" || {
|
||||||
|
echo "FAIL: no temp-ref survived pass 1; cannot drive C7"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK (temp-ref present)"
|
||||||
|
before=$(wc -c <"$counter" 2>/dev/null || echo 0)
|
||||||
|
|
||||||
|
# --- pass 2: --continue -> resume Range -> bogus 304 -> drop + refetch --------
|
||||||
|
printf '[pass 2: resume gets 304, must refetch] ..\t'
|
||||||
|
httrack "${common[@]}" --continue "${base}/resume304/index.html" >"${tmpdir}/log2" 2>&1
|
||||||
|
echo "OK (terminated)"
|
||||||
|
|
||||||
|
blob=$(find "$out" -name blob.bin 2>/dev/null | head -1)
|
||||||
|
full=8200 # len(RESUME304_BODY) = len("C7DATA--") + 8192
|
||||||
|
|
||||||
|
printf '[file recovered whole] ..\t'
|
||||||
|
test -s "$blob" || {
|
||||||
|
echo "FAIL: blob.bin missing after the 304 resume (partial dropped, not refetched)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
got=$(wc -c <"$blob")
|
||||||
|
test "$got" -eq "$full" || {
|
||||||
|
echo "FAIL: blob.bin is ${got} bytes, expected ${full} (partial finalized as complete)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK (${got} bytes)"
|
||||||
|
|
||||||
|
# Pass 2 must issue at least two requests: the resume (Range -> 304) and the
|
||||||
|
# range-less refetch (-> 200). Exactly one means the partial was trusted.
|
||||||
|
after=$(wc -c <"$counter" 2>/dev/null || echo 0)
|
||||||
|
hits=$((after - before))
|
||||||
|
printf '[resume then refetch] ..\t'
|
||||||
|
test "$hits" -ge 2 || {
|
||||||
|
echo "FAIL: only ${hits} pass-2 request(s); the 304 was trusted, no refetch"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK (${hits} requests)"
|
||||||
|
|
||||||
|
# The recovery must go through the resume path: a Range request that drew the
|
||||||
|
# bogus 304 (a fresh re-crawl sends no Range, so this marker stays empty).
|
||||||
|
printf '[resume Range drew a 304] ..\t'
|
||||||
|
test -s "$mark" || {
|
||||||
|
echo "FAIL: no Range request got a 304; the resume path was not exercised"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK"
|
||||||
96
tests/47_local-crange-overflow.test
Executable file
96
tests/47_local-crange-overflow.test
Executable file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# C2: a resume whose 206 carries a Content-Range end of INT64_MAX must not
|
||||||
|
# sign-overflow the crange+1 range check (UBSan aborts on the pre-fix binary).
|
||||||
|
# Pass 1 leaves a partial + temp-ref; pass 2 resumes, gets the hostile 206, and
|
||||||
|
# must reject the range and refetch the whole file rather than overflow. Teeth
|
||||||
|
# are UBSan-only: a normal build wraps to the same reject+restart.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
testdir=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
server="${testdir}/local-server.py"
|
||||||
|
|
||||||
|
command -v python3 >/dev/null || ! echo "python3 not found; skipping" || exit 77
|
||||||
|
|
||||||
|
tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/httrack_crange.XXXXXX") || exit 1
|
||||||
|
serverpid=
|
||||||
|
crawlpid=
|
||||||
|
cleanup() {
|
||||||
|
test -n "$crawlpid" && kill -9 "$crawlpid" 2>/dev/null
|
||||||
|
if test -n "$serverpid"; then
|
||||||
|
kill "$serverpid" 2>/dev/null
|
||||||
|
wait "$serverpid" 2>/dev/null
|
||||||
|
fi
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT QUIT PIPE TERM
|
||||||
|
|
||||||
|
serverlog="${tmpdir}/server.log"
|
||||||
|
python3 "$server" --root "${testdir}/server-root" >"$serverlog" 2>&1 &
|
||||||
|
serverpid=$!
|
||||||
|
port=
|
||||||
|
for _ in $(seq 1 50); do
|
||||||
|
line=$(head -n1 "$serverlog" 2>/dev/null)
|
||||||
|
if test "${line%% *}" == "PORT"; then
|
||||||
|
port="${line#PORT }"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
kill -0 "$serverpid" 2>/dev/null || {
|
||||||
|
echo "server exited early: $(cat "$serverlog")"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
test -n "$port" || {
|
||||||
|
echo "could not discover server port"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
base="http://127.0.0.1:${port}"
|
||||||
|
|
||||||
|
which httrack >/dev/null || {
|
||||||
|
echo "could not find httrack"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
out="${tmpdir}/crawl"
|
||||||
|
mkdir "$out"
|
||||||
|
common=(-O "$out" --quiet --disable-security-limits --robots=0 --timeout=30 --retries=1 -c1)
|
||||||
|
refdir="${out}/hts-cache/ref"
|
||||||
|
|
||||||
|
# --- pass 1: crawl, interrupt once the blob download is underway -------------
|
||||||
|
printf '[pass 1: interrupt mid-download] ..\t'
|
||||||
|
httrack "${common[@]}" "${base}/crange206/index.html" >"${tmpdir}/log1" 2>&1 &
|
||||||
|
crawlpid=$!
|
||||||
|
for _ in $(seq 1 300); do
|
||||||
|
test -n "$(find "$refdir" -name '*.ref' 2>/dev/null)" && break
|
||||||
|
kill -0 "$crawlpid" 2>/dev/null || break
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
sleep 0.3
|
||||||
|
kill -TERM "$crawlpid" 2>/dev/null
|
||||||
|
wait "$crawlpid" 2>/dev/null
|
||||||
|
crawlpid=
|
||||||
|
test -n "$(find "$refdir" -name '*.ref' 2>/dev/null)" || {
|
||||||
|
echo "FAIL: no temp-ref survived pass 1; cannot drive the resume"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK (temp-ref present)"
|
||||||
|
|
||||||
|
# --- pass 2: --continue -> resume -> hostile INT64_MAX Content-Range ----------
|
||||||
|
printf '[pass 2: hostile 206, no overflow, refetch] ..\t'
|
||||||
|
httrack "${common[@]}" --continue "${base}/crange206/index.html" >"${tmpdir}/log2" 2>&1
|
||||||
|
echo "OK (terminated)"
|
||||||
|
|
||||||
|
blob=$(find "$out" -name blob.bin 2>/dev/null | head -1)
|
||||||
|
full=6008 # len(CRANGE206_BODY) = len("CR206DAT") + 6000
|
||||||
|
|
||||||
|
printf '[file recovered whole] ..\t'
|
||||||
|
test -s "$blob" || {
|
||||||
|
echo "FAIL: blob.bin missing after the hostile 206"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
got=$(wc -c <"$blob")
|
||||||
|
test "$got" -eq "$full" || {
|
||||||
|
echo "FAIL: blob.bin is ${got} bytes, expected ${full}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK (${got} bytes)"
|
||||||
96
tests/48_local-crange-memresume.test
Executable file
96
tests/48_local-crange-memresume.test
Executable file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# C2 (memory branch): a resume whose 206 lies text/html with a matching
|
||||||
|
# INT64_MAX Content-Length must not overflow the resume buffer-size add
|
||||||
|
# (UBSan aborts on the pre-fix binary at alloc_mem += totalsize). Pass 1 leaves
|
||||||
|
# a partial + temp-ref; pass 2 resumes and must reject and refetch the whole
|
||||||
|
# file. Teeth are UBSan-only: a normal build wraps to the same reject+restart.
|
||||||
|
set -u
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
testdir=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
server="${testdir}/local-server.py"
|
||||||
|
|
||||||
|
command -v python3 >/dev/null || ! echo "python3 not found; skipping" || exit 77
|
||||||
|
|
||||||
|
tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/httrack_crangemem.XXXXXX") || exit 1
|
||||||
|
serverpid=
|
||||||
|
crawlpid=
|
||||||
|
cleanup() {
|
||||||
|
test -n "$crawlpid" && kill -9 "$crawlpid" 2>/dev/null
|
||||||
|
if test -n "$serverpid"; then
|
||||||
|
kill "$serverpid" 2>/dev/null
|
||||||
|
wait "$serverpid" 2>/dev/null
|
||||||
|
fi
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT QUIT PIPE TERM
|
||||||
|
|
||||||
|
serverlog="${tmpdir}/server.log"
|
||||||
|
python3 "$server" --root "${testdir}/server-root" >"$serverlog" 2>&1 &
|
||||||
|
serverpid=$!
|
||||||
|
port=
|
||||||
|
for _ in $(seq 1 50); do
|
||||||
|
line=$(head -n1 "$serverlog" 2>/dev/null)
|
||||||
|
if test "${line%% *}" == "PORT"; then
|
||||||
|
port="${line#PORT }"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
kill -0 "$serverpid" 2>/dev/null || {
|
||||||
|
echo "server exited early: $(cat "$serverlog")"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
test -n "$port" || {
|
||||||
|
echo "could not discover server port"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
base="http://127.0.0.1:${port}"
|
||||||
|
|
||||||
|
which httrack >/dev/null || {
|
||||||
|
echo "could not find httrack"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
out="${tmpdir}/crawl"
|
||||||
|
mkdir "$out"
|
||||||
|
common=(-O "$out" --quiet --disable-security-limits --robots=0 --timeout=30 --retries=1 -c1)
|
||||||
|
refdir="${out}/hts-cache/ref"
|
||||||
|
|
||||||
|
# --- pass 1: crawl, interrupt once the blob download is underway -------------
|
||||||
|
printf '[pass 1: interrupt mid-download] ..\t'
|
||||||
|
httrack "${common[@]}" "${base}/crange206mem/index.html" >"${tmpdir}/log1" 2>&1 &
|
||||||
|
crawlpid=$!
|
||||||
|
for _ in $(seq 1 300); do
|
||||||
|
test -n "$(find "$refdir" -name '*.ref' 2>/dev/null)" && break
|
||||||
|
kill -0 "$crawlpid" 2>/dev/null || break
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
sleep 0.3
|
||||||
|
kill -TERM "$crawlpid" 2>/dev/null
|
||||||
|
wait "$crawlpid" 2>/dev/null
|
||||||
|
crawlpid=
|
||||||
|
test -n "$(find "$refdir" -name '*.ref' 2>/dev/null)" || {
|
||||||
|
echo "FAIL: no temp-ref survived pass 1; cannot drive the resume"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK (temp-ref present)"
|
||||||
|
|
||||||
|
# --- pass 2: --continue -> resume -> hostile INT64_MAX Content-Range ----------
|
||||||
|
printf '[pass 2: hostile 206, no overflow, refetch] ..\t'
|
||||||
|
httrack "${common[@]}" --continue "${base}/crange206mem/index.html" >"${tmpdir}/log2" 2>&1
|
||||||
|
echo "OK (terminated)"
|
||||||
|
|
||||||
|
blob=$(find "$out" -name blob.bin 2>/dev/null | head -1)
|
||||||
|
full=6008 # len(CRANGE206_BODY) = len("CR206DAT") + 6000
|
||||||
|
|
||||||
|
printf '[file recovered whole] ..\t'
|
||||||
|
test -s "$blob" || {
|
||||||
|
echo "FAIL: blob.bin missing after the hostile 206"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
got=$(wc -c <"$blob")
|
||||||
|
test "$got" -eq "$full" || {
|
||||||
|
echo "FAIL: blob.bin is ${got} bytes, expected ${full}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK (${got} bytes)"
|
||||||
34
tests/49_local-cookiewall.test
Executable file
34
tests/49_local-cookiewall.test
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Cookie-wall self-redirect (#15): httrack replays a Set-Cookie to mirror the
|
||||||
|
# real page, gives up when nothing changes, and stays bounded when it never does.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
|
||||||
|
# Unknown-ext (wall.php) and known-ext (wall.html): the wall sets the cookie once,
|
||||||
|
# then serves real content; httrack must replay it and mirror that content.
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 \
|
||||||
|
--found 'cookiewall/wall.html' \
|
||||||
|
--file-matches 'cookiewall/wall.html' 'REAL-CONTENT-BEHIND-COOKIE-WALL' \
|
||||||
|
httrack 'BASEURL/cookiewall/index.html'
|
||||||
|
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 \
|
||||||
|
--found 'cookiewall2/wall.html' \
|
||||||
|
--file-matches 'cookiewall2/wall.html' 'REAL-CONTENT-BEHIND-COOKIE-WALL' \
|
||||||
|
httrack 'BASEURL/cookiewall2/index.html'
|
||||||
|
|
||||||
|
# No Set-Cookie: the jar never changes, so httrack must give up at once (retry
|
||||||
|
# stays gated) and not mirror the wall. A dropped gate would skip this log line.
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 \
|
||||||
|
--not-found 'cookiewall3/wall.html' \
|
||||||
|
--log-found 'loop to same filename' \
|
||||||
|
httrack 'BASEURL/cookiewall3/index.html'
|
||||||
|
|
||||||
|
# Ever-changing cookie never satisfies the wall: httrack must stop at the retry
|
||||||
|
# cap (bounded, no early give-up) and not mirror it.
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 \
|
||||||
|
--not-found 'cookiewall4/wall.html' \
|
||||||
|
--log-not-found 'loop to same filename' \
|
||||||
|
httrack 'BASEURL/cookiewall4/index.html'
|
||||||
38
tests/50_local-contentcodings.test
Executable file
38
tests/50_local-contentcodings.test
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# br and zstd on the wire: both decode, a junk coding leaves the body alone, an
|
||||||
|
# undecodable one fails the fetch, and br/zstd are advertised over TLS only.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
|
||||||
|
# Both decoders are needed for the wire fixtures; the codec-off matrix is
|
||||||
|
# covered by the fenced 01_zlib-contentcodings self-test.
|
||||||
|
if test "${BROTLI_ENABLED:-yes}" != "yes" || test "${ZSTD_ENABLED:-yes}" != "yes"; then
|
||||||
|
echo "brotli/zstd not both compiled, skipping"
|
||||||
|
exit 77
|
||||||
|
fi
|
||||||
|
|
||||||
|
# bad.html (in memory) and bin.dat (direct-to-disk) both carry an undecodable
|
||||||
|
# coding: the fetch fails and neither leaves coded bytes on disk.
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" --errors 2 --files 5 \
|
||||||
|
--file-matches 'codec/br.html' 'coded body' \
|
||||||
|
--file-matches 'codec/zstd.html' 'coded body' \
|
||||||
|
--file-matches 'codec/junk.html' 'junk coding' \
|
||||||
|
--file-matches 'codec/ae.html' 'AE=gzip, deflate,' \
|
||||||
|
--file-not-matches 'codec/ae.html' ' br' \
|
||||||
|
--file-not-matches 'codec/ae.html' 'zstd' \
|
||||||
|
--not-found 'codec/bad.html' \
|
||||||
|
--not-found 'codec/bin.dat' \
|
||||||
|
--log-found 'Unsupported Content-Encoding' \
|
||||||
|
httrack 'BASEURL/codec/index.html'
|
||||||
|
|
||||||
|
if test "${HTTPS_SUPPORT:-}" == "no"; then
|
||||||
|
echo "no https support compiled, skipping the TLS leg"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" --tls --errors 2 --files 5 \
|
||||||
|
--file-matches 'codec/ae.html' 'AE=gzip, deflate, br, zstd,' \
|
||||||
|
httrack 'BASEURL/codec/index.html'
|
||||||
38
tests/51_local-update-codec.test
Normal file
38
tests/51_local-update-codec.test
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# A coded re-fetch that fails to decode must not destroy the mirrored file (#557).
|
||||||
|
# Pass 1 mirrors from valid gzip; pass 2 (--update) serves an undecodable body for
|
||||||
|
# mem.html (in-memory), disk.bin (direct-to-disk) and unsup.html (a coding we have
|
||||||
|
# no decoder for). All three must keep their pass-1 content. fresh.html and
|
||||||
|
# freshdisk.bin decode on both passes: they are the controls that a good update
|
||||||
|
# still lands, in memory and direct-to-disk (the latter renaming the decoded temp
|
||||||
|
# over an existing file). Unfixed, the decode target is the mirror itself, so the
|
||||||
|
# first three are lost.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
|
||||||
|
# A restrictive umask makes the decoded direct-to-disk file's mode observable:
|
||||||
|
# it is committed by renaming a temp, so it needs the chmod filecreate() does.
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
bash "$top_srcdir/tests/local-crawl.sh" \
|
||||||
|
--rerun-args '--update' \
|
||||||
|
--errors 3 \
|
||||||
|
--log-found 'decompressing.*upcodec/mem\.html' \
|
||||||
|
--log-found 'decompressing.*upcodec/disk\.bin' \
|
||||||
|
--log-found 'Unsupported Content-Encoding.*upcodec/unsup\.html' \
|
||||||
|
--file-matches 'upcodec/mem.html' 'MIRRORED-MEM-V1' \
|
||||||
|
--file-matches 'upcodec/disk.bin' 'MIRRORED-DISK-V1' \
|
||||||
|
--file-min-bytes 'upcodec/disk.bin' 32768 \
|
||||||
|
--file-mode 'upcodec/disk.bin' 644 \
|
||||||
|
--file-matches 'upcodec/unsup.html' 'MIRRORED-UNSUP-V1' \
|
||||||
|
--file-matches 'upcodec/fresh.html' 'FRESH-V2' \
|
||||||
|
--file-not-matches 'upcodec/fresh.html' 'FRESH-V1' \
|
||||||
|
--file-mode 'upcodec/fresh.html' 644 \
|
||||||
|
--file-matches 'upcodec/freshdisk.bin' 'FRESHDISK-V2' \
|
||||||
|
--file-not-matches 'upcodec/freshdisk.bin' 'FRESHDISK-V1' \
|
||||||
|
--file-min-bytes 'upcodec/freshdisk.bin' 32768 \
|
||||||
|
--file-mode 'upcodec/freshdisk.bin' 644 \
|
||||||
|
httrack 'BASEURL/upcodec/index.html'
|
||||||
211
tests/52_local-socks5.test
Normal file
211
tests/52_local-socks5.test
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Issue #563: a SOCKS5 proxy must carry both http and https, resolve the origin
|
||||||
|
# name REMOTELY (ATYP=domain, never a local lookup), and authenticate per RFC
|
||||||
|
# 1929 without leaking the credentials to the origin.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${top_srcdir:=..}"
|
||||||
|
|
||||||
|
if test "${HTTPS_SUPPORT:-}" == "no"; then
|
||||||
|
echo "no https support compiled, skipping"
|
||||||
|
exit 77
|
||||||
|
fi
|
||||||
|
if ! command -v python3 >/dev/null 2>&1 || ! command -v openssl >/dev/null 2>&1; then
|
||||||
|
echo "python3/openssl missing, skipping"
|
||||||
|
exit 77
|
||||||
|
fi
|
||||||
|
|
||||||
|
# a .invalid name never resolves (RFC 6761): reaching the page at all proves the
|
||||||
|
# proxy did the DNS
|
||||||
|
host="socks-origin.invalid"
|
||||||
|
server="$top_srcdir/tests/socks5-server.py"
|
||||||
|
tmpdir=$(mktemp -d)
|
||||||
|
pids=
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
for pid in $pids; do
|
||||||
|
kill "$pid" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
openssl req -x509 -newkey rsa:2048 -keyout "$tmpdir/key.pem" \
|
||||||
|
-out "$tmpdir/cert.pem" -days 2 -nodes -subj "/CN=127.0.0.1" \
|
||||||
|
>/dev/null 2>&1
|
||||||
|
cat "$tmpdir/key.pem" "$tmpdir/cert.pem" >"$tmpdir/both.pem"
|
||||||
|
|
||||||
|
# start_server <logdir> <mode>: sets $tls_port/$http_port/$socks_port
|
||||||
|
start_server() {
|
||||||
|
local dir="$1" mode="$2" ports
|
||||||
|
mkdir -p "$dir"
|
||||||
|
ports="$dir/ports.txt"
|
||||||
|
python3 "$server" "$tmpdir/both.pem" "$dir" "$mode" \
|
||||||
|
>"$ports" 2>"$dir/server.err" &
|
||||||
|
pids="$pids $!"
|
||||||
|
for _ in $(seq 1 100); do
|
||||||
|
grep -q "^ready" "$ports" 2>/dev/null && break
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
grep -q "^ready" "$ports" 2>/dev/null || {
|
||||||
|
echo "server ($mode) did not start" >&2
|
||||||
|
cat "$dir/server.err" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
tls_port=$(awk '/^TLS/{print $2}' "$ports")
|
||||||
|
http_port=$(awk '/^HTTP/{print $2}' "$ports")
|
||||||
|
socks_port=$(awk '/^SOCKS/{print $2}' "$ports")
|
||||||
|
}
|
||||||
|
|
||||||
|
# kill a hung httrack so a missing read bound surfaces as $HANG_RC instead of
|
||||||
|
# stalling the job (macOS has no `timeout`)
|
||||||
|
HANG_RC=137 # 128 + SIGKILL
|
||||||
|
run_crawl() {
|
||||||
|
local out="$1" url="$2" proxy="$3"
|
||||||
|
shift 3
|
||||||
|
local extra="$*"
|
||||||
|
test -n "$extra" || extra="-r1 -s0"
|
||||||
|
rm -rf "$out"
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
httrack "$url" --proxy "$proxy" \
|
||||||
|
-O "$out" $extra --timeout=10 >"$out.log" 2>&1 &
|
||||||
|
local pid=$!
|
||||||
|
(sleep 60 && kill -9 "$pid" 2>/dev/null) &
|
||||||
|
local guard=$!
|
||||||
|
local rc=0
|
||||||
|
wait "$pid" 2>/dev/null || rc=$?
|
||||||
|
kill "$guard" 2>/dev/null || true
|
||||||
|
wait "$guard" 2>/dev/null || true
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- https over socks, remote DNS -------------------------------------------
|
||||||
|
ok="$tmpdir/ok"
|
||||||
|
start_server "$ok" ok
|
||||||
|
|
||||||
|
run_crawl "$ok/out" "https://${host}:${tls_port}/" "socks5://127.0.0.1:${socks_port}"
|
||||||
|
grep -rq "ORIGIN-PAGE-563" "$ok/out" || {
|
||||||
|
echo "FAIL: origin page not downloaded through the socks proxy" >&2
|
||||||
|
cat "$ok/out.log" "$ok/server.err" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
grep -q "^ATYP domain ${host}\$" "$ok/socks.log" || {
|
||||||
|
echo "FAIL: proxy did not receive ATYP=domain ${host} (no remote DNS)" >&2
|
||||||
|
cat "$ok/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
# a client that resolved locally would have sent an address, not a name
|
||||||
|
grep -q "^ATYP ipv4" "$ok/socks.log" && {
|
||||||
|
echo "FAIL: httrack resolved locally and sent an IPv4 to the proxy" >&2
|
||||||
|
cat "$ok/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK: https tunneled through socks5 with remote DNS"
|
||||||
|
|
||||||
|
# --- plain http over socks --------------------------------------------------
|
||||||
|
: >"$ok/origin-headers.log" # the https crawl above also logged a request line
|
||||||
|
run_crawl "$ok/outh" "http://${host}:${http_port}/" "socks5://127.0.0.1:${socks_port}"
|
||||||
|
grep -rq "ORIGIN-PAGE-563" "$ok/outh" || {
|
||||||
|
echo "FAIL: plain http not tunneled through the socks proxy" >&2
|
||||||
|
cat "$ok/outh.log" "$ok/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
# the tunneled request is origin-form, as on a direct connection: the http-proxy
|
||||||
|
# absolute URI would reach the origin as "GET http://host/"
|
||||||
|
grep -q "^REQUEST GET / " "$ok/origin-headers.log" || {
|
||||||
|
echo "FAIL: tunneled request is not origin-form" >&2
|
||||||
|
cat "$ok/origin-headers.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
grep -q "^REQUEST GET http" "$ok/origin-headers.log" && {
|
||||||
|
echo "FAIL: absolute-URI request sent through the socks tunnel" >&2
|
||||||
|
cat "$ok/origin-headers.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK: plain http tunneled through socks5"
|
||||||
|
|
||||||
|
# --- keep-alive socket reuse must NOT re-run the handshake ------------------
|
||||||
|
# A reused keep-alive socket is already tunneled; re-injecting the SOCKS
|
||||||
|
# greeting corrupts the origin stream. -c1 + the origin's max>1 advert makes
|
||||||
|
# httrack serve the whole plain-http crawl over one tunnel: exactly one
|
||||||
|
# handshake, every subpage intact.
|
||||||
|
ka="$tmpdir/ka"
|
||||||
|
start_server "$ka" ok
|
||||||
|
run_crawl "$ka/out" "http://${host}:${http_port}/" "socks5://127.0.0.1:${socks_port}" -r3 -c1
|
||||||
|
missing=0
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
grep -rq "SUBPAGE-563 /p${i}.html" "$ka/out" || missing=1
|
||||||
|
done
|
||||||
|
test "$missing" -eq 0 || {
|
||||||
|
echo "FAIL: a keep-alive subpage was lost (re-handshake corrupted the reused socket)" >&2
|
||||||
|
cat "$ka/out.log" "$ka/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
handshakes=$(grep -c "^CMD " "$ka/socks.log" || true)
|
||||||
|
test "$handshakes" -eq 1 || {
|
||||||
|
echo "FAIL: expected 1 SOCKS handshake for the reused socket, got $handshakes" >&2
|
||||||
|
cat "$ka/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK: keep-alive socket reused over one socks tunnel, no re-handshake"
|
||||||
|
|
||||||
|
# --- authenticated socks (RFC 1929) -----------------------------------------
|
||||||
|
# over plain http: that is the request an http proxy would decorate with
|
||||||
|
# Proxy-Authorization, so the no-leak check below has teeth
|
||||||
|
auth="$tmpdir/auth"
|
||||||
|
start_server "$auth" ok
|
||||||
|
run_crawl "$auth/out" "http://${host}:${http_port}/" \
|
||||||
|
"socks5://user:secret@127.0.0.1:${socks_port}"
|
||||||
|
grep -rq "ORIGIN-PAGE-563" "$auth/out" || {
|
||||||
|
echo "FAIL: origin not downloaded through the authenticated socks proxy" >&2
|
||||||
|
cat "$auth/out.log" "$auth/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
grep -q "^METHOD userpass\$" "$auth/socks.log" || {
|
||||||
|
echo "FAIL: user/pass method not negotiated (auth ignored)" >&2
|
||||||
|
cat "$auth/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
grep -q "^AUTH user secret\$" "$auth/socks.log" || {
|
||||||
|
echo "FAIL: wrong socks credentials sent" >&2
|
||||||
|
cat "$auth/socks.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
grep -qi "secret\|proxy-authorization" "$auth/origin-headers.log" && {
|
||||||
|
echo "FAIL: socks credentials leaked into the origin request" >&2
|
||||||
|
cat "$auth/origin-headers.log" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK: socks5 user/pass negotiated, creds not leaked to origin"
|
||||||
|
|
||||||
|
# --- hostile: refusing proxy ------------------------------------------------
|
||||||
|
ref="$tmpdir/refuse"
|
||||||
|
start_server "$ref" refuse
|
||||||
|
rc=0
|
||||||
|
run_crawl "$ref/out" "https://${host}:${tls_port}/" "socks5://127.0.0.1:${socks_port}" || rc=$?
|
||||||
|
test "$rc" -ne "$HANG_RC" || {
|
||||||
|
echo "FAIL: crawl hung on a refusing socks proxy" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
grep -rq "ORIGIN-PAGE-563" "$ref/out" 2>/dev/null && {
|
||||||
|
echo "FAIL: refusing proxy unexpectedly served the page" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK: refusing socks proxy fails cleanly, no hang"
|
||||||
|
|
||||||
|
# --- hostile: truncated handshake reply -------------------------------------
|
||||||
|
trunc="$tmpdir/trunc"
|
||||||
|
start_server "$trunc" truncate
|
||||||
|
rc=0
|
||||||
|
run_crawl "$trunc/out" "https://${host}:${tls_port}/" "socks5://127.0.0.1:${socks_port}" || rc=$?
|
||||||
|
test "$rc" -ne "$HANG_RC" || {
|
||||||
|
echo "FAIL: crawl hung on a truncated socks reply (bounded read missing)" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
grep -rq "ORIGIN-PAGE-563" "$trunc/out" 2>/dev/null && {
|
||||||
|
echo "FAIL: truncated-reply proxy unexpectedly served the page" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "OK: bounded socks handshake, no hang on a truncated reply"
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
# explicitly: automake does not expand wildcards in EXTRA_DIST, so a glob would
|
# explicitly: automake does not expand wildcards in EXTRA_DIST, so a glob would
|
||||||
# silently drop it from the dist tarball and break "make distcheck".
|
# silently drop it from the dist tarball and break "make distcheck".
|
||||||
EXTRA_DIST = $(TESTS) crawl-test.sh run-all-tests.sh check-network.sh \
|
EXTRA_DIST = $(TESTS) crawl-test.sh run-all-tests.sh check-network.sh \
|
||||||
proxy-https-server.py \
|
proxy-https-server.py socks5-server.py \
|
||||||
local-crawl.sh local-server.py server.crt server.key \
|
local-crawl.sh local-server.py server.crt server.key \
|
||||||
server-root/simple/basic.html server-root/simple/link.html \
|
server-root/simple/basic.html server-root/simple/link.html \
|
||||||
server-root/stripquery/index.html server-root/stripquery/a.html \
|
server-root/stripquery/index.html server-root/stripquery/a.html \
|
||||||
@@ -15,6 +15,8 @@ TESTS_ENVIRONMENT += PATH=$(top_builddir)/src$(PATH_SEPARATOR)$$PATH
|
|||||||
### TESTS_ENVIRONMENT += $(SHLIBPATH_VAR)="$(top_builddir)/src/$(LT_CV_OBJDIR)$${$(SHLIBPATH_VAR):+$(PATH_SEPARATOR)}$$$(SHLIBPATH_VAR)"
|
### TESTS_ENVIRONMENT += $(SHLIBPATH_VAR)="$(top_builddir)/src/$(LT_CV_OBJDIR)$${$(SHLIBPATH_VAR):+$(PATH_SEPARATOR)}$$$(SHLIBPATH_VAR)"
|
||||||
TESTS_ENVIRONMENT += ONLINE_UNIT_TESTS=$(ONLINE_UNIT_TESTS)
|
TESTS_ENVIRONMENT += ONLINE_UNIT_TESTS=$(ONLINE_UNIT_TESTS)
|
||||||
TESTS_ENVIRONMENT += HTTPS_SUPPORT=$(HTTPS_SUPPORT)
|
TESTS_ENVIRONMENT += HTTPS_SUPPORT=$(HTTPS_SUPPORT)
|
||||||
|
TESTS_ENVIRONMENT += BROTLI_ENABLED=$(BROTLI_ENABLED)
|
||||||
|
TESTS_ENVIRONMENT += ZSTD_ENABLED=$(ZSTD_ENABLED)
|
||||||
TESTS_ENVIRONMENT += V6_SUPPORT=$(V6_SUPPORT)
|
TESTS_ENVIRONMENT += V6_SUPPORT=$(V6_SUPPORT)
|
||||||
TESTS_ENVIRONMENT += top_srcdir=$(top_srcdir)
|
TESTS_ENVIRONMENT += top_srcdir=$(top_srcdir)
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@ TESTS = \
|
|||||||
01_engine-cmdline.test \
|
01_engine-cmdline.test \
|
||||||
01_engine-cookies.test \
|
01_engine-cookies.test \
|
||||||
01_engine-copyopt.test \
|
01_engine-copyopt.test \
|
||||||
|
01_engine-crange.test \
|
||||||
01_engine-dns.test \
|
01_engine-dns.test \
|
||||||
01_engine-doitlog.test \
|
01_engine-doitlog.test \
|
||||||
01_engine-entities.test \
|
01_engine-entities.test \
|
||||||
@@ -43,9 +46,11 @@ TESTS = \
|
|||||||
01_engine-header.test \
|
01_engine-header.test \
|
||||||
01_engine-idna.test \
|
01_engine-idna.test \
|
||||||
01_engine-identurl.test \
|
01_engine-identurl.test \
|
||||||
|
01_engine-proxyurl.test \
|
||||||
|
01_engine-socks5.test \
|
||||||
|
01_engine-identabs.test \
|
||||||
01_engine-escape-room.test \
|
01_engine-escape-room.test \
|
||||||
01_engine-inplace-escape.test \
|
01_engine-inplace-escape.test \
|
||||||
01_engine-java.test \
|
|
||||||
01_engine-makeindex.test \
|
01_engine-makeindex.test \
|
||||||
01_engine-mime.test \
|
01_engine-mime.test \
|
||||||
01_engine-parse.test \
|
01_engine-parse.test \
|
||||||
@@ -65,7 +70,10 @@ TESTS = \
|
|||||||
01_engine-urlhack.test \
|
01_engine-urlhack.test \
|
||||||
01_engine-unescape-bounds.test \
|
01_engine-unescape-bounds.test \
|
||||||
01_engine-useragent.test \
|
01_engine-useragent.test \
|
||||||
|
01_engine-version-macros.test \
|
||||||
|
01_engine-xfread.test \
|
||||||
01_zlib-acceptencoding.test \
|
01_zlib-acceptencoding.test \
|
||||||
|
01_zlib-contentcodings.test \
|
||||||
01_zlib-cache.test \
|
01_zlib-cache.test \
|
||||||
01_zlib-cache-corrupt.test \
|
01_zlib-cache-corrupt.test \
|
||||||
01_zlib-cache-legacy.test \
|
01_zlib-cache-legacy.test \
|
||||||
@@ -100,7 +108,6 @@ TESTS = \
|
|||||||
28_local-pause.test \
|
28_local-pause.test \
|
||||||
29_local-redirect-fragment.test \
|
29_local-redirect-fragment.test \
|
||||||
30_local-fragment-link.test \
|
30_local-fragment-link.test \
|
||||||
31_local-javaclass.test \
|
|
||||||
32_local-cdispo.test \
|
32_local-cdispo.test \
|
||||||
33_local-delayed.test \
|
33_local-delayed.test \
|
||||||
34_local-maxtime.test \
|
34_local-maxtime.test \
|
||||||
@@ -113,6 +120,14 @@ TESTS = \
|
|||||||
41_local-utf8-link.test \
|
41_local-utf8-link.test \
|
||||||
42_local-maxsize-slow.test \
|
42_local-maxsize-slow.test \
|
||||||
43_local-update-truncate.test \
|
43_local-update-truncate.test \
|
||||||
44_local-update-errormask.test
|
44_local-update-errormask.test \
|
||||||
|
45_local-maxsize-recv.test \
|
||||||
|
46_local-update-304-resume.test \
|
||||||
|
47_local-crange-overflow.test \
|
||||||
|
48_local-crange-memresume.test \
|
||||||
|
49_local-cookiewall.test \
|
||||||
|
50_local-contentcodings.test \
|
||||||
|
51_local-update-codec.test \
|
||||||
|
52_local-socks5.test
|
||||||
|
|
||||||
CLEANFILES = check-network_sh.cache
|
CLEANFILES = check-network_sh.cache
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ function start-crawl {
|
|||||||
log="${tmp}/log"
|
log="${tmp}/log"
|
||||||
debug starting httrack -O "${tmp}" "${moreargs[@]}" "${@:pos}"
|
debug starting httrack -O "${tmp}" "${moreargs[@]}" "${@:pos}"
|
||||||
info "running httrack ${*:pos}"
|
info "running httrack ${*:pos}"
|
||||||
httrack -O "${tmp}" --user-agent="httrack $ver ut ($(uname -omrs))" "${moreargs[@]}" "${@:pos}" >"${log}" 2>&1 &
|
httrack -O "${tmp}" --user-agent="httrack $ver ut ($(uname -mrs))" "${moreargs[@]}" "${@:pos}" >"${log}" 2>&1 &
|
||||||
crawlpid="$!"
|
crawlpid="$!"
|
||||||
debug "started cralwer on pid $crawlpid"
|
debug "started cralwer on pid $crawlpid"
|
||||||
wait "$crawlpid"
|
wait "$crawlpid"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# --errors N --errors-content N --files N --found PATH ... --directory PATH ... \
|
# --errors N --errors-content N --files N --found PATH ... --directory PATH ... \
|
||||||
# --log-found REGEX ... --log-not-found REGEX ... \
|
# --log-found REGEX ... --log-not-found REGEX ... \
|
||||||
# --file-matches PATH REGEX ... --file-not-matches PATH REGEX ... \
|
# --file-matches PATH REGEX ... --file-not-matches PATH REGEX ... \
|
||||||
# --file-min-bytes PATH N --max-mirror-bytes N \
|
# --file-min-bytes PATH N --file-mode PATH OCTAL --max-mirror-bytes N \
|
||||||
# httrack BASEURL/some/path [httrack-args...]
|
# httrack BASEURL/some/path [httrack-args...]
|
||||||
# --errors counts every "Error:" log line; --errors-content drops transient
|
# --errors counts every "Error:" log line; --errors-content drops transient
|
||||||
# network failures (codes -2..-6) that flake on busy loopback under -c8.
|
# network failures (codes -2..-6) that flake on busy loopback under -c8.
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
# --file-matches/--file-not-matches grep (ERE) a mirrored file (PATH under the
|
# --file-matches/--file-not-matches grep (ERE) a mirrored file (PATH under the
|
||||||
# host root), to assert rewritten link/content survived the crawl.
|
# host root), to assert rewritten link/content survived the crawl.
|
||||||
# --file-min-bytes asserts a mirrored file (PATH) is at least N bytes.
|
# --file-min-bytes asserts a mirrored file (PATH) is at least N bytes.
|
||||||
|
# --file-mode asserts its octal permissions (e.g. 644); POSIX hosts only.
|
||||||
# --rerun-args runs a second pass (same server and mirror dir) with the given
|
# --rerun-args runs a second pass (same server and mirror dir) with the given
|
||||||
# extra httrack args appended, e.g. an --update run under a cap.
|
# extra httrack args appended, e.g. an --update run under a cap.
|
||||||
# --cookie writes a Netscape cookies.txt (scoped to the discovered host:port,
|
# --cookie writes a Netscape cookies.txt (scoped to the discovered host:port,
|
||||||
@@ -141,7 +142,7 @@ while test "$pos" -lt "$nargs"; do
|
|||||||
audit+=("${args[$pos]}" "${args[$((pos + 1))]}")
|
audit+=("${args[$pos]}" "${args[$((pos + 1))]}")
|
||||||
pos=$((pos + 1))
|
pos=$((pos + 1))
|
||||||
;;
|
;;
|
||||||
--file-matches | --file-not-matches | --file-min-bytes)
|
--file-matches | --file-not-matches | --file-min-bytes | --file-mode)
|
||||||
audit+=("${args[$pos]}" "${args[$((pos + 1))]}" "${args[$((pos + 2))]}")
|
audit+=("${args[$pos]}" "${args[$((pos + 1))]}" "${args[$((pos + 2))]}")
|
||||||
pos=$((pos + 2))
|
pos=$((pos + 2))
|
||||||
;;
|
;;
|
||||||
@@ -213,7 +214,7 @@ mkdir "$out" || die "could not create $out"
|
|||||||
declare -a moreargs=(--quiet --max-time=120 --timeout=30 --disable-security-limits --robots=0)
|
declare -a moreargs=(--quiet --max-time=120 --timeout=30 --disable-security-limits --robots=0)
|
||||||
log="${tmpdir}/log"
|
log="${tmpdir}/log"
|
||||||
info "running httrack ${hts[*]}"
|
info "running httrack ${hts[*]}"
|
||||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -omrs))" "${moreargs[@]}" "${hts[@]}" >"$log" 2>&1 &
|
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" "${moreargs[@]}" "${hts[@]}" >"$log" 2>&1 &
|
||||||
crawlpid=$!
|
crawlpid=$!
|
||||||
wait "$crawlpid"
|
wait "$crawlpid"
|
||||||
crawlres=$?
|
crawlres=$?
|
||||||
@@ -230,7 +231,7 @@ grep -iE "^[0-9:]*[[:space:]]Error:" "${out}/hts-log.txt" >&2
|
|||||||
# --- optional second pass: re-mirror into the same dir (cache/update path) ----
|
# --- optional second pass: re-mirror into the same dir (cache/update path) ----
|
||||||
if test -n "$rerun"; then
|
if test -n "$rerun"; then
|
||||||
info "re-running httrack (update pass)"
|
info "re-running httrack (update pass)"
|
||||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -omrs))" \
|
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||||
"${moreargs[@]}" "${hts[@]}" >"${log}.2" 2>&1 &
|
"${moreargs[@]}" "${hts[@]}" >"${log}.2" 2>&1 &
|
||||||
crawlpid=$!
|
crawlpid=$!
|
||||||
wait "$crawlpid"
|
wait "$crawlpid"
|
||||||
@@ -258,7 +259,7 @@ fi
|
|||||||
if test -n "$rerun_args"; then
|
if test -n "$rerun_args"; then
|
||||||
read -ra extra <<<"$rerun_args"
|
read -ra extra <<<"$rerun_args"
|
||||||
info "re-running httrack with ${rerun_args}"
|
info "re-running httrack with ${rerun_args}"
|
||||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -omrs))" \
|
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||||
"${moreargs[@]}" "${hts[@]}" "${extra[@]}" >"${log}.2" 2>&1 &
|
"${moreargs[@]}" "${hts[@]}" "${extra[@]}" >"${log}.2" 2>&1 &
|
||||||
crawlpid=$!
|
crawlpid=$!
|
||||||
wait "$crawlpid"
|
wait "$crawlpid"
|
||||||
@@ -281,7 +282,7 @@ if test -n "$rerun_dead"; then
|
|||||||
wait "$serverpid" 2>/dev/null
|
wait "$serverpid" 2>/dev/null
|
||||||
serverpid=
|
serverpid=
|
||||||
info "re-running httrack against the stopped server"
|
info "re-running httrack against the stopped server"
|
||||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -omrs))" \
|
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||||
"${moreargs[@]}" "${hts[@]}" >"${log}.dead" 2>&1 &
|
"${moreargs[@]}" "${hts[@]}" >"${log}.dead" 2>&1 &
|
||||||
crawlpid=$!
|
crawlpid=$!
|
||||||
wait "$crawlpid" || true
|
wait "$crawlpid" || true
|
||||||
@@ -319,9 +320,10 @@ done
|
|||||||
test -n "$hostroot" || die "could not find host root under $out"
|
test -n "$hostroot" || die "could not find host root under $out"
|
||||||
debug "host root: $hostroot"
|
debug "host root: $hostroot"
|
||||||
|
|
||||||
# No crawl, even a cancelled one, may leave .delayed temporaries (#107, #483).
|
# No crawl, even a cancelled one, may leave engine temporaries: .delayed (#107,
|
||||||
info "checking for leftover .delayed files"
|
# #483), or the .z/.u content-coding temps (#557).
|
||||||
leftovers=$(find "$out" -name '*.delayed' 2>/dev/null | head -5)
|
info "checking for leftover engine temporaries"
|
||||||
|
leftovers=$(find "$out" \( -name '*.delayed' -o -name '*.z' -o -name '*.u' \) 2>/dev/null | head -5)
|
||||||
if test -z "$leftovers"; then result "OK"; else
|
if test -z "$leftovers"; then result "OK"; else
|
||||||
result "leftover: $leftovers"
|
result "leftover: $leftovers"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -436,6 +438,17 @@ while test "$i" -lt "${#audit[@]}"; do
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
--file-mode)
|
||||||
|
path="${audit[$((i + 1))]}"
|
||||||
|
i=$((i + 2))
|
||||||
|
mode=$(stat -c '%a' "${hostroot}/${path}" 2>/dev/null ||
|
||||||
|
stat -f '%Lp' "${hostroot}/${path}" 2>/dev/null)
|
||||||
|
info "checking ${path} mode ${mode:-none} is ${audit[$i]}"
|
||||||
|
if test "$mode" = "${audit[$i]}"; then result "OK"; else
|
||||||
|
result "wrong mode"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ stdlib only (http.server + ssl) -- no new build or runtime dependency.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import base64
|
||||||
import gzip
|
import gzip
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
@@ -633,6 +634,149 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
extra_headers=[("Content-Encoding", "gzip")],
|
extra_headers=[("Content-Encoding", "gzip")],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- content codings ---------------------------------------------------
|
||||||
|
# Canned br/zstd bodies (no brotli/zstd module in the stdlib): both decode
|
||||||
|
# to CODEC_BODY. Regenerate with the brotli/zstd CLIs over that string.
|
||||||
|
CODEC_BODY = (
|
||||||
|
b"<html><head><title>codec</title></head>"
|
||||||
|
b"<body><p>coded body</p></body></html>"
|
||||||
|
)
|
||||||
|
CODEC_BR = base64.b64decode(
|
||||||
|
"G0sAAAQccqSBBfJlUvOccsDeitqC9CbHwENWiptQj5aExP0mBjjVgy2DF17olLzLo2T2Eg=="
|
||||||
|
)
|
||||||
|
CODEC_ZSTD = base64.b64decode(
|
||||||
|
"KLUv/SBMFQIAFAM8aHRtbD48aGVhZD48dGl0bGU+Y29kZWM8LzwvYm9keT48"
|
||||||
|
"cGQgPC9wPjwvL2h0bWw+BQA7p8QMDNQ1PgcWhjkG"
|
||||||
|
)
|
||||||
|
|
||||||
|
def route_codec_index(self):
|
||||||
|
self.send_html(
|
||||||
|
'\t<a href="br.html">br</a>\n'
|
||||||
|
'\t<a href="zstd.html">zstd</a>\n'
|
||||||
|
'\t<a href="junk.html">junk</a>\n'
|
||||||
|
'\t<a href="bad.html">bad</a>\n'
|
||||||
|
'\t<a href="bin.dat">bin</a>\n'
|
||||||
|
'\t<a href="ae.html">ae</a>\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
def route_codec_br(self):
|
||||||
|
self.send_raw(
|
||||||
|
self.CODEC_BR, "text/html", extra_headers=[("Content-Encoding", "br")]
|
||||||
|
)
|
||||||
|
|
||||||
|
def route_codec_zstd(self):
|
||||||
|
self.send_raw(
|
||||||
|
self.CODEC_ZSTD, "text/html", extra_headers=[("Content-Encoding", "zstd")]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Junk token on a plain body: the page must survive (broken servers do this)
|
||||||
|
def route_codec_junk(self):
|
||||||
|
self.send_raw(
|
||||||
|
b"<html><body><p>junk coding</p></body></html>",
|
||||||
|
"text/html",
|
||||||
|
extra_headers=[("Content-Encoding", "utf-8")],
|
||||||
|
)
|
||||||
|
|
||||||
|
# A real coding we have no decoder for: the fetch must fail rather than
|
||||||
|
# save the coded bytes as the page.
|
||||||
|
def route_codec_bad(self):
|
||||||
|
self.send_raw(
|
||||||
|
b"<html><body><p>never decoded</p></body></html>",
|
||||||
|
"text/html",
|
||||||
|
extra_headers=[("Content-Encoding", "compress")],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Same, on a non-HTML body: this takes the direct-to-disk (is_write) branch,
|
||||||
|
# a different discard path than the in-memory bad.html above.
|
||||||
|
def route_codec_bin(self):
|
||||||
|
self.send_raw(
|
||||||
|
b"\x00\x01\x02 CODED-BINARY-MUST-NOT-LAND \xff\xfe" * 8,
|
||||||
|
"application/octet-stream",
|
||||||
|
extra_headers=[("Content-Encoding", "compress")],
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- coded re-fetch that fails to decode (#557) -------------------------
|
||||||
|
# Pass 1 mirrors each file from a valid gzip body; pass 2 (--update) serves
|
||||||
|
# a body that cannot be decoded. The previously-mirrored copy must survive.
|
||||||
|
# fresh.html is the control: its pass-2 body decodes, so it must be updated.
|
||||||
|
UPCODEC_SEEN = {}
|
||||||
|
|
||||||
|
def upcodec_pass(self):
|
||||||
|
"""1 on the first body fetch of this path, 2 on the next ones. HEADs
|
||||||
|
don't count, so a stray one can't shift which pass gets the bad body."""
|
||||||
|
if self.command == "HEAD":
|
||||||
|
return 1
|
||||||
|
seen = Handler.UPCODEC_SEEN.get(self.path, 0) + 1
|
||||||
|
Handler.UPCODEC_SEEN[self.path] = seen
|
||||||
|
return seen
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def gzipped(body):
|
||||||
|
return gzip.compress(body)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bad_gzip(body):
|
||||||
|
"""A gzip stream whose deflate payload is mangled: inflate fails partway
|
||||||
|
through, after some plausible output has already been produced."""
|
||||||
|
raw = bytearray(gzip.compress(body))
|
||||||
|
raw[20:40] = b"\xff" * 20
|
||||||
|
return bytes(raw[:-4])
|
||||||
|
|
||||||
|
def send_coded(self, body, content_type, coding="gzip"):
|
||||||
|
self.send_raw(body, content_type, extra_headers=[("Content-Encoding", coding)])
|
||||||
|
|
||||||
|
def route_upcodec_index(self):
|
||||||
|
self.send_html(
|
||||||
|
'\t<a href="mem.html">mem</a>\n'
|
||||||
|
'\t<a href="disk.bin">disk</a>\n'
|
||||||
|
'\t<a href="unsup.html">unsup</a>\n'
|
||||||
|
'\t<a href="fresh.html">fresh</a>\n'
|
||||||
|
'\t<a href="freshdisk.bin">freshdisk</a>\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
MEM_V1 = b"<html><body><p>MIRRORED-MEM-V1</p></body></html>"
|
||||||
|
DISK_V1 = b"MIRRORED-DISK-V1\n" + b"\x00\x01\x02\xff" * 8192
|
||||||
|
UNSUP_V1 = b"<html><body><p>MIRRORED-UNSUP-V1</p></body></html>"
|
||||||
|
|
||||||
|
def route_upcodec_mem(self):
|
||||||
|
if self.upcodec_pass() == 1:
|
||||||
|
self.send_coded(self.gzipped(self.MEM_V1), "text/html")
|
||||||
|
else:
|
||||||
|
self.send_coded(self.bad_gzip(self.MEM_V1), "text/html")
|
||||||
|
|
||||||
|
def route_upcodec_disk(self):
|
||||||
|
if self.upcodec_pass() == 1:
|
||||||
|
self.send_coded(self.gzipped(self.DISK_V1), "application/octet-stream")
|
||||||
|
else:
|
||||||
|
self.send_coded(self.bad_gzip(self.DISK_V1), "application/octet-stream")
|
||||||
|
|
||||||
|
# Pass 2 switches to a coding we have no decoder for.
|
||||||
|
def route_upcodec_unsup(self):
|
||||||
|
if self.upcodec_pass() == 1:
|
||||||
|
self.send_coded(self.gzipped(self.UNSUP_V1), "text/html")
|
||||||
|
else:
|
||||||
|
self.send_coded(self.UNSUP_V1, "text/html", coding="compress")
|
||||||
|
|
||||||
|
def route_upcodec_fresh(self):
|
||||||
|
pass1 = self.upcodec_pass() == 1
|
||||||
|
body = b"<html><body><p>FRESH-V%d</p></body></html>" % (1 if pass1 else 2)
|
||||||
|
self.send_coded(self.gzipped(body), "text/html")
|
||||||
|
|
||||||
|
# Same, direct-to-disk: the update pass decodes, so the temp is renamed over
|
||||||
|
# an existing mirror file.
|
||||||
|
def route_upcodec_freshdisk(self):
|
||||||
|
pass1 = self.upcodec_pass() == 1
|
||||||
|
body = b"FRESHDISK-V%d\n" % (1 if pass1 else 2) + b"\x03\x02\x01\xfe" * 8192
|
||||||
|
self.send_coded(self.gzipped(body), "application/octet-stream")
|
||||||
|
|
||||||
|
# Echo what httrack advertised, so a crawl can assert the header.
|
||||||
|
def route_codec_ae(self):
|
||||||
|
self.send_raw(
|
||||||
|
b"<html><body><p>AE=%s</p></body></html>"
|
||||||
|
% self.headers.get("Accept-Encoding", "").encode(),
|
||||||
|
"text/html",
|
||||||
|
)
|
||||||
|
|
||||||
# --- MIME-type exclusion abort (issue #58) -----------------------------
|
# --- MIME-type exclusion abort (issue #58) -----------------------------
|
||||||
# A -mime:application/pdf filter must abort the transfer once the header
|
# A -mime:application/pdf filter must abort the transfer once the header
|
||||||
# arrives, not download the whole body and discard it.
|
# arrives, not download the whole body and discard it.
|
||||||
@@ -790,6 +934,56 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
self.send_header("Content-Length", "0")
|
self.send_header("Content-Length", "0")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
|
# C7: stall the first GET (partial + temp-ref), then answer the resume's
|
||||||
|
# Range with a bogus 304; httrack must drop the partial and refetch.
|
||||||
|
RESUME304_BODY = b"C7DATA--" + bytes((i * 7 + 3) % 256 for i in range(8192))
|
||||||
|
_resume304_started = False
|
||||||
|
|
||||||
|
def route_resume304_index(self):
|
||||||
|
self.send_html('\t<a href="blob.bin">blob</a>')
|
||||||
|
|
||||||
|
def route_resume304(self):
|
||||||
|
counter = os.environ.get("RESUME304_COUNTER")
|
||||||
|
if counter:
|
||||||
|
with open(counter, "a") as fp:
|
||||||
|
fp.write("x")
|
||||||
|
rng = self.headers.get("Range")
|
||||||
|
if not Handler._resume304_started:
|
||||||
|
Handler._resume304_started = True
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(self.RESUME304_BODY)))
|
||||||
|
self.send_header("Accept-Ranges", "bytes")
|
||||||
|
self.send_header("Last-Modified", BIG_LASTMOD)
|
||||||
|
self.send_header("ETag", '"c7"')
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(self.RESUME304_BODY[:4096])
|
||||||
|
self.wfile.flush()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(3600)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
if rng is not None: # resume request: bogus out-of-protocol 304
|
||||||
|
mark = os.environ.get("RESUME304_MARK")
|
||||||
|
if mark:
|
||||||
|
with open(mark, "a") as fp:
|
||||||
|
fp.write("z")
|
||||||
|
self.send_response(304)
|
||||||
|
self.send_header("ETag", '"c7"')
|
||||||
|
self.send_header("Content-Length", "0")
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
# Range-less refetch after the partial is dropped: whole file.
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(self.RESUME304_BODY)))
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(self.RESUME304_BODY)
|
||||||
|
|
||||||
# 206 resume must honor the server's Content-Range, not the offset we asked
|
# 206 resume must honor the server's Content-Range, not the offset we asked
|
||||||
# for (#198): a server resuming a few bytes *before* the request must not
|
# for (#198): a server resuming a few bytes *before* the request must not
|
||||||
# leave httrack duplicating the overlap onto the partial. flaky.bin
|
# leave httrack duplicating the overlap onto the partial. flaky.bin
|
||||||
@@ -855,6 +1049,94 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
if self.command != "HEAD":
|
if self.command != "HEAD":
|
||||||
self.wfile.write(part)
|
self.wfile.write(part)
|
||||||
|
|
||||||
|
# C2: a resume answered with a 206 whose Content-Range end is INT64_MAX would
|
||||||
|
# sign-overflow the crange+1 range check (UBSan abort). Stall first (partial +
|
||||||
|
# ref), then answer the resume Range with that hostile 206; httrack must reject
|
||||||
|
# the range and refetch, never overflow.
|
||||||
|
CRANGE206_BODY = b"CR206DAT" + bytes((i * 5 + 1) % 256 for i in range(6000))
|
||||||
|
_crange206_started = False
|
||||||
|
|
||||||
|
def route_crange206_index(self):
|
||||||
|
self.send_html('\t<a href="blob.bin">blob</a>')
|
||||||
|
|
||||||
|
def route_crange206(self):
|
||||||
|
rng = self.headers.get("Range")
|
||||||
|
if not Handler._crange206_started:
|
||||||
|
Handler._crange206_started = True
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(self.CRANGE206_BODY)))
|
||||||
|
self.send_header("Accept-Ranges", "bytes")
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(self.CRANGE206_BODY[:3000])
|
||||||
|
self.wfile.flush()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(3600)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
if rng is not None: # resume: hostile 206, Content-Range end = INT64_MAX
|
||||||
|
self.send_response(206, "Partial Content")
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(self.CRANGE206_BODY)))
|
||||||
|
self.send_header("Content-Range", "bytes 0-9223372036854775807/1")
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(self.CRANGE206_BODY)
|
||||||
|
return
|
||||||
|
# range-less refetch after the bad range is rejected: whole file.
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(self.CRANGE206_BODY)))
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(self.CRANGE206_BODY)
|
||||||
|
|
||||||
|
# C2 memory branch: a resume answered with a 206 that lies text/html (so the
|
||||||
|
# resume buffers in memory) plus a matching INT64_MAX Content-Length would
|
||||||
|
# overflow the buffer-size add. Stall first, then send that hostile 206.
|
||||||
|
_crange206mem_started = False
|
||||||
|
|
||||||
|
def route_crange206mem_index(self):
|
||||||
|
self.send_html('\t<a href="blob.bin">blob</a>')
|
||||||
|
|
||||||
|
def route_crange206mem(self):
|
||||||
|
rng = self.headers.get("Range")
|
||||||
|
if not Handler._crange206mem_started:
|
||||||
|
Handler._crange206mem_started = True
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(self.CRANGE206_BODY)))
|
||||||
|
self.send_header("Accept-Ranges", "bytes")
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(self.CRANGE206_BODY[:3000])
|
||||||
|
self.wfile.flush()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(3600)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
if rng is not None: # resume: text/html + matching INT64_MAX Content-Length
|
||||||
|
self.send_response(206, "Partial Content")
|
||||||
|
self.send_header("Content-Type", "text/html")
|
||||||
|
self.send_header("Content-Length", "9223372036854775807")
|
||||||
|
self.send_header(
|
||||||
|
"Content-Range", "bytes 0-9223372036854775806/9223372036854775807"
|
||||||
|
)
|
||||||
|
self.end_headers()
|
||||||
|
return # the overflow is computed before any body read
|
||||||
|
# range-less refetch after the resume is rejected: whole file.
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(self.CRANGE206_BODY)))
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(self.CRANGE206_BODY)
|
||||||
|
|
||||||
# error pages / 0-byte files (#17): -o0 ("no error pages") must keep 4xx/5xx
|
# error pages / 0-byte files (#17): -o0 ("no error pages") must keep 4xx/5xx
|
||||||
# bodies off disk; a genuine 0-byte 200 is a valid file and stays.
|
# bodies off disk; a genuine 0-byte 200 is a valid file and stays.
|
||||||
def route_errpage_index(self):
|
def route_errpage_index(self):
|
||||||
@@ -1005,6 +1287,56 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
def route_delayed_empty(self):
|
def route_delayed_empty(self):
|
||||||
self.send_raw(b"", "text/html") # 200 + Content-Length: 0
|
self.send_raw(b"", "text/html") # 200 + Content-Length: 0
|
||||||
|
|
||||||
|
# --- /cookiewall/ (#15): a self-redirect that only sets a cookie is a
|
||||||
|
# consent wall; httrack must replay the cookie and fetch the real page.
|
||||||
|
WALL_MARK = b"REAL-CONTENT-BEHIND-COOKIE-WALL"
|
||||||
|
|
||||||
|
def route_cookiewall_index(self):
|
||||||
|
self.send_html('\t<a href="wall.php">wall</a>')
|
||||||
|
|
||||||
|
def route_cookiewall_wall(self):
|
||||||
|
self._cookiewall_reply("wall.php")
|
||||||
|
|
||||||
|
# Known-extension twin: .html so the type is not delayed-resolved.
|
||||||
|
def route_cookiewall2_index(self):
|
||||||
|
self.send_html('\t<a href="wall.html">wall</a>')
|
||||||
|
|
||||||
|
def route_cookiewall2_wall(self):
|
||||||
|
self._cookiewall_reply("wall.html")
|
||||||
|
|
||||||
|
def _cookiewall_reply(self, location):
|
||||||
|
if self.request_cookies().get("gate") == "1":
|
||||||
|
self.send_raw(
|
||||||
|
b"<html><body>" + self.WALL_MARK + b"</body></html>\n", "text/html"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._wall_redirect(location, "gate=1; Path=/")
|
||||||
|
|
||||||
|
# No-cookie self-redirect: the jar never changes, so httrack must give up at
|
||||||
|
# once rather than re-fetch (proves the cookie-wall retry stays gated on #15).
|
||||||
|
def route_cookiewall3_index(self):
|
||||||
|
self.send_html('\t<a href="wall.php">wall</a>')
|
||||||
|
|
||||||
|
def route_cookiewall3_wall(self):
|
||||||
|
self._wall_redirect("wall.php", None)
|
||||||
|
|
||||||
|
# Ever-changing cookie: every hit sets a fresh value, so the jar keeps
|
||||||
|
# changing; httrack must stop at the loops<7 cap, not spin forever.
|
||||||
|
def route_cookiewall4_index(self):
|
||||||
|
self.send_html('\t<a href="wall.php">wall</a>')
|
||||||
|
|
||||||
|
def route_cookiewall4_wall(self):
|
||||||
|
nonce = int(self.request_cookies().get("gate", "0")) + 1
|
||||||
|
self._wall_redirect("wall.php", f"gate={nonce}; Path=/")
|
||||||
|
|
||||||
|
def _wall_redirect(self, location, set_cookie):
|
||||||
|
self.send_response(302, "Found")
|
||||||
|
self.send_header("Location", location)
|
||||||
|
if set_cookie is not None:
|
||||||
|
self.send_header("Set-Cookie", set_cookie)
|
||||||
|
self.send_header("Content-Length", "0")
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
# -E time-limit (#481): pages that trickle far longer than any -E budget,
|
# -E time-limit (#481): pages that trickle far longer than any -E budget,
|
||||||
# so only an engine-side abort can end the crawl.
|
# so only an engine-side abort can end the crawl.
|
||||||
TRICKLE_SECONDS = 60
|
TRICKLE_SECONDS = 60
|
||||||
@@ -1104,6 +1436,22 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# -M received-volume cap (#520): links to large 404 bodies. httrack receives
|
||||||
|
# each (HTS_TOTAL_RECV climbs) but saves none, so saved stays far below -M.
|
||||||
|
def route_maxrecv_index(self):
|
||||||
|
self.send_html(
|
||||||
|
"".join('\t<a href="r%d.bin">r%d</a>\n' % (i, i) for i in range(16))
|
||||||
|
)
|
||||||
|
|
||||||
|
def route_maxrecv_404(self):
|
||||||
|
body = b"x" * self.BIGFILE_BYTES
|
||||||
|
self.send_response(404, "Not Found")
|
||||||
|
self.send_header("Content-Type", "application/octet-stream")
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(body)
|
||||||
|
|
||||||
ROUTES = {
|
ROUTES = {
|
||||||
"/cookies/entrance.php": route_entrance,
|
"/cookies/entrance.php": route_entrance,
|
||||||
"/cookies/second.php": route_second,
|
"/cookies/second.php": route_second,
|
||||||
@@ -1111,6 +1459,19 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
"/gated/index.php": route_gated_index,
|
"/gated/index.php": route_gated_index,
|
||||||
"/gated/secret.php": route_gated_secret,
|
"/gated/secret.php": route_gated_secret,
|
||||||
"/robots.txt": route_robots,
|
"/robots.txt": route_robots,
|
||||||
|
"/codec/index.html": route_codec_index,
|
||||||
|
"/codec/br.html": route_codec_br,
|
||||||
|
"/codec/zstd.html": route_codec_zstd,
|
||||||
|
"/codec/junk.html": route_codec_junk,
|
||||||
|
"/codec/bad.html": route_codec_bad,
|
||||||
|
"/codec/bin.dat": route_codec_bin,
|
||||||
|
"/codec/ae.html": route_codec_ae,
|
||||||
|
"/upcodec/index.html": route_upcodec_index,
|
||||||
|
"/upcodec/mem.html": route_upcodec_mem,
|
||||||
|
"/upcodec/disk.bin": route_upcodec_disk,
|
||||||
|
"/upcodec/unsup.html": route_upcodec_unsup,
|
||||||
|
"/upcodec/fresh.html": route_upcodec_fresh,
|
||||||
|
"/upcodec/freshdisk.bin": route_upcodec_freshdisk,
|
||||||
"/types/index.html": route_types_index,
|
"/types/index.html": route_types_index,
|
||||||
"/types/control.php": route_types,
|
"/types/control.php": route_types,
|
||||||
"/types/photo.png": route_types,
|
"/types/photo.png": route_types,
|
||||||
@@ -1133,9 +1494,15 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
"/intl/" + INTL_NAME: route_intl_page,
|
"/intl/" + INTL_NAME: route_intl_page,
|
||||||
"/resume/index.html": route_resume_index,
|
"/resume/index.html": route_resume_index,
|
||||||
"/resume/blob.txt": route_resume,
|
"/resume/blob.txt": route_resume,
|
||||||
|
"/resume304/index.html": route_resume304_index,
|
||||||
|
"/resume304/blob.bin": route_resume304,
|
||||||
"/overlap/index.html": route_overlap_index,
|
"/overlap/index.html": route_overlap_index,
|
||||||
"/overlap/flaky.bin": route_overlap,
|
"/overlap/flaky.bin": route_overlap,
|
||||||
"/overlap/full.bin": route_overlap_full,
|
"/overlap/full.bin": route_overlap_full,
|
||||||
|
"/crange206/index.html": route_crange206_index,
|
||||||
|
"/crange206/blob.bin": route_crange206,
|
||||||
|
"/crange206mem/index.html": route_crange206mem_index,
|
||||||
|
"/crange206mem/blob.bin": route_crange206mem,
|
||||||
"/size/index.html": route_size_index,
|
"/size/index.html": route_size_index,
|
||||||
"/size/oversize.bin": route_size_oversize,
|
"/size/oversize.bin": route_size_oversize,
|
||||||
"/errpage/index.html": route_errpage_index,
|
"/errpage/index.html": route_errpage_index,
|
||||||
@@ -1199,6 +1566,14 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
"/delayed/chain7.php": route_delayed_chain,
|
"/delayed/chain7.php": route_delayed_chain,
|
||||||
"/delayed/chain8.php": route_delayed_chain,
|
"/delayed/chain8.php": route_delayed_chain,
|
||||||
"/delayed/chain9.php": route_delayed_chain,
|
"/delayed/chain9.php": route_delayed_chain,
|
||||||
|
"/cookiewall/index.html": route_cookiewall_index,
|
||||||
|
"/cookiewall/wall.php": route_cookiewall_wall,
|
||||||
|
"/cookiewall2/index.html": route_cookiewall2_index,
|
||||||
|
"/cookiewall2/wall.html": route_cookiewall2_wall,
|
||||||
|
"/cookiewall3/index.html": route_cookiewall3_index,
|
||||||
|
"/cookiewall3/wall.php": route_cookiewall3_wall,
|
||||||
|
"/cookiewall4/index.html": route_cookiewall4_index,
|
||||||
|
"/cookiewall4/wall.php": route_cookiewall4_wall,
|
||||||
"/redir/index.html": route_redir_index,
|
"/redir/index.html": route_redir_index,
|
||||||
"/redir/go.php": route_redir_go,
|
"/redir/go.php": route_redir_go,
|
||||||
"/redir/target.html": route_redir_target,
|
"/redir/target.html": route_redir_target,
|
||||||
@@ -1206,6 +1581,23 @@ class Handler(SimpleHTTPRequestHandler):
|
|||||||
"/mini304/page.html": route_mini304_page,
|
"/mini304/page.html": route_mini304_page,
|
||||||
"/errmask/index.html": route_errmask_index,
|
"/errmask/index.html": route_errmask_index,
|
||||||
"/errmask/keep.dat": route_errmask_keep,
|
"/errmask/keep.dat": route_errmask_keep,
|
||||||
|
"/maxrecv/index.html": route_maxrecv_index,
|
||||||
|
"/maxrecv/r0.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r1.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r2.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r3.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r4.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r5.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r6.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r7.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r8.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r9.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r10.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r11.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r12.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r13.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r14.bin": route_maxrecv_404,
|
||||||
|
"/maxrecv/r15.bin": route_maxrecv_404,
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- /big/ seeded pseudo-site ------------------------------------------
|
# --- /big/ seeded pseudo-site ------------------------------------------
|
||||||
@@ -1410,7 +1802,12 @@ def main():
|
|||||||
def factory(*a, **kw):
|
def factory(*a, **kw):
|
||||||
return Handler(*a, directory=root, **kw)
|
return Handler(*a, directory=root, **kw)
|
||||||
|
|
||||||
httpd = ThreadingHTTPServer((args.bind, 0), factory)
|
# macOS/BSD drop SYNs when the listen backlog overflows (Linux is lenient);
|
||||||
|
# raise it from Python's default 5 so a busy -c8 crawl can't lose fetches.
|
||||||
|
class BacklogHTTPServer(ThreadingHTTPServer):
|
||||||
|
request_queue_size = 128
|
||||||
|
|
||||||
|
httpd = BacklogHTTPServer((args.bind, 0), factory)
|
||||||
|
|
||||||
if args.tls:
|
if args.tls:
|
||||||
import ssl
|
import ssl
|
||||||
|
|||||||
228
tests/socks5-server.py
Normal file
228
tests/socks5-server.py
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Local SOCKS5 proxy (RFC 1928/1929) + TLS and plain HTTP origins for #563.
|
||||||
|
|
||||||
|
Logs the auth method, any user/pass, and the CONNECT ATYP + literal domain, so
|
||||||
|
the test proves httrack sent a hostname (remote DNS) and negotiated auth.
|
||||||
|
Modes (argv[3]): ok | refuse (REP=5) | truncate (partial reply, must not hang).
|
||||||
|
Usage: socks5-server.py <cert.pem> <logdir> [mode]
|
||||||
|
Prints "TLS <port>", "HTTP <port>", "SOCKS <port>", "ready" on stdout.
|
||||||
|
"""
|
||||||
|
import http.server
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import socketserver
|
||||||
|
import ssl
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
|
||||||
|
# The one name the proxy answers for; a .invalid TLD never resolves (RFC 6761),
|
||||||
|
# so a locally-resolving client could not reach us -- success proves remote DNS.
|
||||||
|
REMOTE_HOST = b"socks-origin.invalid"
|
||||||
|
# index links the subpages so an -r3 crawl reuses one keep-alive socket
|
||||||
|
LINKS = "".join('<a href="/p%d.html">%d</a>' % (i, i) for i in range(1, 6))
|
||||||
|
ORIGIN_BODY = ("<html><body>ORIGIN-PAGE-563 " + LINKS + "</body></html>").encode()
|
||||||
|
SOCKS_LOG = "socks.log"
|
||||||
|
ORIGIN_LOG = "origin-headers.log"
|
||||||
|
|
||||||
|
|
||||||
|
def make_origin(logdir):
|
||||||
|
class Origin(http.server.BaseHTTPRequestHandler):
|
||||||
|
# HTTP/1.1 + a max>1 advertisement lets httrack keep the socket alive
|
||||||
|
protocol_version = "HTTP/1.1"
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
with open(os.path.join(logdir, ORIGIN_LOG), "a") as handle:
|
||||||
|
handle.write(
|
||||||
|
"REQUEST %s %s %s\n"
|
||||||
|
% (self.command, self.path, self.request_version)
|
||||||
|
)
|
||||||
|
for key in self.headers.keys():
|
||||||
|
handle.write(key + ": " + self.headers[key] + "\n")
|
||||||
|
if "p" in self.path and ".html" in self.path:
|
||||||
|
body = (
|
||||||
|
b"<html><body>SUBPAGE-563 " + self.path.encode() + b"</body></html>"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
body = ORIGIN_BODY
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "text/html")
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.send_header("Keep-Alive", "timeout=15, max=100")
|
||||||
|
self.send_header("Connection", "keep-alive")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
|
||||||
|
def log_message(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return Origin
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadingTCPServer(socketserver.ThreadingTCPServer):
|
||||||
|
allow_reuse_address = True
|
||||||
|
daemon_threads = True
|
||||||
|
|
||||||
|
|
||||||
|
def start_origin(logdir, certfile=None):
|
||||||
|
httpd = ThreadingTCPServer(("127.0.0.1", 0), make_origin(logdir))
|
||||||
|
if certfile is not None:
|
||||||
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
|
ctx.load_cert_chain(certfile)
|
||||||
|
httpd.socket = ctx.wrap_socket(httpd.socket, server_side=True)
|
||||||
|
port = httpd.socket.getsockname()[1]
|
||||||
|
threading.Thread(target=httpd.serve_forever, daemon=True).start()
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
|
def recvn(conn, n):
|
||||||
|
buf = b""
|
||||||
|
while len(buf) < n:
|
||||||
|
chunk = conn.recv(n - len(buf))
|
||||||
|
if not chunk:
|
||||||
|
raise OSError("short read")
|
||||||
|
buf += chunk
|
||||||
|
return buf
|
||||||
|
|
||||||
|
|
||||||
|
def pipe(src, dst):
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
data = src.recv(65536)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
dst.sendall(data)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
for sock in (src, dst):
|
||||||
|
try:
|
||||||
|
sock.shutdown(socket.SHUT_RDWR)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def log(logdir, line):
|
||||||
|
with open(os.path.join(logdir, SOCKS_LOG), "a") as handle:
|
||||||
|
handle.write(line + "\n")
|
||||||
|
|
||||||
|
|
||||||
|
def negotiate_auth(conn, logdir):
|
||||||
|
"""RFC 1928 greeting + RFC 1929 sub-negotiation. Returns True to proceed."""
|
||||||
|
ver, nmethods = recvn(conn, 2)
|
||||||
|
if ver != 0x05:
|
||||||
|
return False
|
||||||
|
methods = recvn(conn, nmethods)
|
||||||
|
if 0x02 in methods: # prefer user/pass so the auth test exercises RFC 1929
|
||||||
|
conn.sendall(b"\x05\x02")
|
||||||
|
(subver,) = recvn(conn, 1)
|
||||||
|
(ulen,) = recvn(conn, 1)
|
||||||
|
uname = recvn(conn, ulen)
|
||||||
|
(plen,) = recvn(conn, 1)
|
||||||
|
passwd = recvn(conn, plen)
|
||||||
|
log(logdir, "METHOD userpass")
|
||||||
|
log(logdir, "AUTH %s %s" % (uname.decode(), passwd.decode()))
|
||||||
|
conn.sendall(b"\x01\x00") # RFC 1929 success
|
||||||
|
elif 0x00 in methods:
|
||||||
|
conn.sendall(b"\x05\x00")
|
||||||
|
log(logdir, "METHOD noauth")
|
||||||
|
else:
|
||||||
|
conn.sendall(b"\x05\xff") # no acceptable method
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def read_request(conn, logdir):
|
||||||
|
"""RFC 1928 CONNECT. Logs CMD, ATYP, domain/addr, port. Returns dest port."""
|
||||||
|
ver, cmd, _rsv, atyp = recvn(conn, 4)
|
||||||
|
log(logdir, "CMD %d" % cmd)
|
||||||
|
if atyp == 0x01:
|
||||||
|
addr = socket.inet_ntoa(recvn(conn, 4))
|
||||||
|
log(logdir, "ATYP ipv4 %s" % addr)
|
||||||
|
elif atyp == 0x03:
|
||||||
|
(dlen,) = recvn(conn, 1)
|
||||||
|
domain = recvn(conn, dlen)
|
||||||
|
log(logdir, "ATYP domain %s" % domain.decode())
|
||||||
|
elif atyp == 0x04:
|
||||||
|
recvn(conn, 16)
|
||||||
|
log(logdir, "ATYP ipv6")
|
||||||
|
domain = b""
|
||||||
|
else:
|
||||||
|
return None, None
|
||||||
|
(port,) = struct.unpack(">H", recvn(conn, 2))
|
||||||
|
log(logdir, "PORT %d" % port)
|
||||||
|
name = domain if atyp == 0x03 else b""
|
||||||
|
return name, port
|
||||||
|
|
||||||
|
|
||||||
|
def reply(conn, rep):
|
||||||
|
conn.sendall(bytes([0x05, rep, 0x00, 0x01]) + b"\x00\x00\x00\x00" + b"\x00\x00")
|
||||||
|
|
||||||
|
|
||||||
|
def handle_socks(conn, logdir, mode):
|
||||||
|
try:
|
||||||
|
if not negotiate_auth(conn, logdir):
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
if mode == "truncate":
|
||||||
|
# one byte of the 10-byte reply, then hold the socket: the client
|
||||||
|
# must bound this handshake read and give up, not hang.
|
||||||
|
conn.sendall(b"\x05")
|
||||||
|
threading.Event().wait()
|
||||||
|
return
|
||||||
|
name, port = read_request(conn, logdir)
|
||||||
|
if mode == "refuse" or name != REMOTE_HOST or port is None:
|
||||||
|
reply(conn, 0x05) # connection refused
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
upstream = socket.create_connection(("127.0.0.1", port))
|
||||||
|
except OSError:
|
||||||
|
reply(conn, 0x05)
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
reply(conn, 0x00) # succeeded
|
||||||
|
threading.Thread(target=pipe, args=(conn, upstream), daemon=True).start()
|
||||||
|
pipe(upstream, conn)
|
||||||
|
except OSError:
|
||||||
|
try:
|
||||||
|
conn.close()
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def start_socks(logdir, mode):
|
||||||
|
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
srv.bind(("127.0.0.1", 0))
|
||||||
|
srv.listen(16)
|
||||||
|
port = srv.getsockname()[1]
|
||||||
|
|
||||||
|
def serve():
|
||||||
|
while True:
|
||||||
|
conn, _ = srv.accept()
|
||||||
|
threading.Thread(
|
||||||
|
target=handle_socks, args=(conn, logdir, mode), daemon=True
|
||||||
|
).start()
|
||||||
|
|
||||||
|
threading.Thread(target=serve, daemon=True).start()
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
certfile, logdir = sys.argv[1], sys.argv[2]
|
||||||
|
mode = sys.argv[3] if len(sys.argv) > 3 else "ok"
|
||||||
|
for name in (SOCKS_LOG, ORIGIN_LOG):
|
||||||
|
open(os.path.join(logdir, name), "w").close()
|
||||||
|
tls_port = start_origin(logdir, certfile)
|
||||||
|
http_port = start_origin(logdir, None)
|
||||||
|
socks_port = start_socks(logdir, mode)
|
||||||
|
print("TLS %d" % tls_port, flush=True)
|
||||||
|
print("HTTP %d" % http_port, flush=True)
|
||||||
|
print("SOCKS %d" % socks_port, flush=True)
|
||||||
|
print("ready", flush=True)
|
||||||
|
threading.Event().wait()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
99
tests/webhttrack-smoke.sh
Normal file
99
tests/webhttrack-smoke.sh
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Smoke-test an installed webhttrack: launch it with a stub browser and assert
|
||||||
|
# htsserver comes up and serves the web UI. Arg: the install prefix.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
prefix="${1:?usage: webhttrack-smoke.sh <install-prefix>}"
|
||||||
|
wht="$prefix/bin/webhttrack"
|
||||||
|
test -x "$wht" || {
|
||||||
|
echo "no webhttrack at $wht" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
work="$(mktemp -d)"
|
||||||
|
# webhttrack backgrounds htsserver, which outlives it; reap any stray one (scoped
|
||||||
|
# to this prefix) so a lingering server can never hold the CI step open.
|
||||||
|
trap 'pkill -f "$prefix/bin/htsserver" 2>/dev/null || true; rm -rf "$work"' EXIT
|
||||||
|
export HOME="$work/home"
|
||||||
|
mkdir -p "$HOME/websites"
|
||||||
|
marker="$work/marker"
|
||||||
|
|
||||||
|
stubdir="$work/bin"
|
||||||
|
mkdir -p "$stubdir"
|
||||||
|
|
||||||
|
# On Darwin webhttrack hardcodes "open -W", which launches a real GUI browser and
|
||||||
|
# blocks headless. Shadow uname so it takes the generic path and picks the stub
|
||||||
|
# browser below; htsserver and webhttrack's path resolution still run for real.
|
||||||
|
cat >"$stubdir/uname" <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
[ "${1:-}" = "-s" ] && {
|
||||||
|
echo Linux
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
exec /usr/bin/uname "$@"
|
||||||
|
EOF
|
||||||
|
chmod +x "$stubdir/uname"
|
||||||
|
|
||||||
|
# Stub browser: webhttrack tries its browser-name list in order and runs the
|
||||||
|
# first it finds, so shadow the first entry, "x-www-browser". It fetches the
|
||||||
|
# server URL and records PASS only for the working UI: the brand string AND the
|
||||||
|
# step-2 form action, which a truncated/degraded template page would lack (the
|
||||||
|
# bare title alone is not enough). htsserver only lives until webhttrack exits,
|
||||||
|
# so the check has to happen here.
|
||||||
|
# -a: the UI is served ISO-8859-1, so grep must not treat it as binary.
|
||||||
|
cat >"$stubdir/x-www-browser" <<EOF
|
||||||
|
#!/bin/bash
|
||||||
|
echo "stub browser invoked with: \$1" >&2
|
||||||
|
if body="\$(curl -fsSL --max-time 20 "\$1")" && printf '%s' "\$body" | grep -qai httrack && printf '%s' "\$body" | grep -qaF step2.html; then
|
||||||
|
echo PASS >"$marker"
|
||||||
|
else
|
||||||
|
echo "FAIL: unexpected response from \$1" >"$marker"
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chmod +x "$stubdir/x-www-browser"
|
||||||
|
export PATH="$stubdir:$prefix/bin:$PATH"
|
||||||
|
|
||||||
|
echo "launching webhttrack"
|
||||||
|
"$wht" </dev/null >"$work/webhttrack.log" 2>&1 &
|
||||||
|
whpid=$!
|
||||||
|
|
||||||
|
# Bounded poll for the marker (macOS has no timeout(1)); teardown below kills
|
||||||
|
# webhttrack and reaps htsserver, so the run is bounded without a watchdog.
|
||||||
|
for i in $(seq 1 45); do
|
||||||
|
test -f "$marker" && {
|
||||||
|
echo "marker written after ${i}s"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
kill -0 "$whpid" 2>/dev/null || {
|
||||||
|
echo "webhttrack exited on its own after ${i}s"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Reap webhttrack and the htsserver it spawned. Confirm death with a bounded poll
|
||||||
|
# (not a blocking wait, which could hang on macOS); SIGKILL if it ignores TERM.
|
||||||
|
echo "tearing down"
|
||||||
|
kill "$whpid" 2>/dev/null || true
|
||||||
|
if pkill -f "$prefix/bin/htsserver" 2>/dev/null; then
|
||||||
|
echo "reaped a lingering htsserver"
|
||||||
|
else
|
||||||
|
echo "no lingering htsserver"
|
||||||
|
fi
|
||||||
|
for _ in $(seq 1 10); do
|
||||||
|
kill -0 "$whpid" 2>/dev/null || break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
kill -9 "$whpid" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "--- webhttrack.log ---"
|
||||||
|
cat "$work/webhttrack.log" 2>/dev/null || true
|
||||||
|
echo "--- end ---"
|
||||||
|
echo "marker=[$(cat "$marker" 2>/dev/null || echo NONE)]"
|
||||||
|
|
||||||
|
if test "$(cat "$marker" 2>/dev/null || true)" = PASS; then
|
||||||
|
echo "webhttrack smoke: PASS"
|
||||||
|
else
|
||||||
|
echo "webhttrack smoke: FAIL" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user