Skip to content

Commit 06852a6

Browse files
authored
Merge pull request #27 from jbr/update-http-types
http types and async-h1 for 2.0.0
2 parents a44d486 + dd8a25f commit 06852a6

File tree

5 files changed

+129
-22
lines changed

5 files changed

+129
-22
lines changed

Cargo.toml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ curl_client = ["isahc", "async-std"]
2424
wasm_client = ["js-sys", "web-sys", "wasm-bindgen", "wasm-bindgen-futures"]
2525

2626
[dependencies]
27-
futures = { version = "0.3.1", features = ["compat", "io-compat"] }
28-
http-types = { version = "1.0.1", features = ["hyperium_http"] }
27+
futures = { version = "0.3.1" }
28+
http-types = "2.0.1"
2929
log = "0.4.7"
3030

3131
# h1-client
32-
async-h1 = { version = "1.0.0", optional = true }
33-
async-std = { version = "1.4.0", default-features = false, optional = true }
32+
async-h1 = { version = "2.0.0", optional = true }
33+
async-std = { version = "1.6.0", default-features = false, optional = true }
3434
async-native-tls = { version = "0.3.1", optional = true }
3535

3636
# isahc-client
@@ -62,3 +62,6 @@ features = [
6262
]
6363

6464
[dev-dependencies]
65+
async-std = { version = "1.6.0", features = ["unstable", "attributes"] }
66+
tide = { version = "0.9.0" }
67+
portpicker = "0.1.0"

src/h1.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ impl Clone for H1Client {
3232
impl HttpClient for H1Client {
3333
type Error = Error;
3434

35-
fn send(&self, req: Request) -> BoxFuture<'static, Result<Response, Self::Error>> {
35+
fn send(&self, mut req: Request) -> BoxFuture<'static, Result<Response, Self::Error>> {
3636
Box::pin(async move {
3737
// Insert host
3838
let host = req
3939
.url()
4040
.host_str()
41-
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing hostname"))?;
41+
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing hostname"))?
42+
.to_string();
4243

4344
let scheme = req.url().scheme();
4445
if scheme != "http" && scheme != "https" {
@@ -64,10 +65,14 @@ impl HttpClient for H1Client {
6465
match scheme {
6566
"http" => {
6667
let stream = async_std::net::TcpStream::connect(addr).await?;
68+
req.set_peer_addr(stream.peer_addr().ok());
69+
req.set_local_addr(stream.local_addr().ok());
6770
client::connect(stream, req).await
6871
}
6972
"https" => {
7073
let raw_stream = async_std::net::TcpStream::connect(addr).await?;
74+
req.set_peer_addr(raw_stream.peer_addr().ok());
75+
req.set_local_addr(raw_stream.local_addr().ok());
7176

7277
let stream = async_native_tls::connect(host, raw_stream).await?;
7378

@@ -78,3 +83,49 @@ impl HttpClient for H1Client {
7883
})
7984
}
8085
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use super::*;
90+
use async_std::prelude::*;
91+
use async_std::task;
92+
use http_types::url::Url;
93+
use http_types::Result;
94+
use std::time::Duration;
95+
96+
fn build_test_request(url: Url) -> Request {
97+
let mut req = Request::new(http_types::Method::Post, url);
98+
req.set_body("hello");
99+
req.append_header("test", "value");
100+
req
101+
}
102+
103+
#[async_std::test]
104+
async fn basic_functionality() -> Result<()> {
105+
let port = portpicker::pick_unused_port().unwrap();
106+
let mut app = tide::new();
107+
app.at("/").all(|mut r: tide::Request<()>| async move {
108+
let mut response = tide::Response::new(http_types::StatusCode::Ok);
109+
response.set_body(r.body_bytes().await.unwrap());
110+
Ok(response)
111+
});
112+
113+
let server = task::spawn(async move {
114+
app.listen(("localhost", port)).await?;
115+
Result::Ok(())
116+
});
117+
118+
let client = task::spawn(async move {
119+
task::sleep(Duration::from_millis(100)).await;
120+
let request =
121+
build_test_request(Url::parse(&format!("http://localhost:{}/", port)).unwrap());
122+
let mut response: Response = H1Client::new().send(request).await?;
123+
assert_eq!(response.body_string().await.unwrap(), "hello");
124+
Ok(())
125+
});
126+
127+
server.race(client).await?;
128+
129+
Ok(())
130+
}
131+
}

src/isahc.rs

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use super::{Body, HttpClient, Request, Response};
55
use async_std::io::BufReader;
66
use futures::future::BoxFuture;
77
use isahc::http;
8-
98
use std::sync::Arc;
109

1110
/// Curl-based HTTP Client.
@@ -45,25 +44,83 @@ impl Clone for IsahcClient {
4544
impl HttpClient for IsahcClient {
4645
type Error = isahc::Error;
4746

48-
fn send(&self, req: Request) -> BoxFuture<'static, Result<Response, Self::Error>> {
47+
fn send(&self, mut req: Request) -> BoxFuture<'static, Result<Response, Self::Error>> {
4948
let client = self.client.clone();
5049
Box::pin(async move {
51-
let req_hyperium: http::Request<http_types::Body> = req.into();
52-
let (parts, body) = req_hyperium.into_parts();
50+
let mut builder = http::Request::builder()
51+
.uri(req.url().as_str())
52+
.method(http::Method::from_bytes(req.method().to_string().as_bytes()).unwrap());
53+
54+
for name in req.header_names() {
55+
if let Some(value) = req.header(name) {
56+
builder = builder.header(name.as_str(), value.as_str());
57+
}
58+
}
59+
60+
let body = req.take_body();
61+
5362
let body = match body.len() {
5463
Some(len) => isahc::Body::from_reader_sized(body, len as u64),
5564
None => isahc::Body::from_reader(body),
5665
};
57-
let req: http::Request<isahc::Body> = http::Request::from_parts(parts, body);
58-
59-
let res = client.send_async(req).await?;
6066

67+
let request = builder.body(body).unwrap();
68+
let res = client.send_async(request).await?;
6169
let (parts, body) = res.into_parts();
62-
6370
let len = body.len().map(|len| len as usize);
6471
let body = Body::from_reader(BufReader::new(body), len);
65-
let res = http::Response::from_parts(parts, body);
66-
Ok(res.into())
72+
let mut response = http_types::Response::new(parts.status.as_u16());
73+
for (name, value) in &parts.headers {
74+
response.insert_header(name.as_str(), value.to_str().unwrap());
75+
}
76+
response.set_body(body);
77+
Ok(response)
6778
})
6879
}
6980
}
81+
82+
#[cfg(test)]
83+
mod tests {
84+
use super::*;
85+
use async_std::prelude::*;
86+
use async_std::task;
87+
use http_types::url::Url;
88+
use http_types::Result;
89+
use std::time::Duration;
90+
91+
fn build_test_request(url: Url) -> Request {
92+
let mut req = Request::new(http_types::Method::Post, url);
93+
req.set_body("hello");
94+
req.append_header("test", "value");
95+
req
96+
}
97+
98+
#[async_std::test]
99+
async fn basic_functionality() -> Result<()> {
100+
let port = portpicker::pick_unused_port().unwrap();
101+
let mut app = tide::new();
102+
app.at("/").all(|mut r: tide::Request<()>| async move {
103+
let mut response = tide::Response::new(http_types::StatusCode::Ok);
104+
response.set_body(r.body_bytes().await.unwrap());
105+
Ok(response)
106+
});
107+
108+
let server = task::spawn(async move {
109+
app.listen(("localhost", port)).await?;
110+
Result::Ok(())
111+
});
112+
113+
let client = task::spawn(async move {
114+
task::sleep(Duration::from_millis(100)).await;
115+
let request =
116+
build_test_request(Url::parse(&format!("http://localhost:{}/", port)).unwrap());
117+
let mut response: Response = IsahcClient::new().send(request).await?;
118+
assert_eq!(response.body_string().await.unwrap(), "hello");
119+
Ok(())
120+
});
121+
122+
server.race(client).await?;
123+
124+
Ok(())
125+
}
126+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub type Request = http_types::Request;
3838
/// An HTTP Response type with a streaming body.
3939
pub type Response = http_types::Response;
4040

41+
pub use http_types;
42+
4143
/// An abstract HTTP client.
4244
///
4345
/// __note that this is only exposed for use in middleware. Building new backing clients is not

tests/test.rs

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)