Skip to content

Commit 0fbff90

Browse files
authored
Merge pull request #414 from dignifiedquire/h1
feat: add implementation based on async-h1 and http-service-h1
2 parents a88c3de + 8684daf commit 0fbff90

File tree

20 files changed

+670
-392
lines changed

20 files changed

+670
-392
lines changed

Cargo.toml

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,46 @@ features = ["docs"]
2323
rustdoc-args = ["--cfg", "feature=\"docs\""]
2424

2525
[features]
26-
default = ["hyper-server"]
27-
hyper-server = ["http-service-hyper"]
26+
default = ["h1-server"]
27+
hyper-server = ["futures", "hyper", "http", "tokio"]
28+
h1-server = ["http-service-h1"]
2829
docs = ["unstable"]
2930
unstable = []
3031

3132
[dependencies]
32-
futures = "0.3.1"
33-
http = "0.1.19"
34-
http-service = "0.4.0"
35-
http-service-hyper = { version = "0.4.1", optional = true }
33+
http-types = "1.0.1"
34+
http-service = { git = "https://github.com/dignifiedquire/http-service-1", branch = "h1" }
35+
http-service-h1 = { git = "https://github.com/dignifiedquire/http-service-1", branch = "h1", optional = true }
3636
log = "0.4.8"
3737
route-recognizer = "0.1.13"
3838
serde = "1.0.102"
3939
serde_json = "1.0.41"
4040
serde_qs = "0.5.0"
41-
async-std = { version = "1.0.1", features = ["unstable"] }
41+
async-std = { version = "1.4.0", features = ["unstable"] }
4242
mime = "0.3.14"
4343
cookie = { version="0.12.0", features = ["percent-encode"]}
44+
futures-core = "0.3.1"
45+
futures = { version = "0.3.1", optional = true }
46+
hyper = { version = "0.13.2", optional = true }
47+
http = { version = "0.2.0", optional = true }
48+
tokio = { version = "0.2.13", optional = true }
49+
url = "2.1.1"
4450

4551
[dev-dependencies]
46-
async-std = { version = "1.0.1", features = ["unstable", "attributes"] }
52+
async-std = { version = "1.4.0", features = ["unstable", "attributes"] }
4753
basic-cookies = "0.1.3"
4854
bytes = "0.4.12"
4955
futures-fs = "0.0.5"
5056
futures-util = { version = "0.3.0", features = ["compat"] }
51-
http-service-mock = "0.4.0"
57+
http-service-mock = { git = "https://github.com/dignifiedquire/http-service-1", branch = "h1" }
5258
juniper = "0.14.1"
5359
mime = "0.3.14"
5460
mime_guess = "2.0.1"
5561
percent-encoding = "2.1.0"
5662
serde = { version = "1.0.102", features = ["derive"] }
5763
structopt = "0.3.3"
58-
surf = "1.0.3"
64+
surf = { git = "https://github.com/dignifiedquire/surf-1", branch = "h1" }
65+
futures = "0.3.1"
5966

6067
[[test]]
6168
name = "nested"

examples/cookies.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use async_std::task;
22
use cookie::Cookie;
3+
use http_types::StatusCode;
34
use tide::{Request, Response};
45

56
/// Tide will use the the `Cookies`'s `Extract` implementation to build this parameter.
@@ -9,13 +10,13 @@ async fn retrieve_cookie(cx: Request<()>) -> String {
910
}
1011

1112
async fn set_cookie(_req: Request<()>) -> Response {
12-
let mut res = tide::Response::new(200);
13+
let mut res = tide::Response::new(StatusCode::Ok);
1314
res.set_cookie(Cookie::new("hello", "world"));
1415
res
1516
}
1617

1718
async fn remove_cookie(_req: Request<()>) -> Response {
18-
let mut res = tide::Response::new(200);
19+
let mut res = tide::Response::new(StatusCode::Ok);
1920
res.remove_cookie(Cookie::named("hello"));
2021
res
2122
}

examples/graphql.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use async_std::task;
2+
use http_types::StatusCode;
23
use juniper::RootNode;
34
use std::sync::RwLock;
45
use tide::{Request, Response, Server};
@@ -80,17 +81,21 @@ async fn handle_graphql(mut cx: Request<State>) -> Response {
8081

8182
let schema = create_schema(); // probably worth making the schema a singleton using lazy_static library
8283
let response = query.execute(&schema, cx.state());
83-
let status = if response.is_ok() { 200 } else { 400 };
84+
let status = if response.is_ok() {
85+
StatusCode::Ok
86+
} else {
87+
StatusCode::BadRequest
88+
};
8489

8590
Response::new(status)
8691
.body_json(&response)
8792
.expect("be able to serialize the graphql response")
8893
}
8994

9095
async fn handle_graphiql(_: Request<State>) -> Response {
91-
Response::new(200)
96+
Response::new(StatusCode::Ok)
9297
.body_string(juniper::http::graphiql::graphiql_source("/graphql"))
93-
.set_header("content-type", "text/html;charset=utf-8")
98+
.set_header("content-type".parse().unwrap(), "text/html;charset=utf-8")
9499
}
95100

96101
fn main() -> std::io::Result<()> {

examples/json.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use async_std::io;
22
use async_std::task;
3+
use http_types::StatusCode;
34
use serde::{Deserialize, Serialize};
45

56
#[derive(Deserialize, Serialize)]
@@ -19,7 +20,8 @@ fn main() -> io::Result<()> {
1920
let cat = Cat {
2021
name: "chashu".into(),
2122
};
22-
tide::Response::new(200).body_json(&cat).unwrap()
23+
24+
tide::Response::new(StatusCode::Ok).body_json(&cat).unwrap()
2325
});
2426

2527
app.listen("127.0.0.1:8080").await?;

src/error.rs

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,28 @@
11
//! Tide error types.
2-
use http::{HttpTryFrom, StatusCode};
3-
use http_service::Body;
2+
use http_types::StatusCode;
43

54
use crate::response::{IntoResponse, Response};
65

76
/// A specialized Result type for Tide.
87
pub type Result<T = Response> = std::result::Result<T, Error>;
98

10-
/// A generic error.
11-
#[derive(Debug)]
12-
pub struct Error {
13-
resp: Response,
14-
}
15-
16-
impl IntoResponse for Error {
17-
fn into_response(self) -> Response {
18-
self.resp
19-
}
20-
}
21-
22-
struct Cause(Box<dyn std::error::Error + Send + Sync>);
9+
/// Error type.
10+
pub use http_types::Error;
2311

2412
impl From<Response> for Error {
2513
fn from(resp: Response) -> Error {
26-
Error { resp }
14+
Error::from_str(resp.status(), "")
2715
}
2816
}
2917

30-
impl From<StatusCode> for Error {
31-
fn from(status: StatusCode) -> Error {
32-
Error {
33-
resp: Response::new(status.as_u16()),
34-
}
18+
impl IntoResponse for Error {
19+
fn into_response(self) -> Response {
20+
Response::new(self.status())
21+
.set_header(
22+
http_types::headers::CONTENT_TYPE,
23+
"text/plain; charset=utf-8",
24+
)
25+
.body_string(self.to_string())
3526
}
3627
}
3728

@@ -54,34 +45,22 @@ pub trait ResultExt<T>: Sized {
5445
/// Convert to an `Result`, treating the `Err` case as a client
5546
/// error (response code 400).
5647
fn client_err(self) -> Result<T> {
57-
self.with_err_status(400)
48+
self.with_err_status(StatusCode::BadRequest)
5849
}
5950

6051
/// Convert to an `Result`, treating the `Err` case as a server
6152
/// error (response code 500).
6253
fn server_err(self) -> Result<T> {
63-
self.with_err_status(500)
54+
self.with_err_status(StatusCode::InternalServerError)
6455
}
6556

6657
/// Convert to an `Result`, wrapping the `Err` case with a custom
6758
/// response status.
68-
fn with_err_status<S>(self, status: S) -> Result<T>
69-
where
70-
StatusCode: HttpTryFrom<S>;
59+
fn with_err_status(self, status: StatusCode) -> Result<T>;
7160
}
7261

7362
impl<T, E: std::error::Error + Send + Sync + 'static> ResultExt<T> for std::result::Result<T, E> {
74-
fn with_err_status<S>(self, status: S) -> Result<T>
75-
where
76-
StatusCode: HttpTryFrom<S>,
77-
{
78-
self.map_err(|e| Error {
79-
resp: http::Response::builder()
80-
.status(status)
81-
.extension(Cause(Box::new(e)))
82-
.body(Body::empty())
83-
.unwrap()
84-
.into(),
85-
})
63+
fn with_err_status(self, status: StatusCode) -> Result<T> {
64+
self.map_err(|err| Error::new(status, err))
8665
}
8766
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
//! let mut counter: Counter = req.body_json().await.unwrap();
5252
//! println!("count is {}", counter.count);
5353
//! counter.count += 1;
54-
//! tide::Response::new(200).body_json(&counter).unwrap()
54+
//! tide::Response::new(http_types::StatusCode::Ok).body_json(&counter).unwrap()
5555
//! });
5656
//! app.listen("127.0.0.1:8080").await?;
5757
//! #
@@ -197,7 +197,7 @@ pub use response::{IntoResponse, Response};
197197
#[doc(inline)]
198198
pub use server::{Route, Server};
199199

200-
pub use http;
200+
pub use http_types;
201201

202202
/// Create a new Tide server.
203203
///

src/middleware/cookies.rs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1+
use crate::utils::BoxFuture;
12
use crate::{
23
middleware::{Middleware, Next},
34
response::CookieEvent,
45
Request, Response,
56
};
6-
use cookie::{Cookie, CookieJar, ParseError};
7-
use futures::future::BoxFuture;
7+
use cookie::CookieJar;
8+
use http_types::headers;
89

9-
use http::HeaderMap;
1010
use std::sync::{Arc, RwLock};
1111

1212
/// A middleware for making cookie data available in requests.
@@ -17,7 +17,7 @@ use std::sync::{Arc, RwLock};
1717
/// let mut app = tide::Server::new();
1818
/// app.at("/get").get(|cx: tide::Request<()>| async move { cx.cookie("testCookie").unwrap().value().to_string() });
1919
/// app.at("/set").get(|_| async {
20-
/// let mut res = tide::Response::new(200);
20+
/// let mut res = tide::Response::new(http_types::StatusCode::Ok);
2121
/// res.set_cookie(cookie::Cookie::new("testCookie", "NewCookieValue"));
2222
/// res
2323
/// });
@@ -43,7 +43,7 @@ impl<State: Send + Sync + 'static> Middleware<State> for CookiesMiddleware {
4343
cookie_data.content.clone()
4444
} else {
4545
// no cookie data in local context, so we need to create it
46-
let cookie_data = CookieData::from_headers(ctx.headers());
46+
let cookie_data = CookieData::from_request(&ctx);
4747
let content = cookie_data.content.clone();
4848
ctx = ctx.set_local(cookie_data);
4949
content
@@ -63,9 +63,8 @@ impl<State: Send + Sync + 'static> Middleware<State> for CookiesMiddleware {
6363

6464
// iterate over added and removed cookies
6565
for cookie in cookie_jar.read().unwrap().delta() {
66-
let set_cookie_header = http::header::SET_COOKIE.as_ref();
6766
let encoded_cookie = cookie.encoded().to_string();
68-
res = res.append_header(set_cookie_header, encoded_cookie);
67+
res = res.append_header(headers::SET_COOKIE, encoded_cookie);
6968
}
7069
res
7170
})
@@ -78,23 +77,14 @@ pub(crate) struct CookieData {
7877
}
7978

8079
impl CookieData {
81-
pub(crate) fn from_headers(headers: &HeaderMap) -> Self {
82-
let cookie_header = headers.get(http::header::COOKIE);
83-
let cookie_jar = cookie_header.and_then(|raw| {
80+
pub(crate) fn from_request<S>(req: &Request<S>) -> Self {
81+
let cookie_jar = req.request.cookies().and_then(|cookies| {
8482
let mut jar = CookieJar::new();
85-
86-
// as long as we have an ascii string this will start parsing the cookie
87-
if let Some(raw_str) = raw.to_str().ok() {
88-
raw_str
89-
.split(';')
90-
.try_for_each(|s| -> Result<_, ParseError> {
91-
jar.add_original(Cookie::parse(s.trim().to_owned())?);
92-
Ok(())
93-
})
94-
.ok()?;
83+
for cookie in cookies.into_iter() {
84+
jar.add_original(cookie.into_owned());
9585
}
9686

97-
Some(jar)
87+
Ok(jar)
9888
});
9989
let content = Arc::new(RwLock::new(cookie_jar.unwrap_or_default()));
10090

0 commit comments

Comments
 (0)