From 31902935100eb72ff4cce209b4774cdc61fe50be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jind=C5=99ich=20B=C3=A4r?= Date: Tue, 2 Sep 2025 12:50:14 +0200 Subject: [PATCH 1/2] chore: remove unnecessary `.unwrap()` calls --- impit-node/src/request.rs | 20 ++++++---- impit-node/src/response.rs | 8 +++- impit-python/src/async_client.rs | 2 +- impit-python/src/client.rs | 4 +- impit-python/src/cookies.rs | 57 ++++++++++++++-------------- impit/src/impit.rs | 64 ++++++++++++++++++-------------- 6 files changed, 87 insertions(+), 68 deletions(-) diff --git a/impit-node/src/request.rs b/impit-node/src/request.rs index e451fcf6..de7cbbd5 100644 --- a/impit-node/src/request.rs +++ b/impit-node/src/request.rs @@ -58,9 +58,17 @@ fn await_promise< scope.spawn(move || match tokio::runtime::Runtime::new() { Ok(runtime) => { runtime.block_on(async { - let result = tsfn.call_async(args).await.unwrap().await; - - let _ = tx.send(result); + match tsfn.call_async(args).await { + Ok(result) => { + let _ = tx.send(result.await); + } + Err(e) => { + let _ = tx.send(Err(napi::Error::new( + napi::Status::GenericFailure, + format!("[impit] failed to retrieve cookies from the external cookie store: {e}"), + ))); + } + } }); } Err(e) => { @@ -158,13 +166,11 @@ impl NodeCookieJar { let mut set_cookie = set_cookie_js_method .build_threadsafe_function::<(std::string::String, std::string::String)>() - .build_callback(|ctx| Ok(ctx.value)) - .unwrap(); + .build_callback(|ctx| Ok(ctx.value))?; let mut get_cookies = get_cookie_js_method .build_threadsafe_function::() - .build_callback(|ctx| Ok(ctx.value)) - .unwrap(); + .build_callback(|ctx| Ok(ctx.value))?; // Unless the `ThreadsafeFunction` is unreferenced, the Node.JS application will hang on exit // https://nodejs.github.io/node-addon-examples/special-topics/thread-safe-functions/#q-my-application-isnt-exiting-correctly-it-just-hangs diff --git a/impit-node/src/response.rs b/impit-node/src/response.rs index 4fbf718f..739e1b4e 100644 --- a/impit-node/src/response.rs +++ b/impit-node/src/response.rs @@ -119,7 +119,13 @@ impl<'env> ImpitResponse { )?; } - Ok(this.get(INNER_RESPONSE_PROPERTY_NAME)?.unwrap()) + this.get(INNER_RESPONSE_PROPERTY_NAME).transpose() + .ok_or_else(|| { + napi::Error::new( + napi::Status::GenericFailure, + "fatal: Couldn't get cached response stream".to_string(), + ) + })? } #[napi(ts_return_type = "string")] diff --git a/impit-python/src/async_client.rs b/impit-python/src/async_client.rs index 090ee4b3..e41215ab 100644 --- a/impit-python/src/async_client.rs +++ b/impit-python/src/async_client.rs @@ -107,7 +107,7 @@ impl AsyncClient { builder.with_cookie_store(PythonCookieJar::new(py, cookie_jar.into())) } (None, Some(cookies)) => { - builder.with_cookie_store(PythonCookieJar::from_httpx_cookies(py, cookies.into())) + builder.with_cookie_store(PythonCookieJar::from_httpx_cookies(py, cookies.into())?) } (None, None) => builder, }; diff --git a/impit-python/src/client.rs b/impit-python/src/client.rs index c3c17095..bb88a3ca 100644 --- a/impit-python/src/client.rs +++ b/impit-python/src/client.rs @@ -10,7 +10,7 @@ use pyo3::{ffi::c_str, prelude::*}; use crate::{ cookies::PythonCookieJar, - errors::ImpitPyError, + errors::{CookieConflict, ImpitPyError}, request::{form_to_bytes, RequestBody}, response::{self, ImpitPyResponse}, }; @@ -103,7 +103,7 @@ impl Client { builder.with_cookie_store(PythonCookieJar::new(py, cookie_jar.into())) } (None, Some(cookies)) => { - builder.with_cookie_store(PythonCookieJar::from_httpx_cookies(py, cookies.into())) + builder.with_cookie_store(PythonCookieJar::from_httpx_cookies(py, cookies.into()).map_err(|e| ImpitPyError(ImpitError::CookieConflict))?) } (None, None) => builder, }; diff --git a/impit-python/src/cookies.rs b/impit-python/src/cookies.rs index ff5853a8..e17e3e04 100644 --- a/impit-python/src/cookies.rs +++ b/impit-python/src/cookies.rs @@ -23,18 +23,18 @@ impl CookieStore for PythonCookieJar { let cookie = std::str::from_utf8(header_value.as_bytes()) .map_err(cookie::ParseError::from) .and_then(Cookie::parse) - .unwrap(); + .unwrap_or(Cookie::new("", "")); let kwargs = PyDict::new(py); - kwargs.set_item("name", cookie.name()).unwrap(); - kwargs.set_item("value", cookie.value()).unwrap(); + kwargs.set_item("name", cookie.name()).unwrap_or_default(); + kwargs.set_item("value", cookie.value()).unwrap_or_default(); kwargs .set_item("path", cookie.path().unwrap_or("")) - .unwrap(); + .unwrap_or_default(); kwargs .set_item("secure", cookie.secure().unwrap_or(false)) - .unwrap(); + .unwrap_or_default(); kwargs .set_item( "domain", @@ -42,40 +42,40 @@ impl CookieStore for PythonCookieJar { .domain() .unwrap_or_else(|| url.host_str().unwrap_or_default()), ) - .unwrap(); - kwargs.set_item("comment", None::<&str>).unwrap(); - kwargs.set_item("comment_url", None::<&str>).unwrap(); - kwargs.set_item("port", None::<&str>).unwrap(); - kwargs.set_item("port_specified", false).unwrap(); + .unwrap_or_default(); + kwargs.set_item("comment", None::<&str>).unwrap_or_default(); + kwargs.set_item("comment_url", None::<&str>).unwrap_or_default(); + kwargs.set_item("port", None::<&str>).unwrap_or_default(); + kwargs.set_item("port_specified", false).unwrap_or_default(); kwargs .set_item("path_specified", cookie.path().is_some()) - .unwrap(); + .unwrap_or_default(); kwargs .set_item( "discard", cookie.max_age().is_none() && cookie.expires().is_none(), ) - .unwrap(); + .unwrap_or_default(); kwargs .set_item("domain_specified", cookie.domain().is_some()) - .unwrap(); + .unwrap_or_default(); kwargs .set_item( "domain_initial_dot", cookie.domain().map(|d| d.starts_with('.')), ) - .unwrap(); + .unwrap_or_default(); kwargs .set_item( "expires", cookie.expires_datetime().map(|f| f.unix_timestamp()), ) - .unwrap(); - kwargs.set_item("version", 0).unwrap(); + .unwrap_or_default(); + kwargs.set_item("version", 0).unwrap_or_default(); let rest = PyDict::new(py); if let Some(http_only) = cookie.http_only() { - rest.set_item("HttpOnly", http_only).unwrap(); + rest.set_item("HttpOnly", http_only).unwrap_or_default(); } if let Some(same_site) = cookie.same_site() { @@ -84,10 +84,10 @@ impl CookieStore for PythonCookieJar { cookie::SameSite::Lax => "Lax", cookie::SameSite::None => "None", }; - rest.set_item("SameSite", same_site_str).unwrap(); + rest.set_item("SameSite", same_site_str).unwrap_or_default(); } - kwargs.set_item("rest", rest).unwrap(); + kwargs.set_item("rest", rest).unwrap_or_default(); let py_cookie = self.cookie_constructor.call(py, (), Some(&kwargs)).unwrap(); @@ -110,18 +110,15 @@ impl CookieStore for PythonCookieJar { let domain = py_cookie .getattr("domain") - .unwrap() - .extract::() - .unwrap(); + .and_then(|attr| attr.extract::()) + .unwrap_or_default(); let path = py_cookie .getattr("path") - .unwrap() - .extract::() - .unwrap(); + .and_then(|attr| attr.extract::()) + .unwrap_or_default(); let secure = py_cookie .getattr("secure") - .unwrap() - .extract::() + .and_then(|attr| attr.extract::()) .unwrap_or_default(); if !domain.is_empty() && !url.host_str().unwrap_or_default().contains(&domain) { @@ -187,7 +184,9 @@ impl PythonCookieJar { } } - pub fn from_httpx_cookies(py: Python<'_>, cookies: Py) -> Self { - PythonCookieJar::new(py, cookies.getattr(py, "jar").unwrap()) + pub fn from_httpx_cookies(py: Python<'_>, cookies: Py) -> PyResult { + cookies.getattr(py, "jar").and_then(|jar| { + Ok(PythonCookieJar::new(py, jar.into())) + }) } } diff --git a/impit/src/impit.rs b/impit/src/impit.rs index 30a5d060..80200904 100644 --- a/impit/src/impit.rs +++ b/impit/src/impit.rs @@ -2,7 +2,7 @@ use tokio::sync::RwLock; use log::debug; use reqwest::{cookie::CookieStore, header::HeaderMap, Method, Response, Version}; -use std::{fmt::Debug, net::IpAddr, str::FromStr, sync::Arc, time::Duration}; +use std::{fmt::Debug, net::IpAddr, sync::Arc, time::Duration}; use url::Url; use crate::{ @@ -100,7 +100,7 @@ impl Default for ImpitBuilder Impit { if engine_guard.is_none() { *engine_guard = Some(H3Engine::init().await); } - engine_guard.as_ref().unwrap().host_supports_h3(host).await + + match engine_guard.as_ref() { + None => false, + Some(engine) => engine.host_supports_h3(host).await, + } } } @@ -343,7 +347,7 @@ impl Impit { } let parsed_url = self.parse_url(url.clone())?; - let host = parsed_url.host_str().unwrap().to_string(); + let host = parsed_url.host_str().unwrap_or_default().to_string(); let h3 = options.http3_prior_knowledge || self.should_use_h3(&host).await; @@ -357,7 +361,7 @@ impl Impit { let client = if h3 { debug!("Using QUIC for request to {url}"); - self.h3_client.as_ref().unwrap() + self.h3_client.as_ref().unwrap_or(&self.base_client) } else { debug!("{url} doesn't seem to have HTTP3 support"); &self.base_client @@ -384,25 +388,26 @@ impl Impit { let response = request.send().await; - if response.is_err() { - let max_redirects = match self.config.redirect { - RedirectBehavior::FollowRedirect(max) => max, - RedirectBehavior::ManualRedirect => 0, - }; - - return Err(ImpitError::from( - response.err().unwrap(), - ErrorContext { - timeout: options.timeout.unwrap_or(self.config.request_timeout), - max_redirects, - method: method.to_string(), - protocol: parsed_url.scheme().to_string(), - url: url.clone(), - }, - )); - } - - let response = response.unwrap(); + let response = match response { + Ok(resp) => resp, + Err(err) => { + let max_redirects = match self.config.redirect { + RedirectBehavior::FollowRedirect(max) => max, + RedirectBehavior::ManualRedirect => 0, + }; + + return Err(ImpitError::from( + err, + ErrorContext { + timeout: options.timeout.unwrap_or(self.config.request_timeout), + max_redirects, + method: method.to_string(), + protocol: parsed_url.scheme().to_string(), + url: url.clone(), + }, + )); + } + }; if !h3 { let engine_guard = self.h3_engine.read().await; @@ -410,10 +415,13 @@ impl Impit { h3_engine.set_h3_support(&host, false).await; if let Some(alt_svc) = response.headers().get("Alt-Svc") { - let alt_svc = alt_svc.to_str().unwrap(); - if alt_svc.contains("h3") { - debug!("{host} supports HTTP/3 (alt-svc header), adding to Alt-Svc cache"); - h3_engine.set_h3_support(&host, true).await; + if let Ok(alt_svc_str) = alt_svc.to_str() { + if alt_svc_str.contains("h3") { + debug!( + "{host} supports HTTP/3 (alt-svc header), adding to Alt-Svc cache" + ); + h3_engine.set_h3_support(&host, true).await; + } } } } From a3e022c06531abb91583f9401a8d89a27787e250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jind=C5=99ich=20B=C3=A4r?= Date: Tue, 2 Sep 2025 13:04:49 +0200 Subject: [PATCH 2/2] chore: run linter / formatter --- impit-node/src/response.rs | 4 +++- impit-python/src/client.rs | 9 +++++---- impit-python/src/cookies.rs | 10 ++++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/impit-node/src/response.rs b/impit-node/src/response.rs index 739e1b4e..cbdd378d 100644 --- a/impit-node/src/response.rs +++ b/impit-node/src/response.rs @@ -119,7 +119,9 @@ impl<'env> ImpitResponse { )?; } - this.get(INNER_RESPONSE_PROPERTY_NAME).transpose() + this + .get(INNER_RESPONSE_PROPERTY_NAME) + .transpose() .ok_or_else(|| { napi::Error::new( napi::Status::GenericFailure, diff --git a/impit-python/src/client.rs b/impit-python/src/client.rs index bb88a3ca..b07a4bb4 100644 --- a/impit-python/src/client.rs +++ b/impit-python/src/client.rs @@ -10,7 +10,7 @@ use pyo3::{ffi::c_str, prelude::*}; use crate::{ cookies::PythonCookieJar, - errors::{CookieConflict, ImpitPyError}, + errors::ImpitPyError, request::{form_to_bytes, RequestBody}, response::{self, ImpitPyResponse}, }; @@ -102,9 +102,10 @@ impl Client { (Some(cookie_jar), None) => { builder.with_cookie_store(PythonCookieJar::new(py, cookie_jar.into())) } - (None, Some(cookies)) => { - builder.with_cookie_store(PythonCookieJar::from_httpx_cookies(py, cookies.into()).map_err(|e| ImpitPyError(ImpitError::CookieConflict))?) - } + (None, Some(cookies)) => builder.with_cookie_store( + PythonCookieJar::from_httpx_cookies(py, cookies.into()) + .map_err(|_e| ImpitPyError(ImpitError::CookieConflict))?, + ), (None, None) => builder, }; diff --git a/impit-python/src/cookies.rs b/impit-python/src/cookies.rs index e17e3e04..3545e59f 100644 --- a/impit-python/src/cookies.rs +++ b/impit-python/src/cookies.rs @@ -44,7 +44,9 @@ impl CookieStore for PythonCookieJar { ) .unwrap_or_default(); kwargs.set_item("comment", None::<&str>).unwrap_or_default(); - kwargs.set_item("comment_url", None::<&str>).unwrap_or_default(); + kwargs + .set_item("comment_url", None::<&str>) + .unwrap_or_default(); kwargs.set_item("port", None::<&str>).unwrap_or_default(); kwargs.set_item("port_specified", false).unwrap_or_default(); kwargs @@ -185,8 +187,8 @@ impl PythonCookieJar { } pub fn from_httpx_cookies(py: Python<'_>, cookies: Py) -> PyResult { - cookies.getattr(py, "jar").and_then(|jar| { - Ok(PythonCookieJar::new(py, jar.into())) - }) + cookies + .getattr(py, "jar") + .map(|jar| PythonCookieJar::new(py, jar)) } }