Skip to content

Commit

Permalink
feat(client): Add impl Service<http::Request<Body>> for Client (#202
Browse files Browse the repository at this point in the history
)

from upstream: seanmonstar/reqwest#2397

Implement it only once for `Client`, cloning is cheap, and under certain conditions there is no need to implement it again for `&Client`, which also avoids possible type inference errors
  • Loading branch information
0x676e67 authored Dec 22, 2024
1 parent ef73639 commit 88dcf59
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 3 deletions.
39 changes: 39 additions & 0 deletions src/client/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,45 @@ impl tower_service::Service<Request> for &'_ Client {
}
}

impl tower_service::Service<http::Request<Body>> for Client {
type Response = http::Response<Body>;
type Error = crate::Error;
type Future = MappedPending;

fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}

fn call(&mut self, req: http::Request<Body>) -> Self::Future {
match req.try_into() {
Ok(req) => MappedPending::new(self.execute_request(req)),
Err(err) => MappedPending::new(Pending::new_err(err)),
}
}
}

pin_project! {
pub struct MappedPending {
#[pin]
inner: Pending,
}
}

impl MappedPending {
fn new(inner: Pending) -> MappedPending {
Self { inner }
}
}

impl Future for MappedPending {
type Output = Result<http::Response<Body>, crate::Error>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let inner = self.project().inner;
inner.poll(cx).map_ok(Into::into)
}
}

impl_debug!(
Config,
{
Expand Down
63 changes: 61 additions & 2 deletions src/client/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::future::Future;
use std::time::Duration;

use http::header::CONTENT_LENGTH;
use http::Uri;
use http::{request::Parts, Request as HttpRequest, Uri, Version};
use serde::Serialize;
#[cfg(feature = "json")]
use serde_json;
Expand All @@ -20,7 +20,6 @@ use crate::cookie;
use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE, HOST};
use crate::util::ext::{ConnectExtension, PoolKeyExtension, VersionExtension};
use crate::{redirect, Method, Url};
use http::Version;
#[cfg(feature = "cookies")]
use std::sync::Arc;

Expand Down Expand Up @@ -648,6 +647,66 @@ pub(crate) fn extract_authority(url: &mut Url) -> Option<(String, Option<String>
None
}

impl<T> TryFrom<HttpRequest<T>> for Request
where
T: Into<Body>,
{
type Error = crate::Error;

fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
let (parts, body) = req.into_parts();
let Parts {
method,
uri,
headers,
..
} = parts;
let url = crate::into_url::IntoUrlSealed::into_url(uri.to_string())?;
Ok(Request {
method,
url,
headers,
body: Some(body.into()),
timeout: None,
// TODO: Add version
version: None,
redirect: None,
#[cfg(feature = "cookies")]
cookie_store: None,
})
}
}

impl TryFrom<Request> for HttpRequest<Body> {
type Error = crate::Error;

fn try_from(req: Request) -> crate::Result<Self> {
let Request {
method,
url,
headers,
body,
version,
..
} = req;

let mut builder = HttpRequest::builder();

if let Some(version) = version {
builder = builder.version(version);
}

let mut req = builder
.method(method)
.uri(url.as_str())
.body(body.unwrap_or_else(Body::empty))
.map_err(crate::error::builder)?;

*req.headers_mut() = headers;
Ok(req)
}
}

/// A builder for constructing HTTP requests.
pub(crate) struct InnerRequest<'a> {
builder: http::request::Builder,
Expand Down
10 changes: 10 additions & 0 deletions src/client/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,13 @@ impl From<Response> for Body {
Body::wrap(r.res.into_body())
}
}

/// A `Response` can be converted into a `http::Response`.
// It's supposed to be the inverse of the conversion above.
impl From<Response> for http::Response<Body> {
fn from(r: Response) -> http::Response<Body> {
let (parts, body) = r.res.into_parts();
let body = Body::wrap(body);
http::Response::from_parts(parts, body)
}
}
2 changes: 1 addition & 1 deletion src/tls/ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,4 @@ impl TlsExtension for SslRef {

Ok(())
}
}
}

0 comments on commit 88dcf59

Please sign in to comment.