mirror of
https://github.com/xroche/httrack.git
synced 2026-07-11 11:26:31 +03:00
Compare commits
1 Commits
codeql-wor
...
fix/urlhac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
600001b282 |
88
.github/workflows/ci.yml
vendored
88
.github/workflows/ci.yml
vendored
@@ -61,50 +61,6 @@ jobs:
|
|||||||
if: failure()
|
if: failure()
|
||||||
run: cat tests/test-suite.log 2>/dev/null || true
|
run: cat tests/test-suite.log 2>/dev/null || true
|
||||||
|
|
||||||
# Reproduce the Debian buildds: they build in a minimal chroot with no
|
|
||||||
# python3, so the local-server tests must SKIP (exit 77), not fail. GitHub
|
|
||||||
# runners ship python3, so every other job hides this path; here we remove it
|
|
||||||
# before `make check`. This is the guard that would have caught the 3.49.10-1
|
|
||||||
# FTBFS (28_local-pause failed instead of skipping when python3 was absent).
|
|
||||||
buildd-no-python3:
|
|
||||||
name: build (no python3, Debian buildd)
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Install build dependencies
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y --no-install-recommends \
|
|
||||||
build-essential autoconf automake libtool autoconf-archive \
|
|
||||||
zlib1g-dev libssl-dev
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
autoreconf -fi
|
|
||||||
./configure
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: make -j"$(nproc)"
|
|
||||||
|
|
||||||
- name: Test without python3
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
# Hide every python3* so `command -v python3` fails like it does in the
|
|
||||||
# buildd chroot; masking with /bin/false would still resolve.
|
|
||||||
sudo find /usr/bin /usr/local/bin -maxdepth 1 -name 'python3*' \
|
|
||||||
-exec mv {} {}.hidden \;
|
|
||||||
! command -v python3
|
|
||||||
make check
|
|
||||||
|
|
||||||
- name: Print the test log on failure
|
|
||||||
if: failure()
|
|
||||||
run: cat tests/test-suite.log 2>/dev/null || true
|
|
||||||
|
|
||||||
# Portability: build and test on macOS (Darwin/clang) on a native runner --
|
# Portability: build and test on macOS (Darwin/clang) on a native runner --
|
||||||
# no VM. The tree has no __APPLE__ branches, so Darwin exercises the
|
# no VM. The tree has no __APPLE__ branches, so Darwin exercises the
|
||||||
# generic-Unix path on a second libc and kernel. brew's openssl@3 is keg-only,
|
# generic-Unix path on a second libc and kernel. brew's openssl@3 is keg-only,
|
||||||
@@ -269,54 +225,14 @@ jobs:
|
|||||||
MSAN_OPTIONS: abort_on_error=1:halt_on_error=1
|
MSAN_OPTIONS: abort_on_error=1:halt_on_error=1
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# 01_engine-* only; zlib-dependent self-tests are named 01_zlib-* and
|
# Engine self-tests only; the cache trio pulls in uninstrumented zlib.
|
||||||
# skipped here (uninstrumented libz floods MSan with false positives).
|
tests="$(cd tests && ls 01_engine-*.test | grep -v -- '-cache' | tr '\n' ' ')"
|
||||||
tests="$(cd tests && ls 01_engine-*.test | tr '\n' ' ')"
|
|
||||||
make check TESTS="$tests"
|
make check TESTS="$tests"
|
||||||
|
|
||||||
- name: Print the test log on failure
|
- name: Print the test log on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
run: cat tests/test-suite.log 2>/dev/null || true
|
run: cat tests/test-suite.log 2>/dev/null || true
|
||||||
|
|
||||||
# libFuzzer smoke: build the fuzz/ harnesses over the pure hostile-input
|
|
||||||
# parsers and replay each seed corpus under ASan+UBSan+LeakSanitizer. Replay
|
|
||||||
# (not open-ended mutation) keeps CI deterministic -- it can't hit strjoker's
|
|
||||||
# catastrophic backtracking -- and pins the regression seeds for the bugs the
|
|
||||||
# fuzzers found. Deep discovery is a maintainer / OSS-Fuzz activity.
|
|
||||||
fuzz:
|
|
||||||
name: fuzz (libFuzzer corpus replay, clang)
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Install build dependencies
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y --no-install-recommends \
|
|
||||||
build-essential clang autoconf automake libtool autoconf-archive \
|
|
||||||
zlib1g-dev libssl-dev
|
|
||||||
|
|
||||||
- name: Configure (fuzzers, static)
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
autoreconf -fi
|
|
||||||
./configure CC=clang \
|
|
||||||
CFLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g -O1 -fno-omit-frame-pointer" \
|
|
||||||
LDFLAGS="-fsanitize=address,undefined" \
|
|
||||||
--enable-fuzzers --disable-shared
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: make -j"$(nproc)"
|
|
||||||
|
|
||||||
- name: Replay corpora
|
|
||||||
env:
|
|
||||||
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1:halt_on_error=1
|
|
||||||
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
|
|
||||||
run: bash fuzz/run-fuzzers.sh fuzz check
|
|
||||||
|
|
||||||
# Optional-dependency build: compile and test with HTTPS/OpenSSL disabled --
|
# Optional-dependency build: compile and test with HTTPS/OpenSSL disabled --
|
||||||
# the configuration users on minimal systems build, and one libssl is not even
|
# the configuration users on minimal systems build, and one libssl is not even
|
||||||
# installed here so configure cannot silently re-enable it. The matrix above
|
# installed here so configure cannot silently re-enable it. The matrix above
|
||||||
|
|||||||
63
.github/workflows/codeql.yml
vendored
63
.github/workflows/codeql.yml
vendored
@@ -1,63 +0,0 @@
|
|||||||
# CodeQL static analysis (C). The security-extended suite covers the classes
|
|
||||||
# this codebase actually fights: overflows, tainted-size allocs, format bugs.
|
|
||||||
name: CodeQL
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master]
|
|
||||||
pull_request:
|
|
||||||
schedule:
|
|
||||||
# Weekly re-scan of master so new/updated queries land without a push.
|
|
||||||
- cron: "17 4 * * 1"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: codeql-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: analyze (c-cpp)
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
# Upload findings to the repo's code-scanning dashboard.
|
|
||||||
security-events: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Install build dependencies
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y --no-install-recommends \
|
|
||||||
build-essential autoconf automake libtool autoconf-archive \
|
|
||||||
zlib1g-dev libssl-dev
|
|
||||||
|
|
||||||
- uses: github/codeql-action/init@v4
|
|
||||||
with:
|
|
||||||
languages: c-cpp
|
|
||||||
build-mode: manual
|
|
||||||
queries: security-extended
|
|
||||||
# fopen's umask-controlled 0666 is intended for mirror/cache/log
|
|
||||||
# output; the one credential file (cookies.txt) is kept 0600 on Unix.
|
|
||||||
config: |
|
|
||||||
query-filters:
|
|
||||||
- exclude:
|
|
||||||
id: cpp/world-writable-file-creation
|
|
||||||
|
|
||||||
# Manual build: CodeQL traces the compiler, so build exactly what ships.
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
autoreconf -fi
|
|
||||||
./configure
|
|
||||||
make -j"$(nproc)"
|
|
||||||
|
|
||||||
- uses: github/codeql-action/analyze@v4
|
|
||||||
with:
|
|
||||||
category: "/language:c-cpp"
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -34,12 +34,8 @@ Makefile
|
|||||||
*.so.*
|
*.so.*
|
||||||
*.a
|
*.a
|
||||||
|
|
||||||
# make dist output; dist/ holds httrack-gh-release staging artifacts.
|
# make dist output.
|
||||||
/httrack-*.tar.gz
|
/httrack-*.tar.gz
|
||||||
/dist/
|
|
||||||
|
|
||||||
# Editor / autotools backup files.
|
# Editor / autotools backup files.
|
||||||
*~
|
*~
|
||||||
|
|
||||||
# Python bytecode (tests/local-server.py).
|
|
||||||
__pycache__/
|
|
||||||
|
|||||||
@@ -39,10 +39,6 @@ Welcome, and nothing to disclose. Two rules:
|
|||||||
|
|
||||||
The sign-off covers AI-assisted code too.
|
The sign-off covers AI-assisted code too.
|
||||||
|
|
||||||
## Translations
|
|
||||||
|
|
||||||
Interface strings live in [`lang/`](lang/). See [lang/README.md](lang/README.md) for the file format and how to add or update a language.
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
|
|
||||||
Open an issue with the version, OS, command used, and expected vs actual result.
|
Open an issue with the version, OS, command used, and expected vs actual result.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
SUBDIRS = src man m4 libtest templates lang html tests fuzz
|
SUBDIRS = src man m4 libtest templates lang html tests
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
|||||||
63
configure.ac
63
configure.ac
@@ -1,6 +1,6 @@
|
|||||||
AC_PREREQ([2.71])
|
AC_PREREQ([2.71])
|
||||||
|
|
||||||
AC_INIT([httrack], [3.49.11], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
|
AC_INIT([httrack], [3.49.9], [roche+packaging@httrack.com], [httrack], [http://www.httrack.com/])
|
||||||
AC_COPYRIGHT([
|
AC_COPYRIGHT([
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||||
Copyright (C) 1998-2015 Xavier Roche and other contributors
|
Copyright (C) 1998-2015 Xavier Roche and other contributors
|
||||||
@@ -29,11 +29,10 @@ AC_CONFIG_SRCDIR(src/httrack.c)
|
|||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
AM_INIT_AUTOMAKE([subdir-objects])
|
AM_INIT_AUTOMAKE([subdir-objects])
|
||||||
# 3:3:0: 3.49.11 only adds enum values, macros and inline helpers to the
|
# 3:1:0: 3.49.9 changed code but not the exported interface vs 3.49.8 (same 164
|
||||||
# installed headers (no struct layout or exported signature changed vs
|
# symbols, no struct-layout change), so bump revision only. (3:0:0 was the htsblk
|
||||||
# 3.49.10), so it stays soname .so.3; bump revision.
|
# mime-buffer widening, an ABI break that moved the soname .so.2 -> .so.3.)
|
||||||
# (3:0:0 was the htsblk mime-buffer widening, the ABI break that moved .so.2 -> .so.3.)
|
VERSION_INFO="3:1:0"
|
||||||
VERSION_INFO="3:3:0"
|
|
||||||
AM_MAINTAINER_MODE
|
AM_MAINTAINER_MODE
|
||||||
AC_USE_SYSTEM_EXTENSIONS
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
|
|
||||||
@@ -64,16 +63,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 \
|
||||||
@@ -102,8 +91,7 @@ AX_CHECK_COMPILE_FLAG([-Wignored-qualifiers], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -
|
|||||||
AX_CHECK_COMPILE_FLAG([-Werror=attribute-warning], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=attribute-warning"])
|
AX_CHECK_COMPILE_FLAG([-Werror=attribute-warning], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=attribute-warning"])
|
||||||
AX_CHECK_COMPILE_FLAG([-Werror=user-defined-warnings], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=user-defined-warnings"])
|
AX_CHECK_COMPILE_FLAG([-Werror=user-defined-warnings], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=user-defined-warnings"])
|
||||||
AX_CHECK_COMPILE_FLAG([-fstrict-aliasing -Wstrict-aliasing], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstrict-aliasing -Wstrict-aliasing"])
|
AX_CHECK_COMPILE_FLAG([-fstrict-aliasing -Wstrict-aliasing], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstrict-aliasing -Wstrict-aliasing"])
|
||||||
AX_CHECK_COMPILE_FLAG([-fstack-protector-strong], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector-strong"],
|
AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"])
|
||||||
[AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"])])
|
|
||||||
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"])
|
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"])
|
||||||
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"])
|
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"])
|
||||||
AX_CHECK_LINK_FLAG([-Wl,--discard-all], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--discard-all"])
|
AX_CHECK_LINK_FLAG([-Wl,--discard-all], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--discard-all"])
|
||||||
@@ -111,13 +99,6 @@ AX_CHECK_LINK_FLAG([-Wl,--no-undefined], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,
|
|||||||
AX_CHECK_LINK_FLAG([-Wl,-z,relro,-z,now], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,relro,-z,now"])
|
AX_CHECK_LINK_FLAG([-Wl,-z,relro,-z,now], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,relro,-z,now"])
|
||||||
AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,noexecstack"])
|
AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,noexecstack"])
|
||||||
|
|
||||||
# Fortify libc calls (=3, else =2) unless the toolchain predefines it; skip
|
|
||||||
# sanitizer builds, whose interceptors want the unfortified calls.
|
|
||||||
case "$CFLAGS" in
|
|
||||||
*-fsanitize=*) ;;
|
|
||||||
*) AX_ADD_FORTIFY_SOURCE ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Force libc back into DT_NEEDED for libraries that reach it only through
|
# Force libc back into DT_NEEDED for libraries that reach it only through
|
||||||
# libhttrack (libhtsjava, the libtest callbacks), but only with a GNU-style
|
# libhttrack (libhtsjava, the libtest callbacks), but only with a GNU-style
|
||||||
# linker; Apple ld rejects these flags and links libSystem unconditionally.
|
# linker; Apple ld rejects these flags and links libSystem unconditionally.
|
||||||
@@ -318,37 +299,6 @@ AC_ARG_ENABLE([online-unit-tests],
|
|||||||
])
|
])
|
||||||
AC_SUBST(ONLINE_UNIT_TESTS,$online_unit_tests)
|
AC_SUBST(ONLINE_UNIT_TESTS,$online_unit_tests)
|
||||||
|
|
||||||
## libFuzzer harnesses (fuzz/); requires clang
|
|
||||||
AC_MSG_CHECKING(whether to build fuzzers)
|
|
||||||
AC_ARG_ENABLE([fuzzers],
|
|
||||||
[AS_HELP_STRING([--enable-fuzzers],[Build libFuzzer harnesses in fuzz/ (requires clang) @<:@default=no@:>@])],
|
|
||||||
[
|
|
||||||
case "${enableval}" in
|
|
||||||
no|yes)
|
|
||||||
fuzzers=$enableval
|
|
||||||
AC_MSG_RESULT($enableval)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
AC_MSG_ERROR(bad value for fuzzers, expected yes/no)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
],
|
|
||||||
[
|
|
||||||
fuzzers=no
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
])
|
|
||||||
if test x"$fuzzers" = x"yes"; then
|
|
||||||
# Instrument the whole build for coverage; harnesses link -fsanitize=fuzzer.
|
|
||||||
AX_CHECK_COMPILE_FLAG([-fsanitize=fuzzer-no-link],
|
|
||||||
[DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fsanitize=fuzzer-no-link"],
|
|
||||||
[AC_MSG_ERROR([--enable-fuzzers requires libFuzzer support (clang)])])
|
|
||||||
# clang's static sanitizer runtimes clash with -Wl,--no-undefined on the .so.
|
|
||||||
if test x"$enable_shared" != x"no"; then
|
|
||||||
AC_MSG_ERROR([--enable-fuzzers requires --disable-shared])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL([FUZZERS], [test x"$fuzzers" = x"yes"])
|
|
||||||
|
|
||||||
# Final output
|
# Final output
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
Makefile
|
Makefile
|
||||||
@@ -360,6 +310,5 @@ lang/Makefile
|
|||||||
html/Makefile
|
html/Makefile
|
||||||
libtest/Makefile
|
libtest/Makefile
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
fuzz/Makefile
|
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
34
debian/changelog
vendored
34
debian/changelog
vendored
@@ -1,37 +1,3 @@
|
|||||||
httrack (3.49.11-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* New upstream release: crawl correctness and security fixes (network-facing
|
|
||||||
buffer overflows, file-type detection, redirect handling) and modernized
|
|
||||||
web defaults; full list in history.txt.
|
|
||||||
* Add DEP-12 upstream metadata (#466).
|
|
||||||
* Bump debhelper compat to 14 (#466).
|
|
||||||
* Drop the redundant Priority field and update the NMU lintian override to
|
|
||||||
the current tag names (#466).
|
|
||||||
|
|
||||||
-- Xavier Roche <xavier@debian.org> Sun, 05 Jul 2026 00:03:18 +0200
|
|
||||||
|
|
||||||
httrack (3.49.10-2) unstable; urgency=medium
|
|
||||||
|
|
||||||
* Fix FTBFS: tests/28_local-pause failed instead of skipping when python3 is
|
|
||||||
absent (the local-server tests need python3, which the buildds lack). Add
|
|
||||||
patches/skip-local-pause-test-without-python3.patch to guard the test on
|
|
||||||
python3 up front, like its siblings, so it skips cleanly.
|
|
||||||
|
|
||||||
-- Xavier Roche <xavier@debian.org> Sun, 28 Jun 2026 20:18:46 +0200
|
|
||||||
|
|
||||||
httrack (3.49.10-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* New upstream release: new download-pacing and URL-handling options plus a
|
|
||||||
batch of crawl and robustness fixes (full list in history.txt).
|
|
||||||
* Rewrite debian/copyright in machine-readable DEP-5 format, crediting the
|
|
||||||
bundled minizip, md5 and coucal sources (#415).
|
|
||||||
* Lead the webhttrack browser dependency with chromium so httrack is not
|
|
||||||
dragged into the firefox-esr autoremoval cascade (#436).
|
|
||||||
* Override the embedded-library lint for the bundled minizip (#419).
|
|
||||||
* Bump Standards-Version to 4.7.4 (no changes required).
|
|
||||||
|
|
||||||
-- Xavier Roche <xavier@debian.org> Sun, 28 Jun 2026 14:01:53 +0200
|
|
||||||
|
|
||||||
httrack (3.49.9-1) unstable; urgency=medium
|
httrack (3.49.9-1) unstable; urgency=medium
|
||||||
|
|
||||||
* New upstream release: Content-Type and file-type detection fixes (trust a
|
* New upstream release: Content-Type and file-type detection fixes (trust a
|
||||||
|
|||||||
7
debian/control
vendored
7
debian/control
vendored
@@ -1,8 +1,9 @@
|
|||||||
Source: httrack
|
Source: httrack
|
||||||
Section: web
|
Section: web
|
||||||
|
Priority: optional
|
||||||
Maintainer: Xavier Roche <roche@httrack.com>
|
Maintainer: Xavier Roche <roche@httrack.com>
|
||||||
Standards-Version: 4.7.4
|
Standards-Version: 4.7.0
|
||||||
Build-Depends: debhelper-compat (= 14), autoconf, autoconf-archive, automake, libtool, zlib1g-dev, libssl-dev
|
Build-Depends: debhelper-compat (= 13), autoconf, autoconf-archive, automake, libtool, zlib1g-dev, libssl-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
|
||||||
@@ -29,7 +30,7 @@ Description: Copy websites to your computer (Offline browser)
|
|||||||
Package: webhttrack
|
Package: webhttrack
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Multi-Arch: foreign
|
Multi-Arch: foreign
|
||||||
Depends: ${misc:Depends}, ${shlibs:Depends}, webhttrack-common, sensible-utils, chromium | firefox-esr | www-browser
|
Depends: ${misc:Depends}, ${shlibs:Depends}, webhttrack-common, sensible-utils, firefox-esr | chromium | www-browser
|
||||||
Replaces: webhttrack-common (<< 3.43.9-2)
|
Replaces: webhttrack-common (<< 3.43.9-2)
|
||||||
Breaks: webhttrack-common (<< 3.43.9-2)
|
Breaks: webhttrack-common (<< 3.43.9-2)
|
||||||
Suggests: httrack, httrack-doc
|
Suggests: httrack, httrack-doc
|
||||||
|
|||||||
4
debian/source/lintian-overrides
vendored
4
debian/source/lintian-overrides
vendored
@@ -1,6 +1,4 @@
|
|||||||
# Maintainer uploads sign the changelog as xavier@debian.org while the control
|
httrack source: changelog-should-mention-nmu
|
||||||
# Maintainer is roche@httrack.com; lintian reads the address mismatch as an NMU.
|
|
||||||
httrack source: no-nmu-in-changelog
|
|
||||||
httrack source: source-nmu-has-incorrect-version-number
|
httrack source: source-nmu-has-incorrect-version-number
|
||||||
|
|
||||||
# The bundled HTML pages are the genuine upstream documentation taken from
|
# The bundled HTML pages are the genuine upstream documentation taken from
|
||||||
|
|||||||
6
debian/upstream/metadata
vendored
6
debian/upstream/metadata
vendored
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
Repository: https://github.com/xroche/httrack.git
|
|
||||||
Repository-Browse: https://github.com/xroche/httrack
|
|
||||||
Bug-Database: https://github.com/xroche/httrack/issues
|
|
||||||
Bug-Submit: https://github.com/xroche/httrack/issues/new
|
|
||||||
Contact: Xavier Roche <roche@httrack.com>
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# libFuzzer harnesses; built only with --enable-fuzzers (requires clang).
|
|
||||||
if FUZZERS
|
|
||||||
noinst_PROGRAMS = fuzz-charset fuzz-meta fuzz-idna fuzz-entities \
|
|
||||||
fuzz-unescape fuzz-filters fuzz-url fuzz-header fuzz-cachendx
|
|
||||||
endif
|
|
||||||
|
|
||||||
AM_CPPFLAGS = \
|
|
||||||
@DEFAULT_CFLAGS@ \
|
|
||||||
@THREADS_CFLAGS@ \
|
|
||||||
@V6_FLAG@ \
|
|
||||||
@LFS_FLAG@ \
|
|
||||||
-I$(top_srcdir)/src \
|
|
||||||
-I$(top_srcdir)/src/coucal
|
|
||||||
|
|
||||||
# Static-link libhttrack.la: the internal symbols are hidden in the .so.
|
|
||||||
AM_LDFLAGS = @DEFAULT_LDFLAGS@ -fsanitize=fuzzer -static-libtool-libs
|
|
||||||
LDADD = $(top_builddir)/src/libhttrack.la $(THREADS_LIBS)
|
|
||||||
|
|
||||||
fuzz_charset_SOURCES = fuzz-charset.c fuzz.h
|
|
||||||
fuzz_meta_SOURCES = fuzz-meta.c fuzz.h
|
|
||||||
fuzz_idna_SOURCES = fuzz-idna.c fuzz.h
|
|
||||||
fuzz_entities_SOURCES = fuzz-entities.c fuzz.h
|
|
||||||
fuzz_unescape_SOURCES = fuzz-unescape.c fuzz.h
|
|
||||||
fuzz_filters_SOURCES = fuzz-filters.c fuzz.h
|
|
||||||
fuzz_url_SOURCES = fuzz-url.c fuzz.h
|
|
||||||
fuzz_header_SOURCES = fuzz-header.c fuzz.h
|
|
||||||
fuzz_cachendx_SOURCES = fuzz-cachendx.c fuzz.h
|
|
||||||
|
|
||||||
# List corpus files explicitly: automake does not expand EXTRA_DIST globs.
|
|
||||||
EXTRA_DIST = README.md run-fuzzers.sh \
|
|
||||||
corpus/charset/utf8.txt corpus/charset/latin1.txt corpus/charset/sjis.txt \
|
|
||||||
corpus/meta/meta-charset.html corpus/meta/meta-http-equiv.html \
|
|
||||||
corpus/idna/idna.txt corpus/idna/unicode.txt \
|
|
||||||
corpus/idna/regress-multilabel-leak.txt \
|
|
||||||
corpus/entities/entities.txt \
|
|
||||||
corpus/unescape/percent.txt \
|
|
||||||
corpus/filters/filter.bin corpus/filters/filter-size.bin \
|
|
||||||
corpus/filters/regress-empty-subject-unique.bin \
|
|
||||||
corpus/url/http-url.txt corpus/url/relative-path.txt \
|
|
||||||
corpus/url/regress-file-empty-path.txt corpus/url/regress-long-path-abort.txt \
|
|
||||||
corpus/header/full-response.txt corpus/header/redirect.txt \
|
|
||||||
corpus/cachendx/new-format.txt corpus/cachendx/old-format.txt \
|
|
||||||
corpus/cachendx/regress-overadvance.bin \
|
|
||||||
corpus/cachendx/regress-truncated-entry.bin
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Fuzzing httrack
|
|
||||||
|
|
||||||
libFuzzer harnesses for the pure hostile-input parsers (charset/UTF-8/IDNA codecs, entity and percent decoders, wildcard filters, URL splitter). Off by default; needs clang.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./bootstrap
|
|
||||||
mkdir /var/tmp/bld-fuzz && cd /var/tmp/bld-fuzz
|
|
||||||
CC=clang CFLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g -O1" \
|
|
||||||
LDFLAGS="-fsanitize=address,undefined" \
|
|
||||||
bash /path/to/httrack/configure --enable-fuzzers --disable-shared
|
|
||||||
make
|
|
||||||
bash /path/to/httrack/fuzz/run-fuzzers.sh fuzz 60 # 60s per target
|
|
||||||
```
|
|
||||||
|
|
||||||
Run one target by hand: `fuzz/fuzz-url -max_total_time=300 corpusdir fuzz/corpus/url`. Seed corpora live in `corpus/<target>/`; a crash reproducer is replayed with `fuzz/fuzz-url crash-file`.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
8
|
|
||||||
CACHE-1.1
|
|
||||||
28
|
|
||||||
Mon, 01 Jan 2024 00:00:00 GMT
|
|
||||||
www.example.com
|
|
||||||
/index.html
|
|
||||||
123
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
3
|
|
||||||
1.0
|
|
||||||
www.example.com
|
|
||||||
/page
|
|
||||||
5
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
32768
|
|
||||||
CACHE-1.1
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
8
|
|
||||||
CACHE-1.1
|
|
||||||
1
|
|
||||||
x
|
|
||||||
www.example.com
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
café naďve ¤
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
コンピュータ
|
|
||||||
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
&<>A☃é¬arealentity;�
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
**((
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
HTTP/1.1 200 OK
|
|
||||||
Content-Type: text/html; charset=utf-8
|
|
||||||
Content-Length: 1234
|
|
||||||
Content-Encoding: gzip
|
|
||||||
Last-Modified: Mon, 01 Jan 2024 00:00:00 GMT
|
|
||||||
Etag: "abc"
|
|
||||||
Location: http://example.com/x
|
|
||||||
Set-Cookie: ID=42; path=/; domain=.example.com
|
|
||||||
Content-Range: bytes 0-99/100
|
|
||||||
Transfer-Encoding: chunked
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
HTTP/1.0 301 Moved
|
|
||||||
Location: /elsewhere
|
|
||||||
Content-Disposition: attachment; filename="a.pdf"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
xn--bcher-kva.example.com
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
büchev.例åbücheple
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
bücher.例子.example
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<html><head><meta charset="utf-8"></head><body>x</body></html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
%41%zz%%20%c3%a9+%2e%2e%2f
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
http://user:pass@www.example.com:8080/a/b/../c/./d.html?q=1#frag
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
file://
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ftpumŠ[/../e0O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._f9O_i../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/.../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W//O/../f9O_i<5F>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/i<>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_im<69>W/.¿ù../O/../9O_imÙ<6D>Š<EFBFBD>W/../_/../../e0O/../f9O_./f9O_i<5F>W/../O/../90O/./e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_imÙ<6D>Š<EFBFBD>W/../O/.._i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9O_i/../O/../f9O_i<5F>W/../O/../90O/../itpumÙ/ftpumŠ[/../e0O/../itpumÙ<6D>Š[/../O/../f9O_i<5F>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/../f9OmÙ<6D>Š<EFBFBD>W/../O/../9O_imÙ<6D>Š<EFBFBD>W/../O/..O_imÙ<6D>Š<EFBFBD>W/../O/../../e0O/9O_imÙ<6D>Š<EFBFBD>W/../O/../
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ftp://ftp.example.com/pub/../file.txt
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 2026 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the cache-index (.ndx) parser: a corrupt or truncated index must not
|
|
||||||
walk the length-prefixed cache_brstr/cache_binput scan past the buffer.
|
|
||||||
Mirrors the loader in cache_readex_new (htscache.c). */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htscache.h"
|
|
||||||
#include "htslib.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
char *buf = fuzz_strdup(data, size);
|
|
||||||
const char *const end = buf + size;
|
|
||||||
char firstline[256];
|
|
||||||
char *a = buf;
|
|
||||||
|
|
||||||
/* header: two length-prefixed fields (version, last-modified) */
|
|
||||||
a += cache_brstr(a, firstline, sizeof(firstline));
|
|
||||||
a += cache_brstr(a, firstline, sizeof(firstline));
|
|
||||||
|
|
||||||
/* body: newline-delimited host/file/position triples. The coucal insert
|
|
||||||
the real loader ends with is a separate library's concern; this harness
|
|
||||||
targets the length-prefixed scan that must stay inside the buffer. */
|
|
||||||
while (a != NULL && a < end) {
|
|
||||||
char BIGSTK line[HTS_URLMAXSIZE * 2];
|
|
||||||
char linepos[256];
|
|
||||||
int pos;
|
|
||||||
|
|
||||||
a = strchr(a + 1, '\n');
|
|
||||||
if (a == NULL)
|
|
||||||
break;
|
|
||||||
a++;
|
|
||||||
a += cache_binput(a, end, line, HTS_URLMAXSIZE);
|
|
||||||
a += cache_binput(a, end, line + strlen(line), HTS_URLMAXSIZE);
|
|
||||||
a += cache_binput(a, end, linepos, 200);
|
|
||||||
sscanf(linepos, "%d", &pos);
|
|
||||||
(void) pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
freet(buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the charset codecs: hts_convertStringToUTF8/FromUTF8 and the
|
|
||||||
UTF-8/UCS4 primitives (htscharset.c). First input byte picks the charset. */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htscharset.h"
|
|
||||||
|
|
||||||
static const char *const charsets[] = {
|
|
||||||
"utf-8", "iso-8859-1", "iso-8859-2", "iso-8859-15", "windows-1252",
|
|
||||||
"us-ascii", "shift_jis", "euc-jp", "iso-2022-jp", "gb2312",
|
|
||||||
"big5", "euc-kr", "koi8-r", "utf-16", "unknown-charset",
|
|
||||||
};
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
const char *charset;
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
return 0;
|
|
||||||
charset = charsets[data[0] % (sizeof(charsets) / sizeof(charsets[0]))];
|
|
||||||
data++, size--;
|
|
||||||
s = fuzz_strdup(data, size);
|
|
||||||
|
|
||||||
{
|
|
||||||
char *utf8 = hts_convertStringToUTF8(s, size, charset);
|
|
||||||
freet(utf8);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char *enc = hts_convertStringFromUTF8(s, size, charset);
|
|
||||||
freet(enc);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t nChars = 0;
|
|
||||||
hts_UCS4 *ucs = hts_convertUTF8StringToUCS4(s, size, &nChars);
|
|
||||||
|
|
||||||
if (ucs != NULL) {
|
|
||||||
char *back = hts_convertUCS4StringToUTF8(ucs, nChars);
|
|
||||||
freet(back);
|
|
||||||
freet(ucs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
while (i < size) {
|
|
||||||
hts_UCS4 uc = 0;
|
|
||||||
const size_t nr = hts_readUTF8(s + i, size - i, &uc);
|
|
||||||
char out[8];
|
|
||||||
|
|
||||||
if (nr == 0)
|
|
||||||
break;
|
|
||||||
hts_writeUTF8(uc, out, sizeof(out));
|
|
||||||
i += nr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freet(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the HTML entity decoder (htsencoding.c). First input byte picks the
|
|
||||||
destination size, so truncation bounds get exercised too. */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htsencoding.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
static const size_t dsizes[] = {1, 2, 8, 64, 4096};
|
|
||||||
size_t dsize;
|
|
||||||
char *src, *dest;
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
return 0;
|
|
||||||
dsize = dsizes[data[0] % (sizeof(dsizes) / sizeof(dsizes[0]))];
|
|
||||||
data++, size--;
|
|
||||||
src = fuzz_strdup(data, size);
|
|
||||||
dest = malloct(dsize);
|
|
||||||
|
|
||||||
(void) hts_unescapeEntities(src, dest, dsize);
|
|
||||||
(void) hts_unescapeEntitiesWithCharset(src, dest, dsize, "iso-8859-1");
|
|
||||||
|
|
||||||
freet(dest);
|
|
||||||
freet(src);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the wildcard filter matcher (htsfilters.c; #148 bracket-range OOB was
|
|
||||||
here). Input splits on the first NUL: pattern, then subject string. */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htsfilters.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
char *buf = fuzz_strdup(data, size);
|
|
||||||
const char *joker = buf;
|
|
||||||
const uint8_t *sep = memchr(data, '\0', size);
|
|
||||||
/* subject in its own allocation so ASan bounds it apart from the pattern */
|
|
||||||
char *nom = sep != NULL ? fuzz_strdup(sep + 1, (data + size) - (sep + 1))
|
|
||||||
: fuzz_strdup(data + size, 0);
|
|
||||||
|
|
||||||
(void) strjoker(nom, joker, NULL, NULL);
|
|
||||||
{
|
|
||||||
LLint sz = (LLint) size;
|
|
||||||
int size_flag = 0;
|
|
||||||
|
|
||||||
(void) strjoker(nom, joker, &sz, &size_flag);
|
|
||||||
}
|
|
||||||
(void) strjokerfind(nom, joker);
|
|
||||||
{
|
|
||||||
char *filter = malloct(strlen(joker) + 2);
|
|
||||||
char *filters[1];
|
|
||||||
LLint sz = (LLint) size;
|
|
||||||
int size_flag = 0, depth = 0;
|
|
||||||
|
|
||||||
filter[0] = '-';
|
|
||||||
memcpy(filter + 1, joker, strlen(joker) + 1);
|
|
||||||
filters[0] = filter;
|
|
||||||
(void) fa_strjoker(0, filters, 1, nom, &sz, &size_flag, &depth);
|
|
||||||
freet(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
freet(nom);
|
|
||||||
freet(buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 2026 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the HTTP response-header parser (htslib.c): treatfirstline on the
|
|
||||||
status line, treathead on each following header. Both consume raw bytes
|
|
||||||
off the wire and copy fields into fixed htsblk buffers; treathead also
|
|
||||||
mutates its line in place and drives cookie parsing. */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htslib.h"
|
|
||||||
#include "htsbauth.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
char *buf = fuzz_strdup(data, size);
|
|
||||||
htsblk r;
|
|
||||||
t_cookie *cookie = calloct(1, sizeof(*cookie));
|
|
||||||
char *line = malloct(size + 1);
|
|
||||||
char *p = buf;
|
|
||||||
int first = 1;
|
|
||||||
|
|
||||||
memset(&r, 0, sizeof(r));
|
|
||||||
cookie->max_len = (int) sizeof(cookie->data);
|
|
||||||
r.location = malloct(HTS_URLMAXSIZE * 2);
|
|
||||||
r.location[0] = '\0';
|
|
||||||
|
|
||||||
/* feed one header line at a time, as the receive loop does */
|
|
||||||
while (p != NULL && *p != '\0') {
|
|
||||||
char *nl = strchr(p, '\n');
|
|
||||||
size_t n = (nl != NULL) ? (size_t) (nl - p) : strlen(p);
|
|
||||||
|
|
||||||
memcpy(line, p, n);
|
|
||||||
line[n] = '\0';
|
|
||||||
if (first) {
|
|
||||||
treatfirstline(&r, line);
|
|
||||||
first = 0;
|
|
||||||
} else {
|
|
||||||
treathead(cookie, "www.example.com", "/", &r, line);
|
|
||||||
}
|
|
||||||
p = (nl != NULL) ? nl + 1 : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
freet(r.location);
|
|
||||||
freet(line);
|
|
||||||
freet(cookie);
|
|
||||||
freet(buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the IDNA/punycode codec (htscharset.c, CVE-prone lineage). */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htscharset.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
char *s = fuzz_strdup(data, size);
|
|
||||||
|
|
||||||
{
|
|
||||||
char *idna = hts_convertStringUTF8ToIDNA(s, size);
|
|
||||||
freet(idna);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char *utf8 = hts_convertStringIDNAToUTF8(s, size);
|
|
||||||
freet(utf8);
|
|
||||||
}
|
|
||||||
(void) hts_isStringIDNA(s, size);
|
|
||||||
|
|
||||||
freet(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz hts_getCharsetFromMeta (htscharset.c): scans raw attacker HTML for a
|
|
||||||
<meta> charset declaration. */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htscharset.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
char *html = fuzz_strdup(data, size);
|
|
||||||
char *charset = hts_getCharsetFromMeta(html, size);
|
|
||||||
|
|
||||||
freet(charset);
|
|
||||||
freet(html);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the URL percent-decoders (htslib.c). First input byte picks the
|
|
||||||
output buffer size, so the bounded-copy contract is exercised. */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "httrack-library.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
static const size_t bsizes[] = {1, 2, 16, 256, 8192};
|
|
||||||
size_t bsize;
|
|
||||||
char *s, *catbuff;
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
return 0;
|
|
||||||
bsize = bsizes[data[0] % (sizeof(bsizes) / sizeof(bsizes[0]))];
|
|
||||||
data++, size--;
|
|
||||||
s = fuzz_strdup(data, size);
|
|
||||||
catbuff = malloct(bsize);
|
|
||||||
|
|
||||||
(void) unescape_http(catbuff, bsize, s);
|
|
||||||
(void) unescape_http_unharm(catbuff, bsize, s, 0);
|
|
||||||
(void) unescape_http_unharm(catbuff, bsize, s, 1);
|
|
||||||
unescape_amp(s);
|
|
||||||
|
|
||||||
freet(catbuff);
|
|
||||||
freet(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fuzz the URL splitter and path normalizer (htslib.c): ident_url_absolute
|
|
||||||
is the first parser to touch a raw URL; fil_simplifie collapses ./ and ../
|
|
||||||
in place. */
|
|
||||||
#include "fuzz.h"
|
|
||||||
#include "htscore.h"
|
|
||||||
#include "htslib.h"
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
||||||
char *s = fuzz_strdup(data, size);
|
|
||||||
lien_adrfil *af = calloct(1, sizeof(*af));
|
|
||||||
/* fil_simplifie rewrites in place and may grow an empty path to "./" */
|
|
||||||
char *path = malloct(size + 3);
|
|
||||||
|
|
||||||
(void) ident_url_absolute(s, af);
|
|
||||||
memcpy(path, s, size + 1);
|
|
||||||
fil_simplifie(path);
|
|
||||||
|
|
||||||
freet(path);
|
|
||||||
freet(af);
|
|
||||||
freet(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
51
fuzz/fuzz.h
51
fuzz/fuzz.h
@@ -1,51 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
|
||||||
addresses or to collect any other private information about people. Doing so
|
|
||||||
would dishonor our work and waste the many hours we have spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Shared helpers for the libFuzzer harnesses. */
|
|
||||||
#ifndef FUZZ_H
|
|
||||||
#define FUZZ_H
|
|
||||||
|
|
||||||
#define HTS_INTERNAL_BYTECODE
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "htsbase.h"
|
|
||||||
|
|
||||||
/* Heap NUL-terminated copy of the fuzzer input, so ASan bounds every read. */
|
|
||||||
static char *fuzz_strdup(const uint8_t *data, size_t size) {
|
|
||||||
char *s = malloct(size + 1);
|
|
||||||
|
|
||||||
memcpy(s, data, size);
|
|
||||||
s[size] = '\0';
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Drive every built harness against its seed corpus.
|
|
||||||
# run-fuzzers.sh <build-fuzz-dir> check deterministic replay (CI smoke)
|
|
||||||
# run-fuzzers.sh <build-fuzz-dir> [seconds] timed mutation run (discovery)
|
|
||||||
# Replay is crash/leak-only and never mutates, so it can't hit strjoker's
|
|
||||||
# catastrophic backtracking; the timed mode can, hence the per-unit -timeout.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
srcdir=$(cd "$(dirname "$0")" && pwd)
|
|
||||||
bld=${1:?usage: run-fuzzers.sh <build-fuzz-dir> [check|seconds]}
|
|
||||||
mode=${2:-20}
|
|
||||||
|
|
||||||
status=0
|
|
||||||
for f in "$bld"/fuzz-*; do
|
|
||||||
if [ ! -f "$f" ] || [ ! -r "$f" ]; then continue; fi
|
|
||||||
case "$f" in *.o | *.c | *.dSYM) continue ;; esac
|
|
||||||
name=$(basename "$f")
|
|
||||||
corpus="$srcdir/corpus/${name#fuzz-}"
|
|
||||||
if [ "$mode" = "check" ]; then
|
|
||||||
echo "=== $name (replay) ==="
|
|
||||||
[ -d "$corpus" ] || continue
|
|
||||||
if ! "$f" -runs=0 -timeout=25 -rss_limit_mb=2048 "$corpus"; then
|
|
||||||
echo "*** $name FAILED on its corpus" >&2
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
work=$(mktemp -d)
|
|
||||||
args=("$work")
|
|
||||||
[ -d "$corpus" ] && args+=("$corpus")
|
|
||||||
echo "=== $name (${mode}s) ==="
|
|
||||||
if ! "$f" -max_total_time="$mode" -timeout=25 -rss_limit_mb=2048 \
|
|
||||||
-artifact_prefix="$work/" -print_final_stats=1 "${args[@]}"; then
|
|
||||||
echo "*** $name FAILED; artifacts:" >&2
|
|
||||||
ls -l "$work" >&2
|
|
||||||
status=1
|
|
||||||
else
|
|
||||||
rm -rf "$work"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
exit $status
|
|
||||||
37
history.txt
37
history.txt
@@ -4,42 +4,7 @@ HTTrack Website Copier release history:
|
|||||||
|
|
||||||
This file lists all changes and fixes that have been made for HTTrack
|
This file lists all changes and fixes that have been made for HTTrack
|
||||||
|
|
||||||
3.49-11
|
3.49-9
|
||||||
+ New: parse robots.txt Allow rules and path wildcards per RFC 9309 (#452)
|
|
||||||
+ New: advertise deflate in Accept-Encoding and decode deflate responses (#450)
|
|
||||||
+ New: follow <source> and <track> media elements as embedded links (#451)
|
|
||||||
+ New: added modern web MIME types to the type/extension table (#448)
|
|
||||||
+ Fixed: enforce the -E time limit during a slow transfer instead of only between files (#481)
|
|
||||||
+ Fixed: sniff the leading bytes of a download so a misdeclared Content-Type no longer renames a correct URL extension
|
|
||||||
+ Fixed: fast transfers could be saved under their temporary .delayed placeholder name (#5, #107)
|
|
||||||
+ Fixed: follow a redirect that maps to the same saved file instead of writing a self-pointing stub (#159)
|
|
||||||
+ Fixed: several network-facing buffer overflows in the FTP, Java and HTML parsers
|
|
||||||
+ Fixed: the htsjava plugin could not be loaded (hidden entry points, stale library name)
|
|
||||||
+ Fixed: HTML-escape truncation and a cache-buffer leak in the parser
|
|
||||||
+ Changed: modernized the default User-Agent to an honest HTTrack identifier (#449)
|
|
||||||
+ Changed: decode the full WHATWG set of HTML named character references (#443)
|
|
||||||
+ Changed: refreshed stale HTTP status, proxy-port and TLS-floor constants (#453)
|
|
||||||
+ Changed: multiple internal hardening, build, test and CI improvements
|
|
||||||
|
|
||||||
3.49-10
|
|
||||||
+ New: --cookies-file to preload a Netscape cookies.txt before crawling (#215)
|
|
||||||
+ New: --pause to space out file downloads by a random delay (#185)
|
|
||||||
+ New: --strip-query to drop selected query keys from the dedup naming (#112)
|
|
||||||
+ Changed: split the -%u URL hacks into independent --keep-www-prefix, --keep-double-slashes and --keep-query-order toggles (#271)
|
|
||||||
+ Fixed: follow a redirect Location after dropping its #fragment, instead of requesting the fragment and polluting the saved name (#204)
|
|
||||||
+ Fixed: escaped brackets inside a *[...] filter character class (#148)
|
|
||||||
+ Fixed: honor the server's Content-Range when resuming a partial download, instead of appending overlapping bytes (#198)
|
|
||||||
+ Fixed: abort the download as soon as the response type is excluded by -mime:, instead of fetching then discarding the body (#58)
|
|
||||||
+ Fixed: keep size-based filter rules neutral until the file size is known (#143)
|
|
||||||
+ Fixed: stop the mirror with a clean fatal error on a cache write failure, instead of crashing (#174, #219)
|
|
||||||
+ Fixed: stop the 412/416 partial re-get loop on --continue and --update (#206)
|
|
||||||
+ Fixed: keep an unrecognized URL tail instead of mangling it to .html (#115)
|
|
||||||
+ Fixed: honor --tolerant (-%B) on a broken Content-Length, and fix an out-of-bounds read it exposed (#32, #41)
|
|
||||||
+ Fixed: fall back to the next resolved address when a connection fails or stalls, instead of hanging on a dead IPv6 address
|
|
||||||
+ Fixed: report why a -%L URL list could not be loaded (#49)
|
|
||||||
+ Changed: multiple internal hardening, build and CI improvements
|
|
||||||
|
|
||||||
.49-9
|
|
||||||
+ Fixed: file-type detection from the Content-Type header: trust a declared type over a binary URL extension, honor --assume under the delayed type check, and keep a known extension against a bogus or empty Content-Type (#267, #29, #56)
|
+ Fixed: file-type detection from the Content-Type header: trust a declared type over a binary URL extension, honor --assume under the delayed type check, and keep a known extension against a bogus or empty Content-Type (#267, #29, #56)
|
||||||
+ Fixed: an uninitialized-buffer read when the Content-Type is empty (#411)
|
+ Fixed: an uninitialized-buffer read when the Content-Type is empty (#411)
|
||||||
+ Fixed: restored C++ source-compatibility of the installed headers so reverse dependencies (httraqt) build again (#413)
|
+ Fixed: restored C++ source-compatibility of the installed headers so reverse dependencies (httraqt) build again (#413)
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ See also: The <a href="faq.html#VF1">FAQ</a><br>
|
|||||||
<td>the \ character</td>
|
<td>the \ character</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td nowrap><tt>*[\[,\]]</tt></td>
|
<td nowrap><tt>*[\[\]]</tt></td>
|
||||||
<td>the [ or ] character</td>
|
<td>the [ or ] character</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ Max Depth
|
|||||||
Maximum external depth:
|
Maximum external depth:
|
||||||
Maximum external depth:
|
Maximum external depth:
|
||||||
Filters (refuse/accept links) :
|
Filters (refuse/accept links) :
|
||||||
Filters (refuse/accept links):
|
Filters (refuse/accept links) :
|
||||||
Paths
|
Paths
|
||||||
Paths
|
Paths
|
||||||
Save prefs
|
Save prefs
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
# Translating HTTrack
|
|
||||||
|
|
||||||
Interface strings live here, one `.txt` file per language. `English.txt` is the reference: every other file maps each English string to its translation.
|
|
||||||
|
|
||||||
## File format
|
|
||||||
|
|
||||||
Plain text, entries in consecutive pairs of lines:
|
|
||||||
|
|
||||||
```
|
|
||||||
<English string>
|
|
||||||
<translation>
|
|
||||||
```
|
|
||||||
|
|
||||||
The first line of a pair is the lookup key and must stay identical to the one in `English.txt`; translate only the second line. Missing entries fall back to the English text at runtime, so a partial translation works.
|
|
||||||
|
|
||||||
Preserve any `\r\n`, `\t` and `printf` placeholders (`%s`, `%d`, ...) in the translation.
|
|
||||||
|
|
||||||
A few `LANGUAGE_*` entries at the top describe the file itself:
|
|
||||||
|
|
||||||
| Key | Meaning |
|
|
||||||
| --- | --- |
|
|
||||||
| `LANGUAGE_NAME` | Name shown in the language picker, in its own language (`Deutsch`, not `German`) |
|
|
||||||
| `LANGUAGE_ISO` | ISO 639 code, with region if needed (`de`, `pt_BR`) |
|
|
||||||
| `LANGUAGE_CHARSET` | Encoding the file is saved in (`ISO-8859-1`, `windows-1251`, `UTF-8`, ...) |
|
|
||||||
| `LANGUAGE_AUTHOR` | Your name and contact |
|
|
||||||
| `LANGUAGE_WINDOWSID` | Windows locale name used by WinHTTrack (`German (Standard)`) |
|
|
||||||
|
|
||||||
Save the file in exactly its declared `LANGUAGE_CHARSET`; an editor that rewrites it as UTF-8 will corrupt the non-ASCII bytes.
|
|
||||||
|
|
||||||
## Adding or updating a language
|
|
||||||
|
|
||||||
1. Copy `English.txt` to `<Language>.txt`, or edit the existing file.
|
|
||||||
2. Translate each second line; leave the English keys untouched.
|
|
||||||
3. Fill in the `LANGUAGE_*` header for a new file.
|
|
||||||
4. Open a pull request, or attach the file to a GitHub issue.
|
|
||||||
|
|
||||||
When new strings land in `English.txt` they show up untranslated (as English) until a translator fills them in.
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
# ===========================================================================
|
|
||||||
# https://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html
|
|
||||||
# ===========================================================================
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# AX_ADD_FORTIFY_SOURCE
|
|
||||||
#
|
|
||||||
# DESCRIPTION
|
|
||||||
#
|
|
||||||
# Check whether -D_FORTIFY_SOURCE=2 can be added to CPPFLAGS without macro
|
|
||||||
# redefinition warnings, other cpp warnings or linker. Some distributions
|
|
||||||
# (such as Ubuntu or Gentoo Linux) enable _FORTIFY_SOURCE globally in
|
|
||||||
# their compilers, leading to unnecessary warnings in the form of
|
|
||||||
#
|
|
||||||
# <command-line>:0:0: error: "_FORTIFY_SOURCE" redefined [-Werror]
|
|
||||||
# <built-in>: note: this is the location of the previous definition
|
|
||||||
#
|
|
||||||
# which is a problem if -Werror is enabled. This macro checks whether
|
|
||||||
# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2
|
|
||||||
# to CPPFLAGS.
|
|
||||||
#
|
|
||||||
# Newer mingw-w64 msys2 package comes with a bug in
|
|
||||||
# headers-git-7.0.0.5546.d200317d-1. It broke -D_FORTIFY_SOURCE support,
|
|
||||||
# and would need -lssp or -fstack-protector. See
|
|
||||||
# https://github.com/msys2/MINGW-packages/issues/5803. Try to actually
|
|
||||||
# link it.
|
|
||||||
#
|
|
||||||
# LICENSE
|
|
||||||
#
|
|
||||||
# Copyright (c) 2017 David Seifert <soap@gentoo.org>
|
|
||||||
# Copyright (c) 2019, 2023 Reini Urban <rurban@cpan.org>
|
|
||||||
#
|
|
||||||
# Copying and distribution of this file, with or without modification, are
|
|
||||||
# permitted in any medium without royalty provided the copyright notice
|
|
||||||
# and this notice are preserved. This file is offered as-is, without any
|
|
||||||
# warranty.
|
|
||||||
|
|
||||||
#serial 10
|
|
||||||
|
|
||||||
AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[
|
|
||||||
ac_save_cflags=$CFLAGS
|
|
||||||
ac_cwerror_flag=yes
|
|
||||||
AX_CHECK_COMPILE_FLAG([-Werror],[CFLAGS="$CFLAGS -Werror"])
|
|
||||||
ax_add_fortify_3_failed=
|
|
||||||
AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=3 to CPPFLAGS])
|
|
||||||
AC_LINK_IFELSE([
|
|
||||||
AC_LANG_PROGRAM([],
|
|
||||||
[[
|
|
||||||
#ifndef _FORTIFY_SOURCE
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
_FORTIFY_SOURCE_already_defined;
|
|
||||||
#endif
|
|
||||||
]]
|
|
||||||
)],
|
|
||||||
AC_LINK_IFELSE([
|
|
||||||
AC_LANG_SOURCE([[
|
|
||||||
#define _FORTIFY_SOURCE 3
|
|
||||||
#include <string.h>
|
|
||||||
int main(void) {
|
|
||||||
char *s = " ";
|
|
||||||
strcpy(s, "x");
|
|
||||||
return strlen(s)-1;
|
|
||||||
}
|
|
||||||
]]
|
|
||||||
)],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
CFLAGS=$ac_save_cflags
|
|
||||||
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=3"
|
|
||||||
], [
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
ax_add_fortify_3_failed=1
|
|
||||||
],
|
|
||||||
),
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
ax_add_fortify_3_failed=1
|
|
||||||
])
|
|
||||||
if test -n "$ax_add_fortify_3_failed"
|
|
||||||
then
|
|
||||||
AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CPPFLAGS])
|
|
||||||
AC_LINK_IFELSE([
|
|
||||||
AC_LANG_PROGRAM([],
|
|
||||||
[[
|
|
||||||
#ifndef _FORTIFY_SOURCE
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
_FORTIFY_SOURCE_already_defined;
|
|
||||||
#endif
|
|
||||||
]]
|
|
||||||
)],
|
|
||||||
AC_LINK_IFELSE([
|
|
||||||
AC_LANG_SOURCE([[
|
|
||||||
#define _FORTIFY_SOURCE 2
|
|
||||||
#include <string.h>
|
|
||||||
int main(void) {
|
|
||||||
char *s = " ";
|
|
||||||
strcpy(s, "x");
|
|
||||||
return strlen(s)-1;
|
|
||||||
}
|
|
||||||
]]
|
|
||||||
)],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
CFLAGS=$ac_save_cflags
|
|
||||||
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2"
|
|
||||||
], [
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
CFLAGS=$ac_save_cflags
|
|
||||||
],
|
|
||||||
),
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
CFLAGS=$ac_save_cflags
|
|
||||||
])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
@@ -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 "27 June 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
|
||||||
@@ -24,7 +24,6 @@ httrack \- offline browser : copy websites to a local directory
|
|||||||
[ \fB\-EN, \-\-max\-time[=N]\fR ]
|
[ \fB\-EN, \-\-max\-time[=N]\fR ]
|
||||||
[ \fB\-AN, \-\-max\-rate[=N]\fR ]
|
[ \fB\-AN, \-\-max\-rate[=N]\fR ]
|
||||||
[ \fB\-%cN, \-\-connection\-per\-second[=N]\fR ]
|
[ \fB\-%cN, \-\-connection\-per\-second[=N]\fR ]
|
||||||
[ \fB\-%G, \-\-pause\fR ]
|
|
||||||
[ \fB\-GN, \-\-max\-pause[=N]\fR ]
|
[ \fB\-GN, \-\-max\-pause[=N]\fR ]
|
||||||
[ \fB\-cN, \-\-sockets[=N]\fR ]
|
[ \fB\-cN, \-\-sockets[=N]\fR ]
|
||||||
[ \fB\-TN, \-\-timeout[=N]\fR ]
|
[ \fB\-TN, \-\-timeout[=N]\fR ]
|
||||||
@@ -50,8 +49,6 @@ httrack \- offline browser : copy websites to a local directory
|
|||||||
[ \fB\-%p, \-\-preserve\fR ]
|
[ \fB\-%p, \-\-preserve\fR ]
|
||||||
[ \fB\-%T, \-\-utf8\-conversion\fR ]
|
[ \fB\-%T, \-\-utf8\-conversion\fR ]
|
||||||
[ \fB\-bN, \-\-cookies[=N]\fR ]
|
[ \fB\-bN, \-\-cookies[=N]\fR ]
|
||||||
[ \fB\-%K, \-\-cookies\-file\fR ]
|
|
||||||
[ \fB\-%Y, \-\-why\fR ]
|
|
||||||
[ \fB\-u, \-\-check\-type[=N]\fR ]
|
[ \fB\-u, \-\-check\-type[=N]\fR ]
|
||||||
[ \fB\-j, \-\-parse\-java[=N]\fR ]
|
[ \fB\-j, \-\-parse\-java[=N]\fR ]
|
||||||
[ \fB\-sN, \-\-robots[=N]\fR ]
|
[ \fB\-sN, \-\-robots[=N]\fR ]
|
||||||
@@ -157,8 +154,6 @@ maximum mirror time in seconds (60=1 minute, 3600=1 hour) (\-\-max\-time[=N])
|
|||||||
maximum transfer rate in bytes/seconds (1000=1KB/s max) (\-\-max\-rate[=N])
|
maximum transfer rate in bytes/seconds (1000=1KB/s max) (\-\-max\-rate[=N])
|
||||||
.IP \-%cN
|
.IP \-%cN
|
||||||
maximum number of connections/seconds (*%c10) (\-\-connection\-per\-second[=N])
|
maximum number of connections/seconds (*%c10) (\-\-connection\-per\-second[=N])
|
||||||
.IP \-%G
|
|
||||||
random pause of MIN[:MAX] seconds between files (e.g. %G5:10) (\-\-pause <param>)
|
|
||||||
.IP \-GN
|
.IP \-GN
|
||||||
pause transfer if N bytes reached, and wait until lock file is deleted (\-\-max\-pause[=N])
|
pause transfer if N bytes reached, and wait until lock file is deleted (\-\-max\-pause[=N])
|
||||||
.SS Flow control:
|
.SS Flow control:
|
||||||
@@ -217,10 +212,6 @@ links conversion to UTF\-8 (\-\-utf8\-conversion)
|
|||||||
.SS Spider options:
|
.SS Spider options:
|
||||||
.IP \-bN
|
.IP \-bN
|
||||||
accept cookies in cookies.txt (0=do not accept,* 1=accept) (\-\-cookies[=N])
|
accept cookies in cookies.txt (0=do not accept,* 1=accept) (\-\-cookies[=N])
|
||||||
.IP \-%K
|
|
||||||
load extra cookies from a Netscape cookies.txt (\-\-cookies\-file <param>)
|
|
||||||
.IP \-%Y
|
|
||||||
explain which filter rule accepts or rejects a URL, then exit (\-\-why <param>)
|
|
||||||
.IP \-u
|
.IP \-u
|
||||||
check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always) (\-\-check\-type[=N])
|
check document type if unknown (cgi,asp..) (u0 don't check, * u1 check but /, u2 check always) (\-\-check\-type[=N])
|
||||||
.IP \-j
|
.IP \-j
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ libhttrack_la_SOURCES = htscore.c htsparse.c htsback.c htscache.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 htszlib.c htswrap.c htsconcat.c \
|
||||||
htsmodules.c htscharset.c punycode.c htsencoding.c htssniff.c \
|
htsmodules.c htscharset.c punycode.c htsencoding.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 \
|
||||||
hts-indextmpl.h htsalias.h htsback.h htsbase.h htssafe.h \
|
hts-indextmpl.h htsalias.h htsback.h htsbase.h htssafe.h \
|
||||||
@@ -70,7 +70,7 @@ libhttrack_la_SOURCES = htscore.c htsparse.c htsback.c htscache.c \
|
|||||||
htsconfig.h htscore.h htsparse.h htscoremain.h htsdefines.h \
|
htsconfig.h htscore.h htsparse.h htscoremain.h htsdefines.h \
|
||||||
htsfilters.h htsftp.h htsglobal.h htshash.h coucal/coucal.h \
|
htsfilters.h htsftp.h htsglobal.h htshash.h coucal/coucal.h \
|
||||||
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 \
|
||||||
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 htszlib.h \
|
||||||
htsstrings.h htsarrays.h httrack-library.h \
|
htsstrings.h htsarrays.h httrack-library.h \
|
||||||
|
|||||||
@@ -112,12 +112,6 @@ const char *hts_optalias[][4] = {
|
|||||||
{"include-query-string", "-%q", "single", ""},
|
{"include-query-string", "-%q", "single", ""},
|
||||||
{"strip-query", "-%g", "param1",
|
{"strip-query", "-%g", "param1",
|
||||||
"strip [host/pattern=]key1,key2,... from URLs"},
|
"strip [host/pattern=]key1,key2,... from URLs"},
|
||||||
{"cookies-file", "-%K", "param1",
|
|
||||||
"load extra cookies from a Netscape cookies.txt"},
|
|
||||||
{"why", "-%Y", "param1",
|
|
||||||
"explain which filter rule accepts or rejects a URL, then exit"},
|
|
||||||
{"pause", "-%G", "param1",
|
|
||||||
"random pause of MIN[:MAX] seconds between files"},
|
|
||||||
{"generate-errors", "-o", "single", ""},
|
{"generate-errors", "-o", "single", ""},
|
||||||
{"do-not-generate-errors", "-o0", "single", ""},
|
{"do-not-generate-errors", "-o0", "single", ""},
|
||||||
{"purge-old", "-X", "param", ""},
|
{"purge-old", "-X", "param", ""},
|
||||||
@@ -285,6 +279,7 @@ int optalias_check(int argc, const char *const *argv, int n_arg,
|
|||||||
char *position;
|
char *position;
|
||||||
int need_param = 1;
|
int need_param = 1;
|
||||||
|
|
||||||
|
//int return_param=0;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
command[0] = param[0] = addcommand[0] = '\0';
|
command[0] = param[0] = addcommand[0] = '\0';
|
||||||
@@ -362,6 +357,7 @@ int optalias_check(int argc, const char *const *argv, int n_arg,
|
|||||||
strlcatbuff(return_argv[0], "0", return_argv_size);
|
strlcatbuff(return_argv[0], "0", return_argv_size);
|
||||||
else if (strcmp(param, "on") == 0) {
|
else if (strcmp(param, "on") == 0) {
|
||||||
// on is the default
|
// on is the default
|
||||||
|
// strcatbuff(return_argv[0],"1");
|
||||||
} else
|
} else
|
||||||
strlcatbuff(return_argv[0], param, return_argv_size);
|
strlcatbuff(return_argv[0], param, return_argv_size);
|
||||||
}
|
}
|
||||||
|
|||||||
251
src/htsback.c
251
src/htsback.c
@@ -43,12 +43,14 @@ Please visit our Website: http://www.httrack.com
|
|||||||
|
|
||||||
#include "htsback.h"
|
#include "htsback.h"
|
||||||
|
|
||||||
|
//#ifdef _WIN32
|
||||||
#include "htsftp.h"
|
#include "htsftp.h"
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
#else
|
#else
|
||||||
#error HTS_USEZLIB not defined
|
#error HTS_USEZLIB not defined
|
||||||
#endif
|
#endif
|
||||||
|
//#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
@@ -570,12 +572,9 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
&& back[p].r.size != back[p].r.totalsize && !opt->tolerant) {
|
&& back[p].r.size != back[p].r.totalsize && !opt->tolerant) {
|
||||||
if (back[p].status == STATUS_READY) {
|
if (back[p].status == STATUS_READY) {
|
||||||
hts_log_print(opt, LOG_WARNING,
|
hts_log_print(opt, LOG_WARNING,
|
||||||
"incomplete transfer (expected " LLintP
|
"file not stored in cache due to bogus state (broken size, expected "
|
||||||
" bytes, got " LLintP
|
LLintP " got " LLintP "): %s%s", back[p].r.totalsize,
|
||||||
"): file not cached, will be retried on the next update"
|
back[p].r.size, back[p].url_adr, back[p].url_fil);
|
||||||
" (use -%%B to cache anyway): %s%s",
|
|
||||||
back[p].r.totalsize, back[p].r.size, back[p].url_adr,
|
|
||||||
back[p].url_fil);
|
|
||||||
} else {
|
} else {
|
||||||
hts_log_print(opt, LOG_INFO,
|
hts_log_print(opt, LOG_INFO,
|
||||||
"incomplete file not yet stored in cache (expected "
|
"incomplete file not yet stored in cache (expected "
|
||||||
@@ -595,6 +594,7 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
#if HTS_USEZLIB
|
#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) {
|
||||||
|
//if ( (back[p].r.adr) && (back[p].r.size>0) ) {
|
||||||
// stats
|
// stats
|
||||||
back[p].compressed_size = back[p].r.size;
|
back[p].compressed_size = back[p].r.size;
|
||||||
// en mémoire -> passage sur disque
|
// en mémoire -> passage sur disque
|
||||||
@@ -879,12 +879,11 @@ int back_finalize(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
back[p].url_fil, NULL);
|
back[p].url_fil, NULL);
|
||||||
} else {
|
} else {
|
||||||
/* Partial file, but marked as "ok" ? */
|
/* Partial file, but marked as "ok" ? */
|
||||||
hts_log_print(
|
hts_log_print(opt, LOG_WARNING,
|
||||||
opt, LOG_WARNING,
|
"file not stored in cache due to bogus state (incomplete type with %s (%d), size "
|
||||||
"file with unresolved type not cached (%s (%d), size " LLintP
|
LLintP "): %s%s", back[p].r.msg, back[p].r.statuscode,
|
||||||
"): %s%s",
|
(LLint) back[p].r.size, back[p].url_adr,
|
||||||
back[p].r.msg, back[p].r.statuscode, (LLint) back[p].r.size,
|
back[p].url_fil);
|
||||||
back[p].url_adr, back[p].url_fil);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,6 +923,7 @@ int back_letlive(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
/* clear everything but connection: switch, close, and reswitch */
|
/* clear everything but connection: switch, close, and reswitch */
|
||||||
back_connxfr(src, &tmp);
|
back_connxfr(src, &tmp);
|
||||||
back_delete(opt, cache, sback, p);
|
back_delete(opt, cache, sback, p);
|
||||||
|
//deletehttp(src);
|
||||||
back_connxfr(&tmp, src);
|
back_connxfr(&tmp, src);
|
||||||
src->req.flush_garbage = 1; /* ignore CRLF garbage */
|
src->req.flush_garbage = 1; /* ignore CRLF garbage */
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1358,49 +1358,7 @@ int back_flush_output(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move a still-writing .delayed placeholder to its final name (#483). */
|
|
||||||
hts_boolean back_delayed_rename(httrackp *opt, lien_back *back,
|
|
||||||
const char *newname) {
|
|
||||||
hts_boolean renamed;
|
|
||||||
|
|
||||||
if (!back->r.is_write || back->tmpfile != NULL ||
|
|
||||||
!IS_DELAYED_EXT(back->url_sav) || strcmp(back->url_sav, newname) == 0)
|
|
||||||
return HTS_TRUE; /* nothing bound to the placeholder name */
|
|
||||||
if (back->r.out != NULL) {
|
|
||||||
fclose(back->r.out);
|
|
||||||
back->r.out = NULL;
|
|
||||||
}
|
|
||||||
renamed = RENAME(back->url_sav, newname) == 0 ? HTS_TRUE : HTS_FALSE;
|
|
||||||
if (renamed && (back->status == STATUS_READY ||
|
|
||||||
(back->r.out = FOPEN(newname, "ab")) != NULL)) {
|
|
||||||
filenote(&opt->state.strc, newname, NULL);
|
|
||||||
hts_log_print(opt, LOG_DEBUG, "moved placeholder %s to %s", back->url_sav,
|
|
||||||
newname);
|
|
||||||
return HTS_TRUE;
|
|
||||||
}
|
|
||||||
/* partial lost: drop only what we own (Windows rename won't overwrite) */
|
|
||||||
hts_log_print(opt, LOG_WARNING | LOG_ERRNO, "unable to move %s to %s",
|
|
||||||
back->url_sav, newname);
|
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
|
||||||
strcpybuff(back->r.msg, "Write error on disk");
|
|
||||||
back->r.is_write = 0;
|
|
||||||
(void) UNLINK(renamed ? newname : back->url_sav);
|
|
||||||
return HTS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// effacer entrée
|
// effacer entrée
|
||||||
/* Discard a cancelled mid-write .delayed placeholder (unusable across runs). */
|
|
||||||
void back_delayed_discard(httrackp *opt, lien_back *back) {
|
|
||||||
if (back->r.out != NULL) {
|
|
||||||
fclose(back->r.out);
|
|
||||||
back->r.out = NULL;
|
|
||||||
}
|
|
||||||
back->r.is_write = 0;
|
|
||||||
if (opt != NULL)
|
|
||||||
url_savename_refname_remove(opt, back->url_adr, back->url_fil);
|
|
||||||
(void) UNLINK(back->url_sav);
|
|
||||||
}
|
|
||||||
|
|
||||||
int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
||||||
const int p) {
|
const int p) {
|
||||||
lien_back *const back = sback->lnk;
|
lien_back *const back = sback->lnk;
|
||||||
@@ -1408,12 +1366,6 @@ int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
|
|
||||||
assertf(p >= 0 && p < back_max);
|
assertf(p >= 0 && p < back_max);
|
||||||
if (p >= 0 && p < sback->count) { // on sait jamais..
|
if (p >= 0 && p < sback->count) { // on sait jamais..
|
||||||
/* mid-write cancel: drop a .delayed placeholder; real-named partials
|
|
||||||
survive for resume (--continue) */
|
|
||||||
if (back[p].r.is_write && IS_DELAYED_EXT(back[p].url_sav) &&
|
|
||||||
(back[p].status != STATUS_READY || back[p].r.statuscode <= 0)) {
|
|
||||||
back_delayed_discard(opt, &back[p]);
|
|
||||||
}
|
|
||||||
// Vérificateur d'intégrité
|
// Vérificateur d'intégrité
|
||||||
#if DEBUG_CHECKINT
|
#if DEBUG_CHECKINT
|
||||||
_CHECKINT(&back[p], "Appel back_delete")
|
_CHECKINT(&back[p], "Appel back_delete")
|
||||||
@@ -1433,6 +1385,7 @@ int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
|||||||
back[p].url_adr, back[p].url_fil, back[p].url_sav);
|
back[p].url_adr, back[p].url_fil, back[p].url_sav);
|
||||||
}
|
}
|
||||||
if (cache != NULL) {
|
if (cache != NULL) {
|
||||||
|
//hts_log_print(opt, LOG_TRACE, "finalizing from back_delete");
|
||||||
back_finalize(opt, cache, sback, p);
|
back_finalize(opt, cache, sback, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1573,6 +1526,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
if (back[p].r.soc != INVALID_SOCKET) { /* we never know */
|
if (back[p].r.soc != INVALID_SOCKET) { /* we never know */
|
||||||
deletehttp(&back[p].r);
|
deletehttp(&back[p].r);
|
||||||
}
|
}
|
||||||
|
//memset(&(back[p].r), 0, sizeof(htsblk));
|
||||||
hts_init_htsblk(&back[p].r);
|
hts_init_htsblk(&back[p].r);
|
||||||
back[p].r.location = back[p].location_buffer;
|
back[p].r.location = back[p].location_buffer;
|
||||||
|
|
||||||
@@ -1580,6 +1534,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
strcpybuff(back[p].url_adr, adr);
|
strcpybuff(back[p].url_adr, adr);
|
||||||
strcpybuff(back[p].url_fil, fil);
|
strcpybuff(back[p].url_fil, fil);
|
||||||
strcpybuff(back[p].url_sav, save);
|
strcpybuff(back[p].url_sav, save);
|
||||||
|
//back[p].links_index = links_index;
|
||||||
// copier referer si besoin
|
// copier referer si besoin
|
||||||
strcpybuff(back[p].referer_adr, "");
|
strcpybuff(back[p].referer_adr, "");
|
||||||
strcpybuff(back[p].referer_fil, "");
|
strcpybuff(back[p].referer_fil, "");
|
||||||
@@ -1818,7 +1773,8 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
back[p].url_adr, back[p].url_fil);
|
back[p].url_adr, back[p].url_fil);
|
||||||
}
|
}
|
||||||
back[p].r.notmodified = 1; // fichier non modifié
|
back[p].r.notmodified = 1; // fichier non modifié
|
||||||
back[p].status = STATUS_READY; // OK prêt
|
back[p].status = STATUS_READY; // OK prêt
|
||||||
|
//file_notify(back[p].url_adr, back[p].url_fil, back[p].url_sav, 0, 0, back[p].r.notmodified); // not modified
|
||||||
back_set_finished(sback, p);
|
back_set_finished(sback, p);
|
||||||
|
|
||||||
// finalize transfer
|
// finalize transfer
|
||||||
@@ -1833,6 +1789,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
} else { // erreur
|
} else { // erreur
|
||||||
// effacer r
|
// effacer r
|
||||||
hts_init_htsblk(&back[p].r);
|
hts_init_htsblk(&back[p].r);
|
||||||
|
//memset(&(back[p].r), 0, sizeof(htsblk));
|
||||||
back[p].r.location = back[p].location_buffer;
|
back[p].r.location = back[p].location_buffer;
|
||||||
// et continuer (chercher le fichier)
|
// et continuer (chercher le fichier)
|
||||||
}
|
}
|
||||||
@@ -2027,6 +1984,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
// ouvrir liaison, envoyer requète
|
// ouvrir liaison, envoyer requète
|
||||||
// ne pas traiter ou recevoir l'en tête immédiatement
|
// ne pas traiter ou recevoir l'en tête immédiatement
|
||||||
hts_init_htsblk(&back[p].r);
|
hts_init_htsblk(&back[p].r);
|
||||||
|
// memset(&(back[p].r), 0, sizeof(htsblk));
|
||||||
back[p].r.location = back[p].location_buffer;
|
back[p].r.location = back[p].location_buffer;
|
||||||
// fresh connect: address list not yet probed, start at the first
|
// fresh connect: address list not yet probed, start at the first
|
||||||
sback->connect_fallback[p].addr_index = 0;
|
sback->connect_fallback[p].addr_index = 0;
|
||||||
@@ -2077,6 +2035,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
#if HTS_USEOPENSSL
|
#if HTS_USEOPENSSL
|
||||||
else if (strfield(back[p].url_adr, "https://")) { // let's rock
|
else if (strfield(back[p].url_adr, "https://")) { // let's rock
|
||||||
back[p].r.ssl = 1;
|
back[p].r.ssl = 1;
|
||||||
|
// back[p].r.ssl_soc = NULL;
|
||||||
back[p].r.ssl_con = NULL;
|
back[p].r.ssl_con = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2142,9 +2101,9 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
back[p].rateout = -1; // pas de gestion (default)
|
back[p].rateout = -1; // pas de gestion (default)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: on charge les code-page erreurs (erreur 404, etc) dans le cas où
|
// Note: on charge les code-page erreurs (erreur 404, etc) dans le cas où cela est
|
||||||
// cela est rattrapable (exemple: 301,302 moved xxx -> refresh sur la
|
// rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
|
||||||
// page!)
|
//if ((back[p].statuscode!=HTTP_OK) || (soc<0)) { // ERREUR HTTP/autre
|
||||||
|
|
||||||
#if CNXDEBUG
|
#if CNXDEBUG
|
||||||
printf("Xfopen ok, poll..\n");
|
printf("Xfopen ok, poll..\n");
|
||||||
@@ -2162,6 +2121,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
if (soc == INVALID_SOCKET) { // erreur socket
|
if (soc == INVALID_SOCKET) { // erreur socket
|
||||||
back[p].status = STATUS_READY; // FINI
|
back[p].status = STATUS_READY; // FINI
|
||||||
back_set_finished(sback, p);
|
back_set_finished(sback, p);
|
||||||
|
//if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
|
||||||
back[p].r.soc = INVALID_SOCKET;
|
back[p].r.soc = INVALID_SOCKET;
|
||||||
} else {
|
} else {
|
||||||
if (!back[p].r.is_file)
|
if (!back[p].r.is_file)
|
||||||
@@ -2182,6 +2142,8 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
|
|||||||
|
|
||||||
// note: si il y a erreur (404,etc) status=2 (terminé/échec) mais
|
// note: si il y a erreur (404,etc) status=2 (terminé/échec) mais
|
||||||
// le lien est considéré comme traité
|
// le lien est considéré comme traité
|
||||||
|
//if (back[p].soc<0) // erreur
|
||||||
|
// return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -2254,6 +2216,9 @@ void back_solve(httrackp * opt, lien_back * back) {
|
|||||||
} else {
|
} else {
|
||||||
hts_log_print(opt, LOG_DEBUG, "failed to resolve: %s", a);
|
hts_log_print(opt, LOG_DEBUG, "failed to resolve: %s", a);
|
||||||
}
|
}
|
||||||
|
//if (hts_dnstest(opt, a, 1) == 2) { // non encore testé!..
|
||||||
|
// hts_log_print(opt, LOG_DEBUG, "resolving in background: %s", a);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2272,13 +2237,12 @@ int host_wait(httrackp * opt, lien_back * back) {
|
|||||||
|
|
||||||
static int slot_can_be_cleaned(const lien_back * back) {
|
static int slot_can_be_cleaned(const lien_back * back) {
|
||||||
return (back->status == STATUS_READY) // ready
|
return (back->status == STATUS_READY) // ready
|
||||||
/* Check autoclean */
|
/* Check autoclean */
|
||||||
&& (!back->locked) // not held by hts_wait_delayed (name pending)
|
&& (!back->testmode) // not test mode
|
||||||
&& (!back->testmode) // not test mode
|
&& (strnotempty(back->url_sav)) // filename exists
|
||||||
&& (strnotempty(back->url_sav)) // filename exists
|
&& (HTTP_IS_OK(back->r.statuscode)) // HTTP "OK"
|
||||||
&& (HTTP_IS_OK(back->r.statuscode)) // HTTP "OK"
|
&& (back->r.size >= 0) // size>=0
|
||||||
&& (back->r.size >= 0) // size>=0
|
;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slot_can_be_finalized(httrackp * opt, const lien_back * back) {
|
static int slot_can_be_finalized(httrackp * opt, const lien_back * back) {
|
||||||
@@ -2302,6 +2266,11 @@ void back_clean(httrackp * opt, cache_back * cache, struct_back * sback) {
|
|||||||
(void) back_flush_output(opt, cache, sback, i); // flush output buffers
|
(void) back_flush_output(opt, cache, sback, i); // flush output buffers
|
||||||
usercommand(opt, 0, NULL, back[i].url_sav, back[i].url_adr,
|
usercommand(opt, 0, NULL, back[i].url_sav, back[i].url_adr,
|
||||||
back[i].url_fil);
|
back[i].url_fil);
|
||||||
|
//if (back[i].links_index >= 0) {
|
||||||
|
// assertf(back[i].links_index < opt->hash->max_lien);
|
||||||
|
// opt->hash->liens[back[i].links_index]->pass2 = -1;
|
||||||
|
// // *back[i].pass2_ptr=-1; // Done!
|
||||||
|
//}
|
||||||
/* MANDATORY if we don't want back_fill() to endlessly put the same file on download! */
|
/* MANDATORY if we don't want back_fill() to endlessly put the same file on download! */
|
||||||
{
|
{
|
||||||
int index = hash_read(opt->hash, back[i].url_sav, NULL, HASH_STRUCT_FILENAME ); // lecture type 0 (sav)
|
int index = hash_read(opt->hash, back[i].url_sav, NULL, HASH_STRUCT_FILENAME ); // lecture type 0 (sav)
|
||||||
@@ -2449,34 +2418,6 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
back_clean(opt, cache, sback);
|
back_clean(opt, cache, sback);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Time limit exceeded past grace: abort in-flight transfers so no wait loop
|
|
||||||
starves (#481). FTP slots stay, their thread owns the socket. */
|
|
||||||
if (!back_checkmirror(opt)) {
|
|
||||||
int aborted = 0;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < (unsigned int) back_max; i++) {
|
|
||||||
if (back[i].status > 0 && back[i].status < STATUS_FTP_TRANSFER) {
|
|
||||||
if (back[i].r.soc != INVALID_SOCKET) {
|
|
||||||
deletehttp(&back[i].r);
|
|
||||||
}
|
|
||||||
back[i].r.soc = INVALID_SOCKET;
|
|
||||||
/* drop a .delayed placeholder; real partials survive for resume */
|
|
||||||
if (back[i].r.is_write && IS_DELAYED_EXT(back[i].url_sav))
|
|
||||||
back_delayed_discard(opt, &back[i]);
|
|
||||||
back[i].r.statuscode = STATUSCODE_TIMEOUT;
|
|
||||||
strcpybuff(back[i].r.msg, "Mirror Time Out");
|
|
||||||
back[i].status = STATUS_READY;
|
|
||||||
back_set_finished(sback, i);
|
|
||||||
aborted++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (aborted > 0)
|
|
||||||
hts_log_print(opt, LOG_WARNING,
|
|
||||||
"time limit reached, %d transfer(s) aborted", aborted);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// recevoir tant qu'il y a des données (avec un maximum de max_loop boucles)
|
// recevoir tant qu'il y a des données (avec un maximum de max_loop boucles)
|
||||||
do_wait = 0;
|
do_wait = 0;
|
||||||
gestion_timeout = 0;
|
gestion_timeout = 0;
|
||||||
@@ -2485,6 +2426,9 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
|
|
||||||
busy_state = busy_recv = 0;
|
busy_state = busy_recv = 0;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
check_rate(stat_timestart, opt->maxrate); // vérifier taux de transfert
|
||||||
|
#endif
|
||||||
// inscrire les sockets actuelles, et rechercher l'ID la plus élevée
|
// inscrire les sockets actuelles, et rechercher l'ID la plus élevée
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_ZERO(&fds_c);
|
FD_ZERO(&fds_c);
|
||||||
@@ -2494,7 +2438,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
nfds = INVALID_SOCKET;
|
nfds = INVALID_SOCKET;
|
||||||
|
|
||||||
max_c = 1;
|
max_c = 1;
|
||||||
for (i_mod = 0; i_mod < (unsigned int) back_max; i_mod++) {
|
for(i_mod = 0; i_mod < (unsigned int) back_max; i_mod++) {
|
||||||
|
// for(i=0;i<back_max;i++) {
|
||||||
unsigned int i = (i_mod + mod_random) % (back_max);
|
unsigned int i = (i_mod + mod_random) % (back_max);
|
||||||
|
|
||||||
// en cas de gestion du connect préemptif
|
// en cas de gestion du connect préemptif
|
||||||
@@ -2531,7 +2476,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
// poll pour la lecture sur les sockets
|
// poll pour la lecture sur les sockets
|
||||||
if ((back[i].status > 0) && (back[i].status < 100)) { // en réception http
|
if ((back[i].status > 0) && (back[i].status < 100)) { // en réception http
|
||||||
|
|
||||||
#if BDEBUG == 1
|
#if BDEBUG==1
|
||||||
|
//printf("....socket in progress: %d\n",back[i].r.soc);
|
||||||
#endif
|
#endif
|
||||||
// non local et non ftp
|
// non local et non ftp
|
||||||
if (!back[i].r.is_file) {
|
if (!back[i].r.is_file) {
|
||||||
@@ -2617,7 +2563,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
busy_recv = 0;
|
busy_recv = 0;
|
||||||
|
|
||||||
// recevoir les données arrivées
|
// recevoir les données arrivées
|
||||||
for (i_mod = 0; i_mod < (unsigned int) back_max; i_mod++) {
|
for(i_mod = 0; i_mod < (unsigned int) back_max; i_mod++) {
|
||||||
|
// for(i=0;i<back_max;i++) {
|
||||||
unsigned int i = (i_mod + mod_random) % (back_max);
|
unsigned int i = (i_mod + mod_random) % (back_max);
|
||||||
|
|
||||||
if (back[i].status > 0) {
|
if (back[i].status > 0) {
|
||||||
@@ -2757,6 +2704,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
back[i].rateout_time = back[i].ka_time_start;
|
back[i].rateout_time = back[i].ka_time_start;
|
||||||
}
|
}
|
||||||
// envoyer header
|
// envoyer header
|
||||||
|
//if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0) // vrai get
|
||||||
HTS_STAT.stat_nrequests++;
|
HTS_STAT.stat_nrequests++;
|
||||||
if (!back[i].head_request)
|
if (!back[i].head_request)
|
||||||
http_sendhead(opt, opt->cookie, 0, back[i].send_too,
|
http_sendhead(opt, opt->cookie, 0, back[i].send_too,
|
||||||
@@ -2823,6 +2771,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
#if HTS_XGETHOST
|
#if HTS_XGETHOST
|
||||||
else if (back[i].status == STATUS_WAIT_DNS) { // attendre gethostbyname
|
else if (back[i].status == STATUS_WAIT_DNS) { // attendre gethostbyname
|
||||||
#if DEBUGDNS
|
#if DEBUGDNS
|
||||||
|
//printf("status 101 for %s\n",back[i].url_adr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!gestion_timeout)
|
if (!gestion_timeout)
|
||||||
@@ -2942,10 +2891,10 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
// range size hack old location
|
// range size hack old location
|
||||||
|
|
||||||
#if HTS_DIRECTDISK
|
#if HTS_DIRECTDISK
|
||||||
// Shortcut: store the file directly on disk when possible,
|
// Court-circuit:
|
||||||
// sparing memory
|
// Peut-on stocker le fichier directement sur disque?
|
||||||
if (back[i].status &&
|
// Ahh que ca serait vachement mieux et que ahh que la mémoire vous dit merci!
|
||||||
!back[i].locked) { // name still pending when locked
|
if (back[i].status) {
|
||||||
if (back[i].r.is_write == 0) { // mode mémoire
|
if (back[i].r.is_write == 0) { // mode mémoire
|
||||||
if (back[i].r.adr == NULL) { // rien n'a été écrit
|
if (back[i].r.adr == NULL) { // rien n'a été écrit
|
||||||
if (!back[i].testmode) { // pas mode test
|
if (!back[i].testmode) { // pas mode test
|
||||||
@@ -3095,7 +3044,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
// Si réception chunk, tester si on est pas à la fin!
|
// Si réception chunk, tester si on est pas à la fin!
|
||||||
if (back[i].status == 1) {
|
if (back[i].status == 1) {
|
||||||
if (back[i].is_chunk) { // attendre prochain chunk
|
if (back[i].is_chunk) { // attendre prochain chunk
|
||||||
if (back[i].r.size == back[i].r.totalsize) { // fin chunk!
|
if (back[i].r.size == back[i].r.totalsize) { // fin chunk!
|
||||||
|
//printf("chunk end at %d\n",back[i].r.size);
|
||||||
back[i].status = STATUS_CHUNK_CR; /* fetch ending CRLF */
|
back[i].status = STATUS_CHUNK_CR; /* fetch ending CRLF */
|
||||||
if (back[i].chunk_adr != NULL) {
|
if (back[i].chunk_adr != NULL) {
|
||||||
freet(back[i].chunk_adr);
|
freet(back[i].chunk_adr);
|
||||||
@@ -3158,9 +3108,11 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
back_finalize(opt, cache, sback, i);
|
back_finalize(opt, cache, sback, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (back[i].r.totalsize >= 0) { // tester totalsize
|
if (back[i].r.totalsize >= 0) { // tester totalsize
|
||||||
|
//if ((back[i].r.totalsize>=0) && (back[i].status==STATUS_WAIT_HEADERS)) { // tester totalsize
|
||||||
if (back[i].r.totalsize != back[i].r.size) { // pas la même!
|
if (back[i].r.totalsize != back[i].r.size) { // pas la même!
|
||||||
if (!opt->tolerant) {
|
if (!opt->tolerant) {
|
||||||
|
//#if HTS_CL_IS_FATAL
|
||||||
deleteaddr(&back[i].r);
|
deleteaddr(&back[i].r);
|
||||||
if (back[i].r.size < back[i].r.totalsize)
|
if (back[i].r.size < back[i].r.totalsize)
|
||||||
back[i].r.statuscode = STATUSCODE_CONNERROR; // recatch
|
back[i].r.statuscode = STATUSCODE_CONNERROR; // recatch
|
||||||
@@ -3169,13 +3121,14 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
" expected)", (LLint) back[i].r.size,
|
" expected)", (LLint) back[i].r.size,
|
||||||
(LLint) back[i].r.totalsize);
|
(LLint) back[i].r.totalsize);
|
||||||
} else {
|
} else {
|
||||||
|
//#else
|
||||||
// Un warning suffira..
|
// Un warning suffira..
|
||||||
hts_log_print(opt, LOG_WARNING,
|
hts_log_print(opt, LOG_WARNING,
|
||||||
"Incorrect length (" LLintP "!=" LLintP
|
"Incorrect length (" LLintP "!=" LLintP
|
||||||
" expected) for %s%s",
|
" expected) for %s%s", (LLint) back[i].r.size,
|
||||||
(LLint) back[i].r.size,
|
|
||||||
(LLint) back[i].r.totalsize, back[i].url_adr,
|
(LLint) back[i].r.totalsize, back[i].url_adr,
|
||||||
back[i].url_fil);
|
back[i].url_fil);
|
||||||
|
//#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3302,8 +3255,10 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
back[i].r.size);
|
back[i].r.size);
|
||||||
#endif
|
#endif
|
||||||
/* End */
|
/* End */
|
||||||
back[i].status = STATUS_READY; // fin
|
//if (back[i].status==STATUS_CHUNK_CR) {
|
||||||
|
back[i].status = STATUS_READY; // fin
|
||||||
back_set_finished(sback, i);
|
back_set_finished(sback, i);
|
||||||
|
//}
|
||||||
|
|
||||||
// finalize transfer if not temporary
|
// finalize transfer if not temporary
|
||||||
if (!IS_DELAYED_EXT(back[i].url_sav)) {
|
if (!IS_DELAYED_EXT(back[i].url_sav)) {
|
||||||
@@ -3770,6 +3725,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
back[i].url_adr, back[i].url_fil);
|
back[i].url_adr, back[i].url_fil);
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
|
//file_notify(back[i].url_adr, back[i].url_fil, back[i].url_sav, 0, 0, back[i].r.notmodified); // not modified
|
||||||
if (back[i].r.statuscode > 0) {
|
if (back[i].r.statuscode > 0) {
|
||||||
hts_log_print(opt, LOG_TRACE, "finalizing after cache load");
|
hts_log_print(opt, LOG_TRACE, "finalizing after cache load");
|
||||||
back_finalize(opt, cache, sback, i);
|
back_finalize(opt, cache, sback, i);
|
||||||
@@ -3779,11 +3735,37 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
back[i].url_adr, back[i].url_fil);
|
back[i].url_adr, back[i].url_fil);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
|
||||||
} else { // erreur
|
} else { // erreur
|
||||||
back[i].status = STATUS_READY; // terminé
|
back[i].status = STATUS_READY; // terminé
|
||||||
back_set_finished(sback, i);
|
back_set_finished(sback, i);
|
||||||
|
//printf("erreur cache\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********** NO - must complete the body! ********** */
|
||||||
|
#if 0
|
||||||
|
} else if (HTTP_IS_REDIRECT(back[i].r.statuscode)
|
||||||
|
|| (back[i].r.statuscode == 412)
|
||||||
|
|| (back[i].r.statuscode == 416)
|
||||||
|
) { // Ne pas prendre le html, erreurs connues et gérées
|
||||||
|
#if HTS_DEBUG_CLOSESOCK
|
||||||
|
DEBUG_W
|
||||||
|
("back_wait(301,302,303,307,412,416..): deletehttp\n");
|
||||||
|
#endif
|
||||||
|
// Couper connexion
|
||||||
|
/*KA deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET; */
|
||||||
|
back_maydeletehttp(opt, cache, sback, i);
|
||||||
|
|
||||||
|
back[i].status = STATUS_READY; // terminé
|
||||||
|
back_set_finished(sback, i);
|
||||||
|
// finalize
|
||||||
|
if (back[i].r.statuscode > 0) {
|
||||||
|
hts_log_print(opt, LOG_TRACE, "finalizing redirect & 4xx");
|
||||||
|
back_finalize(opt, cache, sback, i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/********** **************************** ********** */
|
||||||
}
|
}
|
||||||
// MIME type excluded by a -mime: filter: abort, don't fetch
|
// MIME type excluded by a -mime: filter: abort, don't fetch
|
||||||
// the body (#58)
|
// the body (#58)
|
||||||
@@ -3957,6 +3939,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
deletehttp(&back[i].r);
|
deletehttp(&back[i].r);
|
||||||
}
|
}
|
||||||
back[i].r.soc = INVALID_SOCKET;
|
back[i].r.soc = INVALID_SOCKET;
|
||||||
|
//back[i].r.statuscode=206; ????????
|
||||||
back[i].r.statuscode = STATUSCODE_NON_FATAL;
|
back[i].r.statuscode = STATUSCODE_NON_FATAL;
|
||||||
if (strnotempty(back[i].r.msg))
|
if (strnotempty(back[i].r.msg))
|
||||||
strcpybuff(back[i].r.msg,
|
strcpybuff(back[i].r.msg,
|
||||||
@@ -3977,13 +3960,10 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
&& (back[i].r.adr = (char *) malloct(2))) {
|
&& (back[i].r.adr = (char *) malloct(2))) {
|
||||||
back[i].r.adr[0] = 0;
|
back[i].r.adr[0] = 0;
|
||||||
}
|
}
|
||||||
/* locked = name pending; the waiter finalizes after
|
hts_log_print(opt, LOG_TRACE, "finalizing empty");
|
||||||
patching url_sav (else: cached as .delayed, #5) */
|
back_finalize(opt, cache, sback, i);
|
||||||
if (!back[i].locked) {
|
} else if (!back[i].r.is_chunk) { // pas de chunk
|
||||||
hts_log_print(opt, LOG_TRACE, "finalizing empty");
|
//if (back[i].r.http11!=2) { // pas de chunk
|
||||||
back_finalize(opt, cache, sback, i);
|
|
||||||
}
|
|
||||||
} else if (!back[i].r.is_chunk) { // pas de chunk
|
|
||||||
back[i].is_chunk = 0;
|
back[i].is_chunk = 0;
|
||||||
back[i].status = 1; // start body
|
back[i].status = 1; // start body
|
||||||
} else {
|
} else {
|
||||||
@@ -4044,11 +4024,14 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
if (back[i].status < 0) {
|
if (back[i].status < 0) {
|
||||||
if (!back[i].testmode) { // pas en test
|
if (!back[i].testmode) { // pas en test
|
||||||
UNLINK(back[i].url_sav); // éliminer fichier (endommagé)
|
UNLINK(back[i].url_sav); // éliminer fichier (endommagé)
|
||||||
|
//printf("&& %s\n",back[i].url_sav);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* funny log for commandline users */
|
/* funny log for commandline users */
|
||||||
|
//if (!opt->quiet) {
|
||||||
|
// petite animation
|
||||||
if (opt->verbosedisplay == HTS_VERBOSE_SIMPLE) {
|
if (opt->verbosedisplay == HTS_VERBOSE_SIMPLE) {
|
||||||
if (back[i].status == STATUS_READY) {
|
if (back[i].status == STATUS_READY) {
|
||||||
if (back[i].r.statuscode == HTTP_OK)
|
if (back[i].r.statuscode == HTTP_OK)
|
||||||
@@ -4061,16 +4044,18 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//}
|
||||||
|
|
||||||
} // status>0
|
} // status>0
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
// vérifier timeouts
|
// vérifier timeouts
|
||||||
if (gestion_timeout) {
|
if (gestion_timeout) {
|
||||||
TStamp act;
|
TStamp act;
|
||||||
|
|
||||||
act = time_local(); // temps en secondes
|
act = time_local(); // temps en secondes
|
||||||
for (i_mod = 0; i_mod < (unsigned int) back_max; i_mod++) {
|
for(i_mod = 0; i_mod < (unsigned int) back_max; i_mod++) {
|
||||||
|
// for(i=0;i<back_max;i++) {
|
||||||
unsigned int i = (i_mod + mod_random) % (back_max);
|
unsigned int i = (i_mod + mod_random) % (back_max);
|
||||||
|
|
||||||
if (back[i].status > 0) { // réception/connexion/..
|
if (back[i].status > 0) { // réception/connexion/..
|
||||||
@@ -4098,6 +4083,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
|
||||||
if (((int) (act - back[i].timeout_refresh)) >= back[i].timeout) {
|
if (((int) (act - back[i].timeout_refresh)) >= back[i].timeout) {
|
||||||
hts_log_print(opt, LOG_DEBUG, "connection timed out for %s%s", back[i].url_adr,
|
hts_log_print(opt, LOG_DEBUG, "connection timed out for %s%s", back[i].url_adr,
|
||||||
back[i].url_fil);
|
back[i].url_fil);
|
||||||
@@ -4173,11 +4159,6 @@ int back_checksize(httrackp * opt, lien_back * eback, int check_only_totalsize)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grace left to the smooth stop before in-flight transfers are aborted. */
|
|
||||||
static int back_maxtime_grace(const int maxtime) {
|
|
||||||
return maximum(5, minimum(30, maxtime / 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
int back_checkmirror(httrackp * opt) {
|
int back_checkmirror(httrackp * opt) {
|
||||||
// Check max size
|
// Check max size
|
||||||
if ((opt->maxsite > 0) && (HTS_STAT.stat_bytes >= opt->maxsite)) {
|
if ((opt->maxsite > 0) && (HTS_STAT.stat_bytes >= opt->maxsite)) {
|
||||||
@@ -4194,19 +4175,13 @@ int back_checkmirror(httrackp * opt) {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
// Check max time
|
// Check max time
|
||||||
if (opt->maxtime > 0) {
|
if ((opt->maxtime > 0)
|
||||||
const TStamp elapsed = time_local() - HTS_STAT.stat_timestart;
|
&& ((time_local() - HTS_STAT.stat_timestart) >= opt->maxtime)) {
|
||||||
|
if (!opt->state.stop) { /* not yet stopped */
|
||||||
if (elapsed >= opt->maxtime) {
|
hts_log_print(opt, LOG_ERROR, "More than %d seconds passed.. giving up",
|
||||||
if (!opt->state.stop) { /* not yet stopped */
|
opt->maxtime);
|
||||||
hts_log_print(opt, LOG_ERROR, "More than %d seconds passed.. giving up",
|
/* cancel mirror smoothly */
|
||||||
opt->maxtime);
|
hts_request_stop(opt, 0);
|
||||||
/* cancel mirror smoothly */
|
|
||||||
hts_request_stop(opt, 0);
|
|
||||||
}
|
|
||||||
/* smooth stop starved past the grace period: stop waiting (#481) */
|
|
||||||
if (elapsed - opt->maxtime >= back_maxtime_grace(opt->maxtime))
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1; /* Ok, go on */
|
return 1; /* Ok, go on */
|
||||||
|
|||||||
@@ -113,12 +113,6 @@ void back_set_locked(struct_back * sback, const int p);
|
|||||||
void back_set_unlocked(struct_back * sback, const int p);
|
void back_set_unlocked(struct_back * sback, const int p);
|
||||||
int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
|
||||||
const int p);
|
const int p);
|
||||||
/* Discard back's on-disk .delayed placeholder and its refname. */
|
|
||||||
void back_delayed_discard(httrackp *opt, lien_back *back);
|
|
||||||
/* Move back's .delayed placeholder (and open stream) to newname;
|
|
||||||
HTS_FALSE = file lost, slot flagged in error. */
|
|
||||||
hts_boolean back_delayed_rename(httrackp *opt, lien_back *back,
|
|
||||||
const char *newname);
|
|
||||||
void back_index_unlock(struct_back * sback, const int p);
|
void back_index_unlock(struct_back * sback, const int p);
|
||||||
int back_clear_entry(lien_back * back);
|
int back_clear_entry(lien_back * back);
|
||||||
int back_flush_output(httrackp * opt, cache_back * cache, struct_back * sback,
|
int back_flush_output(httrackp * opt, cache_back * cache, struct_back * sback,
|
||||||
@@ -142,8 +136,6 @@ void back_solve(httrackp * opt, lien_back * sback);
|
|||||||
int host_wait(httrackp * opt, lien_back * sback);
|
int host_wait(httrackp * opt, lien_back * sback);
|
||||||
#endif
|
#endif
|
||||||
int back_checksize(httrackp * opt, lien_back * eback, int check_only_totalsize);
|
int back_checksize(httrackp * opt, lien_back * eback, int check_only_totalsize);
|
||||||
/* Enforce -M/-E quotas: requests a smooth stop when reached; returns 0 once
|
|
||||||
the -E deadline overran its grace period (callers must stop waiting). */
|
|
||||||
int back_checkmirror(httrackp * opt);
|
int back_checkmirror(httrackp * opt);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// inline function in Wspiapi.h.
|
// inline function in Wspiapi.h.
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#include <Wspiapi.h>
|
#include <Wspiapi.h>
|
||||||
|
// #include <winsock2.h>
|
||||||
|
// #include <tpipv6.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -127,8 +129,6 @@ typedef enum HTTPStatusCode {
|
|||||||
HTTP_UNSUPPORTED_MEDIA_TYPE = 415,
|
HTTP_UNSUPPORTED_MEDIA_TYPE = 415,
|
||||||
HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
|
HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
|
||||||
HTTP_EXPECTATION_FAILED = 417,
|
HTTP_EXPECTATION_FAILED = 417,
|
||||||
HTTP_TOO_MANY_REQUESTS = 429,
|
|
||||||
HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
|
|
||||||
HTTP_INTERNAL_SERVER_ERROR = 500,
|
HTTP_INTERNAL_SERVER_ERROR = 500,
|
||||||
HTTP_NOT_IMPLEMENTED = 501,
|
HTTP_NOT_IMPLEMENTED = 501,
|
||||||
HTTP_BAD_GATEWAY = 502,
|
HTTP_BAD_GATEWAY = 502,
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
# Change this to download files
|
# Change this to download files
|
||||||
if false; then
|
if false; then
|
||||||
echo "mget https://www.unicode.org/Public/MAPPINGS/ISO8859/8859-*.TXT" | lftp
|
echo "mget ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-*.TXT" | lftp
|
||||||
echo "mget https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP*.TXT" | lftp
|
echo "mget ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP*.TXT" | lftp
|
||||||
echo "mget https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP*.TXT" | lftp
|
echo "mget ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP*.TXT" | lftp
|
||||||
echo "mget https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/EBCDIC/CP*.TXT" | lftp
|
echo "mget ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/EBCDIC/CP*.TXT" | lftp
|
||||||
echo "mget https://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/CP*.TXT" | lftp
|
echo "mget ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/CP*.TXT" | lftp
|
||||||
echo "mget https://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8*.TXT" | lftp
|
echo "mget ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8*.TXT" | lftp
|
||||||
rm -f CP932.TXT CP936.TXT CP949.TXT CP950.TXT
|
rm -f CP932.TXT CP936.TXT CP949.TXT CP950.TXT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ int cookie_add(t_cookie * cookie, const char *cook_name, const char *cook_value,
|
|||||||
#if DEBUG_COOK
|
#if DEBUG_COOK
|
||||||
printf("add_new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",
|
printf("add_new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",
|
||||||
cook_name, cook_value, domain, path);
|
cook_name, cook_value, domain, path);
|
||||||
|
//printf(">>>cook: %s<<<\n",cookie->data);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -207,6 +208,8 @@ int cookie_load(t_cookie * cookie, const char *fpath, const char *name) {
|
|||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
char buffer[8192];
|
char buffer[8192];
|
||||||
|
|
||||||
|
// cookie->data[0]='\0';
|
||||||
|
|
||||||
// Fusionner d'abord les éventuels cookies IE
|
// Fusionner d'abord les éventuels cookies IE
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
{
|
{
|
||||||
@@ -307,25 +310,14 @@ int cookie_load(t_cookie * cookie, const char *fpath, const char *name) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write cookies.txt; returns 0 on success. The jar holds live session
|
// écrire cookies.txt
|
||||||
cookies, so keep it owner-only on Unix (Windows inherits folder ACLs). */
|
// !=0 : erreur
|
||||||
int cookie_save(t_cookie * cookie, const char *name) {
|
int cookie_save(t_cookie * cookie, const char *name) {
|
||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
|
|
||||||
if (strnotempty(cookie->data)) {
|
if (strnotempty(cookie->data)) {
|
||||||
char BIGSTK line[8192];
|
char BIGSTK line[8192];
|
||||||
#ifdef _WIN32
|
|
||||||
FILE *fp = fopen(fconv(catbuff, sizeof(catbuff), name), "wb");
|
FILE *fp = fopen(fconv(catbuff, sizeof(catbuff), name), "wb");
|
||||||
#else
|
|
||||||
const int fd = open(fconv(catbuff, sizeof(catbuff), name),
|
|
||||||
O_WRONLY | O_CREAT | O_TRUNC, HTS_PROTECT_FILE);
|
|
||||||
FILE *fp = fd != -1 ? fdopen(fd, "wb") : NULL;
|
|
||||||
|
|
||||||
if (fd != -1 && fp == NULL)
|
|
||||||
close(fd); /* fdopen failed: don't leak the descriptor */
|
|
||||||
if (fp != NULL) /* O_CREAT's mode skips pre-existing jars: tighten those */
|
|
||||||
(void) fchmod(fd, HTS_PROTECT_FILE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (fp) {
|
if (fp) {
|
||||||
char *a = cookie->data;
|
char *a = cookie->data;
|
||||||
|
|||||||
299
src/htscache.c
299
src/htscache.c
@@ -40,7 +40,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htscore.h"
|
#include "htscore.h"
|
||||||
#include "htsbasenet.h"
|
#include "htsbasenet.h"
|
||||||
#include "htsmd5.h"
|
#include "htsmd5.h"
|
||||||
#include <limits.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
@@ -221,38 +220,23 @@ struct cache_back_zip_entry {
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/* Consecutive entry write failures before the cache stream is declared dead. */
|
/* A cache (new.zip) write failed: storage is gone (disk full / dropped share),
|
||||||
#define CACHE_MAX_WRITE_FAILURES 8
|
so the mirror is doomed too. Abort it via exit_xh, don't crash as assertf
|
||||||
|
did. */
|
||||||
/* Cache write failed: a fatal errno or a failure streak aborts the mirror
|
|
||||||
(exit_xh); an isolated failure only drops the current entry. */
|
|
||||||
static void cache_zip_write_failed(httrackp *opt, cache_back *cache,
|
static void cache_zip_write_failed(httrackp *opt, cache_back *cache,
|
||||||
const char *what, int zErr,
|
const char *what, int zErr) {
|
||||||
hts_boolean entry_open, const char *url_adr,
|
if (!cache->zipWriteFailed) {
|
||||||
const char *url_fil) {
|
cache->zipWriteFailed = HTS_TRUE;
|
||||||
const int fatal_errno = zErr == ZIP_ERRNO && check_fatal_io_errno();
|
if (check_fatal_io_errno()) {
|
||||||
|
hts_log_print(opt, LOG_ERROR,
|
||||||
cache->zipWriteFailures++;
|
"Mirror aborted: disk full or filesystem problems");
|
||||||
if (fatal_errno || cache->zipWriteFailures >= CACHE_MAX_WRITE_FAILURES) {
|
} else {
|
||||||
if (!cache->zipWriteFailed) {
|
hts_log_print(opt, LOG_ERROR,
|
||||||
cache->zipWriteFailed = HTS_TRUE;
|
"Mirror aborted: cache write failed (%s): %s", what,
|
||||||
if (fatal_errno) {
|
hts_get_zerror(zErr));
|
||||||
hts_log_print(opt, LOG_ERROR,
|
|
||||||
"Mirror aborted: disk full or filesystem problems");
|
|
||||||
} else {
|
|
||||||
hts_log_print(opt, LOG_ERROR,
|
|
||||||
"Mirror aborted: cache write failed (%s): %s", what,
|
|
||||||
hts_get_zerror(zErr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
opt->state.exit_xh = -1; /* fatal: stop the mirror, exit non-zero */
|
|
||||||
} else {
|
|
||||||
if (entry_open)
|
|
||||||
zipCloseFileInZip((zipFile) cache->zipOutput); /* abandon, best-effort */
|
|
||||||
hts_log_print(opt, LOG_WARNING,
|
|
||||||
"cache write failed (%s: %s), entry not cached: %s%s", what,
|
|
||||||
hts_get_zerror(zErr), url_adr, url_fil);
|
|
||||||
}
|
}
|
||||||
|
opt->state.exit_xh = -1; /* fatal: stop the mirror, exit non-zero */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ajout d'un fichier en cache */
|
/* Ajout d'un fichier en cache */
|
||||||
@@ -265,6 +249,8 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
|
|||||||
char BIGSTK headers[8192];
|
char BIGSTK headers[8192];
|
||||||
int headersSize = 0;
|
int headersSize = 0;
|
||||||
|
|
||||||
|
//int entryBodySize = 0;
|
||||||
|
//int entryFilenameSize = 0;
|
||||||
zip_fileinfo fi;
|
zip_fileinfo fi;
|
||||||
const char *url_save_suffix = url_save;
|
const char *url_save_suffix = url_save;
|
||||||
int zErr;
|
int zErr;
|
||||||
@@ -300,19 +286,10 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
|
|||||||
if (r->size < 0) // error
|
if (r->size < 0) // error
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// data in cache: the body must fit the 32-bit zip write API
|
// data in cache
|
||||||
if (dataincache && (LLint) (int) r->size != r->size) {
|
if (dataincache) {
|
||||||
if (r->is_write && url_save != NULL && strnotempty(url_save)) {
|
assertf(((int) r->size) == r->size);
|
||||||
hts_log_print(opt, LOG_WARNING,
|
//entryBodySize = (int) r->size;
|
||||||
"file too large for the cache, storing headers only: %s%s",
|
|
||||||
url_adr, url_fil);
|
|
||||||
dataincache = 0;
|
|
||||||
} else {
|
|
||||||
hts_log_print(opt, LOG_WARNING,
|
|
||||||
"entry too large for the cache, not cached: %s%s", url_adr,
|
|
||||||
url_fil);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fields */
|
/* Fields */
|
||||||
@@ -357,6 +334,8 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
|
|||||||
ZIP_FIELD_STRING(headers, headersSize, "X-Fil", url_fil); // Original URI filename
|
ZIP_FIELD_STRING(headers, headersSize, "X-Fil", url_fil); // Original URI filename
|
||||||
ZIP_FIELD_STRING(headers, headersSize, "X-Save", url_save_suffix); // Original save filename
|
ZIP_FIELD_STRING(headers, headersSize, "X-Save", url_save_suffix); // Original save filename
|
||||||
|
|
||||||
|
//entryFilenameSize = (int) ( strlen(url_adr) + strlen(url_fil));
|
||||||
|
|
||||||
/* Filename */
|
/* Filename */
|
||||||
if (!link_has_authority(url_adr)) {
|
if (!link_has_authority(url_adr)) {
|
||||||
strcpybuff(filename, "http://");
|
strcpybuff(filename, "http://");
|
||||||
@@ -390,8 +369,7 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
|
|||||||
*/
|
*/
|
||||||
headers, (uInt) strlen(headers), NULL, 0, NULL, /* comment */
|
headers, (uInt) strlen(headers), NULL, 0, NULL, /* comment */
|
||||||
Z_DEFLATED, Z_DEFAULT_COMPRESSION)) != Z_OK) {
|
Z_DEFLATED, Z_DEFAULT_COMPRESSION)) != Z_OK) {
|
||||||
cache_zip_write_failed(opt, cache, "opening a cache entry", zErr, HTS_FALSE,
|
cache_zip_write_failed(opt, cache, "opening a cache entry", zErr);
|
||||||
url_adr, url_fil);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,8 +380,7 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
|
|||||||
if ((zErr =
|
if ((zErr =
|
||||||
zipWriteInFileInZip((zipFile) cache->zipOutput, r->adr,
|
zipWriteInFileInZip((zipFile) cache->zipOutput, r->adr,
|
||||||
(int) r->size)) != Z_OK) {
|
(int) r->size)) != Z_OK) {
|
||||||
cache_zip_write_failed(opt, cache, "writing to the cache", zErr,
|
cache_zip_write_failed(opt, cache, "writing to the cache", zErr);
|
||||||
HTS_TRUE, url_adr, url_fil);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,8 +402,8 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
|
|||||||
if ((zErr =
|
if ((zErr =
|
||||||
zipWriteInFileInZip((zipFile) cache->zipOutput, buff,
|
zipWriteInFileInZip((zipFile) cache->zipOutput, buff,
|
||||||
(int) nl)) != Z_OK) {
|
(int) nl)) != Z_OK) {
|
||||||
cache_zip_write_failed(opt, cache, "writing to the cache", zErr,
|
cache_zip_write_failed(opt, cache, "writing to the cache",
|
||||||
HTS_TRUE, url_adr, url_fil);
|
zErr);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -442,19 +419,15 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
|
|||||||
|
|
||||||
/* Close */
|
/* Close */
|
||||||
if ((zErr = zipCloseFileInZip((zipFile) cache->zipOutput)) != Z_OK) {
|
if ((zErr = zipCloseFileInZip((zipFile) cache->zipOutput)) != Z_OK) {
|
||||||
cache_zip_write_failed(opt, cache, "closing a cache entry", zErr, HTS_FALSE,
|
cache_zip_write_failed(opt, cache, "closing a cache entry", zErr);
|
||||||
url_adr, url_fil);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flush */
|
/* Flush */
|
||||||
if ((zErr = zipFlush((zipFile) cache->zipOutput)) != 0) {
|
if ((zErr = zipFlush((zipFile) cache->zipOutput)) != 0) {
|
||||||
cache_zip_write_failed(opt, cache, "flushing the cache", zErr, HTS_FALSE,
|
cache_zip_write_failed(opt, cache, "flushing the cache", zErr);
|
||||||
url_adr, url_fil);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->zipWriteFailures = 0; /* entry stored: reset the failure streak */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -623,18 +596,15 @@ htsblk cache_read_ro(httrackp * opt, cache_back * cache, const char *adr,
|
|||||||
return cache_readex(opt, cache, adr, fil, save, location, NULL, 1);
|
return cache_readex(opt, cache, adr, fil, save, location, NULL, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
htsblk cache_read_including_broken(httrackp *opt, cache_back *cache,
|
htsblk cache_read_including_broken(httrackp * opt, cache_back * cache,
|
||||||
const char *adr, const char *fil,
|
const char *adr, const char *fil) {
|
||||||
char *return_save) {
|
htsblk r = cache_read(opt, cache, adr, fil, NULL, NULL);
|
||||||
htsblk r = cache_readex(opt, cache, adr, fil, NULL, NULL, return_save, 0);
|
|
||||||
|
|
||||||
if (r.statuscode == -1) {
|
if (r.statuscode == -1) {
|
||||||
lien_back *itemback = NULL;
|
lien_back *itemback = NULL;
|
||||||
|
|
||||||
if (back_unserialize_ref(opt, adr, fil, &itemback) == 0) {
|
if (back_unserialize_ref(opt, adr, fil, &itemback) == 0) {
|
||||||
r = itemback->r;
|
r = itemback->r;
|
||||||
if (return_save != NULL)
|
|
||||||
strlcpybuff(return_save, itemback->url_sav, HTS_URLMAXSIZE * 2);
|
|
||||||
/* cleanup */
|
/* cleanup */
|
||||||
back_clear_entry(itemback); /* delete entry content */
|
back_clear_entry(itemback); /* delete entry content */
|
||||||
freet(itemback); /* delete item */
|
freet(itemback); /* delete item */
|
||||||
@@ -721,6 +691,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
|||||||
char BIGSTK headerBuff[8192 + 2];
|
char BIGSTK headerBuff[8192 + 2];
|
||||||
int readSizeHeader;
|
int readSizeHeader;
|
||||||
|
|
||||||
|
//int totalHeader = 0;
|
||||||
int dataincache = 0;
|
int dataincache = 0;
|
||||||
|
|
||||||
/* For BIG comments */
|
/* For BIG comments */
|
||||||
@@ -771,10 +742,13 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
|||||||
HTS_URLMAXSIZE * 2);
|
HTS_URLMAXSIZE * 2);
|
||||||
ZIP_READFIELD_STRING(line, value, "Content-Disposition", r.cdispo,
|
ZIP_READFIELD_STRING(line, value, "Content-Disposition", r.cdispo,
|
||||||
sizeof(r.cdispo));
|
sizeof(r.cdispo));
|
||||||
|
//ZIP_READFIELD_STRING(line, value, "X-Addr", ..); // Original address
|
||||||
|
//ZIP_READFIELD_STRING(line, value, "X-Fil", ..); // Original URI filename
|
||||||
ZIP_READFIELD_STRING(line, value, "X-Save", previous_save_,
|
ZIP_READFIELD_STRING(line, value, "X-Save", previous_save_,
|
||||||
sizeof(previous_save_));
|
sizeof(previous_save_));
|
||||||
}
|
}
|
||||||
} while (offset < readSizeHeader && !lineEof);
|
} while(offset < readSizeHeader && !lineEof);
|
||||||
|
//totalHeader = offset;
|
||||||
|
|
||||||
/* Previous entry */
|
/* Previous entry */
|
||||||
if (previous_save_[0] != '\0') {
|
if (previous_save_[0] != '\0') {
|
||||||
@@ -791,15 +765,6 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
|||||||
strlcpybuff(return_save, previous_save, HTS_URLMAXSIZE * 2);
|
strlcpybuff(return_save, previous_save, HTS_URLMAXSIZE * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A negative X-Size is corrupt; so is one >= INT_MAX when the data
|
|
||||||
is in the zip (the write path asserts int-sized). Headers-only
|
|
||||||
entries legitimately exceed INT_MAX (>2GB body on disk): keep
|
|
||||||
them, or every update would re-fetch the file. */
|
|
||||||
if (r.size < 0 || (dataincache && r.size >= INT_MAX)) {
|
|
||||||
r.statuscode = STATUSCODE_INVALID;
|
|
||||||
strcpybuff(r.msg, "Cache Read Error : Bad Size");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Complete fields */
|
/* Complete fields */
|
||||||
r.totalsize = r.size;
|
r.totalsize = r.size;
|
||||||
r.adr = NULL;
|
r.adr = NULL;
|
||||||
@@ -826,8 +791,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
|||||||
} // otherwise, the ZIP file is supposed to be consistent with data.
|
} // otherwise, the ZIP file is supposed to be consistent with data.
|
||||||
}
|
}
|
||||||
/* Read data ? */
|
/* Read data ? */
|
||||||
else if (r.statuscode !=
|
else { /* ne pas lire uniquement header */
|
||||||
STATUSCODE_INVALID) { /* ne pas lire uniquement header */
|
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
#if HTS_DIRECTDISK
|
#if HTS_DIRECTDISK
|
||||||
@@ -956,6 +920,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
|||||||
r.statuscode = STATUSCODE_INVALID;
|
r.statuscode = STATUSCODE_INVALID;
|
||||||
strcpybuff(r.msg,
|
strcpybuff(r.msg,
|
||||||
"Cache Write Error : Unable to Create File");
|
"Cache Write Error : Unable to Create File");
|
||||||
|
//printf("%s\n",save);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -990,10 +955,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
|||||||
strcpybuff(r.msg,
|
strcpybuff(r.msg,
|
||||||
"Previous cache file not found (empty filename)");
|
"Previous cache file not found (empty filename)");
|
||||||
}
|
}
|
||||||
} else if (r.size >= INT_MAX) { /* too big to read in memory */
|
} else { /* Read in memory from disk */
|
||||||
r.statuscode = STATUSCODE_INVALID;
|
|
||||||
strcpybuff(r.msg, "Cache Read Error : Bad Size");
|
|
||||||
} else { /* Read in memory from disk */
|
|
||||||
FILE *const fp = FOPEN(fconv(catbuff, sizeof(catbuff), previous_save), "rb");
|
FILE *const fp = FOPEN(fconv(catbuff, sizeof(catbuff), previous_save), "rb");
|
||||||
|
|
||||||
if (fp != NULL) {
|
if (fp != NULL) {
|
||||||
@@ -1033,6 +995,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
|||||||
strcpybuff(r.msg, "Cache Read Error : Read Data");
|
strcpybuff(r.msg, "Cache Read Error : Read Data");
|
||||||
} else
|
} else
|
||||||
*(r.adr + r.size) = '\0';
|
*(r.adr + r.size) = '\0';
|
||||||
|
//printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
|
||||||
} else { // erreur
|
} else { // erreur
|
||||||
r.statuscode = STATUSCODE_INVALID;
|
r.statuscode = STATUSCODE_INVALID;
|
||||||
strcpybuff(r.msg, "Cache Memory Error");
|
strcpybuff(r.msg, "Cache Memory Error");
|
||||||
@@ -1211,14 +1174,17 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
|
|||||||
// sécurité
|
// sécurité
|
||||||
r.adr = NULL;
|
r.adr = NULL;
|
||||||
r.out = NULL;
|
r.out = NULL;
|
||||||
|
////r.location=NULL; non, fixée lors des 301 ou 302
|
||||||
r.fp = NULL;
|
r.fp = NULL;
|
||||||
|
|
||||||
if ((r.statuscode >= 0) && (r.statuscode <= 999)
|
if ((r.statuscode >= 0) && (r.statuscode <= 999)
|
||||||
&& (r.notmodified >= 0) && (r.notmodified <= 9)) { // petite vérif intégrité
|
&& (r.notmodified >= 0) && (r.notmodified <= 9)) { // petite vérif intégrité
|
||||||
if ((save) && (!header_only)) { /* ne pas lire uniquement header */
|
if ((save) && (!header_only)) { /* ne pas lire uniquement header */
|
||||||
|
//int to_file=0;
|
||||||
|
|
||||||
r.adr = NULL;
|
r.adr = NULL;
|
||||||
r.soc = INVALID_SOCKET;
|
r.soc = INVALID_SOCKET;
|
||||||
|
// // r.location=NULL;
|
||||||
|
|
||||||
#if HTS_DIRECTDISK
|
#if HTS_DIRECTDISK
|
||||||
// Court-circuit:
|
// Court-circuit:
|
||||||
@@ -1227,11 +1193,12 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
|
|||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
r.is_write = 1; // écrire
|
r.is_write = 1; // écrire
|
||||||
if (fexist_utf8(fconv(catbuff, sizeof(catbuff),
|
if (fexist_utf8(fconv(catbuff, sizeof(catbuff), save))) { // un fichier existe déja
|
||||||
save))) { // un fichier existe déja
|
//if (fsize_utf8(fconv(save))==r.size) { // même taille -- NON tant pis (taille mal declaree)
|
||||||
ok = 1; // plus rien à faire
|
ok = 1; // plus rien à faire
|
||||||
filenote(&opt->state.strc, save, NULL); // noter comme connu
|
filenote(&opt->state.strc, save, NULL); // noter comme connu
|
||||||
file_notify(opt, adr, fil, save, 0, 0, 0);
|
file_notify(opt, adr, fil, save, 0, 0, 0);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pos < 0) && (!ok)) { // Pas de donnée en cache et fichier introuvable : erreur!
|
if ((pos < 0) && (!ok)) { // Pas de donnée en cache et fichier introuvable : erreur!
|
||||||
@@ -1282,6 +1249,7 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
|
|||||||
r.statuscode = STATUSCODE_INVALID;
|
r.statuscode = STATUSCODE_INVALID;
|
||||||
strcpybuff(r.msg,
|
strcpybuff(r.msg,
|
||||||
"Cache Write Error : Unable to Create File");
|
"Cache Write Error : Unable to Create File");
|
||||||
|
//printf("%s\n",save);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,13 +1297,14 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
|
|||||||
strcpybuff(r.msg, "Cache Read Error : Read Data");
|
strcpybuff(r.msg, "Cache Read Error : Read Data");
|
||||||
} else
|
} else
|
||||||
*(r.adr + r.size) = '\0';
|
*(r.adr + r.size) = '\0';
|
||||||
|
//printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
|
||||||
} else { // erreur
|
} else { // erreur
|
||||||
r.statuscode = STATUSCODE_INVALID;
|
r.statuscode = STATUSCODE_INVALID;
|
||||||
strcpybuff(r.msg, "Cache Memory Error");
|
strcpybuff(r.msg, "Cache Memory Error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // si save==null, ne rien charger (juste en tête)
|
} // si save==null, ne rien charger (juste en tête)
|
||||||
} else {
|
} else {
|
||||||
#if DEBUGCA
|
#if DEBUGCA
|
||||||
printf("Cache Read Error : Bad Data");
|
printf("Cache Read Error : Bad Data");
|
||||||
@@ -1448,86 +1417,6 @@ static int hts_rename(httrackp * opt, const char *a, const char *b) {
|
|||||||
return rename(a, b);
|
return rename(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pathname of a file inside the mirror dir (rotating concat buffer). */
|
|
||||||
static char *reconcile_path(httrackp *opt, const char *name) {
|
|
||||||
return fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interrupted-run heuristic: prefer the old generation when the new cache
|
|
||||||
stalled below NEW_TINY while the old one grew past OLD_SOLID (historical
|
|
||||||
arbitrary thresholds). */
|
|
||||||
#define CACHE_RECONCILE_NEW_TINY 32768
|
|
||||||
#define CACHE_RECONCILE_OLD_SOLID 65536
|
|
||||||
|
|
||||||
/* Replace the new-generation file by the old one, when the old one exists. */
|
|
||||||
static void reconcile_promote(httrackp *opt, const char *oldname,
|
|
||||||
const char *newname) {
|
|
||||||
if (fexist(reconcile_path(opt, oldname))) {
|
|
||||||
remove(reconcile_path(opt, newname));
|
|
||||||
rename(reconcile_path(opt, oldname), reconcile_path(opt, newname));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hts_cache_reconcile(httrackp *opt, hts_cache_reconcile_mode mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case CACHE_RECONCILE_PROMOTE:
|
|
||||||
/* Previous run rotated new.* to old.* then died before writing: promote
|
|
||||||
the old generation back, whichever format it uses. */
|
|
||||||
if (!fexist(reconcile_path(opt, "hts-cache/new.zip")))
|
|
||||||
reconcile_promote(opt, "hts-cache/old.zip", "hts-cache/new.zip");
|
|
||||||
if ((!fexist(reconcile_path(opt, "hts-cache/new.dat")) ||
|
|
||||||
!fexist(reconcile_path(opt, "hts-cache/new.ndx"))) &&
|
|
||||||
fexist(reconcile_path(opt, "hts-cache/old.dat")) &&
|
|
||||||
fexist(reconcile_path(opt, "hts-cache/old.ndx"))) {
|
|
||||||
reconcile_promote(opt, "hts-cache/old.dat", "hts-cache/new.dat");
|
|
||||||
reconcile_promote(opt, "hts-cache/old.ndx", "hts-cache/new.ndx");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CACHE_RECONCILE_INTERRUPTED:
|
|
||||||
/* Aborted run: keep the larger generation when the new cache is
|
|
||||||
suspiciously small next to the old one. The new file must exist: fsize()
|
|
||||||
is -1 for a missing file, which would spuriously pass the "< TINY" test
|
|
||||||
and overwrite a solid old generation that PROMOTE/ROLLBACK should keep.
|
|
||||||
*/
|
|
||||||
if (!opt->cache || !fexist(reconcile_path(opt, "hts-in_progress.lock")))
|
|
||||||
break;
|
|
||||||
if (fexist(reconcile_path(opt, "hts-cache/new.zip")) &&
|
|
||||||
fexist(reconcile_path(opt, "hts-cache/old.zip")) &&
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/new.zip")) <
|
|
||||||
CACHE_RECONCILE_NEW_TINY &&
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/old.zip")) >
|
|
||||||
CACHE_RECONCILE_OLD_SOLID &&
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/old.zip")) >
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/new.zip")))
|
|
||||||
reconcile_promote(opt, "hts-cache/old.zip", "hts-cache/new.zip");
|
|
||||||
if (fexist(reconcile_path(opt, "hts-cache/new.dat")) &&
|
|
||||||
fexist(reconcile_path(opt, "hts-cache/old.dat")) &&
|
|
||||||
fexist(reconcile_path(opt, "hts-cache/old.ndx")) &&
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/new.dat")) <
|
|
||||||
CACHE_RECONCILE_NEW_TINY &&
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/old.dat")) >
|
|
||||||
CACHE_RECONCILE_OLD_SOLID &&
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/old.dat")) >
|
|
||||||
fsize(reconcile_path(opt, "hts-cache/new.dat"))) {
|
|
||||||
reconcile_promote(opt, "hts-cache/old.dat", "hts-cache/new.dat");
|
|
||||||
reconcile_promote(opt, "hts-cache/old.ndx", "hts-cache/new.ndx");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CACHE_RECONCILE_ROLLBACK:
|
|
||||||
/* Nothing transferred: restore the previous generation and sidecars. */
|
|
||||||
reconcile_promote(opt, "hts-cache/old.zip", "hts-cache/new.zip");
|
|
||||||
if (fexist(reconcile_path(opt, "hts-cache/old.dat")) &&
|
|
||||||
fexist(reconcile_path(opt, "hts-cache/old.ndx"))) {
|
|
||||||
reconcile_promote(opt, "hts-cache/old.dat", "hts-cache/new.dat");
|
|
||||||
reconcile_promote(opt, "hts-cache/old.ndx", "hts-cache/new.ndx");
|
|
||||||
}
|
|
||||||
reconcile_promote(opt, "hts-cache/old.lst", "hts-cache/new.lst");
|
|
||||||
reconcile_promote(opt, "hts-cache/old.txt", "hts-cache/new.txt");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// renvoyer uniquement en tête, ou NULL si erreur
|
// renvoyer uniquement en tête, ou NULL si erreur
|
||||||
// return NULL upon error, and set -1 to r.statuscode
|
// return NULL upon error, and set -1 to r.statuscode
|
||||||
htsblk *cache_header(httrackp * opt, cache_back * cache, const char *adr,
|
htsblk *cache_header(httrackp * opt, cache_back * cache, const char *adr,
|
||||||
@@ -1558,10 +1447,25 @@ void cache_init(cache_back * cache, httrackp * opt) {
|
|||||||
mkdir(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache"),
|
mkdir(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache"),
|
||||||
HTS_PROTECT_FOLDER);
|
HTS_PROTECT_FOLDER);
|
||||||
#endif
|
#endif
|
||||||
if ((fexist(fconcat(
|
if ((fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/new.zip")))) { // il existe déja un cache précédent.. renommer
|
||||||
OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
/* Previous cache from the previous cache version */
|
||||||
StringBuff(opt->path_log),
|
#if 0
|
||||||
"hts-cache/new.zip")))) { // a previous cache exists.. rename it
|
/* No.. reuse with old httrack releases! */
|
||||||
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.dat")))
|
||||||
|
remove(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.dat"));
|
||||||
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.ndx")))
|
||||||
|
remove(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.ndx"));
|
||||||
|
#endif
|
||||||
/* Previous cache version */
|
/* Previous cache version */
|
||||||
if ((fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/new.dat"))) && (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/new.ndx")))) { // il existe déja un cache précédent.. renommer
|
if ((fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/new.dat"))) && (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/new.ndx")))) { // il existe déja un cache précédent.. renommer
|
||||||
rename(fconcat
|
rename(fconcat
|
||||||
@@ -1602,13 +1506,7 @@ void cache_init(cache_back * cache, httrackp * opt) {
|
|||||||
} else {
|
} else {
|
||||||
hts_log_print(opt, LOG_DEBUG, "Cache: successfully renamed");
|
hts_log_print(opt, LOG_DEBUG, "Cache: successfully renamed");
|
||||||
}
|
}
|
||||||
} else if ((fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
} else if ((fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/new.dat"))) && (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache/new.ndx")))) { // il existe déja un cache précédent.. renommer
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.dat"))) &&
|
|
||||||
(fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log),
|
|
||||||
"hts-cache/new.ndx")))) { // a previous cache
|
|
||||||
// exists.. rename it
|
|
||||||
#if DEBUGCA
|
#if DEBUGCA
|
||||||
printf("work with former cache\n");
|
printf("work with former cache\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -1637,7 +1535,7 @@ void cache_init(cache_back * cache, httrackp * opt) {
|
|||||||
"hts-cache/new.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
"hts-cache/new.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
StringBuff(opt->path_log),
|
StringBuff(opt->path_log),
|
||||||
"hts-cache/old.ndx"));
|
"hts-cache/old.ndx"));
|
||||||
} else { // one or both cache files missing: remove the remaining one
|
} else { // un des deux (ou les deux) fichiers cache absents: effacer l'autre éventuel
|
||||||
#if DEBUGCA
|
#if DEBUGCA
|
||||||
printf("new cache\n");
|
printf("new cache\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -1938,17 +1836,15 @@ void cache_init(cache_back * cache, httrackp * opt) {
|
|||||||
char linepos[256];
|
char linepos[256];
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
const char *const end = cache->use + buffl;
|
while((a != NULL) && (a < (cache->use + buffl))) {
|
||||||
|
|
||||||
while ((a != NULL) && (a < end)) {
|
|
||||||
a = strchr(a + 1, '\n'); /* start of line */
|
a = strchr(a + 1, '\n'); /* start of line */
|
||||||
if (a) {
|
if (a) {
|
||||||
a++;
|
a++;
|
||||||
/* read "host/file" */
|
/* read "host/file" */
|
||||||
a += cache_binput(a, end, line, HTS_URLMAXSIZE);
|
a += binput(a, line, HTS_URLMAXSIZE);
|
||||||
a += cache_binput(a, end, line + strlen(line), HTS_URLMAXSIZE);
|
a += binput(a, line + strlen(line), HTS_URLMAXSIZE);
|
||||||
/* read position */
|
/* read position */
|
||||||
a += cache_binput(a, end, linepos, 200);
|
a += binput(a, linepos, 200);
|
||||||
sscanf(linepos, "%d", &pos);
|
sscanf(linepos, "%d", &pos);
|
||||||
coucal_add(cache->hashtable, line, pos);
|
coucal_add(cache->hashtable, line, pos);
|
||||||
}
|
}
|
||||||
@@ -2008,6 +1904,12 @@ void cache_init(cache_back * cache, httrackp * opt) {
|
|||||||
"hts-cache/new.lst"), "wb");
|
"hts-cache/new.lst"), "wb");
|
||||||
strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
|
strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
|
||||||
opt->state.strc.lst = cache->lst;
|
opt->state.strc.lst = cache->lst;
|
||||||
|
//{
|
||||||
|
//filecreate_params tmp;
|
||||||
|
//strcpybuff(tmp.path,StringBuff(opt->path_html)); // chemin
|
||||||
|
//tmp.lst=cache->lst; // fichier lst
|
||||||
|
//filenote("",&tmp); // initialiser filecreate
|
||||||
|
//}
|
||||||
|
|
||||||
// supprimer old.txt
|
// supprimer old.txt
|
||||||
if (fexist
|
if (fexist
|
||||||
@@ -2096,6 +1998,12 @@ void cache_init(cache_back * cache, httrackp * opt) {
|
|||||||
"hts-cache/new.lst"), "wb");
|
"hts-cache/new.lst"), "wb");
|
||||||
strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
|
strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
|
||||||
opt->state.strc.lst = cache->lst;
|
opt->state.strc.lst = cache->lst;
|
||||||
|
//{
|
||||||
|
// filecreate_params tmp;
|
||||||
|
// strcpybuff(tmp.path,StringBuff(opt->path_html)); // chemin
|
||||||
|
// tmp.lst=cache->lst; // fichier lst
|
||||||
|
// filenote("",&tmp); // initialiser filecreate
|
||||||
|
//}
|
||||||
|
|
||||||
// supprimer old.txt
|
// supprimer old.txt
|
||||||
if (fexist
|
if (fexist
|
||||||
@@ -2127,6 +2035,8 @@ void cache_init(cache_back * cache, httrackp * opt) {
|
|||||||
"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"
|
"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"
|
||||||
LF);
|
LF);
|
||||||
}
|
}
|
||||||
|
// test
|
||||||
|
// cache_writedata(cache->ndx,cache->dat,"//[TEST]//","test1","TEST PIPO",9);
|
||||||
} // cache->ndx!=NULL
|
} // cache->ndx!=NULL
|
||||||
} //cache->zipOutput != NULL
|
} //cache->zipOutput != NULL
|
||||||
|
|
||||||
@@ -2293,40 +2203,23 @@ int cache_brstr(char *adr, char *s, size_t s_size) {
|
|||||||
char buff[256 + 4];
|
char buff[256 + 4];
|
||||||
|
|
||||||
off = binput(adr, buff, 256);
|
off = binput(adr, buff, 256);
|
||||||
/* binput stops at the buffer's terminating NUL; a value can only follow a
|
adr += off;
|
||||||
real line terminator, so never step past end-of-buffer. */
|
sscanf(buff, "%d", &i);
|
||||||
if (adr[off - 1] == '\0') {
|
if (i < 0 || i > 32768) /* guard a corrupt length */
|
||||||
s[0] = '\0';
|
|
||||||
return off - 1;
|
|
||||||
}
|
|
||||||
/* an empty/non-numeric field leaves i unset: treat as length 0 */
|
|
||||||
if (sscanf(buff, "%d", &i) != 1 || i < 0 || i > 32768)
|
|
||||||
i = 0;
|
i = 0;
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
/* A corrupt/truncated cache may declare a length past the buffer end;
|
/* copy at most s_size-1 bytes; advance past the full field regardless */
|
||||||
bound both the copy and the advance to the bytes actually present. */
|
const size_t store = (size_t) i < s_size ? (size_t) i : s_size - 1;
|
||||||
const size_t avail = strnlen(adr + off, (size_t) i);
|
|
||||||
const size_t store = avail < s_size ? avail : s_size - 1;
|
|
||||||
|
|
||||||
memcpy(s, adr + off, store);
|
strncpy(s, adr, store);
|
||||||
s[store] = '\0';
|
s[store] = '\0';
|
||||||
off += (int) avail;
|
|
||||||
} else {
|
} else {
|
||||||
s[0] = '\0';
|
s[0] = '\0';
|
||||||
}
|
}
|
||||||
|
off += i;
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* binput bounded to a NUL-terminated buffer: refuse to start a read at or
|
|
||||||
past `end`, so a prior over-advance can't walk a cache-index parse OOB. */
|
|
||||||
int cache_binput(char *adr, const char *end, char *s, int max) {
|
|
||||||
if (adr >= end) {
|
|
||||||
s[0] = '\0';
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return binput(adr, s, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* idem, mais en int */
|
/* idem, mais en int */
|
||||||
int cache_brint(char *adr, int *i) {
|
int cache_brint(char *adr, int *i) {
|
||||||
char s[256];
|
char s[256];
|
||||||
|
|||||||
@@ -66,11 +66,8 @@ htsblk cache_read(httrackp * opt, cache_back * cache, const char *adr,
|
|||||||
const char *fil, const char *save, char *location);
|
const char *fil, const char *save, char *location);
|
||||||
htsblk cache_read_ro(httrackp * opt, cache_back * cache, const char *adr,
|
htsblk cache_read_ro(httrackp * opt, cache_back * cache, const char *adr,
|
||||||
const char *fil, const char *save, char *location);
|
const char *fil, const char *save, char *location);
|
||||||
/* Like cache_read, but also yields entries whose transfer broke; return_save
|
htsblk cache_read_including_broken(httrackp * opt, cache_back * cache,
|
||||||
(optional, HTS_URLMAXSIZE*2) receives the entry's recorded save name. */
|
const char *adr, const char *fil);
|
||||||
htsblk cache_read_including_broken(httrackp *opt, cache_back *cache,
|
|
||||||
const char *adr, const char *fil,
|
|
||||||
char *return_save);
|
|
||||||
htsblk cache_readex(httrackp * opt, cache_back * cache, const char *adr,
|
htsblk cache_readex(httrackp * opt, cache_back * cache, const char *adr,
|
||||||
const char *fil, const char *save, char *location,
|
const char *fil, const char *save, char *location,
|
||||||
char *return_save, int readonly);
|
char *return_save, int readonly);
|
||||||
@@ -78,17 +75,6 @@ htsblk *cache_header(httrackp * opt, cache_back * cache, const char *adr,
|
|||||||
const char *fil, htsblk * r);
|
const char *fil, htsblk * r);
|
||||||
void cache_init(cache_back * cache, httrackp * opt);
|
void cache_init(cache_back * cache, httrackp * opt);
|
||||||
|
|
||||||
/* Which hts-cache/ generation (new.* vs old.*) is authoritative. */
|
|
||||||
typedef enum {
|
|
||||||
CACHE_RECONCILE_PROMOTE, /* no new cache: promote the old generation */
|
|
||||||
CACHE_RECONCILE_INTERRUPTED, /* aborted run: keep the larger generation */
|
|
||||||
CACHE_RECONCILE_ROLLBACK /* nothing transferred: restore the old one */
|
|
||||||
} hts_cache_reconcile_mode;
|
|
||||||
|
|
||||||
/* Reconcile the on-disk cache generations according to mode; a no-op when
|
|
||||||
the involved files are absent. */
|
|
||||||
void hts_cache_reconcile(httrackp *opt, hts_cache_reconcile_mode mode);
|
|
||||||
|
|
||||||
int cache_writedata(FILE * cache_ndx, FILE * cache_dat, const char *str1,
|
int cache_writedata(FILE * cache_ndx, FILE * cache_dat, const char *str1,
|
||||||
const char *str2, char *outbuff, int len);
|
const char *str2, char *outbuff, int len);
|
||||||
int cache_readdata(cache_back * cache, const char *str1, const char *str2,
|
int cache_readdata(cache_back * cache, const char *str1, const char *str2,
|
||||||
@@ -97,8 +83,6 @@ int cache_readdata(cache_back * cache, const char *str1, const char *str2,
|
|||||||
void cache_rstr(FILE *fp, char *s, size_t s_size);
|
void cache_rstr(FILE *fp, char *s, size_t s_size);
|
||||||
char *cache_rstr_addr(FILE * fp);
|
char *cache_rstr_addr(FILE * fp);
|
||||||
int cache_brstr(char *adr, char *s, size_t s_size);
|
int cache_brstr(char *adr, char *s, size_t s_size);
|
||||||
/* binput over a NUL-terminated buffer, bounded: no read starts at/past end. */
|
|
||||||
int cache_binput(char *adr, const char *end, char *s, int max);
|
|
||||||
int cache_brint(char *adr, int *i);
|
int cache_brint(char *adr, int *i);
|
||||||
void cache_rint(FILE * fp, int *i);
|
void cache_rint(FILE * fp, int *i);
|
||||||
void cache_rLLint(FILE * fp, LLint * i);
|
void cache_rLLint(FILE * fp, LLint * i);
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htszlib.h"
|
#include "htszlib.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -322,7 +321,6 @@ typedef struct {
|
|||||||
size_t budget; /**< bytes allowed through before writes start failing */
|
size_t budget; /**< bytes allowed through before writes start failing */
|
||||||
int fail_errno; /**< errno set on the failing write (ENOSPC, EIO, ...) */
|
int fail_errno; /**< errno set on the failing write (ENOSPC, EIO, ...) */
|
||||||
int writes; /**< zwrite call count, to detect re-entry into the stream */
|
int writes; /**< zwrite call count, to detect re-entry into the stream */
|
||||||
int fail_once; /**< recover (unlimited budget) after the first failure */
|
|
||||||
} writefail_inject;
|
} writefail_inject;
|
||||||
|
|
||||||
/* zwrite that copies until the budget runs out, then fails with inj->fail_errno
|
/* zwrite that copies until the budget runs out, then fails with inj->fail_errno
|
||||||
@@ -337,8 +335,6 @@ static uLong selftest_failing_zwrite(voidpf opaque, voidpf stream,
|
|||||||
inj->budget -= (size_t) size;
|
inj->budget -= (size_t) size;
|
||||||
return (uLong) fwrite(buf, 1, (size_t) size, (FILE *) stream);
|
return (uLong) fwrite(buf, 1, (size_t) size, (FILE *) stream);
|
||||||
}
|
}
|
||||||
if (inj->fail_once)
|
|
||||||
inj->budget = (size_t) -1; /* the backend recovers after this failure */
|
|
||||||
errno = inj->fail_errno;
|
errno = inj->fail_errno;
|
||||||
return 0; /* short write -> the minizip op returns an error */
|
return 0; /* short write -> the minizip op returns an error */
|
||||||
}
|
}
|
||||||
@@ -377,50 +373,9 @@ static void writefail_store(httrackp *opt, cache_back *cache, const char *fil,
|
|||||||
freet(bodycopy);
|
freet(bodycopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store an entry claiming a >2GB body; the degrade path never reads data. */
|
/* #174/#219: a failing cache write used to crash via assertf(); it must instead
|
||||||
static void writefail_store_oversized(httrackp *opt, cache_back *cache,
|
stop the mirror (exit_xh = -1) without crashing. Assert that, plus the cache
|
||||||
const char *fil, int is_write) {
|
is flagged and a sibling write doesn't re-enter the broken stream. */
|
||||||
htsblk r;
|
|
||||||
char locbuf[4];
|
|
||||||
|
|
||||||
hts_init_htsblk(&r);
|
|
||||||
r.statuscode = 200;
|
|
||||||
r.size = (LLint) INT_MAX + 1;
|
|
||||||
strcpybuff(r.msg, "OK");
|
|
||||||
strcpybuff(r.contenttype, "application/octet-stream");
|
|
||||||
locbuf[0] = '\0';
|
|
||||||
r.location = locbuf;
|
|
||||||
r.is_write = (short int) is_write;
|
|
||||||
cache_add(opt, cache, &r, "example.com", fil, "example.com/big.bin", 1, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read back `entryname`: extra field (cached headers) and body. Returns the
|
|
||||||
body length, or -1 if the entry is absent or unreadable. */
|
|
||||||
static int writefail_read_entry(const char *path, const char *entryname,
|
|
||||||
char *extra, size_t extralen, char *body,
|
|
||||||
size_t bodylen) {
|
|
||||||
unzFile z = unzOpen(path);
|
|
||||||
int n = -1;
|
|
||||||
|
|
||||||
if (z == NULL)
|
|
||||||
return -1;
|
|
||||||
if (unzLocateFile(z, entryname, 1) == UNZ_OK &&
|
|
||||||
unzOpenCurrentFile(z) == UNZ_OK) {
|
|
||||||
const int elen = unzGetLocalExtrafield(z, extra, (unsigned) (extralen - 1));
|
|
||||||
|
|
||||||
if (elen >= 0) {
|
|
||||||
extra[elen] = '\0';
|
|
||||||
n = unzReadCurrentFile(z, body, (unsigned) bodylen);
|
|
||||||
}
|
|
||||||
unzCloseCurrentFile(z);
|
|
||||||
}
|
|
||||||
unzClose(z);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cache write-failure policy (#174/#219): fatal errno or a failure streak
|
|
||||||
stops the mirror (exit_xh=-1, no crash); isolated/oversized drops the entry.
|
|
||||||
*/
|
|
||||||
int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
char path[HTS_URLMAXSIZE];
|
char path[HTS_URLMAXSIZE];
|
||||||
@@ -433,8 +388,9 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
gen_body(body, body_len, 1 /* incompressible */);
|
gen_body(body, body_len, 1 /* incompressible */);
|
||||||
fconcat(path, sizeof(path), dir, "/wfail.zip");
|
fconcat(path, sizeof(path), dir, "/wfail.zip");
|
||||||
|
|
||||||
/* phase 0: fatal errno (ENOSPC) aborts at once; phase 1: persistent EIO
|
/* phase 0: fail on the body write, fatal errno (ENOSPC, the disk-full
|
||||||
drops entries until the streak caps out, then aborts. */
|
branch). phase 1: fail on the open, non-fatal errno (EIO, dropped-share
|
||||||
|
branch). Both must abort the mirror. */
|
||||||
for (phase = 0; phase < 2; phase++) {
|
for (phase = 0; phase < 2; phase++) {
|
||||||
cache_back cache;
|
cache_back cache;
|
||||||
writefail_inject inj;
|
writefail_inject inj;
|
||||||
@@ -443,7 +399,6 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
inj.budget = (phase == 0) ? 4096 : 0;
|
inj.budget = (phase == 0) ? 4096 : 0;
|
||||||
inj.fail_errno = (phase == 0) ? ENOSPC : EIO;
|
inj.fail_errno = (phase == 0) ? ENOSPC : EIO;
|
||||||
inj.writes = 0;
|
inj.writes = 0;
|
||||||
inj.fail_once = 0;
|
|
||||||
memset(&cache, 0, sizeof(cache));
|
memset(&cache, 0, sizeof(cache));
|
||||||
cache.type = 1;
|
cache.type = 1;
|
||||||
cache.log = stderr;
|
cache.log = stderr;
|
||||||
@@ -457,25 +412,7 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opt->state.exit_xh = 0; /* clear; the failing write must set it to -1 */
|
opt->state.exit_xh = 0; /* clear; the failing write must set it to -1 */
|
||||||
if (phase == 0) {
|
writefail_store(opt, &cache, "/blob.bin", body, body_len);
|
||||||
writefail_store(opt, &cache, "/blob.bin", body, body_len);
|
|
||||||
} else {
|
|
||||||
/* the abort must land exactly on the 8th consecutive failure */
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
|
||||||
char fil[32];
|
|
||||||
|
|
||||||
snprintf(fil, sizeof(fil), "/b%d.bin", i);
|
|
||||||
writefail_store(opt, &cache, fil, body, 16);
|
|
||||||
}
|
|
||||||
if (cache.zipWriteFailed) {
|
|
||||||
fprintf(stderr, "cache-writefail: phase 1: aborted before the "
|
|
||||||
"8th consecutive failure\n");
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
writefail_store(opt, &cache, "/b7.bin", body, 16);
|
|
||||||
}
|
|
||||||
if (!cache.zipWriteFailed) {
|
if (!cache.zipWriteFailed) {
|
||||||
fprintf(stderr, "cache-writefail: phase %d: write error not caught\n",
|
fprintf(stderr, "cache-writefail: phase %d: write error not caught\n",
|
||||||
phase);
|
phase);
|
||||||
@@ -506,136 +443,6 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* failures with successes in between reset the streak: never aborts */
|
|
||||||
{
|
|
||||||
cache_back cache;
|
|
||||||
writefail_inject inj;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
inj.budget = (size_t) -1;
|
|
||||||
inj.fail_errno = EIO;
|
|
||||||
inj.writes = 0;
|
|
||||||
inj.fail_once = 0;
|
|
||||||
memset(&cache, 0, sizeof(cache));
|
|
||||||
cache.type = 1;
|
|
||||||
cache.log = stderr;
|
|
||||||
cache.errlog = stderr;
|
|
||||||
cache.hashtable = coucal_new(0);
|
|
||||||
cache.zipOutput = selftest_open_failing_zip(path, &inj);
|
|
||||||
opt->state.exit_xh = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 10; i++) {
|
|
||||||
char fil[32];
|
|
||||||
|
|
||||||
inj.budget = 0; /* this store fails */
|
|
||||||
snprintf(fil, sizeof(fil), "/s%d.bin", i);
|
|
||||||
writefail_store(opt, &cache, fil, body, 16);
|
|
||||||
inj.budget = (size_t) -1; /* this one succeeds and resets the streak */
|
|
||||||
snprintf(fil, sizeof(fil), "/ok%d.bin", i);
|
|
||||||
writefail_store(opt, &cache, fil, body, 16);
|
|
||||||
}
|
|
||||||
if (cache.zipWriteFailed || opt->state.exit_xh != 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"cache-writefail: scattered: non-consecutive failures aborted "
|
|
||||||
"the mirror (flagged=%d, exit_xh=%d)\n",
|
|
||||||
(int) cache.zipWriteFailed, opt->state.exit_xh);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
zipClose(cache.zipOutput, NULL);
|
|
||||||
cache.zipOutput = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* isolated failure: only that entry drops; a later sibling round-trips */
|
|
||||||
{
|
|
||||||
cache_back cache;
|
|
||||||
writefail_inject inj;
|
|
||||||
char extra[8192];
|
|
||||||
char rbody[64];
|
|
||||||
int n;
|
|
||||||
|
|
||||||
inj.budget = 4096;
|
|
||||||
inj.fail_errno = EIO;
|
|
||||||
inj.writes = 0;
|
|
||||||
inj.fail_once = 1;
|
|
||||||
memset(&cache, 0, sizeof(cache));
|
|
||||||
cache.type = 1;
|
|
||||||
cache.log = stderr;
|
|
||||||
cache.errlog = stderr;
|
|
||||||
cache.hashtable = coucal_new(0);
|
|
||||||
cache.zipOutput = selftest_open_failing_zip(path, &inj);
|
|
||||||
opt->state.exit_xh = 0;
|
|
||||||
|
|
||||||
writefail_store(opt, &cache, "/blob.bin", body, body_len);
|
|
||||||
if (cache.zipWriteFailed || opt->state.exit_xh != 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"cache-writefail: skip: isolated failure aborted the mirror "
|
|
||||||
"(flagged=%d, exit_xh=%d)\n",
|
|
||||||
(int) cache.zipWriteFailed, opt->state.exit_xh);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
writefail_store(opt, &cache, "/blob2.bin", body, 16);
|
|
||||||
zipClose(cache.zipOutput, NULL);
|
|
||||||
cache.zipOutput = NULL;
|
|
||||||
n = writefail_read_entry(path, "http://example.com/blob2.bin", extra,
|
|
||||||
sizeof(extra), rbody, sizeof(rbody));
|
|
||||||
if (n != 16 || memcmp(rbody, body, 16) != 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"cache-writefail: skip: sibling entry lost after a skipped "
|
|
||||||
"entry (%d)\n",
|
|
||||||
n);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* >2GB bodies: in-memory drops the entry, on-disk degrades to headers-only */
|
|
||||||
{
|
|
||||||
cache_back cache;
|
|
||||||
writefail_inject inj;
|
|
||||||
char extra[8192];
|
|
||||||
char rbody[64];
|
|
||||||
int n;
|
|
||||||
|
|
||||||
inj.budget = (size_t) -1; /* no injected failure */
|
|
||||||
inj.fail_errno = 0;
|
|
||||||
inj.writes = 0;
|
|
||||||
inj.fail_once = 0;
|
|
||||||
memset(&cache, 0, sizeof(cache));
|
|
||||||
cache.type = 1;
|
|
||||||
cache.log = stderr;
|
|
||||||
cache.errlog = stderr;
|
|
||||||
cache.hashtable = coucal_new(0);
|
|
||||||
cache.zipOutput = selftest_open_failing_zip(path, &inj);
|
|
||||||
opt->state.exit_xh = 0;
|
|
||||||
|
|
||||||
writefail_store_oversized(opt, &cache, "/bigmem.bin", 0 /* in-memory */);
|
|
||||||
writefail_store_oversized(opt, &cache, "/bigdisk.bin", 1 /* on-disk */);
|
|
||||||
zipClose(cache.zipOutput, NULL);
|
|
||||||
cache.zipOutput = NULL;
|
|
||||||
|
|
||||||
if (cache.zipWriteFailed || opt->state.exit_xh != 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"cache-writefail: oversize: mirror aborted (flagged=%d, "
|
|
||||||
"exit_xh=%d)\n",
|
|
||||||
(int) cache.zipWriteFailed, opt->state.exit_xh);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
if (writefail_read_entry(path, "http://example.com/bigmem.bin", extra,
|
|
||||||
sizeof(extra), rbody, sizeof(rbody)) >= 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"cache-writefail: oversize: in-memory entry was stored\n");
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
n = writefail_read_entry(path, "http://example.com/bigdisk.bin", extra,
|
|
||||||
sizeof(extra), rbody, sizeof(rbody));
|
|
||||||
if (n != 0 || strstr(extra, "X-In-Cache: 0") == NULL) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"cache-writefail: oversize: on-disk entry not stored "
|
|
||||||
"headers-only (%d)\n",
|
|
||||||
n);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freet(body);
|
freet(body);
|
||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
@@ -909,494 +716,3 @@ int cache_golden_selftest(httrackp *opt, const char *dir, int regen) {
|
|||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- hts_cache_reconcile() policies -------------------------------------- */
|
|
||||||
|
|
||||||
/* All reconcile inputs/outputs, wiped between cases. */
|
|
||||||
static const char *const reconcile_files[] = {
|
|
||||||
"hts-cache/new.zip", "hts-cache/old.zip", "hts-cache/new.dat",
|
|
||||||
"hts-cache/old.dat", "hts-cache/new.ndx", "hts-cache/old.ndx",
|
|
||||||
"hts-cache/new.lst", "hts-cache/old.lst", "hts-cache/new.txt",
|
|
||||||
"hts-cache/old.txt", "hts-in_progress.lock"};
|
|
||||||
|
|
||||||
static char *reconcile_st_path(httrackp *opt, const char *name) {
|
|
||||||
return fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
|
||||||
StringBuff(opt->path_log), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reconcile_wipe(httrackp *opt) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(reconcile_files) / sizeof(reconcile_files[0]); i++)
|
|
||||||
remove(reconcile_st_path(opt, reconcile_files[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a filler file of exactly `size` bytes. */
|
|
||||||
static void reconcile_put(httrackp *opt, const char *name, size_t size) {
|
|
||||||
FILE *const fp = fopen(reconcile_st_path(opt, name), "wb");
|
|
||||||
static const char filler[1024] = {'x'};
|
|
||||||
|
|
||||||
assertf(fp != NULL);
|
|
||||||
while (size > 0) {
|
|
||||||
const size_t n = size > sizeof(filler) ? sizeof(filler) : size;
|
|
||||||
|
|
||||||
assertf(fwrite(filler, 1, n, fp) == n);
|
|
||||||
size -= n;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expect `name` to weigh `size` bytes, or be absent when size == -1. */
|
|
||||||
static int reconcile_expect(httrackp *opt, const char *name, off_t size,
|
|
||||||
const char *what) {
|
|
||||||
const off_t got = fsize(reconcile_st_path(opt, name));
|
|
||||||
|
|
||||||
if (got != size) {
|
|
||||||
fprintf(stderr, "cache-reconcile: %s: %s is %d bytes, expected %d\n", what,
|
|
||||||
name, (int) got, (int) size);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cache_reconcile_selftest(httrackp *opt, const char *dir) {
|
|
||||||
int failures = 0;
|
|
||||||
|
|
||||||
/* around the interrupted-run thresholds (new < 32768, old > 65536) */
|
|
||||||
static const off_t TINY = 1024, MID = 40000, SOLID = 131072;
|
|
||||||
|
|
||||||
golden_setup(opt, dir);
|
|
||||||
#ifdef _WIN32
|
|
||||||
mkdir(reconcile_st_path(opt, "hts-cache"));
|
|
||||||
#else
|
|
||||||
mkdir(reconcile_st_path(opt, "hts-cache"), HTS_PROTECT_FOLDER);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* PROMOTE: a zip old generation replaces a missing new one */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.zip", SOLID, "promote-zip");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/old.zip", -1, "promote-zip");
|
|
||||||
|
|
||||||
/* PROMOTE: an existing new.zip is left alone */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.zip", TINY, "promote-zip-noop");
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/old.zip", SOLID, "promote-zip-noop");
|
|
||||||
|
|
||||||
/* PROMOTE: a pure-legacy old generation is promoted too (was dead when no
|
|
||||||
zip cache existed) */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/old.dat", SOLID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.ndx", TINY);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.dat", SOLID, "promote-dat");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.ndx", TINY, "promote-dat");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/old.dat", -1, "promote-dat");
|
|
||||||
|
|
||||||
/* PROMOTE: a half-written legacy new pair is replaced by the old pair */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/new.dat", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.dat", SOLID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.ndx", TINY);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.dat", SOLID, "promote-dat-partial");
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.ndx", TINY, "promote-dat-partial");
|
|
||||||
|
|
||||||
/* INTERRUPTED: no lock file, no action */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.zip", TINY, "interrupted-nolock");
|
|
||||||
|
|
||||||
/* INTERRUPTED: an absent new.zip must NOT promote old.zip (fsize(-1) would
|
|
||||||
spuriously pass "< TINY"); leave the solid old generation for ROLLBACK */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-in_progress.lock", 0);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.zip", -1, "interrupted-nonew");
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/old.zip", SOLID, "interrupted-nonew");
|
|
||||||
|
|
||||||
/* INTERRUPTED: stalled tiny new.zip loses to a solid old.zip (was dead for
|
|
||||||
zip caches: the arm was gated on a legacy new.dat) */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-in_progress.lock", 0);
|
|
||||||
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.zip", SOLID, "interrupted-zip");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/old.zip", -1, "interrupted-zip");
|
|
||||||
|
|
||||||
/* INTERRUPTED: old below the confidence threshold, keep new */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-in_progress.lock", 0);
|
|
||||||
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", MID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.zip", TINY, "interrupted-smallold");
|
|
||||||
|
|
||||||
/* INTERRUPTED: new big enough to trust, keep it */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-in_progress.lock", 0);
|
|
||||||
reconcile_put(opt, "hts-cache/new.zip", MID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.zip", MID, "interrupted-bignew");
|
|
||||||
|
|
||||||
/* INTERRUPTED: the legacy pair follows the same size rule (was dead code) */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-in_progress.lock", 0);
|
|
||||||
reconcile_put(opt, "hts-cache/new.dat", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/new.ndx", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.dat", SOLID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.ndx", MID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.dat", SOLID, "interrupted-dat");
|
|
||||||
failures +=
|
|
||||||
reconcile_expect(opt, "hts-cache/new.ndx", MID, "interrupted-dat");
|
|
||||||
|
|
||||||
/* ROLLBACK: the old zip generation is restored (a zip cache used to lose
|
|
||||||
its only good generation here) */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.zip", SOLID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.zip", SOLID, "rollback-zip");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/old.zip", -1, "rollback-zip");
|
|
||||||
|
|
||||||
/* ROLLBACK: sidecars are restored regardless of format */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/new.lst", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.lst", MID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.txt", MID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.lst", MID, "rollback-lst");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.txt", MID, "rollback-txt");
|
|
||||||
|
|
||||||
/* ROLLBACK: full legacy generation incl. sidecars (historical behavior) */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/new.dat", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/new.ndx", TINY);
|
|
||||||
reconcile_put(opt, "hts-cache/old.dat", SOLID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.ndx", MID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.lst", MID);
|
|
||||||
reconcile_put(opt, "hts-cache/old.txt", MID);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.dat", SOLID, "rollback-dat");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.ndx", MID, "rollback-dat");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.lst", MID, "rollback-dat");
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.txt", MID, "rollback-dat");
|
|
||||||
|
|
||||||
/* ROLLBACK: nothing to restore, the new generation stays */
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
reconcile_put(opt, "hts-cache/new.zip", TINY);
|
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
|
|
||||||
failures += reconcile_expect(opt, "hts-cache/new.zip", TINY, "rollback-noop");
|
|
||||||
|
|
||||||
reconcile_wipe(opt);
|
|
||||||
return failures;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- read-side corruption injection --------------------------------------- */
|
|
||||||
|
|
||||||
/* canary read back intact after each corruption; victim gets the byte surgery
|
|
||||||
*/
|
|
||||||
#define CORRUPT_ADR "corrupt.example.com"
|
|
||||||
static char corrupt_body_a[33 + 1];
|
|
||||||
static char corrupt_body_b[44 + 1];
|
|
||||||
|
|
||||||
/* Write a fresh two-entry cache: /canary.html then /victim.html. */
|
|
||||||
static void corrupt_build(httrackp *opt) {
|
|
||||||
cache_back cache;
|
|
||||||
|
|
||||||
memset(corrupt_body_a, 'a', sizeof(corrupt_body_a) - 1);
|
|
||||||
memset(corrupt_body_b, 'b', sizeof(corrupt_body_b) - 1);
|
|
||||||
remove(reconcile_st_path(opt, "hts-cache/new.zip"));
|
|
||||||
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
|
||||||
selftest_open_for_write(&cache, opt);
|
|
||||||
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
|
||||||
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
|
||||||
strlen(corrupt_body_a));
|
|
||||||
store_entry(opt, &cache, CORRUPT_ADR, "/victim.html", "victim.html", 200,
|
|
||||||
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_b,
|
|
||||||
strlen(corrupt_body_b));
|
|
||||||
selftest_close(&cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Like corrupt_build, but the victim carries a 20-char Etag whose header line
|
|
||||||
is later overwritten with a forged oversized X-Size (same byte length). */
|
|
||||||
static void corrupt_build_etag(httrackp *opt) {
|
|
||||||
cache_back cache;
|
|
||||||
|
|
||||||
memset(corrupt_body_a, 'a', sizeof(corrupt_body_a) - 1);
|
|
||||||
memset(corrupt_body_b, 'b', sizeof(corrupt_body_b) - 1);
|
|
||||||
remove(reconcile_st_path(opt, "hts-cache/new.zip"));
|
|
||||||
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
|
||||||
selftest_open_for_write(&cache, opt);
|
|
||||||
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
|
||||||
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
|
||||||
strlen(corrupt_body_a));
|
|
||||||
store_entry(opt, &cache, CORRUPT_ADR, "/victim.html", "victim.html", 200,
|
|
||||||
"OK", "text/html", "utf-8", "", "AAAAAAAAAAAAAAAAAAAA", "", "",
|
|
||||||
corrupt_body_b, strlen(corrupt_body_b));
|
|
||||||
selftest_close(&cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Like corrupt_build_etag, but the victim is headers-only (X-In-Cache: 0,
|
|
||||||
body on disk): the shape every non-html file is stored with. */
|
|
||||||
static void corrupt_build_disk(httrackp *opt) {
|
|
||||||
cache_back cache;
|
|
||||||
htsblk w;
|
|
||||||
char locw[4];
|
|
||||||
char BIGSTK save[HTS_URLMAXSIZE * 2];
|
|
||||||
char BIGSTK catbuff[HTS_URLMAXSIZE * 2];
|
|
||||||
char *path;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
memset(corrupt_body_a, 'a', sizeof(corrupt_body_a) - 1);
|
|
||||||
remove(reconcile_st_path(opt, "hts-cache/new.zip"));
|
|
||||||
remove(reconcile_st_path(opt, "hts-cache/old.zip"));
|
|
||||||
fconcat(save, sizeof(save), StringBuff(opt->path_html_utf8),
|
|
||||||
CORRUPT_ADR "/victim.bin");
|
|
||||||
selftest_open_for_write(&cache, opt);
|
|
||||||
store_entry(opt, &cache, CORRUPT_ADR, "/canary.html", "canary.html", 200,
|
|
||||||
"OK", "text/html", "utf-8", "", "", "", "", corrupt_body_a,
|
|
||||||
strlen(corrupt_body_a));
|
|
||||||
hts_init_htsblk(&w);
|
|
||||||
w.statuscode = 200;
|
|
||||||
w.size = (LLint) sizeof(corrupt_body_b) - 1;
|
|
||||||
strcpybuff(w.msg, "OK");
|
|
||||||
strcpybuff(w.contenttype, "application/octet-stream");
|
|
||||||
strcpybuff(w.etag, "AAAAAAAAAAAAAAAAAAAA");
|
|
||||||
locw[0] = '\0';
|
|
||||||
w.location = locw;
|
|
||||||
w.is_write = 0;
|
|
||||||
cache_add(opt, &cache, &w, CORRUPT_ADR, "/victim.bin", save,
|
|
||||||
0 /* all_in_cache */, NULL);
|
|
||||||
selftest_close(&cache);
|
|
||||||
/* the reader only checks this file exists; it never reads it here */
|
|
||||||
path = fconv(catbuff, sizeof(catbuff), save);
|
|
||||||
(void) structcheck(path);
|
|
||||||
fp = FOPEN(path, "wb");
|
|
||||||
assertf(fp != NULL);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Patch the nth of total occurrences of pat (same-length rep) in new.zip. */
|
|
||||||
static void corrupt_patch(httrackp *opt, const char *pat, size_t patlen,
|
|
||||||
const char *rep, size_t nth, size_t total) {
|
|
||||||
LLint fsz = 0;
|
|
||||||
char *data = readfile2(reconcile_st_path(opt, "hts-cache/new.zip"), &fsz);
|
|
||||||
const size_t n = (size_t) fsz;
|
|
||||||
size_t k, hits = 0, at = 0;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
assertf(data != NULL);
|
|
||||||
for (k = 0; k + patlen <= n; k++) {
|
|
||||||
if (memcmp(data + k, pat, patlen) == 0) {
|
|
||||||
hits++;
|
|
||||||
if (hits == nth)
|
|
||||||
at = k;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertf(hits == total);
|
|
||||||
memcpy(data + at, rep, patlen);
|
|
||||||
fp = fopen(reconcile_st_path(opt, "hts-cache/new.zip"), "wb");
|
|
||||||
assertf(fp != NULL);
|
|
||||||
assertf(fwrite(data, 1, n, fp) == n);
|
|
||||||
fclose(fp);
|
|
||||||
freet(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Garbage the first bytes of the victim's deflated data (2nd local header). */
|
|
||||||
static void corrupt_victim_body(httrackp *opt) {
|
|
||||||
LLint fsz = 0;
|
|
||||||
char *data = readfile2(reconcile_st_path(opt, "hts-cache/new.zip"), &fsz);
|
|
||||||
const size_t n = (size_t) fsz;
|
|
||||||
size_t k, hits = 0, off = 0;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
assertf(data != NULL);
|
|
||||||
for (k = 0; k + 4 <= n; k++) {
|
|
||||||
if (memcmp(data + k, "PK\x03\x04", 4) == 0 && ++hits == 2) {
|
|
||||||
const size_t namelen =
|
|
||||||
(unsigned char) data[k + 26] | ((unsigned char) data[k + 27] << 8);
|
|
||||||
const size_t extralen =
|
|
||||||
(unsigned char) data[k + 28] | ((unsigned char) data[k + 29] << 8);
|
|
||||||
|
|
||||||
off = k + 30 + namelen + extralen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertf(hits == 2);
|
|
||||||
assertf(off != 0 && off + 4 <= n);
|
|
||||||
memset(data + off, 0xFF, 4);
|
|
||||||
fp = fopen(reconcile_st_path(opt, "hts-cache/new.zip"), "wb");
|
|
||||||
assertf(fp != NULL);
|
|
||||||
assertf(fwrite(data, 1, n, fp) == n);
|
|
||||||
fclose(fp);
|
|
||||||
freet(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the corrupt /victim.html and, in the SAME read session, the intact
|
|
||||||
/canary.html: the victim must be rejected (wantmsg pins which path) and the
|
|
||||||
canary must still decode byte-exact, proving one bad entry never taints a
|
|
||||||
sibling read. */
|
|
||||||
static int corrupt_expect_victim_fil(httrackp *opt, const char *fil,
|
|
||||||
const char *wantmsg, const char *what) {
|
|
||||||
cache_back cache;
|
|
||||||
htsblk v, c;
|
|
||||||
char BIGSTK lv[HTS_URLMAXSIZE * 2];
|
|
||||||
char BIGSTK lc[HTS_URLMAXSIZE * 2];
|
|
||||||
int fail = 0;
|
|
||||||
|
|
||||||
selftest_open_for_read(&cache, opt);
|
|
||||||
lv[0] = lc[0] = '\0';
|
|
||||||
v = cache_readex(opt, &cache, CORRUPT_ADR, fil, "", lv, NULL, 1);
|
|
||||||
if (v.statuscode != STATUSCODE_INVALID) {
|
|
||||||
fprintf(stderr, "%s: %s: victim: statuscode is %d, expected %d\n",
|
|
||||||
selftest_tag, what, v.statuscode, STATUSCODE_INVALID);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
if (wantmsg != NULL && strcmp(v.msg, wantmsg) != 0) {
|
|
||||||
fprintf(stderr, "%s: %s: victim: msg is '%s', expected '%s'\n",
|
|
||||||
selftest_tag, what, v.msg, wantmsg);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
c = cache_readex(opt, &cache, CORRUPT_ADR, "/canary.html", "", lc, NULL, 1);
|
|
||||||
if (c.statuscode != 200 || c.adr == NULL ||
|
|
||||||
c.size != (LLint) strlen(corrupt_body_a) ||
|
|
||||||
memcmp(c.adr, corrupt_body_a, strlen(corrupt_body_a)) != 0) {
|
|
||||||
fprintf(stderr, "%s: %s: canary tainted (status %d)\n", selftest_tag, what,
|
|
||||||
c.statuscode);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
if (v.adr != NULL)
|
|
||||||
freet(v.adr);
|
|
||||||
if (c.adr != NULL)
|
|
||||||
freet(c.adr);
|
|
||||||
selftest_close(&cache);
|
|
||||||
return fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int corrupt_expect_victim(httrackp *opt, const char *wantmsg,
|
|
||||||
const char *what) {
|
|
||||||
return corrupt_expect_victim_fil(opt, "/victim.html", wantmsg, what);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Headers-only probe of the disk victim: must parse OK with the size kept. */
|
|
||||||
static int corrupt_expect_disk_header(httrackp *opt, LLint wantsize,
|
|
||||||
const char *what) {
|
|
||||||
cache_back cache;
|
|
||||||
htsblk v;
|
|
||||||
char BIGSTK lv[HTS_URLMAXSIZE * 2];
|
|
||||||
int fail = 0;
|
|
||||||
|
|
||||||
selftest_open_for_read(&cache, opt);
|
|
||||||
lv[0] = '\0';
|
|
||||||
v = cache_readex(opt, &cache, CORRUPT_ADR, "/victim.bin", NULL, lv, NULL, 1);
|
|
||||||
if (v.statuscode != 200 || v.size != wantsize) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: %s: statuscode %d size " LLintP ", expected 200/" LLintP "\n",
|
|
||||||
selftest_tag, what, v.statuscode, (LLint) v.size, wantsize);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
if (v.adr != NULL)
|
|
||||||
freet(v.adr);
|
|
||||||
selftest_close(&cache);
|
|
||||||
return fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* One zip corruption case: build, patch, then check victim+canary in-session.
|
|
||||||
*/
|
|
||||||
static int corrupt_case_zip(httrackp *opt, const char *pat, const char *rep,
|
|
||||||
size_t nth, size_t total, const char *wantmsg,
|
|
||||||
const char *what) {
|
|
||||||
corrupt_build(opt);
|
|
||||||
corrupt_patch(opt, pat, strlen(pat), rep, nth, total);
|
|
||||||
return corrupt_expect_victim(opt, wantmsg, what);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cache_corruption_selftest(httrackp *opt, const char *dir) {
|
|
||||||
int failures = 0;
|
|
||||||
|
|
||||||
selftest_tag = "cache-corrupt";
|
|
||||||
golden_setup(opt, dir);
|
|
||||||
|
|
||||||
failures +=
|
|
||||||
corrupt_case_zip(opt, "X-Size: 44", "X-Size: 99", 1, 1,
|
|
||||||
"Cache Read Error : Read Data", "oversized X-Size");
|
|
||||||
failures +=
|
|
||||||
corrupt_case_zip(opt, "X-Size: 44", "X-Size: -4", 1, 1,
|
|
||||||
"Cache Read Error : Bad Size", "negative X-Size");
|
|
||||||
/* both entries carry the line; the victim's is the second */
|
|
||||||
failures += corrupt_case_zip(opt, "X-In-Cache: 1", "X-In-Cache: 0", 2, 2,
|
|
||||||
"Previous cache file not found (empty filename)",
|
|
||||||
"blanked X-In-Cache");
|
|
||||||
/* smashed local file header: the entry is dropped at index load */
|
|
||||||
failures +=
|
|
||||||
corrupt_case_zip(opt, "PK\x03\x04", "XK\x03\x04", 2, 2,
|
|
||||||
"File Cache Entry Not Found", "smashed local header");
|
|
||||||
|
|
||||||
corrupt_build(opt);
|
|
||||||
corrupt_victim_body(opt);
|
|
||||||
failures += corrupt_expect_victim(opt, "Cache Read Error : Read Data",
|
|
||||||
"garbled deflate stream");
|
|
||||||
|
|
||||||
/* An X-Size above INT_MAX is positive as int64 (slips a bare sign check) but
|
|
||||||
truncates negative in the (int) cast the malloc uses: a wraparound alloc.
|
|
||||||
cache_add asserts size fits an int, so such a value only reaches the reader
|
|
||||||
from a corrupt/foreign cache; inject it by overwriting the victim's long
|
|
||||||
Etag line with a same-length forged X-Size line (the parser keeps the last
|
|
||||||
X-Size it sees), keeping the zip byte-length and offsets intact. */
|
|
||||||
corrupt_build_etag(opt);
|
|
||||||
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
|
||||||
"X-Size: 2147483648AAAAAAAA", 1, 1);
|
|
||||||
failures += corrupt_expect_victim(opt, "Cache Read Error : Bad Size",
|
|
||||||
"X-Size above INT_MAX");
|
|
||||||
|
|
||||||
/* A headers-only entry (X-In-Cache: 0) may carry an X-Size >= INT_MAX: that
|
|
||||||
is how every >2GB non-html file is stored. It must survive a header probe
|
|
||||||
(or every update re-fetches the file); an in-memory read still rejects. */
|
|
||||||
corrupt_build_disk(opt);
|
|
||||||
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
|
||||||
"X-Size: 2147483648AAAAAAAA", 1, 1);
|
|
||||||
failures += corrupt_expect_disk_header(opt, (LLint) 2147483648LL,
|
|
||||||
"headers-only X-Size above INT_MAX");
|
|
||||||
failures += corrupt_expect_victim_fil(opt, "/victim.bin",
|
|
||||||
"Cache Read Error : Bad Size",
|
|
||||||
"in-memory X-Size above INT_MAX");
|
|
||||||
|
|
||||||
/* exactly INT_MAX pins the >= boundary: (int) r.size + 1 would overflow */
|
|
||||||
corrupt_build_disk(opt);
|
|
||||||
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
|
||||||
"X-Size: 2147483647AAAAAAAA", 1, 1);
|
|
||||||
failures += corrupt_expect_victim_fil(opt, "/victim.bin",
|
|
||||||
"Cache Read Error : Bad Size",
|
|
||||||
"in-memory X-Size at INT_MAX");
|
|
||||||
|
|
||||||
/* the negative check must stay global, headers-only included */
|
|
||||||
corrupt_build_disk(opt);
|
|
||||||
corrupt_patch(opt, "Etag: AAAAAAAAAAAAAAAAAAAA", 26,
|
|
||||||
"X-Size: -2147483648AAAAAAA", 1, 1);
|
|
||||||
failures += corrupt_expect_victim_fil(opt, "/victim.bin",
|
|
||||||
"Cache Read Error : Bad Size",
|
|
||||||
"headers-only negative X-Size");
|
|
||||||
|
|
||||||
return failures;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -52,19 +52,10 @@ int cache_selftests(httrackp *opt, const char *dir);
|
|||||||
committed file, never by the test). Returns the failed-check count. */
|
committed file, never by the test). Returns the failed-check count. */
|
||||||
int cache_golden_selftest(httrackp *opt, const char *dir, int regen);
|
int cache_golden_selftest(httrackp *opt, const char *dir, int regen);
|
||||||
|
|
||||||
/* Cache write-failure policy (#174/#219): abort on fatal errno or a streak,
|
/* #174/#219: assert a failing cache write aborts the mirror cleanly instead of
|
||||||
drop just the entry otherwise. Returns the failed-check count. */
|
crashing. Returns the failed-check count. */
|
||||||
int cache_write_failure_selftest(httrackp *opt, const char *dir);
|
int cache_write_failure_selftest(httrackp *opt, const char *dir);
|
||||||
|
|
||||||
/* Exercise the hts_cache_reconcile() generation policies on file fixtures
|
|
||||||
under <dir>. Returns the failed-check count. */
|
|
||||||
int cache_reconcile_selftest(httrackp *opt, const char *dir);
|
|
||||||
|
|
||||||
/* Inject read-side corruption (zip byte surgery: bad size, header, deflate)
|
|
||||||
under <dir> and assert every case degrades to STATUSCODE_INVALID without
|
|
||||||
tainting a sibling entry. */
|
|
||||||
int cache_corruption_selftest(httrackp *opt, const char *dir);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// catch_url_init(&port,&return_host);
|
// catch_url_init(&port,&return_host);
|
||||||
HTSEXT_API T_SOC catch_url_init_std(int *port_prox, char *adr_prox) {
|
HTSEXT_API T_SOC catch_url_init_std(int *port_prox, char *adr_prox) {
|
||||||
T_SOC soc;
|
T_SOC soc;
|
||||||
int try_to_listen_to[] = {8080, 3128, 80, 81, 82, 8081, 3129, 0, -1};
|
int try_to_listen_to[] = { 8080, 3128, 80, 81, 82, 8081, 3129, 31337, 0, -1 };
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -175,9 +175,7 @@ HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
|
|||||||
//
|
//
|
||||||
socinput(soc, line, 1000);
|
socinput(soc, line, 1000);
|
||||||
if (strnotempty(line)) {
|
if (strnotempty(line)) {
|
||||||
/* widths bound the caller buffers: method[32], url[HTS_URLMAXSIZE*2],
|
if (sscanf(line, "%s %s %s", method, url, protocol) == 3) {
|
||||||
protocol[256] */
|
|
||||||
if (sscanf(line, "%31s %2047s %255s", method, url, protocol) == 3) {
|
|
||||||
lien_adrfil af;
|
lien_adrfil af;
|
||||||
|
|
||||||
// méthode en majuscule
|
// méthode en majuscule
|
||||||
@@ -197,6 +195,7 @@ HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
|
|||||||
htsblk blkretour;
|
htsblk blkretour;
|
||||||
|
|
||||||
hts_init_htsblk(&blkretour);
|
hts_init_htsblk(&blkretour);
|
||||||
|
//memset(&blkretour, 0, sizeof(htsblk)); // effacer
|
||||||
blkretour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
blkretour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
||||||
// Lire en têtes restants
|
// Lire en têtes restants
|
||||||
sprintf(data, "%s %s %s\r\n", method, af.fil, protocol);
|
sprintf(data, "%s %s %s\r\n", method, af.fil, protocol);
|
||||||
@@ -206,8 +205,8 @@ HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
|
|||||||
strlcatbuff(data, line, CATCH_URL_DATA_SIZE);
|
strlcatbuff(data, line, CATCH_URL_DATA_SIZE);
|
||||||
strlcatbuff(data, "\r\n", CATCH_URL_DATA_SIZE);
|
strlcatbuff(data, "\r\n", CATCH_URL_DATA_SIZE);
|
||||||
}
|
}
|
||||||
// CR/LF final de l'en tête inutile car déja placé via la ligne vide
|
// CR/LF final de l'en tête inutile car déja placé via la ligne vide juste au dessus
|
||||||
// juste au dessus
|
//strcatbuff(data,"\r\n");
|
||||||
if (blkretour.totalsize > 0) {
|
if (blkretour.totalsize > 0) {
|
||||||
int len = (int) min(blkretour.totalsize, 32000);
|
int len = (int) min(blkretour.totalsize, 32000);
|
||||||
int pos = (int) strlen(data);
|
int pos = (int) strlen(data);
|
||||||
|
|||||||
@@ -841,6 +841,71 @@ static unsigned int nlz8(unsigned char x) {
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
/* Sample. */
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int i;
|
||||||
|
int hex = 0;
|
||||||
|
|
||||||
|
#define READ_INT(DEST) \
|
||||||
|
( ( !hex && sscanf(argv[i], "%d", &(DEST)) == 1) \
|
||||||
|
|| (hex && sscanf(argv[i], "%x", &(DEST)) == 1 ) )
|
||||||
|
|
||||||
|
for(i = 1 ; i < argc ; i++) {
|
||||||
|
unsigned int uc, from, to;
|
||||||
|
|
||||||
|
if (strcmp(argv[i], "--hex") == 0) {
|
||||||
|
hex = 1;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "--decimal") == 0) {
|
||||||
|
hex = 0;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "--decode") == 0) {
|
||||||
|
#define RD fgetc_unlocked(stdin)
|
||||||
|
#define WR(C) do { \
|
||||||
|
if (C != -1) { \
|
||||||
|
printf("%04x\n", C); \
|
||||||
|
} else if (!feof(stdin)) { \
|
||||||
|
fprintf(stderr, "read error\n"); \
|
||||||
|
exit(EXIT_FAILURE); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
while(!feof(stdin)) {
|
||||||
|
READ_UNICODE(RD, WR);
|
||||||
|
}
|
||||||
|
#undef RD
|
||||||
|
#undef WR
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "-range") == 0
|
||||||
|
&& i + 2 < argc
|
||||||
|
&& (++i, 1)
|
||||||
|
&& READ_INT(from)
|
||||||
|
&& (++i, 1)
|
||||||
|
&& READ_INT(to)
|
||||||
|
) {
|
||||||
|
unsigned int i;
|
||||||
|
for(i = from ; i < to ; i++) {
|
||||||
|
#define EM(C) fputc_unlocked(C, stdout)
|
||||||
|
EMIT_UNICODE(i, EM);
|
||||||
|
#undef EM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (READ_INT(uc)) {
|
||||||
|
#define EM(C) fputc_unlocked(C, stdout)
|
||||||
|
EMIT_UNICODE(uc, EM);
|
||||||
|
#undef EM
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* IDNA helpers. */
|
/* IDNA helpers. */
|
||||||
#undef ADD_BYTE
|
#undef ADD_BYTE
|
||||||
#undef INCREASE_CAPA
|
#undef INCREASE_CAPA
|
||||||
@@ -910,19 +975,19 @@ char *hts_convertStringUTF8ToIDNA(const char *s, size_t size) {
|
|||||||
/* Reader: can read bytes up to j */
|
/* Reader: can read bytes up to j */
|
||||||
#define RD ( utfSeq < j ? segData[utfSeq++] : -1 )
|
#define RD ( utfSeq < j ? segData[utfSeq++] : -1 )
|
||||||
|
|
||||||
/* Writer: a malformed sequence abandons the encode (NULL) */
|
/* Writer: upon error, return FFFD (replacement character) */
|
||||||
#define WR(C) \
|
#define WR(C) do { \
|
||||||
do { \
|
if ((C) != -1) { \
|
||||||
if ((C) != -1) { \
|
/* copy character */ \
|
||||||
/* copy character */ \
|
assertf(segOutputSize < segSize); \
|
||||||
assertf(segOutputSize < segSize); \
|
segInt[segOutputSize++] = (C); \
|
||||||
segInt[segOutputSize++] = (C); \
|
} \
|
||||||
} else { \
|
/* In case of error, abort. */ \
|
||||||
freet(segInt); \
|
else { \
|
||||||
FREE_BUFFER(); \
|
FREE_BUFFER(); \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while(0)
|
||||||
|
|
||||||
/* Read/Write Unicode character. */
|
/* Read/Write Unicode character. */
|
||||||
READ_UNICODE(RD, WR);
|
READ_UNICODE(RD, WR);
|
||||||
@@ -1144,7 +1209,7 @@ int hts_isStringUTF8(const char *s, size_t size) {
|
|||||||
/* Reader: can read bytes up to j */
|
/* Reader: can read bytes up to j */
|
||||||
#define RD ( i < size ? data[i++] : -1 )
|
#define RD ( i < size ? data[i++] : -1 )
|
||||||
|
|
||||||
/* Writer: a malformed sequence means the string is not UTF-8 (return 0) */
|
/* Writer: upon error, return FFFD (replacement character) */
|
||||||
#define WR(C) if ((C) == -1) { return 0; }
|
#define WR(C) if ((C) == -1) { return 0; }
|
||||||
|
|
||||||
/* Read Unicode character. */
|
/* Read Unicode character. */
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// extension par défaut pour fichiers n'en ayant pas
|
// extension par défaut pour fichiers n'en ayant pas
|
||||||
#define DEFAULT_EXT ".html"
|
#define DEFAULT_EXT ".html"
|
||||||
#define DEFAULT_EXT_SHORT ".htm"
|
#define DEFAULT_EXT_SHORT ".htm"
|
||||||
|
// #define DEFAULT_BIN_EXT ".bin"
|
||||||
|
// #define DEFAULT_BIN_EXT_SHORT ".bin"
|
||||||
|
// #define DEFAULT_EXT ".txt"
|
||||||
|
// #define DEFAULT_EXT_SHORT ".txt"
|
||||||
|
|
||||||
// éviter les /nul, /con..
|
// éviter les /nul, /con..
|
||||||
#define HTS_OVERRIDE_DOS_FOLDERS 1
|
#define HTS_OVERRIDE_DOS_FOLDERS 1
|
||||||
@@ -76,6 +80,10 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// always direct-to-disk (0/1)
|
// always direct-to-disk (0/1)
|
||||||
#define HTS_DIRECTDISK_ALWAYS 1
|
#define HTS_DIRECTDISK_ALWAYS 1
|
||||||
|
|
||||||
|
// gérer une table de hachage?
|
||||||
|
// REMOVED
|
||||||
|
// #define HTS_HASH 1
|
||||||
|
|
||||||
// fast cache (build hash table)
|
// fast cache (build hash table)
|
||||||
#define HTS_FAST_CACHE 1
|
#define HTS_FAST_CACHE 1
|
||||||
|
|
||||||
@@ -89,10 +97,27 @@ Please visit our Website: http://www.httrack.com
|
|||||||
// always transform a '//' into a sigle '/'
|
// always transform a '//' into a sigle '/'
|
||||||
#define HTS_STRIP_DOUBLE_SLASH 0
|
#define HTS_STRIP_DOUBLE_SLASH 0
|
||||||
|
|
||||||
|
// case-sensitive pour les dossiers et fichiers (0/1)
|
||||||
|
// [normalement 1, mais pose des problèmes (url malformée par exemple) et n'est
|
||||||
|
// pas très utile..
|
||||||
|
// ..et pas bcp respecté]
|
||||||
|
// REMOVED
|
||||||
|
// #define HTS_CASSE 0
|
||||||
|
|
||||||
|
// Un fichier ayant une taille différente du content-length doit il être annulé?
|
||||||
|
// SEE opt.tolerant and opt.http10
|
||||||
|
// #define HTS_CL_IS_FATAL 0
|
||||||
|
|
||||||
// une erreur supprime le fichier sur disque
|
// une erreur supprime le fichier sur disque
|
||||||
// (non fixé pour cause de retry)
|
// (non fixé pour cause de retry)
|
||||||
#define HTS_REMOVE_BAD_FILES 0
|
#define HTS_REMOVE_BAD_FILES 0
|
||||||
|
|
||||||
|
// en cas de Range: xx- donnant un Content-length: xx
|
||||||
|
// alors skipper le fichier, considéré comme transmis
|
||||||
|
// #define HTS_SKIP_FULL_RANGE 1
|
||||||
|
|
||||||
|
// nombre max de filtres que l'utilisateur peut fixer
|
||||||
|
// #define HTS_FILTERSMAX 10000
|
||||||
#define HTS_FILTERSINC 1000
|
#define HTS_FILTERSINC 1000
|
||||||
|
|
||||||
// connect non bloquant? (poll sur write)
|
// connect non bloquant? (poll sur write)
|
||||||
|
|||||||
745
src/htscore.c
745
src/htscore.c
File diff suppressed because it is too large
Load Diff
@@ -216,7 +216,6 @@ struct cache_back {
|
|||||||
int zipEntriesCapa;
|
int zipEntriesCapa;
|
||||||
hts_boolean
|
hts_boolean
|
||||||
zipWriteFailed; /**< a cache write failed; stop touching the stream */
|
zipWriteFailed; /**< a cache write failed; stop touching the stream */
|
||||||
int zipWriteFailures; /**< consecutive entry write failures; reset on store */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef HTS_DEF_FWSTRUCT_hash_struct
|
#ifndef HTS_DEF_FWSTRUCT_hash_struct
|
||||||
@@ -363,20 +362,6 @@ void usercommand(httrackp * opt, int exe, const char *cmd, const char *file,
|
|||||||
|
|
||||||
void usercommand_exe(const char *cmd, const char *file);
|
void usercommand_exe(const char *cmd, const char *file);
|
||||||
|
|
||||||
// Finish the makeindex index.html (footer + refresh meta), run usercommand.
|
|
||||||
// Updates *makeindex_done/*makeindex_fp in place; adr/fil are the mode strings.
|
|
||||||
void hts_finish_makeindex(httrackp *opt, int *makeindex_done,
|
|
||||||
FILE **makeindex_fp, int makeindex_links,
|
|
||||||
const char *makeindex_firstlink,
|
|
||||||
const char *template_footer, const char *adr,
|
|
||||||
const char *fil);
|
|
||||||
|
|
||||||
// Flush ht_buff[0..ht_len] to save on disk (skip if MD5 unchanged); *fp
|
|
||||||
// closed+NULLed on write. Precondition: ht_len>0.
|
|
||||||
void hts_finish_html_file(httrackp *opt, cache_back *cache, htsblk *r,
|
|
||||||
FILE **fp, const char *ht_buff, size_t ht_len,
|
|
||||||
const char *adr, const char *fil, const char *save);
|
|
||||||
|
|
||||||
int filters_init(char ***ptrfilters, int maxfilter, int filterinc);
|
int filters_init(char ***ptrfilters, int maxfilter, int filterinc);
|
||||||
|
|
||||||
int fspc(httrackp * opt, FILE * fp, const char *type);
|
int fspc(httrackp * opt, FILE * fp, const char *type);
|
||||||
@@ -412,6 +397,10 @@ char *readfile_utf8(const char *fil);
|
|||||||
|
|
||||||
char *readfile_or(const char *fil, const char *defaultdata);
|
char *readfile_or(const char *fil, const char *defaultdata);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void check_rate(TStamp stat_timestart, int maxrate);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Backing (download-slot) scheduler. Operate on the back[] ring (struct_back).
|
/* Backing (download-slot) scheduler. Operate on the back[] ring (struct_back).
|
||||||
Not thread-safe; call from the single crawl loop. */
|
Not thread-safe; call from the single crawl loop. */
|
||||||
|
|
||||||
@@ -429,19 +418,6 @@ int back_pluggable_sockets(struct_back * sback, httrackp * opt);
|
|||||||
|
|
||||||
int back_pluggable_sockets_strict(struct_back * sback, httrackp * opt);
|
int back_pluggable_sockets_strict(struct_back * sback, httrackp * opt);
|
||||||
|
|
||||||
/* One engine-loop tick: refresh the transfer stats and run the loop callback
|
|
||||||
for slot b (-1 = none). HTS_FALSE = the callback requested an abort. */
|
|
||||||
hts_boolean hts_loop_tick(struct_back *sback, httrackp *opt, int b, int ptr);
|
|
||||||
|
|
||||||
/* Wait until a test socket can be plugged, pumping transfers, stats and the
|
|
||||||
loop callback; gives up past the -E deadline. HTS_FALSE = callback abort. */
|
|
||||||
hts_boolean hts_wait_available_socket(struct_back *sback, httrackp *opt,
|
|
||||||
cache_back *cache, int ptr);
|
|
||||||
|
|
||||||
/* Randomized inter-file pause target in [min_ms,max_ms] (#185), derived from a
|
|
||||||
timestamp seed so it is stable within one gap and rerolls per launch. */
|
|
||||||
int hts_pause_target_ms(TStamp seed, int min_ms, int max_ms);
|
|
||||||
|
|
||||||
/* Schedule more links from the heap into free slots. Returns the number queued,
|
/* Schedule more links from the heap into free slots. Returns the number queued,
|
||||||
or <=0 if none could be added (no free slot / paused / stopped). */
|
or <=0 if none could be added (no free slot / paused / stopped). */
|
||||||
int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
|
int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
|
||||||
@@ -463,6 +439,11 @@ int ask_continue(httrackp * opt);
|
|||||||
/* Number of decimal digits in n. */
|
/* Number of decimal digits in n. */
|
||||||
int nombre_digit(int n);
|
int nombre_digit(int n);
|
||||||
|
|
||||||
|
// Java
|
||||||
|
#if 0
|
||||||
|
int hts_add_file(char *file, int file_position);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Polling
|
// Polling
|
||||||
#if HTS_POLL
|
#if HTS_POLL
|
||||||
int check_flot(T_SOC s);
|
int check_flot(T_SOC s);
|
||||||
@@ -485,8 +466,4 @@ void voidf(void);
|
|||||||
/* HTML marker comment marking where the top index is spliced. */
|
/* HTML marker comment marking where the top index is spliced. */
|
||||||
#define HTS_TOPINDEX "TOP_INDEX_HTTRACK"
|
#define HTS_TOPINDEX "TOP_INDEX_HTTRACK"
|
||||||
|
|
||||||
/* Worst-case byte expansion HT_ADD_HTMLESCAPED* must reserve per escaper. */
|
|
||||||
#define HTS_HTMLESCAPE_MAXEXP 5 /* escape_for_html_print: '&'->"&" */
|
|
||||||
#define HTS_HTMLESCAPE_FULL_MAXEXP 6 /* _full: high byte->"&#xHH;" */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
char *url = NULL; // URLS séparées par un espace
|
char *url = NULL; // URLS séparées par un espace
|
||||||
int url_sz = 65535;
|
int url_sz = 65535;
|
||||||
|
|
||||||
|
//char url[65536]; // URLS séparées par un espace
|
||||||
// the parametres
|
// the parametres
|
||||||
int httrack_logmode = 3; // ONE log file
|
int httrack_logmode = 3; // ONE log file
|
||||||
|
|
||||||
@@ -289,11 +290,12 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
if (tmp_argc == 1) { /* pas -P & co */
|
if (tmp_argc == 1) { /* pas -P & co */
|
||||||
if (!cmdl_opt(tmp_argv[0])) { /* pas -c0 & co */
|
if (!cmdl_opt(tmp_argv[0])) { /* pas -c0 & co */
|
||||||
if (argv_url < 0)
|
if (argv_url < 0)
|
||||||
argv_url = 0; // -1==force -> 1=one url already detected, wipe all
|
argv_url = 0; // -1==force -> 1=one url already detected, wipe all previous options
|
||||||
// previous options
|
//if (argv_url>=0) {
|
||||||
argv_url++;
|
argv_url++;
|
||||||
if (!argv_firsturl)
|
if (!argv_firsturl)
|
||||||
argv_firsturl = x_argv[x_argc - 1];
|
argv_firsturl = x_argv[x_argc - 1];
|
||||||
|
//}
|
||||||
} else {
|
} else {
|
||||||
if (strcmp(tmp_argv[0], "-h") == 0) {
|
if (strcmp(tmp_argv[0], "-h") == 0) {
|
||||||
help(argv[0], !opt->quiet);
|
help(argv[0], !opt->quiet);
|
||||||
@@ -322,8 +324,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
} else if (tmp_argc == 2) {
|
} else if (tmp_argc == 2) {
|
||||||
if ((strcmp(tmp_argv[0], "-%L") == 0)) { // liste d'URLs
|
if ((strcmp(tmp_argv[0], "-%L") == 0)) { // liste d'URLs
|
||||||
if (argv_url < 0)
|
if (argv_url < 0)
|
||||||
argv_url = 0; // -1==force -> 1=one url already detected, wipe all
|
argv_url = 0; // -1==force -> 1=one url already detected, wipe all previous options
|
||||||
// previous options
|
//if (argv_url>=0)
|
||||||
argv_url++; /* forcer */
|
argv_url++; /* forcer */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,11 +403,15 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
else
|
else
|
||||||
inQuote = 1;
|
inQuote = 1;
|
||||||
} else if (!inQuote && !noDbl && argv[na][i] == ',') {
|
} else if (!inQuote && !noDbl && argv[na][i] == ',') {
|
||||||
|
//StringAddchar(path, '\0');
|
||||||
|
//j = 0;
|
||||||
path = &opt->path_log;
|
path = &opt->path_log;
|
||||||
} else {
|
} else {
|
||||||
StringAddchar(*path, argv[na][i]);
|
StringAddchar(*path, argv[na][i]);
|
||||||
|
//path[j++] = argv[na][i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//path[j++] = '\0';
|
||||||
if (StringLength(opt->path_log) == 0) {
|
if (StringLength(opt->path_log) == 0) {
|
||||||
StringCopyS(opt->path_log, opt->path_html);
|
StringCopyS(opt->path_log, opt->path_html);
|
||||||
}
|
}
|
||||||
@@ -414,6 +420,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
if (check_path(&opt->path_html, argv_firsturl)) {
|
if (check_path(&opt->path_html, argv_firsturl)) {
|
||||||
opt->dir_topindex = 1; // rebuilt top index
|
opt->dir_topindex = 1; // rebuilt top index
|
||||||
}
|
}
|
||||||
|
//printf("-->%s\n%s\n",StringBuff(opt->path_html),StringBuff(opt->path_log));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
@@ -532,15 +539,74 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
insert_after++;
|
insert_after++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (lastp != NULL);
|
} while(lastp != NULL);
|
||||||
|
//fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No new cache but an old one? promote it
|
// Existence d'un cache - pas de new mais un old.. renommer
|
||||||
#if DEBUG_STEPS
|
#if DEBUG_STEPS
|
||||||
printf("Checking cache\n");
|
printf("Checking cache\n");
|
||||||
#endif
|
#endif
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_PROMOTE);
|
if (!fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log), "hts-cache/new.zip"))) {
|
||||||
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log), "hts-cache/old.zip"))) {
|
||||||
|
rename(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.zip"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.zip"));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if ((!fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log), "hts-cache/new.dat")))
|
||||||
|
||
|
||||||
|
(!fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.ndx")))) {
|
||||||
|
if ((fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log), "hts-cache/old.dat")))
|
||||||
|
&&
|
||||||
|
(fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.ndx")))) {
|
||||||
|
remove(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.dat"));
|
||||||
|
remove(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.ndx"));
|
||||||
|
//remove(fconcat(StringBuff(opt->path_log),"hts-cache/new.lst"));
|
||||||
|
rename(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.dat"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.dat"));
|
||||||
|
rename(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.ndx"));
|
||||||
|
//rename(fconcat(StringBuff(opt->path_log),"hts-cache/old.lst"),fconcat(StringBuff(opt->path_log),"hts-cache/new.lst"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Interrupted mirror detected */
|
/* Interrupted mirror detected */
|
||||||
if (!opt->quiet) {
|
if (!opt->quiet) {
|
||||||
@@ -708,6 +774,24 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
HTS_PANIC_PRINTF(s);
|
HTS_PANIC_PRINTF(s);
|
||||||
htsmain_free();
|
htsmain_free();
|
||||||
return -1;
|
return -1;
|
||||||
|
#else
|
||||||
|
#if 0
|
||||||
|
char _args[8][256];
|
||||||
|
char *args[8];
|
||||||
|
|
||||||
|
printf("Cheking for updates...\n");
|
||||||
|
strcpybuff(_args[0], argv[0]);
|
||||||
|
strcpybuff(_args[1], "--get");
|
||||||
|
sprintf(_args[2], HTS_UPDATE_WEBSITE, 0, "");
|
||||||
|
strcpybuff(_args[3], "--quickinfo");
|
||||||
|
args[0] = _args[0];
|
||||||
|
args[1] = _args[1];
|
||||||
|
args[2] = _args[2];
|
||||||
|
args[3] = _args[3];
|
||||||
|
args[4] = NULL;
|
||||||
|
if (execvp(args[0], args) == -1) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -725,6 +809,103 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compter urls/jokers
|
||||||
|
/*
|
||||||
|
if (argv_url<=0) {
|
||||||
|
int na;
|
||||||
|
argv_url=0;
|
||||||
|
for(na=1;na<argc;na++) {
|
||||||
|
if ( (strcmp(argv[na],"-P")==0) || (strcmp(argv[na],"-N")==0) || (strcmp(argv[na],"-F")==0) || (strcmp(argv[na],"-O")==0) || (strcmp(argv[na],"-V")==0) ) {
|
||||||
|
na++; // sauter nom de proxy
|
||||||
|
} else if (!cmdl_opt(argv[na])) {
|
||||||
|
argv_url++; // un de plus
|
||||||
|
} else if (strcmp(argv[na],"-h")==0) {
|
||||||
|
help(argv[0],!opt->quiet);
|
||||||
|
htsmain_free();
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if ((strchr(argv[na],'q')!=NULL))
|
||||||
|
opt->quiet=1; // ne pas poser de questions! (nohup par exemple)
|
||||||
|
if ((strchr(argv[na],'i')!=NULL)) { // doit.log!
|
||||||
|
argv_url=0;
|
||||||
|
na=argc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Ici on ajoute les arguments qui ont été appelés avant au cas où on récupère une session
|
||||||
|
// Exemple: httrack www.truc.fr -L0 puis ^C puis httrack sans URL : ajouter URL précédente
|
||||||
|
/*
|
||||||
|
if (argv_url==0) {
|
||||||
|
//if ((fexist(fconcat(StringBuff(opt->path_log),"hts-cache/new.dat"))) && (fexist(fconcat(StringBuff(opt->path_log),"hts-cache/new.ndx")))) { // il existe déja un cache précédent.. renommer
|
||||||
|
if (fexist(fconcat(StringBuff(opt->path_log),"hts-cache/doit.log"))) { // un cache est présent
|
||||||
|
|
||||||
|
x_argvblk=(char*) calloct(32768,1);
|
||||||
|
|
||||||
|
if (x_argvblk!=NULL) {
|
||||||
|
FILE* fp;
|
||||||
|
int x_argc;
|
||||||
|
|
||||||
|
//strcpybuff(x_argvblk,"httrack ");
|
||||||
|
fp=fopen(fconcat(StringBuff(opt->path_log),"hts-cache/doit.log"),"rb");
|
||||||
|
if (fp) {
|
||||||
|
linput(fp,x_argvblk+strlen(x_argvblk),8192);
|
||||||
|
fclose(fp); fp=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculer arguments selon derniers arguments
|
||||||
|
x_argv[0]=argv[0];
|
||||||
|
x_argc=1;
|
||||||
|
{
|
||||||
|
char* p=x_argvblk;
|
||||||
|
do {
|
||||||
|
x_argv[x_argc++]=p;
|
||||||
|
//p=strstr(p," ");
|
||||||
|
// exemple de chaine: "echo \"test\"" c:\a "\$0"
|
||||||
|
p=next_token(p,1); // prochain token
|
||||||
|
if (p) {
|
||||||
|
*p=0; // octet nul (tableau)
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
} while(p!=NULL);
|
||||||
|
}
|
||||||
|
// recopier arguments actuels (pointeurs uniquement)
|
||||||
|
{
|
||||||
|
int na;
|
||||||
|
for(na=1;na<argc;na++) {
|
||||||
|
if (strcmp(argv[na],"-O") != 0) // SAUF le path!
|
||||||
|
x_argv[x_argc++]=argv[na];
|
||||||
|
else
|
||||||
|
na++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc=x_argc; // nouvel argc
|
||||||
|
argv=x_argv; // nouvel argv
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Vérifier quiet
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
int na;
|
||||||
|
for(na=1;na<argc;na++) {
|
||||||
|
if (!cmdl_opt(argv[na])) {
|
||||||
|
if ((strcmp(argv[na],"-P")==0) || (strcmp(argv[na],"-N")==0) || (strcmp(argv[na],"-F")==0) || (strcmp(argv[na],"-O")==0) || (strcmp(argv[na],"-V")==0))
|
||||||
|
na++; // sauter nom de proxy
|
||||||
|
} else {
|
||||||
|
if ((strchr(argv[na],'q')!=NULL) || (strchr(argv[na],'i')!=NULL))
|
||||||
|
opt->quiet=1; // ne pas poser de questions! (nohup par exemple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/* Engine self-tests: -#test lists them, -#test=NAME [args] runs one. Handled
|
/* Engine self-tests: -#test lists them, -#test=NAME [args] runs one. Handled
|
||||||
here, ahead of the no-URL usage gate below, so they need no dummy URL. */
|
here, ahead of the no-URL usage gate below, so they need no dummy URL. */
|
||||||
{
|
{
|
||||||
@@ -831,8 +1012,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
} else { // plus de 2 paramètres
|
} else { // plus de 2 paramètres
|
||||||
// un fichier log existe?
|
// un fichier log existe?
|
||||||
if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
StringBuff(opt->path_log),
|
StringBuff(opt->path_log), "hts-in_progress.lock"))) { // fichier lock?
|
||||||
"hts-in_progress.lock"))) { // fichier lock?
|
//char s[32];
|
||||||
|
|
||||||
opt->cache = HTS_CACHE_PRIORITY; // cache prioritaire
|
opt->cache = HTS_CACHE_PRIORITY; // cache prioritaire
|
||||||
if (opt->quiet == 0) {
|
if (opt->quiet == 0) {
|
||||||
@@ -863,8 +1044,11 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
} else
|
||||||
StringBuff(opt->path_html), "index.html"))) {
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_html), "index.html"))) {
|
||||||
|
//char s[32];
|
||||||
opt->cache = HTS_CACHE_TEST_UPDATE;
|
opt->cache = HTS_CACHE_TEST_UPDATE;
|
||||||
if (opt->quiet == 0) {
|
if (opt->quiet == 0) {
|
||||||
if ((fexist
|
if ((fexist
|
||||||
@@ -959,6 +1143,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
//
|
//
|
||||||
case 'g': // récupérer un (ou plusieurs) fichiers isolés
|
case 'g': // récupérer un (ou plusieurs) fichiers isolés
|
||||||
opt->wizard = HTS_WIZARD_AUTO;
|
opt->wizard = HTS_WIZARD_AUTO;
|
||||||
|
//opt->wizard=0; // pas de wizard
|
||||||
opt->cache = HTS_CACHE_NONE; // ni de cache
|
opt->cache = HTS_CACHE_NONE; // ni de cache
|
||||||
opt->makeindex = 0; // ni d'index
|
opt->makeindex = 0; // ni d'index
|
||||||
httrack_logmode = 1; // erreurs à l'écran
|
httrack_logmode = 1; // erreurs à l'écran
|
||||||
@@ -1058,6 +1243,9 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
while(isdigit((unsigned char) *(com + 1)))
|
while(isdigit((unsigned char) *(com + 1)))
|
||||||
com++;
|
com++;
|
||||||
break;
|
break;
|
||||||
|
//
|
||||||
|
//case 'A': opt->urlmode=1; break;
|
||||||
|
//case 'R': opt->urlmode=2; break;
|
||||||
case 'K':
|
case 'K':
|
||||||
opt->urlmode = HTS_URLMODE_ABSOLUTE;
|
opt->urlmode = HTS_URLMODE_ABSOLUTE;
|
||||||
if (isdigit((unsigned char) *(com + 1))) {
|
if (isdigit((unsigned char) *(com + 1))) {
|
||||||
@@ -1069,6 +1257,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
while(isdigit((unsigned char) *(com + 1)))
|
while(isdigit((unsigned char) *(com + 1)))
|
||||||
com++;
|
com++;
|
||||||
}
|
}
|
||||||
|
//if (*(com+1)=='0') { opt->urlmode=2; com++; } break;
|
||||||
|
//
|
||||||
case 'c':
|
case 'c':
|
||||||
if (isdigit((unsigned char) *(com + 1))) {
|
if (isdigit((unsigned char) *(com + 1))) {
|
||||||
sscanf(com + 1, "%d", &opt->maxsoc);
|
sscanf(com + 1, "%d", &opt->maxsoc);
|
||||||
@@ -1556,6 +1746,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
} else {
|
} else {
|
||||||
char *a;
|
char *a;
|
||||||
|
|
||||||
|
//char* b = StringBuff(opt->mimedefs) + StringLength(opt->mimedefs);
|
||||||
for(a = argv[na]; *a != '\0'; a++) {
|
for(a = argv[na]; *a != '\0'; a++) {
|
||||||
if (*a == ';') { /* next one */
|
if (*a == ';') { /* next one */
|
||||||
StringAddchar(opt->mimedefs, '\n');
|
StringAddchar(opt->mimedefs, '\n');
|
||||||
@@ -1785,68 +1976,6 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
StringCat(opt->strip_query, argv[na]);
|
StringCat(opt->strip_query, argv[na]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'K': // cookies-file: extra Netscape cookies.txt to preload
|
|
||||||
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
|
||||||
HTS_PANIC_PRINTF(
|
|
||||||
"Option cookies-file needs a blank space and "
|
|
||||||
"a cookies.txt path");
|
|
||||||
printf("Example: --cookies-file \"/home/me/cookies.txt\"\n");
|
|
||||||
htsmain_free();
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
na++;
|
|
||||||
if (strlen(argv[na]) >= 1024) {
|
|
||||||
HTS_PANIC_PRINTF("Cookie file path too long");
|
|
||||||
htsmain_free();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
StringCopy(opt->cookies_file, argv[na]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'Y': // why: explain the filter verdict for a URL, no crawl
|
|
||||||
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
|
||||||
HTS_PANIC_PRINTF("Option why needs a blank space and a URL");
|
|
||||||
printf(
|
|
||||||
"Example: --why \"http://www.example.com/file.zip\"\n");
|
|
||||||
htsmain_free();
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
na++;
|
|
||||||
if (strlen(argv[na]) >= HTS_URLMAXSIZE) {
|
|
||||||
HTS_PANIC_PRINTF("why URL too long");
|
|
||||||
htsmain_free();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
StringCopy(opt->why_url, argv[na]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'G': // pause: randomized inter-file delay MIN[:MAX] seconds
|
|
||||||
if ((na + 1 >= argc) || (argv[na + 1][0] == '-')) {
|
|
||||||
HTS_PANIC_PRINTF("Option pause needs a blank space and a "
|
|
||||||
"delay in seconds (MIN[:MAX])");
|
|
||||||
printf("Example: --pause 5:10\n");
|
|
||||||
htsmain_free();
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
double pmin = 0, pmax = 0;
|
|
||||||
int nf;
|
|
||||||
|
|
||||||
na++;
|
|
||||||
nf = sscanf(argv[na], "%lf:%lf", &pmin, &pmax);
|
|
||||||
if (nf < 2)
|
|
||||||
pmax = pmin; /* a single value means a fixed delay */
|
|
||||||
/* positive-form bounds: NaN fails every comparison, so this
|
|
||||||
rejects it before the undefined (int)(NaN*1000) cast */
|
|
||||||
if (nf < 1 || !(pmin >= 0 && pmax >= pmin && pmax <= 86400)) {
|
|
||||||
HTS_PANIC_PRINTF("Invalid --pause range (expected "
|
|
||||||
"MIN[:MAX] seconds, 0<=MIN<=MAX<=86400)");
|
|
||||||
htsmain_free();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
opt->pause_min_ms = (int) (pmin * 1000.0);
|
|
||||||
opt->pause_max_ms = (int) (pmax * 1000.0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 't': /* do not change type (ending) of filenames according to the MIME type */
|
case 't': /* do not change type (ending) of filenames according to the MIME type */
|
||||||
opt->no_type_change = 1;
|
opt->no_type_change = 1;
|
||||||
if (*(com+1)=='0') { opt->no_type_change = 0; com++; }
|
if (*(com+1)=='0') { opt->no_type_change = 0; com++; }
|
||||||
@@ -1911,7 +2040,10 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
HTS_PANIC_PRINTF(s);
|
HTS_PANIC_PRINTF(s);
|
||||||
htsmain_free();
|
htsmain_free();
|
||||||
return -1;
|
return -1;
|
||||||
} break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//case 's': opt->sslengine=1; if (isdigit((unsigned char)*(com+1))) { sscanf(com+1,"%d",&opt->sslengine); while(isdigit((unsigned char)*(com+1))) com++; } break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1953,20 +2085,18 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
char BIGSTK url[HTS_URLMAXSIZE * 2];
|
char BIGSTK url[HTS_URLMAXSIZE * 2];
|
||||||
char linepos[256];
|
char linepos[256];
|
||||||
int pos;
|
int pos;
|
||||||
LLint cacheNdxLen = 0;
|
char *cacheNdx =
|
||||||
char *cacheNdx = readfile2(
|
readfile(fconcat
|
||||||
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
StringBuff(opt->path_log), "hts-cache/new.ndx"),
|
"hts-cache/new.ndx"));
|
||||||
&cacheNdxLen);
|
|
||||||
cache_init(&cache, opt); /* load cache */
|
cache_init(&cache, opt); /* load cache */
|
||||||
if (cacheNdx != NULL) {
|
if (cacheNdx != NULL) {
|
||||||
char firstline[256];
|
char firstline[256];
|
||||||
char *a = cacheNdx;
|
char *a = cacheNdx;
|
||||||
const char *const end = cacheNdx + cacheNdxLen;
|
|
||||||
|
|
||||||
a += cache_brstr(a, firstline, sizeof(firstline));
|
a += cache_brstr(a, firstline, sizeof(firstline));
|
||||||
a += cache_brstr(a, firstline, sizeof(firstline));
|
a += cache_brstr(a, firstline, sizeof(firstline));
|
||||||
while (a != NULL && a < end) {
|
while(a != NULL) {
|
||||||
a = strchr(a + 1, '\n'); /* start of line */
|
a = strchr(a + 1, '\n'); /* start of line */
|
||||||
if (a) {
|
if (a) {
|
||||||
htsblk r;
|
htsblk r;
|
||||||
@@ -1974,15 +2104,15 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
/* */
|
/* */
|
||||||
a++;
|
a++;
|
||||||
/* read "host/file" */
|
/* read "host/file" */
|
||||||
a += cache_binput(a, end, afs.af.adr, HTS_URLMAXSIZE);
|
a += binput(a, afs.af.adr, HTS_URLMAXSIZE);
|
||||||
a += cache_binput(a, end, afs.af.fil, HTS_URLMAXSIZE);
|
a += binput(a, afs.af.fil, HTS_URLMAXSIZE);
|
||||||
url[0] = '\0';
|
url[0] = '\0';
|
||||||
if (!link_has_authority(afs.af.adr))
|
if (!link_has_authority(afs.af.adr))
|
||||||
strcatbuff(url, "http://");
|
strcatbuff(url, "http://");
|
||||||
strcatbuff(url, afs.af.adr);
|
strcatbuff(url, afs.af.adr);
|
||||||
strcatbuff(url, afs.af.fil);
|
strcatbuff(url, afs.af.fil);
|
||||||
/* read position */
|
/* read position */
|
||||||
a += cache_binput(a, end, linepos, 200);
|
a += binput(a, linepos, 200);
|
||||||
sscanf(linepos, "%d", &pos);
|
sscanf(linepos, "%d", &pos);
|
||||||
if (!hasFilter
|
if (!hasFilter
|
||||||
|| (strjoker(url, filter, NULL, NULL) != NULL)
|
|| (strjoker(url, filter, NULL, NULL) != NULL)
|
||||||
@@ -2157,7 +2287,15 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case '~': /* internal lib test */
|
case '~': /* internal lib test */
|
||||||
HTS_PANIC_PRINTF("Option #~ is disabled for security reasons");
|
HTS_PANIC_PRINTF
|
||||||
|
("Option #~ is disabled for security reasons");
|
||||||
|
//Disabled because choke on GCC 4.3 (toni from links2linux.de)
|
||||||
|
//{
|
||||||
|
// char thisIsATestYouShouldSeeAnError[12];
|
||||||
|
// const char *const bufferOverflowTest = "0123456789012345678901234567890123456789";
|
||||||
|
// strcpybuff(thisIsATestYouShouldSeeAnError, bufferOverflowTest);
|
||||||
|
// return 0;
|
||||||
|
//}
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
opt->flush = 1;
|
opt->flush = 1;
|
||||||
@@ -2259,6 +2397,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
opt->proxy.active = 1;
|
opt->proxy.active = 1;
|
||||||
// Rechercher MAIS en partant de la fin à cause de user:pass@proxy:port
|
// Rechercher MAIS en partant de la fin à cause de user:pass@proxy:port
|
||||||
a = argv[na] + strlen(argv[na]) - 1;
|
a = argv[na] + strlen(argv[na]) - 1;
|
||||||
|
// a=strstr(argv[na],":"); // port
|
||||||
while((a > argv[na]) && (*a != ':') && (*a != '@'))
|
while((a > argv[na]) && (*a != ':') && (*a != '@'))
|
||||||
a--;
|
a--;
|
||||||
if (*a == ':') { // un port est présent, <proxy>:port
|
if (*a == ':') { // un port est présent, <proxy>:port
|
||||||
@@ -2363,14 +2502,116 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//printf("WARNING! This is *only* a beta-release of HTTrack\n");
|
||||||
io_flush;
|
io_flush;
|
||||||
|
|
||||||
#if DEBUG_STEPS
|
#if DEBUG_STEPS
|
||||||
printf("Cache & log settings\n");
|
printf("Cache & log settings\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If both cache generations exist, keep the most complete one
|
// on utilise le cache..
|
||||||
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
|
// en cas de présence des deux versions, garder la version la plus avancée,
|
||||||
|
// cad la version contenant le plus de fichiers
|
||||||
|
if (opt->cache) {
|
||||||
|
if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-in_progress.lock"))) { // problemes..
|
||||||
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.dat"))) {
|
||||||
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.zip"))) {
|
||||||
|
if (fsize
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.zip")) < 32768) {
|
||||||
|
if (fsize
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.zip")) > 65536) {
|
||||||
|
if (fsize
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.zip")) > fsize(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->
|
||||||
|
path_log),
|
||||||
|
"hts-cache/new.zip")))
|
||||||
|
{
|
||||||
|
remove(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.zip"));
|
||||||
|
rename(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.zip"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.zip"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.dat"))
|
||||||
|
&&
|
||||||
|
fexist(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.ndx"))) {
|
||||||
|
if (fexist
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.dat"))
|
||||||
|
&&
|
||||||
|
fexist(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.ndx"))) {
|
||||||
|
// switcher si new<32Ko et old>65Ko (tailles arbitraires) ?
|
||||||
|
// ce cas est peut être une erreur ou un crash d'un miroir ancien, prendre
|
||||||
|
// alors l'ancien cache
|
||||||
|
if (fsize
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.dat")) < 32768) {
|
||||||
|
if (fsize
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.dat")) > 65536) {
|
||||||
|
if (fsize
|
||||||
|
(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.dat")) > fsize(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->
|
||||||
|
path_log),
|
||||||
|
"hts-cache/new.dat")))
|
||||||
|
{
|
||||||
|
remove(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.dat"));
|
||||||
|
remove(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.ndx"));
|
||||||
|
rename(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.dat"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.dat"));
|
||||||
|
rename(fconcat
|
||||||
|
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
|
"hts-cache/old.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
|
StringBuff(opt->path_log),
|
||||||
|
"hts-cache/new.ndx"));
|
||||||
|
//} else { // ne rien faire
|
||||||
|
// remove("hts-cache/old.dat");
|
||||||
|
// remove("hts-cache/old.ndx");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Débuggage des en têtes
|
// Débuggage des en têtes
|
||||||
if (_DEBUG_HEAD) {
|
if (_DEBUG_HEAD) {
|
||||||
ioinfo =
|
ioinfo =
|
||||||
@@ -2446,6 +2687,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
{
|
{
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
|
//int n=0;
|
||||||
char t[256];
|
char t[256];
|
||||||
|
|
||||||
time_local_rfc822(t); // faut bien que ca serve quelque part l'heure RFC1945 arf'
|
time_local_rfc822(t); // faut bien que ca serve quelque part l'heure RFC1945 arf'
|
||||||
@@ -2479,8 +2721,9 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
strcpybuff(n_lock,
|
strcpybuff(n_lock,
|
||||||
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
|
||||||
StringBuff(opt->path_log), "hts-in_progress.lock"));
|
"hts-in_progress.lock"));
|
||||||
|
//sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
|
||||||
/*do {
|
/*do {
|
||||||
if (!n)
|
if (!n)
|
||||||
sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
|
sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
|
||||||
@@ -2556,6 +2799,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
|||||||
fprintf(fp, LF);
|
fprintf(fp, LF);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
|
//} else if (opt->debug>1) {
|
||||||
|
// printf("! FileOpen error, \"%s\"\n",strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// petit message dans le lock
|
// petit message dans le lock
|
||||||
|
|||||||
@@ -69,15 +69,11 @@ typedef struct t_hts_callbackarg t_hts_callbackarg;
|
|||||||
typedef struct t_hts_callbackarg t_hts_callbackarg;
|
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)
|
(dllexport on Windows, nothing elsewhere). */
|
||||||
hide their own hts_plug()/hts_unplug() entry points. */
|
|
||||||
#ifndef EXTERNAL_FUNCTION
|
#ifndef EXTERNAL_FUNCTION
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define EXTERNAL_FUNCTION __declspec(dllexport)
|
#define EXTERNAL_FUNCTION __declspec(dllexport)
|
||||||
#elif ((defined(__GNUC__) && (__GNUC__ >= 4)) || \
|
|
||||||
(defined(HAVE_VISIBILITY) && HAVE_VISIBILITY))
|
|
||||||
#define EXTERNAL_FUNCTION __attribute__((visibility("default")))
|
|
||||||
#else
|
#else
|
||||||
#define EXTERNAL_FUNCTION
|
#define EXTERNAL_FUNCTION
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -30,14 +30,12 @@ Please visit our Website: http://www.httrack.com
|
|||||||
/* Author: Xavier Roche */
|
/* Author: Xavier Roche */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "htscharset.h"
|
#include "htscharset.h"
|
||||||
#include "htsencoding.h"
|
#include "htsencoding.h"
|
||||||
#include "htssafe.h"
|
#include "htssafe.h"
|
||||||
|
|
||||||
/* static int decode_entity(const uint64_t hash, const size_t len);
|
/* static int decode_entity(const unsigned int hash, const size_t len);
|
||||||
*/
|
*/
|
||||||
#include "htsentities.h"
|
#include "htsentities.h"
|
||||||
|
|
||||||
/* hexadecimal conversion */
|
/* hexadecimal conversion */
|
||||||
@@ -52,31 +50,30 @@ static int get_hex_value(char c) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 64-bit FNV-1a; must match htsentities.sh, which keys the entity table on it.
|
/* Numerical Recipes,
|
||||||
*/
|
see <http://en.wikipedia.org/wiki/Linear_congruential_generator> */
|
||||||
#define HASH_INIT 0xcbf29ce484222325ULL
|
#define HASH_PRIME ( 1664525 )
|
||||||
#define HASH_PRIME 0x100000001b3ULL
|
#define HASH_CONST ( 1013904223 )
|
||||||
#define HASH_ADD(HASH, C) \
|
#define HASH_ADD(HASH, C) do { \
|
||||||
do { \
|
(HASH) *= HASH_PRIME; \
|
||||||
(HASH) ^= (unsigned char) (C); \
|
(HASH) += HASH_CONST; \
|
||||||
(HASH) *= HASH_PRIME; \
|
(HASH) += (C); \
|
||||||
} while (0)
|
} while(0)
|
||||||
|
|
||||||
int hts_unescapeEntitiesWithCharset(const char *src, char *dest, const size_t max, const char *charset) {
|
int hts_unescapeEntitiesWithCharset(const char *src, char *dest, const size_t max, const char *charset) {
|
||||||
size_t i, j, ampStart, ampStartDest;
|
size_t i, j, ampStart, ampStartDest;
|
||||||
int uc;
|
int uc;
|
||||||
int hex;
|
int hex;
|
||||||
uint64_t hash;
|
unsigned int hash;
|
||||||
|
|
||||||
assertf(max != 0);
|
assertf(max != 0);
|
||||||
for (i = 0, j = 0, ampStart = (size_t) -1, ampStartDest = 0, uc = -1, hex = 0,
|
for(i = 0, j = 0, ampStart = (size_t) -1, ampStartDest = 0,
|
||||||
hash = HASH_INIT;
|
uc = -1, hex = 0, hash = 0 ; src[i] != '\0' ; i++) {
|
||||||
src[i] != '\0'; i++) {
|
|
||||||
/* start of entity */
|
/* start of entity */
|
||||||
if (src[i] == '&') {
|
if (src[i] == '&') {
|
||||||
ampStart = i;
|
ampStart = i;
|
||||||
ampStartDest = j;
|
ampStartDest = j;
|
||||||
hash = HASH_INIT;
|
hash = 0;
|
||||||
uc = -1;
|
uc = -1;
|
||||||
}
|
}
|
||||||
/* inside a potential entity */
|
/* inside a potential entity */
|
||||||
@@ -177,11 +174,14 @@ int hts_unescapeEntitiesWithCharset(const char *src, char *dest, const size_t ma
|
|||||||
}
|
}
|
||||||
/* alphanumerical entity */
|
/* alphanumerical entity */
|
||||||
else {
|
else {
|
||||||
/* alphanum, capped at the longest name
|
/* alphanum and not too far ('ϑ' is the longest) */
|
||||||
* '∳' (31) */
|
if (i <= ampStart + 10 &&
|
||||||
if (i <= ampStart + 31 && ((src[i] >= '0' && src[i] <= '9') ||
|
(
|
||||||
(src[i] >= 'A' && src[i] <= 'Z') ||
|
(src[i] >= '0' && src[i] <= '9')
|
||||||
(src[i] >= 'a' && src[i] <= 'z'))) {
|
|| (src[i] >= 'A' && src[i] <= 'Z')
|
||||||
|
|| (src[i] >= 'a' && src[i] <= 'z')
|
||||||
|
)
|
||||||
|
) {
|
||||||
/* compute hash */
|
/* compute hash */
|
||||||
HASH_ADD(hash, (unsigned char) src[i]);
|
HASH_ADD(hash, (unsigned char) src[i]);
|
||||||
} else {
|
} else {
|
||||||
@@ -190,9 +190,9 @@ int hts_unescapeEntitiesWithCharset(const char *src, char *dest, const size_t ma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reserve one byte for the trailing NUL written after the loop */
|
/* copy */
|
||||||
if (j + 1 >= max) {
|
if (j + 1 > max) {
|
||||||
/* overflow */
|
/* overflow */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -300,11 +300,6 @@ int hts_unescapeUrlSpecial(const char *src, char *dest, const size_t max,
|
|||||||
|
|
||||||
/* Was the character read successfully ? */
|
/* Was the character read successfully ? */
|
||||||
if (nRead == utfBufferSize) {
|
if (nRead == utfBufferSize) {
|
||||||
/* the 'continue' below skips the NUL-reserve guard: re-check */
|
|
||||||
if (utfBufferJ + utfBufferSize >= max) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rollback write position to sequence start write position */
|
/* Rollback write position to sequence start write position */
|
||||||
j = utfBufferJ;
|
j = utfBufferJ;
|
||||||
|
|
||||||
@@ -319,8 +314,8 @@ int hts_unescapeUrlSpecial(const char *src, char *dest, const size_t max,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reserve one byte for the trailing NUL written after the loop */
|
/* Check for overflow */
|
||||||
if (j + 1 >= max) {
|
if (j + 1 > max) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13612
src/htsentities.h
13612
src/htsentities.h
File diff suppressed because it is too large
Load Diff
@@ -1,92 +1,75 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# Regenerate htsentities.h from the WHATWG named character references.
|
|
||||||
|
|
||||||
set -euo pipefail
|
src=html40.txt
|
||||||
|
url=http://www.w3.org/TR/1998/REC-html40-19980424/html40.txt
|
||||||
src=entities.json
|
|
||||||
url=https://html.spec.whatwg.org/entities.json
|
|
||||||
dest=htsentities.h
|
dest=htsentities.h
|
||||||
|
|
||||||
# 64-bit FNV-1a of $1, printed as a C constant. Must match the hash in
|
(
|
||||||
# htsencoding.c. The offset basis is stored as its wrapped (signed) bit pattern;
|
cat <<EOF
|
||||||
# bash arithmetic is 64-bit two's complement, so the result is bit-exact.
|
/*
|
||||||
fnv1a() {
|
-- ${dest} --
|
||||||
local s=$1 i c h=$((0xcbf29ce484222325))
|
FILE GENERATED BY $0, DO NOT MODIFY
|
||||||
for ((i = 0; i < ${#s}; i++)); do
|
|
||||||
printf -v c '%d' "'${s:i:1}"
|
|
||||||
h=$(((h ^ (c & 0xff)) * 0x100000001b3))
|
|
||||||
done
|
|
||||||
printf '0x%016xULL' "$h"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ ! -f "$src" ]; then
|
We compute the LCG hash
|
||||||
curl -fsS "$url" -o "$src"
|
(see <http://en.wikipedia.org/wiki/Linear_congruential_generator>)
|
||||||
fi
|
for each entity. We should in theory check using strncmp() that we
|
||||||
|
actually have the correct entity, but this is actually statistically
|
||||||
|
not needed.
|
||||||
|
|
||||||
# Keep ';'-terminated single-codepoint names; the ~93 multi-codepoint refs can't
|
We may want to do better, but we expect the hash function to be uniform, and
|
||||||
# fit decode_entity's single-codepoint return and are skipped (left verbatim).
|
let the compiler be smart enough to optimize the switch (for example by
|
||||||
pairs=$(jq -r '
|
checking in log2() intervals)
|
||||||
to_entries
|
|
||||||
| map(select((.key | endswith(";")) and (.value.codepoints | length == 1)))
|
This code has been generated using the evil $0 script.
|
||||||
| sort_by(.key)
|
*/
|
||||||
| .[] | "\(.key | ltrimstr("&") | rtrimstr(";"))\t\(.value.codepoints[0])"' "$src")
|
|
||||||
|
|
||||||
# Skipped multi-codepoint names, kept to prove none aliases an emitted hash.
|
static int decode_entity(const unsigned int hash, const size_t len) {
|
||||||
skipped=$(jq -r '
|
|
||||||
to_entries
|
|
||||||
| map(select((.key | endswith(";")) and (.value.codepoints | length > 1)))
|
|
||||||
| .[] | .key | ltrimstr("&") | rtrimstr(";")' "$src")
|
|
||||||
|
|
||||||
cases=""
|
|
||||||
emit_hashes=""
|
|
||||||
while IFS=$'\t' read -r name cp; do
|
|
||||||
hash=$(fnv1a "$name")
|
|
||||||
cases+=" /* $name */"$'\n'
|
|
||||||
cases+=" case $hash:"$'\n'
|
|
||||||
cases+=" if (len == ${#name}) {"$'\n'
|
|
||||||
cases+=" return $cp;"$'\n'
|
|
||||||
cases+=" }"$'\n'
|
|
||||||
cases+=" break;"$'\n'
|
|
||||||
emit_hashes+="$hash"$'\n'
|
|
||||||
done <<<"$pairs"
|
|
||||||
|
|
||||||
skip_hashes=""
|
|
||||||
while IFS= read -r name; do
|
|
||||||
[ -n "$name" ] && skip_hashes+="$(fnv1a "$name")"$'\n'
|
|
||||||
done <<<"$skipped"
|
|
||||||
|
|
||||||
# The switch keys on the hash alone, so the dispatch is correct only while every
|
|
||||||
# emitted name hashes uniquely; prove it here, no runtime name compare needed.
|
|
||||||
dups=$(printf '%s' "$emit_hashes" | sort | uniq -d || true)
|
|
||||||
if [ -n "$dups" ]; then
|
|
||||||
echo "FATAL: two entity names share a hash (duplicate switch case); change the hash:" >&2
|
|
||||||
echo "$dups" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# A skipped name colliding with an emitted hash would mis-decode instead of
|
|
||||||
# staying verbatim; forbid that too.
|
|
||||||
aliased=$(comm -12 <(printf '%s' "$emit_hashes" | sort -u) <(printf '%s' "$skip_hashes" | sort -u) || true)
|
|
||||||
if [ -n "$aliased" ]; then
|
|
||||||
echo "FATAL: a skipped multi-codepoint name aliases an emitted hash:" >&2
|
|
||||||
echo "$aliased" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat >"$dest" <<EOF
|
|
||||||
/* GENERATED by $0 from the WHATWG named character references
|
|
||||||
(${url}). DO NOT EDIT.
|
|
||||||
Dispatch keys on a 64-bit FNV-1a hash of the entity name; the generator
|
|
||||||
aborts on any hash collision, so no runtime name compare is needed. */
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
static int decode_entity(const uint64_t hash, const size_t len) {
|
|
||||||
switch(hash) {
|
switch(hash) {
|
||||||
${cases} }
|
EOF
|
||||||
|
(
|
||||||
|
if test -f ${src}; then
|
||||||
|
cat ${src}
|
||||||
|
else
|
||||||
|
GET "${url}"
|
||||||
|
fi
|
||||||
|
) |
|
||||||
|
grep -E '^<!ENTITY [a-zA-Z0-9_]' |
|
||||||
|
sed \
|
||||||
|
-e 's/<!ENTITY //' -e "s/[[:space:]][[:space:]]*/ /g" \
|
||||||
|
-e 's/-->$//' \
|
||||||
|
-e 's/\([^ ]*\) CDATA "&#\([^\"]*\);" -- \(.*\)/\1 \2 \3/' |
|
||||||
|
(
|
||||||
|
read -r A
|
||||||
|
while test -n "$A"; do
|
||||||
|
ent="${A%% *}"
|
||||||
|
code=$(echo "$A" | cut -f2 -d' ')
|
||||||
|
# compute hash
|
||||||
|
hash=0
|
||||||
|
i=0
|
||||||
|
a=1664525
|
||||||
|
c=1013904223
|
||||||
|
m="$((1 << 32))"
|
||||||
|
while test "$i" -lt ${#ent}; do
|
||||||
|
d="$(echo -n "${ent:${i}:1}" | hexdump -v -e '/1 "%d"')"
|
||||||
|
hash="$((((hash * a) % (m) + d + c) % (m)))"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
echo -e " /* $A */"
|
||||||
|
echo -e " case ${hash}u:"
|
||||||
|
echo -e " if (len == ${#ent} /* && strncmp(ent, \"${ent}\") == 0 */) {"
|
||||||
|
echo -e " return ${code};"
|
||||||
|
echo -e " }"
|
||||||
|
echo -e " break;"
|
||||||
|
|
||||||
|
# next
|
||||||
|
read -r A
|
||||||
|
done
|
||||||
|
)
|
||||||
|
cat <<EOF
|
||||||
|
}
|
||||||
/* unknown */
|
/* unknown */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
) >${dest}
|
||||||
echo "wrote $dest ($(grep -c '^ case ' "$dest") entities)" >&2
|
|
||||||
|
|||||||
@@ -94,32 +94,6 @@ int fa_strjoker(int type, char **filters, int nfil, const char *nom, LLint * siz
|
|||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fa_strjoker_dual(int type, char **filters, int nfil, const char *nom1,
|
|
||||||
const char *nom2, LLint *size, int *size_flag,
|
|
||||||
int *depth) {
|
|
||||||
int depth1 = 0, depth2 = 0;
|
|
||||||
int flag1 = 0, flag2 = 0;
|
|
||||||
LLint sz1 = 0, sz2 = 0;
|
|
||||||
int jok1, jok2, use1;
|
|
||||||
|
|
||||||
if (size) {
|
|
||||||
sz1 = *size;
|
|
||||||
sz2 = *size;
|
|
||||||
}
|
|
||||||
jok1 = fa_strjoker(type, filters, nfil, nom1, size ? &sz1 : NULL,
|
|
||||||
size_flag ? &flag1 : NULL, &depth1);
|
|
||||||
jok2 = fa_strjoker(type, filters, nfil, nom2, size ? &sz2 : NULL,
|
|
||||||
size_flag ? &flag2 : NULL, &depth2);
|
|
||||||
use1 = jok2 == 0 || (jok1 != 0 && depth1 >= depth2);
|
|
||||||
if (size)
|
|
||||||
*size = use1 ? sz1 : sz2;
|
|
||||||
if (size_flag)
|
|
||||||
*size_flag = use1 ? flag1 : flag2;
|
|
||||||
if (depth)
|
|
||||||
*depth = use1 ? depth1 : depth2;
|
|
||||||
return use1 ? jok1 : jok2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// supercomparateur joker (tm)
|
// supercomparateur joker (tm)
|
||||||
// compare a et b (b=avec joker dedans), case insensitive [voir CI]
|
// compare a et b (b=avec joker dedans), case insensitive [voir CI]
|
||||||
// renvoi l'adresse de la première lettre de la chaine
|
// renvoi l'adresse de la première lettre de la chaine
|
||||||
@@ -128,8 +102,9 @@ int fa_strjoker_dual(int type, char **filters, int nfil, const char *nom1,
|
|||||||
// cet algo est 'un peu' récursif mais ne consomme pas trop de tm
|
// cet algo est 'un peu' récursif mais ne consomme pas trop de tm
|
||||||
// * = toute lettre
|
// * = toute lettre
|
||||||
// --?-- : spécifique à HTTrack et aux ?
|
// --?-- : spécifique à HTTrack et aux ?
|
||||||
HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * size,
|
||||||
LLint *size, int *size_flag) {
|
int *size_flag) {
|
||||||
|
//int err=0;
|
||||||
if (strnotempty(joker) == 0) { // fin de chaine joker
|
if (strnotempty(joker) == 0) { // fin de chaine joker
|
||||||
if (strnotempty(chaine) == 0) // fin aussi pour la chaine: ok
|
if (strnotempty(chaine) == 0) // fin aussi pour la chaine: ok
|
||||||
return chaine;
|
return chaine;
|
||||||
@@ -218,12 +193,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
|||||||
int len = (int) strlen(joker);
|
int len = (int) strlen(joker);
|
||||||
|
|
||||||
while((joker[i] != RIGHT) && (joker[i]) && (i < len)) {
|
while((joker[i] != RIGHT) && (joker[i]) && (i < len)) {
|
||||||
// '\' escapes the next char as a literal member, e.g. *[\[\]]
|
if ((joker[i] == '<') || (joker[i] == '>')) { // *[<10]
|
||||||
if (joker[i] == '\\' && joker[i + 1] != '\0') {
|
|
||||||
i++;
|
|
||||||
pass[(int) (unsigned char) joker[i]] = 1;
|
|
||||||
i++;
|
|
||||||
} else if ((joker[i] == '<') || (joker[i] == '>')) { // *[<10]
|
|
||||||
int lsize = 0;
|
int lsize = 0;
|
||||||
int lverdict;
|
int lverdict;
|
||||||
|
|
||||||
@@ -251,9 +221,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
|||||||
while(isdigit((unsigned char) joker[i]))
|
while(isdigit((unsigned char) joker[i]))
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
} else if (joker[i + 1] == '-' && joker[i + 2] != '\0') {
|
} else if (joker[i + 1] == '-') { // 2 car, ex: *[A-Z]
|
||||||
// range *[A-Z]; the '\0' guard rejects a truncated *[a- (else
|
|
||||||
// i+=3 overshoots the NUL)
|
|
||||||
if ((int) (unsigned char) joker[i + 2] >
|
if ((int) (unsigned char) joker[i + 2] >
|
||||||
(int) (unsigned char) joker[i]) {
|
(int) (unsigned char) joker[i]) {
|
||||||
int j;
|
int j;
|
||||||
@@ -261,9 +229,14 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
|||||||
for(j = (int) (unsigned char) joker[i];
|
for(j = (int) (unsigned char) joker[i];
|
||||||
j <= (int) (unsigned char) joker[i + 2]; j++)
|
j <= (int) (unsigned char) joker[i + 2]; j++)
|
||||||
pass[j] = 1;
|
pass[j] = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// else err=1;
|
||||||
i += 3;
|
i += 3;
|
||||||
} else { // 1 car, ex: *[ ]
|
} else { // 1 car, ex: *[ ]
|
||||||
|
if (joker[i + 2] == '\\' && joker[i + 3] != 0) { // escaped char, such as *[\[] or *[\]]
|
||||||
|
i++;
|
||||||
|
}
|
||||||
pass[(int) (unsigned char) joker[i]] = 1;
|
pass[(int) (unsigned char) joker[i]] = 1;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -285,6 +258,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
|||||||
for(i = 0; i < 256; i++)
|
for(i = 0; i < 256; i++)
|
||||||
pass[i] = 1; // tout autoriser
|
pass[i] = 1; // tout autoriser
|
||||||
jmp = 1;
|
jmp = 1;
|
||||||
|
////if (joker[2]==LEFT) jmp=3; // permet de recher *<crochet ouvrant>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -312,7 +286,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
|
|||||||
if (!unique)
|
if (!unique)
|
||||||
max = (int) strlen(chaine);
|
max = (int) strlen(chaine);
|
||||||
else /* *(a) only match a (not aaaaa) */
|
else /* *(a) only match a (not aaaaa) */
|
||||||
max = strnotempty(chaine) ? 1 : 0; /* empty chaine: no char to eat */
|
max = 1;
|
||||||
while(i < (int) max) {
|
while(i < (int) max) {
|
||||||
if (pass[(int) (unsigned char) chaine[i]]) { // caractère autorisé
|
if (pass[(int) (unsigned char) chaine[i]]) { // caractère autorisé
|
||||||
if ((adr = strjoker(chaine + i + 1, joker + jmp, size, size_flag))) {
|
if ((adr = strjoker(chaine + i + 1, joker + jmp, size, size_flag))) {
|
||||||
|
|||||||
@@ -41,11 +41,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
|
|
||||||
int fa_strjoker(int type, char **filters, int nfil, const char *nom, LLint * size,
|
int fa_strjoker(int type, char **filters, int nfil, const char *nom, LLint * size,
|
||||||
int *size_flag, int *depth);
|
int *size_flag, int *depth);
|
||||||
/* fa_strjoker() on both URL forms the engine builds (nom1 full, nom2 without
|
|
||||||
scheme); the match latest in the list wins, a "don't know" verdict defers.
|
|
||||||
Returns the merged verdict; the out-params carry the winner's values. */
|
|
||||||
int fa_strjoker_dual(int type, char **filters, int nfil, const char *nom1,
|
|
||||||
const char *nom2, LLint *size, int *size_flag, int *depth);
|
|
||||||
HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * size,
|
HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * size,
|
||||||
int *size_flag);
|
int *size_flag);
|
||||||
const char *strjokerfind(const char *chaine, const char *joker);
|
const char *strjokerfind(const char *chaine, const char *joker);
|
||||||
|
|||||||
185
src/htsftp.c
185
src/htsftp.c
@@ -54,9 +54,15 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ftp mode passif
|
// ftp mode passif
|
||||||
|
// #if HTS_INET6==0
|
||||||
#define FTP_PASV 1
|
#define FTP_PASV 1
|
||||||
|
// #else
|
||||||
|
// no passive mode for v6
|
||||||
|
// #define FTP_PASV 0
|
||||||
|
// #endif
|
||||||
|
|
||||||
#define FTP_DEBUG 0
|
#define FTP_DEBUG 0
|
||||||
|
//#define FORK_DEBUG 0
|
||||||
|
|
||||||
#if USE_BEGINTHREAD
|
#if USE_BEGINTHREAD
|
||||||
|
|
||||||
@@ -122,33 +128,6 @@ void launch_ftp(FTPDownloadStruct * params) {
|
|||||||
return 0; \
|
return 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bounded split of a hostile-URL "user[:pass]@" prefix (see htsftp.h). */
|
|
||||||
void ftp_split_userpass(const char *src, const char *end, char *user,
|
|
||||||
size_t user_size, char *pass, size_t pass_size) {
|
|
||||||
size_t n = 0;
|
|
||||||
|
|
||||||
assertf(user_size > 0 && pass_size > 0); /* the size-1 math underflows on 0 */
|
|
||||||
|
|
||||||
while (src[n] != '\0' && src[n] != ':') {
|
|
||||||
if (n < user_size - 1)
|
|
||||||
user[n] = src[n];
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
user[n < user_size ? n : user_size - 1] = '\0';
|
|
||||||
pass[0] = '\0';
|
|
||||||
if (src[n] == ':') { // password follows the colon
|
|
||||||
const size_t base = n + 1;
|
|
||||||
size_t k = 0;
|
|
||||||
|
|
||||||
while (&src[base + k + 1] < end && src[base + k] != '\0') {
|
|
||||||
if (k < pass_size - 1)
|
|
||||||
pass[k] = src[base + k];
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
pass[k < pass_size ? k : pass_size - 1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// la véritable fonction une fois lancées les routines thread/fork
|
// la véritable fonction une fois lancées les routines thread/fork
|
||||||
int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
||||||
lien_back *back = pStruct->pBack;
|
lien_back *back = pStruct->pBack;
|
||||||
@@ -194,14 +173,43 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
while(*real_adr == '/')
|
while(*real_adr == '/')
|
||||||
real_adr++; // sauter /
|
real_adr++; // sauter /
|
||||||
if ((adr = jump_identification(real_adr)) != real_adr) { // user
|
if ((adr = jump_identification(real_adr)) != real_adr) { // user
|
||||||
ftp_split_userpass(real_adr, adr, user, sizeof(user), pass, sizeof(pass));
|
int i = -1;
|
||||||
|
|
||||||
|
pass[0] = '\0';
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
user[i] = real_adr[i];
|
||||||
|
} while((real_adr[i] != ':') && (real_adr[i]));
|
||||||
|
user[i] = '\0';
|
||||||
|
if (real_adr[i] == ':') { // pass
|
||||||
|
int j = -1;
|
||||||
|
|
||||||
|
i++; // oui on saute aussi le :
|
||||||
|
do {
|
||||||
|
j++;
|
||||||
|
pass[j] = real_adr[i + j];
|
||||||
|
} while(((&real_adr[i + j + 1]) < adr) && (real_adr[i + j]));
|
||||||
|
pass[j] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Calculer RETR <nom>
|
// Calculer RETR <nom>
|
||||||
{
|
{
|
||||||
char *a;
|
char *a;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
a = back->url_fil + strlen(back->url_fil) - 1;
|
||||||
|
while((a > back->url_fil) && (*a != '/'))
|
||||||
|
a--;
|
||||||
|
if (*a != '/') {
|
||||||
|
a = NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
a = back->url_fil;
|
a = back->url_fil;
|
||||||
|
#endif
|
||||||
if (a != NULL && *a != '\0') {
|
if (a != NULL && *a != '\0') {
|
||||||
|
#if 0
|
||||||
|
a++; // sauter /
|
||||||
|
#endif
|
||||||
ftp_filename = a;
|
ftp_filename = a;
|
||||||
if (strnotempty(a)) {
|
if (strnotempty(a)) {
|
||||||
char catbuff[CATBUFF_SIZE];
|
char catbuff[CATBUFF_SIZE];
|
||||||
@@ -225,6 +233,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unexpected PORT error");
|
strcpybuff(back->r.msg, "Unexpected PORT error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,6 +267,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
if (hts_dns_resolve2(opt, _adr, &server, &error) == NULL) {
|
if (hts_dns_resolve2(opt, _adr, &server, &error) == NULL) {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg),
|
snprintf(back->r.msg, sizeof(back->r.msg),
|
||||||
"Unable to get server's address: %s", error);
|
"Unable to get server's address: %s", error);
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_NON_FATAL;
|
back->r.statuscode = STATUSCODE_NON_FATAL;
|
||||||
_HALT_FTP return 0;
|
_HALT_FTP return 0;
|
||||||
}
|
}
|
||||||
@@ -270,17 +280,20 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
soc_ctl = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
|
soc_ctl = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
|
||||||
if (soc_ctl == INVALID_SOCKET) {
|
if (soc_ctl == INVALID_SOCKET) {
|
||||||
strcpybuff(back->r.msg, "Unable to create a socket");
|
strcpybuff(back->r.msg, "Unable to create a socket");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
_HALT_FTP return 0;
|
_HALT_FTP return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCaddr_initport(server, port);
|
SOCaddr_initport(server, port);
|
||||||
|
// server.sin_port = htons((unsigned short int) port);
|
||||||
|
|
||||||
// connexion (bloquante, on est en thread)
|
// connexion (bloquante, on est en thread)
|
||||||
strcpybuff(back->info, "connect");
|
strcpybuff(back->info, "connect");
|
||||||
|
|
||||||
if (connect(soc_ctl, &SOCaddr_sockaddr(server), SOCaddr_size(server)) != 0) {
|
if (connect(soc_ctl, &SOCaddr_sockaddr(server), SOCaddr_size(server)) != 0) {
|
||||||
strcpybuff(back->r.msg, "Unable to connect to the server");
|
strcpybuff(back->r.msg, "Unable to connect to the server");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
_HALT_FTP return 0;
|
_HALT_FTP return 0;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -322,22 +335,64 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "TYPE I error");
|
strcpybuff(back->r.msg, "TYPE I error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
// --CWD--
|
||||||
|
char *a;
|
||||||
|
|
||||||
|
a = back->url_fil + strlen(back->url_fil) - 1;
|
||||||
|
while((a > back->url_fil) && (*a != '/'))
|
||||||
|
a--;
|
||||||
|
if (*a == '/') { // ok repéré
|
||||||
|
char BIGSTK target[1024];
|
||||||
|
|
||||||
|
target[0] = '\0';
|
||||||
|
strncatbuff(target, back->url_fil, (int) (a - back->url_fil));
|
||||||
|
if (strnotempty(target) == 0)
|
||||||
|
strcatbuff(target, "/");
|
||||||
|
strcpybuff(back->info, "cwd");
|
||||||
|
snprintf(line, sizeof(line), "CWD %s", target);
|
||||||
|
send_line(soc_ctl, line);
|
||||||
|
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
||||||
|
_CHECK_HALT_FTP;
|
||||||
|
if (line[0] == '2') {
|
||||||
|
send_line(soc_ctl, "TYPE I");
|
||||||
|
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
||||||
|
_CHECK_HALT_FTP;
|
||||||
|
if (line[0] == '2') {
|
||||||
|
// ok..
|
||||||
|
} else {
|
||||||
|
strcpybuff(back->r.msg, "TYPE I error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snprintf(back->r.msg, sizeof(back->r.msg), "CWD error: %s", linejmp(line));
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
|
} // sinon on est prêts
|
||||||
|
} else {
|
||||||
|
strcpybuff(back->r.msg, "Unexpected ftp error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Bad password: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "Bad password: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Bad user name: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "Bad user name: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Connection refused: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "Connection refused: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,8 +459,8 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
// -- fin analyse de l'adresse IP et du port --
|
// -- fin analyse de l'adresse IP et du port --
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
@@ -436,13 +491,13 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "EPSV incorrect: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "EPSV incorrect: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PASV/EPSV error: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "PASV/EPSV error: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
}
|
}
|
||||||
@@ -548,8 +603,9 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
deletesoc(soc_dat);
|
deletesoc(soc_dat);
|
||||||
soc_dat = INVALID_SOCKET;
|
soc_dat = INVALID_SOCKET;
|
||||||
//
|
//
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg),
|
snprintf(back->r.msg, sizeof(back->r.msg), "RETR command error: %s",
|
||||||
"RETR command error: %s", linejmp(line));
|
linejmp(line));
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
@@ -560,20 +616,23 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
soc_dat = INVALID_SOCKET;
|
soc_dat = INVALID_SOCKET;
|
||||||
//
|
//
|
||||||
strcpybuff(back->r.msg, "Unable to connect");
|
strcpybuff(back->r.msg, "Unable to connect");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unable to create a socket");
|
strcpybuff(back->r.msg, "Unable to create a socket");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg),
|
snprintf(back->r.msg, sizeof(back->r.msg),
|
||||||
"Unable to resolve IP %s: %s", adr_ip, error);
|
"Unable to resolve IP %s: %s", adr_ip, error);
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
} // sinon on est prêts
|
} // sinon on est prêts
|
||||||
#else
|
#else
|
||||||
@@ -594,16 +653,17 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
//T_SOC soc_dat;
|
//T_SOC soc_dat;
|
||||||
if ((soc_dat = accept(soc_servdat, NULL, NULL)) == INVALID_SOCKET) {
|
if ((soc_dat = accept(soc_servdat, NULL, NULL)) == INVALID_SOCKET) {
|
||||||
strcpybuff(back->r.msg, "Unable to accept connection");
|
strcpybuff(back->r.msg, "Unable to accept connection");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg),
|
snprintf(back->r.msg, sizeof(back->r.msg), "RETR command error: %s", linejmp(line));
|
||||||
"RETR command error: %s", linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "PORT command error: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "PORT command error: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -613,6 +673,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unable to listen to a port");
|
strcpybuff(back->r.msg, "Unable to listen to a port");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -636,18 +697,21 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
int len = 1;
|
int len = 1;
|
||||||
int read_len = 1024;
|
int read_len = 1024;
|
||||||
|
|
||||||
|
//HTS_TOTAL_RECV_CHECK(read_len); // Diminuer au besoin si trop de données reçues
|
||||||
|
|
||||||
while((len > 0) && (!stop_ftp(back))) {
|
while((len > 0) && (!stop_ftp(back))) {
|
||||||
// attendre les données
|
// attendre les données
|
||||||
len = 1; // pas d'erreur pour le moment
|
len = 1; // pas d'erreur pour le moment
|
||||||
switch (wait_socket_receive(soc_dat, timeout)) {
|
switch (wait_socket_receive(soc_dat, timeout)) {
|
||||||
case -1:
|
case -1:
|
||||||
strcpybuff(back->r.msg, "FTP read error");
|
strcpybuff(back->r.msg, "FTP read error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
len = 0; // fin
|
len = 0; // fin
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "Time out (%d)",
|
snprintf(back->r.msg, sizeof(back->r.msg), "Time out (%d)", timeout);
|
||||||
timeout);
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
len = 0; // fin
|
len = 0; // fin
|
||||||
break;
|
break;
|
||||||
@@ -669,14 +733,17 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
strcpybuff(back->r.msg, "Write error");
|
strcpybuff(back->r.msg, "Write error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
len = 0; // error
|
len = 0; // error
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unexpected write error");
|
strcpybuff(back->r.msg, "Unexpected write error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else { // Erreur ou terminé
|
} else { // Erreur ou terminé
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = 0;
|
back->r.statuscode = 0;
|
||||||
if (back->r.totalsize > 0
|
if (back->r.totalsize > 0
|
||||||
&& back->r.size != back->r.totalsize) {
|
&& back->r.size != back->r.totalsize) {
|
||||||
@@ -685,6 +752,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_len = 1024;
|
read_len = 1024;
|
||||||
|
//HTS_TOTAL_RECV_CHECK(read_len); // Diminuer au besoin si trop de données reçues
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (back->r.fp) {
|
if (back->r.fp) {
|
||||||
@@ -693,6 +761,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "Unable to write file");
|
strcpybuff(back->r.msg, "Unable to write file");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -708,14 +777,16 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
|
||||||
if (line[0] == '2') { // OK
|
if (line[0] == '2') { // OK
|
||||||
strcpybuff(back->r.msg, "OK");
|
strcpybuff(back->r.msg, "OK");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = HTTP_OK;
|
back->r.statuscode = HTTP_OK;
|
||||||
} else {
|
} else {
|
||||||
snprintf(back->r.msg, sizeof(back->r.msg), "RETR incorrect: %s",
|
snprintf(back->r.msg, sizeof(back->r.msg), "RETR incorrect: %s", linejmp(line));
|
||||||
linejmp(line));
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpybuff(back->r.msg, "FTP read error");
|
strcpybuff(back->r.msg, "FTP read error");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -741,6 +812,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
|||||||
back->r.statuscode = HTTP_OK;
|
back->r.statuscode = HTTP_OK;
|
||||||
strcpybuff(back->r.msg, "OK");
|
strcpybuff(back->r.msg, "OK");
|
||||||
}
|
}
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,11 +979,13 @@ int get_ftp_line(T_SOC soc, char *ptrline, size_t line_size, int timeout) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//HTS_TOTAL_RECV_CHECK(dummy); // Diminuer au besoin si trop de données reçues
|
||||||
switch (recv(soc, &b, 1, 0)) {
|
switch (recv(soc, &b, 1, 0)) {
|
||||||
|
//case 0: break; // pas encore --> erreur (on attend)!
|
||||||
case 1:
|
case 1:
|
||||||
HTS_STAT.HTS_TOTAL_RECV += 1; // compter flux entrant
|
HTS_STAT.HTS_TOTAL_RECV += 1; // compter flux entrant
|
||||||
if ((b != 10) && (b != 13) && (i < (int) sizeof(data) - 1))
|
if ((b != 10) && (b != 13))
|
||||||
data[i++] = b; // truncate hostile over-long reply lines
|
data[i++] = b;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (ptrline)
|
if (ptrline)
|
||||||
@@ -1034,6 +1108,7 @@ int wait_socket_receive(T_SOC soc, int timeout) {
|
|||||||
int stop_ftp(lien_back * back) {
|
int stop_ftp(lien_back * back) {
|
||||||
if (back->stop_ftp) {
|
if (back->stop_ftp) {
|
||||||
strcpybuff(back->r.msg, "Cancelled by User");
|
strcpybuff(back->r.msg, "Cancelled by User");
|
||||||
|
// back->status=STATUS_FTP_READY; // fini
|
||||||
back->r.statuscode = STATUSCODE_INVALID;
|
back->r.statuscode = STATUSCODE_INVALID;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ int back_launch_ftp(FTPDownloadStruct * params);
|
|||||||
int run_launch_ftp(FTPDownloadStruct * params);
|
int run_launch_ftp(FTPDownloadStruct * params);
|
||||||
int send_line(T_SOC soc, const char *data);
|
int send_line(T_SOC soc, const char *data);
|
||||||
int get_ftp_line(T_SOC soc, char *line, size_t line_size, int timeout);
|
int get_ftp_line(T_SOC soc, char *line, size_t line_size, int timeout);
|
||||||
/* Split a "user[:pass]@" prefix (end = jump_identification result) into
|
|
||||||
bounded, NUL-terminated user/pass buffers, truncating to fit.
|
|
||||||
Both sizes must be nonzero. */
|
|
||||||
void ftp_split_userpass(const char *src, const char *end, char *user,
|
|
||||||
size_t user_size, char *pass, size_t pass_size);
|
|
||||||
T_SOC get_datasocket(char *to_send, size_t to_send_size);
|
T_SOC get_datasocket(char *to_send, size_t to_send_size);
|
||||||
int stop_ftp(lien_back * back);
|
int stop_ftp(lien_back * back);
|
||||||
char *linejmp(char *line);
|
char *linejmp(char *line);
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ Please visit our Website: http://www.httrack.com
|
|||||||
configure.ac, decoupled from these). VERSION is the display form, VERSIONID
|
configure.ac, decoupled from these). VERSION is the display form, VERSIONID
|
||||||
the dotted numeric form, AFF_VERSION the short form shown in footers,
|
the dotted numeric form, AFF_VERSION the short form shown in footers,
|
||||||
LIB_VERSION the data/cache format generation. */
|
LIB_VERSION the data/cache format generation. */
|
||||||
#define HTTRACK_VERSION "3.49-11"
|
#define HTTRACK_VERSION "3.49-9"
|
||||||
#define HTTRACK_VERSIONID "3.49.11"
|
#define HTTRACK_VERSIONID "3.49.9"
|
||||||
#define HTTRACK_AFF_VERSION "3.x"
|
#define HTTRACK_AFF_VERSION "3.x"
|
||||||
#define HTTRACK_LIB_VERSION "2.0"
|
#define HTTRACK_LIB_VERSION "2.0"
|
||||||
|
|
||||||
@@ -229,10 +229,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#define HTS_DEFAULT_FOOTER \
|
#define HTS_DEFAULT_FOOTER \
|
||||||
"<!-- Mirrored from %s%s by HTTrack Website Copier/" HTTRACK_AFF_VERSION \
|
"<!-- Mirrored from %s%s by HTTrack Website Copier/" HTTRACK_AFF_VERSION \
|
||||||
" " HTTRACK_AFF_AUTHORS ", %s -->"
|
" " HTTRACK_AFF_AUTHORS ", %s -->"
|
||||||
/* Honest crawler User-Agent; no fake OS/browser to go stale. */
|
|
||||||
#define HTS_DEFAULT_USER_AGENT \
|
|
||||||
"Mozilla/5.0 (compatible; HTTrack/" HTTRACK_AFF_VERSION \
|
|
||||||
"; +https://www.httrack.com/)"
|
|
||||||
#define HTTRACK_WEB "http://www.httrack.com"
|
#define HTTRACK_WEB "http://www.httrack.com"
|
||||||
#define HTS_UPDATE_WEBSITE \
|
#define HTS_UPDATE_WEBSITE \
|
||||||
"http://www.httrack.com/" \
|
"http://www.httrack.com/" \
|
||||||
@@ -422,10 +418,9 @@ typedef int T_SOC;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Permission bits for created folders and files (mkdir and chmod).
|
/* Permission bits for created folders and files (mkdir and chmod).
|
||||||
PROTECT_FOLDER/FILE are owner-only. With HTS_ACCESS set (the default) the
|
PROTECT_FOLDER is owner-only. With HTS_ACCESS set (the default) the ACCESS_
|
||||||
ACCESS_ modes also grant group/other read; otherwise they stay owner-only. */
|
modes also grant group/other read; otherwise they stay owner-only. */
|
||||||
#define HTS_PROTECT_FOLDER (S_IRUSR | S_IWUSR | S_IXUSR)
|
#define HTS_PROTECT_FOLDER (S_IRUSR | S_IWUSR | S_IXUSR)
|
||||||
#define HTS_PROTECT_FILE (S_IRUSR | S_IWUSR)
|
|
||||||
|
|
||||||
#if HTS_ACCESS
|
#if HTS_ACCESS
|
||||||
#define HTS_ACCESS_FILE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
|
#define HTS_ACCESS_FILE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
|
||||||
|
|||||||
@@ -152,6 +152,16 @@ void help_wizard(httrackp * opt) {
|
|||||||
#define str (buffers->str)
|
#define str (buffers->str)
|
||||||
#define argv (buffers->argv)
|
#define argv (buffers->argv)
|
||||||
|
|
||||||
|
//char *urls = (char *) malloct(HTS_URLMAXSIZE * 2);
|
||||||
|
//char *mainpath = (char *) malloct(256);
|
||||||
|
//char *projname = (char *) malloct(256);
|
||||||
|
//char *stropt = (char *) malloct(2048); // options
|
||||||
|
//char *stropt2 = (char *) malloct(2048); // options longues
|
||||||
|
//char *strwild = (char *) malloct(2048); // wildcards
|
||||||
|
//char *cmd = (char *) malloct(4096);
|
||||||
|
//char *str = (char *) malloct(256);
|
||||||
|
//char **argv = (char **) malloct(256 * sizeof(char *));
|
||||||
|
|
||||||
//
|
//
|
||||||
char *a;
|
char *a;
|
||||||
|
|
||||||
@@ -217,6 +227,8 @@ void help_wizard(httrackp * opt) {
|
|||||||
strcatbuff(stropt2, str);
|
strcatbuff(stropt2, str);
|
||||||
strcatbuff(stropt2, projname);
|
strcatbuff(stropt2, projname);
|
||||||
strcatbuff(stropt2, "\" ");
|
strcatbuff(stropt2, "\" ");
|
||||||
|
// Créer si ce n'est fait un index.html 1er niveau
|
||||||
|
make_empty_index(str);
|
||||||
//
|
//
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Enter URLs (separated by commas or blank spaces) :");
|
printf("Enter URLs (separated by commas or blank spaces) :");
|
||||||
@@ -337,6 +349,8 @@ void help_wizard(httrackp * opt) {
|
|||||||
}
|
}
|
||||||
hts_main(argc, argv);
|
hts_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
//} else {
|
||||||
|
// help("httrack",1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free buffers */
|
/* Free buffers */
|
||||||
@@ -441,6 +455,23 @@ void help_catchurl(const char *dest_path) {
|
|||||||
printf("Unable to create a temporary proxy (no remaining port)\n");
|
printf("Unable to create a temporary proxy (no remaining port)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Créer un index.html vide
|
||||||
|
void make_empty_index(const char *str) {
|
||||||
|
#if 0
|
||||||
|
if (!fexist(fconcat(str, "index.html"))) {
|
||||||
|
FILE *fp = fopen(fconcat(str, "index.html"), "wb");
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
fprintf(fp, "<!-- " HTS_TOPINDEX " -->" CRLF);
|
||||||
|
fprintf(fp,
|
||||||
|
"<HTML><BODY>Index is empty!<BR>(File used to index all HTTrack projects)</BODY></HTML>"
|
||||||
|
CRLF);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// mini-aide (h: help)
|
// mini-aide (h: help)
|
||||||
// y
|
// y
|
||||||
void help(const char *app, int more) {
|
void help(const char *app, int more) {
|
||||||
@@ -490,7 +521,6 @@ void help(const char *app, int more) {
|
|||||||
infomsg(" EN maximum mirror time in seconds (60=1 minute, 3600=1 hour)");
|
infomsg(" EN maximum mirror time in seconds (60=1 minute, 3600=1 hour)");
|
||||||
infomsg(" AN maximum transfer rate in bytes/seconds (1000=1KB/s max)");
|
infomsg(" AN maximum transfer rate in bytes/seconds (1000=1KB/s max)");
|
||||||
infomsg(" %cN maximum number of connections/seconds (*%c10)");
|
infomsg(" %cN maximum number of connections/seconds (*%c10)");
|
||||||
infomsg(" %G random pause of MIN[:MAX] seconds between files (e.g. %G5:10)");
|
|
||||||
infomsg
|
infomsg
|
||||||
(" GN pause transfer if N bytes reached, and wait until lock file is deleted");
|
(" GN pause transfer if N bytes reached, and wait until lock file is deleted");
|
||||||
infomsg("");
|
infomsg("");
|
||||||
@@ -542,8 +572,6 @@ void help(const char *app, int more) {
|
|||||||
infomsg("");
|
infomsg("");
|
||||||
infomsg("Spider options:");
|
infomsg("Spider options:");
|
||||||
infomsg(" bN accept cookies in cookies.txt (0=do not accept,* 1=accept)");
|
infomsg(" bN accept cookies in cookies.txt (0=do not accept,* 1=accept)");
|
||||||
infomsg(" %K load extra cookies from a Netscape cookies.txt");
|
|
||||||
infomsg(" %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
|
||||||
@@ -778,4 +806,7 @@ void help(const char *app, int more) {
|
|||||||
infomsg("[compiled: " HTS_PLATFORM_NAME "]");
|
infomsg("[compiled: " HTS_PLATFORM_NAME "]");
|
||||||
#endif
|
#endif
|
||||||
infomsg(NULL);
|
infomsg(NULL);
|
||||||
|
|
||||||
|
// infomsg(" R *relative links (e.g ../link)\n");
|
||||||
|
// infomsg(" A absolute links (e.g /www.adr/link)\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ typedef struct httrackp httrackp;
|
|||||||
|
|
||||||
void infomsg(const char *msg);
|
void infomsg(const char *msg);
|
||||||
void help(const char *app, int more);
|
void help(const char *app, int more);
|
||||||
|
void make_empty_index(const char *str);
|
||||||
void help_wizard(httrackp * opt);
|
void help_wizard(httrackp * opt);
|
||||||
int help_query(const char *list, int def);
|
int help_query(const char *list, int def);
|
||||||
void help_catchurl(const char *dest_path);
|
void help_catchurl(const char *dest_path);
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
char keyword[KEYW_LEN + 32];
|
char keyword[KEYW_LEN + 32];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
//int WordIndexSize = 1024;
|
||||||
coucal WordIndexHash = NULL;
|
coucal WordIndexHash = NULL;
|
||||||
FILE *tmpfp = NULL;
|
FILE *tmpfp = NULL;
|
||||||
|
|
||||||
@@ -176,6 +178,8 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
|| (strfield2(mime, "text/css"))
|
|| (strfield2(mime, "text/css"))
|
||||||
) {
|
) {
|
||||||
inscript = 1;
|
inscript = 1;
|
||||||
|
//} else if (strfield2(mime, "text/vnd.wap.wml")) { // humm won't work in many cases
|
||||||
|
// inscript=0;
|
||||||
} else
|
} else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -271,6 +275,8 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
|
|
||||||
// Process indexing for this page
|
// Process indexing for this page
|
||||||
{
|
{
|
||||||
|
//FILE* fp=NULL;
|
||||||
|
//fp=fopen(concat(indexpath,"index.txt"),"ab");
|
||||||
if (fp_tmpproject) {
|
if (fp_tmpproject) {
|
||||||
while(!feof(tmpfp)) {
|
while(!feof(tmpfp)) {
|
||||||
char line[KEYW_LEN + 32];
|
char line[KEYW_LEN + 32];
|
||||||
@@ -280,6 +286,7 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
intptr_t e = 0;
|
intptr_t e = 0;
|
||||||
|
|
||||||
if (coucal_read(WordIndexHash, line, &e)) {
|
if (coucal_read(WordIndexHash, line, &e)) {
|
||||||
|
//if (e) {
|
||||||
char BIGSTK savelst[HTS_URLMAXSIZE * 2];
|
char BIGSTK savelst[HTS_URLMAXSIZE * 2];
|
||||||
|
|
||||||
e++; /* 0 means "once" */
|
e++; /* 0 means "once" */
|
||||||
@@ -293,9 +300,11 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|
|||||||
fprintf(fp_tmpproject, "%s %d %s\n", line,
|
fprintf(fp_tmpproject, "%s %d %s\n", line,
|
||||||
(int) (KEYW_SORT_MAXCOUNT - e), savelst);
|
(int) (KEYW_SORT_MAXCOUNT - e), savelst);
|
||||||
hts_primindex_size++;
|
hts_primindex_size++;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +330,7 @@ void index_finish(const char *indexpath, int mode) {
|
|||||||
off_t size = fpsize(fp_tmpproject);
|
off_t size = fpsize(fp_tmpproject);
|
||||||
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
|
//FILE* fp=fopen(concat(indexpath,"index.txt"),"rb");
|
||||||
if (fp_tmpproject) {
|
if (fp_tmpproject) {
|
||||||
tab = (char **) malloct(sizeof(char *) * (hts_primindex_size + 2));
|
tab = (char **) malloct(sizeof(char *) * (hts_primindex_size + 2));
|
||||||
if (tab) {
|
if (tab) {
|
||||||
@@ -388,6 +398,8 @@ void index_finish(const char *indexpath, int mode) {
|
|||||||
if (total_hit) {
|
if (total_hit) {
|
||||||
if (mode == 1) // TEXT
|
if (mode == 1) // TEXT
|
||||||
fprintf(fp, "\t=%d\r\n", total_hit);
|
fprintf(fp, "\t=%d\r\n", total_hit);
|
||||||
|
//else // HTML
|
||||||
|
// fprintf(fp,"<br>(%d total hits)\r\n",total_hit);
|
||||||
if ((((total_hit * 1000) / hts_primindex_words) >=
|
if ((((total_hit * 1000) / hts_primindex_words) >=
|
||||||
KEYW_USELESS1K)
|
KEYW_USELESS1K)
|
||||||
|| (((total_line * 1000) / index) >=
|
|| (((total_line * 1000) / index) >=
|
||||||
@@ -404,6 +416,8 @@ void index_finish(const char *indexpath, int mode) {
|
|||||||
if (mode == 1) // TEXT
|
if (mode == 1) // TEXT
|
||||||
fprintf(fp, "\t(%d)\r\n",
|
fprintf(fp, "\t(%d)\r\n",
|
||||||
((total_hit * 1000) / hts_primindex_words));
|
((total_hit * 1000) / hts_primindex_words));
|
||||||
|
//else // HTML
|
||||||
|
// fprintf(fp,"(%d)\r\n",((total_hit*1000)/hts_primindex_words));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mode == 1) // TEXT
|
if (mode == 1) // TEXT
|
||||||
|
|||||||
@@ -63,9 +63,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
/* This file */
|
/* This file */
|
||||||
#include "htsjava.h"
|
#include "htsjava.h"
|
||||||
|
|
||||||
/* calloct/freet wrappers */
|
|
||||||
#include "htssafe.h"
|
|
||||||
|
|
||||||
static int reverse_endian(void) {
|
static int reverse_endian(void) {
|
||||||
int endian = 1;
|
int endian = 1;
|
||||||
|
|
||||||
@@ -175,14 +172,15 @@ static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
|
|||||||
#if JAVADEBUG
|
#if JAVADEBUG
|
||||||
printf("fopen\n");
|
printf("fopen\n");
|
||||||
#endif
|
#endif
|
||||||
if ((fpout = FOPEN(fconv(catbuff, sizeof(catbuff), file), "r+b")) ==
|
if ((fpout = FOPEN(fconv(catbuff, sizeof(catbuff), file), "r+b")) == NULL) {
|
||||||
NULL) {
|
//fprintf(stderr, "Cannot open input file.\n");
|
||||||
sprintf(str->err_msg, "Unable to open file %s", file);
|
sprintf(str->err_msg, "Unable to open file %s", file);
|
||||||
return 0; // une erreur..
|
return 0; // une erreur..
|
||||||
}
|
}
|
||||||
#if JAVADEBUG
|
#if JAVADEBUG
|
||||||
printf("fread\n");
|
printf("fread\n");
|
||||||
#endif
|
#endif
|
||||||
|
//if (fread(&header,1,sizeof(JAVA_HEADER),fpout) != sizeof(JAVA_HEADER)) { // pas complet..
|
||||||
if (fread(&header, 1, 10, fpout) != 10) { // pas complet..
|
if (fread(&header, 1, 10, fpout) != 10) { // pas complet..
|
||||||
fclose(fpout);
|
fclose(fpout);
|
||||||
sprintf(str->err_msg, "File header too small (file len = " LLintP ")",
|
sprintf(str->err_msg, "File header too small (file len = " LLintP ")",
|
||||||
@@ -206,16 +204,7 @@ static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A constant-pool entry is >= 1 byte on disk; reject a count exceeding
|
tab = (RESP_STRUCT *) calloc(header.count, sizeof(RESP_STRUCT));
|
||||||
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) {
|
if (!tab) {
|
||||||
sprintf(str->err_msg, "Unable to alloc %d bytes",
|
sprintf(str->err_msg, "Unable to alloc %d bytes",
|
||||||
(int) sizeof(RESP_STRUCT));
|
(int) sizeof(RESP_STRUCT));
|
||||||
@@ -241,7 +230,7 @@ static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
|
|||||||
} else { // ++ une erreur est survenue!
|
} else { // ++ une erreur est survenue!
|
||||||
if (strnotempty(str->err_msg) == 0)
|
if (strnotempty(str->err_msg) == 0)
|
||||||
strcpy(str->err_msg, "Internal readtable error");
|
strcpy(str->err_msg, "Internal readtable error");
|
||||||
freet(tab);
|
free(tab);
|
||||||
if (fpout) {
|
if (fpout) {
|
||||||
fclose(fpout);
|
fclose(fpout);
|
||||||
fpout = NULL;
|
fpout = NULL;
|
||||||
@@ -256,10 +245,12 @@ static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
|
|||||||
printf("addfiles\n");
|
printf("addfiles\n");
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
//unsigned int acess;
|
||||||
unsigned int Class;
|
unsigned int Class;
|
||||||
unsigned int SClass;
|
unsigned int SClass;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
//acess = readshort(fpout);
|
||||||
Class = readshort(fpout);
|
Class = readshort(fpout);
|
||||||
SClass = readshort(fpout);
|
SClass = readshort(fpout);
|
||||||
|
|
||||||
@@ -297,7 +288,7 @@ static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
|
|||||||
#if JAVADEBUG
|
#if JAVADEBUG
|
||||||
printf("end\n");
|
printf("end\n");
|
||||||
#endif
|
#endif
|
||||||
freet(tab);
|
free(tab);
|
||||||
if (fpout) {
|
if (fpout) {
|
||||||
fclose(fpout);
|
fclose(fpout);
|
||||||
fpout = NULL;
|
fpout = NULL;
|
||||||
@@ -404,9 +395,11 @@ static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp,
|
|||||||
|
|
||||||
p = &buffer[0];
|
p = &buffer[0];
|
||||||
|
|
||||||
|
//fflush(fp);
|
||||||
trans.file_position = ftell(fp);
|
trans.file_position = ftell(fp);
|
||||||
length = readshort(fp);
|
length = readshort(fp);
|
||||||
if (length < HTS_URLMAXSIZE) {
|
if (length < HTS_URLMAXSIZE) {
|
||||||
|
// while ((length > 0) && (length<500)) {
|
||||||
while(length > 0) {
|
while(length > 0) {
|
||||||
*p++ = fgetc(fp);
|
*p++ = fgetc(fp);
|
||||||
|
|
||||||
@@ -414,13 +407,17 @@ static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp,
|
|||||||
}
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
|
//#if JDEBUG
|
||||||
|
// if(tris(buffer)==1) printf("%s\n ",buffer);
|
||||||
|
// if(tris(buffer)==2) printf("%s\n ",printname(buffer));
|
||||||
|
//#endif
|
||||||
if (tris(str->opt, buffer) == 1)
|
if (tris(str->opt, buffer) == 1)
|
||||||
str->addLink(str, buffer); /* trans.file_position */
|
str->addLink(str, buffer); /* trans.file_position */
|
||||||
else if (tris(str->opt, buffer) == 2)
|
else if (tris(str->opt, buffer) == 2)
|
||||||
str->addLink(str, printname(rname, buffer));
|
str->addLink(str, printname(rname, buffer));
|
||||||
|
|
||||||
strcpy(trans.name, buffer);
|
strcpy(trans.name, buffer);
|
||||||
} else { // gros pb
|
} else { // gros pb
|
||||||
while((length > 0) && (!feof(fp))) {
|
while((length > 0) && (!feof(fp))) {
|
||||||
fgetc(fp);
|
fgetc(fp);
|
||||||
length--;
|
length--;
|
||||||
@@ -436,6 +433,7 @@ static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
// printf("Type inconnue\n");
|
||||||
// on arrête tout
|
// on arrête tout
|
||||||
sprintf(str->err_msg, "Internal structure unknown (type %d)", trans.type);
|
sprintf(str->err_msg, "Internal structure unknown (type %d)", trans.type);
|
||||||
*error = 1;
|
*error = 1;
|
||||||
@@ -498,6 +496,7 @@ static char *printname(char rname[1024], char name[1024]) {
|
|||||||
return rname; // ""
|
return rname; // ""
|
||||||
}
|
}
|
||||||
p += 2;
|
p += 2;
|
||||||
|
//rname=(char*)calloct(strlen(name)+8,sizeof(char));
|
||||||
p1 = rname;
|
p1 = rname;
|
||||||
for(j = 0; name[j] != '\0'; j++, p++) {
|
for(j = 0; name[j] != '\0'; j++, p++) {
|
||||||
if (*p == '/')
|
if (*p == '/')
|
||||||
|
|||||||
@@ -33,19 +33,15 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#ifndef HTSJAVA_DEFH
|
#ifndef HTSJAVA_DEFH
|
||||||
#define HTSJAVA_DEFH
|
#define HTSJAVA_DEFH
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifndef HTS_DEF_FWSTRUCT_JAVA_HEADER
|
#ifndef HTS_DEF_FWSTRUCT_JAVA_HEADER
|
||||||
#define HTS_DEF_FWSTRUCT_JAVA_HEADER
|
#define HTS_DEF_FWSTRUCT_JAVA_HEADER
|
||||||
typedef struct JAVA_HEADER JAVA_HEADER;
|
typedef struct JAVA_HEADER JAVA_HEADER;
|
||||||
#endif
|
#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 {
|
struct JAVA_HEADER {
|
||||||
uint32_t magic;
|
unsigned long int magic;
|
||||||
uint16_t minor;
|
unsigned short int minor;
|
||||||
uint16_t major;
|
unsigned short int major;
|
||||||
uint16_t count;
|
unsigned short int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef HTS_DEF_FWSTRUCT_RESP_STRUCT
|
#ifndef HTS_DEF_FWSTRUCT_RESP_STRUCT
|
||||||
|
|||||||
367
src/htslib.c
367
src/htslib.c
@@ -563,62 +563,58 @@ const char *hts_mime[][2] = {
|
|||||||
{"", ""}
|
{"", ""}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Modern web formats (post-2010), kept in their own table: appending to the
|
|
||||||
legacy hts_mime[] above makes clang-format reflow its whole initializer.
|
|
||||||
Scanned after hts_mime[], so it never shadows a legacy mapping. */
|
|
||||||
static const char *hts_mime_modern[][2] = {
|
|
||||||
{"image/webp", "webp"},
|
|
||||||
{"image/avif", "avif"},
|
|
||||||
{"image/heic", "heic"},
|
|
||||||
{"font/woff", "woff"},
|
|
||||||
{"font/woff2", "woff2"},
|
|
||||||
{"font/ttf", "ttf"},
|
|
||||||
{"font/otf", "otf"},
|
|
||||||
{"application/json", "json"},
|
|
||||||
{"application/ld+json", "jsonld"},
|
|
||||||
{"application/manifest+json", "webmanifest"},
|
|
||||||
{"application/wasm", "wasm"},
|
|
||||||
{"text/javascript", "js"},
|
|
||||||
{"text/javascript", "mjs"},
|
|
||||||
{"text/markdown", "md"},
|
|
||||||
{"video/mp4", "mp4"},
|
|
||||||
{"video/webm", "webm"},
|
|
||||||
{"video/ogg", "ogv"},
|
|
||||||
{"video/mp2t", "ts"},
|
|
||||||
{"audio/mp4", "m4a"},
|
|
||||||
{"audio/aac", "aac"},
|
|
||||||
{"audio/ogg", "oga"},
|
|
||||||
{"audio/opus", "opus"},
|
|
||||||
{"audio/flac", "flac"},
|
|
||||||
{"audio/webm", "weba"},
|
|
||||||
{"application/x-7z-compressed", "7z"},
|
|
||||||
{"application/x-rar-compressed", "rar"},
|
|
||||||
{"application/zstd", "zst"},
|
|
||||||
{"", ""}};
|
|
||||||
|
|
||||||
// Reserved (RFC2396)
|
// Reserved (RFC2396)
|
||||||
#define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
|
#define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
|
||||||
#define CHAR_RESERVED(c) \
|
#define CHAR_RESERVED(c) ( CIS(c,';') \
|
||||||
(CIS(c, ';') || CIS(c, '/') || CIS(c, '?') || CIS(c, ':') || CIS(c, '@') || \
|
|| CIS(c,'/') \
|
||||||
CIS(c, '&') || CIS(c, '=') || CIS(c, '+') || CIS(c, '$') || CIS(c, ','))
|
|| CIS(c,'?') \
|
||||||
|
|| CIS(c,':') \
|
||||||
|
|| CIS(c,'@') \
|
||||||
|
|| CIS(c,'&') \
|
||||||
|
|| CIS(c,'=') \
|
||||||
|
|| CIS(c,'+') \
|
||||||
|
|| CIS(c,'$') \
|
||||||
|
|| CIS(c,',') )
|
||||||
|
//#define CHAR_RESERVED(c) ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
|
||||||
// Delimiters (RFC2396)
|
// Delimiters (RFC2396)
|
||||||
#define CHAR_DELIM(c) \
|
#define CHAR_DELIM(c) ( CIS(c,'<') \
|
||||||
(CIS(c, '<') || CIS(c, '>') || CIS(c, '#') || CIS(c, '%') || CIS(c, '\"'))
|
|| CIS(c,'>') \
|
||||||
|
|| CIS(c,'#') \
|
||||||
|
|| CIS(c,'%') \
|
||||||
|
|| CIS(c,'\"') )
|
||||||
|
//#define CHAR_DELIM(c) ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
|
||||||
// Unwise (RFC2396)
|
// Unwise (RFC2396)
|
||||||
#define CHAR_UNWISE(c) \
|
#define CHAR_UNWISE(c) ( CIS(c,'{') \
|
||||||
(CIS(c, '{') || CIS(c, '}') || CIS(c, '|') || CIS(c, '\\') || CIS(c, '^') || \
|
|| CIS(c,'}') \
|
||||||
CIS(c, '[') || CIS(c, ']') || CIS(c, '`'))
|
|| CIS(c,'|') \
|
||||||
|
|| CIS(c,'\\') \
|
||||||
|
|| CIS(c,'^') \
|
||||||
|
|| CIS(c,'[') \
|
||||||
|
|| CIS(c,']') \
|
||||||
|
|| CIS(c,'`') )
|
||||||
|
//#define CHAR_UNWISE(c) ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
|
||||||
// Special (escape chars) (RFC2396 + >127 )
|
// Special (escape chars) (RFC2396 + >127 )
|
||||||
#define CHAR_LOW(c) ( ((unsigned char)(c) <= 31) )
|
#define CHAR_LOW(c) ( ((unsigned char)(c) <= 31) )
|
||||||
#define CHAR_HIG(c) ( ((unsigned char)(c) >= 127) )
|
#define CHAR_HIG(c) ( ((unsigned char)(c) >= 127) )
|
||||||
#define CHAR_SPECIAL(c) ( CHAR_LOW(c) || CHAR_HIG(c) )
|
#define CHAR_SPECIAL(c) ( CHAR_LOW(c) || CHAR_HIG(c) )
|
||||||
// We try to avoid them and encode them instead
|
// We try to avoid them and encode them instead
|
||||||
#define CHAR_XXAVOID(c) \
|
#define CHAR_XXAVOID(c) ( CIS(c,' ') \
|
||||||
(CIS(c, ' ') || CIS(c, '*') || CIS(c, '\'') || CIS(c, '\"') || \
|
|| CIS(c,'*') \
|
||||||
CIS(c, '&') || CIS(c, '!'))
|
|| CIS(c,'\'') \
|
||||||
#define CHAR_MARK(c) \
|
|| CIS(c,'\"') \
|
||||||
(CIS(c, '-') || CIS(c, '_') || CIS(c, '.') || CIS(c, '!') || CIS(c, '~') || \
|
|| CIS(c,'&') \
|
||||||
CIS(c, '*') || CIS(c, '\'') || CIS(c, '(') || CIS(c, ')'))
|
|| CIS(c,'!') )
|
||||||
|
//#define CHAR_XXAVOID(c) ( strchr(" *'\"!",(unsigned char)(c)) != 0 )
|
||||||
|
#define CHAR_MARK(c) ( CIS(c,'-') \
|
||||||
|
|| CIS(c,'_') \
|
||||||
|
|| CIS(c,'.') \
|
||||||
|
|| CIS(c,'!') \
|
||||||
|
|| CIS(c,'~') \
|
||||||
|
|| CIS(c,'*') \
|
||||||
|
|| CIS(c,'\'') \
|
||||||
|
|| CIS(c,'(') \
|
||||||
|
|| CIS(c,')') )
|
||||||
|
//#define CHAR_MARK(c) ( strchr("-_.!~*'()",(unsigned char)(c)) != 0 )
|
||||||
|
|
||||||
// conversion éventuelle / vers antislash
|
// conversion éventuelle / vers antislash
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -812,12 +808,15 @@ int http_proxy_tunnel(httrackp *opt, htsblk *retour, const char *adr,
|
|||||||
// treat: traiter header?
|
// treat: traiter header?
|
||||||
// waitconnect: attendre le connect()
|
// waitconnect: attendre le connect()
|
||||||
// note: dans retour, on met les params du proxy
|
// note: dans retour, on met les params du proxy
|
||||||
T_SOC http_xfopen(httrackp *opt, int mode, int treat, int waitconnect,
|
T_SOC http_xfopen(httrackp * opt, int mode, int treat, int waitconnect,
|
||||||
const char *xsend, const char *adr, const char *fil,
|
const char *xsend, const char *adr, const char *fil, htsblk * retour) {
|
||||||
htsblk *retour) {
|
//htsblk retour;
|
||||||
|
//int bufl=TAILLE_BUFFER; // 8Ko de buffer
|
||||||
T_SOC soc = INVALID_SOCKET;
|
T_SOC soc = INVALID_SOCKET;
|
||||||
char BIGSTK tempo_fil[HTS_URLMAXSIZE * 2];
|
char BIGSTK tempo_fil[HTS_URLMAXSIZE * 2];
|
||||||
|
|
||||||
|
//char *p,*q;
|
||||||
|
|
||||||
// retour prédéfini: erreur
|
// retour prédéfini: erreur
|
||||||
if (retour) {
|
if (retour) {
|
||||||
retour->adr = NULL;
|
retour->adr = NULL;
|
||||||
@@ -902,6 +901,7 @@ T_SOC http_xfopen(httrackp *opt, int mode, int treat, int waitconnect,
|
|||||||
strcpybuff(retour->msg, "Unable to open local file");
|
strcpybuff(retour->msg, "Unable to open local file");
|
||||||
else {
|
else {
|
||||||
// Note: On passe par un FILE* (plus propre)
|
// Note: On passe par un FILE* (plus propre)
|
||||||
|
//soc=open(fil,O_RDONLY,0); // en lecture seule!
|
||||||
retour->fp = FOPEN(fconv(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
retour->fp = FOPEN(fconv(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||||
unescape_http(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), fil)), "rb"); // ouvrir
|
unescape_http(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), fil)), "rb"); // ouvrir
|
||||||
if (retour->fp == NULL)
|
if (retour->fp == NULL)
|
||||||
@@ -978,10 +978,17 @@ T_SOC http_xfopen(httrackp *opt, int mode, int treat, int waitconnect,
|
|||||||
|
|
||||||
} while(strnotempty(rcvd));
|
} while(strnotempty(rcvd));
|
||||||
|
|
||||||
} else { // si GET, on recevra l'en tête APRES
|
//rcvsize=-1; // forCER CHARGEMENT INCONNU
|
||||||
|
|
||||||
|
//if (retour)
|
||||||
|
// retour->totalsize=rcvsize;
|
||||||
|
|
||||||
|
} else { // si GET, on recevra l'en tête APRES
|
||||||
|
//rcvsize=-1; // on ne connait pas la taille de l'en-tête
|
||||||
if (retour)
|
if (retour)
|
||||||
retour->totalsize = -1;
|
retour->totalsize = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1078,12 +1085,19 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
char BIGSTK buffer_head_request[16384];
|
char BIGSTK buffer_head_request[16384];
|
||||||
buff_struct bstr = { buffer_head_request, sizeof(buffer_head_request), 0 };
|
buff_struct bstr = { buffer_head_request, sizeof(buffer_head_request), 0 };
|
||||||
|
|
||||||
|
//int use_11=0; // HTTP 1.1 utilisé
|
||||||
int direct_url = 0; // ne pas analyser l'url (exemple: ftp://)
|
int direct_url = 0; // ne pas analyser l'url (exemple: ftp://)
|
||||||
const char *search_tag = NULL;
|
const char *search_tag = NULL;
|
||||||
|
|
||||||
// Initialize buffer
|
// Initialize buffer
|
||||||
buffer_head_request[0] = '\0';
|
buffer_head_request[0] = '\0';
|
||||||
|
|
||||||
|
// header Date
|
||||||
|
//strcatbuff(buff,"Date: ");
|
||||||
|
//time_gmt_rfc822(buff); // obtenir l'heure au format rfc822
|
||||||
|
//sendc("\n");
|
||||||
|
//strcatbuff(buff,buff);
|
||||||
|
|
||||||
// possibilité non documentée: >post: et >postfile:
|
// possibilité non documentée: >post: et >postfile:
|
||||||
// si présence d'un tag >post: alors executer un POST
|
// si présence d'un tag >post: alors executer un POST
|
||||||
// exemple: http://www.example.com/test.cgi?foo>post:posteddata=10&foo=5
|
// exemple: http://www.example.com/test.cgi?foo>post:posteddata=10&foo=5
|
||||||
@@ -1102,8 +1116,7 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
char BIGSTK protocol[256], url[HTS_URLMAXSIZE * 2], method[256];
|
char BIGSTK protocol[256], url[HTS_URLMAXSIZE * 2], method[256];
|
||||||
|
|
||||||
linput(fp, line, 1000);
|
linput(fp, line, 1000);
|
||||||
/* widths bound method[256], url[HTS_URLMAXSIZE*2], protocol[256] */
|
if (sscanf(line, "%s %s %s", 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
|
// selon que l'on a ou pas un proxy
|
||||||
if (retour->req.proxy.active) {
|
if (retour->req.proxy.active) {
|
||||||
@@ -1177,9 +1190,11 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// protocole
|
// protocole
|
||||||
if (!retour->req.http11) { // forcer HTTP/1.0
|
if (!retour->req.http11) { // forcer HTTP/1.0
|
||||||
|
//use_11=0;
|
||||||
print_buffer(&bstr, " HTTP/1.0\x0d\x0a");
|
print_buffer(&bstr, " HTTP/1.0\x0d\x0a");
|
||||||
} else { // Requète 1.1
|
} else { // Requète 1.1
|
||||||
|
//use_11=1;
|
||||||
print_buffer(&bstr, " HTTP/1.1\x0d\x0a");
|
print_buffer(&bstr, " HTTP/1.1\x0d\x0a");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1278,12 +1293,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;
|
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
compressible = (!retour->req.range_used && !retour->req.nocompression);
|
if ((!retour->req.range_used)
|
||||||
|
&& (!retour->req.nocompression))
|
||||||
|
print_buffer(&bstr, "Accept-Encoding: " "gzip" /* gzip if the preffered encoding */
|
||||||
|
", " "identity;q=0.9" H_CRLF);
|
||||||
|
else
|
||||||
|
print_buffer(&bstr, "Accept-Encoding: identity" H_CRLF); /* no compression */
|
||||||
|
#else
|
||||||
|
print_buffer(&bstr, "Accept-Encoding: identity" H_CRLF); /* no compression */
|
||||||
#endif
|
#endif
|
||||||
print_buffer(&bstr, "Accept-Encoding: %s" H_CRLF,
|
|
||||||
hts_acceptencoding(compressible));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Authentification */
|
/* Authentification */
|
||||||
@@ -1315,7 +1334,9 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
|
|||||||
print_buffer(&bstr, "Authorization: Basic %s"H_CRLF, autorisation);
|
print_buffer(&bstr, "Authorization: Basic %s"H_CRLF, autorisation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
//strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
|
||||||
|
|
||||||
// Custom header(s)
|
// Custom header(s)
|
||||||
if (strnotempty(retour->req.headers)) {
|
if (strnotempty(retour->req.headers)) {
|
||||||
@@ -1469,11 +1490,14 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
a += strlen("filename=");
|
a += strlen("filename=");
|
||||||
while(is_space(*a))
|
while(is_space(*a))
|
||||||
a++;
|
a++;
|
||||||
|
//a=strchr(a,'"');
|
||||||
if (a) {
|
if (a) {
|
||||||
char *c = NULL;
|
char *c = NULL;
|
||||||
|
|
||||||
|
//a++; /* jump " */
|
||||||
while((c = strchr(a, '/'))) /* skip all / (see RFC2616) */
|
while((c = strchr(a, '/'))) /* skip all / (see RFC2616) */
|
||||||
a = c + 1;
|
a = c + 1;
|
||||||
|
//b=strchr(a+1,'"');
|
||||||
b = a + strlen(a) - 1;
|
b = a + strlen(a) - 1;
|
||||||
while(is_space(*b))
|
while(is_space(*b))
|
||||||
b--;
|
b--;
|
||||||
@@ -1490,14 +1514,16 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
} else if ((p = strfield(rcvd, "Last-Modified:")) != 0) {
|
} else if ((p = strfield(rcvd, "Last-Modified:")) != 0) {
|
||||||
while(is_realspace(*(rcvd + p)))
|
while(is_realspace(*(rcvd + p)))
|
||||||
p++; // sauter espaces
|
p++; // sauter espaces
|
||||||
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
||||||
|
//struct tm* tm_time=convert_time_rfc822(rcvd+p);
|
||||||
strcpybuff(retour->lastmodified, rcvd + p);
|
strcpybuff(retour->lastmodified, rcvd + p);
|
||||||
}
|
}
|
||||||
} else if ((p = strfield(rcvd, "Date:")) != 0) {
|
} else if ((p = strfield(rcvd, "Date:")) != 0) {
|
||||||
if (strnotempty(retour->lastmodified) == 0) { /* pas encore de last-modified */
|
if (strnotempty(retour->lastmodified) == 0) { /* pas encore de last-modified */
|
||||||
while(is_realspace(*(rcvd + p)))
|
while(is_realspace(*(rcvd + p)))
|
||||||
p++; // sauter espaces
|
p++; // sauter espaces
|
||||||
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
if ((int) strlen(rcvd + p) < 64) { // pas trop long?
|
||||||
|
//struct tm* tm_time=convert_time_rfc822(rcvd+p);
|
||||||
strcpybuff(retour->lastmodified, rcvd + p);
|
strcpybuff(retour->lastmodified, rcvd + p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1510,11 +1536,14 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
else // erreur.. ignorer
|
else // erreur.. ignorer
|
||||||
retour->etag[0] = '\0';
|
retour->etag[0] = '\0';
|
||||||
}
|
}
|
||||||
} else if ((p = strfield(rcvd, "Transfer-Encoding:")) != 0) { // chunk!
|
}
|
||||||
|
// else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) { // chunk!
|
||||||
|
else if ((p = strfield(rcvd, "Transfer-Encoding:")) != 0) { // chunk!
|
||||||
while(is_realspace(*(rcvd + p)))
|
while(is_realspace(*(rcvd + p)))
|
||||||
p++; // sauter espaces
|
p++; // sauter espaces
|
||||||
if (strfield(rcvd + p, "chunked")) {
|
if (strfield(rcvd + p, "chunked")) {
|
||||||
retour->is_chunk = 1; // chunked
|
retour->is_chunk = 1; // chunked
|
||||||
|
//retour->http11=2; // chunked
|
||||||
#if HDEBUG
|
#if HDEBUG
|
||||||
printf("ok, Transfer-Encoding: détecté\n");
|
printf("ok, Transfer-Encoding: détecté\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -1562,7 +1591,7 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
}
|
}
|
||||||
// An empty/whitespace Content-Type value yields no token: keep the
|
// An empty/whitespace Content-Type value yields no token: keep the
|
||||||
// sentinel default rather than reading an uninitialized tempo.
|
// sentinel default rather than reading an uninitialized tempo.
|
||||||
if (sscanf(rcvd + p, "%1099s", tempo) == 1) { // tempo[1100], server data
|
if (sscanf(rcvd + p, "%s", tempo) == 1) {
|
||||||
if (strlen(tempo) < sizeof(retour->contenttype) - 2) // pas trop long!!
|
if (strlen(tempo) < sizeof(retour->contenttype) - 2) // pas trop long!!
|
||||||
strcpybuff(retour->contenttype, tempo);
|
strcpybuff(retour->contenttype, tempo);
|
||||||
else
|
else
|
||||||
@@ -1657,11 +1686,11 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
if (a)
|
if (a)
|
||||||
*a = '\0';
|
*a = '\0';
|
||||||
}
|
}
|
||||||
// Bound to tempo[1100]; no token => leave empty, don't read uninit tempo.
|
sscanf(a, "%s", tempo);
|
||||||
if (sscanf(a, "%1099s", tempo) == 1 && strlen(tempo) < 64)
|
if (strlen(tempo) < 64) // pas trop long!!
|
||||||
strcpybuff(retour->contentencoding, tempo);
|
strcpybuff(retour->contentencoding, tempo);
|
||||||
else
|
else
|
||||||
retour->contentencoding[0] = '\0';
|
retour->contentencoding[0] = '\0'; // erreur
|
||||||
#if HTS_USEZLIB
|
#if HTS_USEZLIB
|
||||||
/* Check known encodings */
|
/* Check known encodings */
|
||||||
if (retour->contentencoding[0]) {
|
if (retour->contentencoding[0]) {
|
||||||
@@ -1691,8 +1720,7 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
retour->location[0] = '\0';
|
retour->location[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (((p = strfield(rcvd, "Set-Cookie:")) != 0) &&
|
} else if (((p = strfield(rcvd, "Set-Cookie:")) != 0) && (cookie)) { // ohh un cookie
|
||||||
(cookie)) { // ohh un cookie
|
|
||||||
char *a = rcvd + p; // pointeur
|
char *a = rcvd + p; // pointeur
|
||||||
char domain[256]; // domaine cookie (.netscape.com)
|
char domain[256]; // domaine cookie (.netscape.com)
|
||||||
char path[256]; // chemin (/)
|
char path[256]; // chemin (/)
|
||||||
@@ -1736,8 +1764,10 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
|
|||||||
a++; // sauter espaces
|
a++; // sauter espaces
|
||||||
value_st = a;
|
value_st = a;
|
||||||
while((*a != ';') && (*a))
|
while((*a != ';') && (*a))
|
||||||
a++; // prochain ;
|
a++; // prochain ;
|
||||||
|
//while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++; // prochain " (et pas \")
|
||||||
value_end = a;
|
value_end = a;
|
||||||
|
//if (*a==';') { // finit par un ;
|
||||||
// vérifier débordements
|
// vérifier débordements
|
||||||
if ((((int) (token_end - token_st)) < 200)
|
if ((((int) (token_end - token_st)) < 200)
|
||||||
&& (((int) (value_end - value_st)) < 8000)
|
&& (((int) (value_end - value_st)) < 8000)
|
||||||
@@ -1888,10 +1918,6 @@ HTSEXT_API const char *infostatuscode_const(int statuscode) {
|
|||||||
return "Requested Range Not Satisfiable";
|
return "Requested Range Not Satisfiable";
|
||||||
case 417:
|
case 417:
|
||||||
return "Expectation Failed";
|
return "Expectation Failed";
|
||||||
case 429:
|
|
||||||
return "Too Many Requests";
|
|
||||||
case 451:
|
|
||||||
return "Unavailable For Legal Reasons";
|
|
||||||
case 500:
|
case 500:
|
||||||
return "Internal Server Error";
|
return "Internal Server Error";
|
||||||
case 501:
|
case 501:
|
||||||
@@ -2079,6 +2105,8 @@ LLint http_xfread1(htsblk * r, int bufl) {
|
|||||||
nl = READ_ERROR;
|
nl = READ_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
|
||||||
|
// nl=-1; // break
|
||||||
|
|
||||||
// libérer bloc tempo
|
// libérer bloc tempo
|
||||||
freet(buff);
|
freet(buff);
|
||||||
@@ -2166,6 +2194,9 @@ htsblk http_test(httrackp * opt, const char *adr, const char *fil, char *loc) {
|
|||||||
T_SOC soc;
|
T_SOC soc;
|
||||||
htsblk retour;
|
htsblk retour;
|
||||||
|
|
||||||
|
//int rcvsize=-1;
|
||||||
|
//char* rcv=NULL; // adresse de retour
|
||||||
|
//int bufl=TAILLE_BUFFER; // 8Ko de buffer
|
||||||
TStamp tl;
|
TStamp tl;
|
||||||
int timeout = 30; // timeout pour un check (arbitraire) // **
|
int timeout = 30; // timeout pour un check (arbitraire) // **
|
||||||
|
|
||||||
@@ -2174,8 +2205,11 @@ htsblk http_test(httrackp * opt, const char *adr, const char *fil, char *loc) {
|
|||||||
|
|
||||||
loc[0] = '\0';
|
loc[0] = '\0';
|
||||||
hts_init_htsblk(&retour);
|
hts_init_htsblk(&retour);
|
||||||
|
//memset(&retour, 0, sizeof(htsblk)); // effacer
|
||||||
retour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
retour.location = loc; // si non nul, contiendra l'adresse véritable en cas de moved xx
|
||||||
|
|
||||||
|
//soc=http_fopen(adr,fil,&retour,NULL); // ouvrir, + header
|
||||||
|
|
||||||
// on ouvre en head, et on traite l'en tête
|
// on ouvre en head, et on traite l'en tête
|
||||||
soc = http_xfopen(opt, 1, 0, 1, NULL, adr, fil, &retour); // ouvrir HEAD, + envoi header
|
soc = http_xfopen(opt, 1, 0, 1, NULL, adr, fil, &retour); // ouvrir HEAD, + envoi header
|
||||||
|
|
||||||
@@ -2497,10 +2531,6 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
|
|||||||
// effacer adrfil->adr et adrfil->fil
|
// effacer adrfil->adr et adrfil->fil
|
||||||
adrfil->adr[0] = adrfil->fil[0] = '\0';
|
adrfil->adr[0] = adrfil->fil[0] = '\0';
|
||||||
|
|
||||||
// Reject an over-long URL: a root-relative path is copied whole into fil[].
|
|
||||||
if (strlen(url) >= HTS_URLMAXSIZE * 2)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#if HDEBUG
|
#if HDEBUG
|
||||||
printf("protocol: %s\n", url);
|
printf("protocol: %s\n", url);
|
||||||
#endif
|
#endif
|
||||||
@@ -2555,6 +2585,7 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
|
|||||||
|
|
||||||
// chemin www... trop long!!
|
// chemin www... trop long!!
|
||||||
if ((((int) (q - p))) > HTS_URLMAXSIZE) {
|
if ((((int) (q - p))) > HTS_URLMAXSIZE) {
|
||||||
|
//strcpybuff(retour.msg,"Path too long");
|
||||||
return -1; // erreur
|
return -1; // erreur
|
||||||
}
|
}
|
||||||
// recopier adrfil->adresse www..
|
// recopier adrfil->adresse www..
|
||||||
@@ -2576,7 +2607,7 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
|
|||||||
if (*p == '/' || *p == '\\') { /* adrfil->file:///.. */
|
if (*p == '/' || *p == '\\') { /* adrfil->file:///.. */
|
||||||
strcatbuff(adrfil->fil, p); // fichier local ; adrfil->adr="#"
|
strcatbuff(adrfil->fil, p); // fichier local ; adrfil->adr="#"
|
||||||
} else {
|
} else {
|
||||||
if (*p == '\0' || p[1] != ':') { /* empty path: not a DOS drive letter */
|
if (p[1] != ':') {
|
||||||
strcatbuff(adrfil->fil, "//"); /* adrfil->file://server/foo */
|
strcatbuff(adrfil->fil, "//"); /* adrfil->file://server/foo */
|
||||||
strcatbuff(adrfil->fil, p);
|
strcatbuff(adrfil->fil, p);
|
||||||
} else {
|
} else {
|
||||||
@@ -2740,6 +2771,7 @@ void deletesoc_r(htsblk * r) {
|
|||||||
#if HTS_USEOPENSSL
|
#if HTS_USEOPENSSL
|
||||||
if (r->ssl_con) {
|
if (r->ssl_con) {
|
||||||
SSL_shutdown(r->ssl_con);
|
SSL_shutdown(r->ssl_con);
|
||||||
|
// SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
|
||||||
SSL_free(r->ssl_con);
|
SSL_free(r->ssl_con);
|
||||||
r->ssl_con = NULL;
|
r->ssl_con = NULL;
|
||||||
}
|
}
|
||||||
@@ -3128,6 +3160,7 @@ int finput(T_SOC fd, char *s, int max) {
|
|||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
//c=fgetc(fp);
|
||||||
if (read((int) fd, &c, 1) <= 0) {
|
if (read((int) fd, &c, 1) <= 0) {
|
||||||
c = 0;
|
c = 0;
|
||||||
}
|
}
|
||||||
@@ -3143,7 +3176,7 @@ int finput(T_SOC fd, char *s, int max) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while ((c != 0) && (j < max - 1));
|
} while((c != 0) && (j < max - 1));
|
||||||
s[j] = '\0';
|
s[j] = '\0';
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
@@ -4065,32 +4098,24 @@ DECLARE_APPEND_ESCAPE_VERSION(escape_uri)
|
|||||||
|
|
||||||
#undef DECLARE_APPEND_ESCAPE_VERSION
|
#undef DECLARE_APPEND_ESCAPE_VERSION
|
||||||
|
|
||||||
// In-place escaping: copy dest aside, then escape that copy back into dest.
|
// Same as above, but in-place
|
||||||
typedef size_t (*escape_fn_t)(const char *src, char *dest, size_t size);
|
|
||||||
|
|
||||||
static size_t inplace_escape(char *const dest, const size_t size,
|
|
||||||
escape_fn_t escape) {
|
|
||||||
char buffer[256];
|
|
||||||
const size_t len = strnlen(dest, size);
|
|
||||||
const int in_buffer = len + 1 < sizeof(buffer);
|
|
||||||
char *src = in_buffer ? buffer : malloct(len + 1);
|
|
||||||
size_t ret;
|
|
||||||
assertf(src != NULL);
|
|
||||||
assertf(len < size);
|
|
||||||
memcpy(src, dest, len + 1);
|
|
||||||
ret = escape(src, dest, size);
|
|
||||||
if (!in_buffer) {
|
|
||||||
freet(src);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Thin exported wrappers binding inplace_escape() to each escaper (ABI).
|
|
||||||
#undef DECLARE_INPLACE_ESCAPE_VERSION
|
#undef DECLARE_INPLACE_ESCAPE_VERSION
|
||||||
#define DECLARE_INPLACE_ESCAPE_VERSION(NAME) \
|
#define DECLARE_INPLACE_ESCAPE_VERSION(NAME) \
|
||||||
HTSEXT_API size_t inplace_##NAME(char *const dest, const size_t size) { \
|
HTSEXT_API size_t inplace_ ##NAME(char *const dest, const size_t size) { \
|
||||||
return inplace_escape(dest, size, NAME); \
|
char buffer[256]; \
|
||||||
}
|
const size_t len = strnlen(dest, size); \
|
||||||
|
const int in_buffer = len + 1 < sizeof(buffer); \
|
||||||
|
char *src = in_buffer ? buffer : malloct(len + 1); \
|
||||||
|
size_t ret; \
|
||||||
|
assertf(src != NULL); \
|
||||||
|
assertf(len < size); \
|
||||||
|
memcpy(src, dest, len + 1); \
|
||||||
|
ret = NAME(src, dest, size); \
|
||||||
|
if (!in_buffer) { \
|
||||||
|
freet(src); \
|
||||||
|
} \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
DECLARE_INPLACE_ESCAPE_VERSION(escape_in_url)
|
DECLARE_INPLACE_ESCAPE_VERSION(escape_in_url)
|
||||||
DECLARE_INPLACE_ESCAPE_VERSION(escape_spc_url)
|
DECLARE_INPLACE_ESCAPE_VERSION(escape_spc_url)
|
||||||
@@ -4283,20 +4308,6 @@ void guess_httptype(httrackp * opt, char *s, const char *fil) {
|
|||||||
(void) get_httptype_sized(opt, s, HTS_MIMETYPE_SIZE, fil, 1);
|
(void) get_httptype_sized(opt, s, HTS_MIMETYPE_SIZE, fil, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// first match in a NUL-terminated {mime,ext} table. key selects the lookup
|
|
||||||
// column (0=mime, 1=ext); returns the other column, or NULL if no row matches
|
|
||||||
// (a "*" partner means the row carries no value).
|
|
||||||
static const char *hts_mime_lookup(const char *(*table)[2], int key,
|
|
||||||
const char *needle) {
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = 0; strnotempty(table[j][1]); j++) {
|
|
||||||
if (strfield2(table[j][key], needle) && table[j][!key][0] != '*')
|
|
||||||
return table[j][!key];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the mime type for fil into s (capacity ssize)
|
// write the mime type for fil into s (capacity ssize)
|
||||||
// flag: 1 to always return a type (the "application/..." / octet-stream
|
// flag: 1 to always return a type (the "application/..." / octet-stream
|
||||||
// fallback) returns 1 if a type was written to s, 0 otherwise
|
// fallback) returns 1 if a type was written to s, 0 otherwise
|
||||||
@@ -4320,15 +4331,17 @@ HTSEXT_API hts_boolean get_httptype_sized(httrackp *opt, char *s, size_t ssize,
|
|||||||
while ((a > fil) && (*a != '.') && (*a != '/'))
|
while ((a > fil) && (*a != '.') && (*a != '/'))
|
||||||
a--;
|
a--;
|
||||||
if (a >= fil && *a == '.' && strlen(a) < 32) {
|
if (a >= fil && *a == '.' && strlen(a) < 32) {
|
||||||
const char *mime;
|
int j = 0;
|
||||||
|
|
||||||
a++;
|
a++;
|
||||||
mime = hts_mime_lookup(hts_mime, 1, a);
|
while(strnotempty(hts_mime[j][1])) {
|
||||||
if (mime == NULL)
|
if (strfield2(hts_mime[j][1], a)) {
|
||||||
mime = hts_mime_lookup(hts_mime_modern, 1, a);
|
if (hts_mime[j][0][0] != '*') { // a match exists
|
||||||
if (mime != NULL) {
|
strlcpybuff(s, hts_mime[j][0], ssize);
|
||||||
strlcpybuff(s, mime, ssize);
|
return 1;
|
||||||
return 1;
|
}
|
||||||
|
}
|
||||||
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag) {
|
if (flag) {
|
||||||
@@ -4352,11 +4365,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
|
||||||
@@ -4468,16 +4476,18 @@ int get_userhttptype(httrackp * opt, char *s, const char *fil) {
|
|||||||
// returns 1 if an extension was found (and written to s), 0 otherwise
|
// returns 1 if an extension was found (and written to s), 0 otherwise
|
||||||
int give_mimext(char *s, size_t ssize, const char *st) {
|
int give_mimext(char *s, size_t ssize, const char *st) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
const char *ext;
|
int j = 0;
|
||||||
|
|
||||||
st = hts_effective_mime(st); /* no declared type: derive an html ext */
|
st = hts_effective_mime(st); /* no declared type: derive an html ext */
|
||||||
s[0] = '\0';
|
s[0] = '\0';
|
||||||
ext = hts_mime_lookup(hts_mime, 0, st);
|
while((!ok) && (strnotempty(hts_mime[j][1]))) {
|
||||||
if (ext == NULL)
|
if (strfield2(hts_mime[j][0], st)) {
|
||||||
ext = hts_mime_lookup(hts_mime_modern, 0, st);
|
if (hts_mime[j][1][0] != '*') { // a match exists
|
||||||
if (ext != NULL) {
|
strlcpybuff(s, hts_mime[j][1], ssize);
|
||||||
strlcpybuff(s, ext, ssize);
|
ok = 1;
|
||||||
ok = 1;
|
}
|
||||||
|
}
|
||||||
|
j++;
|
||||||
}
|
}
|
||||||
// wrap "x" mimetypes, such as:
|
// wrap "x" mimetypes, such as:
|
||||||
// application/x-mp3
|
// application/x-mp3
|
||||||
@@ -4802,6 +4812,7 @@ LLint check_downloadable_bytes(int rate) {
|
|||||||
|
|
||||||
time_now = mtime_local();
|
time_now = mtime_local();
|
||||||
elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
|
elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
|
||||||
|
// NO totally stupid - elapsed_useconds+=1000; // for the next second, too
|
||||||
bytes_transferred_during_period =
|
bytes_transferred_during_period =
|
||||||
(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[id_timer]);
|
(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[id_timer]);
|
||||||
|
|
||||||
@@ -4814,6 +4825,32 @@ LLint check_downloadable_bytes(int rate) {
|
|||||||
return TAILLE_BUFFER;
|
return TAILLE_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 0 : OK
|
||||||
|
// 1 : slow down
|
||||||
|
#if 0
|
||||||
|
int HTS_TOTAL_RECV_CHECK(int var) {
|
||||||
|
if (HTS_STAT.HTS_TOTAL_RECV_STATE)
|
||||||
|
return 1;
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) {
|
||||||
|
var = min(var,32);
|
||||||
|
Sleep(250);
|
||||||
|
} else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) {
|
||||||
|
var = min(var,256);
|
||||||
|
Sleep(100);
|
||||||
|
} else {
|
||||||
|
var/=2;
|
||||||
|
if (var<=0) var=1;
|
||||||
|
Sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
|
// Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
|
||||||
// returns:
|
// returns:
|
||||||
// >0 : data received
|
// >0 : data received
|
||||||
@@ -4822,6 +4859,7 @@ LLint check_downloadable_bytes(int rate) {
|
|||||||
int hts_read(htsblk * r, char *buff, int size) {
|
int hts_read(htsblk * r, char *buff, int size) {
|
||||||
int retour;
|
int retour;
|
||||||
|
|
||||||
|
// return read(soc,buff,size);
|
||||||
if (r->is_file) {
|
if (r->is_file) {
|
||||||
#if HTS_WIDE_DEBUG
|
#if HTS_WIDE_DEBUG
|
||||||
DEBUG_W("read(%p, %d, %d)\n" _(void *)buff _(int) size _(int) r->fp);
|
DEBUG_W("read(%p, %d, %d)\n" _(void *)buff _(int) size _(int) r->fp);
|
||||||
@@ -4839,6 +4877,7 @@ int hts_read(htsblk * r, char *buff, int size) {
|
|||||||
if (r->soc == INVALID_SOCKET)
|
if (r->soc == INVALID_SOCKET)
|
||||||
printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
|
printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
|
||||||
#endif
|
#endif
|
||||||
|
//HTS_TOTAL_RECV_CHECK(size); // Diminuer au besoin si trop de données reçues
|
||||||
#if HTS_USEOPENSSL
|
#if HTS_USEOPENSSL
|
||||||
if (r->ssl) {
|
if (r->ssl) {
|
||||||
retour = SSL_read(r->ssl_con, buff, size);
|
retour = SSL_read(r->ssl_con, buff, size);
|
||||||
@@ -5273,13 +5312,18 @@ SOCaddr* hts_dns_resolve(httrackp * opt, const char *_iadr, SOCaddr *const addr)
|
|||||||
|
|
||||||
// --- Tracage des mallocs() ---
|
// --- Tracage des mallocs() ---
|
||||||
#ifdef HTS_TRACE_MALLOC
|
#ifdef HTS_TRACE_MALLOC
|
||||||
|
//#define htsLocker(A, N) htsLocker(A, N)
|
||||||
#define htsLocker(A, N) do {} while(0)
|
#define htsLocker(A, N) do {} while(0)
|
||||||
static mlink trmalloc = { NULL, 0, 0, NULL };
|
static mlink trmalloc = { NULL, 0, 0, NULL };
|
||||||
|
|
||||||
static int trmalloc_id = 0;
|
static int trmalloc_id = 0;
|
||||||
static htsmutex *mallocMutex = NULL;
|
static htsmutex *mallocMutex = NULL;
|
||||||
|
static void hts_meminit(void) {
|
||||||
static void hts_meminit(void) {}
|
//if (mallocMutex == NULL) {
|
||||||
|
// mallocMutex = calloc(sizeof(*mallocMutex), 1);
|
||||||
|
// htsLocker(mallocMutex, -999);
|
||||||
|
//}
|
||||||
|
}
|
||||||
void *hts_malloc(size_t len) {
|
void *hts_malloc(size_t len) {
|
||||||
void *adr;
|
void *adr;
|
||||||
|
|
||||||
@@ -5363,6 +5407,7 @@ void hts_free(void *adr) {
|
|||||||
htsboundary);
|
htsboundary);
|
||||||
lnk->next = lnk->next->next;
|
lnk->next = lnk->next->next;
|
||||||
free((void *) blk_free);
|
free((void *) blk_free);
|
||||||
|
//blk_free->id=-1;
|
||||||
free((char *) adr - bsize);
|
free((char *) adr - bsize);
|
||||||
htsLocker(mallocMutex, 0);
|
htsLocker(mallocMutex, 0);
|
||||||
return;
|
return;
|
||||||
@@ -5431,6 +5476,7 @@ mlink *hts_find(char *adr) {
|
|||||||
|
|
||||||
if (depl < 0)
|
if (depl < 0)
|
||||||
depl = -depl;
|
depl = -depl;
|
||||||
|
//assertf(depl < 512000); /* near the stack frame.. doesn't look like malloc but stack variable */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5486,7 +5532,8 @@ int ftp_available(void) {
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int ftp_available(void) {
|
int ftp_available(void) {
|
||||||
return 1; // ok!
|
return 1; // ok!
|
||||||
|
//return 0; // SOUS UNIX, PROBLEMESs
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -5700,19 +5747,13 @@ HTSEXT_API int hts_init(void) {
|
|||||||
assertf("OpenSSL version seems vulnerable to heartbleed bug (CVE-2014-0160)" == NULL);
|
assertf("OpenSSL version seems vulnerable to heartbleed bug (CVE-2014-0160)" == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenSSL_add_all_algorithms();
|
||||||
openssl_ctx = SSL_CTX_new(method);
|
openssl_ctx = SSL_CTX_new(method);
|
||||||
if (!openssl_ctx) {
|
if (!openssl_ctx) {
|
||||||
fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new()\n");
|
fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new()\n");
|
||||||
abortLog("unable to initialize TLS: SSL_CTX_new()");
|
abortLog("unable to initialize TLS: SSL_CTX_new()");
|
||||||
assertf("unable to initialize TLS" == NULL);
|
assertf("unable to initialize TLS" == NULL);
|
||||||
}
|
}
|
||||||
/* Pin a TLS floor (no SSLv3/TLS1.0/1.1); no cert verify, by design. */
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
||||||
SSL_CTX_set_min_proto_version(openssl_ctx, TLS1_2_VERSION);
|
|
||||||
#else
|
|
||||||
SSL_CTX_set_options(openssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
|
||||||
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -5918,11 +5959,9 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
"htsswf", "htsjava", "httrack-plugin", NULL
|
"htsswf", "htsjava", "httrack-plugin", NULL
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
#ifndef HTS_LIBHTSJAVA_NAME
|
static const char *defaultModules[] = {
|
||||||
#define HTS_LIBHTSJAVA_NAME "libhtsjava.so" /* non-autoconf fallback */
|
"libhtsswf.so.1", "libhtsjava.so.2", "httrack-plugin", NULL
|
||||||
#endif
|
};
|
||||||
static const char *defaultModules[] = {"libhtsswf.so.1", HTS_LIBHTSJAVA_NAME,
|
|
||||||
"httrack-plugin", NULL};
|
|
||||||
#endif
|
#endif
|
||||||
httrackp *opt = malloc(sizeof(httrackp));
|
httrackp *opt = malloc(sizeof(httrackp));
|
||||||
|
|
||||||
@@ -5966,7 +6005,8 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
opt->shell = HTS_FALSE;
|
opt->shell = HTS_FALSE;
|
||||||
opt->proxy.active = 0; // pas de proxy
|
opt->proxy.active = 0; // pas de proxy
|
||||||
opt->user_agent_send = HTS_TRUE;
|
opt->user_agent_send = HTS_TRUE;
|
||||||
StringCopy(opt->user_agent, HTS_DEFAULT_USER_AGENT);
|
StringCopy(opt->user_agent,
|
||||||
|
"Mozilla/4.5 (compatible; HTTrack 3.0x; Windows 98)");
|
||||||
StringCopy(opt->referer, "");
|
StringCopy(opt->referer, "");
|
||||||
StringCopy(opt->from, "");
|
StringCopy(opt->from, "");
|
||||||
opt->savename_83 = HTS_SAVENAME_83_LONG; // long names by default
|
opt->savename_83 = HTS_SAVENAME_83_LONG; // long names by default
|
||||||
@@ -6005,10 +6045,6 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
opt->no_query_dedup = HTS_FALSE;
|
opt->no_query_dedup = HTS_FALSE;
|
||||||
StringCopy(opt->footer, HTS_DEFAULT_FOOTER);
|
StringCopy(opt->footer, HTS_DEFAULT_FOOTER);
|
||||||
StringCopy(opt->strip_query, "");
|
StringCopy(opt->strip_query, "");
|
||||||
StringCopy(opt->cookies_file, "");
|
|
||||||
StringCopy(opt->why_url, "");
|
|
||||||
opt->pause_min_ms = 0;
|
|
||||||
opt->pause_max_ms = 0;
|
|
||||||
opt->ftp_proxy = HTS_TRUE;
|
opt->ftp_proxy = HTS_TRUE;
|
||||||
opt->convert_utf8 = HTS_TRUE;
|
opt->convert_utf8 = HTS_TRUE;
|
||||||
StringCopy(opt->filelist, "");
|
StringCopy(opt->filelist, "");
|
||||||
@@ -6022,6 +6058,7 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
opt->log = stdout;
|
opt->log = stdout;
|
||||||
opt->errlog = stderr;
|
opt->errlog = stderr;
|
||||||
opt->flush = HTS_TRUE;
|
opt->flush = HTS_TRUE;
|
||||||
|
// opt->aff_progress=0;
|
||||||
opt->keyboard = HTS_FALSE;
|
opt->keyboard = HTS_FALSE;
|
||||||
//
|
//
|
||||||
StringCopy(opt->path_html, "");
|
StringCopy(opt->path_html, "");
|
||||||
@@ -6031,8 +6068,8 @@ HTSEXT_API httrackp *hts_create_opt(void) {
|
|||||||
//
|
//
|
||||||
opt->maxlink = 100000; // 100,000 liens max par défaut
|
opt->maxlink = 100000; // 100,000 liens max par défaut
|
||||||
opt->maxfilter = 200; // 200 filtres max par défaut
|
opt->maxfilter = 200; // 200 filtres max par défaut
|
||||||
opt->maxcache = 1048576 * 32; // a peu près 32Mo en cache max -- OPTION NON
|
opt->maxcache = 1048576 * 32; // a peu près 32Mo en cache max -- OPTION NON PARAMETRABLE POUR L'INSTANT --
|
||||||
// PARAMETRABLE POUR L'INSTANT --
|
//opt->maxcache_anticipate=256; // maximum de liens à anticiper
|
||||||
opt->maxtime = -1; // temps max en secondes
|
opt->maxtime = -1; // temps max en secondes
|
||||||
opt->maxrate = 100000; // taux maxi
|
opt->maxrate = 100000; // taux maxi
|
||||||
opt->maxconn = 5.0; // nombre connexions/s
|
opt->maxconn = 5.0; // nombre connexions/s
|
||||||
@@ -6153,8 +6190,6 @@ HTSEXT_API void hts_free_opt(httrackp * opt) {
|
|||||||
StringFree(opt->footer);
|
StringFree(opt->footer);
|
||||||
StringFree(opt->mod_blacklist);
|
StringFree(opt->mod_blacklist);
|
||||||
StringFree(opt->strip_query);
|
StringFree(opt->strip_query);
|
||||||
StringFree(opt->cookies_file);
|
|
||||||
StringFree(opt->why_url);
|
|
||||||
|
|
||||||
StringFree(opt->path_html);
|
StringFree(opt->path_html);
|
||||||
StringFree(opt->path_html_utf8);
|
StringFree(opt->path_html_utf8);
|
||||||
@@ -6186,9 +6221,11 @@ const hts_stat_struct* hts_get_stats(httrackp * opt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// defaut wrappers
|
// defaut wrappers
|
||||||
static void __cdecl htsdefault_init(t_hts_callbackarg *carg) {}
|
static void __cdecl htsdefault_init(t_hts_callbackarg * carg) {
|
||||||
|
}
|
||||||
static void __cdecl htsdefault_uninit(t_hts_callbackarg *carg) {}
|
static void __cdecl htsdefault_uninit(t_hts_callbackarg * carg) {
|
||||||
|
// hts_freevar();
|
||||||
|
}
|
||||||
static int __cdecl htsdefault_start(t_hts_callbackarg * carg, httrackp * opt) {
|
static int __cdecl htsdefault_start(t_hts_callbackarg * carg, httrackp * opt) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ HTSEXT_API const char* hts_version(void);
|
|||||||
// fonctions unix/winsock
|
// fonctions unix/winsock
|
||||||
int hts_read(htsblk * r, char *buff, int size);
|
int hts_read(htsblk * r, char *buff, int size);
|
||||||
|
|
||||||
|
//int HTS_TOTAL_RECV_CHECK(int var);
|
||||||
LLint check_downloadable_bytes(int rate);
|
LLint check_downloadable_bytes(int rate);
|
||||||
|
|
||||||
HTSEXT_API int hts_uninit_module(void);
|
HTSEXT_API int hts_uninit_module(void);
|
||||||
@@ -189,6 +190,7 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode, const char *xsend
|
|||||||
int http_cookie_header_selftest(t_cookie *cookie, const char *domain,
|
int http_cookie_header_selftest(t_cookie *cookie, const char *domain,
|
||||||
const char *path, char *dst, size_t dst_size);
|
const char *path, char *dst, size_t dst_size);
|
||||||
|
|
||||||
|
//int newhttp(char* iadr,char* err=NULL);
|
||||||
T_SOC newhttp(httrackp * opt, const char *iadr, htsblk * retour, int port,
|
T_SOC newhttp(httrackp * opt, const char *iadr, htsblk * retour, int port,
|
||||||
int waitconnect);
|
int waitconnect);
|
||||||
/* Like newhttp(), but connect to the addr_index-th resolved address of the host
|
/* Like newhttp(), but connect to the addr_index-th resolved address of the host
|
||||||
@@ -283,9 +285,6 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ extern int fspc(httrackp * opt, FILE * fp, const char *type);
|
|||||||
|
|
||||||
/* >>> Put all modules variables here */
|
/* >>> Put all modules variables here */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
t_gzopen gzopen = NULL;
|
||||||
|
t_gzread gzread = NULL;
|
||||||
|
t_gzclose gzclose = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
int V6_is_available = HTS_INET6;
|
int V6_is_available = HTS_INET6;
|
||||||
|
|
||||||
static char WHAT_is_available[64] = "";
|
static char WHAT_is_available[64] = "";
|
||||||
@@ -106,6 +112,18 @@ int hts_parse_externals(htsmoduleStruct * str) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static void addCallback(htscallbacks* chain, void* moduleHandle, htscallbacksfncptr exitFnc) {
|
||||||
|
// while(chain->next != NULL) {
|
||||||
|
// chain = chain->next;
|
||||||
|
// }
|
||||||
|
// chain->next = calloct(1, sizeof(htscallbacks));
|
||||||
|
// assertf(chain->next != NULL);
|
||||||
|
// chain = chain->next;
|
||||||
|
// memset(chain, 0, sizeof(*chain));
|
||||||
|
// chain->exitFnc = exitFnc;
|
||||||
|
// chain->moduleHandle = moduleHandle;
|
||||||
|
//}
|
||||||
|
|
||||||
void clearCallbacks(htscallbacks * chain_);
|
void clearCallbacks(htscallbacks * chain_);
|
||||||
void clearCallbacks(htscallbacks * chain_) {
|
void clearCallbacks(htscallbacks * chain_) {
|
||||||
htscallbacks *chain;
|
htscallbacks *chain;
|
||||||
|
|||||||
383
src/htsname.c
383
src/htsname.c
@@ -41,10 +41,6 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#include "htstools.h"
|
#include "htstools.h"
|
||||||
#include "htscharset.h"
|
#include "htscharset.h"
|
||||||
#include "htsencoding.h"
|
#include "htsencoding.h"
|
||||||
#include "htssniff.h"
|
|
||||||
#if HTS_USEZLIB
|
|
||||||
#include "htszlib.h"
|
|
||||||
#endif
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#define ADD_STANDARD_PATH \
|
#define ADD_STANDARD_PATH \
|
||||||
@@ -74,6 +70,31 @@ static const char *hts_tbdev[] = {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET() do { \
|
||||||
|
int prev = opt->state._hts_in_html_parsing; \
|
||||||
|
while(back_pluggable_sockets_strict(sback, opt) <= 0) { \
|
||||||
|
opt->state. _hts_in_html_parsing = 6; \
|
||||||
|
/* Wait .. */ \
|
||||||
|
back_wait(sback,opt,cache,0); \
|
||||||
|
/* Transfer rate */ \
|
||||||
|
engine_stats(); \
|
||||||
|
/* Refresh various stats */ \
|
||||||
|
HTS_STAT.stat_nsocket=back_nsoc(sback); \
|
||||||
|
HTS_STAT.stat_errors=fspc(opt,NULL,"error"); \
|
||||||
|
HTS_STAT.stat_warnings=fspc(opt,NULL,"warning"); \
|
||||||
|
HTS_STAT.stat_infos=fspc(opt,NULL,"info"); \
|
||||||
|
HTS_STAT.nbk=backlinks_done(sback,opt->liens,opt->lien_tot,ptr); \
|
||||||
|
HTS_STAT.nb=back_transferred(HTS_STAT.stat_bytes,sback); \
|
||||||
|
/* Check */ \
|
||||||
|
{ \
|
||||||
|
if (!RUN_CALLBACK7(opt, loop, sback->lnk, sback->count,-1,ptr,opt->lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
opt->state._hts_in_html_parsing = prev; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
/* Strip all // */
|
/* Strip all // */
|
||||||
static void cleanDoubleSlash(char *s) {
|
static void cleanDoubleSlash(char *s) {
|
||||||
int i, j;
|
int i, j;
|
||||||
@@ -117,191 +138,37 @@ static void cleanEndingSpaceOrDot(char *s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wire Content-Type vs URL extension: a patchable wire type wins over an
|
/* Should the wire Content-Type override the URL's own extension when naming the
|
||||||
unspecific ext, the HTS_UNKNOWN_MIME sentinel keeps a specific non-HTML ext
|
saved file? True when the type is patchable (may_unknown2) and either the URL
|
||||||
(#267 guard), a declared disagreement is CONTESTED (sniffed below). */
|
extension implies no specific type or the server declared a disagreeing one.
|
||||||
typedef enum wire_verdict {
|
A URL extension mapping to a specific non-HTML type is kept only when the
|
||||||
WIRE_KEEPS_EXT,
|
server declared NO type (the HTS_UNKNOWN_MIME sentinel; the #267 mangle
|
||||||
WIRE_WINS,
|
guard): a typeless .png stays .png, but a .pdf explicitly served as text/html
|
||||||
WIRE_CONTESTED
|
is named .html. The sentinel rides the cache, so updates stay consistent. */
|
||||||
} wire_verdict;
|
static int wire_patches_ext(httrackp *opt, const char *wiremime,
|
||||||
|
const char *file) {
|
||||||
static wire_verdict wire_ext_verdict(httrackp *opt, const char *wiremime,
|
|
||||||
const char *file, char *urlmime,
|
|
||||||
size_t urlmime_size) {
|
|
||||||
if (may_unknown2(opt, wiremime, file))
|
|
||||||
return WIRE_KEEPS_EXT; /* type kept verbatim (keep-list / bogus-multiple) */
|
|
||||||
urlmime[0] = '\0';
|
|
||||||
/* type implied by the URL extension, only when confidently known (flag 0) */
|
|
||||||
if (!get_httptype_sized(opt, urlmime, urlmime_size, file, 0))
|
|
||||||
return WIRE_WINS; /* URL ext implies no known type */
|
|
||||||
if (strfield2(wiremime, urlmime))
|
|
||||||
return WIRE_KEEPS_EXT; /* agreement (no .htm->.html churn) */
|
|
||||||
if (!is_hypertext_mime(opt, urlmime, file) &&
|
|
||||||
strfield2(wiremime, HTS_UNKNOWN_MIME))
|
|
||||||
return WIRE_KEEPS_EXT; /* no declared type */
|
|
||||||
return WIRE_CONTESTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Optional evidence for a contested wire-vs-ext verdict. */
|
|
||||||
typedef struct sniff_src {
|
|
||||||
struct_back *sback; /* live backing (looked up by adr/fil) */
|
|
||||||
const lien_back *headers; /* snapshot: r.adr, else the url_sav file */
|
|
||||||
const char *adr, *fil;
|
|
||||||
const char *prev_save; /* previous run's save name (cache X-Save) */
|
|
||||||
} 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) {
|
|
||||||
char catbuff[CATBUFF_SIZE];
|
|
||||||
FILE *const fp = FOPEN(fconv(catbuff, sizeof(catbuff), path), "rb");
|
|
||||||
size_t n = 0;
|
|
||||||
|
|
||||||
if (fp != NULL) {
|
|
||||||
n = fread(buf, 1, len, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Body head of one slot: memory, else its flushed on-disk file (url_sav, or
|
|
||||||
tmpfile for a compressed stream); inflated so the sniff sees the final body.
|
|
||||||
*/
|
|
||||||
static size_t sniff_slot_head(const lien_back *slot, void *buf, size_t len) {
|
|
||||||
const htsblk *const r = &slot->r;
|
|
||||||
size_t n = 0;
|
|
||||||
|
|
||||||
if (r->adr != NULL && r->size > 0) {
|
|
||||||
n = (size_t) r->size < len ? (size_t) r->size : len;
|
|
||||||
memcpy(buf, r->adr, n);
|
|
||||||
} else {
|
|
||||||
if (r->out != NULL)
|
|
||||||
fflush(r->out);
|
|
||||||
if (slot->url_sav[0] != '\0')
|
|
||||||
n = sniff_read_head(slot->url_sav, buf, len);
|
|
||||||
if (n == 0 && slot->tmpfile != NULL && slot->tmpfile[0] != '\0')
|
|
||||||
n = sniff_read_head(slot->tmpfile, buf, len);
|
|
||||||
}
|
|
||||||
if (n > 0 && r->compressed) {
|
|
||||||
#if HTS_USEZLIB
|
|
||||||
unsigned char raw[HTS_SNIFF_LEN];
|
|
||||||
|
|
||||||
if (n > sizeof(raw))
|
|
||||||
n = sizeof(raw);
|
|
||||||
memcpy(raw, buf, n);
|
|
||||||
n = sniff_inflate_head(raw, n, buf, len);
|
|
||||||
#else
|
|
||||||
n = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Up to len leading body bytes; 0 when unavailable, and always in
|
|
||||||
non-delayed mode (its HEAD-probe first run couldn't sniff either). */
|
|
||||||
static size_t sniff_body_head(httrackp *opt, const sniff_src *src, void *buf,
|
|
||||||
size_t len) {
|
|
||||||
size_t n = 0;
|
|
||||||
|
|
||||||
if (src == NULL || opt->savename_delayed == HTS_SAVENAME_DELAYED_NONE)
|
|
||||||
return 0;
|
|
||||||
/* live backing slot: a snapshot (back_copy_static) loses r.adr/r.out */
|
|
||||||
if (src->sback != NULL && src->adr != NULL && src->fil != NULL) {
|
|
||||||
const int b = back_index(opt, src->sback, src->adr, src->fil, NULL);
|
|
||||||
|
|
||||||
if (b >= 0)
|
|
||||||
n = sniff_slot_head(&src->sback->lnk[b], buf, len);
|
|
||||||
}
|
|
||||||
if (n == 0 && src->headers != NULL)
|
|
||||||
n = sniff_slot_head(src->headers, buf, len);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Contested verdicts: magic proving the URL ext keeps it, else wire wins. */
|
|
||||||
static int wire_patches_ext(httrackp *opt, const sniff_src *src,
|
|
||||||
const char *wiremime, const char *file) {
|
|
||||||
char urlmime[256];
|
char urlmime[256];
|
||||||
|
|
||||||
switch (wire_ext_verdict(opt, wiremime, file, urlmime, sizeof(urlmime))) {
|
if (may_unknown2(opt, wiremime, file))
|
||||||
case WIRE_KEEPS_EXT:
|
return 0; /* type kept verbatim (keep-list / bogus-multiple) */
|
||||||
|
urlmime[0] = '\0';
|
||||||
|
/* type implied by the URL extension, only when confidently known (flag 0) */
|
||||||
|
if (!get_httptype_sized(opt, urlmime, sizeof(urlmime), file, 0))
|
||||||
|
return 1; /* URL ext implies no known type: trust the wire type */
|
||||||
|
if (strfield2(wiremime, urlmime))
|
||||||
|
return 0; /* wire agrees with the ext: keep it (no .htm->.html churn) */
|
||||||
|
/* wire disagrees with a specific non-HTML URL ext. Keep the ext only when
|
||||||
|
the server declared no type (the sentinel); an explicitly declared type,
|
||||||
|
even text/html, is trusted, so a binary-looking URL that really serves
|
||||||
|
HTML (login/error interstitial, soft-404) is named .html. */
|
||||||
|
if (!is_hypertext_mime(opt, urlmime, file) &&
|
||||||
|
strfield2(wiremime, HTS_UNKNOWN_MIME))
|
||||||
return 0;
|
return 0;
|
||||||
case WIRE_WINS:
|
|
||||||
return 1;
|
|
||||||
case WIRE_CONTESTED:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (src != NULL) {
|
|
||||||
if (hts_sniff_mime_known(urlmime)) {
|
|
||||||
unsigned char head[HTS_SNIFF_LEN];
|
|
||||||
const size_t n = sniff_body_head(opt, src, head, sizeof(head));
|
|
||||||
|
|
||||||
if (n > 0)
|
|
||||||
return hts_sniff_mime_consistent(head, n, urlmime) ? 0 : 1;
|
|
||||||
}
|
|
||||||
/* no bytes: reproduce the previous run's verdict (cached X-Save name) */
|
|
||||||
if (src->prev_save != NULL && src->prev_save[0] != '\0') {
|
|
||||||
char prevmime[256];
|
|
||||||
|
|
||||||
prevmime[0] = '\0';
|
|
||||||
if (get_httptype_sized(opt, prevmime, sizeof(prevmime), src->prev_save,
|
|
||||||
0) &&
|
|
||||||
strfield2(prevmime, urlmime))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hts_ext_sniff_wanted(httrackp *opt, const char *wiremime,
|
// forme le nom du fichier à sauver (save) à partir de fil et adr
|
||||||
const char *file) {
|
// système intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html)
|
||||||
char urlmime[256];
|
|
||||||
|
|
||||||
return wiremime != NULL && strnotempty(wiremime) &&
|
|
||||||
wire_ext_verdict(opt, wiremime, file, urlmime, sizeof(urlmime)) ==
|
|
||||||
WIRE_CONTESTED &&
|
|
||||||
hts_sniff_mime_known(urlmime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wire-metadata name change: a Content-Disposition filename wins (returns 2),
|
|
||||||
else the declared type's ext when wire_patches_ext() allows (returns 1),
|
|
||||||
else 0. ext receives the new extension or replacement filename. */
|
|
||||||
static int resolve_extension(httrackp *opt, const sniff_src *src,
|
|
||||||
const char *cdispo, const char *contenttype,
|
|
||||||
const char *fil, char *ext, size_t ext_size) {
|
|
||||||
if (strnotempty(cdispo)) {
|
|
||||||
strlcpybuff(ext, cdispo, ext_size);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (wire_patches_ext(opt, src, contenttype, fil) &&
|
|
||||||
give_mimext(ext, ext_size, contenttype))
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the local save name (save) from adr/fil; renames on collision
|
|
||||||
// (e.g. INDEX.HTML vs index.html).
|
|
||||||
int url_savename(lien_adrfilsave *const afs,
|
int url_savename(lien_adrfilsave *const afs,
|
||||||
lien_adrfil *const former,
|
lien_adrfil *const former,
|
||||||
const char *referer_adr, const char *referer_fil,
|
const char *referer_adr, const char *referer_fil,
|
||||||
@@ -538,30 +405,45 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
|
|
||||||
// si option check_type activée
|
// si option check_type activée
|
||||||
if (is_html < 0 && opt->check_type && !ext_chg) {
|
if (is_html < 0 && opt->check_type && !ext_chg) {
|
||||||
|
int ishtest = 0;
|
||||||
|
|
||||||
if (protocol != PROTOCOL_FILE
|
if (protocol != PROTOCOL_FILE
|
||||||
&& protocol != PROTOCOL_FTP
|
&& protocol != PROTOCOL_FTP
|
||||||
) {
|
) {
|
||||||
// tester type avec requète HEAD si on ne connait pas le type du fichier
|
// tester type avec requète HEAD si on ne connait pas le type du fichier
|
||||||
if (!((opt->check_type == 1) && (fil[strlen(fil) - 1] == '/'))) // slash doit être html?
|
if (!((opt->check_type == 1) && (fil[strlen(fil) - 1] == '/'))) // slash doit être html?
|
||||||
if (opt->savename_delayed == HTS_SAVENAME_DELAYED_HARD ||
|
if (opt->savename_delayed == HTS_SAVENAME_DELAYED_HARD ||
|
||||||
ishtml(opt, fil) < 0) { // unsure whether it's html or a file
|
(ishtest = ishtml(opt, fil)) <
|
||||||
|
0) { // unsure whether it's html or a file
|
||||||
// lire dans le cache
|
// lire dans le cache
|
||||||
char BIGSTK previous_save[HTS_URLMAXSIZE * 2];
|
htsblk r = cache_read_including_broken(opt, cache, adr, fil); // test uniquement
|
||||||
htsblk r;
|
|
||||||
|
|
||||||
previous_save[0] = '\0';
|
if (r.statuscode != -1) { // pas d'erreur de lecture cache
|
||||||
r = cache_read_including_broken(opt, cache, adr, fil,
|
char s[32];
|
||||||
previous_save); // test uniquement
|
|
||||||
|
|
||||||
if (r.statuscode != -1) { // cache entry read OK
|
s[0] = '\0';
|
||||||
hts_log_print(opt, LOG_DEBUG, "Testing link type (from cache) %s%s",
|
hts_log_print(opt, LOG_DEBUG, "Testing link type (from cache) %s%s",
|
||||||
adr_complete, fil_complete);
|
adr_complete, fil_complete);
|
||||||
if (!HTTP_IS_REDIRECT(r.statuscode)) {
|
if (!HTTP_IS_REDIRECT(r.statuscode)) {
|
||||||
const sniff_src src = {sback, NULL, adr, fil, previous_save};
|
if (strnotempty(r.cdispo)) { /* filename given */
|
||||||
|
ext_chg = 2; /* change filename */
|
||||||
ext_chg = resolve_extension(opt, &src, r.cdispo, r.contenttype,
|
strcpybuff(ext, r.cdispo);
|
||||||
fil, ext, sizeof(ext));
|
} else if (wire_patches_ext(opt, r.contenttype, fil)) {
|
||||||
|
if (give_mimext(s, sizeof(s),
|
||||||
|
r.contenttype)) { // recognized extension
|
||||||
|
ext_chg = 1;
|
||||||
|
strcpybuff(ext, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef DEFAULT_BIN_EXT
|
||||||
|
// no extension and potentially bogus
|
||||||
|
else if (ishtest == -2) {
|
||||||
|
ext_chg = 1;
|
||||||
|
strcpybuff(ext, DEFAULT_BIN_EXT + 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//
|
||||||
} else if (opt->savename_delayed != HTS_SAVENAME_DELAYED_HARD &&
|
} else if (opt->savename_delayed != HTS_SAVENAME_DELAYED_HARD &&
|
||||||
is_userknowntype(opt, fil)) { /* PATCH BY BRIAN SCHRÖDER.
|
is_userknowntype(opt, fil)) { /* PATCH BY BRIAN SCHRÖDER.
|
||||||
Lookup mimetype not only by extension,
|
Lookup mimetype not only by extension,
|
||||||
@@ -585,13 +467,22 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
// fail later
|
// fail later
|
||||||
else if (opt->savename_delayed != HTS_SAVENAME_DELAYED_NONE &&
|
else if (opt->savename_delayed != HTS_SAVENAME_DELAYED_NONE &&
|
||||||
!opt->state.stop) {
|
!opt->state.stop) {
|
||||||
// Check if the file is ready in backing.
|
// Check if the file is ready in backing. We basically take the same logic as later.
|
||||||
|
// FIXME: we should cleanup and factorize this unholy mess
|
||||||
if (headers != NULL && headers->status >= 0 && !is_redirect) {
|
if (headers != NULL && headers->status >= 0 && !is_redirect) {
|
||||||
const sniff_src src = {sback, headers, adr, fil, NULL};
|
if (strnotempty(headers->r.cdispo)) { /* filename given */
|
||||||
|
ext_chg = 2; /* change filename */
|
||||||
ext_chg = resolve_extension(opt, &src, headers->r.cdispo,
|
strcpybuff(ext, headers->r.cdispo);
|
||||||
headers->r.contenttype,
|
} else if (wire_patches_ext(opt, headers->r.contenttype,
|
||||||
headers->url_fil, ext, sizeof(ext));
|
headers->url_fil)) {
|
||||||
|
char s[16];
|
||||||
|
if (give_mimext(
|
||||||
|
s, sizeof(s),
|
||||||
|
headers->r.contenttype)) { // recognized extension
|
||||||
|
ext_chg = 1;
|
||||||
|
strcpybuff(ext, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (mime_type != NULL) {
|
else if (mime_type != NULL) {
|
||||||
ext[0] = '\0';
|
ext[0] = '\0';
|
||||||
@@ -609,6 +500,13 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
if (!may_unknown2(opt, mime_type, fil)) {
|
if (!may_unknown2(opt, mime_type, fil)) {
|
||||||
ext_chg = 1;
|
ext_chg = 1;
|
||||||
}
|
}
|
||||||
|
#ifdef DEFAULT_BIN_EXT
|
||||||
|
// no extension and potentially bogus
|
||||||
|
else if (ishtml(opt, fil) == -2) {
|
||||||
|
ext_chg = 1;
|
||||||
|
strcpybuff(ext, DEFAULT_BIN_EXT + 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
ext_chg = 0;
|
ext_chg = 0;
|
||||||
}
|
}
|
||||||
@@ -627,10 +525,11 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
int has_been_moved = 0;
|
int has_been_moved = 0;
|
||||||
lien_adrfil current;
|
lien_adrfil current;
|
||||||
|
|
||||||
/* Wait for an available test slot, honoring the connection limits
|
/* Ensure we don't use too many sockets by using a "testing" one
|
||||||
|
If we have only 1 simultaneous connection authorized, wait for pending download
|
||||||
|
Wait for an available slot
|
||||||
*/
|
*/
|
||||||
if (!hts_wait_available_socket(sback, opt, cache, ptr))
|
URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Rock'in */
|
/* Rock'in */
|
||||||
current.adr[0] = current.fil[0] = '\0';
|
current.adr[0] = current.fil[0] = '\0';
|
||||||
@@ -660,11 +559,24 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
if (ptr >= 0) {
|
if (ptr >= 0) {
|
||||||
back_fillmax(sback, opt, cache, ptr, numero_passe);
|
back_fillmax(sback, opt, cache, ptr, numero_passe);
|
||||||
}
|
}
|
||||||
if (!hts_loop_tick(sback, opt, b, ptr)) {
|
// on est obligé d'appeler le shell pour le refresh..
|
||||||
|
// Transfer rate
|
||||||
|
engine_stats();
|
||||||
|
|
||||||
|
// Refresh various stats
|
||||||
|
HTS_STAT.stat_nsocket = back_nsoc(sback);
|
||||||
|
HTS_STAT.stat_errors = fspc(opt, NULL, "error");
|
||||||
|
HTS_STAT.stat_warnings = fspc(opt, NULL, "warning");
|
||||||
|
HTS_STAT.stat_infos = fspc(opt, NULL, "info");
|
||||||
|
HTS_STAT.nbk = backlinks_done(sback, opt->liens, opt->lien_tot, ptr);
|
||||||
|
HTS_STAT.nb = back_transferred(HTS_STAT.stat_bytes, sback);
|
||||||
|
|
||||||
|
if (!RUN_CALLBACK7
|
||||||
|
(opt, loop, sback->lnk, sback->count, b, ptr, opt->lien_tot,
|
||||||
|
(int) (time_local() - HTS_STAT.stat_timestart),
|
||||||
|
&HTS_STAT)) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (opt->state._hts_cancel ||
|
} else if (opt->state._hts_cancel || !back_checkmirror(opt)) { // cancel 2 ou 1 (cancel parsing)
|
||||||
!back_checkmirror(
|
|
||||||
opt)) { // cancel level 2 or 1 (cancel parsing)
|
|
||||||
back_delete(opt, cache, sback, b); // cancel test
|
back_delete(opt, cache, sback, b); // cancel test
|
||||||
stop_looping = 1;
|
stop_looping = 1;
|
||||||
}
|
}
|
||||||
@@ -729,9 +641,8 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
"Loop with HEAD request (during prefetch) at %s%s",
|
"Loop with HEAD request (during prefetch) at %s%s",
|
||||||
current.adr, current.fil);
|
current.adr, current.fil);
|
||||||
}
|
}
|
||||||
if (!hts_wait_available_socket(sback, opt,
|
// Ajouter
|
||||||
cache, ptr))
|
URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
|
||||||
return -1;
|
|
||||||
if (back_add(sback, opt, cache, moved.adr, moved.fil, methode, referer_adr, referer_fil, 1) != -1) { // OK
|
if (back_add(sback, opt, cache, moved.adr, moved.fil, methode, referer_adr, referer_fil, 1) != -1) { // OK
|
||||||
hts_log_print(opt, LOG_DEBUG,
|
hts_log_print(opt, LOG_DEBUG,
|
||||||
"(during prefetch) %s (%d) to link %s at %s%s",
|
"(during prefetch) %s (%d) to link %s at %s%s",
|
||||||
@@ -785,10 +696,30 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
// libérer emplacement backing
|
// libérer emplacement backing
|
||||||
}
|
}
|
||||||
|
|
||||||
// no error: change the type?
|
{ // pas d'erreur, changer type?
|
||||||
ext_chg = resolve_extension(
|
char s[16];
|
||||||
opt, NULL, back[b].r.cdispo, back[b].r.contenttype,
|
|
||||||
back[b].url_fil, ext, sizeof(ext));
|
s[0] = '\0';
|
||||||
|
if (strnotempty(back[b].r.cdispo)) { /* filename given */
|
||||||
|
ext_chg = 2; /* change filename */
|
||||||
|
strcpybuff(ext, back[b].r.cdispo);
|
||||||
|
} else if (wire_patches_ext(opt, back[b].r.contenttype,
|
||||||
|
back[b].url_fil)) {
|
||||||
|
if (give_mimext(
|
||||||
|
s, sizeof(s),
|
||||||
|
back[b].r.contenttype)) { // recognized extension
|
||||||
|
ext_chg = 1;
|
||||||
|
strcpybuff(ext, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEFAULT_BIN_EXT
|
||||||
|
// no extension and potentially bogus
|
||||||
|
else if (ishtest == -2) {
|
||||||
|
ext_chg = 1;
|
||||||
|
strcpybuff(ext, DEFAULT_BIN_EXT + 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// FIN Si non déplacé, forcer type?
|
// FIN Si non déplacé, forcer type?
|
||||||
|
|
||||||
@@ -1332,7 +1263,8 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
|
|
||||||
while((a > afs->save) && (*a != '.') && (*a != '/'))
|
while((a > afs->save) && (*a != '.') && (*a != '/'))
|
||||||
a--;
|
a--;
|
||||||
if (*a != '.') { // agh pas de point
|
if (*a != '.') { // agh pas de point
|
||||||
|
//strcatbuff(save,".none"); // a éviter
|
||||||
strcatbuff(afs->save, ".html"); // préférable!
|
strcatbuff(afs->save, ".html"); // préférable!
|
||||||
hts_log_print(opt, LOG_DEBUG, "Default HTML type set for %s%s => %s",
|
hts_log_print(opt, LOG_DEBUG, "Default HTML type set for %s%s => %s",
|
||||||
adr_complete, fil_complete, afs->save);
|
adr_complete, fil_complete, afs->save);
|
||||||
@@ -1470,6 +1402,17 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
fil_simplifie(afs->save);
|
fil_simplifie(afs->save);
|
||||||
|
|
||||||
/* convert name to UTF-8 ? Note: already done while parsing. */
|
/* convert name to UTF-8 ? Note: already done while parsing. */
|
||||||
|
//if (charset != NULL && charset[0] != '\0') {
|
||||||
|
// char *const s = hts_convertStringToUTF8(save, (int) strlen(save), charset);
|
||||||
|
|
||||||
|
// if (s != NULL) {
|
||||||
|
// hts_log_print(opt, LOG_DEBUG,
|
||||||
|
// "engine: save-name: charset conversion from '%s' to '%s' using charset '%s'",
|
||||||
|
// save, s, charset);
|
||||||
|
// strcpybuff(save, s);
|
||||||
|
// free(s);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
/* callback */
|
/* callback */
|
||||||
RUN_CALLBACK5(opt, savename, adr_complete, fil_complete, referer_adr,
|
RUN_CALLBACK5(opt, savename, adr_complete, fil_complete, referer_adr,
|
||||||
@@ -1617,6 +1560,10 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
int sameAdr = (strfield2(heap(i)->adr, normadr) != 0);
|
int sameAdr = (strfield2(heap(i)->adr, normadr) != 0);
|
||||||
int sameFil;
|
int sameFil;
|
||||||
|
|
||||||
|
// NO - URL hack is only for stripping // and www.
|
||||||
|
//if (opt->urlhack != 0)
|
||||||
|
// sameFil = ( strfield2(heap(i)->fil, normfil) != 0);
|
||||||
|
//else
|
||||||
sameFil = (strcmp(heap(i)->fil, normfil) == 0);
|
sameFil = (strcmp(heap(i)->fil, normfil) == 0);
|
||||||
if (sameAdr && sameFil) { // ok c'est le même lien, adresse déja définie
|
if (sameAdr && sameFil) { // ok c'est le même lien, adresse déja définie
|
||||||
/* Take the existing name not to screw up with cAsE sEnSiTiViTy of Linux/Unix */
|
/* Take the existing name not to screw up with cAsE sEnSiTiViTy of Linux/Unix */
|
||||||
@@ -1682,13 +1629,17 @@ int url_savename(lien_adrfilsave *const afs,
|
|||||||
|
|
||||||
strcpybuff(afs->save, tempo);
|
strcpybuff(afs->save, tempo);
|
||||||
|
|
||||||
|
//printf("switched: %s\n",save);
|
||||||
|
|
||||||
} // if
|
} // if
|
||||||
}
|
}
|
||||||
#if DEBUG_SAVENAME
|
#if DEBUG_SAVENAME
|
||||||
printf("\nEnd search, %s\n", fil_complete);
|
printf("\nEnd search, %s\n", fil_complete);
|
||||||
#endif
|
#endif
|
||||||
} while (!nom_ok);
|
} while(!nom_ok);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
//printf("'%s' %s %s\n",save,adr,fil);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,8 +100,6 @@ void standard_name(char *b, size_t bsize, const char *dot_pos,
|
|||||||
const char *nom_pos, const char *fil_complete,
|
const char *nom_pos, const char *fil_complete,
|
||||||
int short_ver);
|
int short_ver);
|
||||||
void url_savename_addstr(char *d, const char *s);
|
void url_savename_addstr(char *d, const char *s);
|
||||||
/* Contested wire-vs-ext verdict that a body sniff could settle (htssniff.h). */
|
|
||||||
int hts_ext_sniff_wanted(httrackp *opt, const char *wiremime, const char *file);
|
|
||||||
char *url_md5(char *digest_buffer, const char *fil_complete);
|
char *url_md5(char *digest_buffer, const char *fil_complete);
|
||||||
void url_savename_refname(const char *adr, const char *fil, char *filename);
|
void url_savename_refname(const char *adr, const char *fil, char *filename);
|
||||||
char *url_savename_refname_fullpath(httrackp * opt, const char *adr,
|
char *url_savename_refname_fullpath(httrackp * opt, const char *adr,
|
||||||
|
|||||||
15
src/htsopt.h
15
src/htsopt.h
@@ -105,6 +105,7 @@ typedef struct htsfilters htsfilters;
|
|||||||
struct htsfilters {
|
struct htsfilters {
|
||||||
char ***filters; /**< pointer to the +/-pattern filter array */
|
char ***filters; /**< pointer to the +/-pattern filter array */
|
||||||
int *filptr; /**< pointer to the current filter count */
|
int *filptr; /**< pointer to the current filter count */
|
||||||
|
// int* filter_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* User callbacks chain */
|
/* User callbacks chain */
|
||||||
@@ -439,6 +440,7 @@ struct httrackp {
|
|||||||
float maxconn; /**< max connections per second */
|
float maxconn; /**< max connections per second */
|
||||||
int waittime; /**< scheduled start time (wall-clock seconds) */
|
int waittime; /**< scheduled start time (wall-clock seconds) */
|
||||||
hts_cachemode cache; /**< cache generation mode */
|
hts_cachemode cache; /**< cache generation mode */
|
||||||
|
// int aff_progress; // progress bar
|
||||||
hts_boolean shell; /**< driven by a shell over stdin/stdout pipes */
|
hts_boolean shell; /**< driven by a shell over stdin/stdout pipes */
|
||||||
t_proxy proxy; /**< proxy configuration */
|
t_proxy proxy; /**< proxy configuration */
|
||||||
hts_savename_83
|
hts_savename_83
|
||||||
@@ -490,6 +492,7 @@ struct httrackp {
|
|||||||
hts_verbosedisplay verbosedisplay; /**< animated text progress display */
|
hts_verbosedisplay verbosedisplay; /**< animated text progress display */
|
||||||
String footer; /**< footer/info line injected into pages */
|
String footer; /**< footer/info line injected into pages */
|
||||||
int maxcache; /**< in-memory cache backing limit (bytes) */
|
int maxcache; /**< in-memory cache backing limit (bytes) */
|
||||||
|
// int maxcache_anticipate; // maximum links to anticipate (upper bound)
|
||||||
hts_boolean ftp_proxy; /**< use the HTTP proxy for FTP too */
|
hts_boolean ftp_proxy; /**< use the HTTP proxy for FTP too */
|
||||||
String filelist; /**< file listing URLs to include */
|
String filelist; /**< file listing URLs to include */
|
||||||
String urllist; /**< file listing filters to include */
|
String urllist; /**< file listing filters to include */
|
||||||
@@ -532,12 +535,6 @@ struct httrackp {
|
|||||||
no_www_dedup; /**< with urlhack, keep www.host distinct from host */
|
no_www_dedup; /**< with urlhack, keep www.host distinct from host */
|
||||||
hts_boolean no_slash_dedup; /**< with urlhack, keep redundant // in paths */
|
hts_boolean no_slash_dedup; /**< with urlhack, keep redundant // in paths */
|
||||||
hts_boolean no_query_dedup; /**< with urlhack, keep query-argument order */
|
hts_boolean no_query_dedup; /**< with urlhack, keep query-argument order */
|
||||||
String cookies_file; /**< extra Netscape cookies.txt to preload
|
|
||||||
(--cookies-file) */
|
|
||||||
int pause_min_ms; /**< inter-file pause lower bound, ms (0=off, #185) */
|
|
||||||
int pause_max_ms; /**< inter-file pause upper bound, ms */
|
|
||||||
String why_url; /**< URL to diagnose (--why): print the deciding filter rule
|
|
||||||
and exit without crawling */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Running statistics for a mirror. */
|
/* Running statistics for a mirror. */
|
||||||
@@ -548,6 +545,8 @@ typedef struct hts_stat_struct hts_stat_struct;
|
|||||||
struct hts_stat_struct {
|
struct hts_stat_struct {
|
||||||
LLint HTS_TOTAL_RECV; /**< total bytes received from the network */
|
LLint HTS_TOTAL_RECV; /**< total bytes received from the network */
|
||||||
LLint stat_bytes; /**< total bytes written to disk */
|
LLint stat_bytes; /**< total bytes written to disk */
|
||||||
|
// int HTS_TOTAL_RECV_STATE; // status: 0 ok 1: slow down a little 2: slow
|
||||||
|
// down 3: a lot
|
||||||
TStamp stat_timestart; /**< mirror start time */
|
TStamp stat_timestart; /**< mirror start time */
|
||||||
//
|
//
|
||||||
LLint total_packed; /**< compressed bytes received (on the wire) */
|
LLint total_packed; /**< compressed bytes received (on the wire) */
|
||||||
@@ -679,6 +678,7 @@ struct lien_url {
|
|||||||
int depth; /**< remaining allowed depth; >0 strong, 0 weak */
|
int depth; /**< remaining allowed depth; >0 strong, 0 weak */
|
||||||
int pass2; /**< second-pass marker; -1 means handled in background */
|
int pass2; /**< second-pass marker; -1 means handled in background */
|
||||||
char link_import; /**< imported after a move; skip the usual up/down rules */
|
char link_import; /**< imported after a move; skip the usual up/down rules */
|
||||||
|
// int moved; // pointer to moved
|
||||||
int retry; /**< remaining retries */
|
int retry; /**< remaining retries */
|
||||||
int testmode; /**< test only: send just a HEAD */
|
int testmode; /**< test only: send just a HEAD */
|
||||||
};
|
};
|
||||||
@@ -723,6 +723,9 @@ struct lien_back {
|
|||||||
LLint chunk_size; /**< size of the chunk being loaded */
|
LLint chunk_size; /**< size of the chunk being loaded */
|
||||||
LLint chunk_blocksize; /**< data size declared by the chunk */
|
LLint chunk_blocksize; /**< data size declared by the chunk */
|
||||||
LLint compressed_size; /**< compressed size (stats only) */
|
LLint compressed_size; /**< compressed size (stats only) */
|
||||||
|
//
|
||||||
|
// int links_index; // to access liens[links_index]
|
||||||
|
//
|
||||||
char info[256]; /**< status text, e.g. for FTP */
|
char info[256]; /**< status text, e.g. for FTP */
|
||||||
int stop_ftp; /**< stop flag for FTP */
|
int stop_ftp; /**< stop flag for FTP */
|
||||||
int finalized; /**< finalized (memory optimization) */
|
int finalized; /**< finalized (memory optimization) */
|
||||||
|
|||||||
837
src/htsparse.c
837
src/htsparse.c
File diff suppressed because it is too large
Load Diff
@@ -66,6 +66,7 @@ struct htsmoduleStructExtended {
|
|||||||
char ***filters_;
|
char ***filters_;
|
||||||
robots_wizard *robots_;
|
robots_wizard *robots_;
|
||||||
hash_struct *hash_;
|
hash_struct *hash_;
|
||||||
|
//int *lien_max_;
|
||||||
|
|
||||||
/* Base & codebase */
|
/* Base & codebase */
|
||||||
char *base;
|
char *base;
|
||||||
@@ -115,19 +116,6 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre);
|
|||||||
int hts_mirror_check_moved(htsmoduleStruct * str,
|
int hts_mirror_check_moved(htsmoduleStruct * str,
|
||||||
htsmoduleStructExtended * stre);
|
htsmoduleStructExtended * stre);
|
||||||
|
|
||||||
/*
|
|
||||||
Non-zero if a redirect (cur_adr,cur_fil)->(moved_adr,moved_fil) saves to the
|
|
||||||
same local file, so it must be followed rather than turned into a
|
|
||||||
self-pointing "moved" stub (#159). Mirrors the savename: scheme+userinfo
|
|
||||||
stripped, www kept (www dedup is the crawl layer's job), path
|
|
||||||
slash/query-normalized per the URL-hack flags. Not hash_url_equals: that keys
|
|
||||||
on the dedup hash, which folds www and never collapses http<->https.
|
|
||||||
*/
|
|
||||||
hts_boolean hts_redirect_same_savefile(httrackp *opt, const char *cur_adr,
|
|
||||||
const char *cur_fil,
|
|
||||||
const char *moved_adr,
|
|
||||||
const char *moved_fil);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Process user intercations: pause, add link, delete link..
|
Process user intercations: pause, add link, delete link..
|
||||||
*/
|
*/
|
||||||
@@ -174,4 +162,27 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
|
|||||||
/* Apply changes */ \
|
/* Apply changes */ \
|
||||||
* str->ptr_ = ptr
|
* str->ptr_ = ptr
|
||||||
|
|
||||||
|
#define WAIT_FOR_AVAILABLE_SOCKET() do { \
|
||||||
|
int prev = opt->state._hts_in_html_parsing; \
|
||||||
|
while(back_pluggable_sockets_strict(sback, opt) <= 0) { \
|
||||||
|
opt->state._hts_in_html_parsing = 6; \
|
||||||
|
/* Wait .. */ \
|
||||||
|
back_wait(sback,opt,cache,0); \
|
||||||
|
/* Transfer rate */ \
|
||||||
|
engine_stats(); \
|
||||||
|
/* Refresh various stats */ \
|
||||||
|
HTS_STAT.stat_nsocket=back_nsoc(sback); \
|
||||||
|
HTS_STAT.stat_errors=fspc(opt,NULL,"error"); \
|
||||||
|
HTS_STAT.stat_warnings=fspc(opt,NULL,"warning"); \
|
||||||
|
HTS_STAT.stat_infos=fspc(opt,NULL,"info"); \
|
||||||
|
HTS_STAT.nbk=backlinks_done(sback,opt->liens,opt->lien_tot,ptr); \
|
||||||
|
HTS_STAT.nb=back_transferred(HTS_STAT.stat_bytes,sback); \
|
||||||
|
/* Check */ \
|
||||||
|
if (!RUN_CALLBACK7(opt, loop, sback->lnk, sback->count, -1,ptr,opt->lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
opt->state._hts_in_html_parsing = prev; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
167
src/htsrobots.c
167
src/htsrobots.c
@@ -44,84 +44,28 @@ Please visit our Website: http://www.httrack.com
|
|||||||
|
|
||||||
// -- robots --
|
// -- robots --
|
||||||
|
|
||||||
/* RFC 9309 path-prefix match; '*' any run, '$' anchors end; linear. */
|
|
||||||
static hts_boolean robots_pattern_match(const char *pattern, const char *path) {
|
|
||||||
size_t patlen = strlen(pattern);
|
|
||||||
hts_boolean anchored = HTS_FALSE;
|
|
||||||
const char *p, *pend, *s;
|
|
||||||
const char *star = NULL, *star_s = NULL;
|
|
||||||
|
|
||||||
if (patlen > 0 && pattern[patlen - 1] == '$') {
|
|
||||||
anchored = HTS_TRUE;
|
|
||||||
patlen--;
|
|
||||||
}
|
|
||||||
p = pattern;
|
|
||||||
pend = pattern + patlen;
|
|
||||||
s = path;
|
|
||||||
while (*s != '\0') {
|
|
||||||
if (p == pend) {
|
|
||||||
if (!anchored)
|
|
||||||
return HTS_TRUE; // prefix matched
|
|
||||||
if (star != NULL) { // anchored: '*' must eat the rest
|
|
||||||
p = star + 1;
|
|
||||||
s = ++star_s;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return HTS_FALSE;
|
|
||||||
}
|
|
||||||
if (*p == '*') {
|
|
||||||
star = p++;
|
|
||||||
star_s = s;
|
|
||||||
} else if (*p == *s) {
|
|
||||||
p++;
|
|
||||||
s++;
|
|
||||||
} else if (star != NULL) {
|
|
||||||
p = star + 1;
|
|
||||||
s = ++star_s;
|
|
||||||
} else {
|
|
||||||
return HTS_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (p < pend && *p == '*')
|
|
||||||
p++;
|
|
||||||
return (p == pend) ? HTS_TRUE : HTS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fil="" : vérifier si règle déja enregistrée
|
// fil="" : vérifier si règle déja enregistrée
|
||||||
int checkrobots(robots_wizard * robots, const char *adr, const char *fil) {
|
int checkrobots(robots_wizard * robots, const char *adr, const char *fil) {
|
||||||
while(robots) {
|
while(robots) {
|
||||||
if (strfield2(robots->adr, adr)) {
|
if (strfield2(robots->adr, adr)) {
|
||||||
if (fil[0]) {
|
if (fil[0]) {
|
||||||
/* RFC 9309: longest pattern wins, Allow beats Disallow on ties. */
|
|
||||||
int ptr = 0;
|
int ptr = 0;
|
||||||
char line[HTS_ROBOTS_TOKEN_SIZE];
|
char line[250];
|
||||||
size_t toklen = strlen(robots->token);
|
|
||||||
size_t best_len = 0;
|
|
||||||
hts_boolean matched = HTS_FALSE;
|
|
||||||
hts_boolean best_allow = HTS_FALSE;
|
|
||||||
|
|
||||||
while (ptr < (int) toklen) {
|
if (strnotempty(robots->token)) {
|
||||||
ptr += binput(robots->token + ptr, line, sizeof(line) - 1);
|
do {
|
||||||
if (line[0] != 'A' && line[0] != 'D')
|
ptr += binput(robots->token + ptr, line, 200);
|
||||||
continue;
|
if (line[0] == '/') { // absolu
|
||||||
{
|
if (strfield(fil, line)) { // commence avec ligne
|
||||||
const hts_boolean is_allow =
|
return -1; // interdit
|
||||||
(line[0] == 'A') ? HTS_TRUE : HTS_FALSE;
|
}
|
||||||
const char *pat = line + 1;
|
} else { // relatif
|
||||||
|
if (strstrcase(fil, line)) {
|
||||||
if (robots_pattern_match(pat, fil)) {
|
return -1;
|
||||||
const size_t len = strlen(pat);
|
|
||||||
|
|
||||||
if (!matched || len > best_len || (len == best_len && is_allow)) {
|
|
||||||
matched = HTS_TRUE;
|
|
||||||
best_len = len;
|
|
||||||
best_allow = is_allow;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while((strnotempty(line)) && (ptr < (int) strlen(robots->token)));
|
||||||
}
|
}
|
||||||
if (matched && !best_allow)
|
|
||||||
return -1; // forbidden
|
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -130,93 +74,6 @@ int checkrobots(robots_wizard * robots, const char *adr, const char *fil) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Append "<marker><pattern>\n" to the bounded rule blob if it fits. */
|
|
||||||
static void robots_blob_add(char *blob, size_t blobsize, char marker,
|
|
||||||
const char *pat) {
|
|
||||||
const size_t used = strlen(blob);
|
|
||||||
const size_t need = strlen(pat) + 2; // marker + '\n'
|
|
||||||
|
|
||||||
if (need < blobsize - used) { // overflow-safe: used <= blobsize-1
|
|
||||||
blob[used] = marker;
|
|
||||||
blob[used + 1] = '\0';
|
|
||||||
strlcatbuff(blob, pat, blobsize);
|
|
||||||
strlcatbuff(blob, "\n", blobsize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void robots_parse(robots_wizard *robots, const char *adr, const char *body,
|
|
||||||
size_t bodysize, char *info, size_t infosize,
|
|
||||||
hts_boolean keep_root_disallow) {
|
|
||||||
size_t bptr = 0;
|
|
||||||
int record = 0;
|
|
||||||
char BIGSTK line[1024];
|
|
||||||
char BIGSTK blob[HTS_ROBOTS_TOKEN_SIZE];
|
|
||||||
|
|
||||||
blob[0] = '\0';
|
|
||||||
if (info != NULL && infosize > 0)
|
|
||||||
info[0] = '\0';
|
|
||||||
#if DEBUG_ROBOTS
|
|
||||||
printf("robots.txt dump:\n%s\n", body);
|
|
||||||
#endif
|
|
||||||
while (bptr < bodysize) {
|
|
||||||
char *comm;
|
|
||||||
int llen;
|
|
||||||
|
|
||||||
bptr += binput(body + bptr, line, sizeof(line) - 2);
|
|
||||||
comm = strchr(line, '#'); // strip comment
|
|
||||||
if (comm != NULL)
|
|
||||||
*comm = '\0';
|
|
||||||
llen = (int) strlen(line); // strip trailing spaces
|
|
||||||
while (llen > 0 && is_realspace(line[llen - 1])) {
|
|
||||||
line[llen - 1] = '\0';
|
|
||||||
llen--;
|
|
||||||
}
|
|
||||||
if (strfield(line, "user-agent:")) {
|
|
||||||
char *a = line + 11;
|
|
||||||
|
|
||||||
while (is_realspace(*a))
|
|
||||||
a++;
|
|
||||||
if (*a == '*') {
|
|
||||||
if (record != 2)
|
|
||||||
record = 1; // generic group applies to us
|
|
||||||
} else if (strfield(a, "httrack") || strfield(a, "winhttrack") ||
|
|
||||||
strfield(a, "webhttrack")) {
|
|
||||||
blob[0] = '\0'; // explicit group: restart capture
|
|
||||||
if (info != NULL && infosize > 0)
|
|
||||||
info[0] = '\0';
|
|
||||||
record = 2; // locked to the httrack group
|
|
||||||
} else
|
|
||||||
record = 0;
|
|
||||||
} else if (record) {
|
|
||||||
hts_boolean is_allow = strfield(line, "allow:");
|
|
||||||
hts_boolean is_disallow = !is_allow && strfield(line, "disallow:");
|
|
||||||
|
|
||||||
if (is_allow || is_disallow) {
|
|
||||||
char *a = line + (is_allow ? 6 : 9);
|
|
||||||
|
|
||||||
while (is_realspace(*a))
|
|
||||||
a++;
|
|
||||||
if (strnotempty(a)) {
|
|
||||||
if (is_disallow && !keep_root_disallow && strcmp(a, "/") == 0) {
|
|
||||||
// dropped: site-wide disallow ignored by option
|
|
||||||
} else {
|
|
||||||
robots_blob_add(blob, sizeof(blob), is_allow ? 'A' : 'D', a);
|
|
||||||
if (is_disallow && info != NULL &&
|
|
||||||
strlen(a) + 2 < infosize - strlen(info)) {
|
|
||||||
if (strnotempty(info))
|
|
||||||
strlcatbuff(info, ", ", infosize);
|
|
||||||
strlcatbuff(info, a, infosize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (strnotempty(blob))
|
|
||||||
checkrobots_set(robots, adr, blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
int checkrobots_set(robots_wizard * robots, const char *adr, const char *data) {
|
int checkrobots_set(robots_wizard * robots, const char *adr, const char *data) {
|
||||||
if (((int) strlen(adr)) >= sizeof(robots->adr) - 2)
|
if (((int) strlen(adr)) >= sizeof(robots->adr) - 2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -39,27 +39,17 @@ Please visit our Website: http://www.httrack.com
|
|||||||
#define HTS_DEF_FWSTRUCT_robots_wizard
|
#define HTS_DEF_FWSTRUCT_robots_wizard
|
||||||
typedef struct robots_wizard robots_wizard;
|
typedef struct robots_wizard robots_wizard;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Per-host blob: one rule per line, first byte 'A'/'D' then path pattern. */
|
|
||||||
#define HTS_ROBOTS_TOKEN_SIZE 4096
|
|
||||||
|
|
||||||
struct robots_wizard {
|
struct robots_wizard {
|
||||||
char adr[128];
|
char adr[128];
|
||||||
char token[HTS_ROBOTS_TOKEN_SIZE];
|
char token[4096];
|
||||||
struct robots_wizard *next;
|
struct robots_wizard *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Library internal definictions */
|
/* Library internal definictions */
|
||||||
#ifdef HTS_INTERNAL_BYTECODE
|
#ifdef HTS_INTERNAL_BYTECODE
|
||||||
/* -1 if `fil` disallowed for `adr` (RFC 9309); empty: -1 if rules exist. */
|
|
||||||
int checkrobots(robots_wizard * robots, const char *adr, const char *fil);
|
int checkrobots(robots_wizard * robots, const char *adr, const char *fil);
|
||||||
void checkrobots_free(robots_wizard * robots);
|
void checkrobots_free(robots_wizard * robots);
|
||||||
int checkrobots_set(robots_wizard * robots, const char *adr, const char *data);
|
int checkrobots_set(robots_wizard * robots, const char *adr, const char *data);
|
||||||
/* Parse robots.txt `body` for `adr`, storing the HTTrack group's rules; `info`
|
|
||||||
gets a disallow summary, `keep_root_disallow` FALSE drops "Disallow: /". */
|
|
||||||
void robots_parse(robots_wizard *robots, const char *adr, const char *body,
|
|
||||||
size_t bodysize, char *info, size_t infosize,
|
|
||||||
hts_boolean keep_root_disallow);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#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
|
||||||
|
|||||||
1096
src/htsselftest.c
1096
src/htsselftest.c
File diff suppressed because it is too large
Load Diff
@@ -265,6 +265,7 @@ T_SOC smallserver_init(int *port, char *adr) {
|
|||||||
SOCaddr_initport(server, *port);
|
SOCaddr_initport(server, *port);
|
||||||
if (bind(soc, &SOCaddr_sockaddr(server), SOCaddr_size(server)) == 0) {
|
if (bind(soc, &SOCaddr_sockaddr(server), SOCaddr_size(server)) == 0) {
|
||||||
if (listen(soc, 10) >= 0) {
|
if (listen(soc, 10) >= 0) {
|
||||||
|
// SOCaddr_inetntoa(adr, 128, server2);
|
||||||
strcpy(adr, h_loc);
|
strcpy(adr, h_loc);
|
||||||
} else {
|
} else {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -357,12 +358,12 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
|
|||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
initStrElt initStr[] = {
|
initStrElt initStr[] = {
|
||||||
{"user", HTS_DEFAULT_USER_AGENT},
|
{"user", "Mozilla/4.5 (compatible; HTTrack 3.0x; Windows 98)"},
|
||||||
{"footer", "<!-- Mirrored from %s%s by HTTrack Website Copier/3.x "
|
{"footer",
|
||||||
"[XR&CO'2014], %s -->"},
|
"<!-- Mirrored from %s%s by HTTrack Website Copier/3.x [XR&CO'2014], %s -->"},
|
||||||
{"url2",
|
{"url2", "+*.png +*.gif +*.jpg +*.jpeg +*.css +*.js -ad.doubleclick.net/*"},
|
||||||
"+*.png +*.gif +*.jpg +*.jpeg +*.css +*.js -ad.doubleclick.net/*"},
|
{NULL, NULL}
|
||||||
{NULL, NULL}};
|
};
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for(i = 0; initInt[i].name; i++) {
|
for(i = 0; initInt[i].name; i++) {
|
||||||
@@ -438,6 +439,7 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
|
|||||||
meth = 10;
|
meth = 10;
|
||||||
} else {
|
} else {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
// assert(FALSE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (meth) {
|
if (meth) {
|
||||||
@@ -1358,6 +1360,7 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
|
|||||||
|
|
||||||
StringCat(headers, error_hdr);
|
StringCat(headers, error_hdr);
|
||||||
StringCat(output, error);
|
StringCat(output, error);
|
||||||
|
//assert(file == NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1385,10 +1388,12 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
|
|||||||
!= StringLength(output)))
|
!= StringLength(output)))
|
||||||
) {
|
) {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
//assert(FALSE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
// assert(FALSE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1535,7 +1540,8 @@ static int htslang_load(char *limit_to, size_t limit_size, const char *path) {
|
|||||||
} while(strnotempty(test));
|
} while(strnotempty(test));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strnotempty(test)) { // éviter doublons
|
if (!strnotempty(test)) { // éviter doublons
|
||||||
|
// conv_printf(key,key);
|
||||||
const size_t len = strlen(intkey);
|
const size_t len = strlen(intkey);
|
||||||
char *const buff = (char *) malloc(len + 1);
|
char *const buff = (char *) malloc(len + 1);
|
||||||
|
|
||||||
@@ -1626,6 +1632,8 @@ static int htslang_load(char *limit_to, size_t limit_size, const char *path) {
|
|||||||
intkey = "";
|
intkey = "";
|
||||||
} else {
|
} else {
|
||||||
if (loops > 0) {
|
if (loops > 0) {
|
||||||
|
//err_msg += intkey;
|
||||||
|
//err_msg += " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1732,7 +1740,13 @@ static void LANG_DELETE(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sélection de la langue
|
// sélection de la langue
|
||||||
static void LANG_INIT(const char *path) { LANG_T(path, 0); }
|
static void LANG_INIT(const char *path) {
|
||||||
|
//CWinApp* pApp = AfxGetApp();
|
||||||
|
//if (pApp) {
|
||||||
|
/* pApp->GetProfileInt("Language","IntId",0); */
|
||||||
|
LANG_T(path, 0 /*pApp->GetProfileInt("Language","IntId",0) */ );
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
static int LANG_T(const char *path, int l) {
|
static int LANG_T(const char *path, int l) {
|
||||||
if (l >= 0) {
|
if (l >= 0) {
|
||||||
|
|||||||
352
src/htssniff.c
352
src/htssniff.c
@@ -1,352 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998-2017 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
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/>.
|
|
||||||
|
|
||||||
Important notes:
|
|
||||||
|
|
||||||
- We hereby ask people using this source NOT to use it in purpose of grabbing
|
|
||||||
emails addresses, or collecting any other private information on persons.
|
|
||||||
This would disgrace our work, and spoil the many hours we spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* File: MIME magic-byte consistency checks */
|
|
||||||
/* Author: Xavier Roche */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
|
|
||||||
#include "htssniff.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "htslib.h"
|
|
||||||
|
|
||||||
/* One magic rule: `len` bytes at `off` confirm `mime`. */
|
|
||||||
typedef struct sniff_magic {
|
|
||||||
const char *mime;
|
|
||||||
unsigned short off;
|
|
||||||
unsigned char len;
|
|
||||||
const char *bytes;
|
|
||||||
} sniff_magic;
|
|
||||||
|
|
||||||
/* Direction is mime -> magic (verify a claim, never classify); types with
|
|
||||||
no reliable magic (plain text, css, js..) are deliberately absent. Patterns
|
|
||||||
follow the WHATWG MIME Sniffing Standard tables where it defines them
|
|
||||||
(https://mimesniff.spec.whatwg.org/); the rest covers httrack's wider MIME
|
|
||||||
set. Spec-only types absent from our MIME tables (EOT, font/collection)
|
|
||||||
are omitted as unreachable. */
|
|
||||||
static const sniff_magic sniff_table[] = {
|
|
||||||
/* images */
|
|
||||||
{"image/jpeg", 0, 3, "\xff\xd8\xff"},
|
|
||||||
{"image/pipeg", 0, 3, "\xff\xd8\xff"},
|
|
||||||
{"image/pjpeg", 0, 3, "\xff\xd8\xff"},
|
|
||||||
{"image/png", 0, 8, "\x89PNG\r\n\x1a\n"},
|
|
||||||
{"image/gif", 0, 6, "GIF87a"},
|
|
||||||
{"image/gif", 0, 6, "GIF89a"},
|
|
||||||
{"image/bmp", 0, 2, "BM"},
|
|
||||||
{"image/tiff", 0, 4, "II*\0"},
|
|
||||||
{"image/tiff", 0, 4, "MM\0*"},
|
|
||||||
{"image/x-icon", 0, 4, "\0\0\1\0"},
|
|
||||||
{"image/x-icon", 0, 4, "\0\0\2\0"}, /* Windows cursor, per the spec */
|
|
||||||
{"image/x-portable-bitmap", 0, 2, "P1"},
|
|
||||||
{"image/x-portable-bitmap", 0, 2, "P4"},
|
|
||||||
{"image/x-portable-pixmap", 0, 2, "P3"},
|
|
||||||
{"image/x-portable-pixmap", 0, 2, "P6"},
|
|
||||||
{"image/x-xpixmap", 0, 9, "/* XPM */"},
|
|
||||||
{"image/x-xbitmap", 0, 7, "#define"},
|
|
||||||
{"image/x-rgb", 0, 2, "\x01\xda"},
|
|
||||||
{"image/x-cmu-raster", 0, 4, "\xf1\x00\x40\xbb"},
|
|
||||||
/* audio */
|
|
||||||
{"audio/mpeg", 0, 3, "ID3"},
|
|
||||||
{"audio/basic", 0, 4, ".snd"},
|
|
||||||
{"audio/mid", 0, 8, "MThd\0\0\0\6"},
|
|
||||||
{"audio/midi", 0, 8, "MThd\0\0\0\6"},
|
|
||||||
{"audio/x-pn-realaudio", 0, 4, ".ra\xfd"},
|
|
||||||
{"audio/x-pn-realaudio", 0, 4, ".RMF"},
|
|
||||||
{"audio/x-pn-realaudio-plugin", 0, 4, ".ra\xfd"},
|
|
||||||
{"audio/x-pn-realaudio-plugin", 0, 4, ".RMF"},
|
|
||||||
{"audio/flac", 0, 4, "fLaC"},
|
|
||||||
{"audio/aac", 0, 4, "ADIF"},
|
|
||||||
/* video */
|
|
||||||
{"video/mpeg", 0, 4, "\x00\x00\x01\xba"},
|
|
||||||
{"video/mpeg", 0, 4, "\x00\x00\x01\xb3"},
|
|
||||||
{"video/x-sgi-movie", 0, 4, "MOVI"},
|
|
||||||
/* archives / compression */
|
|
||||||
{"application/x-gzip", 0, 3, "\x1f\x8b\x08"},
|
|
||||||
{"multipart/x-gzip", 0, 3, "\x1f\x8b\x08"},
|
|
||||||
{"application/x-compressed", 0, 3, "\x1f\x8b\x08"},
|
|
||||||
{"application/x-compress", 0, 2, "\x1f\x9d"},
|
|
||||||
{"application/x-bzip2", 0, 3, "BZh"},
|
|
||||||
{"application/x-7z-compressed", 0, 6, "7z\xbc\xaf\x27\x1c"},
|
|
||||||
/* 6-byte prefix common to RAR4 (spec) and RAR5 */
|
|
||||||
{"application/x-rar-compressed", 0, 6, "Rar!\x1a\x07"},
|
|
||||||
{"application/zstd", 0, 4, "\x28\xb5\x2f\xfd"},
|
|
||||||
{"application/arj", 0, 2, "\x60\xea"},
|
|
||||||
{"application/x-cpio", 0, 6, "070701"},
|
|
||||||
{"application/x-cpio", 0, 6, "070707"},
|
|
||||||
{"application/x-cpio", 0, 2, "\xc7\x71"},
|
|
||||||
{"application/x-sv4cpio", 0, 6, "070701"},
|
|
||||||
{"application/x-sv4crc", 0, 6, "070702"},
|
|
||||||
{"application/x-stuffit", 0, 8, "StuffIt "},
|
|
||||||
{"application/x-stuffit", 0, 4, "SIT!"},
|
|
||||||
{"application/mac-binhex40", 0, 10, "(This file"},
|
|
||||||
/* documents */
|
|
||||||
{"application/pdf", 0, 5, "%PDF-"},
|
|
||||||
{"application/postscript", 0, 2, "%!"},
|
|
||||||
{"application/rtf", 0, 5, "{\\rtf"},
|
|
||||||
{"application/x-dvi", 0, 2, "\xf7\x02"},
|
|
||||||
{"application/x-hdf", 0, 4, "\x0e\x03\x13\x01"},
|
|
||||||
{"application/x-hdf", 0, 8, "\x89HDF\r\n\x1a\n"},
|
|
||||||
{"application/x-netcdf", 0, 4, "CDF\x01"},
|
|
||||||
{"application/x-netcdf", 0, 4, "CDF\x02"},
|
|
||||||
{"application/x-msaccess", 0, 19, "\0\1\0\0Standard Jet DB"},
|
|
||||||
/* fonts */
|
|
||||||
{"font/woff", 0, 4, "wOFF"},
|
|
||||||
{"font/woff2", 0, 4, "wOF2"},
|
|
||||||
{"font/ttf", 0, 4, "\0\1\0\0"},
|
|
||||||
{"font/ttf", 0, 4, "true"},
|
|
||||||
{"font/otf", 0, 4, "OTTO"},
|
|
||||||
/* misc */
|
|
||||||
{"application/x-shockwave-flash", 0, 3, "FWS"},
|
|
||||||
{"application/x-shockwave-flash", 0, 3, "CWS"},
|
|
||||||
{"application/x-shockwave-flash", 0, 3, "ZWS"},
|
|
||||||
{"application/futuresplash", 0, 3, "FWS"},
|
|
||||||
{"application/x-director", 0, 4, "RIFX"},
|
|
||||||
{"application/x-director", 0, 4, "XFIR"},
|
|
||||||
{"application/x-java-vm", 0, 4, "\xca\xfe\xba\xbe"},
|
|
||||||
{"application/wasm", 0, 4, "\0asm"},
|
|
||||||
{"application/x-msmetafile", 0, 4, "\xd7\xcd\xc6\x9a"},
|
|
||||||
{"application/x-msmetafile", 0, 4, "\x01\x00\x09\x00"},
|
|
||||||
{"application/x-x509-ca-cert", 0, 2, "\x30\x82"},
|
|
||||||
{"application/x-pkcs12", 0, 2, "\x30\x82"},
|
|
||||||
{"application/x-pkcs7-mime", 0, 2, "\x30\x82"},
|
|
||||||
{"application/x-pkcs7-signature", 0, 2, "\x30\x82"},
|
|
||||||
{"application/x-pkcs7-certificates", 0, 2, "\x30\x82"},
|
|
||||||
{"x-world/x-vrml", 0, 5, "#VRML"},
|
|
||||||
{"application/x-bittorrent", 0, 11, "d8:announce"},
|
|
||||||
{"drawing/x-dwf", 0, 4, "(DWF"},
|
|
||||||
{"application/acad", 0, 4, "AC10"},
|
|
||||||
{NULL, 0, 0, NULL}};
|
|
||||||
|
|
||||||
/* MIME families sharing a container magic */
|
|
||||||
static const char *const zip_mimes[] = {
|
|
||||||
"application/zip", "application/x-zip-compressed", "multipart/x-zip", NULL};
|
|
||||||
static const char *const zip_mime_prefixes[] = {
|
|
||||||
"application/vnd.openxmlformats-officedocument.",
|
|
||||||
"application/vnd.oasis.opendocument.", NULL};
|
|
||||||
static const char *const ole_mimes[] = {"application/msword",
|
|
||||||
"application/excel",
|
|
||||||
"application/vnd.ms-excel",
|
|
||||||
"application/powerpoint",
|
|
||||||
"application/vnd.ms-powerpoint",
|
|
||||||
"application/vnd.ms-project",
|
|
||||||
"application/vnd.ms-works",
|
|
||||||
"application/x-msmoney",
|
|
||||||
"application/x-mspublisher",
|
|
||||||
NULL};
|
|
||||||
static const char *const tar_mimes[] = {
|
|
||||||
"application/x-tar", "application/x-ustar", "application/x-gtar", NULL};
|
|
||||||
static const char *const ogg_mimes[] = {"application/ogg", "audio/ogg",
|
|
||||||
"video/ogg", "audio/opus", NULL};
|
|
||||||
static const char *const ebml_mimes[] = {"video/webm", "audio/webm", NULL};
|
|
||||||
/* ISO-BMFF, any 'ftyp' brand: containers overlap too much to split */
|
|
||||||
static const char *const bmff_mimes[] = {"video/mp4", "audio/mp4",
|
|
||||||
"video/quicktime", NULL};
|
|
||||||
static const char *const avif_mimes[] = {"image/avif", NULL};
|
|
||||||
static const char *const heic_mimes[] = {"image/heic", NULL};
|
|
||||||
static const char *const asf_mimes[] = {"video/x-ms-asf", "video/x-ms-wmv",
|
|
||||||
"video/x-la-asf", NULL};
|
|
||||||
static const char *const xml_mimes[] = {"application/xml", "text/xml",
|
|
||||||
"image/svg+xml", "image/svg-xml", NULL};
|
|
||||||
static const char *const svg_mimes[] = {"image/svg+xml", "image/svg-xml", NULL};
|
|
||||||
static const char *const html_mimes[] = {"text/html", NULL};
|
|
||||||
static const char *const pem_mimes[] = {
|
|
||||||
"application/x-x509-ca-cert", "application/x-pkcs7-certificates",
|
|
||||||
"application/x-pkcs7-mime", "application/x-pkcs7-signature", NULL};
|
|
||||||
|
|
||||||
static hts_boolean mime_in(const char *const *list, const char *mime) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; list[i] != NULL; i++)
|
|
||||||
if (strfield2(list[i], mime))
|
|
||||||
return HTS_TRUE;
|
|
||||||
return HTS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static hts_boolean mime_in_prefix(const char *const *list, const char *mime) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; list[i] != NULL; i++)
|
|
||||||
if (strfield(mime, list[i]))
|
|
||||||
return HTS_TRUE;
|
|
||||||
return HTS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static hts_boolean has_bytes(const unsigned char *d, size_t n, size_t off,
|
|
||||||
const char *bytes, size_t len) {
|
|
||||||
/* overflow-safe: untrusted n alone on one side */
|
|
||||||
return n >= off && len <= n - off && memcmp(d + off, bytes, len) == 0
|
|
||||||
? HTS_TRUE
|
|
||||||
: HTS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char ascii_lower(unsigned char c) {
|
|
||||||
return c >= 'A' && c <= 'Z' ? (unsigned char) (c + 32) : c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Case-insensitive text prefix after an optional UTF-8 BOM and whitespace. */
|
|
||||||
static hts_boolean has_text_prefix(const unsigned char *d, size_t n,
|
|
||||||
const char *prefix) {
|
|
||||||
const size_t len = strlen(prefix);
|
|
||||||
size_t i, k;
|
|
||||||
|
|
||||||
i = n >= 3 && memcmp(d, "\xef\xbb\xbf", 3) == 0 ? 3 : 0;
|
|
||||||
while (i < n && (d[i] == ' ' || d[i] == '\t' || d[i] == '\r' || d[i] == '\n'))
|
|
||||||
i++;
|
|
||||||
if (len > n - i) /* i <= n from the loop above */
|
|
||||||
return HTS_FALSE;
|
|
||||||
for (k = 0; k < len; k++)
|
|
||||||
if (ascii_lower(d[i + k]) != ascii_lower((unsigned char) prefix[k]))
|
|
||||||
return HTS_FALSE;
|
|
||||||
return HTS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum sniff_op {
|
|
||||||
SNIFF_QUERY_KNOWN, /* is any rule defined for this MIME? */
|
|
||||||
SNIFF_QUERY_MATCH /* do the bytes confirm this MIME? */
|
|
||||||
} sniff_op;
|
|
||||||
|
|
||||||
/* Single walk for both queries so the rule set can't drift apart. */
|
|
||||||
static hts_boolean sniff_eval(sniff_op op, const unsigned char *d, size_t n,
|
|
||||||
const char *mime) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* KNOWN short-circuits; MATCH tests the magic */
|
|
||||||
#define SNIFF_RULE(cond) \
|
|
||||||
do { \
|
|
||||||
if (op == SNIFF_QUERY_KNOWN) \
|
|
||||||
return HTS_TRUE; \
|
|
||||||
if (cond) \
|
|
||||||
return HTS_TRUE; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
for (i = 0; sniff_table[i].mime != NULL; i++) {
|
|
||||||
if (strfield2(sniff_table[i].mime, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, sniff_table[i].off, sniff_table[i].bytes,
|
|
||||||
sniff_table[i].len));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mime_in(zip_mimes, mime) || mime_in_prefix(zip_mime_prefixes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "PK\3\4", 4) ||
|
|
||||||
has_bytes(d, n, 0, "PK\5\6", 4));
|
|
||||||
}
|
|
||||||
if (mime_in(ole_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1", 8));
|
|
||||||
}
|
|
||||||
if (mime_in(tar_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 257, "ustar", 5));
|
|
||||||
}
|
|
||||||
if (mime_in(ogg_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "OggS\0", 5));
|
|
||||||
}
|
|
||||||
if (mime_in(ebml_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "\x1a\x45\xdf\xa3", 4));
|
|
||||||
}
|
|
||||||
if (mime_in(bmff_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 4, "ftyp", 4));
|
|
||||||
}
|
|
||||||
if (mime_in(avif_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 4, "ftypavif", 8) ||
|
|
||||||
has_bytes(d, n, 4, "ftypavis", 8));
|
|
||||||
}
|
|
||||||
if (mime_in(heic_mimes, mime)) {
|
|
||||||
SNIFF_RULE(
|
|
||||||
has_bytes(d, n, 4, "ftyphei", 7) || has_bytes(d, n, 4, "ftyphev", 7) ||
|
|
||||||
has_bytes(d, n, 4, "ftypmif1", 8) || has_bytes(d, n, 4, "ftypmsf1", 8));
|
|
||||||
}
|
|
||||||
if (mime_in(asf_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "\x30\x26\xb2\x75\x8e\x66\xcf\x11", 8));
|
|
||||||
}
|
|
||||||
if (strfield2("audio/x-wav", mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "RIFF", 4) && has_bytes(d, n, 8, "WAVE", 4));
|
|
||||||
}
|
|
||||||
if (strfield2("video/x-msvideo", mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "RIFF", 4) && has_bytes(d, n, 8, "AVI ", 4));
|
|
||||||
}
|
|
||||||
if (strfield2("image/webp", mime)) {
|
|
||||||
SNIFF_RULE(has_bytes(d, n, 0, "RIFF", 4) &&
|
|
||||||
has_bytes(d, n, 8, "WEBPVP", 6));
|
|
||||||
}
|
|
||||||
if (strfield2("image/x-portable-anymap", mime)) {
|
|
||||||
SNIFF_RULE(n >= 2 && d[0] == 'P' && d[1] >= '1' && d[1] <= '6');
|
|
||||||
}
|
|
||||||
if (strfield2("audio/x-aiff", mime)) {
|
|
||||||
SNIFF_RULE(
|
|
||||||
has_bytes(d, n, 0, "FORM", 4) &&
|
|
||||||
(has_bytes(d, n, 8, "AIFF", 4) || has_bytes(d, n, 8, "AIFC", 4)));
|
|
||||||
}
|
|
||||||
if (strfield2("audio/mpeg", mime)) {
|
|
||||||
/* MPEG audio frame sync (11 bits), valid layer and bitrate fields */
|
|
||||||
SNIFF_RULE(n >= 2 && d[0] == 0xff && (d[1] & 0xe0) == 0xe0 &&
|
|
||||||
(d[1] & 0x06) != 0);
|
|
||||||
}
|
|
||||||
if (strfield2("audio/aac", mime)) {
|
|
||||||
/* ADTS sync */
|
|
||||||
SNIFF_RULE(n >= 2 && d[0] == 0xff && (d[1] & 0xf6) == 0xf0);
|
|
||||||
}
|
|
||||||
if (strfield2("video/mp2t", mime)) {
|
|
||||||
SNIFF_RULE(n >= 1 && d[0] == 0x47 && (n <= 188 || d[188] == 0x47));
|
|
||||||
}
|
|
||||||
if (mime_in(xml_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_text_prefix(d, n, "<?xml"));
|
|
||||||
}
|
|
||||||
if (mime_in(svg_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_text_prefix(d, n, "<svg") ||
|
|
||||||
has_text_prefix(d, n, "<!DOCTYPE svg"));
|
|
||||||
}
|
|
||||||
if (mime_in(html_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_text_prefix(d, n, "<!DOCTYPE") ||
|
|
||||||
has_text_prefix(d, n, "<html") ||
|
|
||||||
has_text_prefix(d, n, "<head"));
|
|
||||||
}
|
|
||||||
if (mime_in(pem_mimes, mime)) {
|
|
||||||
SNIFF_RULE(has_text_prefix(d, n, "-----BEGIN"));
|
|
||||||
}
|
|
||||||
if (strfield2("audio/x-mpegurl", mime)) {
|
|
||||||
SNIFF_RULE(has_text_prefix(d, n, "#EXTM3U"));
|
|
||||||
}
|
|
||||||
if (strfield2("text/x-vcard", mime)) {
|
|
||||||
SNIFF_RULE(has_text_prefix(d, n, "BEGIN:VCARD"));
|
|
||||||
}
|
|
||||||
#undef SNIFF_RULE
|
|
||||||
return HTS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
hts_boolean hts_sniff_mime_known(const char *mime) {
|
|
||||||
if (mime == NULL || *mime == '\0')
|
|
||||||
return HTS_FALSE;
|
|
||||||
return sniff_eval(SNIFF_QUERY_KNOWN, NULL, 0, mime);
|
|
||||||
}
|
|
||||||
|
|
||||||
hts_boolean hts_sniff_mime_consistent(const void *data, size_t size,
|
|
||||||
const char *mime) {
|
|
||||||
if (data == NULL || size == 0 || mime == NULL || *mime == '\0')
|
|
||||||
return HTS_FALSE;
|
|
||||||
return sniff_eval(SNIFF_QUERY_MATCH, (const unsigned char *) data, size,
|
|
||||||
mime);
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/* ------------------------------------------------------------ */
|
|
||||||
/*
|
|
||||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
|
||||||
Copyright (C) 1998-2017 Xavier Roche and other contributors
|
|
||||||
|
|
||||||
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/>.
|
|
||||||
|
|
||||||
Important notes:
|
|
||||||
|
|
||||||
- We hereby ask people using this source NOT to use it in purpose of grabbing
|
|
||||||
emails addresses, or collecting any other private information on persons.
|
|
||||||
This would disgrace our work, and spoil the many hours we spent on it.
|
|
||||||
|
|
||||||
Please visit our Website: http://www.httrack.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* File: MIME magic-byte consistency checks */
|
|
||||||
/* Author: Xavier Roche */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
|
|
||||||
#ifndef HTSSNIFF_DEFH
|
|
||||||
#define HTSSNIFF_DEFH
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "htsglobal.h"
|
|
||||||
|
|
||||||
/* Leading-body window read to arbitrate a wire/extension MIME conflict. */
|
|
||||||
#define HTS_SNIFF_LEN 512
|
|
||||||
|
|
||||||
/* Can a magic rule ever confirm this MIME? (whether sniffing is worth it) */
|
|
||||||
hts_boolean hts_sniff_mime_known(const char *mime);
|
|
||||||
|
|
||||||
/* TRUE when the leading body bytes are consistent with the claimed MIME;
|
|
||||||
FALSE on unknown MIME, unknown magic, or too-short data (fail-safe). */
|
|
||||||
hts_boolean hts_sniff_mime_consistent(const void *data, size_t size,
|
|
||||||
const char *mime);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -121,6 +121,9 @@ struct String {
|
|||||||
/** Byte at POS (read/write). No bounds check; POS must be < StringLength. **/
|
/** Byte at POS (read/write). No bounds check; POS must be < StringLength. **/
|
||||||
#define StringSubRW(BLK, POS) (StringBuffRW(BLK)[POS])
|
#define StringSubRW(BLK, POS) (StringBuffRW(BLK)[POS])
|
||||||
|
|
||||||
|
/** Subcharacter (read/write) **/
|
||||||
|
#define StringSubRW(BLK, POS) (StringBuffRW(BLK)[POS])
|
||||||
|
|
||||||
/** Byte POS positions from the end (read). POS==1 is the last byte. **/
|
/** Byte POS positions from the end (read). POS==1 is the last byte. **/
|
||||||
#define StringRight(BLK, POS) (StringBuff(BLK)[StringLength(BLK) - POS])
|
#define StringRight(BLK, POS) (StringBuff(BLK)[StringLength(BLK) - POS])
|
||||||
|
|
||||||
@@ -188,9 +191,8 @@ HTS_STATIC char *StringBuffN_(String *blk, int size) {
|
|||||||
asserts SIZE fits the existing content; does not (re)allocate. **/
|
asserts SIZE fits the existing content; does not (re)allocate. **/
|
||||||
#define StringSetLength(BLK, SIZE) \
|
#define StringSetLength(BLK, SIZE) \
|
||||||
do { \
|
do { \
|
||||||
const int len__ = (SIZE); /* signed: negative means strlen(buffer_) */ \
|
if (SIZE >= 0) { \
|
||||||
if (len__ >= 0) { \
|
(BLK).length_ = SIZE; \
|
||||||
(BLK).length_ = len__; \
|
|
||||||
} else { \
|
} else { \
|
||||||
(BLK).length_ = strlen((BLK).buffer_); \
|
(BLK).length_ = strlen((BLK).buffer_); \
|
||||||
} \
|
} \
|
||||||
@@ -306,11 +308,10 @@ HTS_STATIC void StringAttach(String *blk, char **str) {
|
|||||||
#define StringCatN(BLK, STR, SIZE) \
|
#define StringCatN(BLK, STR, SIZE) \
|
||||||
do { \
|
do { \
|
||||||
const char *str__ = (STR); \
|
const char *str__ = (STR); \
|
||||||
const size_t usize__ = (SIZE); \
|
|
||||||
if (str__ != NULL) { \
|
if (str__ != NULL) { \
|
||||||
size_t size__ = strlen(str__); \
|
size_t size__ = strlen(str__); \
|
||||||
if (size__ > usize__) { \
|
if (size__ > (SIZE)) { \
|
||||||
size__ = usize__; \
|
size__ = (SIZE); \
|
||||||
} \
|
} \
|
||||||
StringMemcat(BLK, str__, size__); \
|
StringMemcat(BLK, str__, size__); \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -68,6 +68,16 @@ struct find_handle_struct {
|
|||||||
char path[2048];
|
char path[2048];
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
//#ifndef HTS_DEF_FWSTRUCT_topindex_chain
|
||||||
|
//#define HTS_DEF_FWSTRUCT_topindex_chain
|
||||||
|
//typedef struct topindex_chain topindex_chain;
|
||||||
|
//#endif
|
||||||
|
//struct topindex_chain {
|
||||||
|
// int level; /* sort level */
|
||||||
|
// char *category; /* category */
|
||||||
|
// char name[2048]; /* path */
|
||||||
|
// struct topindex_chain *next; /* next element */
|
||||||
|
//};
|
||||||
|
|
||||||
/* Tools */
|
/* Tools */
|
||||||
|
|
||||||
@@ -283,6 +293,7 @@ int lienrelatif(char *s, size_t ssize, const char *link, const char *curr_fil) {
|
|||||||
char BIGSTK newcurr_fil[HTS_URLMAXSIZE * 2], newlink[HTS_URLMAXSIZE * 2];
|
char BIGSTK newcurr_fil[HTS_URLMAXSIZE * 2], newlink[HTS_URLMAXSIZE * 2];
|
||||||
char *curr;
|
char *curr;
|
||||||
|
|
||||||
|
//int n=0;
|
||||||
char *a;
|
char *a;
|
||||||
int slash = 0;
|
int slash = 0;
|
||||||
|
|
||||||
@@ -327,6 +338,7 @@ int lienrelatif(char *s, size_t ssize, const char *link, const char *curr_fil) {
|
|||||||
if (*curr == '/')
|
if (*curr == '/')
|
||||||
curr++;
|
curr++;
|
||||||
l = link;
|
l = link;
|
||||||
|
//c=curr;
|
||||||
// couper ce qui est commun
|
// couper ce qui est commun
|
||||||
while((streql(*link, *curr)) && (*link != 0)) {
|
while((streql(*link, *curr)) && (*link != 0)) {
|
||||||
link++;
|
link++;
|
||||||
@@ -338,6 +350,8 @@ int lienrelatif(char *s, size_t ssize, const char *link, const char *curr_fil) {
|
|||||||
link--;
|
link--;
|
||||||
curr--;
|
curr--;
|
||||||
}
|
}
|
||||||
|
//if (*link=='/') link++;
|
||||||
|
//if (*curr=='/') curr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculer la profondeur du répertoire courant et remonter
|
// calculer la profondeur du répertoire courant et remonter
|
||||||
@@ -348,6 +362,7 @@ int lienrelatif(char *s, size_t ssize, const char *link, const char *curr_fil) {
|
|||||||
while(*a)
|
while(*a)
|
||||||
if (*(a++) == '/')
|
if (*(a++) == '/')
|
||||||
strlcatbuff(s, "../", ssize);
|
strlcatbuff(s, "../", ssize);
|
||||||
|
//if (strlen(s)==0) strcatbuff(s,"/");
|
||||||
|
|
||||||
if (slash)
|
if (slash)
|
||||||
strlcatbuff(s, "/", ssize); // keep it absolute!
|
strlcatbuff(s, "/", ssize); // keep it absolute!
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user