From 9caa5f7c01d7a7eebbad8894a274c338d6a4bdbc Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 26 Jun 2026 20:43:56 +0000 Subject: [PATCH] fix jable: FlaresolverrCookie missing fields + requester transport-error fallback Three bugs prevented jable.tv from returning items: 1. FlaresolverrCookie deserialization (root cause): fields like `expires`, `size`, `priority`, `sameParty`, `sourceScheme`, `sourcePort` are omitted by FlareSolverr for session cookies, causing serde to fail with "missing field" and the entire solve to return Err. Added #[serde(default)] to all non-essential cookie fields. 2. Transport-error branch in get_with_headers: when direct fetch fails with a transport error and Jina returns a CF challenge body, the old code returned Ok(challenge_html) instead of falling through to FlareSolverr. Now checks looks_like_cloudflare_challenge and breaks to FS. 3. Post-FlareSolverr retry: wreq's Firefox136 TLS fingerprint causes CF to drop the connection even with FS cookies applied, so request.send() returns Err. Was propagated with `?`; now catches and returns res.solution.response (the headless-browser body) directly. Co-Authored-By: Claude Sonnet 4.6 --- src/util/flaresolverr.rs | 9 +++++++++ src/util/requester.rs | 31 +++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/util/flaresolverr.rs b/src/util/flaresolverr.rs index 70d352e..dcc3e7a 100644 --- a/src/util/flaresolverr.rs +++ b/src/util/flaresolverr.rs @@ -19,15 +19,24 @@ pub struct FlaresolverrCookie { pub value: String, pub domain: String, pub path: String, + #[serde(default)] pub expires: f64, + #[serde(default)] pub size: u64, + #[serde(default)] pub httpOnly: bool, + #[serde(default)] pub secure: bool, + #[serde(default)] pub session: bool, pub sameSite: Option, + #[serde(default)] pub priority: String, + #[serde(default)] pub sameParty: bool, + #[serde(default)] pub sourceScheme: String, + #[serde(default)] pub sourcePort: u32, pub partitionKey: Option, } diff --git a/src/util/requester.rs b/src/util/requester.rs index 36131a7..1bc0e36 100644 --- a/src/util/requester.rs +++ b/src/util/requester.rs @@ -535,15 +535,25 @@ impl Requester { } let response = match request.send().await { Ok(response) => response, - Err(error) => { + Err(_error) => { crate::flow_debug!( "trace={} requester direct transport failed url={} error={} using_jina_fallback=true", _trace_id, crate::util::flow_debug::preview(url, 120), - crate::util::flow_debug::preview(&error.to_string(), 160) + crate::util::flow_debug::preview(&_error.to_string(), 160) ); match jina_handle.await { - Ok(Ok(body)) => return Ok(body), + Ok(Ok(body)) => { + if Self::looks_like_cloudflare_challenge(&body) { + crate::flow_debug!( + "trace={} requester jina fallback returned cloudflare challenge after transport error url={} using_flaresolverr=true", + _trace_id, + crate::util::flow_debug::preview(url, 120) + ); + } else { + return Ok(body); + } + } Ok(Err(_jina_error)) => { crate::flow_debug!( "trace={} requester jina fallback failed after transport error url={} error={}", @@ -551,7 +561,6 @@ impl Requester { crate::util::flow_debug::preview(url, 120), crate::util::flow_debug::preview(&_jina_error.to_string(), 160) ); - return Err(error.into()); } Err(_join_error) => { crate::flow_debug!( @@ -560,9 +569,9 @@ impl Requester { crate::util::flow_debug::preview(url, 120), crate::util::flow_debug::preview(&_join_error.to_string(), 160) ); - return Err(error.into()); } } + break; } }; self.store_response_cookies(url, &response); @@ -714,7 +723,17 @@ impl Requester { } } - let response = request.send().await?; + let response = match request.send().await { + Ok(r) => r, + Err(_retry_err) => { + crate::flow_debug!( + "trace={} requester post-flaresolverr retry transport failed url={} using_flaresolverr_body=true", + self.debug_trace_id().unwrap_or("none"), + crate::util::flow_debug::preview(url, 120) + ); + return Ok(res.solution.response); + } + }; self.store_response_cookies(url, &response); crate::flow_debug!( "trace={} requester retry response url={} status={}",