Compare commits

..

3 Commits

Author SHA1 Message Date
Xavier Roche
48c4e57a4e Finish scrubbing the java-class docs across the guides and man source
The -j option still exists (it drives JavaScript parsing), so every "parse
Java Classes" summary in the HTML guides becomes "parse scripts", and the
obsolete .class-parsing descriptions and java-applet troubleshooting entries
are reworded to drop the removed capability. The "Some java classes may not
find..." engine-limit line is dropped at its source (README, from which
makeman.sh regenerates the man LIMITS section), and httrack.1 regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-12 18:05:46 +02:00
Xavier Roche
84ba3044f7 Scrub the removed java/swf modules from the shipped HTML docs
Follow-up to the htsjava/SWF removal: the pre-generated docs in html/ (shipped
in httrack-doc) still named the gone modules. Update the two stale --help
mirrors in httrack.man.html by hand (a full groff regen would rewrite the whole
file under a newer groff) and drop the htsjava.c plugin-example reference from
plug.html.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-12 16:04:07 +02:00
Xavier Roche
f73b352b82 Remove the obsolete Java-applet .class parser and dead SWF vestiges
Java applets stopped running in every mainstream browser years ago (NPAPI
dropped by Chrome in 2015 and Firefox in 2017; the JDK browser plugin gone
since JDK 11), so htsjava -- a hand-rolled parser of hostile .class bytecode
fetched off the network -- chased dependencies no live site serves while
carrying real attack surface for no functional gain. The SWF module was
already gone; only vestiges remained (a dead libhtsswf.so.1 dlopen entry and
help-text examples).

htsjava was a dlopen plugin, never linked into libhttrack, so its removal
leaves libhttrack's ABI untouched: libhttrack.so.3 is unchanged and the
libhttrack3/-dev packages just stop shipping libhtsjava.so.3*. That is a
plain file drop dpkg removes on upgrade -- no package rename, no
Replaces/Breaks, and nothing ever linked the library (it was dlopened), so
there are no reverse dependencies. The parsejava/-j option stays; it also
gates JavaScript parsing.

Drops the plugin sources, the build/config/vcproj wiring, the java self-test
and its two engine tests, and the now-unused hts_count_fits helper (whose
only caller was the plugin), and regenerates the man page. The <applet> URL
rewriting in the HTML parser and the .class codebase bookkeeping are left
intact, so applet pages are still mirrored as plain files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-12 15:55:02 +02:00
11 changed files with 21 additions and 290 deletions

View File

@@ -1,73 +0,0 @@
# Windows build of libhttrack (VS2022 v143 + vcpkg).
#
# The autotools CI covers the unix builds; this covers the MSVC one, which had
# no coverage at all and had drifted (the old .vcproj pinned OpenSSL 1.0.1j).
# libhttrack.dll is what the WinHTTrack GUI links against.
name: windows-build
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
libhttrack:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
platform: [x64, Win32]
configuration: [Release]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive # coucal lives in src/coucal
# Located through vswhere rather than microsoft/setup-msbuild: the repo
# only allows GitHub-owned actions.
- name: Find MSBuild
shell: pwsh
run: |
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$msbuild = & $vswhere -latest -products * -requires Microsoft.Component.MSBuild `
-find MSBuild\**\Bin\MSBuild.exe | Select-Object -First 1
if (-not $msbuild) { throw "MSBuild not found" }
Write-Host "MSBuild: $msbuild"
"MSBUILD=$msbuild" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Enable vcpkg MSBuild integration
shell: pwsh
run: vcpkg integrate install
- name: Build libhttrack
shell: pwsh
run: |
& $env:MSBUILD src\libhttrack.vcxproj `
/m `
/p:Configuration=${{ matrix.configuration }} `
/p:Platform=${{ matrix.platform }} `
/p:VcpkgEnableManifest=true `
/flp:LogFile=msbuild.log`;Verbosity=normal
# WinHTTrack links src\$(Platform)\$(Configuration)\libhttrack.lib, so the
# import lib and the DLL both have to land there under that exact name.
- name: Check the DLL and import lib landed where WinHTTrack expects
shell: pwsh
run: |
$dir = "src\${{ matrix.platform }}\${{ matrix.configuration }}"
foreach ($f in @("libhttrack.dll", "libhttrack.lib")) {
if (-not (Test-Path "$dir\$f")) { throw "missing $dir\$f" }
Write-Host "found $dir\$f"
}
- name: Upload MSBuild log
if: always()
uses: actions/upload-artifact@v4
with:
name: msbuild-${{ matrix.platform }}-${{ matrix.configuration }}
path: msbuild.log
if-no-files-found: ignore

View File

@@ -3868,9 +3868,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
// drop bytes past the resume point; a silent // drop bytes past the resume point; a silent
// failure could leave a stale tail, so on error // failure could leave a stale tail, so on error
// drop the partial and refetch the whole file // drop the partial and refetch the whole file
/* not (off_t): 32-bit on MSVC, wrapping a resume if (HTS_FTRUNCATE(back[i].r.out,
past 2GB */ (off_t) resume) != 0) {
if (HTS_FTRUNCATE(back[i].r.out, resume) != 0) {
fclose(back[i].r.out); fclose(back[i].r.out);
back[i].r.out = NULL; back[i].r.out = NULL;
url_savename_refname_remove( url_savename_refname_remove(
@@ -3882,9 +3881,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
"Can not truncate partial file, " "Can not truncate partial file, "
"restarting"); "restarting");
} else { } else {
/* not (off_t): 32-bit on MSVC, truncating a fseeko(back[i].r.out, (off_t) resume, SEEK_SET);
resume past 2GB */
fseeko(back[i].r.out, resume, SEEK_SET);
/* create a temporary reference file in case of /* create a temporary reference file in case of
* broken mirror */ * broken mirror */
if (back_serialize_ref(opt, &back[i]) != 0) { if (back_serialize_ref(opt, &back[i]) != 0) {

View File

@@ -133,10 +133,9 @@ static struct addrinfo *mock_mkai(const mock_addr *a) {
return ai; return ai;
} }
static int HTS_RESOLVER_CALL mock_getaddrinfo(const char *node, static int mock_getaddrinfo(const char *node, const char *service,
const char *service, const struct addrinfo *hints,
const struct addrinfo *hints, struct addrinfo **res) {
struct addrinfo **res) {
mock_host *const h = mock_find(node); mock_host *const h = mock_find(node);
const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC; const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC;
struct addrinfo *head = NULL, *tail = NULL; struct addrinfo *head = NULL, *tail = NULL;
@@ -165,7 +164,7 @@ static int HTS_RESOLVER_CALL mock_getaddrinfo(const char *node,
return 0; return 0;
} }
static void HTS_RESOLVER_CALL mock_freeaddrinfo(struct addrinfo *res) { static void mock_freeaddrinfo(struct addrinfo *res) {
while (res != NULL) { while (res != NULL) {
struct addrinfo *const next = res->ai_next; struct addrinfo *const next = res->ai_next;

View File

@@ -213,20 +213,6 @@ const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
return strjoker_rec(&memo, chaine, joker, size, size_flag); return strjoker_rec(&memo, chaine, joker, size, size_flag);
} }
/* Test-only: strjoker() reporting the work-budget steps spent and the cap, so a
self-test can prove the budget bounds a hostile pattern's work. */
const char *strjoker_steps(const char *chaine, const char *joker,
size_t *nsteps_out, size_t *maxsteps_out) {
size_t nsteps = 0;
const char *r = strjoker_bounded(chaine, joker, NULL, NULL, &nsteps);
if (nsteps_out != NULL)
*nsteps_out = nsteps;
if (maxsteps_out != NULL)
*maxsteps_out = STRJOKER_MAXSTEPS;
return r;
}
static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine, static const char *strjoker_impl(const strjoker_memo *memo, const char *chaine,
const char *joker, LLint *size, const char *joker, LLint *size,
int *size_flag) { int *size_flag) {

View File

@@ -52,10 +52,6 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * s
oracle for the memoized matcher. */ oracle for the memoized matcher. */
const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size, const char *strjoker_nomemo(const char *chaine, const char *joker, LLint *size,
int *size_flag); int *size_flag);
/* strjoker() reporting the work-budget steps it spent and the cap; test-only,
lets a self-test assert the budget bounds a hostile pattern's work. */
const char *strjoker_steps(const char *chaine, const char *joker,
size_t *nsteps_out, size_t *maxsteps_out);
const char *strjokerfind(const char *chaine, const char *joker); const char *strjokerfind(const char *chaine, const char *joker);
#endif #endif

View File

@@ -5018,7 +5018,7 @@ static struct addrinfo *resolver_make_ai(const char *ip, int want_family) {
return ai; return ai;
} }
static void HTS_RESOLVER_CALL override_freeaddrinfo(struct addrinfo *res) { static void override_freeaddrinfo(struct addrinfo *res) {
while (res != NULL) { while (res != NULL) {
struct addrinfo *const next = res->ai_next; struct addrinfo *const next = res->ai_next;
@@ -5028,10 +5028,9 @@ static void HTS_RESOLVER_CALL override_freeaddrinfo(struct addrinfo *res) {
} }
} }
static int HTS_RESOLVER_CALL override_getaddrinfo(const char *node, static int override_getaddrinfo(const char *node, const char *service,
const char *service, const struct addrinfo *hints,
const struct addrinfo *hints, struct addrinfo **res) {
struct addrinfo **res) {
const char *const spec = getenv("HTTRACK_DEBUG_RESOLVE"); const char *const spec = getenv("HTTRACK_DEBUG_RESOLVE");
const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC; const int want = (hints != NULL) ? hints->ai_family : PF_UNSPEC;
const char *colon; const char *colon;

View File

@@ -493,14 +493,6 @@ HTS_STATIC int strcmpnocase(const char *a, const char *b) {
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
/* MSVC ships these POSIX functions under other names. Kept out of the installed
headers: they would rewrite the same identifiers in a consumer's own code. */
#ifdef _MSC_VER
#define fseeko _fseeki64
#define ftello _ftelli64
#define timegm _mkgmtime
#endif
#define strfield2(f,s) ( (strlen(f)!=strlen(s)) ? 0 : (strfield(f,s)) ) #define strfield2(f,s) ( (strlen(f)!=strlen(s)) ? 0 : (strfield(f,s)) )
// is this MIME an hypertext MIME (text/html), html/js-style or other script/text type? // is this MIME an hypertext MIME (text/html), html/js-style or other script/text type?

View File

@@ -309,19 +309,10 @@ typedef socklen_t SOClen;
self-test can script DNS answers (families, multiplicity, errors) self-test can script DNS answers (families, multiplicity, errors)
in-process. The free function must match its getaddrinfo (a fake allocates in-process. The free function must match its getaddrinfo (a fake allocates
its own chain), hence the pair. */ its own chain), hence the pair. */
/* Winsock's resolver is __stdcall; a plain pointer only compiles on x64, where
there is one convention. Backend implementations must carry this too. */
#ifdef _WIN32
#define HTS_RESOLVER_CALL WSAAPI
#else
#define HTS_RESOLVER_CALL
#endif
typedef struct hts_resolver_backend { typedef struct hts_resolver_backend {
int(HTS_RESOLVER_CALL *getaddrinfo)(const char *node, const char *service, int (*getaddrinfo)(const char *node, const char *service,
const struct addrinfo *hints, const struct addrinfo *hints, struct addrinfo **res);
struct addrinfo **res); void (*freeaddrinfo)(struct addrinfo *res);
void(HTS_RESOLVER_CALL *freeaddrinfo)(struct addrinfo *res);
} hts_resolver_backend; } hts_resolver_backend;
/** Install a resolver backend for the process; NULL restores the libc default. /** Install a resolver backend for the process; NULL restores the libc default.

View File

@@ -744,33 +744,29 @@ static int st_filterdual(httrackp *opt, int argc, char **argv) {
process (OSS-Fuzz 5060751291908096 / 5745936014573568). */ process (OSS-Fuzz 5060751291908096 / 5745936014573568). */
static int st_filterbounds(httrackp *opt, int argc, char **argv) { static int st_filterbounds(httrackp *opt, int argc, char **argv) {
const size_t big = 100000; /* well past the length cap */ const size_t big = 100000; /* well past the length cap */
const size_t stars = 1023; /* pattern len 2047, under the length cap */ const size_t stars = 900; /* star-heavy pattern, under the cap */
const size_t subjlen = 2048;
char *subj = malloct(big + 1); char *subj = malloct(big + 1);
char *pat = malloct(2 * stars + 2); char *pat = malloct(2 * stars + 2);
size_t steps = 0, maxsteps = 0, i; size_t i;
(void) opt; (void) opt;
(void) argc; (void) argc;
(void) argv; (void) argv;
memset(subj, 'a', big); memset(subj, 'a', big);
subj[big] = '\0'; subj[big] = '\0';
/* '*' matches anything, but an over-length subject trips the length cap */ /* '*' matches anything, but an over-length subject is refused by the cap */
assertf(strjoker(subj, "*", NULL, NULL) == NULL); assertf(strjoker(subj, "*", NULL, NULL) == NULL);
assertf(strjokerfind(subj, "*") == NULL); assertf(strjokerfind(subj, "*") == NULL);
/* Star-heavy dead-end at the length cap: unbounded it runs ~1.26e9 memo-steps /* within-cap star-heavy dead-end: the step budget keeps it bounded (a hang
(~6s). */ would time the test out) */
for (i = 0; i < stars; i++) { for (i = 0; i < stars; i++) {
pat[2 * i] = '*'; pat[2 * i] = '*';
pat[2 * i + 1] = 'a'; pat[2 * i + 1] = 'a';
} }
pat[2 * stars] = 'b'; /* never matches an all-'a' subject */ pat[2 * stars] = 'b'; /* never matches an all-'a' subject */
pat[2 * stars + 1] = '\0'; pat[2 * stars + 1] = '\0';
subj[subjlen] = '\0'; subj[stars] = '\0';
/* Budget must fire and hold: steps > cap (deleting the budget zeroes the assertf(strjoker(subj, pat, NULL, NULL) == NULL);
counter that is the enforcement), steps < 10*cap (unbudgeted ~1.26e9). */
assertf(strjoker_steps(subj, pat, &steps, &maxsteps) == NULL);
assertf(steps > maxsteps && steps < 10 * maxsteps);
assertf(strjokerfind(subj, pat) == NULL); assertf(strjokerfind(subj, pat) == NULL);
freet(pat); freet(pat);
freet(subj); freet(subj);

View File

@@ -1,143 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{E76AD871-54C1-45E8-A657-6117ADEFFB46}</ProjectGuid>
<RootNamespace>libhttrack</RootNamespace>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)'==''">10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<!-- OpenSSL 3.x and zlib come from vcpkg. Dynamic triplets: the DLLs ship with
the app, so an OpenSSL CVE is a DLL swap rather than a rebuild. -->
<PropertyGroup>
<VcpkgEnableManifest>true</VcpkgEnableManifest>
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows</VcpkgTriplet>
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows</VcpkgTriplet>
<!-- WinHTTrack links ..\httrack\src\$(Platform)\$(Configuration)\libhttrack.lib -->
<OutDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(MSBuildThisFileDirectory)$(Platform)\$(Configuration)\obj\</IntDir>
<TargetName>libhttrack</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<!-- LIBHTTRACK_EXPORTS turns HTSEXT_API into __declspec(dllexport); ZLIB_DLL
imports zlib from its DLL. Windows 7 floor, matching WinHTTrack. -->
<PreprocessorDefinitions>WIN32;_WINDOWS;_MBCS;_USRDLL;LIBHTTRACK_EXPORTS;ZLIB_DLL;WINVER=0x0601;_WIN32_WINNT=0x0601;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);$(MSBuildThisFileDirectory)coucal;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level3</WarningLevel>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<CompileAs>CompileAsC</CompileAs>
</ClCompile>
<Link>
<!-- vcpkg auto-links libssl/libcrypto/zlib; only the OS import lib is explicit. -->
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>MaxSpeed</Optimization>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="coucal\coucal.c" />
<ClCompile Include="htsalias.c" />
<ClCompile Include="htsback.c" />
<ClCompile Include="htsbauth.c" />
<ClCompile Include="htscache.c" />
<ClCompile Include="htscache_selftest.c" />
<ClCompile Include="htscatchurl.c" />
<ClCompile Include="htscharset.c" />
<ClCompile Include="htsconcat.c" />
<ClCompile Include="htscore.c" />
<ClCompile Include="htscoremain.c" />
<ClCompile Include="htsdns_selftest.c" />
<ClCompile Include="htsencoding.c" />
<ClCompile Include="htsfilters.c" />
<ClCompile Include="htsftp.c" />
<ClCompile Include="htshash.c" />
<ClCompile Include="htshelp.c" />
<ClCompile Include="htsindex.c" />
<ClCompile Include="htslib.c" />
<ClCompile Include="htsmd5.c" />
<ClCompile Include="htsmodules.c" />
<ClCompile Include="htsname.c" />
<ClCompile Include="htsparse.c" />
<ClCompile Include="htsrobots.c" />
<ClCompile Include="htsselftest.c" />
<ClCompile Include="htssniff.c" />
<ClCompile Include="htsthread.c" />
<ClCompile Include="htstools.c" />
<ClCompile Include="htswizard.c" />
<ClCompile Include="htswrap.c" />
<ClCompile Include="htszlib.c" />
<ClCompile Include="md5.c" />
<ClCompile Include="minizip\ioapi.c" />
<ClCompile Include="minizip\iowin32.c" />
<ClCompile Include="minizip\mztools.c" />
<ClCompile Include="minizip\unzip.c" />
<ClCompile Include="minizip\zip.c" />
<ClCompile Include="punycode.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -1,9 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "libhttrack",
"version-string": "3.49",
"dependencies": [
"openssl",
"zlib"
]
}