mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-18 05:44:35 +03:00
fix: split YouTube domains in youtube_via_relay (#275)
Pre-#275, youtube_via_relay=true routed every YouTube-related host through Apps Script — including ytimg.com (thumbnails) and any googlevideo.com chunk request the player issued. Two problems: 1. ytimg.com via Apps Script is wasted quota — image CDN, no Restricted Mode logic to bypass. 2. googlevideo.com wasn't even in SNI_REWRITE_SUFFIXES, so video chunks hit the relay regardless of the flag. A single chunk timeout aborted the whole video on Firefox; long videos risked the Apps Script 6-min execution cap mid-playback. Fix: split YouTube into "API/HTML hosts" (where Restricted Mode lives, gated by the flag) and "asset CDNs" (always direct). The new YOUTUBE_RELAY_HOSTS list is youtube.com, youtu.be, youtube-nocookie.com, youtubei.googleapis.com — those go through relay when the flag is on. ytimg.com, googlevideo.com (added), ggpht.com all stay on SNI rewrite. The matches_sni_rewrite logic was also restructured: the carve-out now runs FIRST before the SNI suffix match, so the broad googleapis.com entry can't override the narrower youtubei.googleapis.com decision. Reported with detailed analysis by @amirabbas117. Will ship in v1.7.4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+114
-28
@@ -47,6 +47,18 @@ const SNI_REWRITE_SUFFIXES: &[&str] = &[
|
||||
"youtu.be",
|
||||
"youtube-nocookie.com",
|
||||
"ytimg.com",
|
||||
// YouTube video CDN. Issue #275: a user reported that with
|
||||
// `youtube_via_relay = true`, every video chunk was traversing the
|
||||
// Apps Script relay and a single chunk timeout aborted playback —
|
||||
// because `googlevideo.com` was not on this list, all chunks
|
||||
// fell through to the relay path. Adding it here keeps video
|
||||
// bytes on the direct GFE tunnel even when the relay flag is on
|
||||
// (the YOUTUBE_RELAY_HOSTS carve-out below excludes only the API
|
||||
// / HTML surfaces, not the CDN). The chunks are unauthenticated
|
||||
// bytes anyway — there's no Restricted Mode logic on the CDN, so
|
||||
// routing them through Apps Script gains nothing and costs the
|
||||
// 6-minute Apps Script execution cap on long videos.
|
||||
"googlevideo.com",
|
||||
// Google Video Transport CDN — YouTube video chunks, Chrome
|
||||
// auto-updates, Google Play Store downloads. The single biggest
|
||||
// gap vs the upstream Python port: without these in the list
|
||||
@@ -72,27 +84,62 @@ const SNI_REWRITE_SUFFIXES: &[&str] = &[
|
||||
"blogger.com",
|
||||
];
|
||||
|
||||
/// YouTube-family suffixes. Extracted so `youtube_via_relay` config can
|
||||
/// pull them out of the SNI-rewrite dispatch at runtime.
|
||||
const YOUTUBE_SNI_SUFFIXES: &[&str] = &[
|
||||
/// YouTube hosts that should be routed through the Apps Script relay
|
||||
/// when `youtube_via_relay` is enabled — the API + HTML surfaces where
|
||||
/// Restricted Mode is actually enforced (via the SNI=www.google.com
|
||||
/// edge looking at the request). Issue #102 / #275.
|
||||
///
|
||||
/// Deliberately narrower than the YouTube section of
|
||||
/// `SNI_REWRITE_SUFFIXES`:
|
||||
/// - `youtube.com` / `youtu.be` / `youtube-nocookie.com`: HTML pages
|
||||
/// and player frames. These trigger Restricted Mode if served via
|
||||
/// the SNI rewrite, so when the flag is on we relay them.
|
||||
/// - `youtubei.googleapis.com`: the YouTube data API the player
|
||||
/// queries for video metadata + manifest. Restricted Mode also
|
||||
/// gates video availability here. Without this entry, the JSON
|
||||
/// RPC layer would still hit the SNI-rewrite tunnel via the
|
||||
/// broader `googleapis.com` suffix — the user-visible symptom of
|
||||
/// that miss is "youtube_via_relay flips on but Restricted Mode
|
||||
/// stays sticky on some videos."
|
||||
///
|
||||
/// **NOT** in this list (intentional, was a regression in #275):
|
||||
/// - `ytimg.com`: thumbnails. No Restricted Mode logic on a static
|
||||
/// image CDN; routing through Apps Script makes thumbnails slow
|
||||
/// for zero gain.
|
||||
/// - `googlevideo.com`: video chunk CDN. Routing through Apps Script
|
||||
/// means every chunk eats Apps Script quota *and* risks the 6-min
|
||||
/// execution cap aborting long videos mid-playback.
|
||||
/// - `ggpht.com`: channel/profile images, same reasoning as ytimg.
|
||||
const YOUTUBE_RELAY_HOSTS: &[&str] = &[
|
||||
"youtube.com",
|
||||
"youtu.be",
|
||||
"youtube-nocookie.com",
|
||||
"ytimg.com",
|
||||
"youtubei.googleapis.com",
|
||||
];
|
||||
|
||||
fn matches_sni_rewrite(host: &str, youtube_via_relay: bool) -> bool {
|
||||
let h = host.to_ascii_lowercase();
|
||||
let h = h.trim_end_matches('.');
|
||||
|
||||
// YouTube relay carve-out runs FIRST so it wins over the broad
|
||||
// `googleapis.com` suffix that would otherwise pull
|
||||
// `youtubei.googleapis.com` into the SNI-rewrite path. The earlier
|
||||
// implementation iterated SNI_REWRITE_SUFFIXES with a filter, which
|
||||
// works for sibling entries (e.g. `youtube.com` in both lists) but
|
||||
// not for nested ones (`youtubei.googleapis.com` matches the broad
|
||||
// `googleapis.com` even when its specific entry is filtered out).
|
||||
// The short-circuit here is unconditional — we don't need to check
|
||||
// SNI rewrite once we've decided this host goes to the relay.
|
||||
if youtube_via_relay {
|
||||
for s in YOUTUBE_RELAY_HOSTS {
|
||||
if h == *s || h.ends_with(&format!(".{}", s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SNI_REWRITE_SUFFIXES
|
||||
.iter()
|
||||
.filter(|s| {
|
||||
// If the user opted into youtube_via_relay, skip YouTube
|
||||
// suffixes so they fall through to the Apps Script relay
|
||||
// path. See config.rs `youtube_via_relay` docs for the
|
||||
// trade-off. Issue #102.
|
||||
!(youtube_via_relay && YOUTUBE_SNI_SUFFIXES.contains(s))
|
||||
})
|
||||
.any(|s| h == *s || h.ends_with(&format!(".{}", s)))
|
||||
}
|
||||
|
||||
@@ -2587,36 +2634,75 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn youtube_via_relay_routes_youtube_through_relay_path() {
|
||||
// Issue #102. When youtube_via_relay=true, YouTube suffixes
|
||||
// must NOT match the SNI-rewrite path, so traffic falls
|
||||
// through to Apps Script relay. Other Google suffixes are
|
||||
// unaffected.
|
||||
// Issue #102 + #275. When youtube_via_relay=true:
|
||||
// - YouTube API + HTML hosts (where Restricted Mode lives)
|
||||
// opt out of SNI rewrite so they go through the relay.
|
||||
// - YouTube image / video / channel-asset CDNs STAY on SNI
|
||||
// rewrite — Restricted Mode isn't enforced on those, and
|
||||
// routing video chunks through Apps Script burns quota
|
||||
// and risks the 6-min execution cap. Pre-#275 ytimg.com
|
||||
// was incorrectly carved out alongside the API surfaces.
|
||||
// - Non-YouTube Google suffixes are unaffected by the flag.
|
||||
let hosts = std::collections::HashMap::new();
|
||||
|
||||
// Default behaviour: everything in the pool rewrites.
|
||||
assert!(should_use_sni_rewrite(
|
||||
&hosts,
|
||||
"www.youtube.com",
|
||||
443,
|
||||
false
|
||||
));
|
||||
// Default behaviour (flag off): everything in the SNI pool
|
||||
// rewrites including all YouTube assets.
|
||||
assert!(should_use_sni_rewrite(&hosts, "www.youtube.com", 443, false));
|
||||
assert!(should_use_sni_rewrite(&hosts, "i.ytimg.com", 443, false));
|
||||
assert!(should_use_sni_rewrite(&hosts, "youtu.be", 443, false));
|
||||
assert!(should_use_sni_rewrite(&hosts, "www.google.com", 443, false));
|
||||
assert!(should_use_sni_rewrite(
|
||||
&hosts,
|
||||
"rr1---sn-abc.googlevideo.com",
|
||||
443,
|
||||
false
|
||||
));
|
||||
assert!(should_use_sni_rewrite(
|
||||
&hosts,
|
||||
"youtubei.googleapis.com",
|
||||
443,
|
||||
false
|
||||
));
|
||||
|
||||
// With the toggle on: YouTube opts out, Google stays.
|
||||
// Flag on: only the API + HTML hosts opt out.
|
||||
assert!(!should_use_sni_rewrite(&hosts, "www.youtube.com", 443, true));
|
||||
assert!(!should_use_sni_rewrite(&hosts, "youtu.be", 443, true));
|
||||
assert!(!should_use_sni_rewrite(
|
||||
&hosts,
|
||||
"www.youtube.com",
|
||||
"www.youtube-nocookie.com",
|
||||
443,
|
||||
true
|
||||
));
|
||||
assert!(!should_use_sni_rewrite(&hosts, "i.ytimg.com", 443, true));
|
||||
assert!(!should_use_sni_rewrite(&hosts, "youtu.be", 443, true));
|
||||
assert!(should_use_sni_rewrite(&hosts, "www.google.com", 443, true));
|
||||
assert!(!should_use_sni_rewrite(
|
||||
&hosts,
|
||||
"youtubei.googleapis.com",
|
||||
443,
|
||||
true
|
||||
));
|
||||
|
||||
// Flag on: video / image / channel-asset CDNs STAY on SNI
|
||||
// rewrite. The pre-#275 implementation broke playback by
|
||||
// routing googlevideo.com through Apps Script (it wasn't even
|
||||
// in the SNI list before #275, so it always went via relay)
|
||||
// and routed ytimg.com through the relay too.
|
||||
assert!(should_use_sni_rewrite(&hosts, "i.ytimg.com", 443, true));
|
||||
assert!(should_use_sni_rewrite(
|
||||
&hosts,
|
||||
"fonts.gstatic.com",
|
||||
"rr1---sn-abc.googlevideo.com",
|
||||
443,
|
||||
true
|
||||
));
|
||||
assert!(should_use_sni_rewrite(&hosts, "yt3.ggpht.com", 443, true));
|
||||
|
||||
// Flag on: non-YouTube Google suffixes are unaffected. Note
|
||||
// youtubei.googleapis.com (above) is the *carve-out* — the
|
||||
// broader googleapis.com suffix is NOT carved out, so e.g.
|
||||
// Drive / Calendar / etc. continue to SNI-rewrite.
|
||||
assert!(should_use_sni_rewrite(&hosts, "www.google.com", 443, true));
|
||||
assert!(should_use_sni_rewrite(&hosts, "fonts.gstatic.com", 443, true));
|
||||
assert!(should_use_sni_rewrite(
|
||||
&hosts,
|
||||
"drive.googleapis.com",
|
||||
443,
|
||||
true
|
||||
));
|
||||
|
||||
Reference in New Issue
Block a user