From 947f67834ab8aff171f7e5406f2853329c24e51c Mon Sep 17 00:00:00 2001 From: Kayos Date: Sun, 24 May 2026 11:56:41 -0700 Subject: [PATCH] =?UTF-8?q?tests:=20smoke=20=E2=80=94=20switch=20HEAD=20to?= =?UTF-8?q?=20Range=20GET=20+=20iOS=20UA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit YouTube googlevideo CDN 403s HEAD requests + 403s requests with a non-client User-Agent. Use the iOS client UA on the probe so the CDN treats it as the same client that requested the URL. --- tests/sulkta_smoke.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/sulkta_smoke.rs b/tests/sulkta_smoke.rs index 2b2f0f0..7381c0b 100644 --- a/tests/sulkta_smoke.rs +++ b/tests/sulkta_smoke.rs @@ -89,7 +89,9 @@ async fn default_client_order_returns_streams(rp: RustyPipe) { "expected at least one audio stream from the default-clients path" ); - // HEAD-probe one returned audio stream to confirm YT actually serves it. + // Probe one returned audio stream to confirm YT actually serves it. + // GET with Range 0-1023 + an iOS User-Agent because YT's googlevideo + // CDN tends to 403 HEAD requests and UA mismatches. let stream_url = pd .audio_streams .first() @@ -98,17 +100,28 @@ async fn default_client_order_returns_streams(rp: RustyPipe) { .clone(); eprintln!("probing first audio URL: {}", &stream_url[..stream_url.len().min(180)]); let client = reqwest::Client::builder() - .user_agent("Mozilla/5.0 sulkta-rustypipe-smoke/1.0") + .user_agent( + "com.google.ios.youtube/19.45.4 (iPhone16,2; U; CPU iOS 18_1 like Mac OS X; en_US)", + ) .build() .unwrap(); let resp = client - .head(&stream_url) + .get(&stream_url) + .header("Range", "bytes=0-1023") .send() .await - .expect("HEAD request to YT CDN should not error"); + .expect("GET request to YT CDN should not error"); + let status = resp.status(); + let body_len = resp.bytes().await.map(|b| b.len()).unwrap_or(0); + eprintln!("response: {} bytes, status {}", body_len, status); assert!( - resp.status().is_success() || resp.status().is_redirection(), - "audio URL HEAD returned non-OK status: {} (sig deobf likely needed but skipped)", - resp.status() + status.is_success() || status.is_redirection(), + "audio URL Range-GET returned non-OK status: {} (body={} bytes; URL may need visitor_data or po_token)", + status, + body_len + ); + assert!( + body_len > 0, + "audio URL returned OK but zero bytes — likely a sig-required URL we couldn't deobf" ); }