Repository: seanmonstar/reqwest (language: rust)

Issue:
Put encoding_rs dependency behind a Cargo feature?
I'm doing binary size analysis of my release binary using Size Bench: https://devblogs.microsoft.com/performance-diagnostics/sizebench-a-new-tool-for-analyzing-windows-binary-size/
A significant contributor to the size of the .rdata section is encoding_rs's data tables: https://raw.githubusercontent.com/hsivonen/encoding_rs/master/src/data.rs
It would be nice to place the dependency on encoding_rs behind a Cargo feature to avoid this size increase, e.g. in cases where Reqwest is used only to consume binary data or REST endpoints that speak utf-8.


Discussion / hints:
Sounds potentially useful for when we do the next breaking change!

At the same time, I suspect calling `.text()` to be very common, and I wonder how surprising it would be that it's not available by default.
> At the same time, I suspect calling `.text()` to be very common, and I wonder how surprising it would be that it's not available by default.

Perhaps we could include `encoding_rs` as a default feature, allowing users to disable it if they prefer to handle all content in bytes.

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index 93b8d9534..7a0c2d490 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,7 +27,7 @@ features = [
 ]
 
 [features]
-default = ["default-tls", "http2", "macos-system-configuration"]
+default = ["default-tls", "encoding_rs", "http2", "macos-system-configuration"]
 
 # Note: this doesn't enable the 'native-tls' feature, which adds specific
 # functionality for it.
@@ -60,7 +60,7 @@ json = ["dep:serde_json"]
 multipart = ["dep:mime_guess"]
 
 # Deprecated, remove this feature while bumping minor versions.
-trust-dns = ["dep:trust-dns-resolver"]
+trust-dns = []
 hickory-dns = ["dep:hickory-resolver"]
 
 stream = ["tokio/fs", "dep:tokio-util", "dep:wasm-streams"]
@@ -107,7 +107,7 @@ serde_json = { version = "1.0", optional = true }
 mime_guess = { version = "2.0", default-features = false, optional = true }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-encoding_rs = "0.8"
+encoding_rs = { version = "0.8", optional = true }
 http-body = "1"
 http-body-util = "0.1"
 hyper = { version = "1", features = ["http1", "client"] }
diff --git a/src/async_impl/response.rs b/src/async_impl/response.rs
index 1ee4a2f36..bad9429c2 100644
--- a/src/async_impl/response.rs
+++ b/src/async_impl/response.rs
@@ -3,11 +3,9 @@ use std::net::SocketAddr;
 use std::pin::Pin;
 
 use bytes::Bytes;
-use encoding_rs::{Encoding, UTF_8};
 use http_body_util::BodyExt;
 use hyper::{HeaderMap, StatusCode, Version};
 use hyper_util::client::legacy::connect::HttpInfo;
-use mime::Mime;
 #[cfg(feature = "json")]
 use serde::de::DeserializeOwned;
 #[cfg(feature = "json")]
@@ -21,6 +19,11 @@ use crate::async_impl::body::ResponseBody;
 #[cfg(feature = "cookies")]
 use crate::cookie;
 
+#[cfg(feature = "encoding_rs")]
+use encoding_rs::{Encoding, UTF_8};
+#[cfg(feature = "encoding_rs")]
+use mime::Mime;
+
 /// A Response to a submitted `Request`.
 pub struct Response {
     pub(super) res: hyper::Response<Decoder>,
@@ -135,6 +138,11 @@ impl Response {
     ///
     /// Note that the BOM is stripped from the returned String.
     ///
+    /// # Note
+    ///
+    /// If the `encoding_rs` feature is disabled the method will only attempt to decode the
+    /// response as UTF-8, regardless of the given `Content-Type`
+    ///
     /// # Example
     ///
     /// ```
@@ -149,7 +157,17 @@ impl Response {
     /// # }
     /// ```
     pub async fn text(self) -> crate::Result<String> {
-        self.text_with_charset("utf-8").await
+        #[cfg(feature = "encoding_rs")]
+        {
+            self.text_with_charset("utf-8").await
+        }
+
+        #[cfg(not(feature = "encoding_rs"))]
+        {
+            let full = self.bytes().await?;
+            let text = String::from_utf8_lossy(&full);
+            Ok(text.into_owned())
+        }
     }
 
     /// Get the full response text given a specific encoding.
@@ -164,6 +182,10 @@ impl Response {
     ///
     /// [`encoding_rs`]: https://docs.rs/encoding_rs/0.8/encoding_rs/#relationship-with-windows-code-pages
     ///
+    /// # Optional
+    ///
+    /// This requires the optional `encoding_rs` feature enabled.
+    ///
     /// # Example
     ///
     /// ```
@@ -177,6 +199,8 @@ impl Response {
     /// # Ok(())
     /// # }
     /// ```
+    #[cfg(feature = "encoding_rs")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "encoding_rs")))]
     pub async fn text_with_charset(self, default_encoding: &str) -> crate::Result<String> {
         let content_type = self
             .headers()
diff --git a/src/blocking/response.rs b/src/blocking/response.rs
index 6ece95ba6..5dbf09a38 100644
--- a/src/blocking/response.rs
+++ b/src/blocking/response.rs
@@ -270,6 +270,11 @@ impl Response {
     /// Encoding is determined from the `charset` parameter of `Content-Type` header,
     /// and defaults to `utf-8` if not presented.
     ///
+    /// # Note
+    ///
+    /// If the `encoding_rs` feature is disabled the method will only attempt to decode the
+    /// response as UTF-8, regardless of the given `Content-Type`
+    ///
     /// # Example
     ///
     /// ```rust
@@ -280,7 +285,10 @@ impl Response {
     /// # }
     /// ```
     pub fn text(self) -> crate::Result<String> {
-        self.text_with_charset("utf-8")
+        wait::timeout(self.inner.text(), self.timeout).map_err(|e| match e {
+            wait::Waited::TimedOut(e) => crate::error::decode(e),
+            wait::Waited::Inner(e) => e,
+        })
     }
 
     /// Get the response text given a specific encoding.
@@ -293,6 +301,10 @@ impl Response {
     ///
     /// [`encoding_rs`]: https://docs.rs/encoding_rs/0.8/encoding_rs/#relationship-with-windows-code-pages
     ///
+    /// # Optional
+    ///
+    /// This requires the optional `encoding_rs` feature enabled.
+    ///
     /// # Example
     ///
     /// ```rust
@@ -303,6 +315,8 @@ impl Response {
     /// # Ok(())
     /// # }
     /// ```
+    #[cfg(feature = "encoding_rs")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "encoding_rs")))]
     pub fn text_with_charset(self, default_encoding: &str) -> crate::Result<String> {
         wait::timeout(self.inner.text_with_charset(default_encoding), self.timeout).map_err(|e| {
             match e {


Test patch: