Compare commits

..

1 Commits

Author SHA1 Message Date
Xavier Roche
2494c65539 debian: restore the 3.49.10-2 changelog entry omitted from 3.49.11-1
The 3.49.10-2 FTBFS-fix upload was made straight to the archive and its
changelog entry was never committed back, so the 3.49.11-1 changelog
jumped from 3.49.10-1 to 3.49.11-1. The BTS derives its version graph
from upload changelogs, so #1140983 (fixed in 3.49.10-2) is counted as
still present in 3.49.11-1 and britney blocks testing migration.

Restore the entry verbatim from the archive; the BTS metadata itself is
corrected separately with a control message (fixed 1140983 3.49.11-1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-05 07:46:36 +02:00
51 changed files with 1728 additions and 1517 deletions

View File

@@ -283,6 +283,7 @@ int optalias_check(int argc, const char *const *argv, int n_arg,
char *position;
int need_param = 1;
//int return_param=0;
int pos;
command[0] = param[0] = addcommand[0] = '\0';
@@ -360,6 +361,7 @@ int optalias_check(int argc, const char *const *argv, int n_arg,
strlcatbuff(return_argv[0], "0", return_argv_size);
else if (strcmp(param, "on") == 0) {
// on is the default
// strcatbuff(return_argv[0],"1");
} else
strlcatbuff(return_argv[0], param, return_argv_size);
}

View File

@@ -43,12 +43,14 @@ Please visit our Website: http://www.httrack.com
#include "htsback.h"
//#ifdef _WIN32
#include "htsftp.h"
#if HTS_USEZLIB
#include "htszlib.h"
#else
#error HTS_USEZLIB not defined
#endif
//#endif
#ifdef _WIN32
#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) {
if (back[p].status == STATUS_READY) {
hts_log_print(opt, LOG_WARNING,
"incomplete transfer (expected " LLintP
" bytes, got " LLintP
"): file not cached, will be retried on the next update"
" (use -%%B to cache anyway): %s%s",
back[p].r.totalsize, back[p].r.size, back[p].url_adr,
back[p].url_fil);
"file not stored in cache due to bogus state (broken size, expected "
LLintP " got " LLintP "): %s%s", back[p].r.totalsize,
back[p].r.size, back[p].url_adr, back[p].url_fil);
} else {
hts_log_print(opt, LOG_INFO,
"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 (back[p].r.compressed) {
if (back[p].r.size > 0) {
//if ( (back[p].r.adr) && (back[p].r.size>0) ) {
// stats
back[p].compressed_size = back[p].r.size;
// 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);
} else {
/* Partial file, but marked as "ok" ? */
hts_log_print(
opt, LOG_WARNING,
"file with unresolved type not cached (%s (%d), size " LLintP
"): %s%s",
back[p].r.msg, back[p].r.statuscode, (LLint) back[p].r.size,
back[p].url_adr, back[p].url_fil);
hts_log_print(opt, LOG_WARNING,
"file not stored in cache due to bogus state (incomplete type with %s (%d), size "
LLintP "): %s%s", back[p].r.msg, back[p].r.statuscode,
(LLint) back[p].r.size, 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 */
back_connxfr(src, &tmp);
back_delete(opt, cache, sback, p);
//deletehttp(src);
back_connxfr(&tmp, src);
src->req.flush_garbage = 1; /* ignore CRLF garbage */
return 1;
@@ -1358,39 +1358,9 @@ int back_flush_output(httrackp * opt, cache_back * cache, struct_back * sback,
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
/* Discard a cancelled mid-write .delayed placeholder (unusable across runs). */
void back_delayed_discard(httrackp *opt, lien_back *back) {
static void back_delayed_discard(httrackp *opt, lien_back *back) {
if (back->r.out != NULL) {
fclose(back->r.out);
back->r.out = NULL;
@@ -1433,6 +1403,7 @@ int back_delete(httrackp * opt, cache_back * cache, struct_back * sback,
back[p].url_adr, back[p].url_fil, back[p].url_sav);
}
if (cache != NULL) {
//hts_log_print(opt, LOG_TRACE, "finalizing from back_delete");
back_finalize(opt, cache, sback, p);
}
}
@@ -1573,6 +1544,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
if (back[p].r.soc != INVALID_SOCKET) { /* we never know */
deletehttp(&back[p].r);
}
//memset(&(back[p].r), 0, sizeof(htsblk));
hts_init_htsblk(&back[p].r);
back[p].r.location = back[p].location_buffer;
@@ -1580,6 +1552,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
strcpybuff(back[p].url_adr, adr);
strcpybuff(back[p].url_fil, fil);
strcpybuff(back[p].url_sav, save);
//back[p].links_index = links_index;
// copier referer si besoin
strcpybuff(back[p].referer_adr, "");
strcpybuff(back[p].referer_fil, "");
@@ -1818,7 +1791,8 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
back[p].url_adr, back[p].url_fil);
}
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);
// finalize transfer
@@ -1833,6 +1807,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
} else { // erreur
// effacer r
hts_init_htsblk(&back[p].r);
//memset(&(back[p].r), 0, sizeof(htsblk));
back[p].r.location = back[p].location_buffer;
// et continuer (chercher le fichier)
}
@@ -2027,6 +2002,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
// ouvrir liaison, envoyer requète
// ne pas traiter ou recevoir l'en tête immédiatement
hts_init_htsblk(&back[p].r);
// memset(&(back[p].r), 0, sizeof(htsblk));
back[p].r.location = back[p].location_buffer;
// fresh connect: address list not yet probed, start at the first
sback->connect_fallback[p].addr_index = 0;
@@ -2077,6 +2053,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
#if HTS_USEOPENSSL
else if (strfield(back[p].url_adr, "https://")) { // let's rock
back[p].r.ssl = 1;
// back[p].r.ssl_soc = NULL;
back[p].r.ssl_con = NULL;
}
#endif
@@ -2142,9 +2119,9 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
back[p].rateout = -1; // pas de gestion (default)
}
// Note: on charge les code-page erreurs (erreur 404, etc) dans le cas où
// cela est rattrapable (exemple: 301,302 moved xxx -> refresh sur la
// page!)
// Note: on charge les code-page erreurs (erreur 404, etc) dans le cas où cela est
// rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
//if ((back[p].statuscode!=HTTP_OK) || (soc<0)) { // ERREUR HTTP/autre
#if CNXDEBUG
printf("Xfopen ok, poll..\n");
@@ -2162,6 +2139,7 @@ int back_add(struct_back * sback, httrackp * opt, cache_back * cache, const char
if (soc == INVALID_SOCKET) { // erreur socket
back[p].status = STATUS_READY; // FINI
back_set_finished(sback, p);
//if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
back[p].r.soc = INVALID_SOCKET;
} else {
if (!back[p].r.is_file)
@@ -2182,6 +2160,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
// le lien est considéré comme traité
//if (back[p].soc<0) // erreur
// return -1;
return 0;
} else {
@@ -2254,6 +2234,9 @@ void back_solve(httrackp * opt, lien_back * back) {
} else {
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);
//}
}
}
@@ -2302,6 +2285,11 @@ void back_clean(httrackp * opt, cache_back * cache, struct_back * sback) {
(void) back_flush_output(opt, cache, sback, i); // flush output buffers
usercommand(opt, 0, NULL, back[i].url_sav, back[i].url_adr,
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! */
{
int index = hash_read(opt->hash, back[i].url_sav, NULL, HASH_STRUCT_FILENAME ); // lecture type 0 (sav)
@@ -2485,6 +2473,9 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
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
FD_ZERO(&fds);
FD_ZERO(&fds_c);
@@ -2494,7 +2485,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
nfds = INVALID_SOCKET;
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);
// en cas de gestion du connect préemptif
@@ -2531,7 +2523,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
// poll pour la lecture sur les sockets
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
// non local et non ftp
if (!back[i].r.is_file) {
@@ -2617,7 +2610,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
busy_recv = 0;
// 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);
if (back[i].status > 0) {
@@ -2757,6 +2751,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
back[i].rateout_time = back[i].ka_time_start;
}
// envoyer header
//if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0) // vrai get
HTS_STAT.stat_nrequests++;
if (!back[i].head_request)
http_sendhead(opt, opt->cookie, 0, back[i].send_too,
@@ -2823,6 +2818,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
#if HTS_XGETHOST
else if (back[i].status == STATUS_WAIT_DNS) { // attendre gethostbyname
#if DEBUGDNS
//printf("status 101 for %s\n",back[i].url_adr);
#endif
if (!gestion_timeout)
@@ -3095,7 +3091,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
// Si réception chunk, tester si on est pas à la fin!
if (back[i].status == 1) {
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 */
if (back[i].chunk_adr != NULL) {
freet(back[i].chunk_adr);
@@ -3158,9 +3155,11 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
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 (!opt->tolerant) {
//#if HTS_CL_IS_FATAL
deleteaddr(&back[i].r);
if (back[i].r.size < back[i].r.totalsize)
back[i].r.statuscode = STATUSCODE_CONNERROR; // recatch
@@ -3169,13 +3168,14 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
" expected)", (LLint) back[i].r.size,
(LLint) back[i].r.totalsize);
} else {
//#else
// Un warning suffira..
hts_log_print(opt, LOG_WARNING,
"Incorrect length (" LLintP "!=" LLintP
" expected) for %s%s",
(LLint) back[i].r.size,
" expected) for %s%s", (LLint) back[i].r.size,
(LLint) back[i].r.totalsize, back[i].url_adr,
back[i].url_fil);
//#endif
}
}
}
@@ -3302,8 +3302,10 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
back[i].r.size);
#endif
/* 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);
//}
// finalize transfer if not temporary
if (!IS_DELAYED_EXT(back[i].url_sav)) {
@@ -3770,6 +3772,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
back[i].url_adr, back[i].url_fil);
// 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) {
hts_log_print(opt, LOG_TRACE, "finalizing after cache load");
back_finalize(opt, cache, sback, i);
@@ -3779,11 +3782,37 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
back[i].url_adr, back[i].url_fil);
#endif
//printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
} else { // erreur
back[i].status = STATUS_READY; // terminé
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
// the body (#58)
@@ -3957,6 +3986,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
deletehttp(&back[i].r);
}
back[i].r.soc = INVALID_SOCKET;
//back[i].r.statuscode=206; ????????
back[i].r.statuscode = STATUSCODE_NON_FATAL;
if (strnotempty(back[i].r.msg))
strcpybuff(back[i].r.msg,
@@ -3983,7 +4013,8 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
hts_log_print(opt, LOG_TRACE, "finalizing empty");
back_finalize(opt, cache, sback, i);
}
} else if (!back[i].r.is_chunk) { // pas de chunk
} else if (!back[i].r.is_chunk) { // pas de chunk
//if (back[i].r.http11!=2) { // pas de chunk
back[i].is_chunk = 0;
back[i].status = 1; // start body
} else {
@@ -4044,11 +4075,14 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
if (back[i].status < 0) {
if (!back[i].testmode) { // pas en test
UNLINK(back[i].url_sav); // éliminer fichier (endommagé)
//printf("&& %s\n",back[i].url_sav);
}
}
#endif
/* funny log for commandline users */
//if (!opt->quiet) {
// petite animation
if (opt->verbosedisplay == HTS_VERBOSE_SIMPLE) {
if (back[i].status == STATUS_READY) {
if (back[i].r.statuscode == HTTP_OK)
@@ -4061,16 +4095,18 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
fflush(stdout);
}
}
//}
} // status>0
} // for
} // for
// vérifier timeouts
if (gestion_timeout) {
TStamp act;
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);
if (back[i].status > 0) { // réception/connexion/..
@@ -4098,6 +4134,7 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
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) {
hts_log_print(opt, LOG_DEBUG, "connection timed out for %s%s", back[i].url_adr,
back[i].url_fil);

View File

@@ -113,12 +113,6 @@ void back_set_locked(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,
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);
int back_clear_entry(lien_back * back);
int back_flush_output(httrackp * opt, cache_back * cache, struct_back * sback,

View File

@@ -55,6 +55,8 @@ Please visit our Website: http://www.httrack.com
// inline function in Wspiapi.h.
#include <ws2tcpip.h>
#include <Wspiapi.h>
// #include <winsock2.h>
// #include <tpipv6.h>
#endif

View File

@@ -107,6 +107,7 @@ int cookie_add(t_cookie * cookie, const char *cook_name, const char *cook_value,
#if DEBUG_COOK
printf("add_new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",
cook_name, cook_value, domain, path);
//printf(">>>cook: %s<<<\n",cookie->data);
#endif
return 0;
}
@@ -207,6 +208,8 @@ int cookie_load(t_cookie * cookie, const char *fpath, const char *name) {
char catbuff[CATBUFF_SIZE];
char buffer[8192];
// cookie->data[0]='\0';
// Fusionner d'abord les éventuels cookies IE
#ifdef _WIN32
{

View File

@@ -40,7 +40,6 @@ Please visit our Website: http://www.httrack.com
#include "htscore.h"
#include "htsbasenet.h"
#include "htsmd5.h"
#include <limits.h>
#include <time.h>
#include "htszlib.h"
@@ -221,38 +220,23 @@ struct cache_back_zip_entry {
} \
} while(0)
/* Consecutive entry write failures before the cache stream is declared dead. */
#define CACHE_MAX_WRITE_FAILURES 8
/* Cache write failed: a fatal errno or a failure streak aborts the mirror
(exit_xh); an isolated failure only drops the current entry. */
/* A cache (new.zip) write failed: storage is gone (disk full / dropped share),
so the mirror is doomed too. Abort it via exit_xh, don't crash as assertf
did. */
static void cache_zip_write_failed(httrackp *opt, cache_back *cache,
const char *what, int zErr,
hts_boolean entry_open, const char *url_adr,
const char *url_fil) {
const int fatal_errno = zErr == ZIP_ERRNO && check_fatal_io_errno();
cache->zipWriteFailures++;
if (fatal_errno || cache->zipWriteFailures >= CACHE_MAX_WRITE_FAILURES) {
if (!cache->zipWriteFailed) {
cache->zipWriteFailed = HTS_TRUE;
if (fatal_errno) {
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));
}
const char *what, int zErr) {
if (!cache->zipWriteFailed) {
cache->zipWriteFailed = HTS_TRUE;
if (check_fatal_io_errno()) {
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 */
@@ -265,6 +249,8 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
char BIGSTK headers[8192];
int headersSize = 0;
//int entryBodySize = 0;
//int entryFilenameSize = 0;
zip_fileinfo fi;
const char *url_save_suffix = url_save;
int zErr;
@@ -300,19 +286,10 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
if (r->size < 0) // error
return;
// data in cache: the body must fit the 32-bit zip write API
if (dataincache && (LLint) (int) r->size != r->size) {
if (r->is_write && url_save != NULL && strnotempty(url_save)) {
hts_log_print(opt, LOG_WARNING,
"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;
}
// data in cache
if (dataincache) {
assertf(((int) r->size) == r->size);
//entryBodySize = (int) r->size;
}
/* 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-Save", url_save_suffix); // Original save filename
//entryFilenameSize = (int) ( strlen(url_adr) + strlen(url_fil));
/* Filename */
if (!link_has_authority(url_adr)) {
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 */
Z_DEFLATED, Z_DEFAULT_COMPRESSION)) != Z_OK) {
cache_zip_write_failed(opt, cache, "opening a cache entry", zErr, HTS_FALSE,
url_adr, url_fil);
cache_zip_write_failed(opt, cache, "opening a cache entry", zErr);
return;
}
@@ -402,8 +380,7 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
if ((zErr =
zipWriteInFileInZip((zipFile) cache->zipOutput, r->adr,
(int) r->size)) != Z_OK) {
cache_zip_write_failed(opt, cache, "writing to the cache", zErr,
HTS_TRUE, url_adr, url_fil);
cache_zip_write_failed(opt, cache, "writing to the cache", zErr);
return;
}
}
@@ -425,8 +402,8 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
if ((zErr =
zipWriteInFileInZip((zipFile) cache->zipOutput, buff,
(int) nl)) != Z_OK) {
cache_zip_write_failed(opt, cache, "writing to the cache", zErr,
HTS_TRUE, url_adr, url_fil);
cache_zip_write_failed(opt, cache, "writing to the cache",
zErr);
fclose(fp);
return;
}
@@ -442,19 +419,15 @@ void cache_add(httrackp * opt, cache_back * cache, const htsblk * r,
/* Close */
if ((zErr = zipCloseFileInZip((zipFile) cache->zipOutput)) != Z_OK) {
cache_zip_write_failed(opt, cache, "closing a cache entry", zErr, HTS_FALSE,
url_adr, url_fil);
cache_zip_write_failed(opt, cache, "closing a cache entry", zErr);
return;
}
/* Flush */
if ((zErr = zipFlush((zipFile) cache->zipOutput)) != 0) {
cache_zip_write_failed(opt, cache, "flushing the cache", zErr, HTS_FALSE,
url_adr, url_fil);
cache_zip_write_failed(opt, cache, "flushing the cache", zErr);
return;
}
cache->zipWriteFailures = 0; /* entry stored: reset the failure streak */
}
#else
@@ -721,6 +694,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
char BIGSTK headerBuff[8192 + 2];
int readSizeHeader;
//int totalHeader = 0;
int dataincache = 0;
/* For BIG comments */
@@ -771,10 +745,13 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
HTS_URLMAXSIZE * 2);
ZIP_READFIELD_STRING(line, value, "Content-Disposition", 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_,
sizeof(previous_save_));
}
} while (offset < readSizeHeader && !lineEof);
} while(offset < readSizeHeader && !lineEof);
//totalHeader = offset;
/* Previous entry */
if (previous_save_[0] != '\0') {
@@ -791,15 +768,6 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
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 */
r.totalsize = r.size;
r.adr = NULL;
@@ -826,8 +794,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
} // otherwise, the ZIP file is supposed to be consistent with data.
}
/* Read data ? */
else if (r.statuscode !=
STATUSCODE_INVALID) { /* ne pas lire uniquement header */
else { /* ne pas lire uniquement header */
int ok = 0;
#if HTS_DIRECTDISK
@@ -956,6 +923,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
r.statuscode = STATUSCODE_INVALID;
strcpybuff(r.msg,
"Cache Write Error : Unable to Create File");
//printf("%s\n",save);
}
}
@@ -990,10 +958,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
strcpybuff(r.msg,
"Previous cache file not found (empty filename)");
}
} else if (r.size >= INT_MAX) { /* too big to read in memory */
r.statuscode = STATUSCODE_INVALID;
strcpybuff(r.msg, "Cache Read Error : Bad Size");
} else { /* Read in memory from disk */
} else { /* Read in memory from disk */
FILE *const fp = FOPEN(fconv(catbuff, sizeof(catbuff), previous_save), "rb");
if (fp != NULL) {
@@ -1033,6 +998,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
strcpybuff(r.msg, "Cache Read Error : Read Data");
} else
*(r.adr + r.size) = '\0';
//printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
} else { // erreur
r.statuscode = STATUSCODE_INVALID;
strcpybuff(r.msg, "Cache Memory Error");
@@ -1211,14 +1177,17 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
// sécurité
r.adr = NULL;
r.out = NULL;
////r.location=NULL; non, fixée lors des 301 ou 302
r.fp = NULL;
if ((r.statuscode >= 0) && (r.statuscode <= 999)
&& (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.soc = INVALID_SOCKET;
// // r.location=NULL;
#if HTS_DIRECTDISK
// Court-circuit:
@@ -1227,11 +1196,12 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
int ok = 0;
r.is_write = 1; // écrire
if (fexist_utf8(fconv(catbuff, sizeof(catbuff),
save))) { // un fichier existe déja
if (fexist_utf8(fconv(catbuff, sizeof(catbuff), 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
filenote(&opt->state.strc, save, NULL); // noter comme connu
file_notify(opt, adr, fil, save, 0, 0, 0);
//}
}
if ((pos < 0) && (!ok)) { // Pas de donnée en cache et fichier introuvable : erreur!
@@ -1282,6 +1252,7 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
r.statuscode = STATUSCODE_INVALID;
strcpybuff(r.msg,
"Cache Write Error : Unable to Create File");
//printf("%s\n",save);
}
}
@@ -1329,13 +1300,14 @@ static htsblk cache_readex_old(httrackp * opt, cache_back * cache,
strcpybuff(r.msg, "Cache Read Error : Read Data");
} else
*(r.adr + r.size) = '\0';
//printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
} else { // erreur
r.statuscode = STATUSCODE_INVALID;
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 {
#if DEBUGCA
printf("Cache Read Error : Bad Data");
@@ -1448,86 +1420,6 @@ static int hts_rename(httrackp * opt, const char *a, const char *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
// return NULL upon error, and set -1 to r.statuscode
htsblk *cache_header(httrackp * opt, cache_back * cache, const char *adr,
@@ -1558,10 +1450,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"),
HTS_PROTECT_FOLDER);
#endif
if ((fexist(fconcat(
OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log),
"hts-cache/new.zip")))) { // a previous cache exists.. rename it
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
/* Previous cache from the previous cache version */
#if 0
/* 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 */
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
@@ -1602,13 +1509,7 @@ void cache_init(cache_back * cache, httrackp * opt) {
} else {
hts_log_print(opt, LOG_DEBUG, "Cache: successfully renamed");
}
} 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")))) { // a previous cache
// exists.. rename it
} 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
#if DEBUGCA
printf("work with former cache\n");
#endif
@@ -1637,7 +1538,7 @@ void cache_init(cache_back * cache, httrackp * opt) {
"hts-cache/new.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log),
"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
printf("new cache\n");
#endif
@@ -2006,6 +1907,12 @@ void cache_init(cache_back * cache, httrackp * opt) {
"hts-cache/new.lst"), "wb");
strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
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
if (fexist
@@ -2094,6 +2001,12 @@ void cache_init(cache_back * cache, httrackp * opt) {
"hts-cache/new.lst"), "wb");
strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
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
if (fexist
@@ -2125,6 +2038,8 @@ void cache_init(cache_back * cache, httrackp * opt) {
"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"
LF);
}
// test
// cache_writedata(cache->ndx,cache->dat,"//[TEST]//","test1","TEST PIPO",9);
} // cache->ndx!=NULL
} //cache->zipOutput != NULL

View File

@@ -78,17 +78,6 @@ htsblk *cache_header(httrackp * opt, cache_back * cache, const char *adr,
const char *fil, htsblk * r);
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,
const char *str2, char *outbuff, int len);
int cache_readdata(cache_back * cache, const char *str1, const char *str2,

View File

@@ -48,7 +48,6 @@ Please visit our Website: http://www.httrack.com
#include "htszlib.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
@@ -322,7 +321,6 @@ typedef struct {
size_t budget; /**< bytes allowed through before writes start failing */
int fail_errno; /**< errno set on the failing write (ENOSPC, EIO, ...) */
int writes; /**< zwrite call count, to detect re-entry into the stream */
int fail_once; /**< recover (unlimited budget) after the first failure */
} writefail_inject;
/* 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;
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;
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);
}
/* Store an entry claiming a >2GB body; the degrade path never reads data. */
static void writefail_store_oversized(httrackp *opt, cache_back *cache,
const char *fil, int is_write) {
htsblk r;
char locbuf[4];
hts_init_htsblk(&r);
r.statuscode = 200;
r.size = (LLint) INT_MAX + 1;
strcpybuff(r.msg, "OK");
strcpybuff(r.contenttype, "application/octet-stream");
locbuf[0] = '\0';
r.location = locbuf;
r.is_write = (short int) is_write;
cache_add(opt, cache, &r, "example.com", fil, "example.com/big.bin", 1, NULL);
}
/* Read back `entryname`: extra field (cached headers) and body. Returns the
body length, or -1 if the entry is absent or unreadable. */
static int writefail_read_entry(const char *path, const char *entryname,
char *extra, size_t extralen, char *body,
size_t bodylen) {
unzFile z = unzOpen(path);
int n = -1;
if (z == NULL)
return -1;
if (unzLocateFile(z, entryname, 1) == UNZ_OK &&
unzOpenCurrentFile(z) == UNZ_OK) {
const int elen = unzGetLocalExtrafield(z, extra, (unsigned) (extralen - 1));
if (elen >= 0) {
extra[elen] = '\0';
n = unzReadCurrentFile(z, body, (unsigned) bodylen);
}
unzCloseCurrentFile(z);
}
unzClose(z);
return n;
}
/* Cache write-failure policy (#174/#219): fatal errno or a failure streak
stops the mirror (exit_xh=-1, no crash); isolated/oversized drops the entry.
*/
/* #174/#219: a failing cache write used to crash via assertf(); it must instead
stop the mirror (exit_xh = -1) without crashing. Assert that, plus the cache
is flagged and a sibling write doesn't re-enter the broken stream. */
int cache_write_failure_selftest(httrackp *opt, const char *dir) {
int fail = 0;
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 */);
fconcat(path, sizeof(path), dir, "/wfail.zip");
/* phase 0: fatal errno (ENOSPC) aborts at once; phase 1: persistent EIO
drops entries until the streak caps out, then aborts. */
/* phase 0: fail on the body write, fatal errno (ENOSPC, the disk-full
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++) {
cache_back cache;
writefail_inject inj;
@@ -443,7 +399,6 @@ int cache_write_failure_selftest(httrackp *opt, const char *dir) {
inj.budget = (phase == 0) ? 4096 : 0;
inj.fail_errno = (phase == 0) ? ENOSPC : EIO;
inj.writes = 0;
inj.fail_once = 0;
memset(&cache, 0, sizeof(cache));
cache.type = 1;
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 */
if (phase == 0) {
writefail_store(opt, &cache, "/blob.bin", body, body_len);
} else {
/* the abort must land exactly on the 8th consecutive failure */
int i;
for (i = 0; i < 7; i++) {
char fil[32];
snprintf(fil, sizeof(fil), "/b%d.bin", i);
writefail_store(opt, &cache, fil, body, 16);
}
if (cache.zipWriteFailed) {
fprintf(stderr, "cache-writefail: phase 1: aborted before the "
"8th consecutive failure\n");
fail++;
}
writefail_store(opt, &cache, "/b7.bin", body, 16);
}
writefail_store(opt, &cache, "/blob.bin", body, body_len);
if (!cache.zipWriteFailed) {
fprintf(stderr, "cache-writefail: phase %d: write error not caught\n",
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);
return fail;
}
@@ -909,494 +716,3 @@ int cache_golden_selftest(httrackp *opt, const char *dir, int regen) {
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;
}

View File

@@ -52,19 +52,10 @@ int cache_selftests(httrackp *opt, const char *dir);
committed file, never by the test). Returns the failed-check count. */
int cache_golden_selftest(httrackp *opt, const char *dir, int regen);
/* Cache write-failure policy (#174/#219): abort on fatal errno or a streak,
drop just the entry otherwise. Returns the failed-check count. */
/* #174/#219: assert a failing cache write aborts the mirror cleanly instead of
crashing. Returns the failed-check count. */
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

View File

@@ -197,6 +197,7 @@ HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
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
// Lire en têtes restants
sprintf(data, "%s %s %s\r\n", method, af.fil, protocol);
@@ -206,8 +207,8 @@ HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
strlcatbuff(data, line, CATCH_URL_DATA_SIZE);
strlcatbuff(data, "\r\n", CATCH_URL_DATA_SIZE);
}
// CR/LF final de l'en tête inutile car déja placé via la ligne vide
// juste au dessus
// CR/LF final de l'en tête inutile car déja placé via la ligne vide juste au dessus
//strcatbuff(data,"\r\n");
if (blkretour.totalsize > 0) {
int len = (int) min(blkretour.totalsize, 32000);
int pos = (int) strlen(data);

View File

@@ -841,6 +841,71 @@ static unsigned int nlz8(unsigned char x) {
} \
} 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. */
#undef ADD_BYTE
#undef INCREASE_CAPA

View File

@@ -54,6 +54,10 @@ Please visit our Website: http://www.httrack.com
// extension par défaut pour fichiers n'en ayant pas
#define DEFAULT_EXT ".html"
#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..
#define HTS_OVERRIDE_DOS_FOLDERS 1
@@ -76,6 +80,10 @@ Please visit our Website: http://www.httrack.com
// always direct-to-disk (0/1)
#define HTS_DIRECTDISK_ALWAYS 1
// gérer une table de hachage?
// REMOVED
// #define HTS_HASH 1
// fast cache (build hash table)
#define HTS_FAST_CACHE 1
@@ -89,10 +97,27 @@ Please visit our Website: http://www.httrack.com
// always transform a '//' into a sigle '/'
#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
// (non fixé pour cause de retry)
#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
// connect non bloquant? (poll sur write)

View File

@@ -119,93 +119,46 @@ hts_log_print(opt, LOG_INFO, "engine: end"); \
RUN_CALLBACK0(opt, end); \
}
#define XH_extuninit \
do { \
HTMLCHECK_UNINIT \
hts_record_free(opt); \
if (filters && filters[0]) { \
freet(filters[0]); \
filters[0] = NULL; \
} \
if (filters) { \
freet(filters); \
filters = NULL; \
} \
back_delete_all(opt, &cache, sback); \
back_free(&sback); \
checkrobots_free(&robots); \
if (cache.use) { \
freet(cache.use); \
cache.use = NULL; \
} \
if (cache.dat) { \
fclose(cache.dat); \
cache.dat = NULL; \
} \
if (cache.ndx) { \
fclose(cache.ndx); \
cache.ndx = NULL; \
} \
if (cache.zipOutput) { \
zipClose(cache.zipOutput, \
"Created by HTTrack Website Copier/" HTTRACK_VERSION); \
cache.zipOutput = NULL; \
} \
if (cache.zipInput) { \
unzClose(cache.zipInput); \
cache.zipInput = NULL; \
} \
if (cache.olddat) { \
fclose(cache.olddat); \
cache.olddat = NULL; \
} \
if (cache.lst) { \
fclose(cache.lst); \
cache.lst = opt->state.strc.lst = NULL; \
} \
if (cache.txt) { \
fclose(cache.txt); \
cache.txt = NULL; \
} \
if (opt->log != NULL) \
fflush(opt->log); \
if (makestat_fp) { \
fclose(makestat_fp); \
makestat_fp = NULL; \
} \
if (maketrack_fp) { \
fclose(maketrack_fp); \
maketrack_fp = NULL; \
} \
if (opt->accept_cookie) \
cookie_save(opt->cookie, \
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), \
StringBuff(opt->path_log), "cookies.txt")); \
if (makeindex_fp) { \
fclose(makeindex_fp); \
makeindex_fp = NULL; \
} \
if (cache_hashtable) { \
coucal_delete(&cache_hashtable); \
} \
if (cache_tests) { \
coucal_delete(&cache_tests); \
} \
if (template_header) { \
freet(template_header); \
template_header = NULL; \
} \
if (template_body) { \
freet(template_body); \
template_body = NULL; \
} \
if (template_footer) { \
freet(template_footer); \
template_footer = NULL; \
} \
hash_free(&hash); \
clearCallbacks(&opt->state.callbacks); \
} while (0)
#define XH_extuninit do { \
HTMLCHECK_UNINIT \
hts_record_free(opt); \
if (filters && filters[0]) { \
freet(filters[0]); filters[0]=NULL; \
} \
if (filters) { \
freet(filters); filters=NULL; \
} \
back_delete_all(opt,&cache,sback); \
back_free(&sback); \
checkrobots_free(&robots);\
if (cache.use) { freet(cache.use); cache.use=NULL; } \
if (cache.dat) { fclose(cache.dat); cache.dat=NULL; } \
if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
if (cache.zipOutput) { \
zipClose(cache.zipOutput, "Created by HTTrack Website Copier/"HTTRACK_VERSION); \
cache.zipOutput = NULL; \
} \
if (cache.zipInput) { \
unzClose(cache.zipInput); \
cache.zipInput = NULL; \
} \
if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
if (cache.lst) { fclose(cache.lst); cache.lst=opt->state.strc.lst=NULL; } \
if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
if (opt->log != NULL) fflush(opt->log); \
if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
if (opt->accept_cookie) cookie_save(opt->cookie,fconcat(OPT_GET_BUFF(opt),OPT_GET_BUFF_SIZE(opt),StringBuff(opt->path_log),"cookies.txt")); \
if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
if (cache_hashtable) { coucal_delete(&cache_hashtable); } \
if (cache_tests) { coucal_delete(&cache_tests); } \
if (template_header) { freet(template_header); template_header=NULL; } \
if (template_body) { freet(template_body); template_body=NULL; } \
if (template_footer) { freet(template_footer); template_footer=NULL; } \
hash_free(&hash); \
clearCallbacks(&opt->state.callbacks); \
/*structcheck_init(-1);*/ \
} while(0)
#define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
struct lien_buffers {
@@ -570,6 +523,7 @@ int httpmirror(char *url1, httrackp * opt) {
hash_struct *const hashptr = &hash;
t_cookie BIGSTK cookie; // gestion des cookies
//char* tab_alloc=NULL;
int ptr; // pointeur actuel sur les liens
//
@@ -580,12 +534,15 @@ int httpmirror(char *url1, httrackp * opt) {
// pour les stats, nombre de fichiers & octets écrits
LLint stat_fragment = 0; // pour la fragmentation
//TStamp istat_timestart; // départ pour calcul instantanné
//
TStamp last_info_shell = 0;
int info_shell = 0;
// filtres
char **filters = NULL;
//int filter_max=0;
int filptr = 0;
//
@@ -625,6 +582,7 @@ int httpmirror(char *url1, httrackp * opt) {
// noter heure actuelle de départ en secondes
memset(&HTS_STAT, 0, sizeof(HTS_STAT));
HTS_STAT.stat_timestart = time_local();
//istat_timestart=stat_timestart;
HTS_STAT.istat_timestart[0] = HTS_STAT.istat_timestart[1] = mtime_local();
/* reset stats */
HTS_STAT.HTS_TOTAL_RECV = 0;
@@ -658,6 +616,9 @@ int httpmirror(char *url1, httrackp * opt) {
// initialiser usercommand
usercommand(opt, opt->sys_com_exec, StringBuff(opt->sys_com), "", "", "");
// initialiser structcheck
// structcheck_init(1);
// initialiser verif_backblue
verif_backblue(opt, NULL);
verif_external(opt, 0, 0);
@@ -677,6 +638,9 @@ int httpmirror(char *url1, httrackp * opt) {
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_bin),
"templates/index-footer.html"), HTS_INDEX_FOOTER);
// initialiser mimedefs
//get_userhttptype(opt,1,StringBuff(opt->mimedefs),NULL);
// Initialiser indexation
if (opt->kindex)
index_init(StringBuff(opt->path_html));
@@ -720,6 +684,7 @@ int httpmirror(char *url1, httrackp * opt) {
opt->filters.filters = &filters;
//
opt->filters.filptr = &filptr;
//opt->filters.filter_max=&filter_max;
// hash table
opt->hash = &hash;
@@ -766,7 +731,8 @@ int httpmirror(char *url1, httrackp * opt) {
else if (*a == '-')
joker = 1;
if (joker) { // joker ou filters
if (joker) { // joker ou filters
//char* p;
char BIGSTK tempo[HTS_URLMAXSIZE * 2];
int type;
int plus = 0;
@@ -821,11 +787,12 @@ int httpmirror(char *url1, httrackp * opt) {
XH_extuninit;
return 0;
}
//opt->filters.filters=filters;
}
}
} else { // adresse normale
} else { // adresse normale
char BIGSTK url[HTS_URLMAXSIZE * 2];
// prochaine adresse
@@ -900,6 +867,7 @@ int httpmirror(char *url1, httrackp * opt) {
htsbuff_cat(&primarybuff, "\n");
}
}
// fclose(fp);
hts_log_print(opt, LOG_NOTICE, "%d links added from %s", n,
StringBuff(opt->filelist));
@@ -954,6 +922,7 @@ int httpmirror(char *url1, httrackp * opt) {
#endif
// backing
//soc_max=opt->maxsoc;
if (opt->maxsoc > 0) {
#if BDEBUG==2
_CLRSCR;
@@ -1267,10 +1236,15 @@ int httpmirror(char *url1, httrackp * opt) {
// tester r.adr
if (!error) {
// erreur, pas de fichier chargé:
if ((!r.adr) && (r.is_write == 0) && (r.statuscode != 301) &&
(r.statuscode != 302) && (r.statuscode != 303) &&
(r.statuscode != 307) && (r.statuscode != 412) &&
(r.statuscode != 416)) {
if ((!r.adr) && (r.is_write == 0)
&& (r.statuscode != 301)
&& (r.statuscode != 302)
&& (r.statuscode != 303)
&& (r.statuscode != 307)
&& (r.statuscode != 412)
&& (r.statuscode != 416)
) {
// error=1;
// peut être que le fichier était trop gros?
if ((istoobig
@@ -1352,8 +1326,30 @@ int httpmirror(char *url1, httrackp * opt) {
||may_be_hypertext_mime(opt, r.contenttype, urlfil())) /* Is real media, .. */
) {
/* Convert charset to UTF-8 - NOT! (what about links ? remote server
* side will have troubles with converted names) */
/* Convert charset to UTF-8 - NOT! (what about links ? remote server side will have troubles with converted names) */
//if (r.adr != NULL && r.size != 0 && opt->convert_utf8) {
// char *charset;
// char *pos;
// if (r.charset[0] != '\0') {
// charset = strdup(r.charset);
// } else {
// charset = hts_getCharsetFromMeta(r.adr, r.size);
// }
// if (charset != NULL) {
// char *const utf8 = hts_convertStringToUTF8(r.adr, r.size, charset);
// /* Use new buffer */
// if (utf8 != NULL) {
// freet(r.adr);
// r.size = strlen(utf8);
// r.adr = utf8;
// /* New UTF-8 charset */
// r.charset[0] = '\0';
// strcpy(r.charset, "utf-8");
// }
// /* Free charset */
// free(charset);
// }
//}
/* Check bogus chars */
if ((r.adr) && (r.size)) {
@@ -1494,6 +1490,50 @@ int httpmirror(char *url1, httrackp * opt) {
}
}
// MOVED IN back_finalize()
//
// --------------------
// REAL MEDIA HACK
// Check if we have to load locally the file
// --------------------
//if (!error) {
// if (r.statuscode == HTTP_OK) { // OK (ou 304 en backing)
// if (r.adr==NULL) { // Written file
// if (may_be_hypertext_mime(r.contenttype, urlfil())) { // to parse!
// LLint sz;
// sz=fsize_utf8(savename());
// if (sz>0) { // ok, exists!
// if (sz < 8192) { // ok, small file --> to parse!
// FILE* fp=FOPEN(savename(),"rb");
// if (fp) {
// r.adr=malloct(sz + 1);
// if (r.adr) {
// if (fread(r.adr,1,sz,fp) == sz) {
// r.size=sz;
// r.adr[sz] = '\0';
// r.is_write = 0;
// } else {
// freet(r.adr);
// r.size=0;
// r.adr = NULL;
// r.statuscode=STATUSCODE_INVALID;
// strcpybuff(r.msg, ".RAM read error");
// }
// fclose(fp);
// fp=NULL;
// // remove (temporary) file!
// remove(savename());
// }
// if (fp)
// fclose(fp);
// }
// }
// }
// }
// }
// }
//}
// EN OF REAL MEDIA HACK
// ---stockage en cache---
// stocker dans le cache?
@@ -1614,6 +1654,24 @@ int httpmirror(char *url1, httrackp * opt) {
}
#endif
/* info: updated */
/*
if (ptr>0) {
// "mis à jour"
if ((!r.notmodified) && (opt->is_update) && (!store_errpage)) { // page modifiée
if (strnotempty(savename())) {
HTS_STAT.stat_updated_files++;
//if ((opt->debug>0) && (opt->log!=NULL)) {
hts_log_print(opt, LOG_INFO, "File updated: %s%s",urladr(),urlfil());
}
} else {
if (!store_errpage) {
hts_log_print(opt, LOG_INFO, "File recorded: %s%s",urladr(),urlfil());
}
}
}
*/
// ------------------------------------------------------
// traitement (parsing)
// ------------------------------------------------------
@@ -1659,8 +1717,13 @@ int httpmirror(char *url1, httrackp * opt) {
free(charset);
}
/* Could not detect charset: could it be UTF-8 ? */
/* No, we can not do that: browsers do not do it
/* No, we can not do that: browsers do not do it
(and it would break links). */
//if (page_charset[0] == '\0') {
// if (is_unicode_utf8(r.adr, r.size)) {
// strcpy(page_charset, "utf-8");
// }
//}
/* Could not detect charset */
if (page_charset[0] == '\0') {
hts_log_print(opt, LOG_INFO,
@@ -1738,6 +1801,10 @@ int httpmirror(char *url1, httrackp * opt) {
XH_uninit;
return -1;
}
// I'll have to segment this part
// #include "htsparse.c"
}
}
// Fin parsing HTML
@@ -1833,6 +1900,7 @@ int httpmirror(char *url1, httrackp * opt) {
HTS_STAT.stat_files++;
HTS_STAT.stat_bytes+=r.size;
*/
//printf("ok......\n");
} else {
// Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
// récursion nous en empêche
@@ -1901,6 +1969,8 @@ int httpmirror(char *url1, httrackp * opt) {
}
}
//printf("extern=%s\n",r.contenttype);
// ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!
if (r.adr != NULL || r.size == 0) {
file_notify(opt, urladr(), urlfil(), savename(), 1, 1, r.notmodified);
@@ -2022,9 +2092,16 @@ int httpmirror(char *url1, httrackp * opt) {
// prochain pass2
while((ptr < opt->lien_tot) ? (!heap(ptr)->pass2) : 0)
ptr++;
//printf("first link==%d\n");
}
}
}
// copy abort state if necessary from outside
//if (!exit_xh && opt->state.exit_xh) {
// exit_xh=opt->state.exit_xh;
//}
// a-t-on dépassé le quota?
if (!back_checkmirror(opt)) {
ptr = opt->lien_tot;
@@ -2060,7 +2137,47 @@ int httpmirror(char *url1, httrackp * opt) {
hts_log_print(opt, LOG_NOTICE,
"No data seems to have been transferred during this session! : restoring previous one!");
XH_uninit;
hts_cache_reconcile(opt, CACHE_RECONCILE_ROLLBACK);
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
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
"hts-cache/new.lst"));
remove(fconcat
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
"hts-cache/new.txt"));
rename(fconcat
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
"hts-cache/old.dat"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log),
"hts-cache/new.dat"));
rename(fconcat
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
"hts-cache/old.ndx"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log),
"hts-cache/new.ndx"));
rename(fconcat
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
"hts-cache/old.lst"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log),
"hts-cache/new.lst"));
rename(fconcat
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
"hts-cache/old.txt"), fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log),
"hts-cache/new.txt"));
}
opt->state.exit_xh = 2; /* interrupted (no connection detected) */
return 1;
}
@@ -2181,11 +2298,13 @@ int httpmirror(char *url1, httrackp * opt) {
char BIGSTK htstime[256];
char BIGSTK infoupdated[256];
// int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
LLint n =
(LLint) (HTS_STAT.HTS_TOTAL_RECV /
(max(1, time_local() - HTS_STAT.stat_timestart)));
sec2str(htstime, time_local() - HTS_STAT.stat_timestart);
//sprintf(finalInfo + strlen(finalInfo),LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
infoupdated[0] = '\0';
if (opt->is_update) {
if (HTS_STAT.stat_updated_files > 0) {
@@ -2268,6 +2387,12 @@ int httpmirror(char *url1, httrackp * opt) {
*/
int engine_stats(void) {
#if 0
static FILE *debug_fp = NULL; /* ok */
if (!debug_fp)
debug_fp = fopen("esstat.txt", "wb");
#endif
HTS_STAT.stat_nsocket = HTS_STAT.stat_errors = HTS_STAT.nbk = 0;
HTS_STAT.nb = 0;
if (HTS_STAT.HTS_TOTAL_RECV > 2048) {
@@ -2278,6 +2403,10 @@ int engine_stats(void) {
if ((cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
TStamp dif;
#if 0
fprintf(debug_fp, "set timer %d\n", i);
fflush(debug_fp);
#endif
dif = cdif - HTS_STAT.istat_timestart[i];
if ((TStamp) (dif / 1000) > 0) {
LLint byt = (HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
@@ -2296,6 +2425,10 @@ int engine_stats(void) {
// timer #0 resync timer #1 when reaching 1 second limit
if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
if ((cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
#if 0
fprintf(debug_fp, "resync timer 1\n");
fflush(debug_fp);
#endif
HTS_STAT.istat_bytes[1] = HTS_STAT.HTS_TOTAL_RECV;
HTS_STAT.istat_timestart[1] = cdif;
HTS_STAT.istat_reference01 = HTS_STAT.istat_timestart[0];
@@ -2316,6 +2449,7 @@ void host_ban(httrackp * opt, int ptr,
lien_back *const back = sback->lnk;
const int back_max = sback->count;
//int l;
int i;
if (host[0] == '!')
@@ -2372,7 +2506,9 @@ void host_ban(httrackp * opt, int ptr,
}
// effacer liens
for (i = 0; i < opt->lien_tot; i++) {
//l=strlen(host);
for(i = 0; i < opt->lien_tot; i++) {
//if (heap(i)->adr_len==l) { // même taille de chaîne
// Calcul de taille sécurisée
if (heap(i)) {
if (heap(i)->adr) {
@@ -2411,6 +2547,7 @@ void host_ban(httrackp * opt, int ptr,
"WARNING! HostCancel detected memory leaks [null at %d]",
i);
}
//}
}
}
@@ -2755,9 +2892,6 @@ int check_fatal_io_errno(void) {
#endif
#ifdef EROFS
case EROFS: /* Read-only file system */
#endif
#ifdef EDQUOT
case EDQUOT: /* Disk quota exceeded */
#endif
return 1;
break;
@@ -2827,6 +2961,7 @@ FILE *fileappend(filenote_strc * strc, const char *s) {
// noter lst
filenote(strc, s, NULL);
// if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s); // pas de / (root!!) // ** SIIIIIII!!! à cause de -O <path>
strcpybuff(fname, s);
#if HTS_DOSNAME
@@ -2870,6 +3005,7 @@ int filecreateempty(filenote_strc * strc, const char *filename) {
int filenote(filenote_strc * strc, const char *s, filecreate_params * params) {
// gestion du fichier liste liste
if (params) {
//filecreate_params* p = (filecreate_params*) params;
strcpybuff(strc->path, params->path);
strc->lst = params->lst;
return 0;
@@ -2949,8 +3085,9 @@ void usercommand_exe(const char *cmd, const char *file) {
}
}
static void postprocess_file(httrackp *opt, const char *save, const char *adr,
static void postprocess_file(httrackp * opt, const char *save, const char *adr,
const char *fil) {
//int first = 0;
/* MIME-html archive to build */
if (opt != NULL && opt->mimehtml) {
if (adr != NULL && strcmp(adr, "primary") == 0) {
@@ -2978,6 +3115,7 @@ static void postprocess_file(httrackp *opt, const char *save, const char *adr,
}
if (!opt->state.mimehtml_created) {
//first = 1;
opt->state.mimefp =
fopen(fconcat
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
@@ -3121,6 +3259,28 @@ int fspc(httrackp * opt, FILE * fp, const char *type) {
return 0;
}
// vérifier taux de transfert
#if 0
void check_rate(TStamp stat_timestart, int maxrate) {
// vérifier taux de transfert (pas trop grand?)
/*
if (maxrate>0) {
int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart)); // taux actuel de transfert
HTS_STAT.HTS_TOTAL_RECV_STATE=0;
if (r>maxrate) { // taux>taux autorisé
int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
if (taux<15)
HTS_STAT.HTS_TOTAL_RECV_STATE=1; // ralentir un peu (<15% dépassement)
else if (taux<50)
HTS_STAT.HTS_TOTAL_RECV_STATE=2; // beaucoup (<50% dépassement)
else
HTS_STAT.HTS_TOTAL_RECV_STATE=3; // énormément (>50% dépassement)
}
}
*/
}
#endif
// ---
// sous routines liées au moteur et au backing
@@ -3130,8 +3290,21 @@ int backlinks_done(const struct_back * sback,
int ptr) {
int n = 0;
#if 0
int i;
//Links done and stored in cache
for(i = ptr + 1; i < lien_tot; i++) {
if (heap(i)) {
if (heap(i)->pass2 == -1) {
n++;
}
}
}
#else
// finalized in background
n += HTS_STAT.stat_background;
#endif
n += back_done_incache(sback);
return n;
}
@@ -3268,7 +3441,8 @@ int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
/* on a déja parcouru */
if (p < cache->ptr_ant)
p = cache->ptr_ant;
while (p < opt->lien_tot && n > 0 && back_checkmirror(opt)) {
while(p < opt->lien_tot && n > 0 && back_checkmirror(opt)) {
//while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
int ok = 1;
// on ne met pas le fichier en backing si il doit être traité après ou s'il a déja été traité
@@ -3280,6 +3454,12 @@ int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
ok = 0;
}
// Why in hell did I do that ?
//if (ok && heap(p)->sav != NULL && heap(p)->sav[0] != '\0'
// && hash_read(opt->hash,heap(p)->sav,NULL,HASH_STRUCT_FILENAME ) >= 0) // lookup in liens_record
//{
// ok = 0;
//}
if (heap(p)->sav == NULL || heap(p)->sav[0] == '\0'
|| hash_read(opt->hash, heap(p)->sav, NULL, HASH_STRUCT_FILENAME ) < 0) {
ok = 0;
@@ -3308,7 +3488,7 @@ int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
}
}
p++;
} // while
} // while
/* sauver position dernière anticipation */
cache->ptr_ant = p;
cache->ptr_last = ptr;
@@ -3570,7 +3750,20 @@ HTSEXT_API hts_boolean hts_has_stopped(httrackp *opt) {
return ended;
}
// régler en cours de route les paramètres réglables..
// -1 : erreur
//HTSEXT_API int hts_setopt(httrackp* set_opt) {
// if (set_opt) {
// httrackp* engine_opt=hts_declareoptbuffer(NULL);
// if (engine_opt) {
// //_hts_setopt=opt;
// copy_htsopt(set_opt,engine_opt);
// }
// }
// return 0;
//}
// ajout d'URL
// -1 : erreur
HTSEXT_API hts_boolean hts_addurl(httrackp *opt, char **url) {
if (url)
opt->state._hts_addurl = url;
@@ -3831,7 +4024,10 @@ int htsAddLink(htsmoduleStruct * str, char *link) {
heap_top()->link_import = 0; // pas mode import
// écrire autres paramètres de la structure-lien
//if (meme_adresse)
heap_top()->premier = heap(ptr)->premier;
//else // sinon l'objet père est le précédent lui même
// heap_top()->premier=ptr;
heap_top()->precedent = ptr;
// noter la priorité
@@ -3842,6 +4038,9 @@ int htsAddLink(htsmoduleStruct * str, char *link) {
heap_top()->pass2 = max(pass_fix, numero_passe);
heap_top()->retry = opt->retry;
//strcpybuff(heap_top()->adr,adr);
//strcpybuff(heap_top()->fil,fil);
//strcpybuff(heap_top()->sav,save);
hts_log_print(opt, LOG_DEBUG, "(module): OK, NOTE: %s%s -> %s",
heap_top()->adr, heap_top()->fil,
heap_top()->sav);

View File

@@ -216,7 +216,6 @@ struct cache_back {
int zipEntriesCapa;
hts_boolean
zipWriteFailed; /**< a cache write failed; stop touching the stream */
int zipWriteFailures; /**< consecutive entry write failures; reset on store */
};
#ifndef HTS_DEF_FWSTRUCT_hash_struct
@@ -412,6 +411,10 @@ char *readfile_utf8(const char *fil);
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).
Not thread-safe; call from the single crawl loop. */
@@ -463,6 +466,11 @@ int ask_continue(httrackp * opt);
/* Number of decimal digits in n. */
int nombre_digit(int n);
// Java
#if 0
int hts_add_file(char *file, int file_position);
#endif
// Polling
#if HTS_POLL
int check_flot(T_SOC s);

View File

@@ -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
int url_sz = 65535;
//char url[65536]; // URLS séparées par un espace
// the parametres
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 (!cmdl_opt(tmp_argv[0])) { /* pas -c0 & co */
if (argv_url < 0)
argv_url = 0; // -1==force -> 1=one url already detected, wipe all
// previous options
argv_url = 0; // -1==force -> 1=one url already detected, wipe all previous options
//if (argv_url>=0) {
argv_url++;
if (!argv_firsturl)
argv_firsturl = x_argv[x_argc - 1];
//}
} else {
if (strcmp(tmp_argv[0], "-h") == 0) {
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) {
if ((strcmp(tmp_argv[0], "-%L") == 0)) { // liste d'URLs
if (argv_url < 0)
argv_url = 0; // -1==force -> 1=one url already detected, wipe all
// previous options
argv_url = 0; // -1==force -> 1=one url already detected, wipe all previous options
//if (argv_url>=0)
argv_url++; /* forcer */
}
}
@@ -401,11 +403,15 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
else
inQuote = 1;
} else if (!inQuote && !noDbl && argv[na][i] == ',') {
//StringAddchar(path, '\0');
//j = 0;
path = &opt->path_log;
} else {
StringAddchar(*path, argv[na][i]);
//path[j++] = argv[na][i];
}
}
//path[j++] = '\0';
if (StringLength(opt->path_log) == 0) {
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)) {
opt->dir_topindex = 1; // rebuilt top index
}
//printf("-->%s\n%s\n",StringBuff(opt->path_html),StringBuff(opt->path_log));
}
break;
} // switch
@@ -532,15 +539,74 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
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
printf("Checking cache\n");
#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 */
if (!opt->quiet) {
@@ -708,6 +774,24 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
HTS_PANIC_PRINTF(s);
htsmain_free();
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
}
//
@@ -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
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
// un fichier log existe?
if (fexist(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log),
"hts-in_progress.lock"))) { // fichier lock?
StringBuff(opt->path_log), "hts-in_progress.lock"))) { // fichier lock?
//char s[32];
opt->cache = HTS_CACHE_PRIORITY; // cache prioritaire
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),
StringBuff(opt->path_html), "index.html"))) {
} else
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;
if (opt->quiet == 0) {
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
opt->wizard = HTS_WIZARD_AUTO;
//opt->wizard=0; // pas de wizard
opt->cache = HTS_CACHE_NONE; // ni de cache
opt->makeindex = 0; // ni d'index
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)))
com++;
break;
//
//case 'A': opt->urlmode=1; break;
//case 'R': opt->urlmode=2; break;
case 'K':
opt->urlmode = HTS_URLMODE_ABSOLUTE;
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)))
com++;
}
//if (*(com+1)=='0') { opt->urlmode=2; com++; } break;
//
case 'c':
if (isdigit((unsigned char) *(com + 1))) {
sscanf(com + 1, "%d", &opt->maxsoc);
@@ -1556,6 +1746,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
} else {
char *a;
//char* b = StringBuff(opt->mimedefs) + StringLength(opt->mimedefs);
for(a = argv[na]; *a != '\0'; a++) {
if (*a == ';') { /* next one */
StringAddchar(opt->mimedefs, '\n');
@@ -1894,7 +2085,10 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
HTS_PANIC_PRINTF(s);
htsmain_free();
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;
@@ -2138,7 +2332,15 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
return 0;
break;
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;
case 'f':
opt->flush = 1;
@@ -2240,6 +2442,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
opt->proxy.active = 1;
// Rechercher MAIS en partant de la fin à cause de user:pass@proxy:port
a = argv[na] + strlen(argv[na]) - 1;
// a=strstr(argv[na],":"); // port
while((a > argv[na]) && (*a != ':') && (*a != '@'))
a--;
if (*a == ':') { // un port est présent, <proxy>:port
@@ -2344,14 +2547,116 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
#endif
#endif
//printf("WARNING! This is *only* a beta-release of HTTrack\n");
io_flush;
#if DEBUG_STEPS
printf("Cache & log settings\n");
#endif
// If both cache generations exist, keep the most complete one
hts_cache_reconcile(opt, CACHE_RECONCILE_INTERRUPTED);
// on utilise le cache..
// 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
if (_DEBUG_HEAD) {
ioinfo =
@@ -2427,6 +2732,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
{
FILE *fp = NULL;
//int n=0;
char t[256];
time_local_rfc822(t); // faut bien que ca serve quelque part l'heure RFC1945 arf'
@@ -2460,8 +2766,9 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
}
strcpybuff(n_lock,
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-in_progress.lock"));
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log),
"hts-in_progress.lock"));
//sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
/*do {
if (!n)
sprintf(n_lock,fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-in_progress.lock"),n);
@@ -2537,6 +2844,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
fprintf(fp, LF);
fclose(fp);
fp = NULL;
//} else if (opt->debug>1) {
// printf("! FileOpen error, \"%s\"\n",strerror(errno));
}
}
// petit message dans le lock

View File

@@ -102,8 +102,9 @@ int fa_strjoker(int type, char **filters, int nfil, const char *nom, LLint * siz
// cet algo est 'un peu' récursif mais ne consomme pas trop de tm
// * = toute lettre
// --?-- : spécifique à HTTrack et aux ?
HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
LLint *size, int *size_flag) {
HTS_INLINE const char *strjoker(const char *chaine, const char *joker, LLint * size,
int *size_flag) {
//int err=0;
if (strnotempty(joker) == 0) { // fin de chaine joker
if (strnotempty(chaine) == 0) // fin aussi pour la chaine: ok
return chaine;
@@ -235,7 +236,9 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
for(j = (int) (unsigned char) joker[i];
j <= (int) (unsigned char) joker[i + 2]; j++)
pass[j] = 1;
}
// else err=1;
i += 3;
} else { // 1 car, ex: *[ ]
pass[(int) (unsigned char) joker[i]] = 1;
@@ -259,6 +262,7 @@ HTS_INLINE const char *strjoker(const char *chaine, const char *joker,
for(i = 0; i < 256; i++)
pass[i] = 1; // tout autoriser
jmp = 1;
////if (joker[2]==LEFT) jmp=3; // permet de recher *<crochet ouvrant>
}
{

View File

@@ -54,9 +54,15 @@ Please visit our Website: http://www.httrack.com
#endif
// ftp mode passif
// #if HTS_INET6==0
#define FTP_PASV 1
// #else
// no passive mode for v6
// #define FTP_PASV 0
// #endif
#define FTP_DEBUG 0
//#define FORK_DEBUG 0
#if USE_BEGINTHREAD
@@ -200,8 +206,20 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
{
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;
#endif
if (a != NULL && *a != '\0') {
#if 0
a++; // sauter /
#endif
ftp_filename = a;
if (strnotempty(a)) {
char catbuff[CATBUFF_SIZE];
@@ -225,6 +243,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
}
} else {
strcpybuff(back->r.msg, "Unexpected PORT error");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
}
@@ -258,6 +277,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
if (hts_dns_resolve2(opt, _adr, &server, &error) == NULL) {
snprintf(back->r.msg, sizeof(back->r.msg),
"Unable to get server's address: %s", error);
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_NON_FATAL;
_HALT_FTP return 0;
}
@@ -270,17 +290,20 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
soc_ctl = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
if (soc_ctl == INVALID_SOCKET) {
strcpybuff(back->r.msg, "Unable to create a socket");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
_HALT_FTP return 0;
}
SOCaddr_initport(server, port);
// server.sin_port = htons((unsigned short int) port);
// connexion (bloquante, on est en thread)
strcpybuff(back->info, "connect");
if (connect(soc_ctl, &SOCaddr_sockaddr(server), SOCaddr_size(server)) != 0) {
strcpybuff(back->r.msg, "Unable to connect to the server");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
_HALT_FTP return 0;
#ifdef _WIN32
@@ -322,22 +345,64 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
// ok
} else {
strcpybuff(back->r.msg, "TYPE I error");
// back->status=STATUS_FTP_READY; // fini
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 {
snprintf(back->r.msg, sizeof(back->r.msg), "Bad password: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "Bad password: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "Bad user name: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "Bad user name: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "Connection refused: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "Connection refused: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
@@ -404,8 +469,8 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
}
// -- fin analyse de l'adresse IP et du port --
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
} // sinon on est prêts
} else {
@@ -436,13 +501,13 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
}
}
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "EPSV incorrect: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "EPSV incorrect: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "PASV/EPSV error: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "PASV/EPSV error: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
} // sinon on est prêts
}
@@ -548,8 +613,9 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
deletesoc(soc_dat);
soc_dat = INVALID_SOCKET;
//
snprintf(back->r.msg, sizeof(back->r.msg),
"RETR command error: %s", linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "RETR command error: %s",
linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
} // sinon on est prêts
} else {
@@ -560,20 +626,23 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
soc_dat = INVALID_SOCKET;
//
strcpybuff(back->r.msg, "Unable to connect");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
} // sinon on est prêts
} else {
strcpybuff(back->r.msg, "Unable to create a socket");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
} // sinon on est prêts
} else {
snprintf(back->r.msg, sizeof(back->r.msg),
"Unable to resolve IP %s: %s", adr_ip, error);
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
} // sinon on est prêts
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "PASV incorrect: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
} // sinon on est prêts
#else
@@ -594,16 +663,17 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
//T_SOC soc_dat;
if ((soc_dat = accept(soc_servdat, NULL, NULL)) == INVALID_SOCKET) {
strcpybuff(back->r.msg, "Unable to accept connection");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
} else {
snprintf(back->r.msg, sizeof(back->r.msg),
"RETR command error: %s", linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "RETR command error: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "PORT command error: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "PORT command error: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
#ifdef _WIN32
@@ -613,6 +683,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
#endif
} else {
strcpybuff(back->r.msg, "Unable to listen to a port");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
#endif
@@ -636,18 +707,21 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
int len = 1;
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))) {
// attendre les données
len = 1; // pas d'erreur pour le moment
switch (wait_socket_receive(soc_dat, timeout)) {
case -1:
strcpybuff(back->r.msg, "FTP read error");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
len = 0; // fin
break;
case 0:
snprintf(back->r.msg, sizeof(back->r.msg), "Time out (%d)",
timeout);
snprintf(back->r.msg, sizeof(back->r.msg), "Time out (%d)", timeout);
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
len = 0; // fin
break;
@@ -669,14 +743,17 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
}
*/
strcpybuff(back->r.msg, "Write error");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
len = 0; // error
}
} else {
strcpybuff(back->r.msg, "Unexpected write error");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
} else { // Erreur ou terminé
} else { // Erreur ou terminé
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = 0;
if (back->r.totalsize > 0
&& back->r.size != back->r.totalsize) {
@@ -685,6 +762,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
}
}
read_len = 1024;
//HTS_TOTAL_RECV_CHECK(read_len); // Diminuer au besoin si trop de données reçues
}
}
if (back->r.fp) {
@@ -693,6 +771,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
}
} else {
strcpybuff(back->r.msg, "Unable to write file");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
#ifdef _WIN32
@@ -708,14 +787,16 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
get_ftp_line(soc_ctl, line, sizeof(line), timeout);
if (line[0] == '2') { // OK
strcpybuff(back->r.msg, "OK");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = HTTP_OK;
} else {
snprintf(back->r.msg, sizeof(back->r.msg), "RETR incorrect: %s",
linejmp(line));
snprintf(back->r.msg, sizeof(back->r.msg), "RETR incorrect: %s", linejmp(line));
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
} else {
strcpybuff(back->r.msg, "FTP read error");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
}
}
@@ -741,6 +822,7 @@ int run_launch_ftp(FTPDownloadStruct * pStruct) {
back->r.statuscode = HTTP_OK;
strcpybuff(back->r.msg, "OK");
}
// back->status=STATUS_FTP_READY; // fini
return 0;
}
@@ -907,7 +989,9 @@ int get_ftp_line(T_SOC soc, char *ptrline, size_t line_size, int timeout) {
break;
}
//HTS_TOTAL_RECV_CHECK(dummy); // Diminuer au besoin si trop de données reçues
switch (recv(soc, &b, 1, 0)) {
//case 0: break; // pas encore --> erreur (on attend)!
case 1:
HTS_STAT.HTS_TOTAL_RECV += 1; // compter flux entrant
if ((b != 10) && (b != 13) && (i < (int) sizeof(data) - 1))
@@ -1034,6 +1118,7 @@ int wait_socket_receive(T_SOC soc, int timeout) {
int stop_ftp(lien_back * back) {
if (back->stop_ftp) {
strcpybuff(back->r.msg, "Cancelled by User");
// back->status=STATUS_FTP_READY; // fini
back->r.statuscode = STATUSCODE_INVALID;
return 1;
}

View File

@@ -152,6 +152,16 @@ void help_wizard(httrackp * opt) {
#define str (buffers->str)
#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;
@@ -217,6 +227,8 @@ void help_wizard(httrackp * opt) {
strcatbuff(stropt2, str);
strcatbuff(stropt2, projname);
strcatbuff(stropt2, "\" ");
// Créer si ce n'est fait un index.html 1er niveau
make_empty_index(str);
//
printf("\n");
printf("Enter URLs (separated by commas or blank spaces) :");
@@ -337,6 +349,8 @@ void help_wizard(httrackp * opt) {
}
hts_main(argc, argv);
}
//} else {
// help("httrack",1);
}
/* Free buffers */
@@ -441,6 +455,23 @@ void help_catchurl(const char *dest_path) {
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)
// y
void help(const char *app, int more) {
@@ -777,4 +808,7 @@ void help(const char *app, int more) {
infomsg("[compiled: " HTS_PLATFORM_NAME "]");
#endif
infomsg(NULL);
// infomsg(" R *relative links (e.g ../link)\n");
// infomsg(" A absolute links (e.g /www.adr/link)\n");
}

View File

@@ -45,6 +45,7 @@ typedef struct httrackp httrackp;
void infomsg(const char *msg);
void help(const char *app, int more);
void make_empty_index(const char *str);
void help_wizard(httrackp * opt);
int help_query(const char *list, int def);
void help_catchurl(const char *dest_path);

View File

@@ -142,6 +142,8 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
char keyword[KEYW_LEN + 32];
int i = 0;
//
//int WordIndexSize = 1024;
coucal WordIndexHash = NULL;
FILE *tmpfp = NULL;
@@ -176,6 +178,8 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
|| (strfield2(mime, "text/css"))
) {
inscript = 1;
//} else if (strfield2(mime, "text/vnd.wap.wml")) { // humm won't work in many cases
// inscript=0;
} else
return 0;
@@ -271,6 +275,8 @@ int index_keyword(const char *html_data, LLint size, const char *mime,
// Process indexing for this page
{
//FILE* fp=NULL;
//fp=fopen(concat(indexpath,"index.txt"),"ab");
if (fp_tmpproject) {
while(!feof(tmpfp)) {
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;
if (coucal_read(WordIndexHash, line, &e)) {
//if (e) {
char BIGSTK savelst[HTS_URLMAXSIZE * 2];
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,
(int) (KEYW_SORT_MAXCOUNT - e), savelst);
hts_primindex_size++;
//}
}
}
}
//fclose(fp);
}
}
@@ -321,6 +330,7 @@ void index_finish(const char *indexpath, int mode) {
off_t size = fpsize(fp_tmpproject);
if (size > 0) {
//FILE* fp=fopen(concat(indexpath,"index.txt"),"rb");
if (fp_tmpproject) {
tab = (char **) malloct(sizeof(char *) * (hts_primindex_size + 2));
if (tab) {
@@ -388,6 +398,8 @@ void index_finish(const char *indexpath, int mode) {
if (total_hit) {
if (mode == 1) // TEXT
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) >=
KEYW_USELESS1K)
|| (((total_line * 1000) / index) >=
@@ -404,6 +416,8 @@ void index_finish(const char *indexpath, int mode) {
if (mode == 1) // TEXT
fprintf(fp, "\t(%d)\r\n",
((total_hit * 1000) / hts_primindex_words));
//else // HTML
// fprintf(fp,"(%d)\r\n",((total_hit*1000)/hts_primindex_words));
}
}
if (mode == 1) // TEXT

View File

@@ -175,14 +175,15 @@ static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
#if JAVADEBUG
printf("fopen\n");
#endif
if ((fpout = FOPEN(fconv(catbuff, sizeof(catbuff), file), "r+b")) ==
NULL) {
if ((fpout = FOPEN(fconv(catbuff, sizeof(catbuff), file), "r+b")) == NULL) {
//fprintf(stderr, "Cannot open input file.\n");
sprintf(str->err_msg, "Unable to open file %s", file);
return 0; // une erreur..
}
#if JAVADEBUG
printf("fread\n");
#endif
//if (fread(&header,1,sizeof(JAVA_HEADER),fpout) != sizeof(JAVA_HEADER)) { // pas complet..
if (fread(&header, 1, 10, fpout) != 10) { // pas complet..
fclose(fpout);
sprintf(str->err_msg, "File header too small (file len = " LLintP ")",
@@ -256,10 +257,12 @@ static int hts_parse_java(t_hts_callbackarg * carg, httrackp * opt,
printf("addfiles\n");
#endif
{
//unsigned int acess;
unsigned int Class;
unsigned int SClass;
int i;
//acess = readshort(fpout);
Class = readshort(fpout);
SClass = readshort(fpout);
@@ -404,9 +407,11 @@ static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp,
p = &buffer[0];
//fflush(fp);
trans.file_position = ftell(fp);
length = readshort(fp);
if (length < HTS_URLMAXSIZE) {
// while ((length > 0) && (length<500)) {
while(length > 0) {
*p++ = fgetc(fp);
@@ -414,13 +419,17 @@ static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp,
}
*p = '\0';
//#if JDEBUG
// if(tris(buffer)==1) printf("%s\n ",buffer);
// if(tris(buffer)==2) printf("%s\n ",printname(buffer));
//#endif
if (tris(str->opt, buffer) == 1)
str->addLink(str, buffer); /* trans.file_position */
else if (tris(str->opt, buffer) == 2)
str->addLink(str, printname(rname, buffer));
strcpy(trans.name, buffer);
} else { // gros pb
} else { // gros pb
while((length > 0) && (!feof(fp))) {
fgetc(fp);
length--;
@@ -436,6 +445,7 @@ static RESP_STRUCT readtable(htsmoduleStruct * str, FILE * fp,
}
break;
default:
// printf("Type inconnue\n");
// on arrête tout
sprintf(str->err_msg, "Internal structure unknown (type %d)", trans.type);
*error = 1;
@@ -498,6 +508,7 @@ static char *printname(char rname[1024], char name[1024]) {
return rname; // ""
}
p += 2;
//rname=(char*)calloct(strlen(name)+8,sizeof(char));
p1 = rname;
for(j = 0; name[j] != '\0'; j++, p++) {
if (*p == '/')

View File

@@ -598,27 +598,56 @@ static const char *hts_mime_modern[][2] = {
// Reserved (RFC2396)
#define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
#define CHAR_RESERVED(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) ( 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)
#define CHAR_DELIM(c) \
(CIS(c, '<') || CIS(c, '>') || CIS(c, '#') || CIS(c, '%') || CIS(c, '\"'))
#define CHAR_DELIM(c) ( CIS(c,'<') \
|| CIS(c,'>') \
|| CIS(c,'#') \
|| CIS(c,'%') \
|| CIS(c,'\"') )
//#define CHAR_DELIM(c) ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
// Unwise (RFC2396)
#define CHAR_UNWISE(c) \
(CIS(c, '{') || CIS(c, '}') || CIS(c, '|') || CIS(c, '\\') || CIS(c, '^') || \
CIS(c, '[') || CIS(c, ']') || CIS(c, '`'))
#define CHAR_UNWISE(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 )
#define CHAR_LOW(c) ( ((unsigned char)(c) <= 31) )
#define CHAR_HIG(c) ( ((unsigned char)(c) >= 127) )
#define CHAR_SPECIAL(c) ( CHAR_LOW(c) || CHAR_HIG(c) )
// We try to avoid them and encode them instead
#define CHAR_XXAVOID(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, ')'))
#define CHAR_XXAVOID(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
#ifdef _WIN32
@@ -812,12 +841,15 @@ int http_proxy_tunnel(httrackp *opt, htsblk *retour, const char *adr,
// treat: traiter header?
// waitconnect: attendre le connect()
// note: dans retour, on met les params du proxy
T_SOC http_xfopen(httrackp *opt, int mode, int treat, int waitconnect,
const char *xsend, const char *adr, const char *fil,
htsblk *retour) {
T_SOC http_xfopen(httrackp * opt, int mode, int treat, int waitconnect,
const char *xsend, const char *adr, const char *fil, htsblk * retour) {
//htsblk retour;
//int bufl=TAILLE_BUFFER; // 8Ko de buffer
T_SOC soc = INVALID_SOCKET;
char BIGSTK tempo_fil[HTS_URLMAXSIZE * 2];
//char *p,*q;
// retour prédéfini: erreur
if (retour) {
retour->adr = NULL;
@@ -902,6 +934,7 @@ T_SOC http_xfopen(httrackp *opt, int mode, int treat, int waitconnect,
strcpybuff(retour->msg, "Unable to open local file");
else {
// 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),
unescape_http(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), fil)), "rb"); // ouvrir
if (retour->fp == NULL)
@@ -978,10 +1011,17 @@ T_SOC http_xfopen(httrackp *opt, int mode, int treat, int waitconnect,
} 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)
retour->totalsize = -1;
}
}
}
@@ -1078,12 +1118,19 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
char BIGSTK buffer_head_request[16384];
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://)
const char *search_tag = NULL;
// Initialize buffer
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:
// si présence d'un tag >post: alors executer un POST
// exemple: http://www.example.com/test.cgi?foo>post:posteddata=10&foo=5
@@ -1177,9 +1224,11 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
}
// 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");
} else { // Requète 1.1
} else { // Requète 1.1
//use_11=1;
print_buffer(&bstr, " HTTP/1.1\x0d\x0a");
}
@@ -1315,7 +1364,9 @@ int http_sendhead(httrackp * opt, t_cookie * cookie, int mode,
print_buffer(&bstr, "Authorization: Basic %s"H_CRLF, autorisation);
}
}
}
//strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
// Custom header(s)
if (strnotempty(retour->req.headers)) {
@@ -1469,11 +1520,14 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
a += strlen("filename=");
while(is_space(*a))
a++;
//a=strchr(a,'"');
if (a) {
char *c = NULL;
//a++; /* jump " */
while((c = strchr(a, '/'))) /* skip all / (see RFC2616) */
a = c + 1;
//b=strchr(a+1,'"');
b = a + strlen(a) - 1;
while(is_space(*b))
b--;
@@ -1490,14 +1544,16 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
} else if ((p = strfield(rcvd, "Last-Modified:")) != 0) {
while(is_realspace(*(rcvd + p)))
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);
}
} else if ((p = strfield(rcvd, "Date:")) != 0) {
if (strnotempty(retour->lastmodified) == 0) { /* pas encore de last-modified */
while(is_realspace(*(rcvd + p)))
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);
}
}
@@ -1510,11 +1566,14 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
else // erreur.. ignorer
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)))
p++; // sauter espaces
if (strfield(rcvd + p, "chunked")) {
retour->is_chunk = 1; // chunked
retour->is_chunk = 1; // chunked
//retour->http11=2; // chunked
#if HDEBUG
printf("ok, Transfer-Encoding: détecté\n");
#endif
@@ -1691,8 +1750,7 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
retour->location[0] = '\0';
}
}
} else if (((p = strfield(rcvd, "Set-Cookie:")) != 0) &&
(cookie)) { // ohh un cookie
} else if (((p = strfield(rcvd, "Set-Cookie:")) != 0) && (cookie)) { // ohh un cookie
char *a = rcvd + p; // pointeur
char domain[256]; // domaine cookie (.netscape.com)
char path[256]; // chemin (/)
@@ -1736,8 +1794,10 @@ void treathead(t_cookie * cookie, const char *adr, const char *fil, htsblk * ret
a++; // sauter espaces
value_st = a;
while((*a != ';') && (*a))
a++; // prochain ;
a++; // prochain ;
//while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++; // prochain " (et pas \")
value_end = a;
//if (*a==';') { // finit par un ;
// vérifier débordements
if ((((int) (token_end - token_st)) < 200)
&& (((int) (value_end - value_st)) < 8000)
@@ -2079,6 +2139,8 @@ LLint http_xfread1(htsblk * r, int bufl) {
nl = READ_ERROR;
}
}
//if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
// nl=-1; // break
// libérer bloc tempo
freet(buff);
@@ -2166,6 +2228,9 @@ htsblk http_test(httrackp * opt, const char *adr, const char *fil, char *loc) {
T_SOC soc;
htsblk retour;
//int rcvsize=-1;
//char* rcv=NULL; // adresse de retour
//int bufl=TAILLE_BUFFER; // 8Ko de buffer
TStamp tl;
int timeout = 30; // timeout pour un check (arbitraire) // **
@@ -2174,8 +2239,11 @@ htsblk http_test(httrackp * opt, const char *adr, const char *fil, char *loc) {
loc[0] = '\0';
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
//soc=http_fopen(adr,fil,&retour,NULL); // ouvrir, + header
// 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
@@ -2551,6 +2619,7 @@ int ident_url_absolute(const char *url, lien_adrfil *adrfil) {
// chemin www... trop long!!
if ((((int) (q - p))) > HTS_URLMAXSIZE) {
//strcpybuff(retour.msg,"Path too long");
return -1; // erreur
}
// recopier adrfil->adresse www..
@@ -2736,6 +2805,7 @@ void deletesoc_r(htsblk * r) {
#if HTS_USEOPENSSL
if (r->ssl_con) {
SSL_shutdown(r->ssl_con);
// SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
SSL_free(r->ssl_con);
r->ssl_con = NULL;
}
@@ -3124,6 +3194,7 @@ int finput(T_SOC fd, char *s, int max) {
int j = 0;
do {
//c=fgetc(fp);
if (read((int) fd, &c, 1) <= 0) {
c = 0;
}
@@ -3139,7 +3210,7 @@ int finput(T_SOC fd, char *s, int max) {
break;
}
}
} while ((c != 0) && (j < max - 1));
} while((c != 0) && (j < max - 1));
s[j] = '\0';
return j;
}
@@ -4798,6 +4869,7 @@ LLint check_downloadable_bytes(int rate) {
time_now = mtime_local();
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 =
(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[id_timer]);
@@ -4810,6 +4882,32 @@ LLint check_downloadable_bytes(int rate) {
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)
// returns:
// >0 : data received
@@ -4818,6 +4916,7 @@ LLint check_downloadable_bytes(int rate) {
int hts_read(htsblk * r, char *buff, int size) {
int retour;
// return read(soc,buff,size);
if (r->is_file) {
#if HTS_WIDE_DEBUG
DEBUG_W("read(%p, %d, %d)\n" _(void *)buff _(int) size _(int) r->fp);
@@ -4835,6 +4934,7 @@ int hts_read(htsblk * r, char *buff, int size) {
if (r->soc == INVALID_SOCKET)
printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
#endif
//HTS_TOTAL_RECV_CHECK(size); // Diminuer au besoin si trop de données reçues
#if HTS_USEOPENSSL
if (r->ssl) {
retour = SSL_read(r->ssl_con, buff, size);
@@ -5269,13 +5369,18 @@ SOCaddr* hts_dns_resolve(httrackp * opt, const char *_iadr, SOCaddr *const addr)
// --- Tracage des mallocs() ---
#ifdef HTS_TRACE_MALLOC
//#define htsLocker(A, N) htsLocker(A, N)
#define htsLocker(A, N) do {} while(0)
static mlink trmalloc = { NULL, 0, 0, NULL };
static int trmalloc_id = 0;
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 *adr;
@@ -5359,6 +5464,7 @@ void hts_free(void *adr) {
htsboundary);
lnk->next = lnk->next->next;
free((void *) blk_free);
//blk_free->id=-1;
free((char *) adr - bsize);
htsLocker(mallocMutex, 0);
return;
@@ -5427,6 +5533,7 @@ mlink *hts_find(char *adr) {
if (depl < 0)
depl = -depl;
//assertf(depl < 512000); /* near the stack frame.. doesn't look like malloc but stack variable */
return NULL;
}
}
@@ -5482,7 +5589,8 @@ int ftp_available(void) {
}
#else
int ftp_available(void) {
return 1; // ok!
return 1; // ok!
//return 0; // SOUS UNIX, PROBLEMESs
}
#endif
@@ -5696,6 +5804,7 @@ HTSEXT_API int hts_init(void) {
assertf("OpenSSL version seems vulnerable to heartbleed bug (CVE-2014-0160)" == NULL);
}
// OpenSSL_add_all_algorithms();
openssl_ctx = SSL_CTX_new(method);
if (!openssl_ctx) {
fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new()\n");
@@ -6017,6 +6126,7 @@ HTSEXT_API httrackp *hts_create_opt(void) {
opt->log = stdout;
opt->errlog = stderr;
opt->flush = HTS_TRUE;
// opt->aff_progress=0;
opt->keyboard = HTS_FALSE;
//
StringCopy(opt->path_html, "");
@@ -6026,8 +6136,8 @@ HTSEXT_API httrackp *hts_create_opt(void) {
//
opt->maxlink = 100000; // 100,000 liens max par défaut
opt->maxfilter = 200; // 200 filtres max par défaut
opt->maxcache = 1048576 * 32; // a peu près 32Mo en cache max -- OPTION NON
// PARAMETRABLE POUR L'INSTANT --
opt->maxcache = 1048576 * 32; // a peu près 32Mo en cache max -- OPTION NON PARAMETRABLE POUR L'INSTANT --
//opt->maxcache_anticipate=256; // maximum de liens à anticiper
opt->maxtime = -1; // temps max en secondes
opt->maxrate = 100000; // taux maxi
opt->maxconn = 5.0; // nombre connexions/s
@@ -6180,9 +6290,11 @@ const hts_stat_struct* hts_get_stats(httrackp * opt) {
}
// defaut wrappers
static void __cdecl htsdefault_init(t_hts_callbackarg *carg) {}
static void __cdecl htsdefault_uninit(t_hts_callbackarg *carg) {}
static void __cdecl htsdefault_init(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) {
return 1;
}

View File

@@ -171,6 +171,7 @@ HTSEXT_API const char* hts_version(void);
// fonctions unix/winsock
int hts_read(htsblk * r, char *buff, int size);
//int HTS_TOTAL_RECV_CHECK(int var);
LLint check_downloadable_bytes(int rate);
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,
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,
int waitconnect);
/* Like newhttp(), but connect to the addr_index-th resolved address of the host

View File

@@ -55,6 +55,12 @@ extern int fspc(httrackp * opt, FILE * fp, const char *type);
/* >>> 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;
static char WHAT_is_available[64] = "";
@@ -106,6 +112,18 @@ int hts_parse_externals(htsmoduleStruct * str) {
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_) {
htscallbacks *chain;

View File

@@ -1332,7 +1332,8 @@ int url_savename(lien_adrfilsave *const afs,
while((a > afs->save) && (*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!
hts_log_print(opt, LOG_DEBUG, "Default HTML type set for %s%s => %s",
adr_complete, fil_complete, afs->save);
@@ -1470,6 +1471,17 @@ int url_savename(lien_adrfilsave *const afs,
fil_simplifie(afs->save);
/* 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 */
RUN_CALLBACK5(opt, savename, adr_complete, fil_complete, referer_adr,
@@ -1617,6 +1629,10 @@ int url_savename(lien_adrfilsave *const afs,
int sameAdr = (strfield2(heap(i)->adr, normadr) != 0);
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);
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 */
@@ -1682,13 +1698,17 @@ int url_savename(lien_adrfilsave *const afs,
strcpybuff(afs->save, tempo);
//printf("switched: %s\n",save);
} // if
}
#if DEBUG_SAVENAME
printf("\nEnd search, %s\n", fil_complete);
#endif
} while (!nom_ok);
} while(!nom_ok);
}
//printf("'%s' %s %s\n",save,adr,fil);
return 0;
}

View File

@@ -105,6 +105,7 @@ typedef struct htsfilters htsfilters;
struct htsfilters {
char ***filters; /**< pointer to the +/-pattern filter array */
int *filptr; /**< pointer to the current filter count */
// int* filter_max;
};
/* User callbacks chain */
@@ -439,6 +440,7 @@ struct httrackp {
float maxconn; /**< max connections per second */
int waittime; /**< scheduled start time (wall-clock seconds) */
hts_cachemode cache; /**< cache generation mode */
// int aff_progress; // progress bar
hts_boolean shell; /**< driven by a shell over stdin/stdout pipes */
t_proxy proxy; /**< proxy configuration */
hts_savename_83
@@ -490,6 +492,7 @@ struct httrackp {
hts_verbosedisplay verbosedisplay; /**< animated text progress display */
String footer; /**< footer/info line injected into pages */
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 */
String filelist; /**< file listing URLs to include */
String urllist; /**< file listing filters to include */
@@ -546,6 +549,8 @@ typedef struct hts_stat_struct hts_stat_struct;
struct hts_stat_struct {
LLint HTS_TOTAL_RECV; /**< total bytes received from the network */
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 */
//
LLint total_packed; /**< compressed bytes received (on the wire) */
@@ -677,6 +682,7 @@ struct lien_url {
int depth; /**< remaining allowed depth; >0 strong, 0 weak */
int pass2; /**< second-pass marker; -1 means handled in background */
char link_import; /**< imported after a move; skip the usual up/down rules */
// int moved; // pointer to moved
int retry; /**< remaining retries */
int testmode; /**< test only: send just a HEAD */
};
@@ -721,6 +727,9 @@ struct lien_back {
LLint chunk_size; /**< size of the chunk being loaded */
LLint chunk_blocksize; /**< data size declared by the chunk */
LLint compressed_size; /**< compressed size (stats only) */
//
// int links_index; // to access liens[links_index]
//
char info[256]; /**< status text, e.g. for FTP */
int stop_ftp; /**< stop flag for FTP */
int finalized; /**< finalized (memory optimization) */

View File

@@ -192,48 +192,6 @@ static void hts_automate_lookup(const script_automate *aut) {
}
}
/* Attribute name owning the quoted value at 'quote' inside a tag, spanning
[name, *nend); NULL when the quote is not an attribute value. */
static const char *dirty_attr_name(const char *quote, const char *tag_start,
const char **nend) {
const char *a = quote - 1;
while (a > tag_start && is_taborspace(*a))
a--;
if (a == tag_start || *a != '=')
return NULL;
a--;
while (a > tag_start && is_taborspace(*a))
a--;
*nend = a + 1;
while (a > tag_start && *a != '=' && *a != '\"' && *a != '\'' &&
!is_realspace(*a))
a--;
a++;
// a name starting right after '<' is the tag name, not an attribute
return a < *nend && a > tag_start + 1 ? a : NULL;
}
/* Accept the in-tag quoted value at 'quote' for dirty parsing? Resolves the
owning attribute itself (intag_startattr is unreliable mid-tag) and rejects
no-detect/xmlns names. */
static hts_boolean dirty_attr_detectable(const char *quote,
const char *tag_start) {
const char *nend;
const char *name = dirty_attr_name(quote, tag_start, &nend);
int i;
if (name == NULL)
return HTS_FALSE;
for (i = 0; strnotempty(hts_nodetect[i]); i++) {
const int l = strfield(name, hts_nodetect[i]);
if (l && name + l == nend)
return HTS_FALSE;
}
i = strfield(name, "xmlns");
if (i && (name + i == nend || name[i] == ':'))
return HTS_FALSE;
return HTS_TRUE;
}
/* Advance the cursor by 'steps' bytes, feeding each to the automaton. */
static void hts_automate_increment(const script_automate *aut, int steps) {
while (steps > 0) {
@@ -395,13 +353,16 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
// terminaison (" ou ') du "<body onLoad=.."
int inscriptgen = 0; // on est dans un code générant, ex après obj.write("..
//int inscript_check_comments=0, inscript_in_comments=0; // javascript comments
char scriptgen_q = '\0'; // caractère faisant office de guillemet (' ou ")
//int no_esc_utf=0; // ne pas echapper chars > 127
int nofollow = 0; // ne pas scanner
//
int parseall_lastc = '\0'; // dernier caractère parsé pour parseall
//int parseall_incomment=0; // dans un /* */ (exemple: a = /* URL */ "img.gif";)
//
const char *intag_start = html;
const char *intag_name = NULL;
@@ -514,6 +475,12 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
lastsaved = html;
}
}
// Detect UTF8 format
//if (is_unicode_utf8(r->adr, (unsigned int) r->size) == 1) {
// no_esc_utf=1;
//} else {
// no_esc_utf=0;
//}
// Hack to prevent any problems with ram files of other files
*(r->adr + r->size) = '\0';
@@ -678,6 +645,8 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
) {
intag = 1;
intag_ctype = 0;
//parseall_incomment=0;
//inquote=0; // effacer quote
intag_start = html;
for(intag_name = html + 1; is_realspace(*intag_name); intag_name++) ;
intag_start_valid = 1;
@@ -695,6 +664,8 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
if (len > 0) {
if (strfield(token, "content-type")) {
intag_ctype = 1;
//NOPE-we do not convert the whole page actually
//intag_start[1] = 'X';
} else if (strfield(token, "refresh")) {
intag_ctype = 2;
}
@@ -755,6 +726,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
html_inline_safe(urlfil(), safe_fil, sizeof(safe_fil)), gmttime,
HTTRACK_VERSIONID, /* EOF */ NULL);
strcatbuff(tempo, eol);
//fwrite(tempo,1,strlen(tempo),fp);
HT_ADD(tempo);
}
// Emit charset ?
@@ -782,8 +754,6 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
) {
if (inscript_tag) {
inscript_tag = inscript = 0;
// reset the automaton on exit or its state leaks into plain HTML
inscript_state_pos = INSCRIPT_START;
intag = 0;
incomment = 0;
intag_start_valid = 0;
@@ -795,8 +765,8 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
intag = 0; //inquote=0;
// entrée dans du javascript?
// on parse ICI car il se peut qu'on ait eu a parser les src=..
// dedans
// on parse ICI car il se peut qu'on ait eu a parser les src=.. dedans
//if (!inscript) { // sinon on est dans un obj.write("..
if ((intag_start_valid) && (check_tag(intag_start, "script")
|| check_tag(intag_start, "style")
)
@@ -842,9 +812,12 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
#endif
}
} else if (intag || inscript ||
in_media) { // nous sommes dans un tag/commentaire, tester si
// on recoit un tag
//}
}
//else if (*adr==34) {
// inquote=(inquote?0:1);
//}
else if (intag || inscript || in_media) { // nous sommes dans un tag/commentaire, tester si on recoit un tag
int p_type = 0;
int p_nocatch = 0;
int p_searchMETAURL = 0; // chercher ..URL=<url>
@@ -864,7 +837,6 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
if (*html == inscript_tag_lastc) {
/* sortir */
inscript_tag = inscript = 0;
inscript_state_pos = INSCRIPT_START;
incomment = 0;
if (opt->parsedebug) {
HT_ADD("<@@ /inscript @@>");
@@ -1083,6 +1055,27 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
if (p) {
if (intag_ctype == 1) {
p = 0;
#if 0
//if ((pos=rech_tageq(html, "content"))) {
char temp[256];
char *token = NULL;
int len = rech_endtoken(html + pos, &token);
if (len > 0 && len < sizeof(temp) - 2) {
char *chpos;
temp[0] = '\0';
strncat(temp, token, len);
if ((chpos = strstr(temp, "charset"))
&& (chpos = strchr(chpos, '='))
) {
chpos++;
while(is_space(*chpos))
chpod++;
//chpos
}
}
#endif
}
// <META HTTP-EQUIV="Refresh" CONTENT="3;URL=http://www.example.com">
else if (intag_ctype == 2) {
@@ -1267,6 +1260,21 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
} else if (inscript) {
#if 0
/* Check // javascript comments */
if (*html == 10 || *html == 13) {
inscript_check_comments = 1;
inscript_in_comments = 0;
} else if (inscript_check_comments) {
if (!is_realspace(*html)) {
inscript_check_comments = 0;
if (html[0] == '/' && html[1] == '/') {
inscript_in_comments = 1;
}
}
}
#endif
/* Parse */
assertf(inscript_name != NULL);
if (*html == '/'
@@ -1279,17 +1287,18 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
&& inscript_locked == 0) {
const char *a = html;
//while(is_realspace(*(--a)));
while(is_realspace(*a))
a--;
a--;
if (*a == '<') { // sûr que c'est un tag?
inscript = 0;
inscript_state_pos = INSCRIPT_START;
if (opt->parsedebug) {
HT_ADD("<@@ /inscript @@>");
}
}
} else if (inscript_state_pos == INSCRIPT_START) {
} else if (inscript_state_pos ==
INSCRIPT_START /*!inscript_in_comments */ ) {
/*
Script Analyzing - different types supported:
foo="url"
@@ -1478,10 +1487,12 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
} else { // ptr == 0
//p=rech_tageq(adr,"primary"); // lien primaire, yeah
p = 0; // No stupid tag anymore, raw link
valid_p = 1; // Valid even if p==0
while((html[p] == '\r') || (html[p] == '\n'))
p++;
//can_avoid_quotes=1;
ending_p = '\r';
}
@@ -1494,11 +1505,25 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
// risque: générer de faux fichiers parazites
// fix: ne parse plus dans les commentaires
// ------------------------------------------------------------
if (opt->parseall && (opt->parsejava & HTSPARSE_NO_AGGRESSIVE) == 0 &&
(ptr > 0) && (!in_media)) { // option parsing "brut"
if (opt->parseall && (opt->parsejava & HTSPARSE_NO_AGGRESSIVE) == 0 && (ptr > 0) && (!in_media) /* && (!inscript_in_comments) */ ) { // option parsing "brut"
//int incomment_justquit=0;
if (!is_realspace(*html)) {
int noparse = 0;
// Gestion des /* */
#if 0
if (inscript) {
if (parseall_incomment) {
if ((*html == '/') && (*(html - 1) == '*'))
parseall_incomment = 0;
incomment_justquit = 1; // ne pas noter dernier caractère
} else {
if ((*html == '/') && (*(html + 1) == '*'))
parseall_incomment = 1;
}
} else
parseall_incomment = 0;
#endif
/* ensure automate state 0 (not in comments, quotes..) */
if (inscript
&& (inscript_state_pos != INSCRIPT_INQUOTE
@@ -1512,6 +1537,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
// recherche d'URLs
if (!noparse) {
//if ((!parseall_incomment) && (!noparse)) {
if (!p) { // non déja trouvé
if (html != r->adr) { // >1 caractère
// scanner les chaines
@@ -1535,16 +1561,15 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
&& (count > 0)) {
char c;
//char* aend;
//
//aend=a; // sauver début
a++;
while(is_taborspace(*a))
a++;
c = *a;
// in-tag, an attribute value ends at its quote: no
// delimiter required after it (mid-tag attrs, #201)
if (strchr("),;>/+\r\n", c) ||
(intag && !inscript && intag_start_valid &&
dirty_attr_detectable(html, intag_start))) {
// '/' covers a value followed by a JS comment
if (strchr("),;>/+\r\n", c)) { // exemple: ..img.gif";
// le / est pour funct("img.gif" /* URL */);
char BIGSTK tempo[HTS_URLMAXSIZE * 2];
char type[256];
int url_ok = 0; // url valide?
@@ -1589,8 +1614,10 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
if (!invalid_url) {
// Un plus à la fin? Alors ne pas prendre sauf si extension ("/toto.html#"+tag)
if (c != '+') { // PAS de plus à la fin
// "Comparisons of scheme names MUST be
// case-insensitive" (RFC2616)
#if 0
char *a;
#endif
// "Comparisons of scheme names MUST be case-insensitive" (RFC2616)
if ((strfield(tempo, "http:"))
|| (strfield(tempo, "ftp:"))
#if HTS_USEOPENSSL
@@ -1603,6 +1630,15 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
if (inscript) // sinon si pas javascript, méfiance (répertoire style base?)
url_ok = 1;
}
#if 0
else if ((a = strchr(tempo, '/'))) { // un slash: ok..
if (inscript) { // sinon si pas javascript, méfiance (style "text/css")
if (strchr(a + 1, '/')) // un seul / : abandon (STYLE type='text/css')
if (!strchr(tempo, ' ')) // avoid spaces (too dangerous for comments)
url_ok = 1;
}
}
#endif
}
// Prendre si extension reconnue
if (!url_ok) {
@@ -1681,9 +1717,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
}
}
} // p == 0
} // p == 0
} // not in comment
} // not in comment
// plus dans un commentaire
if (inscript_state_pos == INSCRIPT_START
@@ -1692,15 +1728,17 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
} // if realspace
} // if parseall
} // if parseall
// ------------------------------------------------------------
// p!=0 : on a repéré un éventuel lien
// ------------------------------------------------------------
//
if ((p > 0) || (valid_p)) { // on a repéré un lien
if ((p > 0) || (valid_p)) { // on a repéré un lien
//int lien_valide=0;
const char *eadr = NULL; /* fin de l'URL */
//char* quote_adr=NULL; /* adresse du ? dans l'adresse */
int ok = 1;
char quote = '\0';
int quoteinscript = 0;
@@ -1723,6 +1761,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
lastsaved = html; // dernier écrit+1
}
// sauter espaces
// adr+=p;
hts_automate_increment(&saut, p);
while((is_space(*html)
|| (inscriptgen && html[0] == '\\' && is_space(html[1])
@@ -1751,7 +1790,8 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
// sauter éventuel \" ou \' javascript
if (inscript) { // on est dans un obj.write("..
if (*html == '\\') {
if ((*(html + 1) == '\'') || (*(html + 1) == '"')) { // \" ou \'
if ((*(html + 1) == '\'') || (*(html + 1) == '"')) { // \" ou \'
// html+=2; // sauter
hts_automate_increment(&saut, 2);
}
}
@@ -1826,6 +1866,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
ok = -1; // ne pas traiter ce lien
if (ok > 0) {
//if (*eadr!=' ') {
if (is_space(*eadr)) { // guillemets,CR, etc
if ((*eadr == quote && (!quoteinscript || *(eadr - 1) == '\\')) // end quote
|| (noquote && (*eadr == '\"' || *eadr == '\'')) // end at any quote
@@ -1871,6 +1912,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
break;
}
}
//}
}
eadr++;
} while(ok == 1);
@@ -1899,10 +1941,14 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
char BIGSTK lien[HTS_URLMAXSIZE * 2];
int meme_adresse = 0; // 0 par défaut pour primary
//char *copie_de_adr=html;
//char* p;
// construire lien (découpage)
if (eadr - html - 1 < HTS_URLMAXSIZE) { // pas trop long?
strncpy(lien, html, eadr - html - 1);
lien[eadr - html - 1] = '\0';
//printf("link: %s\n",lien);
// supprimer les espaces
while((lien[strlen(lien) - 1] == ' ') && (strnotempty(lien)))
lien[strlen(lien) - 1] = '\0';
@@ -2146,6 +2192,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
a += 2;
else
a = lien;
// while((*a) && (*a!='/') && (*a!=':')) a++;
a = jump_toport(a);
if (a) { // port
int port = 0;
@@ -2153,6 +2200,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
char *b = a + 1;
#if HTS_USEOPENSSL
// FIXME
//if (strfield(adr, "https:")) {
//}
#endif
while(isdigit((unsigned char) *b)) {
port *= 10;
@@ -2243,6 +2293,13 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
*(a + 1) = '\0';
}
}
//char BIGSTK tempo[HTS_URLMAXSIZE*2];
//strcpybuff(tempo,"http://");
//strcatbuff(tempo,urladr()); // host
//if (*lien!='/')
// strcatbuff(tempo,"/");
//strcatbuff(tempo,lien);
//strcpybuff(lien,tempo);
}
}
@@ -2271,17 +2328,22 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
// stocker base ou codebase?
switch (p_type) {
case 2: {
strlcpybuff(base, lien, HTS_URLMAXSIZE * 2);
} break; // base
case -2: {
strlcpybuff(codebase, lien, HTS_URLMAXSIZE * 2);
} break; // base
case 2:{
//if (*lien!='/') strcatbuff(base,"/");
strlcpybuff(base, lien, HTS_URLMAXSIZE * 2);
}
break; // base
case -2:{
//if (*lien!='/') strcatbuff(codebase,"/");
strlcpybuff(codebase, lien, HTS_URLMAXSIZE * 2);
}
break; // base
}
hts_log_print(opt, LOG_DEBUG,
"code/codebase link %s base %s", lien,
base);
//printf("base code: %s - %s\n",lien,base);
}
} else {
@@ -2394,6 +2456,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
// Tester si un lien doit être accepté ou refusé (wizard)
// forbidden_url=1 : lien refusé
// forbidden_url=0 : lien accepté
//if ((ptr>0) && (p_type!=2) && (p_type!=-2)) { // tester autorisations?
if ((p_type != 2) && (p_type != -2)) { // tester autorisations?
if (!p_nocatch) {
if (afs.af.adr[0] != '\0') {
@@ -2443,7 +2506,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
/* Calc */
last_adr[0] = '\0';
strcpybuff(last_adr, afs.af.adr); // ancienne adresse
//char last_fil[HTS_URLMAXSIZE*2]="";
strcpybuff(last_adr, afs.af.adr); // ancienne adresse
//strcpybuff(last_fil,fil); // ancien chemin
r_sv =
url_savename(&afs, &former, heap(ptr)->adr, heap(ptr)->fil, opt,
sback, cache, hash, ptr,
@@ -2474,6 +2539,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
}
}
//import_done=1; // c'est un import!
meme_adresse = 0; // on a changé
}
} else {
@@ -2671,8 +2737,11 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
if (lienrelatif(tempo, sizeof(tempo), save,
relativesavename()) == 0) {
/* Never escape high-chars (we don't know the encoding!!) */
inplace_escape_uri_utf(
tempo, sizeof(tempo)); // escape with %xx
inplace_escape_uri_utf(tempo, sizeof(tempo)); // escape with %xx
//if (!no_esc_utf)
// escape_uri(tempo); // escape with %xx
//else
// escape_uri_utf(tempo); // escape with %xx
HT_ADD_HTMLESCAPED(tempo); // page externe
if (add_url) {
HT_ADD("?link="); // page externe
@@ -2909,6 +2978,16 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
// unquoted url() (CSS/JS): keep parens escaped
if (ending_p == ')')
escape_url_parens(tempo, sizeof(tempo));
//if (!no_esc_utf)
// escape_uri(tempo); // escape with %xx
//else {
// /* No escaping at all - remaining upper chars will be escaped below */
// /* FIXME - Should be done in all local cases */
// //x_escape_html(tempo);
// //escape_uri_utf(tempo); // FIXME - escape with %xx
// //escape_uri(tempo); // escape with %xx
//}
}
hts_log_print(opt, LOG_DEBUG,
"relative link at %s build with %s and %s: %s",
@@ -2966,9 +3045,22 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
HT_ADD(tempo4); // refresh code="
}
}
//lastsaved=adr; // dernier écrit+1
}
if ((opt->getmode & HTS_GETMODE_HTML) && (ptr > 0)) {
// convert to local codepage - NOT, already converted into %NN, and passed to the remote server so we do not have anything to do
//if (str->page_charset_ != NULL && *str->page_charset_ != '\0') {
// char *const local_save = hts_convertStringFromUTF8(tempo, strlen(tempo), str->page_charset_);
// if (local_save != NULL) {
// strcpybuff(tempo, local_save);
// free(local_save);
// } else {
// if ((opt->debug>1) && (opt->log!=NULL)) {
// fprintf(opt->log, "Warning: could not build local charset representation of '%s' in '%s'"LF, tempo, str->page_charset_);
// }
// }
//}
// écrire le lien modifié, relatif
// Note: escape all chars, even >127 (no UTF)
@@ -2992,6 +3084,16 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
}
} // sinon le lien sera écrit normalement
#if 0
if (fexist(save)) { // le fichier existe..
adr[0] = '\0';
//if ((opt->debug>0) && (opt->log!=NULL)) {
hts_log_print(opt, LOG_WARNING,
"Link has already been written on disk, cancelled: %s",
save);
}
#endif
/* Security check */
if (strlen(afs.save) >= HTS_URLMAXSIZE) {
afs.af.adr[0] = '\0';
@@ -3033,7 +3135,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
/*
if (strnotempty(save)) {
if (ishtml(opt,save) == 1) {
// descore_prio = 2;
} else {
// descore_prio = 1;
}
}
*/
@@ -3069,6 +3173,8 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
// >>>> CREER LE LIEN <<<<
//
// enregistrer lien à charger
//heap_top()->adr[0]=heap_top()->fil[0]=heap_top()->sav[0]='\0';
// même adresse: l'objet père est l'objet père de l'actuel
// DEBUT ROBOTS.TXT AJOUT
if (!just_test_it) {
@@ -3147,6 +3253,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
heap_top()->premier = heap(ptr)->premier;
else // sinon l'objet père est le précédent lui même
heap_top()->premier = heap_top_index();
// heap_top()->premier=ptr;
heap_top()->precedent = ptr;
// noter la priorité
@@ -3158,6 +3265,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
heap_top()->pass2 = pass_fix;
heap_top()->retry = opt->retry;
//strcpybuff(heap_top()->adr,adr);
//strcpybuff(heap_top()->fil,fil);
//strcpybuff(heap_top()->sav,save);
if (!just_test_it) {
hts_log_print(opt, LOG_DEBUG,
"OK, NOTE: %s%s -> %s",
@@ -3192,6 +3302,7 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
if (eadr > html) {
hts_automate_increment(&saut, (int) (eadr - 1 - html));
}
// adr=eadr-1; // ** sauter
/* srcset candidate loop: skip the descriptor and comma, then
re-enter the capture for the next URL. Backward goto, not a loop:
@@ -3221,9 +3332,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
inscript_state_pos = INSCRIPT_START;
} */
} // if (p)
} // if (p)
} // si '<' ou '>'
} // si '<' ou '>'
// plus loin
html++; // automate will be checked next loop
@@ -3293,7 +3404,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
*stre->exit_xh_ = 1; // exit requested
XH_uninit;
return -1;
//adr = r->adr + r->size; // exit
} else if (opt->state._hts_cancel == 1) {
// adr = r->adr + r->size; // exit
nofollow = 1; // moins violent
opt->state._hts_cancel = 0;
}
@@ -3351,6 +3464,9 @@ int htsparse(htsmoduleStruct * str, htsmoduleStructExtended * stre) {
fp = NULL;
}
}
// sauver fichier
//structcheck(savename());
//filesave(opt,r->adr,r->size,savename());
} // analyse OK
@@ -3389,11 +3505,17 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
// DEBUT rattrapage des 301,302,307..
// ------------------------------------------------------------
if (!error) {
////////{
// on a chargé un fichier en plus
// if (!error) stat_loaded+=r.size;
// ------------------------------------------------------------
// Rattrapage des 301,302,307 (moved) et 412,416 - les 304 le sont dans le backing
// ------------------------------------------------------------
if (HTTP_IS_REDIRECT(r->statuscode)) {
//if (r->adr!=NULL) { // adr==null si fichier direct. [catch: davename normalement si cgi]
//int i=0;
// char* p;
hts_log_print(opt, LOG_WARNING, "%s for %s%s", r->msg, urladr(), urlfil());
@@ -3420,6 +3542,7 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
// A same-file alias redirect must be followed, not stubbed (#159).
const hts_boolean same_savefile = hts_redirect_same_savefile(
opt, urladr(), urlfil(), moved->adr, moved->fil);
//if (ident_url_absolute(mov_url,moved->adr,moved->fil)!=-1) { // ok URL reconnue
// c'est (en gros) la même URL..
// si c'est un problème de casse dans le host c'est que le serveur est buggé
// ("RFC says.." : host name IS case insensitive)
@@ -3459,6 +3582,7 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
} /* sinon traité normalement */
}
//if ((strfield2(moved->adr,urladr())!=0) && (strfield2(moved->fil,urlfil())!=0)) { // identique à casse près
if (get_it == 1) {
// court-circuiter le reste du traitement
// et reculer pour mieux sauter
@@ -3469,6 +3593,9 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
error = 1;
hts_invalidate_link(opt, ptr); // invalidate hashtable entry
// noter NOUVEAU lien
//xxc xxc
// set_prio_to=0+1; // protection if the moved URL is an html page!!
//xxc xxc
{
// calculer lien et éventuellement modifier addresse/fichier
if (url_savename(&savedmoved, NULL,
@@ -3506,6 +3633,8 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
}
}
//printf("-> %s %s %s\n",liens[lien_tot-1]->adr,liens[lien_tot-1]->fil,liens[lien_tot-1]->sav);
// note métaphysique: il se peut qu'il y ait un index.html et un INDEX.HTML
// sous DOS ca marche pas très bien... mais comme je suis génial url_savename()
// est à même de régler ce problème
@@ -3627,6 +3756,7 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
// cas où l'on peut reessayer
switch (r->statuscode) {
//case -1: can_retry=1; break;
case STATUSCODE_TIMEOUT:
if (opt->hostcontrol) { // timeout et retry épuisés
if ((opt->hostcontrol & HTS_HOSTCONTROL_BAN_TIMEOUT) &&
@@ -3758,7 +3888,7 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
// FIN rattrapage des 301,302,307..
// ------------------------------------------------------------
} // if !error
} // if !error
/* Apply changes */
ENGINE_SAVE_CONTEXT();
@@ -3825,6 +3955,9 @@ void hts_mirror_process_user_interaction(htsmoduleStruct * str,
}
}
}
// On désalloue le buffer d'enregistrement des chemins créée, au cas où pendant la pause
// l'utilisateur ferait un rm -r après avoir effectué un tar
// structcheck_init(1);
{
FILE *fp =
fopen(fconcat
@@ -4205,8 +4338,33 @@ int hts_mirror_wait_for_next_file(htsmoduleStruct * str,
"link #%d is ready, no more on the stack, skipping: %s%s..",
ptr, urladr(), urlfil());
return 2; // goto jump_if_done;
// prochain lien
// ptr++;
return 2; // goto jump_if_done;
}
#if 0
/* FIXME - finalized HAS NO MORE THIS MEANING */
/* link put in cache by the backing system for memory spare - reclaim */
else if (back[b].finalized) {
assertf(back[b].r.adr == NULL);
/* read file in cache */
back[b].r =
cache_read_ro(opt, cache, back[b].url_adr, back[b].url_fil,
back[b].url_sav, back[b].location_buffer);
/* ensure correct location buffer set */
back[b].r.location = back[b].location_buffer;
if (back[b].r.statuscode == STATUSCODE_INVALID) {
hts_log_print(opt, LOG_ERROR,
"Unexpected error: %s%s not found anymore in cache",
back[b].url_adr, back[b].url_fil);
} else {
hts_log_print(opt, LOG_DEBUG, "reclaim file %s%s (%d)", back[b].url_adr,
back[b].url_fil, back[b].r.statuscode);
}
}
#endif
if (!opt->verbosedisplay) {
if (!opt->quiet) {
@@ -4230,6 +4388,7 @@ int hts_mirror_wait_for_next_file(htsmoduleStruct * str,
}
fflush(stdout);
}
//}
// ------------------------------------------------------------
// Vérificateur d'intégrité
@@ -4397,6 +4556,9 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
if (back[b].r.statuscode == STATUSCODE_INVALID && back[b].r.adr == NULL) {
lien_back delayed_back;
//char BIGSTK delayed_ctype[128];
// delayed_ctype[0] = '\0';
// strncatbuff(delayed_ctype, back[b].r.contenttype, sizeof(delayed_ctype) - 1); // copier content-type
back_copy_static(&back[b], &delayed_back);
/* Delete entry */
@@ -4404,12 +4566,6 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
back_maydelete(opt, cache, sback, b); // cancel
b = -1;
/* the cancel may leave the now-unreferenced placeholder on disk
* (#483) */
if (fexist_utf8(delayed_back.url_sav)) {
back_delayed_discard(opt, &delayed_back);
}
/* Recompute filename with MIME type */
afs->save[0] = '\0';
url_savename(afs, former, heap(ptr)->adr,
@@ -4501,6 +4657,9 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
if (b >= 0) {
lien_back delayed_back;
//char BIGSTK delayed_ctype[128];
//delayed_ctype[0] = '\0';
//strncatbuff(delayed_ctype, back[b].r.contenttype, sizeof(delayed_ctype) - 1); // copier content-type
back_copy_static(&back[b], &delayed_back);
/* Error */
@@ -4623,9 +4782,6 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
/* Still have a back reference */
if (b >= 0) {
/* move a still-writing placeholder before the url_sav patch
blinds every cleanup to it (#483) */
back_delayed_rename(opt, &back[b], afs->save);
/* patch url_sav BEFORE finalize: it records/caches under this name
*/
strcpybuff(back[b].url_sav, afs->save);
@@ -4652,8 +4808,13 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
/* 'no error page' selected or file discarded by size rules! */
if (!opt->errpage || (in_error == STATUSCODE_TOO_BIG)) {
/* Note: the cache 'cached_tests' system will remember this error, and we'll only issue ONE request */
/* Do not post-exclude the link here (*forbidden_url): the cache system
would never process it again, and it would be refetched endlessly */
#if 0
/* No (3.43) - don't do that. We must not post-exclude an authorized link, because this will prevent the cache
system from processing it, leading to refetch it endlessly. Just accept it, and handle the error as
usual during parsing.
*/
*forbidden_url = 1; /* Forbidden! */
#endif
if (in_error == STATUSCODE_TOO_BIG) {
hts_log_print(opt, LOG_INFO,
"link not taken because of its size (%d bytes) at %s%s",

View File

@@ -66,6 +66,7 @@ struct htsmoduleStructExtended {
char ***filters_;
robots_wizard *robots_;
hash_struct *hash_;
//int *lien_max_;
/* Base & codebase */
char *base;

View File

@@ -1347,30 +1347,6 @@ static int st_cache_writefail(httrackp *opt, int argc, char **argv) {
return err;
}
static int st_cache_corrupt(httrackp *opt, int argc, char **argv) {
int err;
if (argc < 1) {
fprintf(stderr, "cache-corrupt: needs a directory\n");
return 1;
}
err = cache_corruption_selftest(opt, argv[0]);
printf("cache-corrupt: %s\n", err ? "FAIL" : "OK");
return err;
}
static int st_reconcile(httrackp *opt, int argc, char **argv) {
int err;
if (argc < 1) {
fprintf(stderr, "reconcile: needs a directory\n");
return 1;
}
err = cache_reconcile_selftest(opt, argv[0]);
printf("cache-reconcile: %s\n", err ? "FAIL" : "OK");
return err;
}
static int st_dns(httrackp *opt, int argc, char **argv) {
const int err = dns_selftests(opt);
@@ -2143,10 +2119,6 @@ static const struct selftest_entry {
st_cache_golden},
{"cache-writefail", "<dir>", "cache write-failure handling self-test",
st_cache_writefail},
{"reconcile", "<dir>", "cache generation reconcile policy self-test",
st_reconcile},
{"cache-corrupt", "<dir>", "cache read-side corruption self-test",
st_cache_corrupt},
{"dns", "", "DNS resolver/cache self-test", st_dns},
{"cookies", "", "cookie request-header self-test", st_cookies},
{"useragent", "", "default User-Agent self-test", st_useragent},

View File

@@ -265,6 +265,7 @@ T_SOC smallserver_init(int *port, char *adr) {
SOCaddr_initport(server, *port);
if (bind(soc, &SOCaddr_sockaddr(server), SOCaddr_size(server)) == 0) {
if (listen(soc, 10) >= 0) {
// SOCaddr_inetntoa(adr, 128, server2);
strcpy(adr, h_loc);
} else {
#ifdef _WIN32
@@ -438,6 +439,7 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
meth = 10;
} else {
#ifdef _DEBUG
// assert(FALSE);
#endif
}
if (meth) {
@@ -1358,6 +1360,7 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
StringCat(headers, error_hdr);
StringCat(output, error);
//assert(file == NULL);
}
}
} else {
@@ -1385,10 +1388,12 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
!= StringLength(output)))
) {
#ifdef _DEBUG
//assert(FALSE);
#endif
}
} else {
#ifdef _DEBUG
// assert(FALSE);
#endif
}
@@ -1535,7 +1540,8 @@ static int htslang_load(char *limit_to, size_t limit_size, const char *path) {
} while(strnotempty(test));
}
if (!strnotempty(test)) { // éviter doublons
if (!strnotempty(test)) { // éviter doublons
// conv_printf(key,key);
const size_t len = strlen(intkey);
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 = "";
} else {
if (loops > 0) {
//err_msg += intkey;
//err_msg += " ";
}
}
}
@@ -1732,7 +1740,13 @@ static void LANG_DELETE(void) {
}
// 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) {
if (l >= 0) {

View File

@@ -68,6 +68,16 @@ struct find_handle_struct {
char path[2048];
};
#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 */
@@ -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 *curr;
//int n=0;
char *a;
int slash = 0;
@@ -327,6 +338,7 @@ int lienrelatif(char *s, size_t ssize, const char *link, const char *curr_fil) {
if (*curr == '/')
curr++;
l = link;
//c=curr;
// couper ce qui est commun
while((streql(*link, *curr)) && (*link != 0)) {
link++;
@@ -338,6 +350,8 @@ int lienrelatif(char *s, size_t ssize, const char *link, const char *curr_fil) {
link--;
curr--;
}
//if (*link=='/') link++;
//if (*curr=='/') curr++;
}
// 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)
if (*(a++) == '/')
strlcatbuff(s, "../", ssize);
//if (strlen(s)==0) strcatbuff(s,"/");
if (slash)
strlcatbuff(s, "/", ssize); // keep it absolute!

View File

@@ -639,7 +639,8 @@ int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_back * b
for(_i = 0 + k; (_i < max(back_max * k, 1)) && (index < NStatsBuffer); _i++) { // no lien
int i = (back_index + _i) % back_max; // commencer par le "premier" (l'actuel)
if (back[i].status >= 0) { // signifie "lien actif"
if (back[i].status >= 0) { // signifie "lien actif"
// int ok=0; // OPTI
ok = 0;
switch (j) {
case 0: // prioritaire

View File

@@ -188,10 +188,12 @@ static int hts_acceptlink_(httrackp * opt, int ptr,
/* Doit-on traiter les non html? */
if ((opt->getmode & HTS_GETMODE_NONHTML) == 0) { // non on ne doit pas
if (!ishtml(opt, fil)) { // non il ne faut pas
if (!ishtml(opt, fil)) { // non il ne faut pas
//adr[0]='\0'; // ne pas traiter ce lien, pas traiter
forbidden_url = 1; // interdire récupération du lien
hts_log_print(opt, LOG_DEBUG, "non-html file ignored at %s : %s", adr,
fil);
}
}
@@ -350,6 +352,7 @@ static int hts_acceptlink_(httrackp * opt, int ptr,
} else { // adresse différente, sortir?
//if (!opt->wizard) { // mode non wizard
// doit-on traiter ce lien?.. vérifier droits de sortie
switch ((opt->travel & HTS_TRAVEL_SCOPE_MASK)) {
case HTS_TRAVEL_SAME_ADDRESS:
@@ -377,6 +380,7 @@ static int hts_acceptlink_(httrackp * opt, int ptr,
if ((i > 0) && (j > 0)) {
if (!strfield2(adr + i, urladr() + j)) { // !=
if (!opt->wizard) { // mode non wizard
// printf("refused: %s\n",adr);
forbidden_url = 1; // pas même domaine
hts_log_print(opt, LOG_DEBUG, "foreign domain link canceled: %s%s",
adr, fil);
@@ -404,6 +408,7 @@ static int hts_acceptlink_(httrackp * opt, int ptr,
if ((i > 0) && (j > 0)) {
if (!strfield2(adr + i, urladr() + j)) { // !-
if (!opt->wizard) { // mode non wizard
// printf("refused: %s\n",adr);
forbidden_url = 1; // pas même .xx
hts_log_print(opt, LOG_DEBUG,
"foreign location link canceled: %s%s", adr, fil);
@@ -434,6 +439,7 @@ static int hts_acceptlink_(httrackp * opt, int ptr,
// récupérer les liens à côtés d'un lien (nearlink) (nvelle pos)
if (forbidden_url != 0 && opt->nearlink) {
if (!ishtml(opt, fil)) { // non html
//printf("ok %s%s\n",ad,fil);
forbidden_url = 0; // autoriser
may_set_prio_to = 1 + 1; // set prio to 1 (parse but skip urls) if near is the winner
hts_log_print(opt, LOG_DEBUG, "near link authorized: %s%s", adr, fil);
@@ -881,6 +887,7 @@ static int hts_acceptlink_(httrackp * opt, int ptr,
}
}
}
//adr[0]='\0'; // cancel
}
// -------------------- FINAL PHASE --------------------
// Test if the "Near" test won

View File

@@ -36,6 +36,7 @@ Please visit our Website: http://www.httrack.com
/* ZLib */
#include "zlib.h"
//#include "zutil.h"
/* MiniZip */
#include "minizip/zip.h"

View File

@@ -54,6 +54,7 @@ static int linput(FILE * fp, char *s, int max);
#include "htswrap.h"
/* specific definitions */
//#include "htsbase.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -453,7 +454,8 @@ static int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_b
for(_i = 0 + k; (_i < max(back_max * k, 1)) && (index < NStatsBuffer); _i++) { // no lien
int i = (back_index + _i) % back_max; // commencer par le "premier" (l'actuel)
if (back[i].status >= 0) { // signifie "lien actif"
if (back[i].status >= 0) { // signifie "lien actif"
// int ok=0; // OPTI
ok = 0;
switch (j) {
case 0: // prioritaire
@@ -771,7 +773,28 @@ static void sig_finish(int code) { // finir et quitter
fprintf(stderr, "\nExit requested to engine (signal %d)\n", code);
}
#ifndef _WIN32
#ifdef _WIN32
#if 0
static void sig_ask(int code) { // demander
char s[256];
signal(code, sig_term); // quitter si encore
printf("\nQuit program/Interrupt/Cancel? (Q/I/C) ");
fflush(stdout);
scanf("%s", s);
if ((s[0] == 'y') || (s[0] == 'Y') || (s[0] == 'o') || (s[0] == 'O')
|| (s[0] == 'q') || (s[0] == 'Q'))
exit(0); // quitter
else if ((s[0] == 'i') || (s[0] == 'I')) {
if (global_opt != NULL) {
// ask for stop
global_opt->state.stop = 1;
}
}
signal(code, sig_ask); // remettre signal
}
#endif
#else
static void sig_doback(int blind);
static void sig_back(int code) { // ignorer et mettre en backing
if (global_opt != NULL && !global_opt->background_on_suspend) {
@@ -786,6 +809,36 @@ static void sig_back(int code) { // ignorer et mettre en backing
}
}
#if 0
static void sig_ask(int code) { // demander
char s[256];
signal(code, sig_term); // quitter si encore
printf
("\nQuit program/Interrupt/Background/bLind background/Cancel? (Q/I/B/L/C) ");
fflush(stdout);
scanf("%s", s);
if ((s[0] == 'y') || (s[0] == 'Y') || (s[0] == 'o') || (s[0] == 'O')
|| (s[0] == 'q') || (s[0] == 'Q'))
exit(0); // quitter
else if ((s[0] == 'b') || (s[0] == 'B') || (s[0] == 'a') || (s[0] == 'A'))
sig_doback(0); // arrière plan
else if ((s[0] == 'l') || (s[0] == 'L'))
sig_doback(1); // arrière plan
else if ((s[0] == 'i') || (s[0] == 'I')) {
if (global_opt != NULL) {
// ask for stop
printf("finishing pending transfers.. please wait\n");
global_opt->state.stop = 1;
}
signal(code, sig_ask); // remettre signal
} else {
printf("cancel..\n");
signal(code, sig_ask); // remettre signal
}
}
#endif
static void sig_brpipe(int code) { // treat if necessary
signal(code, sig_brpipe);
}
@@ -898,12 +951,23 @@ static void sig_leave(int code) {
static void signal_handlers(void) {
#ifdef _WIN32
#if 0 /* BUG366763 */
signal(SIGINT, sig_ask); // ^C
#else
signal(SIGINT, sig_leave); // ^C
#endif
signal(SIGTERM, sig_finish); // kill <process>
#else
#if 0 /* BUG366763 */
signal(SIGHUP, sig_back); // close window
#endif
signal(SIGTSTP, sig_back); // ^Z
signal(SIGTERM, sig_finish); // kill <process>
#if 0 /* BUG366763 */
signal(SIGINT, sig_ask); // ^C
#else
signal(SIGINT, sig_leave); // ^C
#endif
signal(SIGPIPE, sig_brpipe); // broken pipe (write into non-opened socket)
signal(SIGCHLD, sig_ignore); // child change status
#endif

View File

@@ -250,6 +250,13 @@ static int gethost(const char *hostname, SOCaddr * server) {
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
#if 0
if (IPV6_resolver == 1) // V4 only (for bogus V6 entries)
hints.ai_family = PF_INET;
else if (IPV6_resolver == 2) // V6 only (for testing V6 only)
hints.ai_family = PF_INET6;
else
#endif
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@@ -333,7 +340,12 @@ int proxytrack_main(char *proxyAddr, int proxyPort, char *icpAddr, int icpPort,
T_SOC socICP = smallserver_init(proxyAddr, icpPort, SOCK_DGRAM);
if (soc != INVALID_SOCKET && socICP != INVALID_SOCKET) {
//char url[HTS_URLMAXSIZE * 2];
//char method[32];
//char data[32768];
//url[0] = method[0] = data[0] = '\0';
//
printf("HTTP Proxy installed on %s:%d/\n", proxyAddr, proxyPort);
printf("ICP Proxy installed on %s:%d/\n", icpAddr, icpPort);
#ifndef _WIN32
@@ -938,6 +950,7 @@ static void proxytrack_process_HTTP(PT_Indexes indexes, T_SOC soc_c) {
char *command;
char *proto;
char *surl;
//int directHit = 0;
int headRequest = 0;
int listRequest = 0;
@@ -1079,8 +1092,10 @@ static void proxytrack_process_HTTP(PT_Indexes indexes, T_SOC soc_c) {
/* Post-process request */
if (link_has_authority(surl)) {
if (strncasecmp(surl, "http://proxytrack/",
sizeof("http://proxytrack/") - 1) == 0) {
if (strncasecmp
(surl, "http://proxytrack/",
sizeof("http://proxytrack/") - 1) == 0) {
//directHit = 1; /* Another direct hit hack */
}
StringCopy(url, surl);
} else {
@@ -1101,6 +1116,7 @@ static void proxytrack_process_HTTP(PT_Indexes indexes, T_SOC soc_c) {
toHit += 7;
}
/* Direct hit */
//directHit = 1;
StringCopy(url, "");
if (!link_has_authority(toHit))
StringCat(url, "http://");
@@ -1111,6 +1127,7 @@ static void proxytrack_process_HTTP(PT_Indexes indexes, T_SOC soc_c) {
const char *toHit = surl + sizeof("/proxytrack/") - 1;
/* Direct hit */
//directHit = 1;
StringCopy(url, "");
if (!link_has_authority(toHit))
StringCat(url, "http://");
@@ -1594,7 +1611,10 @@ static int proxytrack_start_ICP(PT_Indexes indexes, T_SOC soc) {
unsigned char Opcode = buffer[0];
unsigned char Version = buffer[1];
unsigned short Message_Length = READ_NET16(&buffer[2]);
unsigned int Request_Number = READ_NET32(&buffer[4]); /* Session ID */
unsigned int Request_Number = READ_NET32(&buffer[4]); /* Session ID */
//unsigned int Options = READ_NET32(&buffer[8]);
//unsigned int Option_Data = READ_NET32(&buffer[12]); /* ICP_FLAG_SRC_RTT */
//unsigned int Sender_Host_Address = READ_NET32(&buffer[16]); /* ignored */
unsigned char *Payload = &buffer[20];
buffer[bufferSize] = '\0'; /* Ensure payload is NULL terminated */

View File

@@ -1035,6 +1035,7 @@ static PT_Element PT_ReadCache__New_u(PT_Index index_, const char *url,
if (unzOpenCurrentFile(index->zFile) == Z_OK) {
char headerBuff[8192 + 2];
int readSizeHeader;
//int totalHeader = 0;
int dataincache = 0;
/* For BIG comments */
@@ -1073,8 +1074,9 @@ static PT_Element PT_ReadCache__New_u(PT_Index index_, const char *url,
ZIP_READFIELD_STRING(line, value, "Last-Modified", r->lastmodified); // last-modified
ZIP_READFIELD_STRING(line, value, "Etag", r->etag); // Etag
ZIP_READFIELD_STRING(line, value, "Location", r->location); // 'location' pour moved
ZIP_READFIELD_STRING(line, value, "Content-Disposition",
r->cdispo); // Content-disposition
ZIP_READFIELD_STRING(line, value, "Content-Disposition", r->cdispo); // Content-disposition
//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_); // Original save filename
if (line[0] != '\0') {
int len = r->headers ? ((int) strlen(r->headers)) : 0;
@@ -1088,7 +1090,8 @@ static PT_Element PT_ReadCache__New_u(PT_Index index_, const char *url,
strcat(r->headers, "\r\n");
}
}
} while (offset < readSizeHeader && !lineEof);
} while(offset < readSizeHeader && !lineEof);
//totalHeader = offset;
/* Previous entry */
if (previous_save_[0] != '\0') {
@@ -1199,6 +1202,7 @@ static PT_Element PT_ReadCache__New_u(PT_Index index_, const char *url,
strcpy(r->msg, "Cache Read Error : Read Data");
} else
*(r->adr + r->size) = '\0';
//printf(">%s status %d\n",back[p].r->contenttype,back[p].r->statuscode);
} else { // erreur
r->statuscode = STATUSCODE_INVALID;
strcpy(r->msg, "Cache Memory Error");
@@ -1480,12 +1484,14 @@ static int PT_LoadCache__Old(PT_Index index_, const char *filename) {
a += cache_brstr(a, firstline);
strcpy(cache->lastmodified, firstline);
} else {
// fprintf(opt->errlog,"Cache: version 1.%d not supported, ignoring current cache"LF,cache->version);
fclose(cache->dat);
cache->dat = NULL;
free(use);
use = NULL;
}
} else { // non supporté
} else { // non supporté
// fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: %s not supported, ignoring current cache"LF,firstline);
fclose(cache->dat);
cache->dat = NULL;
free(use);
@@ -1494,6 +1500,7 @@ static int PT_LoadCache__Old(PT_Index index_, const char *filename) {
/* */
} else { // Vieille version du cache
/* */
// hts_log_print(opt, LOG_WARNING, "Cache: importing old cache format");
cache->version = 0; // cache 1.0
strcpy(cache->lastmodified, firstline);
}

View File

@@ -106,6 +106,8 @@ grep -Eq 'srcset="j\.gif 2x"' "$saved" ||
# inline style attribute, with the URL unquoted, double-quoted and single-quoted
# (the quote style is preserved on rewrite). No-detect attributes (title, alt,
# ...) are left untouched. Asserted by rewrite (deterministic), not download.
# data-* (#201/#203) is omitted: its detection is currently nondeterministic and
# can't be locked yet.
site2="$tmp/attrs"
mkdir -p "$site2"
for f in xl ibg ibgs cex cexd cexs tt; do gif "$site2/$f.gif"; done
@@ -350,64 +352,4 @@ found "v.webm" "$out10"
found "subs.vtt" "$out10"
notfound "plain.gif" "$out10"
# Unknown-attr (data-*) URLs (#201/#203): the script automaton state must reset at
# </script>, or detection dies for the rest of the page after the first script.
site11="$tmp/dataattr"
mkdir -p "$site11"
for f in pre post mid spdata handler handler2 jsdecoy jsdecoy2 nodecoy \
spalt glalt spxml jtail1 jtail2 textdecoy tagdecoy phantom; do gif "$site11/$f.gif"; done
cat >"$site11/index.html" <<EOF
<html><body>
<img data-pre="file://$site11/pre.gif">
<script>var x = 1;</script>
<img data-post="file://$site11/post.gif">
<img data-mid="file://$site11/mid.gif" alt="mid-tag attr, no delimiter after">
<img data-sp = "file://$site11/spdata.gif" q=1>
<img alt="nodecoy.gif" src="pre.gif">
<img alt = "spalt.gif" id=x>
<img src="pre.gif"alt="glalt.gif" id=x>
<p xmlns:bar = "spxml.gif" id=x></p>
<div data-json='["jtail1.gif","jtail2.gif"]' q=1></div>
<p>t = "textdecoy.gif" q</p>
<img ="tagdecoy.gif" q>
<a onclick='q = 1; "h1'>x</a>
<img data-h1="file://$site11/handler.gif">
<a onclick='w = 1; "h2>x</a>
<img data-h2="file://$site11/handler2.gif">
<script>var s; s = 1; "jsdecoy.gif";</script>
<script>var s2 = "jsdecoy2.gif" x;</script>
<script>var f = "</script>
<img alt="y" "phantom.gif">
</body></html>
EOF
out11="$tmp/dataattr-out"
crawl "$site11/index.html" "$out11"
saved11=$(savedhtml "$out11")
test -n "$saved11" || ! echo "FAIL: saved dataattr page not found" || exit 1
grep -Fq 'data-pre="pre.gif"' "$saved11" ||
! echo "FAIL #201: data-* URL before any script not detected/rewritten" || exit 1
grep -Fq 'data-post="post.gif"' "$saved11" ||
! echo "FAIL #201: data-* URL after a script not detected (state leak)" || exit 1
grep -Fq 'data-mid="mid.gif"' "$saved11" ||
! echo "FAIL #201: mid-tag data-* URL not detected" || exit 1
grep -Fq 'data-sp = "spdata.gif"' "$saved11" ||
! echo "FAIL #201: spaced-= data-* URL not detected" || exit 1
found "handler.gif" "$out11" # automaton reset at the handler-terminator exit
found "handler2.gif" "$out11" # ... and at the '>' exit of an unterminated handler
# a JS string not preceded by =/(/, is still ignored after the reset
notfound "jsdecoy.gif" "$out11"
# in-script, the strict follower gate still applies (intag is 1 in script bodies)
notfound "jsdecoy2.gif" "$out11"
# no-detect attrs stay exempt, incl. spaced-'=' and glued-attr forms
notfound "nodecoy.gif" "$out11"
notfound "spalt.gif" "$out11"
notfound "glalt.gif" "$out11"
notfound "spxml.gif" "$out11"
# not '='-preceded: comma-list tails and out-of-tag text tokens stay ignored
notfound "jtail2.gif" "$out11"
notfound "textdecoy.gif" "$out11"
notfound "tagdecoy.gif" "$out11" # a '=' glued to the tag name is not an attr
# a </script> inside a JS string must not cause phantom fetches later
notfound "phantom.gif" "$out11"
exit 0

View File

@@ -1,17 +0,0 @@
#!/bin/bash
#
# Cache generation reconcile policies (httrack -#test=reconcile <dir>):
# promote a stranded old generation, keep the larger one after an aborted
# run, and restore the old one when an update transferred nothing.
set -eu
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
out=$(httrack -#test=reconcile "$dir")
test "$out" = "cache-reconcile: OK" || {
echo "expected 'cache-reconcile: OK', got: $out" >&2
exit 1
}

View File

@@ -1,19 +0,0 @@
#!/bin/bash
#
# Read-side cache corruption (httrack -#test=cache-corrupt <dir>): zip byte
# surgery (bad/oversized X-Size, blanked X-In-Cache, smashed header, garbled
# deflate) must each be rejected per-entry, never crash, never taint the sibling.
set -eu
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
# the smashed-header case logs expected "Corrupted cache entry" warnings on
# stdout; the verdict is the last line
out=$(httrack -#test=cache-corrupt "$dir" 2>/dev/null | tail -n1)
test "$out" = "cache-corrupt: OK" || {
echo "expected 'cache-corrupt: OK', got: $out" >&2
exit 1
}

View File

@@ -4,9 +4,10 @@
# POSIX /bin/sh on some platforms (e.g. macOS), so avoid bashisms and GNU-only
# tool flags despite the #!/bin/bash above.
# Cache write-failure policy (-#test=cache-writefail <dir>). #174/#219: disk
# full or a failure streak aborts cleanly; an isolated failure or an oversized
# entry is only dropped.
# Cache write-failure handling (httrack -#test=cache-writefail <dir>). #174/#219.
# A failing new.zip write (disk full) used to crash the process via assertf; it
# must instead stop the mirror with a fatal error (exit_xh=-1), no crash. The
# self-test asserts that; reverting the fix makes -#test=cache-writefail abort (SIGABRT) and fail.
set -eu
@@ -21,9 +22,3 @@ printf '%s\n' "$out" | grep -qx "cache-writefail: OK" || {
echo "expected 'cache-writefail: OK', got: $out" >&2
exit 1
}
# A skipped entry must be warned about with its URL.
printf '%s\n' "$out" | grep -q "entry not cached: example.com/" || {
echo "expected a URL-bearing skip warning" >&2
exit 1
}

View File

@@ -1,19 +1,17 @@
#!/bin/bash
# Issues #32/#41: a Content-Length that disagrees with the body warns
# "incomplete transfer" and skips the cache; -%B (tolerant) accepts it.
set -euo pipefail
# Issues #32/#41: a Content-Length that disagrees with the body warns "bogus
# state (broken size)" and skips the cache; -%B (tolerant) accepts it.
: "${top_srcdir:=..}"
# Default: warn, but the file is still written.
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 \
--found 'size/oversize.bin' \
--log-found 'incomplete transfer \(expected' \
--log-found 'bogus state \(broken size' \
httrack 'BASEURL/size/index.html'
# -%B (tolerant): no warning, file written.
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 \
--found 'size/oversize.bin' \
--log-not-found 'incomplete transfer|not cached' \
--log-not-found 'bogus state' \
httrack 'BASEURL/size/index.html' '-%B'

View File

@@ -2,7 +2,7 @@
#
# Degenerate delayed-type paths (#5/#107 family): redirects that never resolve
# a name must drop cleanly -- no .delayed leftovers (audited by local-crawl.sh),
# no "not cached" warnings, resolvable links still land correctly.
# no "bogus state" cache warnings, resolvable links still land correctly.
set -euo pipefail
@@ -16,5 +16,5 @@ bash "$top_srcdir/tests/local-crawl.sh" --rerun --errors 0 \
--not-found 'delayed/noloc.html' \
--not-found 'delayed/selfloop.html' \
--not-found 'delayed/chain9.pdf' \
--log-not-found 'not cached' \
--log-not-found 'bogus state' \
httrack 'BASEURL/delayed/index.html'

View File

@@ -7,8 +7,10 @@ set -euo pipefail
: "${top_srcdir:=..}"
# cancelled crawls can orphan .delayed placeholders (#483): skip that audit
start=$(date +%s)
bash "$top_srcdir/tests/local-crawl.sh" \
--skip-delayed-audit \
--log-found 'More than 2 seconds passed' \
httrack 'BASEURL/trickle/index.html' -E2 -c4
wall=$(($(date +%s) - start))

View File

@@ -44,7 +44,7 @@ bash "$top_srcdir/tests/local-crawl.sh" --rerun \
--file-matches 'big/a/blk2.css' 'url\(blk2-bg\.png\)' \
--file-matches 'big/p/5.html' "document\\.write\\('<a href=\"\\.\\./f5/dw\\.html\"" \
--file-not-matches 'big/p/1.html' 'href="/big/' \
--log-not-found 'not cached|[Pp]anic|assert' \
--log-not-found 'bogus state|[Pp]anic|assert' \
--log-found '\(404\) at link [^ ]*/big/e/404\.html' \
--log-found '\(410\) at link [^ ]*/big/e/410\.html' \
--log-found '\(500\) at link [^ ]*/big/e/500\.html' \

View File

@@ -1,12 +0,0 @@
#!/bin/bash
#
# An update run against a dead server must not destroy the cache: the no-data
# rollback restores the previous hts-cache generation (zip caches lost it).
set -eu
: "${top_srcdir:=..}"
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 --rerun-dead \
--found 'simple/basic.html' \
httrack 'BASEURL/simple/basic.html'

View File

@@ -1,14 +0,0 @@
#!/bin/bash
#
# An all-304 update of a tiny site (headers under the 32K rollback threshold)
# is a healthy run: it must not trip the no-data rollback as a fake outage.
set -eu
: "${top_srcdir:=..}"
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 --rerun \
--log-found 'no files updated' \
--log-not-found 'No data seems to have been transferred' \
--found 'mini304/index.html' --found 'mini304/page.html' \
httrack 'BASEURL/mini304/index.html'

View File

@@ -1,13 +0,0 @@
#!/bin/bash
#
# Cancelled delayed-type-checks must not orphan .delayed placeholders (#483).
# Timing-dependent (hence two tries); -A keeps the window reachable.
set -euo pipefail
: "${top_srcdir:=..}"
for _ in 1 2; do
bash "$top_srcdir/tests/local-crawl.sh" \
httrack 'BASEURL/dcancel/index.html' -E1 -c4 -A25000
done

View File

@@ -48,7 +48,6 @@ TESTS = \
01_engine-parse.test \
01_engine-pause.test \
01_engine-rcfile.test \
01_engine-reconcile.test \
01_engine-redirect.test \
01_engine-relative.test \
01_engine-robots.test \
@@ -64,7 +63,6 @@ TESTS = \
01_engine-useragent.test \
01_zlib-acceptencoding.test \
01_zlib-cache.test \
01_zlib-cache-corrupt.test \
01_zlib-cache-golden.test \
01_zlib-cache-writefail.test \
01_zlib-savename-cached.test \
@@ -101,9 +99,6 @@ TESTS = \
33_local-delayed.test \
34_local-maxtime.test \
35_local-maxsize.test \
36_local-bigcrawl.test \
37_local-cache-outage.test \
38_local-update-304.test \
39_local-delayed-cancel.test
36_local-bigcrawl.test
CLEANFILES = check-network_sh.cache

View File

@@ -25,8 +25,6 @@
# --cookie writes a Netscape cookies.txt (scoped to the discovered host:port,
# which the ephemeral port forces into the cookie domain) and passes it to
# httrack via --cookies-file, to exercise preloaded cookies.
# --rerun-dead re-runs with the server stopped: the no-data rollback must
# restore the previous hts-cache generation byte-identical.
set -u
@@ -39,7 +37,6 @@ key="${testdir}/server.key"
tls=
verbose=
rerun=
rerun_dead=
tmpdir=
serverpid=
crawlpid=
@@ -97,6 +94,7 @@ tmpdir=$(mktemp -d "${tmptopdir}/httrack_local.XXXXXX") || die "could not create
# --- parse leading control flags --------------------------------------------
declare -a audit=()
declare -a cookies=()
skip_delayed_audit=""
scheme=http
pos=0
args=("$@")
@@ -104,8 +102,7 @@ nargs=$#
while test "$pos" -lt "$nargs"; do
case "${args[$pos]}" in
--debug) verbose=1 ;;
--rerun) rerun=1 ;; # run httrack a second time (update pass) before auditing
--rerun-dead) rerun_dead=1 ;; # re-run with the server stopped (cache rollback)
--rerun) rerun=1 ;; # run httrack a second time (update pass) before auditing
--no-purge)
nopurge=1
audit+=("--no-purge")
@@ -122,6 +119,9 @@ while test "$pos" -lt "$nargs"; do
pos=$((pos + 1))
cookies+=("${args[$pos]}")
;;
--skip-delayed-audit)
skip_delayed_audit=1
;;
--errors | --files)
audit+=("${args[$pos]}" "${args[$((pos + 1))]}")
pos=$((pos + 1))
@@ -241,43 +241,6 @@ if test -n "$rerun"; then
fi
fi
# --- optional dead pass: server stopped, the cache must survive the rollback --
if test -n "$rerun_dead"; then
zip="${out}/hts-cache/new.zip"
test -s "$zip" || die "no cache was written by the first pass"
cp "$zip" "${tmpdir}/cache-before.zip"
cp "${out}/hts-log.txt" "${tmpdir}/log-before.txt"
kill "$serverpid" 2>/dev/null
wait "$serverpid" 2>/dev/null
serverpid=
info "re-running httrack against the stopped server"
httrack -O "$out" --user-agent="httrack $ver local ($(uname -omrs))" \
"${moreargs[@]}" "${hts[@]}" >"${log}.dead" 2>&1 &
crawlpid=$!
wait "$crawlpid" || true
crawlpid=
result "OK (dead pass ran)"
# The dead pass must have gone through the no-data rollback, not bailed out
# before the mirror loop (which would leave the cache trivially untouched).
info "checking the dead pass hit the rollback"
if grep -aq "No data seems to have been transferred" "${out}/hts-log.txt"; then
result "OK"
else
result "rollback notice not found in hts-log.txt"
exit 1
fi
info "checking the previous cache generation was restored"
if cmp -s "$zip" "${tmpdir}/cache-before.zip" &&
test ! -e "${out}/hts-cache/old.zip"; then
result "OK"
else
result "new.zip differs from the pre-outage cache (or old.zip left behind)"
exit 1
fi
# Audits below describe the healthy crawl, not the dead pass.
cp "${tmpdir}/log-before.txt" "${out}/hts-log.txt"
fi
# --- discover the single host root (127.0.0.1_<port> or 127.0.0.1) -----------
hostroot=
for cand in "${out}/127.0.0.1_${port}" "${out}/127.0.0.1"; do
@@ -289,12 +252,15 @@ done
test -n "$hostroot" || die "could not find host root under $out"
debug "host root: $hostroot"
# No crawl, even a cancelled one, may leave .delayed temporaries (#107, #483).
info "checking for leftover .delayed files"
leftovers=$(find "$out" -name '*.delayed' 2>/dev/null | head -5)
if test -z "$leftovers"; then result "OK"; else
result "leftover: $leftovers"
exit 1
# A completed crawl must leave no .delayed temporaries (issue #107).
# --skip-delayed-audit: a cancelled crawl can orphan placeholders (issue #483)
if test -z "$skip_delayed_audit"; then
info "checking for leftover .delayed files"
leftovers=$(find "$out" -name '*.delayed' 2>/dev/null | head -5)
if test -z "$leftovers"; then result "OK"; else
result "leftover: $leftovers"
exit 1
fi
fi
# --- audit -------------------------------------------------------------------

View File

@@ -781,7 +781,7 @@ class Handler(SimpleHTTPRequestHandler):
self.send_raw(b"", "text/html")
# broken Content-Length (#32/#41): declared size != bytes sent. httrack
# warns "incomplete transfer" and skips the cache unless -%B.
# warns "bogus state (broken size)" and skips the cache unless -%B.
def route_size_index(self):
self.send_html('\t<a href="oversize.bin">over</a>\n')
@@ -831,16 +831,6 @@ class Handler(SimpleHTTPRequestHandler):
def route_redir_target(self):
self.send_raw(b"<html><body>redirect target</body></html>\n", "text/html")
# --- /mini304/: tiny fully-cacheable site (an update gets only 304s) ---
def route_mini304_index(self):
self.big_send(
b'<html><body>\n\t<a href="page.html">page</a>\n</body></html>\n',
"text/html",
)
def route_mini304_page(self):
self.big_send(b"<html><body>tiny cacheable page</body></html>\n", "text/html")
# --- delayed-type degenerate paths (issues #5/#107) --------------------
def route_delayed_index(self):
self.send_html(
@@ -913,26 +903,6 @@ class Handler(SimpleHTTPRequestHandler):
except OSError:
pass
# #483: trickled .bin pages so the -E stop lands in the type waiter's
# unlock-to-patch window with body bytes pending.
def route_dcancel_index(self):
self.send_bin_index()
def route_dcancel_page(self):
self.send_response(200)
self.send_header("Content-Type", "application/octet-stream")
self.send_header("Content-Length", "4096")
self.end_headers()
if self.command == "HEAD":
return
try:
for _ in range(32):
self.wfile.write(b"z" * 128)
self.wfile.flush()
time.sleep(0.05)
except OSError:
pass
# -M byte cap (#77): large fast files so a crawl overruns -M immediately.
BIGFILE_BYTES = 640 * 1024
@@ -996,15 +966,6 @@ class Handler(SimpleHTTPRequestHandler):
"/trickle/p5.bin": route_trickle_page,
"/trickle/p6.bin": route_trickle_page,
"/trickle/p7.bin": route_trickle_page,
"/dcancel/index.html": route_dcancel_index,
"/dcancel/p0.bin": route_dcancel_page,
"/dcancel/p1.bin": route_dcancel_page,
"/dcancel/p2.bin": route_dcancel_page,
"/dcancel/p3.bin": route_dcancel_page,
"/dcancel/p4.bin": route_dcancel_page,
"/dcancel/p5.bin": route_dcancel_page,
"/dcancel/p6.bin": route_dcancel_page,
"/dcancel/p7.bin": route_dcancel_page,
"/bigfiles/index.html": route_bigfiles_index,
"/bigfiles/p0.bin": route_bigfile,
"/bigfiles/p1.bin": route_bigfile,
@@ -1032,8 +993,6 @@ class Handler(SimpleHTTPRequestHandler):
"/redir/index.html": route_redir_index,
"/redir/go.php": route_redir_go,
"/redir/target.html": route_redir_target,
"/mini304/index.html": route_mini304_index,
"/mini304/page.html": route_mini304_page,
}
# --- /big/ seeded pseudo-site ------------------------------------------