Skip to content

Commit

Permalink
refactor(core): Remove attohttpc in favor of reqwest (#7143)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>
  • Loading branch information
FabianLars and lucasfernog authored Jun 6, 2023
1 parent 52474e4 commit db7c5fb
Show file tree
Hide file tree
Showing 13 changed files with 36 additions and 273 deletions.
5 changes: 5 additions & 0 deletions .changes/remove-attohttpc-bundler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tauri-bundler': patch
---

Remove `attohttpc` in favor of `ureq`.
5 changes: 5 additions & 0 deletions .changes/remove-attohttpc-core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tauri': patch
---

Remove `attohttpc` in favor of `reqwest`.
13 changes: 6 additions & 7 deletions core/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ targets = [
]

[package.metadata.cargo-udeps.ignore]
normal = [ "attohttpc", "reqwest" ]
normal = [ "reqwest" ]

[dependencies]
serde_json = { version = "1.0", features = [ "raw_value" ] }
Expand Down Expand Up @@ -69,7 +69,6 @@ base64 = { version = "0.21", optional = true }
clap = { version = "3", optional = true }
reqwest = { version = "0.11", features = [ "json", "stream" ], optional = true }
bytes = { version = "1", features = [ "serde" ], optional = true }
attohttpc = { version = "0.22", features = [ "compress", "json", "form" ], optional = true }
open = { version = "3.2", optional = true }
shared_child = { version = "1.0", optional = true }
os_pipe = { version = "1.0", optional = true }
Expand Down Expand Up @@ -141,14 +140,14 @@ updater = [
"dialog-ask",
"fs-extract-api"
]
http-api = [ "attohttpc" ]
http-multipart = [ "attohttpc/multipart-form", "reqwest/multipart" ]
http-api = [ "reqwest", "bytes" ]
http-multipart = [ "reqwest/multipart" ]
os-api = [ "sys-locale" ]
shell-open-api = [ "open", "regex", "tauri-macros/shell-scope" ]
fs-extract-api = [ "zip" ]
reqwest-client = [ "reqwest", "bytes" ]
reqwest-native-tls-vendored = [ "reqwest-client", "reqwest/native-tls-vendored" ]
native-tls-vendored = [ "attohttpc/tls-vendored" ]
reqwest-client = [ "http-api" ]
reqwest-native-tls-vendored = [ "native-tls-vendored" ]
native-tls-vendored = [ "reqwest/native-tls-vendored" ]
process-command-api = [ "shared_child", "os_pipe" ]
global-shortcut = [
"tauri-runtime/global-shortcut",
Expand Down
9 changes: 1 addition & 8 deletions core/tauri/src/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,13 @@ pub enum Error {
#[error("user cancelled the dialog")]
DialogCancelled,
/// The network error.
#[cfg(all(feature = "http-api", not(feature = "reqwest-client")))]
#[error("Network Error: {0}")]
Network(#[from] attohttpc::Error),
/// The network error.
#[cfg(feature = "reqwest-client")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "reqwest-client")))]
#[cfg(feature = "http-api")]
#[error("Network Error: {0}")]
Network(#[from] reqwest::Error),
/// HTTP method error.
#[error(transparent)]
HttpMethod(#[from] http::method::InvalidMethod),
/// Invalid HTTP header value.
#[cfg(feature = "reqwest-client")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "reqwest-client")))]
#[error(transparent)]
HttpHeaderValue(#[from] http::header::InvalidHeaderValue),
/// Invalid HTTP header value.
Expand Down
175 changes: 0 additions & 175 deletions core/tauri/src/api/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ use url::Url;

use std::{collections::HashMap, path::PathBuf, time::Duration};

#[cfg(feature = "reqwest-client")]
pub use reqwest::header;

#[cfg(not(feature = "reqwest-client"))]
pub use attohttpc::header;

use header::{HeaderName, HeaderValue};

#[derive(Deserialize)]
Expand Down Expand Up @@ -73,13 +69,6 @@ impl ClientBuilder {
}

/// Builds the Client.
#[cfg(not(feature = "reqwest-client"))]
pub fn build(self) -> crate::api::Result<Client> {
Ok(Client(self))
}

/// Builds the Client.
#[cfg(feature = "reqwest-client")]
pub fn build(self) -> crate::api::Result<Client> {
let mut client_builder = reqwest::Client::builder();

Expand All @@ -101,146 +90,9 @@ impl ClientBuilder {
}

/// The HTTP client based on [`reqwest`].
#[cfg(feature = "reqwest-client")]
#[derive(Debug, Clone)]
pub struct Client(reqwest::Client);

/// The HTTP client.
#[cfg(not(feature = "reqwest-client"))]
#[derive(Debug, Clone)]
pub struct Client(ClientBuilder);

#[cfg(not(feature = "reqwest-client"))]
impl Client {
/// Executes an HTTP request.
///
/// # Examples
///
/// ```rust,no_run
/// use tauri::api::http::{ClientBuilder, HttpRequestBuilder, ResponseType};
/// async fn run_request() {
/// let client = ClientBuilder::new().build().unwrap();
/// let response = client.send(
/// HttpRequestBuilder::new("GET", "https://www.rust-lang.org")
/// .unwrap()
/// .response_type(ResponseType::Binary)
/// ).await;
/// if let Ok(response) = response {
/// let bytes = response.bytes();
/// }
/// }
/// ```
pub async fn send(&self, request: HttpRequestBuilder) -> crate::api::Result<Response> {
let method = Method::from_bytes(request.method.to_uppercase().as_bytes())?;

let mut request_builder = attohttpc::RequestBuilder::try_new(method, &request.url)?;

if let Some(query) = request.query {
request_builder = request_builder.params(&query);
}

if let Some(headers) = &request.headers {
for (name, value) in headers.0.iter() {
request_builder = request_builder.header(name, value);
}
}

if let Some(max_redirections) = self.0.max_redirections {
if max_redirections == 0 {
request_builder = request_builder.follow_redirects(false);
} else {
request_builder = request_builder.max_redirections(max_redirections as u32);
}
}

if let Some(timeout) = request.timeout {
request_builder = request_builder.timeout(timeout);
}

let response = if let Some(body) = request.body {
match body {
Body::Bytes(data) => request_builder.body(attohttpc::body::Bytes(data)).send()?,
Body::Text(text) => request_builder.body(attohttpc::body::Bytes(text)).send()?,
Body::Json(json) => request_builder.json(&json)?.send()?,
Body::Form(form_body) => {
#[allow(unused_variables)]
fn send_form(
request_builder: attohttpc::RequestBuilder,
headers: &Option<HeaderMap>,
form_body: FormBody,
) -> crate::api::Result<attohttpc::Response> {
#[cfg(feature = "http-multipart")]
if matches!(
headers
.as_ref()
.and_then(|h| h.0.get("content-type"))
.map(|v| v.as_bytes()),
Some(b"multipart/form-data")
) {
let mut multipart = attohttpc::MultipartBuilder::new();
let mut byte_cache: HashMap<String, Vec<u8>> = Default::default();

for (name, part) in &form_body.0 {
if let FormPart::File { file, .. } = part {
byte_cache.insert(name.to_string(), file.clone().try_into()?);
}
}
for (name, part) in &form_body.0 {
multipart = match part {
FormPart::File {
file,
mime,
file_name,
} => {
// safe to unwrap: always set by previous loop
let mut file =
attohttpc::MultipartFile::new(name, byte_cache.get(name).unwrap());
if let Some(mime) = mime {
file = file.with_type(mime)?;
}
if let Some(file_name) = file_name {
file = file.with_filename(file_name);
}
multipart.with_file(file)
}
FormPart::Text(value) => multipart.with_text(name, value),
};
}
return request_builder
.body(multipart.build()?)
.send()
.map_err(Into::into);
}

let mut form = Vec::new();
for (name, part) in form_body.0 {
match part {
FormPart::File { file, .. } => {
let bytes: Vec<u8> = file.try_into()?;
form.push((name, serde_json::to_string(&bytes)?))
}
FormPart::Text(value) => form.push((name, value)),
}
}
request_builder.form(&form)?.send().map_err(Into::into)
}

send_form(request_builder, &request.headers, form_body)?
}
}
} else {
request_builder.send()?
};

Ok(Response(
request.response_type.unwrap_or(ResponseType::Json),
response,
request.url,
))
}
}

#[cfg(feature = "reqwest-client")]
impl Client {
/// Executes an HTTP request
///
Expand Down Expand Up @@ -557,13 +409,8 @@ impl HttpRequestBuilder {
}

/// The HTTP response.
#[cfg(feature = "reqwest-client")]
#[derive(Debug)]
pub struct Response(ResponseType, reqwest::Response);
/// The HTTP response.
#[cfg(not(feature = "reqwest-client"))]
#[derive(Debug)]
pub struct Response(ResponseType, attohttpc::Response, Url);

impl Response {
/// Get the [`StatusCode`] of this Response.
Expand All @@ -579,20 +426,10 @@ impl Response {
/// Reads the response as raw bytes.
pub async fn bytes(self) -> crate::api::Result<RawResponse> {
let status = self.status().as_u16();
#[cfg(feature = "reqwest-client")]
let data = self.1.bytes().await?.to_vec();
#[cfg(not(feature = "reqwest-client"))]
let data = self.1.bytes()?;
Ok(RawResponse { status, data })
}

#[cfg(not(feature = "reqwest-client"))]
#[allow(dead_code)]
pub(crate) fn reader(self) -> attohttpc::ResponseReader {
let (_, _, reader) = self.1.split();
reader
}

// Convert the response into a Stream of [`bytes::Bytes`] from the body.
//
// # Examples
Expand All @@ -612,7 +449,6 @@ impl Response {
// # Ok(())
// # }
// ```
#[cfg(feature = "reqwest-client")]
#[allow(dead_code)]
pub(crate) fn bytes_stream(
self,
Expand All @@ -625,10 +461,7 @@ impl Response {
///
/// Note that the body is serialized to a [`Value`].
pub async fn read(self) -> crate::api::Result<ResponseData> {
#[cfg(feature = "reqwest-client")]
let url = self.1.url().clone();
#[cfg(not(feature = "reqwest-client"))]
let url = self.2;

let mut headers = HashMap::new();
let mut raw_headers = HashMap::new();
Expand All @@ -650,20 +483,12 @@ impl Response {
}
let status = self.1.status().as_u16();

#[cfg(feature = "reqwest-client")]
let data = match self.0 {
ResponseType::Json => self.1.json().await?,
ResponseType::Text => Value::String(self.1.text().await?),
ResponseType::Binary => serde_json::to_value(&self.1.bytes().await?)?,
};

#[cfg(not(feature = "reqwest-client"))]
let data = match self.0 {
ResponseType::Json => self.1.json()?,
ResponseType::Text => Value::String(self.1.text()?),
ResponseType::Binary => serde_json::to_value(self.1.bytes()?)?,
};

Ok(ResponseData {
url,
status,
Expand Down
6 changes: 3 additions & 3 deletions core/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
//! - **shell-open-api**: Enables the [`api::shell`] module.
//! - **http-api**: Enables the [`api::http`] module.
//! - **http-multipart**: Adds support to `multipart/form-data` requests.
//! - **reqwest-client**: Uses `reqwest` as HTTP client on the `http` APIs. Improves performance, but increases the bundle size.
//! - **native-tls-vendored**: Compile and statically link to a vendored copy of OpenSSL (applies to the default HTTP client).
//! - **reqwest-native-tls-vendored**: Compile and statically link to a vendored copy of OpenSSL (applies to the `reqwest` HTTP client).
//! - **reqwest-client**: Alias for the `http-api` feature flag.
//! - **native-tls-vendored**: Compile and statically link to a vendored copy of OpenSSL.
//! - **reqwest-native-tls-vendored**: Alias for the `native-tls-vendored` feature flag.
//! - **os-api**: Enables the [`api::os`] module.
//! - **process-command-api**: Enables the [`api::process::Command`] APIs.
//! - **global-shortcut**: Enables the global shortcut APIs.
Expand Down
20 changes: 0 additions & 20 deletions core/tauri/src/updater/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,6 @@ impl<R: Runtime> Update<R> {
.and_then(|value| value.parse().ok());

let mut buffer = Vec::new();
#[cfg(feature = "reqwest-client")]
{
use futures_util::StreamExt;
let mut stream = response.bytes_stream();
Expand All @@ -570,25 +569,6 @@ impl<R: Runtime> Update<R> {
buffer.extend(bytes);
}
}
#[cfg(not(feature = "reqwest-client"))]
{
let mut reader = response.reader();
let mut buf = [0; 16384];
loop {
match reader.read(&mut buf) {
Ok(b) => {
if b == 0 {
break;
} else {
let bytes = buf[0..b].to_vec();
on_chunk(bytes.len(), content_length);
buffer.extend(bytes);
}
}
Err(e) => return Err(e.into()),
}
}
}

on_download_finish();

Expand Down
1 change: 0 additions & 1 deletion examples/api/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ features = [
"isolation",
"macos-private-api",
"windows7-compat",
"reqwest-client",
"system-tray",
"updater"
]
Expand Down
11 changes: 6 additions & 5 deletions tooling/bundler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ tempfile = "3.5.0"
log = { version = "0.4.18", features = [ "kv_unstable" ] }
dirs-next = "2.0"
os_pipe = "1"
attohttpc = { version = "0.25", default-features = false }
ureq = { version = "2.5", default-features = false }
native-tls = { version = "0.2", optional = true }
hex = "0.4"
semver = "1"
sha1 = "0.10"
Expand Down Expand Up @@ -64,7 +65,7 @@ name = "tauri_bundler"
path = "src/lib.rs"

[features]
default = [ "native-tls" ]
native-tls = [ "attohttpc/tls-native" ]
native-tls-vendored = [ "attohttpc/tls-native-vendored" ]
rustls = [ "attohttpc/rustls" ]
default = ["rustls"]
native-tls = [ "ureq/native-tls" ]
native-tls-vendored = [ "native-tls", "native-tls/vendored" ]
rustls = [ "ureq/tls" ]
Loading

0 comments on commit db7c5fb

Please sign in to comment.