Skip to content

Fix FilterFullFeed to handle HTTPS/HTTP scheme mismatches and encoding - #149

Merged
id774 merged 1 commit into
masterfrom
claude/filterfullfeeds-bug-23av56
Aug 15, 2026
Merged

Fix FilterFullFeed to handle HTTPS/HTTP scheme mismatches and encoding#149
id774 merged 1 commit into
masterfrom
claude/filterfullfeeds-bug-23av56

Conversation

@id774

@id774 id774 commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Summary

Significantly improves the FilterFullFeed plugin to work with modern HTTPS feeds against a 2013-era siteinfo database, properly handle character encodings, and gracefully handle edge cases where XPath selectors no longer match redesigned sites.

Key Changes

  • Scheme-agnostic matching: Records anchored on http:// now match https:// links and vice versa, since the database describes site layouts rather than transport protocols. 3,448 of 3,504 records anchor on schemes, nearly all ^http://, but feeds now deliver HTTPS links.

  • Encoding handling improvements:

    • Pages are now parsed from streams rather than decoded strings, allowing Nokogiri to read charset declarations in meta tags
    • Record-level enc field is used as a fallback for pages declaring no charset anywhere
    • Invalid encoding names in records are silently ignored rather than failing
    • Output is always normalized to valid UTF-8
  • Graceful XPath failures: When an XPath selector matches nothing (site redesigned), the original feed summary is preserved instead of replacing it with an empty description. Misses are logged at warn level.

  • Performance optimization: Siteinfo records are now compiled into Entry structs with pre-compiled regex patterns, eliminating thousands of Regexp.new calls per feed run.

  • Data validation: Records with missing URL patterns, missing XPath, or invalid regex patterns are filtered out during load rather than failing at match time. Empty patterns would otherwise match every link.

  • API enhancement: Added Automatic::Http.open(url) to complement Http.read(), allowing callers that need stream-level control (like HTML parsers) to avoid pre-decoded strings that interfere with charset detection.

Implementation Details

  • New Entry struct holds compiled patterns and metadata for efficient matching
  • match() method tries links under both HTTP and HTTPS schemes
  • document() method carefully manages encoding detection: response charset > meta tag > record fallback
  • body() method returns nil for empty XPath results, allowing callers to distinguish "nothing found" from "found empty content"
  • Comprehensive test suite added covering scheme mismatches, encoding edge cases, and graceful degradation scenarios

https://claude.ai/code/session_01RSLxro7DeKVdunYdYMyjvY

The filter did nothing on almost every feed, and where it did something it
could make the item worse than it found it. Three separate causes, all of them
consequences of the shipped siteinfo being a 2013 snapshot of a database that
can no longer be refreshed.

A link was matched against a record's pattern exactly as the feed gave it.
3,448 of the 3,504 usable records anchor on a scheme and all but twenty of
those say `^http://`, while the sites they name have since moved to HTTPS, so
an ordinary feed today matched nothing at all and every item was logged as
"Fulltext SITEINFO not found". A record describes a site's layout, not how it
is transported, so the link is now tried under either scheme; only the match is
rewritten, and the page is still fetched from the link the feed gave. Against
the shipped database, https links to gigazine.net, blog.livedoor.jp and
webcre8.jp reach their records again instead of missing.

Where a record did match but its XPath selected nothing -- a site redesigned
since the XPath was written -- the empty result was assigned anyway, so the
item lost the summary it arrived with and the feed went out with an empty
body. The summary is now kept, and the miss is logged at warn with the XPath
that missed.

Page encoding was read from a decoded string. `Automatic::Http.read` returns
what open-uri has already applied an encoding to whether or not the response
declared one -- a page served as `text/html` with no charset comes back tagged
UTF-8 because that is the fallback, not because the page said so -- and a
parser given that string believes the tag and never looks at the meta charset
underneath it, which is a whole article in mojibake for the many sites in this
database that declare their charset only in a meta tag. The page is now handed
to the parser as a stream, through `Automatic::Http.open`, so the parser
detects the encoding for itself. A record's own `enc` is the fallback for a
page that declares nothing anywhere; 1,186 records carry one, mostly EUC-JP and
Shift_JIS, and an `enc` naming an encoding Ruby does not have is ignored rather
than raised. The result is converted to UTF-8 with invalid bytes replaced as
well as undefined ones, because converting UTF-8 to UTF-8 leaves invalid bytes
alone unless they are named, and what leaves here goes on to a publish plugin
that cannot recover from a string it cannot encode.

Records are now compiled when the file is loaded rather than per item, which
was several thousand `Regexp.new` calls for every link in every feed, and a
record with no URL pattern, no XPath or a pattern that is not a regular
expression is dropped there -- an empty pattern matches every link, so such a
record would have put its own XPath over the whole feed.

The spec reached the network for the one case that mattered and pointed at a
host that has not served what it expected for years, so none of the above was
covered. Sixteen local examples cover it now: they write a siteinfo file into a
temporary HOME and stand in for open-uri, and each of the fixes fails at least
one of them when reverted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RSLxro7DeKVdunYdYMyjvY
@id774
id774 merged commit 7afefd3 into master Aug 15, 2026
8 checks passed
@id774
id774 deleted the claude/filterfullfeeds-bug-23av56 branch August 15, 2026 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants