Skip to content

Commit 91d8b0a

Browse files
authored
feat(client): port the hyper 0.14 as legacy::Client (#19)
1 parent 9ecd28a commit 91d8b0a

File tree

15 files changed

+1803
-38
lines changed

15 files changed

+1803
-38
lines changed

Cargo.toml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ edition = "2018"
1515
publish = false # no accidents while in dev
1616

1717
[dependencies]
18-
hyper = "=1.0.0-rc.2"
18+
hyper = { git = "https://github.com/hyperium/hyper" } #"=1.0.0-rc.2"
1919
futures-channel = "0.3"
2020
futures-util = { version = "0.3", default-features = false }
2121
http = "0.2"
@@ -28,22 +28,34 @@ socket2 = "0.4"
2828
tracing = { version = "0.1", default-features = false, features = ["std"] }
2929
tokio = { version = "1", features = ["net", "rt", "time"] }
3030
tower-service = "0.3"
31-
tower = { version = "0.4", features = ["util"] }
31+
tower = { version = "0.4", features = ["make", "util"] }
3232

3333
[dev-dependencies]
34+
bytes = "1"
35+
http-body-util = "0.1.0-rc.2"
3436
tokio = { version = "1", features = ["macros", "test-util"] }
3537

3638
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dev-dependencies]
3739
pnet_datalink = "0.27.2"
3840

3941
[features]
42+
default = []
43+
4044
# Shorthand to enable everything
41-
full = ["http1", "http2", "tcp", "runtime"]
45+
full = ["client", "server", "http1", "http2", "tcp", "runtime"]
46+
47+
client = ["hyper/client"]
48+
server = ["hyper/server"]
49+
50+
http1 = ["hyper/http1"]
51+
http2 = ["hyper/http2"]
4252

43-
runtime = []
4453
tcp = []
45-
http1 = []
46-
http2 = []
54+
runtime = []
4755

4856
# internal features used in CI
4957
__internal_happy_eyeballs_tests = []
58+
59+
[[example]]
60+
name = "client"
61+
required-features = ["client", "http1", "tcp", "runtime"]

examples/client.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use std::env;
2+
3+
use http_body_util::Empty;
4+
use hyper::Request;
5+
use hyper_util::client::{connect::HttpConnector, legacy::Client};
6+
7+
#[tokio::main(flavor = "current_thread")]
8+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
9+
let url = match env::args().nth(1) {
10+
Some(url) => url,
11+
None => {
12+
eprintln!("Usage: client <url>");
13+
return Ok(());
14+
}
15+
};
16+
17+
// HTTPS requires picking a TLS implementation, so give a better
18+
// warning if the user tries to request an 'https' URL.
19+
let url = url.parse::<hyper::Uri>()?;
20+
if url.scheme_str() != Some("http") {
21+
eprintln!("This example only works with 'http' URLs.");
22+
return Ok(());
23+
}
24+
25+
let client = Client::builder(hyper_util::rt::TokioExecutor::new()).build(HttpConnector::new());
26+
27+
let req = Request::builder()
28+
.uri(url)
29+
.body(Empty::<bytes::Bytes>::new())?;
30+
31+
let resp = client.request(req).await?;
32+
33+
eprintln!("{:?} {:?}", resp.version(), resp.status());
34+
eprintln!("{:#?}", resp.headers());
35+
36+
Ok(())
37+
}

src/client/client.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,132 @@
1+
use hyper::{Request, Response};
2+
use tower::{Service, MakeService};
3+
4+
use super::connect::Connect;
5+
use super::pool;
6+
7+
pub struct Client<M> {
8+
// Hi there. So, let's take a 0.14.x hyper::Client, and build up its layers
9+
// here. We don't need to fully expose the layers to start with, but that
10+
// is the end goal.
11+
//
12+
// Client = MakeSvcAsService<
13+
// SetHost<
14+
// Http1RequestTarget<
15+
// DelayedRelease<
16+
// ConnectingPool<C, P>
17+
// >
18+
// >
19+
// >
20+
// >
21+
make_svc: M,
22+
}
23+
24+
// We might change this... :shrug:
25+
type PoolKey = hyper::Uri;
26+
27+
struct ConnectingPool<C, P> {
28+
connector: C,
29+
pool: P,
30+
}
31+
32+
struct PoolableSvc<S>(S);
33+
134
/// A marker to identify what version a pooled connection is.
235
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
336
#[allow(dead_code)]
437
pub enum Ver {
538
Auto,
639
Http2,
740
}
41+
42+
// ===== impl Client =====
43+
44+
impl<M, /*ReqBody, ResBody,*/ E> Client<M>
45+
where
46+
M: MakeService<
47+
hyper::Uri,
48+
Request<()>,
49+
Response = Response<()>,
50+
Error = E,
51+
MakeError = E,
52+
>,
53+
//M: Service<hyper::Uri, Error = E>,
54+
//M::Response: Service<Request<ReqBody>, Response = Response<ResBody>>,
55+
{
56+
pub async fn request(&mut self, req: Request<()>) -> Result<Response<()>, E> {
57+
let mut svc = self.make_svc.make_service(req.uri().clone()).await?;
58+
svc.call(req).await
59+
}
60+
}
61+
62+
impl<M, /*ReqBody, ResBody,*/ E> Client<M>
63+
where
64+
M: MakeService<
65+
hyper::Uri,
66+
Request<()>,
67+
Response = Response<()>,
68+
Error = E,
69+
MakeError = E,
70+
>,
71+
//M: Service<hyper::Uri, Error = E>,
72+
//M::Response: Service<Request<ReqBody>, Response = Response<ResBody>>,
73+
{
74+
75+
}
76+
77+
// ===== impl ConnectingPool =====
78+
79+
impl<C, P> ConnectingPool<C, P>
80+
where
81+
C: Connect,
82+
C::_Svc: Unpin + Send + 'static,
83+
{
84+
async fn connection_for(&self, target: PoolKey) -> Result<pool::Pooled<PoolableSvc<C::_Svc>, PoolKey>, ()> {
85+
todo!()
86+
}
87+
}
88+
89+
impl<S> pool::Poolable for PoolableSvc<S>
90+
where
91+
S: Unpin + Send + 'static,
92+
{
93+
fn is_open(&self) -> bool {
94+
/*
95+
match self.tx {
96+
PoolTx::Http1(ref tx) => tx.is_ready(),
97+
#[cfg(feature = "http2")]
98+
PoolTx::Http2(ref tx) => tx.is_ready(),
99+
}
100+
*/
101+
true
102+
}
103+
104+
fn reserve(self) -> pool::Reservation<Self> {
105+
/*
106+
match self.tx {
107+
PoolTx::Http1(tx) => Reservation::Unique(PoolClient {
108+
conn_info: self.conn_info,
109+
tx: PoolTx::Http1(tx),
110+
}),
111+
#[cfg(feature = "http2")]
112+
PoolTx::Http2(tx) => {
113+
let b = PoolClient {
114+
conn_info: self.conn_info.clone(),
115+
tx: PoolTx::Http2(tx.clone()),
116+
};
117+
let a = PoolClient {
118+
conn_info: self.conn_info,
119+
tx: PoolTx::Http2(tx),
120+
};
121+
Reservation::Shared(a, b)
122+
}
123+
}
124+
*/
125+
pool::Reservation::Unique(self)
126+
}
127+
128+
fn can_share(&self) -> bool {
129+
false
130+
//self.is_http2()
131+
}
132+
}

0 commit comments

Comments
 (0)