Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion impit-python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ h2 = "0.4.7"
reqwest = "0.12.9"
tokio-stream = "0.1.17"
bytes = "1.9.0"
pyo3 = { version = "0.27", features = ["extension-module"] }
pyo3 = { version = "0.27", features = ["extension-module", "auto-initialize"] }
pyo3-async-runtimes = { version = "0.27", features = ["attributes", "async-std-runtime", "tokio-runtime"] }
openssl = { version = "*", features = ["vendored"] }
urlencoding = "2.1.3"
Expand Down
6 changes: 3 additions & 3 deletions impit-python/src/async_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,9 +437,9 @@ impl AsyncClient {

match response {
Ok(response) => {
let py_response =
ImpitPyResponse::from_async(response, default_encoding, stream_value).await;
Ok(py_response)
ImpitPyResponse::from_async(response, default_encoding, stream_value)
.await
.map_err(|e| ImpitPyError(e).into())
}
Err(err) => Err(ImpitPyError(err).into()),
}
Expand Down
16 changes: 7 additions & 9 deletions impit-python/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,15 +425,13 @@ impl Client {
};

match response {
Ok(response) => {
let py_response = ImpitPyResponse::from_async(
response,
self.default_encoding.clone(),
stream.unwrap_or(false),
)
.await;
Ok(py_response)
}
Ok(response) => ImpitPyResponse::from_async(
response,
self.default_encoding.clone(),
stream.unwrap_or(false),
)
.await
.map_err(ImpitPyError),
Err(err) => Err(ImpitPyError(err)),
}
})
Expand Down
14 changes: 9 additions & 5 deletions impit-python/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tokio::sync::Mutex as AsyncMutex;
use bytes::Bytes;
use encoding::label::encoding_from_whatwg_label;
use futures::{Stream, StreamExt};
use impit::utils::ContentType;
use impit::{errors::ImpitError, utils::ContentType};
use pyo3::prelude::*;
use reqwest::{Response, StatusCode, Version};
use std::pin::Pin;
Expand Down Expand Up @@ -521,7 +521,7 @@ impl ImpitPyResponse {
val: Response,
preferred_encoding: Option<String>,
stream: bool,
) -> Self {
) -> Result<Self, ImpitError> {
let status_code = val.status().as_u16();
let url = val.url().to_string();
let reason_phrase = val
Expand Down Expand Up @@ -551,7 +551,11 @@ impl ImpitPyResponse {
.and_then(|ct| ct.into());

let (content, inner_state, encoding, inner, is_closed, is_stream_consumed) = if !stream {
let content = val.bytes().await.map(|b| b.to_vec()).unwrap_or_default();
let content = val
.bytes()
.await
.map(|b| b.to_vec())
.map_err(|e| ImpitError::from(e, None))?;
let encoding = preferred_encoding
.and_then(|e| encoding_from_whatwg_label(&e))
.or(content_type_charset)
Expand Down Expand Up @@ -581,7 +585,7 @@ impl ImpitPyResponse {
)
};

ImpitPyResponse {
Ok(ImpitPyResponse {
status_code,
url,
reason_phrase,
Expand All @@ -595,6 +599,6 @@ impl ImpitPyResponse {
is_stream_consumed,
inner_state,
inner,
}
})
}
}
2 changes: 1 addition & 1 deletion impit-python/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 16 additions & 11 deletions impit/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use std::{error::Error, time::Duration};

use thiserror::Error;

#[derive(Default)]
pub struct ErrorContext {
pub timeout: Duration,
pub max_redirects: usize,
pub method: String,
pub protocol: String,
pub url: String,
pub timeout: Option<Duration>,
pub max_redirects: Option<usize>,
pub method: Option<String>,
pub protocol: Option<String>,
pub url: Option<String>,
}

/// Error types that can be returned by the [`Impit`] struct.
Expand All @@ -22,8 +23,8 @@ pub enum ImpitError {
RequestError,
#[error("Transport error occurred.")]
TransportError,
#[error("Request timeout ({0} ms) exceeded.")]
TimeoutException(u128),
#[error("Request timeout ({}) exceeded.", .0.map_or("unknown".to_string(), |ms| format!("{ms} ms"))) ]
Comment thread
barjin marked this conversation as resolved.
TimeoutException(Option<u128>),
#[error("Connection timed out.")]
ConnectTimeout,
#[error("Read operation timed out.")]
Expand Down Expand Up @@ -54,8 +55,8 @@ pub enum ImpitError {
UnsupportedProtocol,
#[error("The response body couldn't be decoded.")]
DecodingError,
#[error("Too many redirects occurred. Maximum allowed: {0}")]
TooManyRedirects(usize),
#[error("Too many redirects occurred. Maximum allowed: {}.", .0.map_or("unknown".to_string(), |n| n.to_string())) ]
Comment thread
barjin marked this conversation as resolved.
TooManyRedirects(Option<usize>),
#[error("HTTP status error occurred with status code {0}.")]
HTTPStatusError(u16),
#[error("The URL is invalid.")]
Expand Down Expand Up @@ -99,9 +100,13 @@ impl From<reqwest::Error> for ImpitError {
}

impl ImpitError {
pub fn from(error: reqwest::Error, context: ErrorContext) -> Self {
pub fn from(error: reqwest::Error, context: Option<ErrorContext>) -> Self {
let context = context.unwrap_or_default();
if error.is_timeout() {
return ImpitError::TimeoutException(context.timeout.as_millis());
if (format!("{:?}", error).to_lowercase()).contains("connection timed out") {
return ImpitError::ConnectTimeout;
}
Comment thread
barjin marked this conversation as resolved.
return ImpitError::TimeoutException(context.timeout.map(|x| x.as_millis()));
}

if error.is_redirect() {
Expand Down
14 changes: 7 additions & 7 deletions impit/src/impit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,13 +435,13 @@ impl<CookieStoreImpl: CookieStore + 'static> Impit<CookieStoreImpl> {

return Err(ImpitError::from(
err,
ErrorContext {
timeout: timeout.unwrap_or(self.config.request_timeout),
max_redirects,
method: method.to_string(),
protocol: request.url.scheme().to_string(),
url: url.clone(),
},
Some(ErrorContext {
timeout: Some(timeout.unwrap_or(self.config.request_timeout)),
max_redirects: Some(max_redirects),
method: Some(method.to_string()),
protocol: Some(request.url.scheme().to_string()),
url: Some(url.clone()),
}),
));
}
};
Expand Down
Loading