mirror of
https://github.com/xroche/httrack.git
synced 2026-07-17 22:29:55 +03:00
Compare commits
2 Commits
master
...
fix-port-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cd001f862 | ||
|
|
9f3129efbd |
@@ -46,9 +46,11 @@ htsserver_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_PIE)
|
||||
|
||||
lib_LTLIBRARIES = libhttrack.la
|
||||
|
||||
htsserver_SOURCES = htsserver.c htsserver.h htsweb.c htsweb.h
|
||||
htsserver_SOURCES = htsserver.c htsserver.h htsweb.c htsweb.h \
|
||||
htsurlport.c htsurlport.h
|
||||
proxytrack_SOURCES = proxy/main.c \
|
||||
proxy/proxytrack.c proxy/store.c \
|
||||
htsurlport.c htsurlport.h \
|
||||
coucal/coucal.c htsmd5.c md5.c \
|
||||
minizip/ioapi.c minizip/mztools.c minizip/unzip.c minizip/zip.c
|
||||
|
||||
@@ -58,7 +60,7 @@ whttrackrun_SCRIPTS = webhttrack
|
||||
libhttrack_la_SOURCES = htscore.c htsparse.c htsback.c htscache.c \
|
||||
htscache_selftest.c htsdns_selftest.c htsselftest.c \
|
||||
htscatchurl.c htsfilters.c htsftp.c htshash.c coucal/coucal.c \
|
||||
htshelp.c htslib.c htscoremain.c \
|
||||
htshelp.c htslib.c htsurlport.c htscoremain.c \
|
||||
htsname.c htsrobots.c htstools.c htswizard.c \
|
||||
htsalias.c htsthread.c htsindex.c htsbauth.c \
|
||||
htsmd5.c htscodec.c htsproxy.c htszlib.c htswrap.c htsconcat.c \
|
||||
@@ -69,7 +71,7 @@ libhttrack_la_SOURCES = htscore.c htsparse.c htsback.c htscache.c \
|
||||
htsbasenet.h htsbauth.h htscache.h htscache_selftest.h htsdns_selftest.h htsselftest.h htscatchurl.h \
|
||||
htsconfig.h htscore.h htsparse.h htscoremain.h htsdefines.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 htsurlport.h htsmd5.h \
|
||||
htsmodules.h htsname.h htsnet.h htssniff.h \
|
||||
htsopt.h htsrobots.h htsthread.h \
|
||||
htstools.h htswizard.h htswrap.h htscodec.h htsproxy.h htszlib.h \
|
||||
|
||||
@@ -425,10 +425,25 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
|
||||
} // for
|
||||
|
||||
// path_html is already UTF-8 (argv is UTF-8 on Windows via
|
||||
// hts_argv_utf8), so no re-encoding.
|
||||
// Convert path to UTF-8
|
||||
#ifdef _WIN32
|
||||
{
|
||||
char *const path =
|
||||
hts_convertStringSystemToUTF8(StringBuff(opt->path_html),
|
||||
(int) StringLength(opt->path_html));
|
||||
if (path != NULL) {
|
||||
StringCopy(opt->path_html_utf8, path);
|
||||
free(path);
|
||||
} else {
|
||||
StringCopyN(opt->path_html_utf8, StringBuff(opt->path_html),
|
||||
StringLength(opt->path_html));
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Assume UTF-8 filesystem.
|
||||
StringCopyN(opt->path_html_utf8, StringBuff(opt->path_html),
|
||||
StringLength(opt->path_html));
|
||||
#endif
|
||||
|
||||
/* if doit.log exists, or if new URL(s) defined,
|
||||
then DO NOT load standard config files */
|
||||
@@ -2471,12 +2486,9 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
}
|
||||
} */
|
||||
|
||||
// vérifier existence de la structure (path_html/path_log are UTF-8, use
|
||||
// the UTF-8 mkdir path)
|
||||
structcheck_utf8(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||
StringBuff(opt->path_html), "/"));
|
||||
structcheck_utf8(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
|
||||
StringBuff(opt->path_log), "/"));
|
||||
// vérifier existence de la structure
|
||||
structcheck(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_html), "/"));
|
||||
structcheck(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "/"));
|
||||
|
||||
// reprise/update
|
||||
if (opt->cache) {
|
||||
|
||||
@@ -248,7 +248,13 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
|
||||
// port
|
||||
a = strchr(adr, ':'); // port
|
||||
if (a) {
|
||||
sscanf(a + 1, "%d", &port);
|
||||
// folding a nonsense port into 1..65535 fetches one the link never named;
|
||||
// an empty "host:" just means the default (#614)
|
||||
if (a[1] != '\0' && !hts_parse_url_port(a + 1, &port)) {
|
||||
snprintf(back->r.msg, sizeof(back->r.msg), "Invalid port: %s", a + 1);
|
||||
back->r.statuscode = STATUSCODE_INVALID; // permanent, unlike a DNS miss
|
||||
_HALT_FTP return 0;
|
||||
}
|
||||
strncatbuff(_adr, adr, (int) (a - adr));
|
||||
} else
|
||||
strcpybuff(_adr, adr);
|
||||
|
||||
13
src/htslib.c
13
src/htslib.c
@@ -3751,19 +3751,6 @@ static int proxy_default_port(const char *arg) {
|
||||
return hts_proxy_is_socks(arg) ? 1080 : 8080;
|
||||
}
|
||||
|
||||
hts_boolean hts_parse_url_port(const char *a, int *port) {
|
||||
char *end;
|
||||
long p;
|
||||
|
||||
if (!isdigit((unsigned char) *a)) // strtol would eat a sign or leading space
|
||||
return HTS_FALSE;
|
||||
p = strtol(a, &end, 10);
|
||||
if (*end != '\0' || p < 1 || p > 65535) // ERANGE lands out of range too
|
||||
return HTS_FALSE;
|
||||
*port = (int) p;
|
||||
return HTS_TRUE;
|
||||
}
|
||||
|
||||
// port "a" of -P argument "arg": digits fitting TCP's 1..65535, else the scheme
|
||||
// default. Not sscanf("%d"): past INT_MAX it wraps to a garbage port (#602)
|
||||
static int parse_proxy_port(const char *a, const char *arg) {
|
||||
|
||||
@@ -61,6 +61,7 @@ typedef struct lien_adrfilsave lien_adrfilsave;
|
||||
|
||||
/* définitions globales */
|
||||
#include "htsglobal.h"
|
||||
#include "htsurlport.h"
|
||||
|
||||
/* basic net definitions */
|
||||
#include "htsbase.h"
|
||||
@@ -288,12 +289,6 @@ const char *strrchr_limit(const char *s, char c, const char *limit);
|
||||
char *jump_protocol(char *source);
|
||||
const char *jump_protocol_const(const char *source);
|
||||
|
||||
/* Parse a URL's port text "a" (after the ':', up to the end of the string):
|
||||
TRUE and *port set for a bare decimal in 1..65535, else FALSE and *port left
|
||||
alone. Not sscanf("%d"), which range-checks nothing and wraps past INT_MAX.
|
||||
*/
|
||||
hts_boolean hts_parse_url_port(const char *a, int *port);
|
||||
|
||||
/* Split a -P proxy argument "[scheme://][user:pass@]host[:port]" into the proxy
|
||||
host string (scheme and any user:pass kept, for later stripping and auth),
|
||||
written NUL-terminated into name[name_size] (truncated to fit), and the port
|
||||
|
||||
@@ -2477,45 +2477,6 @@ static int st_makeindex(httrackp *opt, int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// hts_buildtopindex takes a system-charset path but verif_backblue() below it
|
||||
// expects utf-8, so on Windows a non-ASCII project dir gets the gifs written to
|
||||
// a mangled twin (issues #216/#217). argv[0] is a writable dir.
|
||||
static int st_topindex(httrackp *opt, int argc, char **argv) {
|
||||
char projdir[HTS_URLMAXSIZE];
|
||||
char path[HTS_URLMAXSIZE + 16]; /* projdir plus a basename */
|
||||
#ifdef _WIN32
|
||||
/* the GUI hands hts_buildtopindex an ANSI path; mimic it. CP1252 'cafe' */
|
||||
static const char *const projName = "caf\xE9";
|
||||
#else
|
||||
/* POSIX system charset is UTF-8 */
|
||||
static const char *const projName = "caf\xC3\xA9";
|
||||
#endif
|
||||
|
||||
assertf(argc >= 1);
|
||||
snprintf(projdir, sizeof(projdir), "%s/%s", argv[0], projName);
|
||||
|
||||
/* structcheck(), not the utf-8 MKDIR family: same charset as buildtopindex */
|
||||
snprintf(path, sizeof(path), "%s/", projdir);
|
||||
assertf(structcheck(path) == 0);
|
||||
|
||||
/* returns 0 here: the dir holds no sub-project, only the gifs matter */
|
||||
(void) hts_buildtopindex(opt, projdir, "");
|
||||
|
||||
/* the gifs must land in the project dir itself, not in a mangled sibling */
|
||||
snprintf(path, sizeof(path), "%s/backblue.gif", projdir);
|
||||
assertf(fexist(path));
|
||||
|
||||
/* raw unlink/rmdir: UNLINK is utf-8 on Windows, these paths aren't */
|
||||
unlink(path);
|
||||
snprintf(path, sizeof(path), "%s/fade.gif", projdir);
|
||||
unlink(path);
|
||||
snprintf(path, sizeof(path), "%s/index.html", projdir);
|
||||
unlink(path);
|
||||
rmdir(projdir);
|
||||
printf("topindex self-test OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Each inplace_escape_*() must equal escape_*() on a copy. */
|
||||
static int st_inplace_escape(httrackp *opt, int argc, char **argv) {
|
||||
/* >255 bytes forces the helper's malloct path, not the stack buffer */
|
||||
@@ -3223,9 +3184,6 @@ static const struct selftest_entry {
|
||||
{"useragent", "", "default User-Agent self-test", st_useragent},
|
||||
{"makeindex", "[dir]", "hts_finish_makeindex footer/refresh self-test",
|
||||
st_makeindex},
|
||||
{"topindex", "[dir]",
|
||||
"hts_buildtopindex charset handling of a non-ASCII project dir",
|
||||
st_topindex},
|
||||
{"inplace-escape", "", "inplace_escape_* vs escape_* equivalence self-test",
|
||||
st_inplace_escape},
|
||||
{"escape-room", "", "HT_ADD_HTMLESCAPED* reservation-factor self-test",
|
||||
|
||||
@@ -164,12 +164,13 @@ HTS_UNUSED static int linputsoc_t(T_SOC soc, char *s, int max, int timeout) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Same contract as hts_gethome(), which is hidden and out of reach from here */
|
||||
static const char *gethomedir(void) {
|
||||
const char *home = getenv("HOME");
|
||||
|
||||
/* An empty $HOME would put the base path and httrack.ini at the root */
|
||||
return strnotempty(home) ? home : ".";
|
||||
if (home)
|
||||
return home;
|
||||
else
|
||||
return ".";
|
||||
}
|
||||
static int linput_cpp(FILE * fp, char *s, int max) {
|
||||
int rlen = 0;
|
||||
|
||||
@@ -896,20 +896,7 @@ HTSEXT_API int hts_buildtopindex(httrackp * opt, const char *path,
|
||||
if (fpo) {
|
||||
find_handle h;
|
||||
|
||||
// générer gif. verif_backblue() is utf-8, but our path is the system
|
||||
// charset, so on Windows convert it or the gifs land in a mangled twin
|
||||
// dir (#217). Elsewhere the system charset is already utf-8.
|
||||
#ifdef _WIN32
|
||||
{
|
||||
const char *const base = concat(catbuff, sizeof(catbuff), rpath, "/");
|
||||
char *const base_utf8 =
|
||||
hts_convertStringSystemToUTF8(base, strlen(base));
|
||||
verif_backblue(opt, base_utf8 != NULL ? base_utf8 : base);
|
||||
free(base_utf8);
|
||||
}
|
||||
#else
|
||||
verif_backblue(opt, concat(catbuff, sizeof(catbuff), rpath, "/"));
|
||||
#endif
|
||||
verif_backblue(opt, concat(catbuff, sizeof(catbuff), rpath, "/")); // générer gif
|
||||
// Header
|
||||
hts_template_format(fpo, toptemplate_header,
|
||||
"<!-- Mirror and index made by HTTrack Website Copier/"
|
||||
|
||||
50
src/htsurlport.c
Normal file
50
src/htsurlport.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||
Copyright (C) 1998 Xavier Roche and other contributors
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||
addresses or to collect any other private information about people. Doing so
|
||||
would dishonor our work and waste the many hours we have spent on it.
|
||||
|
||||
Please visit our Website: http://www.httrack.com
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* File: TCP port parser, shared by the engine, htsserver and */
|
||||
/* proxytrack */
|
||||
/* Author: Xavier Roche */
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
#include "htsurlport.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
hts_boolean hts_parse_url_port(const char *a, int *port) {
|
||||
char *end;
|
||||
long p;
|
||||
|
||||
if (!isdigit((unsigned char) *a)) // strtol would eat a sign or leading space
|
||||
return HTS_FALSE;
|
||||
p = strtol(a, &end, 10);
|
||||
if (*end != '\0' || p < 1 || p > 65535) // ERANGE lands out of range too
|
||||
return HTS_FALSE;
|
||||
*port = (int) p;
|
||||
return HTS_TRUE;
|
||||
}
|
||||
45
src/htsurlport.h
Normal file
45
src/htsurlport.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
HTTrack Website Copier, Offline Browser for Windows and Unix
|
||||
Copyright (C) 1998 Xavier Roche and other contributors
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Ethical use: we kindly ask that you NOT use this software to harvest email
|
||||
addresses or to collect any other private information about people. Doing so
|
||||
would dishonor our work and waste the many hours we have spent on it.
|
||||
|
||||
Please visit our Website: http://www.httrack.com
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* File: TCP port parser, shared by the engine, htsserver and */
|
||||
/* proxytrack */
|
||||
/* Author: Xavier Roche */
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
#ifndef HTSURLPORT_DEFH
|
||||
#define HTSURLPORT_DEFH
|
||||
|
||||
#include "htsglobal.h"
|
||||
|
||||
/* Parse the port text "a" (after the ':', up to the end of the string): TRUE
|
||||
and *port set for a bare decimal in 1..65535, else FALSE and *port left
|
||||
alone. Not sscanf("%d"), which range-checks nothing and wraps past INT_MAX.
|
||||
Its own file so proxytrack, which does not link the library, can share it. */
|
||||
hts_boolean hts_parse_url_port(const char *a, int *port);
|
||||
|
||||
#endif
|
||||
@@ -63,6 +63,7 @@ Please visit our Website: http://www.httrack.com
|
||||
#include "md5.c"
|
||||
|
||||
#include "htsserver.h"
|
||||
#include "htsurlport.h"
|
||||
#include "htsweb.h"
|
||||
|
||||
#if USE_BEGINTHREAD==0
|
||||
@@ -257,8 +258,10 @@ int main(int argc, char *argv[]) {
|
||||
/* set commandline keys */
|
||||
for(i = 2; i < argc; i += 2) {
|
||||
if (strcmp(argv[i], "--port") == 0 && i + 1 < argc) {
|
||||
if (sscanf(argv[i + 1], "%d", &defaultPort) != 1 || defaultPort < 0
|
||||
|| defaultPort >= 65535) {
|
||||
// the range check ran after sscanf("%d") had wrapped a huge value into a
|
||||
// plausible port, and listened there (#614). 0 (was the auto-pick) and
|
||||
// 65535 (was refused, off by one) now both mean what they say.
|
||||
if (!hts_parse_url_port(argv[i + 1], &defaultPort)) {
|
||||
fprintf(stderr, "couldn't set the port number to %s\n", argv[i + 1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
<ClCompile Include="htshelp.c" />
|
||||
<ClCompile Include="htsindex.c" />
|
||||
<ClCompile Include="htslib.c" />
|
||||
<ClCompile Include="htsurlport.c" />
|
||||
<ClCompile Include="htsmd5.c" />
|
||||
<ClCompile Include="htsmodules.c" />
|
||||
<ClCompile Include="htsname.c" />
|
||||
|
||||
@@ -47,7 +47,9 @@ static void sig_brpipe(int code) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int scanHostPort(const char *str, char *host, int *port) {
|
||||
// split a "host:port" listen argument; FALSE sends the caller to the usage
|
||||
// screen. The port was unchecked, so a huge one wrapped into range (#614).
|
||||
static hts_boolean scanHostPort(const char *str, char *host, int *port) {
|
||||
char *pos = strrchr(str, ':');
|
||||
|
||||
if (pos != NULL) {
|
||||
@@ -56,12 +58,10 @@ static int scanHostPort(const char *str, char *host, int *port) {
|
||||
if (n < 256) {
|
||||
host[0] = '\0';
|
||||
strncat(host, str, n);
|
||||
if (sscanf(pos + 1, "%d", port) == 1) {
|
||||
return 1;
|
||||
}
|
||||
return hts_parse_url_port(pos + 1, port);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return HTS_FALSE;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@@ -107,12 +107,13 @@ HTS_UNUSED static void proxytrack_print_log(const char *severity, const char *fo
|
||||
"<!-- _-._.--._._-._.--._._-._.--._._-._.--._._-._.--._. -->\r\n" \
|
||||
"<!-- End Disable IE Friendly HTTP Error Messages -->\r\n"
|
||||
|
||||
/* Same contract as hts_gethome(): proxytrack does not link libhttrack */
|
||||
HTS_UNUSED static const char *gethomedir(void) {
|
||||
const char *home = getenv("HOME");
|
||||
|
||||
/* An empty $HOME would resolve a relative path against the root */
|
||||
return strnotempty(home) ? home : ".";
|
||||
if (home)
|
||||
return home;
|
||||
else
|
||||
return ".";
|
||||
}
|
||||
|
||||
HTS_UNUSED static int linput(FILE * fp, char *s, int max) {
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<ClCompile Include="proxy\main.c" />
|
||||
<ClCompile Include="proxy\proxytrack.c" />
|
||||
<ClCompile Include="proxy\store.c" />
|
||||
<ClCompile Include="htsurlport.c" />
|
||||
<ClCompile Include="coucal\coucal.c" />
|
||||
<ClCompile Include="htsmd5.c" />
|
||||
<ClCompile Include="md5.c" />
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="htsserver.c" />
|
||||
<ClCompile Include="htsweb.c" />
|
||||
<ClCompile Include="htsurlport.c" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# hts_buildtopindex takes a system-charset path but verif_backblue below it
|
||||
# expects utf-8, mangling a non-ASCII project dir on Windows (#216, #217).
|
||||
dir=$(mktemp -d)
|
||||
trap 'rm -rf "$dir"' EXIT
|
||||
|
||||
httrack -O /dev/null -#test=topindex "$dir" run |
|
||||
grep -q "topindex self-test OK"
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# htsserver's $HOME lookup, through the web UI it actually renders. An exported
|
||||
# but empty $HOME must not resolve the default base path against the root.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
testdir=$(cd "$(dirname "$0")" && pwd)
|
||||
distdir=${top_srcdir:-$(cd "${testdir}/.." && pwd)}
|
||||
distdir=$(cd "${distdir}" && pwd)
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v htsserver >/dev/null || fail "no htsserver in PATH"
|
||||
# Mirror local-crawl.sh's skip-with-77: the Debian buildd chroot has no python3.
|
||||
command -v python3 >/dev/null || {
|
||||
echo "python3 not found; skipping" >&2
|
||||
exit 77
|
||||
}
|
||||
|
||||
srv=
|
||||
cleanup() {
|
||||
test -z "${srv}" || kill -9 "${srv}" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT HUP INT QUIT PIPE TERM
|
||||
|
||||
log=$(mktemp)
|
||||
trap 'cleanup; rm -f "${log}"' EXIT
|
||||
|
||||
# Ask htsserver for its rendered default base path, under the given $HOME
|
||||
# ("-" = leave $HOME unset).
|
||||
pathfor() {
|
||||
local homeval=$1 port url got
|
||||
port=$(python3 -c 'import socket
|
||||
s = socket.socket()
|
||||
s.bind(("127.0.0.1", 0))
|
||||
print(s.getsockname()[1])
|
||||
s.close()')
|
||||
|
||||
: >"${log}"
|
||||
(
|
||||
# htsserver ignores SIGTERM/SIGTTOU handling from the harness shell
|
||||
trap '' TERM TTOU
|
||||
if test "${homeval}" = -; then unset HOME; else export HOME="${homeval}"; fi
|
||||
exec htsserver "${distdir}/" --port "${port}" >"${log}" 2>&1
|
||||
) &
|
||||
srv=$!
|
||||
|
||||
for _ in $(seq 1 40); do
|
||||
url=$(sed -n 's/^URL=//p' "${log}" 2>/dev/null) && test -n "${url}" && break
|
||||
kill -0 "${srv}" 2>/dev/null || break
|
||||
sleep 0.25
|
||||
done
|
||||
test -n "${url:-}" || fail "htsserver did not come up: $(cat "${log}")"
|
||||
|
||||
# The UI is served ISO-8859-1, so keep python out of text mode.
|
||||
got=$(python3 -c 'import re, sys, urllib.request
|
||||
body = urllib.request.urlopen(sys.argv[1] + "server/step2.html", timeout=20).read()
|
||||
m = re.search(br"name=\"path\" value=\"([^\"]*)\"", body)
|
||||
print(m.group(1).decode("latin-1") if m else "")' "${url}")
|
||||
|
||||
kill -9 "${srv}" 2>/dev/null || true
|
||||
wait "${srv}" 2>/dev/null || true
|
||||
srv=
|
||||
test -n "${got}" || fail "no path field in the rendered step2.html"
|
||||
echo "${got}"
|
||||
}
|
||||
|
||||
check() {
|
||||
local desc=$1 homeval=$2 want=$3 got
|
||||
got=$(pathfor "${homeval}")
|
||||
test "${got}" = "${want}" || fail "${desc}: want ${want}, got ${got}"
|
||||
echo "ok: ${desc} -> ${got}"
|
||||
}
|
||||
|
||||
# A real HOME must reach the page, or the two cases below are vacuous: they
|
||||
# also pass when gethomedir() ignores the environment and always answers ".".
|
||||
check 'a set HOME is used' /nonexistent/hts-home /nonexistent/hts-home/websites
|
||||
|
||||
# Exported but empty is the regression: getenv() returns "", not NULL, so a
|
||||
# bare NULL check let the base path collapse onto /websites.
|
||||
check 'an empty HOME' '' ./websites
|
||||
check 'an unset HOME' - ./websites
|
||||
|
||||
echo "PASS"
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# A non-ASCII -O output dir must receive the mirror, not a double-encoded twin
|
||||
# (#621). argv is UTF-8 on Windows, so path_html was re-encoded as if it were
|
||||
# the ANSI codepage, prefixing every saved file with a mangled directory. Only
|
||||
# path_html is the non-ASCII "café"; path_log stays ASCII so the harness reads
|
||||
# hts-log.txt/hts-cache normally and this isolates the -O encoding path.
|
||||
|
||||
: "${top_srcdir:=..}"
|
||||
|
||||
bash "$top_srcdir/tests/local-crawl.sh" --html-subdir 'café' --errors 0 --files 5 \
|
||||
--found 'simple/basic.html' \
|
||||
httrack 'BASEURL/simple/basic.html'
|
||||
111
tests/64_port-siblings.test
Normal file
111
tests/64_port-siblings.test
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
# Port parsing outside the crawled-URL path (#614): the htsserver --port listen
|
||||
# port, proxytrack's host:port listen arguments, and an ftp:// URL port. All
|
||||
# three took the port from sscanf("%d"), which range-checks nothing and wraps
|
||||
# past INT_MAX, so a value naming no real port silently became a plausible one.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
testdir=$(cd "$(dirname "$0")" && pwd)
|
||||
# run_with_timeout: timeout(1) is absent on macOS, and the listen servers block.
|
||||
# shellcheck source=tests/testlib.sh
|
||||
. "${testdir}/testlib.sh"
|
||||
|
||||
tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_portsib.XXXXXX") || exit 1
|
||||
trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM
|
||||
|
||||
# A port the old code accepted only by wrapping: 4295009395 = 2^32 + 42099 and
|
||||
# 4294967376 = 2^32 + 80 both fold to a plausible listen port. They are the
|
||||
# load-bearing cases, since a value that merely exceeds 65535 while still
|
||||
# fitting an int (65616) was already caught by the htsserver range check.
|
||||
overflowing="4295009395"
|
||||
|
||||
# Values sscanf("%d") took as a port that no operator meant: a trailing
|
||||
# character, a sign, leading whitespace, a decimal point. Each silently listened
|
||||
# on the prefix it managed to scan.
|
||||
malformed=("80x" "+80" " 80" "8.0" "")
|
||||
|
||||
# --- htsserver --port ------------------------------------------------------
|
||||
# Its argv[1] is the html root; the option pairs follow. It blocks serving once
|
||||
# a port is accepted, so bound it; we assert on the output, not the exit status.
|
||||
|
||||
websrv() {
|
||||
run_with_timeout 3 htsserver "$tmp" --port "$1" >"$tmp/web.log" 2>&1 || true
|
||||
}
|
||||
|
||||
web_refused() {
|
||||
websrv "$1"
|
||||
grep -q "couldn't set the port number" "$tmp/web.log" ||
|
||||
! echo "FAIL: #614: htsserver --port '$1' not refused" || exit 1
|
||||
# it must not have reached the listen socket on some other port
|
||||
! grep -q "^URL=" "$tmp/web.log" ||
|
||||
! echo "FAIL: #614: htsserver --port '$1' listened anyway" || exit 1
|
||||
}
|
||||
|
||||
web_accepted() {
|
||||
websrv "$1"
|
||||
! grep -q "couldn't set the port number" "$tmp/web.log" ||
|
||||
! echo "FAIL: #614: htsserver --port '$1' wrongly refused" || exit 1
|
||||
# the value must reach the listener: either it bound, or the bind failed,
|
||||
# both prove the parser passed it through, whether or not the port is free
|
||||
grep -qE "^URL=http://.*:$1/|Unable to initialize a temporary server" "$tmp/web.log" ||
|
||||
! echo "FAIL: #614: htsserver --port '$1' never reached the listener" || exit 1
|
||||
}
|
||||
|
||||
# this used to listen on 42099
|
||||
web_refused "$overflowing"
|
||||
for p in "${malformed[@]}" 0 65536 99999 -1; do
|
||||
web_refused "$p"
|
||||
done
|
||||
|
||||
# 65535 is a valid port the old "< 65535" bound refused
|
||||
web_accepted 65535
|
||||
|
||||
# --- proxytrack <proxy-addr:port> <ICP-addr:port> --------------------------
|
||||
# A bad argument falls through to the usage screen; it had no range check at
|
||||
# all, so 65616 quietly listened on port 80. A valid one binds and blocks.
|
||||
|
||||
proxy_refused() {
|
||||
run_with_timeout 3 proxytrack "127.0.0.1:$1" 127.0.0.1:3130 >"$tmp/pt.log" 2>&1 || true
|
||||
grep -q "^usage:" "$tmp/pt.log" ||
|
||||
! echo "FAIL: #614: proxytrack port '$1' not refused" || exit 1
|
||||
}
|
||||
|
||||
proxy_accepted() {
|
||||
run_with_timeout 3 proxytrack "127.0.0.1:$1" 127.0.0.1:3130 >"$tmp/pt.log" 2>&1 || true
|
||||
! grep -q "^usage:" "$tmp/pt.log" ||
|
||||
! echo "FAIL: #614: proxytrack port '$1' wrongly refused" || exit 1
|
||||
}
|
||||
|
||||
for p in "${malformed[@]}" 65616 4294967376 "$overflowing" 0 -1; do
|
||||
proxy_refused "$p"
|
||||
done
|
||||
proxy_accepted 45678
|
||||
|
||||
# --- ftp:// URL port -------------------------------------------------------
|
||||
# A URL port, so it follows the crawled-URL policy: refuse the link rather than
|
||||
# fold it into range. An ftp:// link in scanned HTML is not followed, so the
|
||||
# seed has to come from the command line.
|
||||
|
||||
ftp_port() {
|
||||
local out="$tmp/ftp"
|
||||
|
||||
rm -rf "$out"
|
||||
run_with_timeout 30 httrack "ftp://127.0.0.1:$1/x" -O "$out" --quiet -n \
|
||||
>/dev/null 2>&1 || true
|
||||
grep -c "Invalid port: $1" "$out/hts-log.txt" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# 65616 truncated to 80 and really did connect there
|
||||
for p in 65616 99999; do
|
||||
test "$(ftp_port "$p")" -gt 0 ||
|
||||
! echo "FAIL: #614: ftp:// port $p not refused" || exit 1
|
||||
done
|
||||
|
||||
# a valid port still reaches the connect attempt
|
||||
test "$(ftp_port 65535)" -eq 0 ||
|
||||
! echo "FAIL: #614: ftp:// port 65535 wrongly refused" || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -71,7 +71,6 @@ TESTS = \
|
||||
01_engine-status.test \
|
||||
01_engine-stripquery.test \
|
||||
01_engine-strsafe.test \
|
||||
01_engine-topindex.test \
|
||||
01_engine-urlhack.test \
|
||||
01_engine-unescape-bounds.test \
|
||||
01_engine-useragent.test \
|
||||
@@ -144,7 +143,6 @@ TESTS = \
|
||||
60_crawl-log-salvage.test \
|
||||
61_webhttrack-locale.test \
|
||||
62_lang-integrity.test \
|
||||
63_webhttrack-home.test \
|
||||
64_local-intl-outdir.test
|
||||
64_port-siblings.test
|
||||
|
||||
CLEANFILES = check-network_sh.cache
|
||||
|
||||
@@ -47,7 +47,6 @@ key="${testdir}/server.key"
|
||||
|
||||
tls=
|
||||
verbose=
|
||||
html_subdir=
|
||||
rerun=
|
||||
rerun_args=
|
||||
rerun_dead=
|
||||
@@ -133,13 +132,6 @@ while test "$pos" -lt "$nargs"; do
|
||||
pos=$((pos + 1))
|
||||
rerun_args="${args[$pos]}"
|
||||
;;
|
||||
--html-subdir)
|
||||
# Mirror into "$out/NAME" (path_html) but keep logs/cache in "$out"
|
||||
# (path_log): a non-ASCII NAME exercises the -O path encoding (#621)
|
||||
# without routing the harness-read hts-log.txt through a non-ASCII path.
|
||||
pos=$((pos + 1))
|
||||
html_subdir="${args[$pos]}"
|
||||
;;
|
||||
--errors | --errors-content | --files)
|
||||
audit+=("${args[$pos]}" "${args[$((pos + 1))]}")
|
||||
pos=$((pos + 1))
|
||||
@@ -215,21 +207,12 @@ test -n "$ver" || die "could not run httrack"
|
||||
|
||||
out="${tmpdir}/crawl"
|
||||
mkdir "$out" || die "could not create $out"
|
||||
# path_html holds the mirror + index; path_log holds hts-cache/hts-log.txt.
|
||||
# Default: both are "$out". With --html-subdir, path_html becomes "$out/NAME"
|
||||
# (the mirror root the audits inspect) while path_log stays "$out".
|
||||
mirrorroot="$out"
|
||||
odir="$out"
|
||||
if test -n "$html_subdir"; then
|
||||
mirrorroot="${out}/${html_subdir}"
|
||||
odir="${mirrorroot},${out}"
|
||||
fi
|
||||
# Localhost is fast; disable the rate/bandwidth safety limits but keep a
|
||||
# max-time backstop so a hang cannot wedge the suite.
|
||||
declare -a moreargs=(--quiet --max-time=120 --timeout=30 --disable-security-limits --robots=0)
|
||||
log="${tmpdir}/log"
|
||||
info "running httrack ${hts[*]}"
|
||||
httrack -O "$odir" --user-agent="httrack $ver local ($(uname -mrs))" "${moreargs[@]}" "${hts[@]}" >"$log" 2>&1 &
|
||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" "${moreargs[@]}" "${hts[@]}" >"$log" 2>&1 &
|
||||
crawlpid=$!
|
||||
wait "$crawlpid"
|
||||
crawlres=$?
|
||||
@@ -246,7 +229,7 @@ grep -iE "^[0-9:]*[[:space:]]Error:" "${out}/hts-log.txt" >&2
|
||||
# --- optional second pass: re-mirror into the same dir (cache/update path) ----
|
||||
if test -n "$rerun"; then
|
||||
info "re-running httrack (update pass)"
|
||||
httrack -O "$odir" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||
"${moreargs[@]}" "${hts[@]}" >"${log}.2" 2>&1 &
|
||||
crawlpid=$!
|
||||
wait "$crawlpid"
|
||||
@@ -274,7 +257,7 @@ fi
|
||||
if test -n "$rerun_args"; then
|
||||
read -ra extra <<<"$rerun_args"
|
||||
info "re-running httrack with ${rerun_args}"
|
||||
httrack -O "$odir" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||
"${moreargs[@]}" "${hts[@]}" "${extra[@]}" >"${log}.2" 2>&1 &
|
||||
crawlpid=$!
|
||||
wait "$crawlpid"
|
||||
@@ -296,7 +279,7 @@ if test -n "$rerun_dead"; then
|
||||
stop_server "$serverpid"
|
||||
serverpid=
|
||||
info "re-running httrack against the stopped server"
|
||||
httrack -O "$odir" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||
httrack -O "$out" --user-agent="httrack $ver local ($(uname -mrs))" \
|
||||
"${moreargs[@]}" "${hts[@]}" >"${log}.dead" 2>&1 &
|
||||
crawlpid=$!
|
||||
wait "$crawlpid" || true
|
||||
@@ -325,7 +308,7 @@ fi
|
||||
|
||||
# --- discover the single host root (127.0.0.1_<port> or 127.0.0.1) -----------
|
||||
hostroot=
|
||||
for cand in "${mirrorroot}/127.0.0.1_${port}" "${mirrorroot}/127.0.0.1"; do
|
||||
for cand in "${out}/127.0.0.1_${port}" "${out}/127.0.0.1"; do
|
||||
if test -d "$cand"; then
|
||||
hostroot="$cand"
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user