From 2c29cc230cad7437a162e4ab49bc7eea9121602a Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Sun, 30 Jan 2022 13:53:47 +0100 Subject: [PATCH] Remove Sync requirement of ReadWrite trait 3rd party TLS connections are currently required to provide a Sync guarantee. Since ureq will only ever use the connection on a single thread, this is not necessary. The reason we end up with this bound is because we want Response and Error to be Sync, in which case Rust's automatic inferral of Sync fails. This change "masks" the Stream in a wrapper making it Sync. Close #474 --- Cargo.toml | 1 + src/response.rs | 9 +++++---- src/stream.rs | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 040f179..6f21f10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ socks = { version = "0.3", optional = true } serde = { version = "1", optional = true } serde_json = { version = "1", optional = true } encoding_rs = { version = "0.8", optional = true } +sync_wrapper = { version = "0.1" } cookie_store = { version = "0.15", optional = true, default-features = false, features = ["preserve_order"] } log = "0.4" webpki = { version = "0.22", optional = true } diff --git a/src/response.rs b/src/response.rs index 128b5c8..23508b8 100644 --- a/src/response.rs +++ b/src/response.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use std::{fmt, io::BufRead}; use chunked_transfer::Decoder as ChunkDecoder; +use sync_wrapper::SyncWrapper; use url::Url; use crate::error::{Error, ErrorKind::BadStatus}; @@ -67,7 +68,7 @@ pub struct Response { // Boxed to avoid taking up too much size. unit: Option>, // Boxed to avoid taking up too much size. - stream: Box, + stream: SyncWrapper>, /// The redirect history of this response, if any. The history starts with /// the first response received and ends with the response immediately /// previous to this one. @@ -292,7 +293,7 @@ impl Response { self.length }; - let stream = self.stream; + let stream = self.stream.into_inner(); let unit = self.unit; if let Some(unit) = &unit { let result = stream.set_read_timeout(unit.agent.config.timeout_read); @@ -512,7 +513,7 @@ impl Response { status, headers, unit: unit.map(Box::new), - stream: Box::new(stream.into()), + stream: SyncWrapper::new(Box::new(stream.into())), history: vec![], length, compression, @@ -522,7 +523,7 @@ impl Response { #[cfg(test)] pub fn into_written_bytes(self) -> Vec { // Deliberately consume `self` so that any access to `self.stream` must be non-shared. - self.stream.written_bytes() + self.stream.into_inner().written_bytes() } #[cfg(test)] diff --git a/src/stream.rs b/src/stream.rs index 10e25d6..c8cee56 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -18,7 +18,7 @@ use crate::error::ErrorKind; use crate::unit::Unit; /// Trait for things implementing [std::io::Read] + [std::io::Write]. Used in [TlsConnector]. -pub trait ReadWrite: Read + Write + Send + Sync + 'static { +pub trait ReadWrite: Read + Write + Send + 'static { fn socket(&self) -> Option<&TcpStream>; } @@ -31,7 +31,7 @@ pub trait TlsConnector: Send + Sync { } pub(crate) struct Stream { - inner: BufReader>, + inner: BufReader>, } trait Inner: Read + Write { @@ -188,7 +188,7 @@ impl fmt::Debug for Stream { } impl Stream { - fn new(t: impl Inner + Send + Sync + 'static) -> Stream { + fn new(t: impl Inner + Send + 'static) -> Stream { Stream::logged_create(Stream { inner: BufReader::new(Box::new(t)), })