pimpbunny fix
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
use serde::Serialize;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use wreq::Client;
|
||||
use wreq::Proxy;
|
||||
use wreq::Response;
|
||||
use wreq::Uri;
|
||||
use wreq::Version;
|
||||
use wreq::cookie::{CookieStore, Cookies, Jar};
|
||||
use wreq::header::{HeaderMap, HeaderValue, USER_AGENT};
|
||||
use wreq::header::{HeaderMap, HeaderValue, SET_COOKIE, USER_AGENT};
|
||||
use wreq::multipart::Form;
|
||||
use wreq::redirect::Policy;
|
||||
use wreq_util::Emulation;
|
||||
@@ -45,6 +45,79 @@ impl fmt::Debug for Requester {
|
||||
}
|
||||
|
||||
impl Requester {
|
||||
fn shared_cookie_jar() -> Arc<Jar> {
|
||||
static SHARED_COOKIE_JAR: OnceLock<Arc<Jar>> = OnceLock::new();
|
||||
SHARED_COOKIE_JAR
|
||||
.get_or_init(|| Arc::new(Jar::default()))
|
||||
.clone()
|
||||
}
|
||||
|
||||
fn origin_url_for_cookie_scope(url: &str) -> Option<url::Url> {
|
||||
let parsed = url::Url::parse(url).ok()?;
|
||||
let host = parsed.host_str()?;
|
||||
let scheme = parsed.scheme();
|
||||
url::Url::parse(&format!("{scheme}://{host}/")).ok()
|
||||
}
|
||||
|
||||
fn store_response_cookies(&self, url: &str, response: &Response) {
|
||||
let Some(origin) = Self::origin_url_for_cookie_scope(url) else {
|
||||
return;
|
||||
};
|
||||
|
||||
for value in response.headers().get_all(SET_COOKIE).iter() {
|
||||
if let Ok(cookie) = value.to_str() {
|
||||
self.cookie_jar.add_cookie_str(cookie, &origin.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn store_flaresolverr_cookies(
|
||||
&mut self,
|
||||
request_url: &str,
|
||||
cookies: &[crate::util::flaresolverr::FlaresolverrCookie],
|
||||
) {
|
||||
let fallback_origin = Self::origin_url_for_cookie_scope(request_url);
|
||||
|
||||
for cookie in cookies {
|
||||
let origin = if !cookie.domain.is_empty() {
|
||||
let scheme = fallback_origin
|
||||
.as_ref()
|
||||
.map(|url| url.scheme())
|
||||
.unwrap_or("https");
|
||||
let host = cookie.domain.trim_start_matches('.');
|
||||
url::Url::parse(&format!("{scheme}://{host}/"))
|
||||
.ok()
|
||||
.or_else(|| fallback_origin.clone())
|
||||
} else {
|
||||
fallback_origin.clone()
|
||||
};
|
||||
|
||||
let Some(origin) = origin else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut cookie_string =
|
||||
format!("{}={}; Path={}", cookie.name, cookie.value, cookie.path);
|
||||
if !cookie.domain.is_empty() {
|
||||
cookie_string.push_str(&format!("; Domain={}", cookie.domain));
|
||||
}
|
||||
if cookie.secure {
|
||||
cookie_string.push_str("; Secure");
|
||||
}
|
||||
if cookie.httpOnly {
|
||||
cookie_string.push_str("; HttpOnly");
|
||||
}
|
||||
if let Some(same_site) = cookie.sameSite.as_deref() {
|
||||
if !same_site.is_empty() {
|
||||
cookie_string.push_str(&format!("; SameSite={same_site}"));
|
||||
}
|
||||
}
|
||||
|
||||
self.cookie_jar
|
||||
.add_cookie_str(&cookie_string, &origin.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_cookie_preview_from_owned_headers(
|
||||
&self,
|
||||
url: &str,
|
||||
@@ -62,6 +135,7 @@ impl Requester {
|
||||
.unwrap_or_else(|| "none".to_string())
|
||||
}
|
||||
|
||||
#[cfg(any(not(hottub_single_provider), hottub_provider = "hypnotube"))]
|
||||
fn debug_cookie_preview_from_borrowed_headers(
|
||||
&self,
|
||||
url: &str,
|
||||
@@ -98,7 +172,7 @@ impl Requester {
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
let cookie_jar = Arc::new(Jar::default());
|
||||
let cookie_jar = Self::shared_cookie_jar();
|
||||
let client = Self::build_client(cookie_jar.clone(), None);
|
||||
|
||||
let requester = Requester {
|
||||
@@ -122,14 +196,11 @@ impl Requester {
|
||||
self.proxy = proxy;
|
||||
}
|
||||
|
||||
pub fn proxy_enabled(&self) -> bool {
|
||||
self.proxy
|
||||
}
|
||||
|
||||
pub fn set_debug_trace_id(&mut self, debug_trace_id: Option<String>) {
|
||||
self.debug_trace_id = debug_trace_id;
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
pub fn debug_trace_id(&self) -> Option<&str> {
|
||||
self.debug_trace_id.as_deref()
|
||||
}
|
||||
@@ -176,7 +247,9 @@ impl Requester {
|
||||
}
|
||||
}
|
||||
|
||||
request.send().await
|
||||
let response = request.send().await?;
|
||||
self.store_response_cookies(url, &response);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn get_raw_with_headers(
|
||||
@@ -209,7 +282,9 @@ impl Requester {
|
||||
for (key, value) in headers.iter() {
|
||||
request = request.header(key, value);
|
||||
}
|
||||
request.send().await
|
||||
let response = request.send().await?;
|
||||
self.store_response_cookies(url, &response);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn post_json<S>(
|
||||
@@ -246,9 +321,12 @@ impl Requester {
|
||||
}
|
||||
}
|
||||
|
||||
request.send().await
|
||||
let response = request.send().await?;
|
||||
self.store_response_cookies(url, &response);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
#[cfg(any(not(hottub_single_provider), hottub_provider = "hypnotube"))]
|
||||
pub async fn post(
|
||||
&mut self,
|
||||
url: &str,
|
||||
@@ -285,7 +363,9 @@ impl Requester {
|
||||
}
|
||||
}
|
||||
|
||||
request.send().await
|
||||
let response = request.send().await?;
|
||||
self.store_response_cookies(url, &response);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn post_multipart(
|
||||
@@ -325,7 +405,9 @@ impl Requester {
|
||||
}
|
||||
}
|
||||
|
||||
request.send().await
|
||||
let response = request.send().await?;
|
||||
self.store_response_cookies(url, &response);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
@@ -370,6 +452,7 @@ impl Requester {
|
||||
}
|
||||
}
|
||||
let response = request.send().await?;
|
||||
self.store_response_cookies(url, &response);
|
||||
crate::flow_debug!(
|
||||
"trace={} requester direct response url={} status={}",
|
||||
self.debug_trace_id().unwrap_or("none"),
|
||||
@@ -424,17 +507,9 @@ impl Requester {
|
||||
.map_err(|e| -> AnyErr { format!("Failed to solve FlareSolverr: {e}").into() })?;
|
||||
|
||||
// Rebuild client and apply UA/cookies from FlareSolverr
|
||||
let cookie_origin = url.split('/').take(3).collect::<Vec<&str>>().join("/");
|
||||
|
||||
let useragent = res.solution.userAgent;
|
||||
self.user_agent = Some(useragent);
|
||||
|
||||
if url::Url::parse(&cookie_origin).is_ok() {
|
||||
for cookie in res.solution.cookies {
|
||||
self.cookie_jar
|
||||
.add_cookie_str(&format!("{}={}", cookie.name, cookie.value), &cookie_origin);
|
||||
}
|
||||
}
|
||||
self.store_flaresolverr_cookies(url, &res.solution.cookies);
|
||||
|
||||
self.client = Self::build_client(self.cookie_jar.clone(), self.user_agent.as_deref());
|
||||
crate::flow_debug!(
|
||||
@@ -457,6 +532,7 @@ impl Requester {
|
||||
}
|
||||
|
||||
let response = request.send().await?;
|
||||
self.store_response_cookies(url, &response);
|
||||
crate::flow_debug!(
|
||||
"trace={} requester retry response url={} status={}",
|
||||
self.debug_trace_id().unwrap_or("none"),
|
||||
@@ -476,3 +552,26 @@ impl Requester {
|
||||
Ok(res.solution.response)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Requester;
|
||||
|
||||
#[test]
|
||||
fn new_requesters_share_cookie_jar() {
|
||||
let a = Requester::new();
|
||||
let b = Requester::new();
|
||||
let origin = "https://shared-cookie-requester-test.invalid/";
|
||||
|
||||
a.cookie_jar.add_cookie_str(
|
||||
"shared_cookie=1; Path=/; SameSite=Lax",
|
||||
origin,
|
||||
);
|
||||
|
||||
let cookie_header = b
|
||||
.cookie_header_for_url("https://shared-cookie-requester-test.invalid/path")
|
||||
.unwrap_or_default();
|
||||
|
||||
assert!(cookie_header.contains("shared_cookie=1"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user