feed: absolute URLs in syndicated HTML (RSS + JSON Feed) #21
Loading…
Reference in a new issue
No description provided.
Delete branch "feed/absolute-urls"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out of the PR #13 review. Spec + full evidence chain:
specs/feed-image-url.md(Appendix A).Problem
build_feed_items()renders post bodies with the template-sharedparse_markdownfilter, so/feed.xml+/feed.jsonwent out with root-relative URLs. Measured on the live feed: 38src/ 8href/ 169srcsetroot-relative occurrences across 41 items.Readers render
content_htmlinside their own document context, so those URLs resolve against the reader's origin → broken images/links by construction. The W3C feed validator flags the live feed today:(FreshRSS looks fine only because SimplePie rewrites URL attributes against the channel link — and even SimplePie never rewrites
srcset, so all 169 responsive candidates 404'd silently there. Details in spec Appendix A.3.)Fix
Attribute-aware rewrite with
lol_htmlat the single feed choke point (build_feed_items, covers RSS + JSON):a[href],img[src],iframe|video|audio|source[src]— prefix root-relative/…(not//) withhttps://michalvanko.devimg[srcset],source[srcset]— per-candidate rewrite, descriptors keptCode samples are safe by construction: only real attribute values are rewritten, never text content. (17/41 posts contain code blocks — naive replace was rejected for exactly this reason.)
Tests (9 in
src/feed.rs, suite 43/43)src/href/srcsetsrc0 rel / 53 abs,href0 rel / 352 abs,srcset0 rel / 171 abs (was 38 / 8 / 169 root-relative)Notes
lol_html 3(~40 lines of rewrite logic).length="0", truncateddescriptionHTML,<iframe>incontent:encoded, missingatom:link rel="self".🪦 Live preview
removed (PR closed)
- 2022-05-07 treasure-hunt weekly: [HackKosice hackathon]() and [Bevy game engine]() had empty URLs — the W3C feed validator counts href="" as a relative reference (ContainsRelRef). Gave them the real destinations (hackkosice.com, bevyengine.org — same URL the post already uses later). - delete _posts/blog/dev-2019-08-09-ide-to copy.md: an accidental leftover draft copy (" copy" filename, test tags another-one/another, thumbnail /images/uploads/screenshot.gif that 404s) that was published: true and live in the feed. Surfaced by the new enclosure-length stat logging.Review + follow-up round (agent session, 2026-09-14)
Core fix verified end-to-end: root-relative
src/href/srcsetwent 38/8/169 → 0 locally and on the preview; code samples byte-identical; srcset descriptors intact; separator format matches the picture generator exactly. Merge-worthy.Re-running the W3C validator against this PR's preview surfaced a second wave, now fixed in
3c61928+bfbcf5b:length=""×20fs::metadata; unstattable → enclosure dropped withwarn!ContainsRelRef×25href="#anchor"TOC links → now rewritten to<post-url>#anchor; + 2 empty[text]()links fixed in post contentMissingAtomSelfLinkatom:link rel=self(rss crateatomfeature)MissingRealNamewebMaster→email (Michal Vanko)pubDate= oldest post (bug).first()— newest itemResult:
validity: true(cache-busted validator run against the refreshed preview). Remaining findings are documented opens in the spec:<p><figure>stray</p>HTML from the markdown image handler (site-wide, affects the website too — own PR), iframe policy in feed content, SVG og:image, hex-escape style in titles.Bonus finds: the new enclosure-length logging immediately caught
_posts/blog/dev-2019-08-09-ide-to copy.md— an accidental draft copy (published: true, test tags, 404 thumbnail) that was live in the feed — deleted. Also confirmed the old "feeds never land in dist/" finding is already resolved (base.html discovery links).CI: cargo test green on
bfbcf5b(46 tests, incl. 3 new feed audits).b9153ab056e48a10b029Correction to my earlier comment:
_posts/blog/dev-2019-08-09-ide-to copy.mdis an intentionally published development article — restored ind1b142c(it was deleted in3c61928as a presumed accident). The only kept change: itsthumbnail:line stays commented out because/images/uploads/screenshot.gif404s and trips the enclosure-length warning. Spec updated to match.