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
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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<Box<Unit>>,
|
||||
// Boxed to avoid taking up too much size.
|
||||
stream: Box<Stream>,
|
||||
stream: SyncWrapper<Box<Stream>>,
|
||||
/// 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<u8> {
|
||||
// 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)]
|
||||
|
||||
@@ -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<Box<dyn Inner + Send + Sync + 'static>>,
|
||||
inner: BufReader<Box<dyn Inner + Send + 'static>>,
|
||||
}
|
||||
|
||||
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)),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user