mirror of https://github.com/http-rs/async-h1
init structify
This commit is contained in:
parent
b8f3ba8a81
commit
ed66b38b76
|
@ -15,7 +15,7 @@ edition = "2018"
|
|||
url = "2.1.0"
|
||||
httparse = "1.3.3"
|
||||
async-std = { version = "1.5.0", features = ["unstable"] }
|
||||
http-types = "1.2.0"
|
||||
http-types = { version = "1.2.0", features = ["unstable"] }
|
||||
pin-project-lite = "0.1.1"
|
||||
byte-pool = "0.2.1"
|
||||
lazy_static = "1.4.0"
|
||||
|
@ -27,3 +27,6 @@ pretty_assertions = "0.6.1"
|
|||
async-std = { version = "1.4.0", features = ["unstable", "attributes"] }
|
||||
tempfile = "3.1.0"
|
||||
async-test = "1.0.0"
|
||||
|
||||
[patch.crates-io]
|
||||
http-types = { path = "../http-types", features = ["unstable"] }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use async_h1::client;
|
||||
use async_h1::HttpClient;
|
||||
use async_std::net::TcpStream;
|
||||
use http_types::{Error, Method, Request, Url};
|
||||
|
||||
|
@ -12,7 +12,7 @@ async fn main() -> Result<(), Error> {
|
|||
println!("making request {}/2", i + 1);
|
||||
let url = Url::parse(&format!("http://{}/foo", peer_addr)).unwrap();
|
||||
let req = Request::new(Method::Get, url);
|
||||
let res = client::connect(stream.clone(), req).await?;
|
||||
let res = HttpClient::connect(stream.clone(), req).await?;
|
||||
println!("{:?}", res);
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -3,24 +3,76 @@
|
|||
use async_std::io::{self, Read, Write};
|
||||
use http_types::{Request, Response};
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
mod decode;
|
||||
mod encode;
|
||||
|
||||
pub use decode::decode;
|
||||
pub use encode::Encoder;
|
||||
|
||||
/// Opens an HTTP/1.1 connection to a remote host.
|
||||
pub async fn connect<RW>(mut stream: RW, req: Request) -> http_types::Result<Response>
|
||||
where
|
||||
RW: Read + Write + Send + Sync + Unpin + 'static,
|
||||
{
|
||||
let mut req = Encoder::encode(req).await?;
|
||||
log::trace!("> {:?}", &req);
|
||||
/// HTTP/1.1 client.
|
||||
#[derive(Debug)]
|
||||
pub struct HttpClient;
|
||||
|
||||
io::copy(&mut req, &mut stream).await?;
|
||||
impl HttpClient {
|
||||
/// Creates a new instance of `HttpClientBuilder`.
|
||||
pub fn builder() -> HttpClientBuilder {
|
||||
HttpClientBuilder::new()
|
||||
}
|
||||
|
||||
let res = decode(stream).await?;
|
||||
log::trace!("< {:?}", &res);
|
||||
// Public for testing purposes only.
|
||||
#[doc(hidden)]
|
||||
pub async fn decode<R>(reader: R) -> http_types::Result<Response>
|
||||
where
|
||||
R: Read + Unpin + Send + Sync + 'static,
|
||||
{
|
||||
decode(reader).await
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
/// Opens an HTTP/1.1 connection to a remote host.
|
||||
pub async fn connect<RW>(stream: RW, req: Request) -> http_types::Result<Response>
|
||||
where
|
||||
RW: Read + Write + Send + Sync + Unpin + 'static,
|
||||
{
|
||||
let builder = HttpClientBuilder::new();
|
||||
builder.connect(stream, req).await
|
||||
}
|
||||
}
|
||||
|
||||
/// HTTP/1.1 client builder.
|
||||
#[derive(Debug)]
|
||||
pub struct HttpClientBuilder;
|
||||
|
||||
impl HttpClientBuilder {
|
||||
/// Creates a new instance of `HttpClientBuilder`.
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
/// Opens an HTTP/1.1 connection to a remote host.
|
||||
pub async fn connect<RW>(self, mut stream: RW, req: Request) -> http_types::Result<Response>
|
||||
where
|
||||
RW: Read + Write + Send + Sync + Unpin + 'static,
|
||||
{
|
||||
let mut req = Encoder::encode(req).await?;
|
||||
log::trace!("> {:?}", &req);
|
||||
|
||||
io::copy(&mut req, &mut stream).await?;
|
||||
|
||||
let res = decode(stream).await?;
|
||||
log::trace!("< {:?}", &res);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl http_types::Client for HttpClient {
|
||||
fn send_req(
|
||||
&self,
|
||||
req: Request,
|
||||
) -> Pin<Box<dyn Future<Output = http_service::Result<Response>> + 'static + Send>> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -27,7 +27,7 @@
|
|||
//! __HTTP client__
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use async_h1::client;
|
||||
//! use async_h1::HttpClient;
|
||||
//! use async_std::net::{TcpStream};
|
||||
//! use http_types::{Error, Method, Request, Url};
|
||||
//!
|
||||
|
@ -41,7 +41,7 @@
|
|||
//! println!("making request {}/2", i + 1);
|
||||
//! let url = Url::parse(&format!("http://{}/foo", peer_addr)).unwrap();
|
||||
//! let req = Request::new(Method::Get, url);
|
||||
//! let res = client::connect(stream.clone(), req).await?;
|
||||
//! let res = HttpClient::connect(stream.clone(), req).await?;
|
||||
//! println!("{:?}", res);
|
||||
//! }
|
||||
//! Ok(())
|
||||
|
@ -115,10 +115,5 @@ mod server;
|
|||
#[doc(hidden)]
|
||||
pub mod client;
|
||||
|
||||
pub use client::connect;
|
||||
pub use server::{HttpServer, HttpServerBuilder};
|
||||
|
||||
// pub struct HttpClient {}
|
||||
// impl HttpClient {
|
||||
// pub fn connect() {}
|
||||
// }
|
||||
pub use client::{HttpClient, HttpClientBuilder};
|
||||
pub use server::HttpServer;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Process HTTP connections on the server.
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_std::future::{timeout, Future, TimeoutError};
|
||||
|
@ -15,54 +16,35 @@ use encode::Encoder;
|
|||
|
||||
/// HTTP/1.1 server.
|
||||
#[derive(Debug)]
|
||||
pub struct HttpServer {
|
||||
builder: HttpServerBuilder,
|
||||
}
|
||||
|
||||
impl HttpServer {
|
||||
/// Create a new `HttpServer` builder that takes various configuration.
|
||||
pub fn builder() -> HttpServerBuilder {
|
||||
HttpServerBuilder::new()
|
||||
}
|
||||
|
||||
/// Accept a new incoming HTTP/1.1 connection.
|
||||
///
|
||||
/// Supports `KeepAlive` requests by default.
|
||||
pub async fn accept<RW, F, Fut>(addr: &str, io: RW, endpoint: F) -> http_types::Result<()>
|
||||
where
|
||||
RW: Read + Write + Clone + Send + Sync + Unpin + 'static,
|
||||
F: Fn(Request) -> Fut,
|
||||
Fut: Future<Output = http_types::Result<Response>>,
|
||||
{
|
||||
let builder = HttpServerBuilder::new();
|
||||
builder.accept(addr, io, endpoint).await
|
||||
}
|
||||
}
|
||||
|
||||
/// HTTP/1.1 server builder.
|
||||
#[derive(Debug)]
|
||||
pub struct HttpServerBuilder {
|
||||
/// Timeout to handle headers. Defaults to 60s.
|
||||
pub struct HttpServer<F, Fut> {
|
||||
headers_timeout: Option<Duration>,
|
||||
endpoint: F,
|
||||
__fut: std::marker::PhantomData<Fut>,
|
||||
}
|
||||
|
||||
impl HttpServerBuilder {
|
||||
/// Create a new instance of `HttpServerBuilder`.
|
||||
pub fn new() -> Self {
|
||||
impl<F, Fut> HttpServer<F, Fut>
|
||||
where
|
||||
F: Fn(Request) -> Fut,
|
||||
Fut: Future<Output = http_types::Result<Response>>,
|
||||
{
|
||||
/// Create a new `HttpServer` builder that takes various configuration.
|
||||
// pub fn builder() -> HttpServerBuilder {
|
||||
// HttpServerBuilder::new()
|
||||
// }
|
||||
|
||||
/// Create a new instance of `HttpServer`.
|
||||
pub async fn new(endpoint: F) -> Self {
|
||||
Self {
|
||||
headers_timeout: Some(Duration::from_secs(60)),
|
||||
endpoint,
|
||||
__fut: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Accept a new incoming HTTP/1.1 connection.
|
||||
///
|
||||
/// Supports `KeepAlive` requests by default.
|
||||
pub async fn accept<RW, F, Fut>(
|
||||
self,
|
||||
addr: &str,
|
||||
mut io: RW,
|
||||
endpoint: F,
|
||||
) -> http_types::Result<()>
|
||||
pub async fn accept<RW>(self, addr: &str, io: RW) -> http_types::Result<()>
|
||||
where
|
||||
RW: Read + Write + Clone + Send + Sync + Unpin + 'static,
|
||||
F: Fn(Request) -> Fut,
|
||||
|
@ -70,7 +52,7 @@ impl HttpServerBuilder {
|
|||
{
|
||||
loop {
|
||||
// Decode a new request, timing out if this takes longer than the timeout duration.
|
||||
let fut = decode(addr, io.clone());
|
||||
let fut = decode(self.addr, io.clone());
|
||||
|
||||
let req = if let Some(timeout_duration) = self.headers_timeout {
|
||||
match timeout(timeout_duration, fut).await {
|
||||
|
@ -86,7 +68,7 @@ impl HttpServerBuilder {
|
|||
};
|
||||
|
||||
// Pass the request to the endpoint and encode the response.
|
||||
let res = endpoint(req).await?;
|
||||
let res = self.endpoint(req).await?;
|
||||
let mut encoder = Encoder::encode(res);
|
||||
|
||||
// Stream the response to the writer.
|
||||
|
@ -96,3 +78,15 @@ impl HttpServerBuilder {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Fut> http_types::Server for HttpServer<F, Fut> {
|
||||
fn recv_req(
|
||||
&self,
|
||||
req: Request,
|
||||
) -> Pin<Box<dyn Future<Output = http_types::Result<Response>> + 'static + Send>> {
|
||||
Box::pin(async move {
|
||||
let res = self.endpoint(req).await?;
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::common::fixture_path;
|
||||
use async_h1::client;
|
||||
use async_h1::HttpClient;
|
||||
use async_std::fs::File;
|
||||
use http_types::{headers, Method, Request, StatusCode};
|
||||
use url::Url;
|
||||
|
@ -20,7 +20,7 @@ async fn test_encode_request_add_date() {
|
|||
let mut req = Request::new(Method::Post, url);
|
||||
req.set_body("hello");
|
||||
|
||||
let res = client::connect(case.clone(), req).await.unwrap();
|
||||
let res = HttpClient::connect(case.clone(), req).await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::Ok);
|
||||
|
||||
case.assert().await;
|
||||
|
@ -32,7 +32,7 @@ async fn test_response_no_date() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let res = client::decode(response_fixture).await.unwrap();
|
||||
let res = HttpClient::decode(response_fixture).await.unwrap();
|
||||
|
||||
pretty_assertions::assert_eq!(res.header(&headers::DATE).is_some(), true);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ async fn test_multiple_header_values_for_same_header_name() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let res = client::decode(response_fixture).await.unwrap();
|
||||
let res = HttpClient::decode(response_fixture).await.unwrap();
|
||||
|
||||
pretty_assertions::assert_eq!(res.header(&headers::SET_COOKIE).unwrap().len(), 2);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ async fn test_response_newlines() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let res = client::decode(response_fixture).await.unwrap();
|
||||
let res = HttpClient::decode(response_fixture).await.unwrap();
|
||||
|
||||
pretty_assertions::assert_eq!(
|
||||
res.header(&headers::CONTENT_LENGTH)
|
||||
|
@ -79,7 +79,7 @@ async fn test_encode_request_with_connect() {
|
|||
let url = Url::parse("https://example.com:443").unwrap();
|
||||
let req = Request::new(Method::Connect, url);
|
||||
|
||||
let res = client::connect(case.clone(), req).await.unwrap();
|
||||
let res = HttpClient::connect(case.clone(), req).await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::Ok);
|
||||
|
||||
case.assert().await;
|
||||
|
|
Loading…
Reference in New Issue