A fragment on an inlined reference is dropped, so an SVG sprite selector is lost - #804
Merged
Conversation
sf_resolve cuts a reference at '#' to find the mirrored file, and sf_inline then replaced the whole reference with the data: URI it built, so the fragment never came back. On an SVG that changes what renders: "sprite.svg#icon" selects one element, and without the selector the browser draws the whole sheet. Re-attach it to both replacements, the data: URI and the rebased path an over-cap asset falls back to. The query stays dropped: it named the remote resource, not the mirrored file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
The fragment is copied out of the document, so its '%' and '&' are the document's own escapes; percent-encoding them again turns "#a&b" into a lookup for "a&b". A mirrored path is the opposite case, a raw filesystem name that has to be escaped, '#' included now that a fragment can follow it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Only ')' and the '%'/'&' pass-through were exercised, so dropping '"', a quote, a paren, a backslash, '<'/'>', whitespace or the high-byte rule from sf_append_escaped left the suite green. The two that would be a real injection are the '"' that ends the attribute the rewriter re-quotes and the whitespace that ends an unquoted url() token; the fixture now carries one fragment per class, and each one dies to its own mutant. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
…-766 Signed-off-by: Xavier Roche <roche@httrack.com> # Conflicts: # tests/Makefile.am
…-766 Signed-off-by: Xavier Roche <roche@httrack.com> # Conflicts: # tests/Makefile.am
Fix the TESTS-tail union merge's missing continuation backslash. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Register 112_local-single-file-fragment.test in tests-list.mk after the #845 TESTS-list restructure moved it out of tests/Makefile.am. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
xroche
added a commit
that referenced
this pull request
Aug 7, 2026
Resolves three collisions the branch had with what landed since it was cut. #804 kept a fragment on an inlined reference by parsing it back out of the reference and re-escaping it. Under the mark design the mark covers the reference alone, so the fragment is document text the pass never touches and reaches the data: URI byte-identical; sf_fragment/sf_append_fragment go with the scanner they were written for. The query has to go the other way -- glued to base64 it corrupts the payload -- so htsparse now writes the mark after it and the marked span carries it. #1011 added a private hts_random_bytes to htsweb.c while this branch added one to htstools.c. htsserver links libhttrack but cannot see a hidden symbol inside it, so the two now share htsrandom.c: master's runtime-resolved RtlGenRandom on Windows, this branch's getrandom-then-/dev/urandom on POSIX. Master's test 94 then caught a bug the branch shipped: sf_rel_is_stylesheet() bounded its outer scan at the tag's '>' but handed strstrcase the raw buffer, so a <link rel="canonical"> on a page carrying any later rel="stylesheet" was classed as one and the pass inlined the page it named. rel is now matched as a token inside the value rech_endtoken() delimits. Only a crawl test sees this -- the engine self-test writes the marks it feeds the pass, so the class is an input there rather than something htsparse decided. 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.
--single-fileresolves a reference by cutting it at#, then substitutes thedata:URI it built, so the fragment is gone. On an SVG that is a rendering bug rather than a broken link:sprite.svg#iconpicks one element out of a sprite sheet, and without the selector the browser draws the whole sheet. The page still loads, which is why this is easy to miss.The fragment now comes back onto both replacements, the
data:URI and the relative path an over-cap asset falls back to inside an inlined stylesheet. It gets percent-escaped on the way out, because a)inside a fragment would otherwise close an unquoted CSSurl()token;#joined the escape set on the path side for the same reason. Escapes the document already carried (%,&) stay as they are, since encoding them twice changes which id the browser looks for. The query is still dropped: it named the remote resource, not the mirrored file. The lookup keeps cutting at#, so which file gets found is unchanged.The
-#test=singlefileengine self-test covers all four reference shapes, the rebase fallback, and one fragment per member of the escape set, so dropping any single character from that set turns the suite red. A new crawl test covers the whole thing end to end. Both go red on master.Closes #766