Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose Hyper Client #1045

Closed
borchero opened this issue Sep 30, 2020 · 7 comments
Closed

Expose Hyper Client #1045

borchero opened this issue Sep 30, 2020 · 7 comments

Comments

@borchero
Copy link

borchero commented Sep 30, 2020

I'm currently using reqwest to make requests to an API using mutual TLS.

For some endpoints, more advanced networking features are required and I need to fall back to using a Hyper client. However, it is hard to establish mutual TLS using Hyper and rustls and, furthermore, it's a little undesirable to manage two distinct Hyper clients (as reqwest is backed by one anyway).

It would be great if reqwest's client would expose a method granting access to the underlying Hyper client.

@seanmonstar
Copy link
Owner

What part of a hyper::Client would you need access to?

@borchero
Copy link
Author

Basically, I wanted to get access to .inner.hyper, but I noticed I need to expose too many types that are not public.

I now went with the following public function that I added to the client. It does its job but I'm not sure if it should be part of this crate (although I'd love to not use my own fork):

pub fn execute_hyper(
    &self,
    builder: http::request::Builder,
    body: impl Into<super::body::Body>,
) -> Result<hyper::client::ResponseFuture, http::Error> {
    let request = builder.body(body.into().into_stream())?;
    return Ok(self.inner.hyper.request(request));
}

@seanmonstar
Copy link
Owner

What does that give you that isn't possible with the reqwest::Client? I'm trying to understand the intent, to see if there's another solution besides just opening up private methods.

@borchero
Copy link
Author

Basically, I need to hijack the underlying TCP stream (I'm interfacing with the Docker API and this is required for some interactive calls). Using Hyper, I can schedule the request and then get access to the TCP stream using the Upgraded type.

This looks something like that:

let request = hyper::Request::builder()
    .method(hyper::Method::POST)
    .uri(format!("http://localhost:2375/exec/{}/start", id))
    .header(hyper::header::CONTENT_TYPE, "application/json")
    .header(hyper::header::CONNECTION, "Upgrade")
    .header(hyper::header::UPGRADE, "tcp")
    .body(hyper::Body::from(body))?;

let client = hyper::Client::new();
let response = client.request(request).await?;
let mut upgraded = response.into_body().on_upgrade().await?;
// `upgraded` is now `AsyncRead` and `AsyncWrite`

I doubt that reqwest currently enables doing something like that and I'm not sure if gaining access to the underlying TCP connection is a common use case.

@seanmonstar
Copy link
Owner

seanmonstar commented Sep 30, 2020 via email

@borchero
Copy link
Author

Yes, exactly. I'm not too familiar with reqwest's internals at the moment, but if you think this would be nice to have in reqwest, I might familiarize myself a bit more with it in the coming days and might open a PR soon.

@luqmana
Copy link
Contributor

luqmana commented Jul 28, 2022

HTTP Upgrade support has landed with #1376:

reqwest/tests/upgrade.rs

Lines 33 to 50 in 61474f4

let res = reqwest::Client::builder()
.build()
.unwrap()
.get(format!("http://{}", server.addr()))
.header(http::header::CONNECTION, "upgrade")
.header(http::header::UPGRADE, "foobar")
.send()
.await
.unwrap();
assert_eq!(res.status(), http::StatusCode::SWITCHING_PROTOCOLS);
let mut upgraded = res.upgrade().await.unwrap();
upgraded.write_all(b"foo=bar").await.unwrap();
let mut buf = vec![];
upgraded.read_to_end(&mut buf).await.unwrap();
assert_eq!(buf, b"bar=foo");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants