An update purge deletes the children of a page that failed to fetch - #1390
Merged
Conversation
The end-of-update purge unlinks what the previous mirror had and this run did not write. A page that fails after its last retry keeps its own copy (#746) but is never parsed, so the links it carries are never queued and never noted: the purge reads them as gone from the site and deletes them. A dropped connection on one hub page therefore costs its whole subtree, unlogged at the default verbosity, and the run still reports success. Hold the purge back for the run when a link that could carry links gave up: the mirror is not a complete scan of the site, so the old.lst minus new.lst difference no longer means what the purge assumes. This is the guard an aborted run already gets. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
A library consumer reusing one httrackp for two mirrors carried the first run's verdict into the second and never purged again: the flag was cleared only in hts_create_opt. Clear it where the run's other state is reset. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Review found the guard reading the wrong evidence and missing two cases. A content type on an error reply describes the error page, so a .bin that 500s with an HTML body held the purge back; what the previous run cached decides now, and this reply only when the cache has nothing. A banned host and a size cap also stop the parser before it can queue anything, so both join the gate. The warning moves inside the old.lst branch, where a purge could have happened. Test 348 gains a third pass whose failures are a 404 and a lost .bin: it must still purge. Without that, a guard that fired on any dead link at all passed the whole suite. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
This fix had to invert an assertion in a neighbouring self-test, and its own guard passed all 372 tests while firing on any dead link at all. Both say the same thing, and AGENTS.md's adversarial section did not. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
The guard listed failure codes by hand and missed STATUSCODE_INVALID, which is what a mangled Content-Encoding, a bad chunk length, a disk write error or an aborted external wrapper all report. Those pages keep their previous copy under #746 but never set the flag, so the purge still took every child they linked: the bug this whole change exists to fix. Key it on back_transfer_failed() instead, the predicate that decides whether the copy is kept, so the two sets cannot drift apart again. banned is subsumed by it (timeout and slow are both negative codes) and can_retry adds nothing: an answered HTTP error is recovered from the cache on an update, which re-queues what it linked. The other direction was worse. Typing the link fell through to its savename when there was no cache entry, so any new permanently-dead .html link disabled the purge for the whole run, every run. Only a page the previous run fetched successfully has a subtree at risk, so require that instead. The test now drives five shapes past the guard and reports through hts-changes.json rather than a log string, including two boundaries that must not hold: an answered 500, and a page the size cap makes the engine skip on purpose (whose own copy #746 drops, so its children go with it). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On
--updatethe engine unlinks what the previous mirror had and this run did not write. A page that gives up after its last retry keeps its copy (#746) but is never parsed, so its links never reachnew.lst, and the purge reads that gap as the site dropping them: one dropped connection on a hub page costs its whole subtree, silently, while the run reports success. An HTTP error already escapes this, being masked to a 304 and recovered from the cache. A transport failure has no such path.The purge now holds off for the run when a link that could carry links fails to transfer, keyed on
back_transfer_failed()so it cannot drift from the predicate that decides whether the copy is kept. A mangledContent-Encoding, a bad chunk length, a disk write error and an aborted external wrapper all reportSTATUSCODE_INVALID, keep their copy, and now keep their children with it. Two cases deliberately do not hold: an answered HTTP error, which is recovered and re-queues its links, and a page the size cap skips, whose own copy #746 drops so its children go with it rather than being stranded. The guard also requires that the previous run actually mirrored the page, since only then is there a subtree at risk. Typing the link by its savename instead let any new permanently dead.htmllink disable the purge on every run.Masking the failure as a 304 was the alternative and does not work this far down the loop: that masking sits ahead of
back_finalize, and doing it at the give-up point would disarm the "no data transferred, restore the previous session" rollback, so a mirror whose host had vanished would report success.httrackpgains one field at its tail, live statecopy_htsoptleaves alone. It lands in the padding afterwizard_filterson LP64, sosizeofis unchanged there; on ILP32 the struct has no trailing padding and grows by four bytes, as every earlier tail field did.size_httrackpis asserted againstsizeofat each entry point, so a stale-header consumer aborts rather than corrupts.Known gap, not fixed here: a failed fetch writes no cache entry, so a hub failing on two consecutive runs has no previous entry the second time and stops holding the purge.
Test 348 drives five shapes past the guard and reads
hts-changes.jsonrather than a log line, the two boundaries above among them. Found by the httrack-android session's overnight robustness audit, reproduced against 3.49.23.