fix(stalker): treat every reserved localhost name as portal-local

Codex P2 on #1364, the fourth in this class. RFC 6761 §6.3 reserves
`localhost` AND every name ending in `.localhost` for the loopback interface,
and resolvers honour it — so `http://stream.localhost/ch/1234_` reached the
player's own machine instead of being sent to the portal to resolve.

Closed the class rather than adding one more name: the suffix is matched, and
`localhost.localdomain` goes in with it as the conventional `/etc/hosts` alias
for 127.0.0.1 on most Linux systems. Together with the earlier rounds the
predicate now covers `localhost` and `*.localhost`, `localhost.localdomain`,
`127.0.0.0/8`, `0.0.0.0`, `::1`, `::`, the IPv4-mapped forms `URL` rewrites to
hex, and a terminal DNS root dot on any of them.

Only the suffix is reserved, so the guard must not over-match: tests pin that
`localhost.cdn.example` and `notlocalhost` remain ordinary routable names and
keep playing statically. Mutation-checked: dropping the suffix rule and the
localdomain alias fails four tests and nothing else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5 committed 2026-08-03 11:51:25 +02:00
1 parent 259be083c7
commit 6114c2d459
3 files changed
+51 -3

No files matched your search

+1 -1
View File
@@ -333,7 +333,7 @@ path, so they cannot regress a portal that works today:
| A row carrying neither flag KEY | `create_link` | Absence means "no evidence", not "no". A stock portal returns both flags on every row, so their PRESENCE is the provenance signal — and the only one available, because rows persisted into Favorites/Recently Viewed before this change were stripped of them by `buildStalkerSelectedVodItem`'s whitelist, making a legacy snapshot indistinguishable from a genuinely unflagged row. There is no migration for those. **Radio is the documented exception**: a directly playable radio command has always played as-is, so a flagless radio row keeps that rather than newly minting. |
| Relative `/media/file_12.mpg` or query-only `?token=…` | `create_link` | Only the portal turns those into an address; the VOD `has_files` rewrite produces exactly the first shape. |
| Non-HTTP scheme (`ffrt4://ch/live/…`) | `create_link` | Portal-internal pseudo-URL. |
| Portal-local host — `localhost`, all of `127.0.0.0/8`, `0.0.0.0`, `::1`, `::`, and the IPv4-mapped forms `URL` normalizes to hex (`::ffff:7f00:1`) | `create_link` | `ffrt3 http://localhost/ch/1234_` is an instruction to the portal, not an address a set-top box could open. |
| Portal-local host — `localhost` and any `*.localhost` name (RFC 6761 §6.3 reserves the whole suffix for loopback), `localhost.localdomain`, all of `127.0.0.0/8`, `0.0.0.0`, `::1`, `::`, and the IPv4-mapped forms `URL` normalizes to hex (`::ffff:7f00:1`); a terminal DNS root dot is stripped first | `create_link` | `ffrt3 http://localhost/ch/1234_` is an instruction to the portal, not an address a set-top box could open. |
| Otherwise | static `cmd` | Solution prefix stripped by `normalizeStalkerPlaybackCommand()`. |
`fetchStalkerPlaybackLink()` applies the verdict for ITV, VOD and radio, and