reliability+safety: nsig shape fixes, bounded self-heal, no url/id leaks, revived JS tests
Some checks failed
gitleaks / scan (push) Failing after 2s

- nsig name resolution: route direct-vs-array on capture-group PARTICIPATION,
  not declared-group count (regexes 6/7 carry an optional array group) — a
  direct-call player.js shape no longer hard-fails NsigArrayLookupFailed.
- nsig fixup_function: also strip the `if(typeof X==="undefined")return a;`
  guard on the `function name(a){...}` body shape (previously required a
  leading `;`), so the regex-fallback shape no longer silently yields an
  identity result that gets cached as a permanent throttle.
- player_manager: never hold the state lock across the network; serialize
  player.js downloads behind a fetch gate; add a per-artifact failure memo
  (5-min cooldown) so a persistently-broken player.js costs one refetch per
  open instead of a ~20-25 x 1.7MB storm. Transient-rotation self-heal
  preserved (eval failure -> invalidate + refetch, no memo).
- errors no longer leak watch URLs / video ids: From<reqwest::Error> uses
  without_url(); Recaptcha + link errors reduce to scheme+host (paths like
  /embed/<id> and /shorts/<id> carried the id in the path).
- revive tests/ after the strawcore-core rename; js_phase2_offline green.
  133 lib + 7 integration tests, clippy -D clean.
This commit is contained in:
Cobb 2026-07-28 22:31:20 -07:00
parent 50fd74c874
commit 988e67414d
13 changed files with 907 additions and 140 deletions

View file

@ -9,16 +9,22 @@
use std::sync::Arc;
use strawcore::downloader::request::Request;
use strawcore::downloader::ReqwestDownloader;
use strawcore::exceptions::NetworkError;
use strawcore::localization::{ContentCountry, Localization};
use strawcore::{Downloader, NewPipe};
use strawcore_core::downloader::request::Request;
use strawcore_core::downloader::ReqwestDownloader;
use strawcore_core::exceptions::NetworkError;
use strawcore_core::localization::{ContentCountry, Localization};
use strawcore_core::{Downloader, NewPipe};
/// The Downloader trait dropped its `get` convenience (commit f917e4a);
/// mirror it here so the suite reads as before.
fn get(dl: &impl Downloader, url: &str) -> Result<strawcore_core::Response, NetworkError> {
dl.execute(Request::get(url).build())
}
#[test]
fn get_through_default_downloader() {
let dl = ReqwestDownloader::new().expect("build downloader");
let resp = dl.get("https://httpbin.org/get").expect("transport");
let resp = get(&dl, "https://httpbin.org/get").expect("transport");
assert_eq!(resp.response_code(), 200);
assert!(resp.response_body().contains("\"url\""));
}
@ -26,9 +32,7 @@ fn get_through_default_downloader() {
#[test]
fn latest_url_follows_redirects() {
let dl = ReqwestDownloader::new().expect("build downloader");
let resp = dl
.get("https://httpbin.org/redirect/3")
.expect("transport");
let resp = get(&dl, "https://httpbin.org/redirect/3").expect("transport");
assert_eq!(resp.response_code(), 200);
assert!(
resp.latest_url().ends_with("/get"),
@ -40,14 +44,14 @@ fn latest_url_follows_redirects() {
#[test]
fn non_2xx_returns_ok_not_err() {
let dl = ReqwestDownloader::new().expect("build downloader");
let resp = dl.get("https://httpbin.org/status/404").expect("transport");
let resp = get(&dl, "https://httpbin.org/status/404").expect("transport");
assert_eq!(resp.response_code(), 404);
}
#[test]
fn http_429_surfaces_as_recaptcha_err() {
let dl = ReqwestDownloader::new().expect("build downloader");
let err = dl.get("https://httpbin.org/status/429").expect_err("429 must be NetworkError");
let err = get(&dl, "https://httpbin.org/status/429").expect_err("429 must be NetworkError");
match err {
NetworkError::Recaptcha { url } => assert!(url.contains("/status/429")),
other => panic!("expected Recaptcha, got {other:?}"),
@ -72,8 +76,8 @@ fn localization_header_attached_when_enabled() {
#[test]
fn header_keys_lowercased_in_response() {
let dl = ReqwestDownloader::new().expect("build downloader");
let resp = dl.get("https://httpbin.org/get").expect("transport");
for (k, _) in resp.response_headers() {
let resp = get(&dl, "https://httpbin.org/get").expect("transport");
for k in resp.response_headers().keys() {
assert_eq!(k, &k.to_ascii_lowercase(), "header key {k} not lowercased");
}
}
@ -88,7 +92,9 @@ fn newpipe_singleton_wires_downloader() {
);
let from_global = NewPipe::downloader().expect("downloader registered");
let resp = from_global.get("https://httpbin.org/get").expect("transport");
let resp = from_global
.execute(Request::get("https://httpbin.org/get").build())
.expect("transport");
assert_eq!(resp.response_code(), 200);
assert_eq!(NewPipe::preferred_localization().localization_code(), "en-GB");
}

View file

@ -14,7 +14,7 @@
// * url_with_throttling_parameter_deobfuscated round-trip changes &n=
// and caches the result
use strawcore::youtube::js::{signature, nsig, runtime, DeobfError};
use strawcore_core::youtube::js::{signature, nsig, runtime, DeobfError};
// Synthetic minified player.js — replicates the shape of real YT player.js.
//