From d67ec8f0857c5dac4fb779b68ef06b2d6d52c3d0 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 13 May 2019 21:03:16 +0530 Subject: [PATCH 01/95] isolate core revamp fix cargo fmt loosen up clippy to warnings on examples snipe dev deps from core eliminate some clippy warnings for examples add publish false, and remove publish requirements rename tide-examples to just examples --- Cargo.toml | 65 ++----------------- examples/Cargo.toml | 46 +++++++++++++ examples/{ => src}/body_types.rs | 4 +- examples/{ => src}/catch_all.rs | 4 +- examples/{ => src}/cookies.rs | 5 +- examples/{ => src}/default_headers.rs | 4 +- examples/{ => src}/graphql.rs | 5 +- examples/{ => src}/hello.rs | 4 +- examples/src/lib.rs | 13 ++++ examples/{ => src}/messages.rs | 4 +- .../main.rs => src/multipart_form/mod.rs} | 4 +- .../multipart_form}/test.txt | 0 examples/{ => src}/staticfile.rs | 6 +- tide/Cargo.toml | 52 +++++++++++++++ {src => tide/src}/app.rs | 0 {src => tide/src}/context.rs | 0 {src => tide/src}/cookies.rs | 0 {src => tide/src}/endpoint.rs | 0 {src => tide/src}/error.rs | 0 {src => tide/src}/forms.rs | 0 {src => tide/src}/lib.rs | 0 {src => tide/src}/middleware/cookies.rs | 0 .../src}/middleware/default_headers.rs | 0 {src => tide/src}/middleware/logger.rs | 0 {src => tide/src}/middleware/mod.rs | 0 {src => tide/src}/querystring.rs | 0 {src => tide/src}/response.rs | 0 {src => tide/src}/route.rs | 0 {src => tide/src}/router.rs | 0 {tests => tide/tests}/wildcard.rs | 0 30 files changed, 125 insertions(+), 91 deletions(-) create mode 100644 examples/Cargo.toml rename examples/{ => src}/body_types.rs (97%) rename examples/{ => src}/catch_all.rs (88%) rename examples/{ => src}/cookies.rs (95%) rename examples/{ => src}/default_headers.rs (89%) rename examples/{ => src}/graphql.rs (98%) rename examples/{ => src}/hello.rs (77%) create mode 100644 examples/src/lib.rs rename examples/{ => src}/messages.rs (98%) rename examples/{multipart-form/main.rs => src/multipart_form/mod.rs} (98%) rename examples/{multipart-form => src/multipart_form}/test.txt (100%) rename examples/{ => src}/staticfile.rs (98%) create mode 100644 tide/Cargo.toml rename {src => tide/src}/app.rs (100%) rename {src => tide/src}/context.rs (100%) rename {src => tide/src}/cookies.rs (100%) rename {src => tide/src}/endpoint.rs (100%) rename {src => tide/src}/error.rs (100%) rename {src => tide/src}/forms.rs (100%) rename {src => tide/src}/lib.rs (100%) rename {src => tide/src}/middleware/cookies.rs (100%) rename {src => tide/src}/middleware/default_headers.rs (100%) rename {src => tide/src}/middleware/logger.rs (100%) rename {src => tide/src}/middleware/mod.rs (100%) rename {src => tide/src}/querystring.rs (100%) rename {src => tide/src}/response.rs (100%) rename {src => tide/src}/route.rs (100%) rename {src => tide/src}/router.rs (100%) rename {tests => tide/tests}/wildcard.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index d90daaea7..78f2f7172 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,65 +1,8 @@ -[package] -authors = [ - "Aaron Turon ", - "Yoshua Wuyts ", +[workspace] +members = [ + "tide", + "examples", ] -description = "WIP modular web framework" -documentation = "https://docs.rs/tide" -keywords = ["tide", "http", "web", "framework", "async"] -categories = [ - "network-programming", - "asynchronous", - "web-programming::http-server" -] -edition = "2018" -license = "MIT OR Apache-2.0" -name = "tide" -readme = "README.md" -repository = "https://github.com/rustasync/tide" -version = "0.2.0" - -[dependencies] -cookie = { version = "0.12", features = ["percent-encode"] } -futures-preview = "0.3.0-alpha.16" -fnv = "1.0.6" -http = "0.1" -http-service = "0.2.0" -pin-utils = "0.1.0-alpha.4" -route-recognizer = "0.1.12" -serde = "1.0.91" -serde_derive = "1.0.91" -serde_json = "1.0.39" -slog = "2.4.1" -slog-async = "2.3.0" -slog-term = "2.4.0" -typemap = "0.3.3" -serde_urlencoded = "0.5.5" - -[dependencies.http-service-hyper] -optional = true -version = "0.2.0" - -[dependencies.multipart] -default-features = false -features = ["server"] -version = "0.16.1" - -[features] -default = ["hyper"] -hyper = ["http-service-hyper"] - -[dev-dependencies] -basic-cookies = "0.1.3" -bytes = "0.4.12" -futures-fs = "0.0.5" -futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } -http-service-mock = "0.2.0" -juniper = "0.11.1" -mime = "0.3.13" -mime_guess = "2.0.0-alpha.6" -percent-encoding = "1.0.1" -serde = { version = "1.0.90", features = ["derive"] } -structopt = "0.2.15" [patch.crates-io] http-service = { git = "https://github.com/rustasync/http-service", branch = "master" } diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 000000000..54a73b1ff --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,46 @@ +[package] +authors = [ + "Tide Developers", +] +description = "Tide web server examples" +documentation = "https://docs.rs/tide" +edition = "2018" +license = "MIT OR Apache-2.0" +name = "examples" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" +publish = false + +[dependencies] +tide = { path = "../tide" } +cookie = { version = "0.12", features = ["percent-encode"] } +futures-preview = "0.3.0-alpha.16" +fnv = "1.0.6" +http = "0.1" +http-service = "0.2.0" +pin-utils = "0.1.0-alpha.4" +route-recognizer = "0.1.12" +serde_json = "1.0.39" +slog = "2.4.1" +slog-async = "2.3.0" +slog-term = "2.4.0" +typemap = "0.3.3" +serde_urlencoded = "0.5.5" +basic-cookies = "0.1.3" +bytes = "0.4.12" +futures-fs = "0.0.5" +futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } +http-service-mock = "0.2.0" +juniper = "0.11.1" +mime = "0.3.13" +mime_guess = "2.0.0-alpha.6" +percent-encoding = "1.0.1" +serde = { version = "1.0.91", features = ["derive"] } +structopt = "0.2.15" + +[dependencies.multipart] +default-features = false +features = ["server"] +version = "0.16.1" + diff --git a/examples/body_types.rs b/examples/src/body_types.rs similarity index 97% rename from examples/body_types.rs rename to examples/src/body_types.rs index 01c9b393c..0cc0e66a1 100644 --- a/examples/body_types.rs +++ b/examples/src/body_types.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use serde::{Deserialize, Serialize}; use tide::{ error::ResultExt, @@ -41,7 +39,7 @@ async fn echo_form(mut cx: Context<()>) -> EndpointResult { Ok(forms::form(msg)) } -fn main() { +pub fn main() { let mut app = App::new(); app.at("/echo/string").post(echo_string); diff --git a/examples/catch_all.rs b/examples/src/catch_all.rs similarity index 88% rename from examples/catch_all.rs rename to examples/src/catch_all.rs index 354ddbb03..69947f1f7 100644 --- a/examples/catch_all.rs +++ b/examples/src/catch_all.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use tide::Context; async fn echo_path(cx: Context<()>) -> String { @@ -7,7 +5,7 @@ async fn echo_path(cx: Context<()>) -> String { format!("Your path is: {}", path) } -fn main() { +pub fn main() { let mut app = tide::App::new(); app.at("/echo_path/*path").get(echo_path); app.serve("127.0.0.1:8000").unwrap(); diff --git a/examples/cookies.rs b/examples/src/cookies.rs similarity index 95% rename from examples/cookies.rs rename to examples/src/cookies.rs index 094030f27..4ebff0738 100644 --- a/examples/cookies.rs +++ b/examples/src/cookies.rs @@ -1,10 +1,7 @@ -#![feature(async_await)] - use cookie::Cookie; use tide::{cookies::ContextExt, middleware::CookiesMiddleware, Context}; /// Tide will use the the `Cookies`'s `Extract` implementation to build this parameter. -/// async fn retrieve_cookie(mut cx: Context<()>) -> String { format!("hello cookies: {:?}", cx.get_cookie("hello").unwrap()) } @@ -19,7 +16,7 @@ async fn remove_cookie(mut cx: Context<()>) { cx.remove_cookie(Cookie::named("hello")).unwrap(); } -fn main() { +pub fn main() { let mut app = tide::App::new(); app.middleware(CookiesMiddleware::new()); diff --git a/examples/default_headers.rs b/examples/src/default_headers.rs similarity index 89% rename from examples/default_headers.rs rename to examples/src/default_headers.rs index 47f13a091..23f057e30 100644 --- a/examples/default_headers.rs +++ b/examples/src/default_headers.rs @@ -1,8 +1,6 @@ -#![feature(async_await)] - use tide::middleware::DefaultHeaders; -fn main() { +pub fn main() { let mut app = tide::App::new(); app.middleware( diff --git a/examples/graphql.rs b/examples/src/graphql.rs similarity index 98% rename from examples/graphql.rs rename to examples/src/graphql.rs index aeb9abfdf..7a263cbcf 100644 --- a/examples/graphql.rs +++ b/examples/src/graphql.rs @@ -2,9 +2,6 @@ // a look at [the Juniper book]. // // [the Juniper book]: https://graphql-rust.github.io/ - -#![feature(async_await)] - use http::status::StatusCode; use juniper::graphql_object; use std::sync::{atomic, Arc}; @@ -59,7 +56,7 @@ async fn handle_graphql(mut cx: Context) -> EndpointResult { Ok(resp) } -fn main() { +pub fn main() { let mut app = App::with_state(Data::default()); app.at("/graphql").post(handle_graphql); app.serve("127.0.0.1:8000").unwrap(); diff --git a/examples/hello.rs b/examples/src/hello.rs similarity index 77% rename from examples/hello.rs rename to examples/src/hello.rs index 030d394c1..83e246463 100644 --- a/examples/hello.rs +++ b/examples/src/hello.rs @@ -1,6 +1,4 @@ -#![feature(async_await)] - -fn main() { +pub fn main() { let mut app = tide::App::new(); app.at("/").get(async move |_| "Hello, world!"); app.serve("127.0.0.1:8000").unwrap(); diff --git a/examples/src/lib.rs b/examples/src/lib.rs new file mode 100644 index 000000000..31679fc28 --- /dev/null +++ b/examples/src/lib.rs @@ -0,0 +1,13 @@ +#![feature(async_await)] +#![warn(clippy::all)] +#![allow(dead_code)] + +mod body_types; +mod catch_all; +mod cookies; +mod default_headers; +mod graphql; +mod hello; +mod messages; +mod multipart_form; +mod staticfile; diff --git a/examples/messages.rs b/examples/src/messages.rs similarity index 98% rename from examples/messages.rs rename to examples/src/messages.rs index 7b8ef25dd..3ec8db93e 100644 --- a/examples/messages.rs +++ b/examples/src/messages.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use http::status::StatusCode; use serde::{Deserialize, Serialize}; use std::sync::Mutex; @@ -66,7 +64,7 @@ async fn get_message(cx: Context) -> EndpointResult { } } -fn main() { +pub fn main() { let mut app = App::with_state(Database::default()); app.at("/message").post(new_message); app.at("/message/:id").get(get_message).post(set_message); diff --git a/examples/multipart-form/main.rs b/examples/src/multipart_form/mod.rs similarity index 98% rename from examples/multipart-form/main.rs rename to examples/src/multipart_form/mod.rs index 14ca63639..fd3485b12 100644 --- a/examples/multipart-form/main.rs +++ b/examples/src/multipart_form/mod.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use serde::{Deserialize, Serialize}; use std::io::Read; use tide::{forms::ExtractForms, response, App, Context, EndpointResult}; @@ -57,7 +55,7 @@ async fn upload_file(mut cx: Context<()>) -> EndpointResult { Ok(response::json(message)) } -fn main() { +pub fn run() { let mut app = App::new(); app.at("/upload_file").post(upload_file); app.serve("127.0.0.1:8000").unwrap(); diff --git a/examples/multipart-form/test.txt b/examples/src/multipart_form/test.txt similarity index 100% rename from examples/multipart-form/test.txt rename to examples/src/multipart_form/test.txt diff --git a/examples/staticfile.rs b/examples/src/staticfile.rs similarity index 98% rename from examples/staticfile.rs rename to examples/src/staticfile.rs index 462a1f4bd..63524b36b 100644 --- a/examples/staticfile.rs +++ b/examples/src/staticfile.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use bytes::Bytes; use futures_fs::FsPool; use futures_util::compat::*; @@ -44,7 +42,7 @@ impl StaticFile { // Check if the path exists and handle if it's a directory containing `index.html` if meta.is_some() && meta.as_ref().map(|m| !m.is_file()).unwrap_or(false) { // Redirect if path is a dir and URL doesn't end with "/" - if !actual_path.ends_with("/") { + if !actual_path.ends_with('/') { return Ok(response .status(StatusCode::MOVED_PERMANENTLY) .header(header::LOCATION, String::from(actual_path) + "/") @@ -121,7 +119,7 @@ async fn handle_path(ctx: Context) -> EndpointResult { }) } -fn main() { +pub fn main() { let mut app = App::with_state(StaticFile::new("./")); app.at("/*").get(handle_path); app.serve("127.0.0.1:8000").unwrap(); diff --git a/tide/Cargo.toml b/tide/Cargo.toml new file mode 100644 index 000000000..9e70bf5ea --- /dev/null +++ b/tide/Cargo.toml @@ -0,0 +1,52 @@ +[package] +authors = [ + "Aaron Turon ", + "Yoshua Wuyts ", +] +description = "WIP modular web framework" +documentation = "https://docs.rs/tide" +keywords = ["tide", "http", "web", "framework", "async"] +categories = [ + "network-programming", + "asynchronous", + "web-programming::http-server" +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.2.0" + +[dependencies] +cookie = { version = "0.12", features = ["percent-encode"] } +futures-preview = "0.3.0-alpha.16" +fnv = "1.0.6" +http = "0.1" +http-service = "0.2.0" +pin-utils = "0.1.0-alpha.4" +route-recognizer = "0.1.12" +serde = "1.0.91" +serde_derive = "1.0.91" +serde_json = "1.0.39" +slog = "2.4.1" +slog-async = "2.3.0" +slog-term = "2.4.0" +typemap = "0.3.3" +serde_urlencoded = "0.5.5" + +[dependencies.http-service-hyper] +optional = true +version = "0.2.0" + +[dependencies.multipart] +default-features = false +features = ["server"] +version = "0.16.1" + +[features] +default = ["hyper"] +hyper = ["http-service-hyper"] + +[dev-dependencies] +http-service-mock = "0.2.0" diff --git a/src/app.rs b/tide/src/app.rs similarity index 100% rename from src/app.rs rename to tide/src/app.rs diff --git a/src/context.rs b/tide/src/context.rs similarity index 100% rename from src/context.rs rename to tide/src/context.rs diff --git a/src/cookies.rs b/tide/src/cookies.rs similarity index 100% rename from src/cookies.rs rename to tide/src/cookies.rs diff --git a/src/endpoint.rs b/tide/src/endpoint.rs similarity index 100% rename from src/endpoint.rs rename to tide/src/endpoint.rs diff --git a/src/error.rs b/tide/src/error.rs similarity index 100% rename from src/error.rs rename to tide/src/error.rs diff --git a/src/forms.rs b/tide/src/forms.rs similarity index 100% rename from src/forms.rs rename to tide/src/forms.rs diff --git a/src/lib.rs b/tide/src/lib.rs similarity index 100% rename from src/lib.rs rename to tide/src/lib.rs diff --git a/src/middleware/cookies.rs b/tide/src/middleware/cookies.rs similarity index 100% rename from src/middleware/cookies.rs rename to tide/src/middleware/cookies.rs diff --git a/src/middleware/default_headers.rs b/tide/src/middleware/default_headers.rs similarity index 100% rename from src/middleware/default_headers.rs rename to tide/src/middleware/default_headers.rs diff --git a/src/middleware/logger.rs b/tide/src/middleware/logger.rs similarity index 100% rename from src/middleware/logger.rs rename to tide/src/middleware/logger.rs diff --git a/src/middleware/mod.rs b/tide/src/middleware/mod.rs similarity index 100% rename from src/middleware/mod.rs rename to tide/src/middleware/mod.rs diff --git a/src/querystring.rs b/tide/src/querystring.rs similarity index 100% rename from src/querystring.rs rename to tide/src/querystring.rs diff --git a/src/response.rs b/tide/src/response.rs similarity index 100% rename from src/response.rs rename to tide/src/response.rs diff --git a/src/route.rs b/tide/src/route.rs similarity index 100% rename from src/route.rs rename to tide/src/route.rs diff --git a/src/router.rs b/tide/src/router.rs similarity index 100% rename from src/router.rs rename to tide/src/router.rs diff --git a/tests/wildcard.rs b/tide/tests/wildcard.rs similarity index 100% rename from tests/wildcard.rs rename to tide/tests/wildcard.rs From a376d602eebf30afacf4f4be4284c0e09c1dfe53 Mon Sep 17 00:00:00 2001 From: dalei Date: Wed, 15 May 2019 11:06:20 +0800 Subject: [PATCH 02/95] Fix example link in readme --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 548b64ba2..6ed6885f2 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,14 @@ fn main() -> Result<(), std::io::Error> { **More Examples** -- [Hello World](https://github.com/rustasync/tide/tree/master/examples/hello.rs) -- [Messages](https://github.com/rustasync/tide/blob/master/examples/messages.rs) -- [Body Types](https://github.com/rustasync/tide/blob/master/examples/body_types.rs) -- [Multipart Form](https://github.com/rustasync/tide/tree/master/examples/multipart-form/main.rs) -- [Catch All](https://github.com/rustasync/tide/tree/master/examples/catch_all.rs) -- [Cookies](https://github.com/rustasync/tide/tree/master/examples/cookies.rs) -- [Default Headers](https://github.com/rustasync/tide/tree/master/examples/default_headers.rs) -- [GraphQL](https://github.com/rustasync/tide/tree/master/examples/graphql.rs) +- [Hello World](https://github.com/rustasync/tide/tree/master/examples/src/hello.rs) +- [Messages](https://github.com/rustasync/tide/blob/master/examples/src/messages.rs) +- [Body Types](https://github.com/rustasync/tide/blob/master/examples/src/body_types.rs) +- [Multipart Form](https://github.com/rustasync/tide/tree/master/examples/src/multipart-form/main.rs) +- [Catch All](https://github.com/rustasync/tide/tree/master/examples/src/catch_all.rs) +- [Cookies](https://github.com/rustasync/tide/tree/master/examples/src/cookies.rs) +- [Default Headers](https://github.com/rustasync/tide/tree/master/src/examples/default_headers.rs) +- [GraphQL](https://github.com/rustasync/tide/tree/master/examples/src/graphql.rs) ## Resources From be577efc069a2c34332f475e6493f9ee67e2ddc4 Mon Sep 17 00:00:00 2001 From: "Prasanna V. Loganathar" Date: Wed, 15 May 2019 09:19:38 +0530 Subject: [PATCH 03/95] fix broken links in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6ed6885f2..043de727f 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,12 @@ fn main() -> Result<(), std::io::Error> { **More Examples** - [Hello World](https://github.com/rustasync/tide/tree/master/examples/src/hello.rs) -- [Messages](https://github.com/rustasync/tide/blob/master/examples/src/messages.rs) -- [Body Types](https://github.com/rustasync/tide/blob/master/examples/src/body_types.rs) -- [Multipart Form](https://github.com/rustasync/tide/tree/master/examples/src/multipart-form/main.rs) +- [Messages](https://github.com/rustasync/tide/tree/master/examples/src/messages.rs) +- [Body Types](https://github.com/rustasync/tide/tree/master/examples/src/body_types.rs) +- [Multipart Form](https://github.com/rustasync/tide/tree/master/examples/src/multipart_form/mod.rs) - [Catch All](https://github.com/rustasync/tide/tree/master/examples/src/catch_all.rs) - [Cookies](https://github.com/rustasync/tide/tree/master/examples/src/cookies.rs) -- [Default Headers](https://github.com/rustasync/tide/tree/master/src/examples/default_headers.rs) +- [Default Headers](https://github.com/rustasync/tide/tree/master/examples/src/default_headers.rs) - [GraphQL](https://github.com/rustasync/tide/tree/master/examples/src/graphql.rs) ## Resources From f4473d6489f461c92dd387d3a42fbc6d92e16b68 Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Wed, 15 May 2019 14:53:04 +0900 Subject: [PATCH 04/95] Rename `serve` to `run`, add asynchronous `serve` --- README.md | 2 +- examples/src/body_types.rs | 2 +- examples/src/catch_all.rs | 2 +- examples/src/cookies.rs | 2 +- examples/src/default_headers.rs | 2 +- examples/src/graphql.rs | 2 +- examples/src/hello.rs | 2 +- examples/src/messages.rs | 2 +- examples/src/multipart_form/mod.rs | 2 +- examples/src/staticfile.rs | 2 +- tide/src/app.rs | 23 ++++++++++++++++++----- tide/src/endpoint.rs | 4 ++-- 12 files changed, 30 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 043de727f..124409d03 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Ecosystem WG, and **not ready for production use yet**. fn main() -> Result<(), std::io::Error> { let mut app = tide::App::new(); app.at("/").get(async move |_| "Hello, world!"); - Ok(app.serve("127.0.0.1:8000")?) + Ok(app.run("127.0.0.1:8000")?) } ``` diff --git a/examples/src/body_types.rs b/examples/src/body_types.rs index 0cc0e66a1..9df1509a5 100644 --- a/examples/src/body_types.rs +++ b/examples/src/body_types.rs @@ -47,5 +47,5 @@ pub fn main() { app.at("/echo/json").post(echo_json); app.at("/echo/form").post(echo_form); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/src/catch_all.rs b/examples/src/catch_all.rs index 69947f1f7..ebdf736c3 100644 --- a/examples/src/catch_all.rs +++ b/examples/src/catch_all.rs @@ -8,5 +8,5 @@ async fn echo_path(cx: Context<()>) -> String { pub fn main() { let mut app = tide::App::new(); app.at("/echo_path/*path").get(echo_path); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/src/cookies.rs b/examples/src/cookies.rs index 4ebff0738..a43dc67c1 100644 --- a/examples/src/cookies.rs +++ b/examples/src/cookies.rs @@ -23,5 +23,5 @@ pub fn main() { app.at("/").get(retrieve_cookie); app.at("/set").get(set_cookie); app.at("/remove").get(remove_cookie); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/src/default_headers.rs b/examples/src/default_headers.rs index 23f057e30..b76bfddc7 100644 --- a/examples/src/default_headers.rs +++ b/examples/src/default_headers.rs @@ -11,5 +11,5 @@ pub fn main() { app.at("/").get(async move |_| "Hello, world!"); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/src/graphql.rs b/examples/src/graphql.rs index 7a263cbcf..a85af2e69 100644 --- a/examples/src/graphql.rs +++ b/examples/src/graphql.rs @@ -59,5 +59,5 @@ async fn handle_graphql(mut cx: Context) -> EndpointResult { pub fn main() { let mut app = App::with_state(Data::default()); app.at("/graphql").post(handle_graphql); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/src/hello.rs b/examples/src/hello.rs index 83e246463..1a11e05c9 100644 --- a/examples/src/hello.rs +++ b/examples/src/hello.rs @@ -1,5 +1,5 @@ pub fn main() { let mut app = tide::App::new(); app.at("/").get(async move |_| "Hello, world!"); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/src/messages.rs b/examples/src/messages.rs index 3ec8db93e..4cf905f79 100644 --- a/examples/src/messages.rs +++ b/examples/src/messages.rs @@ -68,5 +68,5 @@ pub fn main() { let mut app = App::with_state(Database::default()); app.at("/message").post(new_message); app.at("/message/:id").get(get_message).post(set_message); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/src/multipart_form/mod.rs b/examples/src/multipart_form/mod.rs index fd3485b12..ce4d74ca3 100644 --- a/examples/src/multipart_form/mod.rs +++ b/examples/src/multipart_form/mod.rs @@ -58,7 +58,7 @@ async fn upload_file(mut cx: Context<()>) -> EndpointResult { pub fn run() { let mut app = App::new(); app.at("/upload_file").post(upload_file); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } // Test with: diff --git a/examples/src/staticfile.rs b/examples/src/staticfile.rs index 63524b36b..cf44ccd97 100644 --- a/examples/src/staticfile.rs +++ b/examples/src/staticfile.rs @@ -122,5 +122,5 @@ async fn handle_path(ctx: Context) -> EndpointResult { pub fn main() { let mut app = App::with_state(StaticFile::new("./")); app.at("/*").get(handle_path); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } diff --git a/tide/src/app.rs b/tide/src/app.rs index 7e4273036..83cd3f517 100644 --- a/tide/src/app.rs +++ b/tide/src/app.rs @@ -34,7 +34,7 @@ use crate::{ /// /// let mut app = tide::App::new(); /// app.at("/hello").get(async move |_| "Hello, world!"); -/// app.serve("127.0.0.1:8000"); +/// app.run("127.0.0.1:8000"); /// ``` /// /// # Routing and parameters @@ -67,7 +67,7 @@ use crate::{ /// "Use /hello/{your name} or /goodbye/{your name}" /// }); /// -/// app.serve("127.0.0.1:8000"); +/// app.run("127.0.0.1:8000"); /// ``` /// /// You can learn more about routing in the [`App::at`] documentation. @@ -123,7 +123,7 @@ use crate::{ /// let mut app = App::with_state(Database::default()); /// app.at("/message").post(new_message); /// app.at("/message/:id").get(get_message); -/// app.serve("127.0.0.1:8000").unwrap(); +/// app.run("127.0.0.1:8000").unwrap(); /// } /// ``` @@ -232,11 +232,11 @@ impl App { } } - /// Start serving the app at the given address. + /// Run the app at the given address. /// /// Blocks the calling thread indefinitely. #[cfg(feature = "hyper")] - pub fn serve(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> { + pub fn run(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> { let addr = addr .to_socket_addrs()? .next() @@ -246,6 +246,19 @@ impl App { http_service_hyper::run(self.into_http_service(), addr); Ok(()) } + + /// Asynchronously serve the app at the given address. + #[cfg(feature = "hyper")] + pub async fn serve(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> { + let addr = addr + .to_socket_addrs()? + .next() + .ok_or(std::io::ErrorKind::InvalidInput)?; + + // TODO: propagate the error from hyper + http_service_hyper::serve(self.into_http_service(), addr).await.ok(); + Ok(()) + } } /// An instantiated Tide server. diff --git a/tide/src/endpoint.rs b/tide/src/endpoint.rs index f4adbfcf8..8ec5e988b 100644 --- a/tide/src/endpoint.rs +++ b/tide/src/endpoint.rs @@ -28,7 +28,7 @@ use crate::{response::IntoResponse, Context, Response}; /// fn main() { /// let mut app = tide::App::new(); /// app.at("/hello").get(hello); -/// app.serve("127.0.0.1:8000").unwrap() +/// app.run("127.0.0.1:8000").unwrap() /// } /// ``` /// @@ -43,7 +43,7 @@ use crate::{response::IntoResponse, Context, Response}; /// fn main() { /// let mut app = tide::App::new(); /// app.at("/hello").get(hello); -/// app.serve("127.0.0.1:8000").unwrap() +/// app.run("127.0.0.1:8000").unwrap() /// } /// ``` /// From 6078fc40dcfb2e59a65573b94bc41851e15de71d Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Wed, 15 May 2019 15:06:25 +0900 Subject: [PATCH 05/95] Run rustfmt --- tide/src/app.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tide/src/app.rs b/tide/src/app.rs index 83cd3f517..91699dd38 100644 --- a/tide/src/app.rs +++ b/tide/src/app.rs @@ -256,7 +256,9 @@ impl App { .ok_or(std::io::ErrorKind::InvalidInput)?; // TODO: propagate the error from hyper - http_service_hyper::serve(self.into_http_service(), addr).await.ok(); + http_service_hyper::serve(self.into_http_service(), addr) + .await + .ok(); Ok(()) } } From 059a8f833c4e150a14950f16a9a3da079aa4111b Mon Sep 17 00:00:00 2001 From: grey Date: Tue, 14 May 2019 23:15:27 -0700 Subject: [PATCH 06/95] add tide-compression crate --- .travis.yml | 6 +- Cargo.toml | 1 + tide-compression/Cargo.toml | 30 ++ tide-compression/README.md | 16 ++ tide-compression/examples/simple.rs | 22 ++ tide-compression/src/lib.rs | 423 ++++++++++++++++++++++++++++ tide/src/context.rs | 5 + 7 files changed, 500 insertions(+), 3 deletions(-) create mode 100644 tide-compression/Cargo.toml create mode 100644 tide-compression/README.md create mode 100644 tide-compression/examples/simple.rs create mode 100644 tide-compression/src/lib.rs diff --git a/.travis.yml b/.travis.yml index 3e4d10906..7a662d4f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ before_script: | rustup component add rustfmt clippy script: | cargo fmt --all -- --check && - cargo clippy --all -- -D clippy::all && + cargo clippy --all --all-features -- -D clippy::all && cargo build --no-default-features --verbose && - cargo build --all --verbose && - cargo test --all --verbose + cargo build --all --all-features --verbose && + cargo test --all --all-features --verbose cache: cargo diff --git a/Cargo.toml b/Cargo.toml index 78f2f7172..6105ea9a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "tide", + "tide-compression", "examples", ] diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml new file mode 100644 index 000000000..19bb2c92c --- /dev/null +++ b/tide-compression/Cargo.toml @@ -0,0 +1,30 @@ +[package] +authors = [ + "Tide Developers", +] +description = "Compression-related middleware for Tide" +documentation = "https://docs.rs/tide-compression" +keywords = ["tide", "web", "async", "middleware", "compression"] +categories = ["network-programming", "compression", "asynchronous"] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide-compression" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" + +[dependencies] +tide = { path = "../tide" } +accept-encoding = "0.2.0-alpha.2" +bytes = "0.4.12" +futures-preview = "0.3.0-alpha.16" +http = "0.1" +http-service = "0.2.0" + +[dependencies.async-compression] +default-features = false +features = ["stream", "gzip", "zlib", "brotli", "zstd"] +version = "0.1.0-alpha.1" + +[dev-dependencies] +http-service-mock = "0.2.0" diff --git a/tide-compression/README.md b/tide-compression/README.md new file mode 100644 index 000000000..7f13f1f9f --- /dev/null +++ b/tide-compression/README.md @@ -0,0 +1,16 @@ +# tide-compression + +This crate provides compression-related middleware for Tide. + +## Examples + +Examples are in the `/examples` folder of this crate. + +__Simple Example__ + +You can test the simple example by running `cargo run --example simple` while in this crate's directory, and then running either of the following commands: + +```console +$ curl http://127.0.0.1:8000/ -v +$ curl http://127.0.0.1:8000/echo -v -d "why hello there" +``` diff --git a/tide-compression/examples/simple.rs b/tide-compression/examples/simple.rs new file mode 100644 index 000000000..981236353 --- /dev/null +++ b/tide-compression/examples/simple.rs @@ -0,0 +1,22 @@ +#![feature(async_await)] +use tide::{App, Context}; +use tide_compression::{Compression, Decompression, Encoding}; + +// Returns a portion of the lorem ipsum text. +async fn lorem_ipsum(_cx: Context<()>) -> String { + String::from("Lorem ipsum dolor sit amet, consectetur adipiscing elit.") +} + +// Echoes the request body in bytes. +async fn echo_bytes(mut cx: Context<()>) -> Vec { + cx.body_bytes().await.unwrap() +} + +pub fn main() { + let mut app = App::new(); + app.at("/").get(lorem_ipsum); + app.at("/echo").post(echo_bytes); + app.middleware(Compression::with_default(Encoding::Brotli)); + app.middleware(Decompression::new()); + app.serve("127.0.0.1:8000").unwrap(); +} diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs new file mode 100644 index 000000000..e0f88be3a --- /dev/null +++ b/tide-compression/src/lib.rs @@ -0,0 +1,423 @@ +#![cfg_attr(feature = "nightly", deny(missing_docs))] +#![cfg_attr(feature = "nightly", feature(external_doc))] +#![cfg_attr(feature = "nightly", doc(include = "../README.md"))] +#![cfg_attr(test, deny(warnings))] +#![feature(async_await)] +#![deny( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + +pub use accept_encoding::Encoding; +use async_compression::stream; +use futures::future::BoxFuture; +use http::{header::CONTENT_ENCODING, status::StatusCode, HeaderMap}; +use http_service::{Body, Request}; +use tide::{ + middleware::{Middleware, Next}, + response::IntoResponse, + Context, Error, Response, +}; + +macro_rules! box_async { + {$($t:tt)*} => { + ::futures::future::FutureExt::boxed(async move { $($t)* }) + }; +} + +/// Encode settings for the compression middleware. +/// +/// This can be modified in the case that you want more control over the speed or quality of compression. +/// +/// For more information on how to configure each of these settings, see the async-compression crate. +#[derive(Debug)] +pub struct EncodeSettings { + /// Settings for gzip compression. + pub gzip: async_compression::flate2::Compression, + /// Settings for deflate compression. + pub deflate: async_compression::flate2::Compression, + /// Settings for brotli compression. Ranges from 0-11. (default: `11`) + pub brotli: u32, + /// Settings for zstd compression. Ranges from 1-21. (default: `3`) + pub zstd: i32, +} + +impl Default for EncodeSettings { + fn default() -> Self { + Self { + gzip: Default::default(), + deflate: Default::default(), + brotli: 11, + zstd: 3, + } + } +} + +/// Middleware for automatically handling outgoing response compression. +/// +/// This middleware currently supports HTTP compression using `gzip`, `deflate`, `br`, and `zstd`. +#[derive(Debug)] +pub struct Compression { + default_encoding: Encoding, + settings: EncodeSettings, +} + +impl Default for Compression { + fn default() -> Self { + Self::new() + } +} + +impl Compression { + /// Creates a new Compression middleware. The default encoding is [`Encoding::Identity`] (no encoding). + pub fn new() -> Self { + Self { + default_encoding: Encoding::Identity, + settings: Default::default(), + } + } + + /// Creates a new Compression middleware with a provided default encoding. + /// + /// This encoding will be selected if the client has not set the `Accept-Encoding` header or `*` is set as the most preferred encoding. + pub fn with_default(default_encoding: Encoding) -> Self { + Self { + default_encoding, + settings: Default::default(), + } + } + + /// Accesses a mutable handle to this middleware's [`EncodeSettings`]. + /// + /// This will allow you to configure this middleware's settings. + pub fn settings_mut(&mut self) -> &mut EncodeSettings { + &mut self.settings + } + + fn preferred_encoding(&self, headers: &HeaderMap) -> Result { + let encoding = match accept_encoding::parse(headers) { + Ok(encoding) => encoding, + Err(_) => return Err(Error::from(StatusCode::BAD_REQUEST)), + }; + Ok(encoding.unwrap_or(self.default_encoding)) + } + + /// Consumes the response and returns an encoded version of it. + fn encode(&self, mut res: Response, encoding: Encoding) -> Response { + if res.headers().get(CONTENT_ENCODING).is_some() || encoding == Encoding::Identity { + return res; // avoid double-encoding a given response + } + let body = std::mem::replace(res.body_mut(), Body::empty()); + match encoding { + Encoding::Gzip => { + let stream = stream::GzipEncoder::new(body, self.settings.gzip); + *res.body_mut() = Body::from_stream(stream); + } + Encoding::Deflate => { + let stream = stream::ZlibEncoder::new(body, self.settings.deflate); + *res.body_mut() = Body::from_stream(stream); + } + Encoding::Brotli => { + let stream = stream::BrotliEncoder::new(body, self.settings.brotli); + *res.body_mut() = Body::from_stream(stream); + } + Encoding::Zstd => { + let stream = stream::ZstdEncoder::new(body, self.settings.zstd); + *res.body_mut() = Body::from_stream(stream); + } + Encoding::Identity => unreachable!(), + }; + res.headers_mut() + .append(CONTENT_ENCODING, encoding.to_header_value()); + res + } +} + +impl Middleware for Compression { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { + box_async! { + let encoding = match self.preferred_encoding(cx.headers()) { + Ok(encoding) => encoding, + Err(e) => return e.into_response(), + }; + let res = next.run(cx).await; + self.encode(res, encoding) + } + } +} + +/// Middleware for handling incoming request decompression. +/// +/// This middleware currently supports HTTP decompression under the `gzip`, `deflate`, `br`, and `zstd` algorithms. +#[derive(Debug, Default)] +pub struct Decompression {} + +impl Decompression { + /// Creates a new Decompression middleware. + pub fn new() -> Self { + Self {} + } + + fn parse_encoding(s: &str) -> Result { + match s { + "gzip" => Ok(Encoding::Gzip), + "deflate" => Ok(Encoding::Deflate), + "br" => Ok(Encoding::Brotli), + "zstd" => Ok(Encoding::Zstd), + "identity" => Ok(Encoding::Identity), + _ => Err(Error::from(StatusCode::UNSUPPORTED_MEDIA_TYPE)), + } + } + + fn decode(&self, req: &mut Request) -> Result<(), Error> { + let encodings = if let Some(hval) = req.headers().get(CONTENT_ENCODING) { + let hval = match hval.to_str() { + Ok(hval) => hval, + Err(_) => return Err(Error::from(StatusCode::BAD_REQUEST)), + }; + hval.split(',') + .map(str::trim) + .rev() // apply decodings in reverse order + .map(Decompression::parse_encoding) + .collect::, Error>>()? + } else { + return Ok(()); + }; + + for encoding in encodings { + match encoding { + Encoding::Gzip => { + let body = std::mem::replace(req.body_mut(), Body::empty()); + let stream = stream::GzipDecoder::new(body); + *req.body_mut() = Body::from_stream(stream); + } + Encoding::Deflate => { + let body = std::mem::replace(req.body_mut(), Body::empty()); + let stream = stream::ZlibDecoder::new(body); + *req.body_mut() = Body::from_stream(stream); + } + Encoding::Brotli => { + let body = std::mem::replace(req.body_mut(), Body::empty()); + let stream = stream::BrotliDecoder::new(body); + *req.body_mut() = Body::from_stream(stream); + } + Encoding::Zstd => { + let body = std::mem::replace(req.body_mut(), Body::empty()); + let stream = stream::ZstdDecoder::new(body); + *req.body_mut() = Body::from_stream(stream); + } + Encoding::Identity => (), + } + } + + // strip the content-encoding header + req.headers_mut().remove(CONTENT_ENCODING).unwrap(); + + Ok(()) + } +} + +impl Middleware for Decompression { + fn handle<'a>( + &'a self, + mut cx: Context, + next: Next<'a, Data>, + ) -> BoxFuture<'a, Response> { + box_async! { + match self.decode(cx.request_mut()) { + Ok(_) => (), + Err(e) => return e.into_response(), + }; + next.run(cx).await + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use async_compression::flate2; + use bytes::Bytes; + use futures::{ + executor::{block_on, block_on_stream}, + stream::StreamExt, + }; + use http::header::ACCEPT_ENCODING; + use http_service::Body; + use http_service_mock::make_server; + + async fn lorem_ipsum(_cx: Context<()>) -> String { + String::from(r#" + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rutrum et risus sed egestas. Maecenas dapibus enim a posuere + semper. Cras venenatis et turpis quis aliquam. Suspendisse eget risus in libero tristique consectetur. Ut ut risus cursus, scelerisque + enim ac, tempus tellus. Vestibulum ac porta felis. Aenean fringilla posuere felis, in blandit enim tristique ut. Sed elementum iaculis + enim eu commodo. + "#) + } + + fn lorem_ipsum_bytes() -> Vec { + String::from(r#" + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rutrum et risus sed egestas. Maecenas dapibus enim a posuere + semper. Cras venenatis et turpis quis aliquam. Suspendisse eget risus in libero tristique consectetur. Ut ut risus cursus, scelerisque + enim ac, tempus tellus. Vestibulum ac porta felis. Aenean fringilla posuere felis, in blandit enim tristique ut. Sed elementum iaculis + enim eu commodo. + "#).into_bytes() + } + + // Echoes the request body in bytes. + async fn echo_bytes(mut cx: Context<()>) -> Vec { + cx.body_bytes().await.unwrap() + } + + // Generates the app. + fn app() -> tide::App<()> { + let mut app = tide::App::new(); + app.at("/").get(lorem_ipsum); + app.at("/echo").post(echo_bytes); + app.middleware(Compression::new()); + app.middleware(Decompression::new()); + app + } + + // Generates a response given a string that represents the Accept-Encoding header value. + fn get_encoded_response(hval: &str) -> Response { + let app = app(); + let mut server = make_server(app.into_http_service()).unwrap(); + let req = http::Request::get("/") + .header(ACCEPT_ENCODING, hval) + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + res + } + + // Generates a decoded response given a request body and the header value representing its encoding. + fn get_decoded_response(body: Body, hval: &str) -> Response { + let app = app(); + let mut server = make_server(app.into_http_service()).unwrap(); + let req = http::Request::post("/echo") + .header(CONTENT_ENCODING, hval) + .body(body) + .unwrap(); + let res = server.simulate(req).unwrap(); + res + } + + #[test] + fn compressed_gzip_response() { + let res = get_encoded_response("gzip"); + assert_eq!(res.status(), 200); + let body = res.into_body(); + let stream = stream::GzipDecoder::new(body); + let decompressed_body: Vec = block_on_stream(stream) + .map(Result::unwrap) + .flatten() + .collect(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(decompressed_body, lorem_ipsum); + } + + #[test] + fn compressed_deflate_response() { + let res = get_encoded_response("deflate"); + assert_eq!(res.status(), 200); + let body = res.into_body(); + let stream = stream::ZlibDecoder::new(body); + let decompressed_body: Vec = block_on_stream(stream) + .map(Result::unwrap) + .flatten() + .collect(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(decompressed_body, lorem_ipsum); + } + + #[test] + fn compressed_brotli_response() { + let res = get_encoded_response("br"); + assert_eq!(res.status(), 200); + let body = res.into_body(); + let stream = stream::BrotliDecoder::new(body); + let decompressed_body: Vec = block_on_stream(stream) + .map(Result::unwrap) + .flatten() + .collect(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(decompressed_body, lorem_ipsum); + } + + #[test] + fn compressed_zstd_response() { + let res = get_encoded_response("zstd"); + assert_eq!(res.status(), 200); + let body = res.into_body(); + let stream = stream::ZstdDecoder::new(body); + let decompressed_body: Vec = block_on_stream(stream) + .map(Result::unwrap) + .flatten() + .collect(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(decompressed_body, lorem_ipsum); + } + + #[test] + fn decompressed_gzip_response() { + let lorem_ipsum = lorem_ipsum_bytes(); + let req_body = Body::from_stream(stream::GzipEncoder::new( + futures::stream::iter(vec![lorem_ipsum]) + .map(Bytes::from) + .map(Ok), + flate2::Compression::default(), + )); + let res = get_decoded_response(req_body, "gzip"); + let body = block_on(res.into_body().into_vec()).unwrap(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(body, lorem_ipsum); + } + + #[test] + fn decompressed_deflate_response() { + let lorem_ipsum = lorem_ipsum_bytes(); + let req_body = Body::from_stream(stream::ZlibEncoder::new( + futures::stream::iter(vec![lorem_ipsum]) + .map(Bytes::from) + .map(Ok), + flate2::Compression::default(), + )); + let res = get_decoded_response(req_body, "deflate"); + let body = block_on(res.into_body().into_vec()).unwrap(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(body, lorem_ipsum); + } + + #[test] + fn decompressed_brotli_response() { + let lorem_ipsum = lorem_ipsum_bytes(); + let req_body = Body::from_stream(stream::BrotliEncoder::new( + futures::stream::iter(vec![lorem_ipsum]) + .map(Bytes::from) + .map(Ok), + 11, + )); + let res = get_decoded_response(req_body, "br"); + let body = block_on(res.into_body().into_vec()).unwrap(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(body, lorem_ipsum); + } + + #[test] + fn decompressed_zstd_response() { + let lorem_ipsum = lorem_ipsum_bytes(); + let req_body = Body::from_stream(stream::ZstdEncoder::new( + futures::stream::iter(vec![lorem_ipsum]) + .map(Bytes::from) + .map(Ok), + 3, + )); + let res = get_decoded_response(req_body, "zstd"); + let body = block_on(res.into_body().into_vec()).unwrap(); + let lorem_ipsum = lorem_ipsum_bytes(); + assert_eq!(body, lorem_ipsum); + } +} diff --git a/tide/src/context.rs b/tide/src/context.rs index 4c96cc896..543ac8a5d 100644 --- a/tide/src/context.rs +++ b/tide/src/context.rs @@ -55,6 +55,11 @@ impl Context { &self.request } + /// Access a mutable handle to the entire request. + pub fn request_mut(&mut self) -> &mut http_service::Request { + &mut self.request + } + /// Access app-global data. pub fn state(&self) -> &State { &self.state From 80f0af6ba0b6825a404ee33846c858fd7fda6a28 Mon Sep 17 00:00:00 2001 From: grey Date: Tue, 14 May 2019 23:44:12 -0700 Subject: [PATCH 07/95] use run instead of serve --- tide-compression/examples/simple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-compression/examples/simple.rs b/tide-compression/examples/simple.rs index 981236353..2f5d0e174 100644 --- a/tide-compression/examples/simple.rs +++ b/tide-compression/examples/simple.rs @@ -18,5 +18,5 @@ pub fn main() { app.at("/echo").post(echo_bytes); app.middleware(Compression::with_default(Encoding::Brotli)); app.middleware(Decompression::new()); - app.serve("127.0.0.1:8000").unwrap(); + app.run("127.0.0.1:8000").unwrap(); } From 962fddc55ad2c98aa37715327a74d97726404bdb Mon Sep 17 00:00:00 2001 From: Allen Date: Tue, 14 May 2019 23:45:30 -0700 Subject: [PATCH 08/95] Update tide-compression/README.md Co-Authored-By: Wonwoo Choi --- tide-compression/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-compression/README.md b/tide-compression/README.md index 7f13f1f9f..c84f65b12 100644 --- a/tide-compression/README.md +++ b/tide-compression/README.md @@ -12,5 +12,5 @@ You can test the simple example by running `cargo run --example simple` while in ```console $ curl http://127.0.0.1:8000/ -v -$ curl http://127.0.0.1:8000/echo -v -d "why hello there" +$ echo 'why hello there' | gzip | curl -v --compressed -H 'Content-Encoding: gzip' 'http://127.0.0.1:8000/echo' --data-binary @- ``` From b19eb2e2a8827595290bae4600e9b7337ba4b2a8 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Wed, 15 May 2019 20:19:14 +0200 Subject: [PATCH 09/95] Check example in readme compiles during testing --- README.md | 2 +- tide/src/lib.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 124409d03..e54a09afa 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Ecosystem WG, and **not ready for production use yet**. **Hello World** -```rust +```rust,no_run #![feature(async_await)] fn main() -> Result<(), std::io::Error> { diff --git a/tide/src/lib.rs b/tide/src/lib.rs index ac931431d..c3c7841ba 100755 --- a/tide/src/lib.rs +++ b/tide/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(feature = "nightly", deny(missing_docs))] -#![cfg_attr(feature = "nightly", feature(external_doc))] +#![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![cfg_attr(test, deny(warnings))] #![feature(async_await, existential_type)] @@ -21,6 +21,10 @@ //! //! +#[cfg(test)] +#[doc(include = "../../README.md")] +const _README: () = (); + macro_rules! box_async { {$($t:tt)*} => { ::futures::future::FutureExt::boxed(async move { $($t)* }) From 3af12d9b5f549021c27f697ccdfc08405d5206d8 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Fri, 17 May 2019 00:26:05 +0900 Subject: [PATCH 10/95] Remove #[allow(unused_mut)] --- examples/src/body_types.rs | 4 ---- examples/src/cookies.rs | 2 -- examples/src/messages.rs | 2 -- examples/src/multipart_form/mod.rs | 1 - tide/src/middleware/cookies.rs | 4 ---- 5 files changed, 13 deletions(-) diff --git a/examples/src/body_types.rs b/examples/src/body_types.rs index 9df1509a5..c2d518903 100644 --- a/examples/src/body_types.rs +++ b/examples/src/body_types.rs @@ -11,28 +11,24 @@ struct Message { contents: String, } -#[allow(unused_mut)] // Workaround clippy bug async fn echo_string(mut cx: Context<()>) -> String { let msg = cx.body_string().await.unwrap(); println!("String: {}", msg); msg } -#[allow(unused_mut)] // Workaround clippy bug async fn echo_bytes(mut cx: Context<()>) -> Vec { let msg = cx.body_bytes().await.unwrap(); println!("Bytes: {:?}", msg); msg } -#[allow(unused_mut)] // Workaround clippy bug async fn echo_json(mut cx: Context<()>) -> EndpointResult { let msg = cx.body_json().await.client_err()?; println!("JSON: {:?}", msg); Ok(response::json(msg)) } -#[allow(unused_mut)] // Workaround clippy bug async fn echo_form(mut cx: Context<()>) -> EndpointResult { let msg = cx.body_form().await?; println!("Form: {:?}", msg); diff --git a/examples/src/cookies.rs b/examples/src/cookies.rs index a43dc67c1..670c6afd7 100644 --- a/examples/src/cookies.rs +++ b/examples/src/cookies.rs @@ -6,12 +6,10 @@ async fn retrieve_cookie(mut cx: Context<()>) -> String { format!("hello cookies: {:?}", cx.get_cookie("hello").unwrap()) } -#[allow(unused_mut)] // Workaround clippy bug async fn set_cookie(mut cx: Context<()>) { cx.set_cookie(Cookie::new("hello", "world")).unwrap(); } -#[allow(unused_mut)] // Workaround clippy bug async fn remove_cookie(mut cx: Context<()>) { cx.remove_cookie(Cookie::named("hello")).unwrap(); } diff --git a/examples/src/messages.rs b/examples/src/messages.rs index 4cf905f79..4abdadf61 100644 --- a/examples/src/messages.rs +++ b/examples/src/messages.rs @@ -37,13 +37,11 @@ impl Database { } } -#[allow(unused_mut)] // Workaround clippy bug async fn new_message(mut cx: Context) -> EndpointResult { let msg = cx.body_json().await.client_err()?; Ok(cx.state().insert(msg).to_string()) } -#[allow(unused_mut)] // Workaround clippy bug async fn set_message(mut cx: Context) -> EndpointResult<()> { let msg = cx.body_json().await.client_err()?; let id = cx.param("id").client_err()?; diff --git a/examples/src/multipart_form/mod.rs b/examples/src/multipart_form/mod.rs index ce4d74ca3..1e7e91b45 100644 --- a/examples/src/multipart_form/mod.rs +++ b/examples/src/multipart_form/mod.rs @@ -9,7 +9,6 @@ struct Message { file: Option, } -#[allow(unused_mut)] // Workaround clippy bug async fn upload_file(mut cx: Context<()>) -> EndpointResult { // https://stackoverflow.com/questions/43424982/how-to-parse-multipart-forms-using-abonander-multipart-with-rocket let mut message = Message { diff --git a/tide/src/middleware/cookies.rs b/tide/src/middleware/cookies.rs index 9c3dd6910..adb1152c3 100644 --- a/tide/src/middleware/cookies.rs +++ b/tide/src/middleware/cookies.rs @@ -72,23 +72,19 @@ mod tests { static COOKIE_NAME: &str = "testCookie"; /// Tide will use the the `Cookies`'s `Extract` implementation to build this parameter. - #[allow(unused_mut)] // Workaround clippy bug async fn retrieve_cookie(mut cx: Context<()>) -> String { format!("{}", cx.get_cookie(COOKIE_NAME).unwrap().unwrap().value()) } - #[allow(unused_mut)] // Workaround clippy bug async fn set_cookie(mut cx: Context<()>) { cx.set_cookie(Cookie::new(COOKIE_NAME, "NewCookieValue")) .unwrap(); } - #[allow(unused_mut)] // Workaround clippy bug async fn remove_cookie(mut cx: Context<()>) { cx.remove_cookie(Cookie::named(COOKIE_NAME)).unwrap(); } - #[allow(unused_mut)] // Workaround clippy bug async fn set_multiple_cookie(mut cx: Context<()>) { cx.set_cookie(Cookie::new("C1", "V1")).unwrap(); cx.set_cookie(Cookie::new("C2", "V2")).unwrap(); From 45319777f0ef0f5f334404329c29f4bf2cecfc6b Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 17 May 2019 15:49:53 +0000 Subject: [PATCH 11/95] Improve curl command consistency --- tide-compression/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tide-compression/README.md b/tide-compression/README.md index c84f65b12..4c8eb8b10 100644 --- a/tide-compression/README.md +++ b/tide-compression/README.md @@ -11,6 +11,6 @@ __Simple Example__ You can test the simple example by running `cargo run --example simple` while in this crate's directory, and then running either of the following commands: ```console -$ curl http://127.0.0.1:8000/ -v -$ echo 'why hello there' | gzip | curl -v --compressed -H 'Content-Encoding: gzip' 'http://127.0.0.1:8000/echo' --data-binary @- +$ curl -v http://127.0.0.1:8000/ +$ echo 'why hello there' | gzip | curl -v --compressed -H 'Content-Encoding: gzip' http://127.0.0.1:8000/echo --data-binary @- ``` From 77b3a1cd2970f3fca6baa2ee9749e3eea15ae811 Mon Sep 17 00:00:00 2001 From: Ravi Shankar Date: Sun, 19 May 2019 21:43:11 +0530 Subject: [PATCH 12/95] Split tide into smaller crates (#220) * Move core traits and types to tide-core * Move cookies middleware to tide-cookies * Remove unncessary dependencies and use relative paths in README --- Cargo.toml | 2 + README.md | 17 +-- examples/Cargo.toml | 16 +-- tide-cookies/Cargo.toml | 21 ++++ .../cookies.rs => tide-cookies/src/data.rs | 3 +- tide-cookies/src/lib.rs | 18 +++ .../src/middleware.rs | 12 +- tide-core/Cargo.toml | 32 ++++++ {tide => tide-core}/src/app.rs | 1 + {tide => tide-core}/src/context.rs | 0 {tide => tide-core}/src/endpoint.rs | 0 tide-core/src/error.rs | 104 ++++++++++++++++++ tide-core/src/lib.rs | 37 +++++++ tide-core/src/middleware.rs | 38 +++++++ {tide => tide-core}/src/response.rs | 0 {tide => tide-core}/src/route.rs | 0 {tide => tide-core}/src/router.rs | 0 tide/Cargo.toml | 17 +-- tide/src/error.rs | 101 +---------------- tide/src/lib.rs | 26 ++--- tide/src/middleware/mod.rs | 45 +------- 21 files changed, 288 insertions(+), 202 deletions(-) create mode 100644 tide-cookies/Cargo.toml rename tide/src/cookies.rs => tide-cookies/src/data.rs (98%) create mode 100644 tide-cookies/src/lib.rs rename tide/src/middleware/cookies.rs => tide-cookies/src/middleware.rs (96%) create mode 100644 tide-core/Cargo.toml rename {tide => tide-core}/src/app.rs (99%) rename {tide => tide-core}/src/context.rs (100%) rename {tide => tide-core}/src/endpoint.rs (100%) create mode 100644 tide-core/src/error.rs create mode 100644 tide-core/src/lib.rs create mode 100644 tide-core/src/middleware.rs rename {tide => tide-core}/src/response.rs (100%) rename {tide => tide-core}/src/route.rs (100%) rename {tide => tide-core}/src/router.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 6105ea9a2..3cf23390f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ members = [ "tide", "tide-compression", + "tide-cookies", + "tide-core", "examples", ] diff --git a/README.md b/README.md index e54a09afa..4e60e6f65 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,15 @@ fn main() -> Result<(), std::io::Error> { **More Examples** -- [Hello World](https://github.com/rustasync/tide/tree/master/examples/src/hello.rs) -- [Messages](https://github.com/rustasync/tide/tree/master/examples/src/messages.rs) -- [Body Types](https://github.com/rustasync/tide/tree/master/examples/src/body_types.rs) -- [Multipart Form](https://github.com/rustasync/tide/tree/master/examples/src/multipart_form/mod.rs) -- [Catch All](https://github.com/rustasync/tide/tree/master/examples/src/catch_all.rs) -- [Cookies](https://github.com/rustasync/tide/tree/master/examples/src/cookies.rs) -- [Default Headers](https://github.com/rustasync/tide/tree/master/examples/src/default_headers.rs) -- [GraphQL](https://github.com/rustasync/tide/tree/master/examples/src/graphql.rs) +- [Hello World](https://github.com/rustasync/tide/blob/master/examples/src/hello.rs) +- [Messages](https://github.com/rustasync/tide/blob/master/examples/src/messages.rs) +- [Body Types](https://github.com/rustasync/tide/blob/master/examples/src/body_types.rs) +- [Multipart Form](https://github.com/rustasync/tide/blob/master/examples/src/multipart-form/main.rs) +- [Catch All](https://github.com/rustasync/tide/blob/master/examples/src/catch_all.rs) +- [Cookies](https://github.com/rustasync/tide/blob/master/examples/src/cookies.rs) +- [Default Headers](https://github.com/rustasync/tide/blob/master/examples/src/default_headers.rs) +- [GraphQL](https://github.com/rustasync/tide/blob/master/examples/src/graphql.rs) +- [Staticfile](https://github.com/rustasync/tide/blob/master/examples/src/staticfile.rs) ## Resources diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 54a73b1ff..af1206539 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,6 +1,6 @@ [package] authors = [ - "Tide Developers", + "Tide Developers", ] description = "Tide web server examples" documentation = "https://docs.rs/tide" @@ -15,32 +15,18 @@ publish = false [dependencies] tide = { path = "../tide" } cookie = { version = "0.12", features = ["percent-encode"] } -futures-preview = "0.3.0-alpha.16" -fnv = "1.0.6" http = "0.1" http-service = "0.2.0" -pin-utils = "0.1.0-alpha.4" -route-recognizer = "0.1.12" -serde_json = "1.0.39" -slog = "2.4.1" -slog-async = "2.3.0" -slog-term = "2.4.0" -typemap = "0.3.3" -serde_urlencoded = "0.5.5" -basic-cookies = "0.1.3" bytes = "0.4.12" futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } -http-service-mock = "0.2.0" juniper = "0.11.1" mime = "0.3.13" mime_guess = "2.0.0-alpha.6" percent-encoding = "1.0.1" serde = { version = "1.0.91", features = ["derive"] } -structopt = "0.2.15" [dependencies.multipart] default-features = false features = ["server"] version = "0.16.1" - diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml new file mode 100644 index 000000000..34b388977 --- /dev/null +++ b/tide-cookies/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "tide-cookies" +version = "0.2.0" +edition = "2018" +authors = [ + "Tide Developers", +] +description = "Cookie management for Tide web framework" +documentation = "https://docs.rs/tide-core" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rustasync/tide" + +[dependencies] +cookie = { version = "0.12", features = ["percent-encode"] } +futures-preview = "0.3.0-alpha.16" +http = "0.1" +http-service = "0.2.0" +tide-core = { path = "../tide-core" } + +[dev-dependencies] +http-service-mock = "0.2.0" diff --git a/tide/src/cookies.rs b/tide-cookies/src/data.rs similarity index 98% rename from tide/src/cookies.rs rename to tide-cookies/src/data.rs index 48fa1a2cb..7430b10e0 100644 --- a/tide/src/cookies.rs +++ b/tide-cookies/src/data.rs @@ -1,9 +1,8 @@ use cookie::{Cookie, CookieJar, ParseError}; -use crate::error::StringError; -use crate::Context; use http::HeaderMap; use std::sync::{Arc, RwLock}; +use tide_core::{error::StringError, Context}; const MIDDLEWARE_MISSING_MSG: &str = "CookiesMiddleware must be used to populate request and response cookies"; diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs new file mode 100644 index 000000000..da88a7054 --- /dev/null +++ b/tide-cookies/src/lib.rs @@ -0,0 +1,18 @@ +#![cfg_attr(feature = "nightly", deny(missing_docs))] +#![cfg_attr(test, deny(warnings))] +#![feature(async_await)] +#![deny( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + +#[macro_use] +extern crate tide_core; + +mod data; +mod middleware; + +pub use self::data::ContextExt; +pub use self::middleware::CookiesMiddleware; diff --git a/tide/src/middleware/cookies.rs b/tide-cookies/src/middleware.rs similarity index 96% rename from tide/src/middleware/cookies.rs rename to tide-cookies/src/middleware.rs index adb1152c3..99142c82a 100644 --- a/tide/src/middleware/cookies.rs +++ b/tide-cookies/src/middleware.rs @@ -1,8 +1,8 @@ -use crate::cookies::CookieData; +use crate::data::CookieData; use futures::future::BoxFuture; use http::header::HeaderValue; -use crate::{ +use tide_core::{ middleware::{Middleware, Next}, Context, Response, }; @@ -63,11 +63,12 @@ impl Middleware for CookiesMiddleware { #[cfg(test)] mod tests { use super::*; - use crate::{cookies::ContextExt, Context}; + use crate::data::ContextExt; use cookie::Cookie; use futures::executor::block_on; use http_service::Body; use http_service_mock::make_server; + use tide_core::Context; static COOKIE_NAME: &str = "testCookie"; @@ -90,8 +91,8 @@ mod tests { cx.set_cookie(Cookie::new("C2", "V2")).unwrap(); } - fn app() -> crate::App<()> { - let mut app = crate::App::new(); + fn app() -> tide_core::App<()> { + let mut app = tide_core::App::new(); app.middleware(CookiesMiddleware::new()); app.at("/get").get(retrieve_cookie); @@ -168,5 +169,4 @@ mod tests { assert!(iter.next().is_none()); } - } diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml new file mode 100644 index 000000000..60ef60fe8 --- /dev/null +++ b/tide-core/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "tide-core" +version = "0.2.0" +edition = "2018" +authors = [ + "Tide Developers", +] +description = "Core types and traits for Tide web framework" +documentation = "https://docs.rs/tide-core" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rustasync/tide" + +[dependencies] +fnv = "1.0.6" +futures-preview = "0.3.0-alpha.16" +http = "0.1" +http-service = "0.2.0" +route-recognizer = "0.1.12" +serde = "1.0.91" +serde_json = "1.0.39" + +[dependencies.http-service-hyper] +optional = true +version = "0.2.0" + +[dev-dependencies] +tide = { path = "../tide" } +serde_derive = "1.0.91" + +[features] +default = ["hyper"] +hyper = ["http-service-hyper"] diff --git a/tide/src/app.rs b/tide-core/src/app.rs similarity index 99% rename from tide/src/app.rs rename to tide-core/src/app.rs index 91699dd38..ef65b35ad 100644 --- a/tide/src/app.rs +++ b/tide-core/src/app.rs @@ -76,6 +76,7 @@ use crate::{ /// /// ```rust, no_run /// #![feature(async_await)] +/// #[macro_use] extern crate serde_derive; /// /// use http::status::StatusCode; /// use serde::{Deserialize, Serialize}; diff --git a/tide/src/context.rs b/tide-core/src/context.rs similarity index 100% rename from tide/src/context.rs rename to tide-core/src/context.rs diff --git a/tide/src/endpoint.rs b/tide-core/src/endpoint.rs similarity index 100% rename from tide/src/endpoint.rs rename to tide-core/src/endpoint.rs diff --git a/tide-core/src/error.rs b/tide-core/src/error.rs new file mode 100644 index 000000000..eacfe93ac --- /dev/null +++ b/tide-core/src/error.rs @@ -0,0 +1,104 @@ +// use core::pin::Pin; +// use futures::future::Future; +use http::{HttpTryFrom, Response, StatusCode}; +use http_service::Body; + +use crate::response::IntoResponse; + +#[derive(Debug)] +pub struct StringError(pub String); +impl std::error::Error for StringError {} + +impl std::fmt::Display for StringError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { + self.0.fmt(f) + } +} + +#[macro_export] +macro_rules! err_fmt { + {$($t:tt)*} => { + crate::error::StringError(format!($($t)*)) + } +} + +/// A convenient `Result` instantiation appropriate for most endpoints. +pub type EndpointResult> = Result; + +/// A generic endpoint error, which can be converted into a response. +#[derive(Debug)] +pub struct Error { + resp: Response, +} + +impl IntoResponse for Error { + fn into_response(self) -> Response { + self.resp + } +} + +struct Cause(Box); + +impl From> for Error { + fn from(resp: Response) -> Error { + Error { resp } + } +} + +impl From for Error { + fn from(status: StatusCode) -> Error { + let resp = Response::builder() + .status(status) + .body(Body::empty()) + .unwrap(); + Error { resp } + } +} + +/// Extends the `Result` type with convenient methods for constructing Tide errors. +pub trait ResultExt: Sized { + /// Convert to an `EndpointResult`, treating the `Err` case as a client + /// error (response code 400). + fn client_err(self) -> EndpointResult { + self.with_err_status(400) + } + + /// Convert to an `EndpointResult`, treating the `Err` case as a server + /// error (response code 500). + fn server_err(self) -> EndpointResult { + self.with_err_status(500) + } + + /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom + /// response status. + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom; +} + +/// Extends the `Response` type with a method to extract error causes when applicable. +pub trait ResponseExt { + /// Extract the cause of the unsuccessful response, if any + fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)>; +} + +impl ResponseExt for Response { + fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { + self.extensions().get().map(|Cause(c)| &**c) + } +} + +impl ResultExt for std::result::Result { + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom, + { + self.map_err(|e| Error { + resp: Response::builder() + .status(status) + .extension(Cause(Box::new(e))) + .body(Body::empty()) + .unwrap(), + }) + } +} diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs new file mode 100644 index 000000000..ca0df3282 --- /dev/null +++ b/tide-core/src/lib.rs @@ -0,0 +1,37 @@ +#![cfg_attr(feature = "nightly", deny(missing_docs))] +#![cfg_attr(test, deny(warnings))] +#![feature(async_await, existential_type)] +#![deny( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] +// TODO: Remove this after clippy bug due to async await is resolved. +// ISSUE: https://github.com/rust-lang/rust-clippy/issues/3988 +#![allow(clippy::needless_lifetimes)] + +#[macro_export] +macro_rules! box_async { + {$($t:tt)*} => { + ::futures::future::FutureExt::boxed(async move { $($t)* }) + }; +} + +mod app; +mod context; +mod endpoint; +pub mod error; +pub mod middleware; +pub mod response; +mod route; +mod router; + +pub use crate::{ + app::{App, Server}, + context::Context, + endpoint::Endpoint, + error::{EndpointResult, Error}, + response::Response, + route::Route, +}; diff --git a/tide-core/src/middleware.rs b/tide-core/src/middleware.rs new file mode 100644 index 000000000..47d1caa13 --- /dev/null +++ b/tide-core/src/middleware.rs @@ -0,0 +1,38 @@ +use crate::{endpoint::DynEndpoint, Context, Response}; +use futures::future::BoxFuture; + +use std::sync::Arc; + +/// Middleware that wraps around remaining middleware chain. +pub trait Middleware: 'static + Send + Sync { + /// Asynchronously handle the request, and return a response. + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response>; +} + +impl Middleware for F +where + F: Send + Sync + 'static + for<'a> Fn(Context, Next<'a, Data>) -> BoxFuture<'a, Response>, +{ + fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { + (self)(cx, next) + } +} + +/// The remainder of a middleware chain, including the endpoint. +#[allow(missing_debug_implementations)] +pub struct Next<'a, State> { + pub(crate) endpoint: &'a DynEndpoint, + pub(crate) next_middleware: &'a [Arc>], +} + +impl<'a, State: 'static> Next<'a, State> { + /// Asynchronously execute the remaining middleware chain. + pub fn run(mut self, cx: Context) -> BoxFuture<'a, Response> { + if let Some((current, next)) = self.next_middleware.split_first() { + self.next_middleware = next; + current.handle(cx, self) + } else { + (self.endpoint)(cx) + } + } +} diff --git a/tide/src/response.rs b/tide-core/src/response.rs similarity index 100% rename from tide/src/response.rs rename to tide-core/src/response.rs diff --git a/tide/src/route.rs b/tide-core/src/route.rs similarity index 100% rename from tide/src/route.rs rename to tide-core/src/route.rs diff --git a/tide/src/router.rs b/tide-core/src/router.rs similarity index 100% rename from tide/src/router.rs rename to tide-core/src/router.rs diff --git a/tide/Cargo.toml b/tide/Cargo.toml index 9e70bf5ea..ce2cb9f28 100644 --- a/tide/Cargo.toml +++ b/tide/Cargo.toml @@ -19,25 +19,17 @@ repository = "https://github.com/rustasync/tide" version = "0.2.0" [dependencies] -cookie = { version = "0.12", features = ["percent-encode"] } futures-preview = "0.3.0-alpha.16" -fnv = "1.0.6" http = "0.1" http-service = "0.2.0" -pin-utils = "0.1.0-alpha.4" -route-recognizer = "0.1.12" serde = "1.0.91" serde_derive = "1.0.91" -serde_json = "1.0.39" slog = "2.4.1" slog-async = "2.3.0" slog-term = "2.4.0" -typemap = "0.3.3" serde_urlencoded = "0.5.5" - -[dependencies.http-service-hyper] -optional = true -version = "0.2.0" +tide-cookies = { path = "../tide-cookies", optional = true } +tide-core = { path = "../tide-core" } [dependencies.multipart] default-features = false @@ -45,8 +37,9 @@ features = ["server"] version = "0.16.1" [features] -default = ["hyper"] -hyper = ["http-service-hyper"] +default = ["hyper", "cookies"] +cookies = ["tide-cookies"] +hyper = ["tide-core/http-service-hyper"] [dev-dependencies] http-service-mock = "0.2.0" diff --git a/tide/src/error.rs b/tide/src/error.rs index 174c6987a..25ae1cc4b 100644 --- a/tide/src/error.rs +++ b/tide/src/error.rs @@ -1,105 +1,6 @@ use core::pin::Pin; use futures::future::Future; -use http::{HttpTryFrom, Response, StatusCode}; -use http_service::Body; -use crate::response::IntoResponse; +pub use tide_core::error::{EndpointResult, Error, ResponseExt, ResultExt, StringError}; pub(crate) type BoxTryFuture = Pin> + Send + 'static>>; - -/// A convenient `Result` instantiation appropriate for most endpoints. -pub type EndpointResult> = Result; - -#[derive(Debug)] -pub struct StringError(pub String); -impl std::error::Error for StringError {} - -impl std::fmt::Display for StringError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - self.0.fmt(f) - } -} - -macro_rules! err_fmt { - {$($t:tt)*} => { - crate::error::StringError(format!($($t)*)) - } -} - -/// A generic endpoint error, which can be converted into a response. -#[derive(Debug)] -pub struct Error { - resp: Response, -} - -impl IntoResponse for Error { - fn into_response(self) -> Response { - self.resp - } -} - -struct Cause(Box); - -impl From> for Error { - fn from(resp: Response) -> Error { - Error { resp } - } -} - -impl From for Error { - fn from(status: StatusCode) -> Error { - let resp = Response::builder() - .status(status) - .body(Body::empty()) - .unwrap(); - Error { resp } - } -} - -/// Extends the `Result` type with convenient methods for constructing Tide errors. -pub trait ResultExt: Sized { - /// Convert to an `EndpointResult`, treating the `Err` case as a client - /// error (response code 400). - fn client_err(self) -> EndpointResult { - self.with_err_status(400) - } - - /// Convert to an `EndpointResult`, treating the `Err` case as a server - /// error (response code 500). - fn server_err(self) -> EndpointResult { - self.with_err_status(500) - } - - /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom - /// response status. - fn with_err_status(self, status: S) -> EndpointResult - where - StatusCode: HttpTryFrom; -} - -/// Extends the `Response` type with a method to extract error causes when applicable. -pub trait ResponseExt { - /// Extract the cause of the unsuccessful response, if any - fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)>; -} - -impl ResponseExt for Response { - fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { - self.extensions().get().map(|Cause(c)| &**c) - } -} - -impl ResultExt for std::result::Result { - fn with_err_status(self, status: S) -> EndpointResult - where - StatusCode: HttpTryFrom, - { - self.map_err(|e| Error { - resp: Response::builder() - .status(status) - .extension(Cause(Box::new(e))) - .body(Body::empty()) - .unwrap(), - }) - } -} diff --git a/tide/src/lib.rs b/tide/src/lib.rs index c3c7841ba..6ef962c0b 100755 --- a/tide/src/lib.rs +++ b/tide/src/lib.rs @@ -10,9 +10,6 @@ future_incompatible, missing_debug_implementations )] -// TODO: Remove this after clippy bug due to async await is resolved. -// ISSUE: https://github.com/rust-lang/rust-clippy/issues/3988 -#![allow(clippy::needless_lifetimes)] //! //! Welcome to Tide. @@ -32,27 +29,20 @@ macro_rules! box_async { } #[macro_use] -pub mod error; +extern crate tide_core; + +#[cfg(feature = "cookies")] +#[doc(inline)] +pub use tide_cookies as cookies; -mod app; -mod context; -pub mod cookies; -mod endpoint; +pub mod error; pub mod forms; pub mod middleware; pub mod querystring; -pub mod response; -mod route; -mod router; #[doc(inline)] -pub use crate::{ - app::{App, Server}, - context::Context, - endpoint::Endpoint, - error::{EndpointResult, Error}, - response::Response, - route::Route, +pub use tide_core::{ + response, App, Context, Endpoint, EndpointResult, Error, Response, Route, Server, }; pub use http; diff --git a/tide/src/middleware/mod.rs b/tide/src/middleware/mod.rs index 64c6c5692..aaa20d48b 100644 --- a/tide/src/middleware/mod.rs +++ b/tide/src/middleware/mod.rs @@ -1,44 +1,7 @@ -use futures::future::BoxFuture; -use std::sync::Arc; - -use crate::{endpoint::DynEndpoint, Context, Response}; - -mod cookies; mod default_headers; mod logger; -pub use self::{cookies::CookiesMiddleware, default_headers::DefaultHeaders, logger::RootLogger}; - -/// Middleware that wraps around remaining middleware chain. -pub trait Middleware: 'static + Send + Sync { - /// Asynchronously handle the request, and return a response. - fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response>; -} - -impl Middleware for F -where - F: Send + Sync + 'static + for<'a> Fn(Context, Next<'a, Data>) -> BoxFuture<'a, Response>, -{ - fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { - (self)(cx, next) - } -} - -/// The remainder of a middleware chain, including the endpoint. -#[allow(missing_debug_implementations)] -pub struct Next<'a, State> { - pub(crate) endpoint: &'a DynEndpoint, - pub(crate) next_middleware: &'a [Arc>], -} - -impl<'a, State: 'static> Next<'a, State> { - /// Asynchronously execute the remaining middleware chain. - pub fn run(mut self, cx: Context) -> BoxFuture<'a, Response> { - if let Some((current, next)) = self.next_middleware.split_first() { - self.next_middleware = next; - current.handle(cx, self) - } else { - (self.endpoint)(cx) - } - } -} +pub use self::{default_headers::DefaultHeaders, logger::RootLogger}; +#[cfg(feature = "cookies")] +pub use tide_cookies::CookiesMiddleware; +pub use tide_core::middleware::{Middleware, Next}; From 85b85e9f12f596bad07153beff039bed590c1712 Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Sun, 19 May 2019 18:49:58 +0200 Subject: [PATCH 13/95] Update travis configuration (#228) * Update travis config * Separate out individual build jobs for faster wall-clock testing * Fix clippy not actually denying warnings (excluded examples because these are currently failing and have non-trivial fixes) * Add build job that checks --no-default-features works * Add build job that checks for intra-doc-resolution failures (excluded tide because of bugs in re-exports with the intra-doc feature) * Fix warnings * Fix doc-link in tide-cookies --- .travis.yml | 39 ++++++++++++++++++++++++---------- tide-compression/src/lib.rs | 6 ++---- tide-cookies/src/middleware.rs | 11 ++++++---- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a662d4f7..cc4c46432 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,30 @@ language: rust -rust: - - nightly-2019-05-09 - -before_script: | - rustup component add rustfmt clippy -script: | - cargo fmt --all -- --check && - cargo clippy --all --all-features -- -D clippy::all && - cargo build --no-default-features --verbose && - cargo build --all --all-features --verbose && - cargo test --all --all-features --verbose +rust: nightly-2019-05-09 cache: cargo + +matrix: + include: + - name: cargo doc + env: [CACHE_NAME=docs] + script: + - RUSTDOCFLAGS=-Dwarnings + cargo doc --all --all-features --no-deps --exclude tide + + - name: cargo fmt + cache: false + before_script: rustup component add rustfmt + script: cargo fmt --all -- --check + + - name: cargo clippy + env: [CACHE_NAME=clippy] + before_script: rustup component add clippy + script: cargo clippy --all --all-targets --exclude examples -- -Dwarnings + + - name: cargo build --no-default-features + env: [CACHE_NAME=no-default-features] + script: + - cargo build --manifest-path tide/Cargo.toml --no-default-features + - cargo build --manifest-path tide-core/Cargo.toml --no-default-features + + - name: cargo test + script: cargo test --all --verbose diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index e0f88be3a..4c1cad9b1 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -289,8 +289,7 @@ mod tests { .header(ACCEPT_ENCODING, hval) .body(Body::empty()) .unwrap(); - let res = server.simulate(req).unwrap(); - res + server.simulate(req).unwrap() } // Generates a decoded response given a request body and the header value representing its encoding. @@ -301,8 +300,7 @@ mod tests { .header(CONTENT_ENCODING, hval) .body(body) .unwrap(); - let res = server.simulate(req).unwrap(); - res + server.simulate(req).unwrap() } #[test] diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 99142c82a..86f5ff87e 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -9,7 +9,7 @@ use tide_core::{ /// Middleware to work with cookies. /// -/// [`CookiesMiddleware`] along with [`ContextExt`](crate::cookies::ContextExt) provide smooth +/// [`CookiesMiddleware`] along with [`ContextExt`](crate::data::ContextExt) provide smooth /// access to request cookies and setting/removing cookies from response. This leverages the /// [cookie](https://crates.io/crates/cookie) crate. /// This middleware parses cookies from request and caches them in the extension. Once the request @@ -74,7 +74,11 @@ mod tests { /// Tide will use the the `Cookies`'s `Extract` implementation to build this parameter. async fn retrieve_cookie(mut cx: Context<()>) -> String { - format!("{}", cx.get_cookie(COOKIE_NAME).unwrap().unwrap().value()) + cx.get_cookie(COOKIE_NAME) + .unwrap() + .unwrap() + .value() + .to_string() } async fn set_cookie(mut cx: Context<()>) { @@ -109,8 +113,7 @@ mod tests { .header(http::header::COOKIE, "testCookie=RequestCookieValue") .body(Body::empty()) .unwrap(); - let res = server.simulate(req).unwrap(); - res + server.simulate(req).unwrap() } #[test] From e7a7dacdddc791d74edd7e4585e18e10541d3e3d Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 20 May 2019 12:09:05 +0530 Subject: [PATCH 14/95] add tide-log --- Cargo.toml | 1 + tide-log/Cargo.toml | 24 +++++++++++++++++ tide-log/src/lib.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 tide-log/Cargo.toml create mode 100644 tide-log/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 3cf23390f..c5df7f535 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "tide", + "tide-log", "tide-compression", "tide-cookies", "tide-core", diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml new file mode 100644 index 000000000..ac8440f6c --- /dev/null +++ b/tide-log/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = [ + "Tide Developers" +] +description = "Tide middleware for logging" +documentation = "https://docs.rs/tide-log" +keywords = ["tide", "web", "async", "middleware", "logging"] +categories = [ + "logging", + "network-programming", + "web-programming::http-server", +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide-log" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" + + [dependencies] +tide = { path = "../tide" } +futures-preview = "0.3.0-alpha.16" +http = "0.1" +log = "0.4.6" diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs new file mode 100644 index 000000000..3e82ebc77 --- /dev/null +++ b/tide-log/src/lib.rs @@ -0,0 +1,65 @@ +#![feature(async_await)] +#![deny( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + +use futures::future::BoxFuture; +use log::{info, trace}; +use tide::{ + middleware::{Middleware, Next}, + Context, Response, +}; + +macro_rules! box_async { + {$($t:tt)*} => { + ::futures::future::FutureExt::boxed(async move { $($t)* }) + }; +} + +/// A simple requests logger +/// +/// # Examples +/// +/// ```rust +/// +/// let mut app = tide::App::new(); +/// app.middleware(tide_log::RequestLogger::new()); +/// ``` +#[derive(Debug, Clone, Default)] +pub struct RequestLogger; + +impl RequestLogger { + pub fn new() -> Self { + Self::default() + } + + async fn log_basic<'a, Data: Send + Sync + 'static>( + &'a self, + ctx: Context, + next: Next<'a, Data>, + ) -> tide::Response { + let path = ctx.uri().path().to_owned(); + let method = ctx.method().as_str().to_owned(); + trace!("IN => {} {}", method, path); + let start = std::time::Instant::now(); + let res = next.run(ctx).await; + let status = res.status(); + info!( + "{} {} {} {}ms", + method, + path, + status.as_str(), + start.elapsed().as_millis() + ); + res + } +} + +impl Middleware for RequestLogger { + fn handle<'a>(&'a self, ctx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { + box_async! { self.log_basic(ctx, next).await } + } +} From 1106a85955aa7b9881d91d63aae121425c0fb99c Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 20 May 2019 12:16:27 +0530 Subject: [PATCH 15/95] change deny attr to warn; consistent enforcement for all crates --- tide-compression/src/lib.rs | 2 +- tide-cookies/src/lib.rs | 2 +- tide-core/src/lib.rs | 2 +- tide-log/src/lib.rs | 4 +++- tide/src/lib.rs | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 4c1cad9b1..3e0992ac1 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -3,7 +3,7 @@ #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![cfg_attr(test, deny(warnings))] #![feature(async_await)] -#![deny( +#![warn( nonstandard_style, rust_2018_idioms, future_incompatible, diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs index da88a7054..c60f045ef 100644 --- a/tide-cookies/src/lib.rs +++ b/tide-cookies/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "nightly", deny(missing_docs))] #![cfg_attr(test, deny(warnings))] #![feature(async_await)] -#![deny( +#![warn( nonstandard_style, rust_2018_idioms, future_incompatible, diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index ca0df3282..54577781f 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "nightly", deny(missing_docs))] #![cfg_attr(test, deny(warnings))] #![feature(async_await, existential_type)] -#![deny( +#![warn( nonstandard_style, rust_2018_idioms, future_incompatible, diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index 3e82ebc77..20442315e 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -1,5 +1,7 @@ +#![cfg_attr(feature = "nightly", deny(missing_docs))] +#![cfg_attr(test, deny(warnings))] #![feature(async_await)] -#![deny( +#![warn( nonstandard_style, rust_2018_idioms, future_incompatible, diff --git a/tide/src/lib.rs b/tide/src/lib.rs index 6ef962c0b..dbf6c6123 100755 --- a/tide/src/lib.rs +++ b/tide/src/lib.rs @@ -4,7 +4,7 @@ #![cfg_attr(test, deny(warnings))] #![feature(async_await, existential_type)] #![allow(unused_variables)] -#![deny( +#![warn( nonstandard_style, rust_2018_idioms, future_incompatible, From 2878abad4695a9fa85a90818c31eb844363bce35 Mon Sep 17 00:00:00 2001 From: Zihan Liu Date: Mon, 20 May 2019 17:35:31 +0800 Subject: [PATCH 16/95] Add ResultDynErrExt (#216) --- tide-core/src/error.rs | 52 +++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/tide-core/src/error.rs b/tide-core/src/error.rs index eacfe93ac..d7e748b6b 100644 --- a/tide-core/src/error.rs +++ b/tide-core/src/error.rs @@ -1,5 +1,3 @@ -// use core::pin::Pin; -// use futures::future::Future; use http::{HttpTryFrom, Response, StatusCode}; use http_service::Body; @@ -55,6 +53,18 @@ impl From for Error { } } +/// Extends the `Response` type with a method to extract error causes when applicable. +pub trait ResponseExt { + /// Extract the cause of the unsuccessful response, if any + fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)>; +} + +impl ResponseExt for Response { + fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { + self.extensions().get().map(|Cause(c)| &**c) + } +} + /// Extends the `Result` type with convenient methods for constructing Tide errors. pub trait ResultExt: Sized { /// Convert to an `EndpointResult`, treating the `Err` case as a client @@ -76,19 +86,39 @@ pub trait ResultExt: Sized { StatusCode: HttpTryFrom; } -/// Extends the `Response` type with a method to extract error causes when applicable. -pub trait ResponseExt { - /// Extract the cause of the unsuccessful response, if any - fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)>; +impl ResultExt for std::result::Result { + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom, + { + let r = self.map_err(|e| Box::new(e) as Box); + r.with_err_status(status) + } } -impl ResponseExt for Response { - fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { - self.extensions().get().map(|Cause(c)| &**c) +/// Extends the `Result` type using `std::error::Error` trait object as the error type with +/// convenient methods for constructing Tide errors. +pub trait ResultDynErrExt: Sized { + /// Convert to an `EndpointResult`, treating the `Err` case as a client + /// error (response code 400). + fn client_err(self) -> EndpointResult { + self.with_err_status(400) } + + /// Convert to an `EndpointResult`, treating the `Err` case as a server + /// error (response code 500). + fn server_err(self) -> EndpointResult { + self.with_err_status(500) + } + + /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom + /// response status. + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom; } -impl ResultExt for std::result::Result { +impl ResultDynErrExt for std::result::Result> { fn with_err_status(self, status: S) -> EndpointResult where StatusCode: HttpTryFrom, @@ -96,7 +126,7 @@ impl ResultExt for std::resu self.map_err(|e| Error { resp: Response::builder() .status(status) - .extension(Cause(Box::new(e))) + .extension(Cause(e)) .body(Body::empty()) .unwrap(), }) From 4d6da98a7fd2ecc35d645a331a0ed300a87a189a Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 20 May 2019 18:53:13 +0530 Subject: [PATCH 17/95] remove remaining deny attrs --- tide-compression/src/lib.rs | 2 -- tide-cookies/src/lib.rs | 2 -- tide-core/src/lib.rs | 2 -- tide-log/src/lib.rs | 2 -- tide/src/lib.rs | 2 -- 5 files changed, 10 deletions(-) diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 3e0992ac1..718425195 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -1,7 +1,5 @@ -#![cfg_attr(feature = "nightly", deny(missing_docs))] #![cfg_attr(feature = "nightly", feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] -#![cfg_attr(test, deny(warnings))] #![feature(async_await)] #![warn( nonstandard_style, diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs index c60f045ef..6137ae114 100644 --- a/tide-cookies/src/lib.rs +++ b/tide-cookies/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(feature = "nightly", deny(missing_docs))] -#![cfg_attr(test, deny(warnings))] #![feature(async_await)] #![warn( nonstandard_style, diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index 54577781f..88c3690d3 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(feature = "nightly", deny(missing_docs))] -#![cfg_attr(test, deny(warnings))] #![feature(async_await, existential_type)] #![warn( nonstandard_style, diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index 20442315e..4811a4676 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(feature = "nightly", deny(missing_docs))] -#![cfg_attr(test, deny(warnings))] #![feature(async_await)] #![warn( nonstandard_style, diff --git a/tide/src/lib.rs b/tide/src/lib.rs index dbf6c6123..1c9880fe1 100755 --- a/tide/src/lib.rs +++ b/tide/src/lib.rs @@ -1,7 +1,5 @@ -#![cfg_attr(feature = "nightly", deny(missing_docs))] #![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] -#![cfg_attr(test, deny(warnings))] #![feature(async_await, existential_type)] #![allow(unused_variables)] #![warn( From 011d0db078d74e78ccf53f03605271b1bba60290 Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 20 May 2019 08:28:28 -0700 Subject: [PATCH 18/95] rename trait ExtractForms to ContextExt (#239) as follows https://github.com/rustasync/tide/issues/187 --- examples/src/body_types.rs | 2 +- examples/src/multipart_form/mod.rs | 2 +- tide/src/forms.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/src/body_types.rs b/examples/src/body_types.rs index c2d518903..f85c90a00 100644 --- a/examples/src/body_types.rs +++ b/examples/src/body_types.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use tide::{ error::ResultExt, - forms::{self, ExtractForms}, + forms::{self, ContextExt}, response, App, Context, EndpointResult, }; diff --git a/examples/src/multipart_form/mod.rs b/examples/src/multipart_form/mod.rs index 1e7e91b45..bf6acc4a4 100644 --- a/examples/src/multipart_form/mod.rs +++ b/examples/src/multipart_form/mod.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; use std::io::Read; -use tide::{forms::ExtractForms, response, App, Context, EndpointResult}; +use tide::{forms::ContextExt, response, App, Context, EndpointResult}; #[derive(Serialize, Deserialize, Clone)] struct Message { diff --git a/tide/src/forms.rs b/tide/src/forms.rs index b7338dab5..a6f4a7b5f 100644 --- a/tide/src/forms.rs +++ b/tide/src/forms.rs @@ -8,7 +8,7 @@ use crate::{ }; /// An extension trait for `Context`, providing form extraction. -pub trait ExtractForms { +pub trait ContextExt { /// Asynchronously extract the entire body as a single form. fn body_form(&mut self) -> BoxTryFuture; @@ -16,7 +16,7 @@ pub trait ExtractForms { fn body_multipart(&mut self) -> BoxTryFuture>>>; } -impl ExtractForms for Context { +impl ContextExt for Context { fn body_form(&mut self) -> BoxTryFuture { let body = self.take_body(); box_async! { From 6637aafb9ac994a3eb68167dcd2bb2d2a568180e Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 20 May 2019 17:15:42 +0200 Subject: [PATCH 19/95] remove async box macro Signed-off-by: Yoshua Wuyts --- tide-compression/src/lib.rs | 15 +++++---------- tide-cookies/src/lib.rs | 3 --- tide-cookies/src/middleware.rs | 5 +++-- tide-core/src/app.rs | 5 +++-- tide-core/src/endpoint.rs | 5 +++-- tide-core/src/lib.rs | 7 ------- tide-core/src/router.rs | 7 ++++--- tide/src/forms.rs | 9 +++++---- tide/src/lib.rs | 6 ------ tide/src/middleware/default_headers.rs | 5 +++-- tide/src/middleware/logger.rs | 5 +++-- 11 files changed, 29 insertions(+), 43 deletions(-) diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 4c1cad9b1..dd8605533 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -13,6 +13,7 @@ pub use accept_encoding::Encoding; use async_compression::stream; use futures::future::BoxFuture; +use futures::prelude::*; use http::{header::CONTENT_ENCODING, status::StatusCode, HeaderMap}; use http_service::{Body, Request}; use tide::{ @@ -21,12 +22,6 @@ use tide::{ Context, Error, Response, }; -macro_rules! box_async { - {$($t:tt)*} => { - ::futures::future::FutureExt::boxed(async move { $($t)* }) - }; -} - /// Encode settings for the compression middleware. /// /// This can be modified in the case that you want more control over the speed or quality of compression. @@ -137,14 +132,14 @@ impl Compression { impl Middleware for Compression { fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { - box_async! { + FutureExt::boxed(async move { let encoding = match self.preferred_encoding(cx.headers()) { Ok(encoding) => encoding, Err(e) => return e.into_response(), }; let res = next.run(cx).await; self.encode(res, encoding) - } + }) } } @@ -225,13 +220,13 @@ impl Middleware for Decompression { mut cx: Context, next: Next<'a, Data>, ) -> BoxFuture<'a, Response> { - box_async! { + FutureExt::boxed(async move { match self.decode(cx.request_mut()) { Ok(_) => (), Err(e) => return e.into_response(), }; next.run(cx).await - } + }) } } diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs index da88a7054..c7619d222 100644 --- a/tide-cookies/src/lib.rs +++ b/tide-cookies/src/lib.rs @@ -8,9 +8,6 @@ missing_debug_implementations )] -#[macro_use] -extern crate tide_core; - mod data; mod middleware; diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 86f5ff87e..2d300369f 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -1,6 +1,7 @@ use crate::data::CookieData; use futures::future::BoxFuture; use http::header::HeaderValue; +use futures::prelude::*; use tide_core::{ middleware::{Middleware, Next}, @@ -31,7 +32,7 @@ impl Middleware for CookiesMiddleware { mut cx: Context, next: Next<'a, Data>, ) -> BoxFuture<'a, Response> { - box_async! { + FutureExt::boxed(async move { let cookie_data = cx .extensions_mut() .remove() @@ -56,7 +57,7 @@ impl Middleware for CookiesMiddleware { } } res - } + }) } } diff --git a/tide-core/src/app.rs b/tide-core/src/app.rs index ef65b35ad..e0e0549a0 100644 --- a/tide-core/src/app.rs +++ b/tide-core/src/app.rs @@ -1,4 +1,5 @@ use futures::future::{self, BoxFuture}; +use futures::prelude::*; use http_service::HttpService; use std::sync::Arc; @@ -292,7 +293,7 @@ impl HttpService for Server { let middleware = self.middleware.clone(); let data = self.data.clone(); - box_async! { + FutureExt::boxed(async move { let fut = { let Selection { endpoint, params } = router.route(&path, method); let cx = Context::new(data, req, params); @@ -306,7 +307,7 @@ impl HttpService for Server { }; Ok(fut.await) - } + }) } } diff --git a/tide-core/src/endpoint.rs b/tide-core/src/endpoint.rs index 8ec5e988b..663654868 100644 --- a/tide-core/src/endpoint.rs +++ b/tide-core/src/endpoint.rs @@ -1,4 +1,5 @@ use futures::future::{BoxFuture, Future}; +use futures::prelude::*; use crate::{response::IntoResponse, Context, Response}; @@ -68,8 +69,8 @@ where type Fut = BoxFuture<'static, Response>; fn call(&self, cx: Context) -> Self::Fut { let fut = (self)(cx); - box_async! { + FutureExt::boxed(async move { fut.await.into_response() - } + }) } } diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index ca0df3282..f1f06a77b 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -11,13 +11,6 @@ // ISSUE: https://github.com/rust-lang/rust-clippy/issues/3988 #![allow(clippy::needless_lifetimes)] -#[macro_export] -macro_rules! box_async { - {$($t:tt)*} => { - ::futures::future::FutureExt::boxed(async move { $($t)* }) - }; -} - mod app; mod context; mod endpoint; diff --git a/tide-core/src/router.rs b/tide-core/src/router.rs index 34710110d..0b028c2fa 100644 --- a/tide-core/src/router.rs +++ b/tide-core/src/router.rs @@ -1,5 +1,6 @@ use fnv::FnvHashMap; -use futures::future::{BoxFuture, FutureExt}; +use futures::future::BoxFuture; +use futures::prelude::*; use http_service::Body; use route_recognizer::{Match, Params, Router as MethodRouter}; @@ -62,7 +63,7 @@ impl Router { } fn not_found_endpoint(_cx: Context) -> BoxFuture<'static, Response> { - box_async! { + FutureExt::boxed(async move { http::Response::builder().status(http::StatusCode::NOT_FOUND).body(Body::empty()).unwrap() - } + }) } diff --git a/tide/src/forms.rs b/tide/src/forms.rs index b7338dab5..2465b2e59 100644 --- a/tide/src/forms.rs +++ b/tide/src/forms.rs @@ -1,5 +1,6 @@ use http_service::Body; use multipart::server::Multipart; +use futures::prelude::*; use std::io::Cursor; use crate::{ @@ -19,10 +20,10 @@ pub trait ExtractForms { impl ExtractForms for Context { fn body_form(&mut self) -> BoxTryFuture { let body = self.take_body(); - box_async! { + FutureExt::boxed(async move { let body = body.into_vec().await.client_err()?; Ok(serde_urlencoded::from_bytes(&body).map_err(|e| err_fmt!("could not decode form: {}", e)).client_err()?) - } + }) } fn body_multipart(&mut self) -> BoxTryFuture>>> { @@ -35,11 +36,11 @@ impl ExtractForms for Context { let body = self.take_body(); - box_async! { + FutureExt::boxed(async move { let body = body.into_vec().await.client_err()?; let boundary = boundary.ok_or_else(|| err_fmt!("no boundary found")).client_err()?; Ok(Multipart::with_body(Cursor::new(body), boundary)) - } + }) } } diff --git a/tide/src/lib.rs b/tide/src/lib.rs index 6ef962c0b..3337ff4f9 100755 --- a/tide/src/lib.rs +++ b/tide/src/lib.rs @@ -22,12 +22,6 @@ #[doc(include = "../../README.md")] const _README: () = (); -macro_rules! box_async { - {$($t:tt)*} => { - ::futures::future::FutureExt::boxed(async move { $($t)* }) - }; -} - #[macro_use] extern crate tide_core; diff --git a/tide/src/middleware/default_headers.rs b/tide/src/middleware/default_headers.rs index d7b5bffe4..d76dbb192 100644 --- a/tide/src/middleware/default_headers.rs +++ b/tide/src/middleware/default_headers.rs @@ -1,4 +1,5 @@ use futures::future::BoxFuture; +use futures::prelude::*; use http::{ header::{HeaderValue, IntoHeaderName}, @@ -41,7 +42,7 @@ impl DefaultHeaders { impl Middleware for DefaultHeaders { fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { - box_async! { + FutureExt::boxed(async move { let mut res = next.run(cx).await; let headers = res.headers_mut(); @@ -49,6 +50,6 @@ impl Middleware for DefaultHeaders { headers.entry(key).unwrap().or_insert_with(|| value.clone()); } res - } + }) } } diff --git a/tide/src/middleware/logger.rs b/tide/src/middleware/logger.rs index 3becf7928..8036cf585 100644 --- a/tide/src/middleware/logger.rs +++ b/tide/src/middleware/logger.rs @@ -3,6 +3,7 @@ use slog_async; use slog_term; use futures::future::BoxFuture; +use futures::prelude::*; use crate::{ middleware::{Middleware, Next}, @@ -37,7 +38,7 @@ impl Default for RootLogger { /// is generated. impl Middleware for RootLogger { fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { - box_async! { + FutureExt::boxed(async move { let path = cx.uri().path().to_owned(); let method = cx.method().as_str().to_owned(); @@ -45,6 +46,6 @@ impl Middleware for RootLogger { let status = res.status(); info!(self.inner_logger, "{} {} {}", method, path, status.as_str()); res - } + }) } } From e7703fddddba990cc450ef7dda92dfe7a90cf2a4 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 20 May 2019 23:35:50 +0200 Subject: [PATCH 20/95] rustfmt Signed-off-by: Yoshua Wuyts --- tide-cookies/src/middleware.rs | 2 +- tide-core/src/endpoint.rs | 4 +--- tide-core/src/router.rs | 5 ++++- tide/src/forms.rs | 10 +++++++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 2d300369f..e8dafd243 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -1,7 +1,7 @@ use crate::data::CookieData; use futures::future::BoxFuture; -use http::header::HeaderValue; use futures::prelude::*; +use http::header::HeaderValue; use tide_core::{ middleware::{Middleware, Next}, diff --git a/tide-core/src/endpoint.rs b/tide-core/src/endpoint.rs index 663654868..c7959b469 100644 --- a/tide-core/src/endpoint.rs +++ b/tide-core/src/endpoint.rs @@ -69,8 +69,6 @@ where type Fut = BoxFuture<'static, Response>; fn call(&self, cx: Context) -> Self::Fut { let fut = (self)(cx); - FutureExt::boxed(async move { - fut.await.into_response() - }) + FutureExt::boxed(async move { fut.await.into_response() }) } } diff --git a/tide-core/src/router.rs b/tide-core/src/router.rs index 0b028c2fa..eb97a90ba 100644 --- a/tide-core/src/router.rs +++ b/tide-core/src/router.rs @@ -64,6 +64,9 @@ impl Router { fn not_found_endpoint(_cx: Context) -> BoxFuture<'static, Response> { FutureExt::boxed(async move { - http::Response::builder().status(http::StatusCode::NOT_FOUND).body(Body::empty()).unwrap() + http::Response::builder() + .status(http::StatusCode::NOT_FOUND) + .body(Body::empty()) + .unwrap() }) } diff --git a/tide/src/forms.rs b/tide/src/forms.rs index 2465b2e59..be4a39367 100644 --- a/tide/src/forms.rs +++ b/tide/src/forms.rs @@ -1,6 +1,6 @@ +use futures::prelude::*; use http_service::Body; use multipart::server::Multipart; -use futures::prelude::*; use std::io::Cursor; use crate::{ @@ -22,7 +22,9 @@ impl ExtractForms for Context { let body = self.take_body(); FutureExt::boxed(async move { let body = body.into_vec().await.client_err()?; - Ok(serde_urlencoded::from_bytes(&body).map_err(|e| err_fmt!("could not decode form: {}", e)).client_err()?) + Ok(serde_urlencoded::from_bytes(&body) + .map_err(|e| err_fmt!("could not decode form: {}", e)) + .client_err()?) }) } @@ -38,7 +40,9 @@ impl ExtractForms for Context { FutureExt::boxed(async move { let body = body.into_vec().await.client_err()?; - let boundary = boundary.ok_or_else(|| err_fmt!("no boundary found")).client_err()?; + let boundary = boundary + .ok_or_else(|| err_fmt!("no boundary found")) + .client_err()?; Ok(Multipart::with_body(Cursor::new(body), boundary)) }) } From 4806db4abfe03f8ae17d09b7d734c7cba19c2242 Mon Sep 17 00:00:00 2001 From: Dalei Date: Tue, 21 May 2019 05:55:41 +0800 Subject: [PATCH 21/95] Fix broken links in readme (#242) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e60e6f65..f2129f50b 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ fn main() -> Result<(), std::io::Error> { - [Hello World](https://github.com/rustasync/tide/blob/master/examples/src/hello.rs) - [Messages](https://github.com/rustasync/tide/blob/master/examples/src/messages.rs) - [Body Types](https://github.com/rustasync/tide/blob/master/examples/src/body_types.rs) -- [Multipart Form](https://github.com/rustasync/tide/blob/master/examples/src/multipart-form/main.rs) +- [Multipart Form](https://github.com/rustasync/tide/blob/master/examples/src/multipart_form/mod.rs) - [Catch All](https://github.com/rustasync/tide/blob/master/examples/src/catch_all.rs) - [Cookies](https://github.com/rustasync/tide/blob/master/examples/src/cookies.rs) - [Default Headers](https://github.com/rustasync/tide/blob/master/examples/src/default_headers.rs) From 114c17cc6eeaededeb4d470ef891088ddf827174 Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Tue, 21 May 2019 01:50:38 +0200 Subject: [PATCH 22/95] Sweep the cache before uploading it (#246) --- .travis.yml | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc4c46432..dd540f831 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,29 +2,57 @@ language: rust rust: nightly-2019-05-09 cache: cargo +before_script: +- > + [[ "$(cargo-sweep --version)" == "cargo-sweep 0.4.1" ]] + || cargo install cargo-sweep +- cargo sweep --stamp + +before_cache: +- cargo sweep --file + matrix: include: - name: cargo doc env: [CACHE_NAME=docs] script: - - RUSTDOCFLAGS=-Dwarnings - cargo doc --all --all-features --no-deps --exclude tide + - RUSTDOCFLAGS=-Dwarnings cargo doc + -Zmtime-on-use + --all --all-features + --exclude tide + --no-deps - name: cargo fmt cache: false - before_script: rustup component add rustfmt - script: cargo fmt --all -- --check + before_script: [] + install: + - rustup component add rustfmt + script: + - cargo fmt --all -- --check - name: cargo clippy env: [CACHE_NAME=clippy] - before_script: rustup component add clippy - script: cargo clippy --all --all-targets --exclude examples -- -Dwarnings + install: + - rustup component add clippy + script: + - cargo clippy + -Zmtime-on-use + --all --all-targets + --exclude examples + -- -Dwarnings - name: cargo build --no-default-features env: [CACHE_NAME=no-default-features] script: - - cargo build --manifest-path tide/Cargo.toml --no-default-features - - cargo build --manifest-path tide-core/Cargo.toml --no-default-features + - cargo build + -Zmtime-on-use + --manifest-path tide-core/Cargo.toml + --no-default-features + - cargo build + -Zmtime-on-use + --manifest-path tide/Cargo.toml + --no-default-features - name: cargo test - script: cargo test --all --verbose + script: + - cargo test -Zmtime-on-use --all --verbose From 0d8caa9608691eff161c4dc8df154e65dc7fa8bc Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 21 May 2019 01:51:46 +0200 Subject: [PATCH 23/95] move tide/ to src/ Signed-off-by: Yoshua Wuyts --- Cargo.toml | 64 +++++++++++++++++-- examples/Cargo.toml | 32 ---------- examples/{src => }/body_types.rs | 0 examples/{src => }/catch_all.rs | 0 examples/{src => }/cookies.rs | 0 examples/{src => }/default_headers.rs | 0 examples/{src => }/graphql.rs | 0 examples/{src => }/hello.rs | 0 examples/{src => }/lib.rs | 0 examples/{src => }/messages.rs | 0 examples/{src => }/multipart_form/mod.rs | 0 examples/{src => }/multipart_form/test.txt | 0 examples/{src => }/staticfile.rs | 0 {tide/src => src}/error.rs | 0 {tide/src => src}/forms.rs | 0 {tide/src => src}/lib.rs | 0 .../src => src}/middleware/default_headers.rs | 0 {tide/src => src}/middleware/logger.rs | 0 {tide/src => src}/middleware/mod.rs | 0 {tide/src => src}/querystring.rs | 0 {tide/tests => tests}/wildcard.rs | 0 tide-compression/Cargo.toml | 2 +- tide-core/Cargo.toml | 2 +- tide/Cargo.toml | 45 ------------- 24 files changed, 59 insertions(+), 86 deletions(-) delete mode 100644 examples/Cargo.toml rename examples/{src => }/body_types.rs (100%) rename examples/{src => }/catch_all.rs (100%) rename examples/{src => }/cookies.rs (100%) rename examples/{src => }/default_headers.rs (100%) rename examples/{src => }/graphql.rs (100%) rename examples/{src => }/hello.rs (100%) rename examples/{src => }/lib.rs (100%) rename examples/{src => }/messages.rs (100%) rename examples/{src => }/multipart_form/mod.rs (100%) rename examples/{src => }/multipart_form/test.txt (100%) rename examples/{src => }/staticfile.rs (100%) rename {tide/src => src}/error.rs (100%) rename {tide/src => src}/forms.rs (100%) rename {tide/src => src}/lib.rs (100%) rename {tide/src => src}/middleware/default_headers.rs (100%) rename {tide/src => src}/middleware/logger.rs (100%) rename {tide/src => src}/middleware/mod.rs (100%) rename {tide/src => src}/querystring.rs (100%) rename {tide/tests => tests}/wildcard.rs (100%) delete mode 100644 tide/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 3cf23390f..8a466bd06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,63 @@ +[package] +authors = [ + "Aaron Turon ", + "Yoshua Wuyts ", +] +description = "WIP modular web framework" +documentation = "https://docs.rs/tide" +keywords = ["tide", "http", "web", "framework", "async"] +categories = [ + "network-programming", + "asynchronous", + "web-programming::http-server" +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.2.0" + +[features] +default = ["hyper", "cookies"] +cookies = ["tide-cookies"] +hyper = ["tide-core/http-service-hyper"] + +[dependencies] +futures-preview = "0.3.0-alpha.16" +http = "0.1" +http-service = "0.2.0" +serde = "1.0.91" +serde_derive = "1.0.91" +slog = "2.4.1" +slog-async = "2.3.0" +slog-term = "2.4.0" +serde_urlencoded = "0.5.5" +tide-cookies = { path = "./tide-cookies", optional = true } +tide-core = { path = "./tide-core" } + +[dependencies.multipart] +default-features = false +features = ["server"] +version = "0.16.1" + +[dev-dependencies] +bytes = "0.4.12" +cookie = { version = "0.12", features = ["percent-encode"] } +futures-fs = "0.0.5" +futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } +http = "0.1" +http-service = "0.2.0" +http-service-mock = "0.2.0" +juniper = "0.11.1" +mime = "0.3.13" +mime_guess = "2.0.0-alpha.6" +percent-encoding = "1.0.1" +serde = { version = "1.0.91", features = ["derive"] } + [workspace] members = [ - "tide", "tide-compression", "tide-cookies", "tide-core", - "examples", ] - -[patch.crates-io] -http-service = { git = "https://github.com/rustasync/http-service", branch = "master" } -http-service-hyper = { git = "https://github.com/rustasync/http-service", branch = "master" } -http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "master" } diff --git a/examples/Cargo.toml b/examples/Cargo.toml deleted file mode 100644 index af1206539..000000000 --- a/examples/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -authors = [ - "Tide Developers", -] -description = "Tide web server examples" -documentation = "https://docs.rs/tide" -edition = "2018" -license = "MIT OR Apache-2.0" -name = "examples" -readme = "README.md" -repository = "https://github.com/rustasync/tide" -version = "0.1.0" -publish = false - -[dependencies] -tide = { path = "../tide" } -cookie = { version = "0.12", features = ["percent-encode"] } -http = "0.1" -http-service = "0.2.0" -bytes = "0.4.12" -futures-fs = "0.0.5" -futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } -juniper = "0.11.1" -mime = "0.3.13" -mime_guess = "2.0.0-alpha.6" -percent-encoding = "1.0.1" -serde = { version = "1.0.91", features = ["derive"] } - -[dependencies.multipart] -default-features = false -features = ["server"] -version = "0.16.1" diff --git a/examples/src/body_types.rs b/examples/body_types.rs similarity index 100% rename from examples/src/body_types.rs rename to examples/body_types.rs diff --git a/examples/src/catch_all.rs b/examples/catch_all.rs similarity index 100% rename from examples/src/catch_all.rs rename to examples/catch_all.rs diff --git a/examples/src/cookies.rs b/examples/cookies.rs similarity index 100% rename from examples/src/cookies.rs rename to examples/cookies.rs diff --git a/examples/src/default_headers.rs b/examples/default_headers.rs similarity index 100% rename from examples/src/default_headers.rs rename to examples/default_headers.rs diff --git a/examples/src/graphql.rs b/examples/graphql.rs similarity index 100% rename from examples/src/graphql.rs rename to examples/graphql.rs diff --git a/examples/src/hello.rs b/examples/hello.rs similarity index 100% rename from examples/src/hello.rs rename to examples/hello.rs diff --git a/examples/src/lib.rs b/examples/lib.rs similarity index 100% rename from examples/src/lib.rs rename to examples/lib.rs diff --git a/examples/src/messages.rs b/examples/messages.rs similarity index 100% rename from examples/src/messages.rs rename to examples/messages.rs diff --git a/examples/src/multipart_form/mod.rs b/examples/multipart_form/mod.rs similarity index 100% rename from examples/src/multipart_form/mod.rs rename to examples/multipart_form/mod.rs diff --git a/examples/src/multipart_form/test.txt b/examples/multipart_form/test.txt similarity index 100% rename from examples/src/multipart_form/test.txt rename to examples/multipart_form/test.txt diff --git a/examples/src/staticfile.rs b/examples/staticfile.rs similarity index 100% rename from examples/src/staticfile.rs rename to examples/staticfile.rs diff --git a/tide/src/error.rs b/src/error.rs similarity index 100% rename from tide/src/error.rs rename to src/error.rs diff --git a/tide/src/forms.rs b/src/forms.rs similarity index 100% rename from tide/src/forms.rs rename to src/forms.rs diff --git a/tide/src/lib.rs b/src/lib.rs similarity index 100% rename from tide/src/lib.rs rename to src/lib.rs diff --git a/tide/src/middleware/default_headers.rs b/src/middleware/default_headers.rs similarity index 100% rename from tide/src/middleware/default_headers.rs rename to src/middleware/default_headers.rs diff --git a/tide/src/middleware/logger.rs b/src/middleware/logger.rs similarity index 100% rename from tide/src/middleware/logger.rs rename to src/middleware/logger.rs diff --git a/tide/src/middleware/mod.rs b/src/middleware/mod.rs similarity index 100% rename from tide/src/middleware/mod.rs rename to src/middleware/mod.rs diff --git a/tide/src/querystring.rs b/src/querystring.rs similarity index 100% rename from tide/src/querystring.rs rename to src/querystring.rs diff --git a/tide/tests/wildcard.rs b/tests/wildcard.rs similarity index 100% rename from tide/tests/wildcard.rs rename to tests/wildcard.rs diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml index 19bb2c92c..f00c417d5 100644 --- a/tide-compression/Cargo.toml +++ b/tide-compression/Cargo.toml @@ -14,7 +14,7 @@ repository = "https://github.com/rustasync/tide" version = "0.1.0" [dependencies] -tide = { path = "../tide" } +tide = { path = "../" } accept-encoding = "0.2.0-alpha.2" bytes = "0.4.12" futures-preview = "0.3.0-alpha.16" diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index 60ef60fe8..137b65f38 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -24,7 +24,7 @@ optional = true version = "0.2.0" [dev-dependencies] -tide = { path = "../tide" } +tide = { path = "../" } serde_derive = "1.0.91" [features] diff --git a/tide/Cargo.toml b/tide/Cargo.toml deleted file mode 100644 index ce2cb9f28..000000000 --- a/tide/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -authors = [ - "Aaron Turon ", - "Yoshua Wuyts ", -] -description = "WIP modular web framework" -documentation = "https://docs.rs/tide" -keywords = ["tide", "http", "web", "framework", "async"] -categories = [ - "network-programming", - "asynchronous", - "web-programming::http-server" -] -edition = "2018" -license = "MIT OR Apache-2.0" -name = "tide" -readme = "README.md" -repository = "https://github.com/rustasync/tide" -version = "0.2.0" - -[dependencies] -futures-preview = "0.3.0-alpha.16" -http = "0.1" -http-service = "0.2.0" -serde = "1.0.91" -serde_derive = "1.0.91" -slog = "2.4.1" -slog-async = "2.3.0" -slog-term = "2.4.0" -serde_urlencoded = "0.5.5" -tide-cookies = { path = "../tide-cookies", optional = true } -tide-core = { path = "../tide-core" } - -[dependencies.multipart] -default-features = false -features = ["server"] -version = "0.16.1" - -[features] -default = ["hyper", "cookies"] -cookies = ["tide-cookies"] -hyper = ["tide-core/http-service-hyper"] - -[dev-dependencies] -http-service-mock = "0.2.0" From e11f71a31877e8c4e35599f3c073d82655c4e45a Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 21 May 2019 01:56:58 +0200 Subject: [PATCH 24/95] fix examples Signed-off-by: Yoshua Wuyts --- Cargo.toml | 9 ++++++--- examples/body_types.rs | 3 ++- examples/catch_all.rs | 3 ++- examples/cookies.rs | 3 ++- examples/default_headers.rs | 4 +++- examples/graphql.rs | 3 ++- examples/hello.rs | 3 ++- examples/lib.rs | 13 ------------- examples/messages.rs | 4 +++- examples/multipart_form/mod.rs | 1 + examples/staticfile.rs | 4 +++- tide-compression/examples/simple.rs | 2 +- 12 files changed, 27 insertions(+), 25 deletions(-) delete mode 100644 examples/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 8a466bd06..e8ccfe732 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,10 +29,10 @@ http = "0.1" http-service = "0.2.0" serde = "1.0.91" serde_derive = "1.0.91" +serde_urlencoded = "0.5.5" slog = "2.4.1" slog-async = "2.3.0" slog-term = "2.4.0" -serde_urlencoded = "0.5.5" tide-cookies = { path = "./tide-cookies", optional = true } tide-core = { path = "./tide-core" } @@ -46,8 +46,6 @@ bytes = "0.4.12" cookie = { version = "0.12", features = ["percent-encode"] } futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } -http = "0.1" -http-service = "0.2.0" http-service-mock = "0.2.0" juniper = "0.11.1" mime = "0.3.13" @@ -61,3 +59,8 @@ members = [ "tide-cookies", "tide-core", ] + +[patch.crates-io] +http-service = { git = "https://github.com/rustasync/http-service", branch = "master" } +http-service-hyper = { git = "https://github.com/rustasync/http-service", branch = "master" } +http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "master" } diff --git a/examples/body_types.rs b/examples/body_types.rs index f85c90a00..10dd46fac 100644 --- a/examples/body_types.rs +++ b/examples/body_types.rs @@ -1,3 +1,4 @@ +#![feature(async_await)] use serde::{Deserialize, Serialize}; use tide::{ error::ResultExt, @@ -35,7 +36,7 @@ async fn echo_form(mut cx: Context<()>) -> EndpointResult { Ok(forms::form(msg)) } -pub fn main() { +fn main() { let mut app = App::new(); app.at("/echo/string").post(echo_string); diff --git a/examples/catch_all.rs b/examples/catch_all.rs index ebdf736c3..7ff1980d5 100644 --- a/examples/catch_all.rs +++ b/examples/catch_all.rs @@ -1,3 +1,4 @@ +#![feature(async_await)] use tide::Context; async fn echo_path(cx: Context<()>) -> String { @@ -5,7 +6,7 @@ async fn echo_path(cx: Context<()>) -> String { format!("Your path is: {}", path) } -pub fn main() { +fn main() { let mut app = tide::App::new(); app.at("/echo_path/*path").get(echo_path); app.run("127.0.0.1:8000").unwrap(); diff --git a/examples/cookies.rs b/examples/cookies.rs index 670c6afd7..92820e6a8 100644 --- a/examples/cookies.rs +++ b/examples/cookies.rs @@ -1,3 +1,4 @@ +#![feature(async_await)] use cookie::Cookie; use tide::{cookies::ContextExt, middleware::CookiesMiddleware, Context}; @@ -14,7 +15,7 @@ async fn remove_cookie(mut cx: Context<()>) { cx.remove_cookie(Cookie::named("hello")).unwrap(); } -pub fn main() { +fn main() { let mut app = tide::App::new(); app.middleware(CookiesMiddleware::new()); diff --git a/examples/default_headers.rs b/examples/default_headers.rs index b76bfddc7..70f4a8d54 100644 --- a/examples/default_headers.rs +++ b/examples/default_headers.rs @@ -1,6 +1,8 @@ +#![feature(async_await)] + use tide::middleware::DefaultHeaders; -pub fn main() { +fn main() { let mut app = tide::App::new(); app.middleware( diff --git a/examples/graphql.rs b/examples/graphql.rs index a85af2e69..a78c71c00 100644 --- a/examples/graphql.rs +++ b/examples/graphql.rs @@ -2,6 +2,7 @@ // a look at [the Juniper book]. // // [the Juniper book]: https://graphql-rust.github.io/ +#![feature(async_await)] use http::status::StatusCode; use juniper::graphql_object; use std::sync::{atomic, Arc}; @@ -56,7 +57,7 @@ async fn handle_graphql(mut cx: Context) -> EndpointResult { Ok(resp) } -pub fn main() { +fn main() { let mut app = App::with_state(Data::default()); app.at("/graphql").post(handle_graphql); app.run("127.0.0.1:8000").unwrap(); diff --git a/examples/hello.rs b/examples/hello.rs index 1a11e05c9..edcf106e2 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,4 +1,5 @@ -pub fn main() { +#![feature(async_await)] +fn main() { let mut app = tide::App::new(); app.at("/").get(async move |_| "Hello, world!"); app.run("127.0.0.1:8000").unwrap(); diff --git a/examples/lib.rs b/examples/lib.rs deleted file mode 100644 index 31679fc28..000000000 --- a/examples/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(async_await)] -#![warn(clippy::all)] -#![allow(dead_code)] - -mod body_types; -mod catch_all; -mod cookies; -mod default_headers; -mod graphql; -mod hello; -mod messages; -mod multipart_form; -mod staticfile; diff --git a/examples/messages.rs b/examples/messages.rs index 4abdadf61..023528c89 100644 --- a/examples/messages.rs +++ b/examples/messages.rs @@ -1,3 +1,5 @@ +#![feature(async_await)] + use http::status::StatusCode; use serde::{Deserialize, Serialize}; use std::sync::Mutex; @@ -62,7 +64,7 @@ async fn get_message(cx: Context) -> EndpointResult { } } -pub fn main() { +fn main() { let mut app = App::with_state(Database::default()); app.at("/message").post(new_message); app.at("/message/:id").get(get_message).post(set_message); diff --git a/examples/multipart_form/mod.rs b/examples/multipart_form/mod.rs index bf6acc4a4..0abef7c48 100644 --- a/examples/multipart_form/mod.rs +++ b/examples/multipart_form/mod.rs @@ -1,3 +1,4 @@ +#![feature(async_await)] use serde::{Deserialize, Serialize}; use std::io::Read; use tide::{forms::ContextExt, response, App, Context, EndpointResult}; diff --git a/examples/staticfile.rs b/examples/staticfile.rs index cf44ccd97..d712aceb8 100644 --- a/examples/staticfile.rs +++ b/examples/staticfile.rs @@ -1,3 +1,5 @@ +#![feature(async_await)] + use bytes::Bytes; use futures_fs::FsPool; use futures_util::compat::*; @@ -119,7 +121,7 @@ async fn handle_path(ctx: Context) -> EndpointResult { }) } -pub fn main() { +fn main() { let mut app = App::with_state(StaticFile::new("./")); app.at("/*").get(handle_path); app.run("127.0.0.1:8000").unwrap(); diff --git a/tide-compression/examples/simple.rs b/tide-compression/examples/simple.rs index 2f5d0e174..73484eac0 100644 --- a/tide-compression/examples/simple.rs +++ b/tide-compression/examples/simple.rs @@ -12,7 +12,7 @@ async fn echo_bytes(mut cx: Context<()>) -> Vec { cx.body_bytes().await.unwrap() } -pub fn main() { +fn main() { let mut app = App::new(); app.at("/").get(lorem_ipsum); app.at("/echo").post(echo_bytes); From 15eee7708e976c5a8d8afa4c450d4ff52a4be74d Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 21 May 2019 02:13:29 +0200 Subject: [PATCH 25/95] fix tests Signed-off-by: Yoshua Wuyts --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6ef962c0b..ef9650015 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ //! #[cfg(test)] -#[doc(include = "../../README.md")] +#[doc(include = "../README.md")] const _README: () = (); macro_rules! box_async { From 7a8a33bb157682ed16c0336560f751942786fd0b Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 21 May 2019 02:14:29 +0200 Subject: [PATCH 26/95] remove certificate Signed-off-by: Yoshua Wuyts --- .github/CONTRIBUTING.md | 8 -------- CERTIFICATE | 37 ------------------------------------- 2 files changed, 45 deletions(-) delete mode 100644 CERTIFICATE diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e3ad56ae0..a11172a7f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -11,7 +11,6 @@ Repository. - [Code of Conduct](#code-of-conduct) - [Bad Actors](#bad-actors) -- [Developer Certificate of Origin](#developer-certificate-of-origin) ## Code of Conduct The project has a [Code of Conduct](./CODE_OF_CONDUCT.md) that *all* @@ -54,10 +53,3 @@ contributors the benefit of the doubt and having a sincere willingness to admit that you *might* be wrong is critical for any successful open collaboration. Don't be a bad actor. - -## Developer Certificate of Origin -All contributors must read and agree to the [Developer Certificate of -Origin (DCO)](../CERTIFICATE). - -The DCO allows us to accept contributions from people to the project, similarly -to how a license allows us to distribute our code. diff --git a/CERTIFICATE b/CERTIFICATE deleted file mode 100644 index 8201f9921..000000000 --- a/CERTIFICATE +++ /dev/null @@ -1,37 +0,0 @@ -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -1 Letterman Drive -Suite D4700 -San Francisco, CA, 94129 - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. From e30f184f0ffa666897cac6f2394f58b75cae5bf0 Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 20 May 2019 21:54:38 -0700 Subject: [PATCH 27/95] remove `--manifest-path` `tide` now sits at root of crate --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cc4c46432..cde8a0275 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ matrix: - name: cargo build --no-default-features env: [CACHE_NAME=no-default-features] script: - - cargo build --manifest-path tide/Cargo.toml --no-default-features + - cargo build --no-default-features - cargo build --manifest-path tide-core/Cargo.toml --no-default-features - name: cargo test From 4df808d0290cb2b8212f452335b7371f7dcb0299 Mon Sep 17 00:00:00 2001 From: "Prasanna V. Loganathar" Date: Tue, 21 May 2019 10:53:04 +0530 Subject: [PATCH 28/95] add tide-log (#222) * add tide-log * remove box_async macro --- Cargo.toml | 1 + tide-log/Cargo.toml | 24 ++++++++++++++++++ tide-log/src/lib.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 tide-log/Cargo.toml create mode 100644 tide-log/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e8ccfe732..a8fdb55e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ members = [ "tide-compression", "tide-cookies", "tide-core", + "tide-log", ] [patch.crates-io] diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml new file mode 100644 index 000000000..515dda102 --- /dev/null +++ b/tide-log/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = [ + "Tide Developers" +] +description = "Tide middleware for logging" +documentation = "https://docs.rs/tide-log" +keywords = ["tide", "web", "async", "middleware", "logging"] +categories = [ + "logging", + "network-programming", + "web-programming::http-server", +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide-log" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" + + [dependencies] +tide = { path = "../" } +futures-preview = "0.3.0-alpha.16" +http = "0.1" +log = "0.4.6" diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs new file mode 100644 index 000000000..865c6f37b --- /dev/null +++ b/tide-log/src/lib.rs @@ -0,0 +1,60 @@ +#![feature(async_await)] +#![deny( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + +use futures::future::BoxFuture; +use futures::prelude::*; +use log::{info, trace}; +use tide::{ + middleware::{Middleware, Next}, + Context, Response, +}; + +/// A simple requests logger +/// +/// # Examples +/// +/// ```rust +/// +/// let mut app = tide::App::new(); +/// app.middleware(tide_log::RequestLogger::new()); +/// ``` +#[derive(Debug, Clone, Default)] +pub struct RequestLogger; + +impl RequestLogger { + pub fn new() -> Self { + Self::default() + } + + async fn log_basic<'a, Data: Send + Sync + 'static>( + &'a self, + ctx: Context, + next: Next<'a, Data>, + ) -> tide::Response { + let path = ctx.uri().path().to_owned(); + let method = ctx.method().as_str().to_owned(); + trace!("IN => {} {}", method, path); + let start = std::time::Instant::now(); + let res = next.run(ctx).await; + let status = res.status(); + info!( + "{} {} {} {}ms", + method, + path, + status.as_str(), + start.elapsed().as_millis() + ); + res + } +} + +impl Middleware for RequestLogger { + fn handle<'a>(&'a self, ctx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { + FutureExt::boxed(async move { self.log_basic(ctx, next).await }) + } +} From a9fbc58d2376fc00393edcdc0d1d6fba8eb31f21 Mon Sep 17 00:00:00 2001 From: k-nasa Date: Tue, 21 May 2019 14:52:20 +0900 Subject: [PATCH 29/95] feat: add type annotation --- examples/body_types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/body_types.rs b/examples/body_types.rs index 10dd46fac..18269bfb0 100644 --- a/examples/body_types.rs +++ b/examples/body_types.rs @@ -25,13 +25,13 @@ async fn echo_bytes(mut cx: Context<()>) -> Vec { } async fn echo_json(mut cx: Context<()>) -> EndpointResult { - let msg = cx.body_json().await.client_err()?; + let msg: Message = cx.body_json().await.client_err()?; println!("JSON: {:?}", msg); Ok(response::json(msg)) } async fn echo_form(mut cx: Context<()>) -> EndpointResult { - let msg = cx.body_form().await?; + let msg: Message = cx.body_form().await?; println!("Form: {:?}", msg); Ok(forms::form(msg)) } From e45a7e5c54d5afaeccf44c403c16b5f6adf36c44 Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 20 May 2019 23:11:44 -0700 Subject: [PATCH 30/95] Update .travis.yml `examples` is no longer a package in the workspace following #247 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 97dc27fc2..5a15187c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,6 @@ matrix: - cargo clippy -Zmtime-on-use --all --all-targets - --exclude examples -- -Dwarnings - name: cargo build --no-default-features From 1a93fc25ec6314af7e72f5e4e8fd4304b4f24055 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 21 May 2019 07:34:25 +0000 Subject: [PATCH 31/95] Update juniper requirement from 0.11.1 to 0.12.0 Updates the requirements on [juniper](https://github.com/graphql-rust/juniper) to permit the latest version. - [Release notes](https://github.com/graphql-rust/juniper/releases) - [Commits](https://github.com/graphql-rust/juniper/commits) Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a8fdb55e7..d6e03173d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ cookie = { version = "0.12", features = ["percent-encode"] } futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } http-service-mock = "0.2.0" -juniper = "0.11.1" +juniper = "0.12.0" mime = "0.3.13" mime_guess = "2.0.0-alpha.6" percent-encoding = "1.0.1" From 8b06916e75de05b8ba34021f07b3e897479857e3 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 21 May 2019 16:50:14 +0530 Subject: [PATCH 32/95] isolate tide-headers, tide-slog; better; improve loggers --- Cargo.toml | 11 ++-- src/{middleware/mod.rs => middleware.rs} | 10 ++-- tide-headers/Cargo.toml | 23 ++++++++ .../src/lib.rs | 19 +++++-- tide-log/Cargo.toml | 6 +-- tide-log/src/lib.rs | 29 ++++++++-- tide-slog/Cargo.toml | 27 ++++++++++ .../logger.rs => tide-slog/src/lib.rs | 54 +++++++++++++------ 8 files changed, 142 insertions(+), 37 deletions(-) rename src/{middleware/mod.rs => middleware.rs} (53%) create mode 100644 tide-headers/Cargo.toml rename src/middleware/default_headers.rs => tide-headers/src/lib.rs (79%) create mode 100644 tide-slog/Cargo.toml rename src/middleware/logger.rs => tide-slog/src/lib.rs (51%) diff --git a/Cargo.toml b/Cargo.toml index a8fdb55e7..61250f838 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,11 +30,10 @@ http-service = "0.2.0" serde = "1.0.91" serde_derive = "1.0.91" serde_urlencoded = "0.5.5" -slog = "2.4.1" -slog-async = "2.3.0" -slog-term = "2.4.0" tide-cookies = { path = "./tide-cookies", optional = true } tide-core = { path = "./tide-core" } +tide-headers = { path = "./tide-headers" } +tide-log = { path = "./tide-log" } [dependencies.multipart] default-features = false @@ -52,13 +51,19 @@ mime = "0.3.13" mime_guess = "2.0.0-alpha.6" percent-encoding = "1.0.1" serde = { version = "1.0.91", features = ["derive"] } +tide-log = { path = "./tide-log" } +env_logger = "0.6.1" +log4rs = "0.8.3" +log = "0.4.6" [workspace] members = [ "tide-compression", "tide-cookies", "tide-core", + "tide-headers", "tide-log", + "tide-slog", ] [patch.crates-io] diff --git a/src/middleware/mod.rs b/src/middleware.rs similarity index 53% rename from src/middleware/mod.rs rename to src/middleware.rs index aaa20d48b..581792a7a 100644 --- a/src/middleware/mod.rs +++ b/src/middleware.rs @@ -1,7 +1,9 @@ -mod default_headers; -mod logger; +// Core +pub use tide_core::middleware::{Middleware, Next}; + +// Exports from tide repo. +pub use tide_headers::DefaultHeaders; +pub use tide_log::RequestLogger; -pub use self::{default_headers::DefaultHeaders, logger::RootLogger}; #[cfg(feature = "cookies")] pub use tide_cookies::CookiesMiddleware; -pub use tide_core::middleware::{Middleware, Next}; diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml new file mode 100644 index 000000000..0d02e69a0 --- /dev/null +++ b/tide-headers/Cargo.toml @@ -0,0 +1,23 @@ +[package] +authors = [ + "Tide Developers" +] +description = "Header related middleware for tide" +documentation = "https://docs.rs/tide-log" +keywords = ["tide", "web", "async", "middleware", "headers"] +categories = [ + "network-programming", + "web-programming::http-server", +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide-headers" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" + + [dependencies] +tide-core = { path = "../tide-core" } +futures-preview = "0.3.0-alpha.16" +http = "0.1" +log = "0.4.6" diff --git a/src/middleware/default_headers.rs b/tide-headers/src/lib.rs similarity index 79% rename from src/middleware/default_headers.rs rename to tide-headers/src/lib.rs index d76dbb192..36b080567 100644 --- a/src/middleware/default_headers.rs +++ b/tide-headers/src/lib.rs @@ -1,12 +1,23 @@ +//! Crate that provides helpers, and/or middlewares for tide +//! related to http headers. +#![feature(async_await)] +#![warn( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + use futures::future::BoxFuture; use futures::prelude::*; +use log::trace; use http::{ header::{HeaderValue, IntoHeaderName}, HeaderMap, HttpTryFrom, }; -use crate::{ +use tide_core::{ middleware::{Middleware, Next}, Context, Response, }; @@ -20,10 +31,9 @@ pub struct DefaultHeaders { impl DefaultHeaders { /// Construct a new instance with an empty list of headers. pub fn new() -> DefaultHeaders { - DefaultHeaders::default() + Self::default() } - #[inline] /// Add a header to the default header list. pub fn header(mut self, key: K, value: V) -> Self where @@ -35,7 +45,6 @@ impl DefaultHeaders { .expect("Cannot create default header"); self.headers.append(key, value); - self } } @@ -44,9 +53,9 @@ impl Middleware for DefaultHeaders { fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { let mut res = next.run(cx).await; - let headers = res.headers_mut(); for (key, value) in self.headers.iter() { + trace!("add default: {} {:?}", &key, &value); headers.entry(key).unwrap().or_insert_with(|| value.clone()); } res diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml index 515dda102..24671ec59 100644 --- a/tide-log/Cargo.toml +++ b/tide-log/Cargo.toml @@ -2,7 +2,7 @@ authors = [ "Tide Developers" ] -description = "Tide middleware for logging" +description = "Logging middleware for tide" documentation = "https://docs.rs/tide-log" keywords = ["tide", "web", "async", "middleware", "logging"] categories = [ @@ -18,7 +18,7 @@ repository = "https://github.com/rustasync/tide" version = "0.1.0" [dependencies] -tide = { path = "../" } +tide-core = { path = "../tide-core" } futures-preview = "0.3.0-alpha.16" http = "0.1" -log = "0.4.6" +log = "0.4.6" diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index 91f057031..a7a875014 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -1,3 +1,6 @@ +//! Crate that provides helpers and/or middlewares for tide +//! related to logging. +//! #![feature(async_await)] #![warn( nonstandard_style, @@ -9,7 +12,8 @@ use futures::future::BoxFuture; use futures::prelude::*; use log::{info, trace}; -use tide::{ + +use tide_core::{ middleware::{Middleware, Next}, Context, Response, }; @@ -24,25 +28,40 @@ use tide::{ /// app.middleware(tide_log::RequestLogger::new()); /// ``` #[derive(Debug, Clone, Default)] -pub struct RequestLogger; +pub struct RequestLogger { + target: String, +} impl RequestLogger { + /// Create a new instance of logger with default target as + /// "requests" pub fn new() -> Self { - Self::default() + Self { + target: "requests".to_owned(), + } + } + + /// Create a new instance of logger with supplied `target` for + /// logging. + pub fn with_target(target: String) -> Self { + Self { + target, + } } async fn log_basic<'a, Data: Send + Sync + 'static>( &'a self, ctx: Context, next: Next<'a, Data>, - ) -> tide::Response { + ) -> Response { let path = ctx.uri().path().to_owned(); let method = ctx.method().as_str().to_owned(); - trace!("IN => {} {}", method, path); + trace!(target: &self.target, "IN => {} {}", method, path); let start = std::time::Instant::now(); let res = next.run(ctx).await; let status = res.status(); info!( + target: &self.target, "{} {} {} {}ms", method, path, diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml new file mode 100644 index 000000000..92487dae0 --- /dev/null +++ b/tide-slog/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = [ + "Tide Developers" +] +description = "Logging middleware for tide based on slog" +documentation = "https://docs.rs/tide-log" +keywords = ["tide", "web", "async", "middleware", "logging", "slog"] +categories = [ + "logging", + "network-programming", + "web-programming::http-server", +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide-slog" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" + + [dependencies] +tide-core = { path = "../tide-core" } +futures-preview = "0.3.0-alpha.16" +http = "0.1" +log = "0.4.6" +slog = "2.4.1" +slog-async = "2.3.0" +slog-term = "2.4.0" diff --git a/src/middleware/logger.rs b/tide-slog/src/lib.rs similarity index 51% rename from src/middleware/logger.rs rename to tide-slog/src/lib.rs index 8036cf585..121f45e8c 100644 --- a/src/middleware/logger.rs +++ b/tide-slog/src/lib.rs @@ -1,50 +1,70 @@ -use slog::{info, o, Drain}; +#![feature(async_await)] +#![warn( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + +use slog::{info, trace, o, Drain}; use slog_async; use slog_term; use futures::future::BoxFuture; use futures::prelude::*; -use crate::{ +use tide_core::{ middleware::{Middleware, Next}, Context, Response, }; -/// Root logger for Tide. Wraps over logger provided by slog.SimpleLogger +/// RequestLogger based on slog.SimpleLogger #[derive(Debug)] -pub struct RootLogger { +pub struct RequestLogger { // drain: dyn slog::Drain, - inner_logger: slog::Logger, + inner: slog::Logger, } -impl RootLogger { - pub fn new() -> RootLogger { - let decorator = slog_term::TermDecorator::new().build(); - let drain = slog_term::CompactFormat::new(decorator).build().fuse(); - let drain = slog_async::Async::new(drain).build().fuse(); +impl RequestLogger { + pub fn new() -> Self { + Default::default() + } - let log = slog::Logger::root(drain, o!()); - RootLogger { inner_logger: log } + pub fn with_logger(logger: slog::Logger) -> Self { + Self { inner: logger } } } -impl Default for RootLogger { +impl Default for RequestLogger { fn default() -> Self { - Self::new() + let decorator = slog_term::TermDecorator::new().build(); + let drain = slog_term::CompactFormat::new(decorator).build().fuse(); + let drain = slog_async::Async::new(drain).build().fuse(); + + let log = slog::Logger::root(drain, o!()); + Self { inner: log } } } /// Stores information during request phase and logs information once the response /// is generated. -impl Middleware for RootLogger { +impl Middleware for RequestLogger { fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { let path = cx.uri().path().to_owned(); let method = cx.method().as_str().to_owned(); - + trace!(self.inner, "IN => {} {}", method, path); + let start = std::time::Instant::now(); let res = next.run(cx).await; let status = res.status(); - info!(self.inner_logger, "{} {} {}", method, path, status.as_str()); + info!( + self.inner, + "{} {} {} {}ms", + method, + path, + status.as_str(), + start.elapsed().as_millis() + ); res }) } From 225a43d0029a04700442e40833475d2cf7184546 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 21 May 2019 16:52:50 +0530 Subject: [PATCH 33/95] add logging examples --- examples/hello_envlog.rs | 8 ++++++++ examples/hello_logrs.rs | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 examples/hello_envlog.rs create mode 100644 examples/hello_logrs.rs diff --git a/examples/hello_envlog.rs b/examples/hello_envlog.rs new file mode 100644 index 000000000..d57a5a4bd --- /dev/null +++ b/examples/hello_envlog.rs @@ -0,0 +1,8 @@ +#![feature(async_await)] +fn main() { + env_logger::from_env(env_logger::Env::default().default_filter_or("info")).init(); + let mut app = tide::App::new(); + app.middleware(tide::middleware::RequestLogger::new()); + app.at("/").get(async move |_| "Hello, world!"); + app.run("127.0.0.1:8000").unwrap(); +} diff --git a/examples/hello_logrs.rs b/examples/hello_logrs.rs new file mode 100644 index 000000000..d32f2696e --- /dev/null +++ b/examples/hello_logrs.rs @@ -0,0 +1,18 @@ +#![feature(async_await)] +fn main() { + use log::LevelFilter; + use log4rs::append::console::ConsoleAppender; + use log4rs::config::{Appender, Config, Root}; + + let stdout = ConsoleAppender::builder().build(); + let config = Config::builder() + .appender(Appender::builder().build("stdout", Box::new(stdout))) + .build(Root::builder().appender("stdout").build(LevelFilter::Info)) + .unwrap(); + let _handle = log4rs::init_config(config).unwrap(); + + let mut app = tide::App::new(); + app.middleware(tide::middleware::RequestLogger::new()); + app.at("/").get(async move |_| "Hello, world!"); + app.run("127.0.0.1:8000").unwrap(); +} From 7d9e136b8183156c5dd0d96ff4eff78bd537de50 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 21 May 2019 17:42:35 +0530 Subject: [PATCH 34/95] cargo fmt --- tide-log/src/lib.rs | 4 +--- tide-slog/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index a7a875014..88edf072b 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -44,9 +44,7 @@ impl RequestLogger { /// Create a new instance of logger with supplied `target` for /// logging. pub fn with_target(target: String) -> Self { - Self { - target, - } + Self { target } } async fn log_basic<'a, Data: Send + Sync + 'static>( diff --git a/tide-slog/src/lib.rs b/tide-slog/src/lib.rs index 121f45e8c..1b1724fa7 100644 --- a/tide-slog/src/lib.rs +++ b/tide-slog/src/lib.rs @@ -6,7 +6,7 @@ missing_debug_implementations )] -use slog::{info, trace, o, Drain}; +use slog::{info, o, trace, Drain}; use slog_async; use slog_term; From 8aac219292e2688779de1d390fde6e447c70f3c6 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 21 May 2019 17:59:42 +0530 Subject: [PATCH 35/95] add tide dev-dep to all crates --- tide-compression/Cargo.toml | 1 + tide-cookies/Cargo.toml | 1 + tide-headers/Cargo.toml | 3 +++ tide-log/Cargo.toml | 3 +++ tide-slog/Cargo.toml | 3 +++ 5 files changed, 11 insertions(+) diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml index f00c417d5..395fff270 100644 --- a/tide-compression/Cargo.toml +++ b/tide-compression/Cargo.toml @@ -27,4 +27,5 @@ features = ["stream", "gzip", "zlib", "brotli", "zstd"] version = "0.1.0-alpha.1" [dev-dependencies] +tide = { path = "../" } http-service-mock = "0.2.0" diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index 34b388977..e37532055 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -18,4 +18,5 @@ http-service = "0.2.0" tide-core = { path = "../tide-core" } [dev-dependencies] +tide = { path = "../" } http-service-mock = "0.2.0" diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index 0d02e69a0..1340c08bd 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -21,3 +21,6 @@ tide-core = { path = "../tide-core" } futures-preview = "0.3.0-alpha.16" http = "0.1" log = "0.4.6" + +[dev-dependencies] +tide = { path = "../" } \ No newline at end of file diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml index 24671ec59..dee006c86 100644 --- a/tide-log/Cargo.toml +++ b/tide-log/Cargo.toml @@ -22,3 +22,6 @@ tide-core = { path = "../tide-core" } futures-preview = "0.3.0-alpha.16" http = "0.1" log = "0.4.6" + +[dev-dependencies] +tide = { path = "../" } diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index 92487dae0..ef6ddb36a 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -25,3 +25,6 @@ log = "0.4.6" slog = "2.4.1" slog-async = "2.3.0" slog-term = "2.4.0" + +[dev-dependencies] +tide = { path = "../" } \ No newline at end of file From f41754bf270c7aba03df9425e9a4cf4adbc3c367 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 21 May 2019 18:11:47 +0530 Subject: [PATCH 36/95] fixup manifest documentation links --- tide-cookies/Cargo.toml | 4 ++-- tide-headers/Cargo.toml | 2 +- tide-slog/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index e37532055..012f61f72 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -5,8 +5,8 @@ edition = "2018" authors = [ "Tide Developers", ] -description = "Cookie management for Tide web framework" -documentation = "https://docs.rs/tide-core" +description = "Cookie middleware and extensions for tide" +documentation = "https://docs.rs/tide-cookies" license = "MIT OR Apache-2.0" repository = "https://github.com/rustasync/tide" diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index 1340c08bd..04ff51499 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -3,7 +3,7 @@ authors = [ "Tide Developers" ] description = "Header related middleware for tide" -documentation = "https://docs.rs/tide-log" +documentation = "https://docs.rs/tide-headers" keywords = ["tide", "web", "async", "middleware", "headers"] categories = [ "network-programming", diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index ef6ddb36a..dfddda8f3 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -3,7 +3,7 @@ authors = [ "Tide Developers" ] description = "Logging middleware for tide based on slog" -documentation = "https://docs.rs/tide-log" +documentation = "https://docs.rs/tide-slog" keywords = ["tide", "web", "async", "middleware", "logging", "slog"] categories = [ "logging", From b47e780552bd48e9353355f18c9eefe8b1fc06a5 Mon Sep 17 00:00:00 2001 From: updogliu Date: Tue, 21 May 2019 21:28:14 +0800 Subject: [PATCH 37/95] pub use ResultDynErrExt in tide::error --- src/error.rs | 4 +++- tide-core/src/error.rs | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/error.rs b/src/error.rs index 25ae1cc4b..6f987973b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,8 @@ use core::pin::Pin; use futures::future::Future; -pub use tide_core::error::{EndpointResult, Error, ResponseExt, ResultExt, StringError}; +pub use tide_core::error::{ + EndpointResult, Error, ResponseExt, ResultDynErrExt, ResultExt, StringError, +}; pub(crate) type BoxTryFuture = Pin> + Send + 'static>>; diff --git a/tide-core/src/error.rs b/tide-core/src/error.rs index d7e748b6b..fa5d0db22 100644 --- a/tide-core/src/error.rs +++ b/tide-core/src/error.rs @@ -79,8 +79,7 @@ pub trait ResultExt: Sized { self.with_err_status(500) } - /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom - /// response status. + /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom response status. fn with_err_status(self, status: S) -> EndpointResult where StatusCode: HttpTryFrom; @@ -111,8 +110,7 @@ pub trait ResultDynErrExt: Sized { self.with_err_status(500) } - /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom - /// response status. + /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom response status. fn with_err_status(self, status: S) -> EndpointResult where StatusCode: HttpTryFrom; From 476d75b57ffc10ae8ca9c30af15488cd64832870 Mon Sep 17 00:00:00 2001 From: Allen Date: Tue, 21 May 2019 07:43:30 -0700 Subject: [PATCH 38/95] Update Cargo.toml add newline before EOF --- tide-headers/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index 04ff51499..f53dff0ed 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -23,4 +23,4 @@ http = "0.1" log = "0.4.6" [dev-dependencies] -tide = { path = "../" } \ No newline at end of file +tide = { path = "../" } From f354835c211a30035ca997b229b9325f35b1bcc2 Mon Sep 17 00:00:00 2001 From: grey Date: Tue, 21 May 2019 07:51:53 -0700 Subject: [PATCH 39/95] capitalize Tide in crate desc --- tide-cookies/Cargo.toml | 2 +- tide-headers/Cargo.toml | 2 +- tide-log/Cargo.toml | 2 +- tide-slog/Cargo.toml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index 012f61f72..6c0742f4e 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" authors = [ "Tide Developers", ] -description = "Cookie middleware and extensions for tide" +description = "Cookie middleware and extensions for Tide" documentation = "https://docs.rs/tide-cookies" license = "MIT OR Apache-2.0" repository = "https://github.com/rustasync/tide" diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index f53dff0ed..294bc7791 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -2,7 +2,7 @@ authors = [ "Tide Developers" ] -description = "Header related middleware for tide" +description = "Header related middleware for Tide" documentation = "https://docs.rs/tide-headers" keywords = ["tide", "web", "async", "middleware", "headers"] categories = [ diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml index dee006c86..4a2074b85 100644 --- a/tide-log/Cargo.toml +++ b/tide-log/Cargo.toml @@ -2,7 +2,7 @@ authors = [ "Tide Developers" ] -description = "Logging middleware for tide" +description = "Logging middleware for Tide" documentation = "https://docs.rs/tide-log" keywords = ["tide", "web", "async", "middleware", "logging"] categories = [ diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index dfddda8f3..ca23079b8 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -2,7 +2,7 @@ authors = [ "Tide Developers" ] -description = "Logging middleware for tide based on slog" +description = "Logging middleware for Tide based on slog" documentation = "https://docs.rs/tide-slog" keywords = ["tide", "web", "async", "middleware", "logging", "slog"] categories = [ @@ -27,4 +27,4 @@ slog-async = "2.3.0" slog-term = "2.4.0" [dev-dependencies] -tide = { path = "../" } \ No newline at end of file +tide = { path = "../" } From 34cb65c4df352917431a8d90767ec9dd1475dc43 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Tue, 21 May 2019 21:32:12 +0530 Subject: [PATCH 40/95] refactor tide-forms, tide-querystring --- Cargo.toml | 12 +++---- src/error.rs | 8 ----- src/lib.rs | 31 +++++++++++++------ src/middleware.rs | 9 ------ tide-core/src/internal.rs | 8 +++++ tide-core/src/lib.rs | 3 ++ tide-forms/Cargo.toml | 31 +++++++++++++++++++ src/forms.rs => tide-forms/src/lib.rs | 14 +++++++-- tide-querystring/Cargo.toml | 31 +++++++++++++++++++ .../src/lib.rs | 15 ++++++--- 10 files changed, 120 insertions(+), 42 deletions(-) delete mode 100644 src/error.rs delete mode 100644 src/middleware.rs create mode 100644 tide-core/src/internal.rs create mode 100644 tide-forms/Cargo.toml rename src/forms.rs => tide-forms/src/lib.rs (90%) create mode 100644 tide-querystring/Cargo.toml rename src/querystring.rs => tide-querystring/src/lib.rs (91%) diff --git a/Cargo.toml b/Cargo.toml index 86801ad61..f977500a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,18 +27,12 @@ hyper = ["tide-core/http-service-hyper"] futures-preview = "0.3.0-alpha.16" http = "0.1" http-service = "0.2.0" -serde = "1.0.91" -serde_derive = "1.0.91" -serde_urlencoded = "0.5.5" tide-cookies = { path = "./tide-cookies", optional = true } tide-core = { path = "./tide-core" } tide-headers = { path = "./tide-headers" } tide-log = { path = "./tide-log" } - -[dependencies.multipart] -default-features = false -features = ["server"] -version = "0.16.1" +tide-forms = { path = "./tide-forms" } +tide-querystring = { path = "./tide-querystring" } [dev-dependencies] bytes = "0.4.12" @@ -61,8 +55,10 @@ members = [ "tide-compression", "tide-cookies", "tide-core", + "tide-forms", "tide-headers", "tide-log", + "tide-querystring", "tide-slog", ] diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index 6f987973b..000000000 --- a/src/error.rs +++ /dev/null @@ -1,8 +0,0 @@ -use core::pin::Pin; -use futures::future::Future; - -pub use tide_core::error::{ - EndpointResult, Error, ResponseExt, ResultDynErrExt, ResultExt, StringError, -}; - -pub(crate) type BoxTryFuture = Pin> + Send + 'static>>; diff --git a/src/lib.rs b/src/lib.rs index 63609583a..cf3c600b2 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ #![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![feature(async_await, existential_type)] -#![allow(unused_variables)] #![warn( nonstandard_style, rust_2018_idioms, @@ -20,21 +19,33 @@ #[doc(include = "../README.md")] const _README: () = (); -#[macro_use] -extern crate tide_core; +pub use http; #[cfg(feature = "cookies")] #[doc(inline)] pub use tide_cookies as cookies; -pub mod error; -pub mod forms; -pub mod middleware; -pub mod querystring; - #[doc(inline)] pub use tide_core::{ - response, App, Context, Endpoint, EndpointResult, Error, Response, Route, Server, + response, App, Context, Endpoint, EndpointResult, Error, Response, Route, Server, err_fmt + // TODO: export Body once it's in turn exported by tide_core }; -pub use http; +pub mod error { + pub use tide_core::error::{EndpointResult, Error, ResponseExt, ResultExt, ResultDynErrExt, StringError}; +} + +pub use tide_forms as forms; +pub use tide_querystring as querystring; + +pub mod middleware { + // Core + pub use tide_core::middleware::{Middleware, Next}; + + // Exports from tide repo. + pub use tide_headers::DefaultHeaders; + pub use tide_log::RequestLogger; + + #[cfg(feature = "cookies")] + pub use tide_cookies::CookiesMiddleware; +} \ No newline at end of file diff --git a/src/middleware.rs b/src/middleware.rs deleted file mode 100644 index 581792a7a..000000000 --- a/src/middleware.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Core -pub use tide_core::middleware::{Middleware, Next}; - -// Exports from tide repo. -pub use tide_headers::DefaultHeaders; -pub use tide_log::RequestLogger; - -#[cfg(feature = "cookies")] -pub use tide_cookies::CookiesMiddleware; diff --git a/tide-core/src/internal.rs b/tide-core/src/internal.rs new file mode 100644 index 000000000..3866fc5d0 --- /dev/null +++ b/tide-core/src/internal.rs @@ -0,0 +1,8 @@ +//! For internal use. These APIs will never be stable and +//! are meant to be used internally by the tide repo. + +use core::pin::Pin; +use futures::future::Future; + +/// Convenience alias for pinned box of Future> + Send + 'static +pub type BoxTryFuture = Pin> + Send + 'static>>; \ No newline at end of file diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index 4bd2d646a..c025d772e 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -18,6 +18,9 @@ pub mod response; mod route; mod router; +// Internal shared API for limited use across crates in our repo +pub mod internal; + pub use crate::{ app::{App, Server}, context::Context, diff --git a/tide-forms/Cargo.toml b/tide-forms/Cargo.toml new file mode 100644 index 000000000..3b5fe4a44 --- /dev/null +++ b/tide-forms/Cargo.toml @@ -0,0 +1,31 @@ +[package] +authors = [ + "Tide Developers" +] +description = "Form helpers and extensions for Tide" +documentation = "https://docs.rs/tide-forms" +keywords = ["tide", "web", "async", "helpers", "forms"] +categories = [ + "network-programming", + "web-programming::http-server", +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide-forms" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" + +[dependencies] +tide-core = { path = "../tide-core" } +http-service = "0.2.0" +futures-preview = "0.3.0-alpha.16" +http = "0.1" +log = "0.4.6" +multipart = { version = "0.16.1", features = ["server"], default-features = false } +serde = { version = "1.0.91", features = ["derive"] } +serde_urlencoded = "0.5.5" + +[dev-dependencies] +tide = { path = "../" } + diff --git a/src/forms.rs b/tide-forms/src/lib.rs similarity index 90% rename from src/forms.rs rename to tide-forms/src/lib.rs index ddfea6d7d..e8829405d 100644 --- a/src/forms.rs +++ b/tide-forms/src/lib.rs @@ -1,11 +1,21 @@ +#![feature(async_await)] +#![warn( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + use futures::prelude::*; use http_service::Body; use multipart::server::Multipart; use std::io::Cursor; -use crate::{ - error::{BoxTryFuture, ResultExt}, +use tide_core::{ + error::ResultExt, Context, Response, + err_fmt, + internal::BoxTryFuture }; /// An extension trait for `Context`, providing form extraction. diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml new file mode 100644 index 000000000..5f5bbbd95 --- /dev/null +++ b/tide-querystring/Cargo.toml @@ -0,0 +1,31 @@ +[package] +authors = [ + "Tide Developers" +] +description = "Query string helpers and extensions for Tide" +documentation = "https://docs.rs/tide-querystring" +keywords = ["tide", "web", "async", "helpers", "querystring"] +categories = [ + "network-programming", + "web-programming::http-server", +] +edition = "2018" +license = "MIT OR Apache-2.0" +name = "tide-querystring" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +version = "0.1.0" + + [dependencies] +tide-core = { path = "../tide-core" } +futures-preview = "0.3.0-alpha.16" +http = "0.1" +log = "0.4.6" +serde = { version = "1.0.91", features = ["derive"] } +serde_urlencoded = "0.5.5" + +[dev-dependencies] +tide = { path = "../" } +http-service = "0.2.0" +http-service-mock = "0.2.0" + diff --git a/src/querystring.rs b/tide-querystring/src/lib.rs similarity index 91% rename from src/querystring.rs rename to tide-querystring/src/lib.rs index 883108a32..d83076a21 100644 --- a/src/querystring.rs +++ b/tide-querystring/src/lib.rs @@ -1,4 +1,12 @@ -use crate::{error::Error, Context}; +#![feature(async_await)] +#![warn( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations +)] + +use tide_core::{error::Error, Context}; use http::StatusCode; use serde::Deserialize; @@ -8,14 +16,11 @@ pub trait ContextExt<'de> { } impl<'de, Data> ContextExt<'de> for Context { - #[inline] fn url_query>(&'de self) -> Result { let query = self.uri().query(); - if query.is_none() { return Err(Error::from(StatusCode::BAD_REQUEST)); } - Ok(serde_urlencoded::from_str(query.unwrap()) .map_err(|_| Error::from(StatusCode::BAD_REQUEST))?) } @@ -27,7 +32,7 @@ mod tests { use futures::executor::block_on; use http_service::Body; use http_service_mock::make_server; - use serde_derive::Deserialize; + use serde::de::Deserialize; #[derive(Deserialize)] struct Params { From 5c483ba6ae3ae4e033d2af8ee98dae30d99ed4c1 Mon Sep 17 00:00:00 2001 From: Kirk Turner Date: Tue, 21 May 2019 23:02:13 +0800 Subject: [PATCH 41/95] Fix the documentation for wildcards for path definitions to match implementation Also add a bunch of tests that demonstrate the implemented behavior --- tests/wildcard.rs | 169 +++++++++++++++++++++++++++++++++++++++++++ tide-core/src/app.rs | 19 +++-- 2 files changed, 180 insertions(+), 8 deletions(-) diff --git a/tests/wildcard.rs b/tests/wildcard.rs index 6d21ccf46..01c364620 100644 --- a/tests/wildcard.rs +++ b/tests/wildcard.rs @@ -10,6 +10,22 @@ async fn add_one(cx: Context<()>) -> Result { Ok((num + 1).to_string()) } +async fn add_two(cx: Context<()>) -> Result { + let one: i64 = cx.param("one").client_err()?; + let two: i64 = cx.param("two").client_err()?; + Ok((one + two).to_string()) +} + +async fn echo_path(cx: Context<()>) -> Result { + let path: String = cx.param("path").client_err()?; + Ok(path) +} + +async fn echo_empty(cx: Context<()>) -> Result { + let path: String = cx.param("").client_err()?; + Ok(path) +} + #[test] fn wildcard() { let mut app = tide::App::new(); @@ -56,3 +72,156 @@ fn not_found_error() { let res = server.simulate(req).unwrap(); assert_eq!(res.status(), 404); } + +#[test] +fn wildpath() { + let mut app = tide::App::new(); + app.at("/echo/*path").get(echo_path); + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get("/echo/some_path") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"some_path"); + + let req = http::Request::get("/echo/multi/segment/path") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"multi/segment/path"); + + let req = http::Request::get("/echo/").body(Body::empty()).unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 404); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b""); +} + +#[test] +fn multi_wildcard() { + let mut app = tide::App::new(); + app.at("/add_two/:one/:two/").get(add_two); + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get("/add_two/1/2/") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"3"); + + let req = http::Request::get("/add_two/-1/2/") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"1"); + let req = http::Request::get("/add_two/1") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 404); +} + +#[test] +fn wild_last_segment() { + let mut app = tide::App::new(); + app.at("/echo/:path/*").get(echo_path); + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get("/echo/one/two") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"one"); + + let req = http::Request::get("/echo/one/two/three/four") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"one"); +} + +#[test] +fn invalid_wildcard() { + let mut app = tide::App::new(); + app.at("/echo/*path/:one/").get(echo_path); + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get("/echo/one/two") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 404); +} + +#[test] +fn nameless_wildcard() { + let mut app = tide::App::new(); + app.at("/echo/:").get(async move |_| ""); + + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get("/echo/one/two") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 404); + + let req = http::Request::get("/echo/one").body(Body::empty()).unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); +} + +#[test] +fn nameless_internal_wildcard() { + let mut app = tide::App::new(); + app.at("/echo/:/:path").get(echo_path); + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get("/echo/one").body(Body::empty()).unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 404); + + let req = http::Request::get("/echo/one/two") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"two"); + + let req = http::Request::get("/echo/one/two") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"two"); +} + +#[test] +fn nameless_internal_wildcard2() { + let mut app = tide::App::new(); + app.at("/echo/:/:path").get(echo_empty); + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get("/echo/one/two") + .body(Body::empty()) + .unwrap(); + let res = server.simulate(req).unwrap(); + assert_eq!(res.status(), 200); + let body = block_on(res.into_body().into_vec()).unwrap(); + assert_eq!(&*body, &*b"one"); +} diff --git a/tide-core/src/app.rs b/tide-core/src/app.rs index e0e0549a0..8f7b64bc7 100644 --- a/tide-core/src/app.rs +++ b/tide-core/src/app.rs @@ -41,7 +41,7 @@ use crate::{ /// # Routing and parameters /// /// Tide's routing system is simple and similar to many other frameworks. It -/// uses `:foo` for "wildcard" URL segments, and `:foo*` to match the rest of a +/// uses `:foo` for "wildcard" URL segments, and `*foo` to match the rest of a /// URL (which may include multiple segments). Here's an example using wildcard /// segments as parameters to endpoints: /// @@ -183,12 +183,13 @@ impl App { /// parameter called `name`. It is not possible to define wildcard segments /// with different names for otherwise identical paths. /// - /// Wildcard definitions can be followed by an optional *wildcard - /// modifier*. Currently, there is only one modifier: `*`, which means that - /// the wildcard will match to the end of given path, no matter how many - /// segments are left, even nothing. It is an error to define two wildcard - /// segments with different wildcard modifiers, or to write other path - /// segment after a segment with wildcard modifier. + /// Alternatively a wildcard definitions can start with a `*`, for example + /// `*path`, which means that the wildcard will match to the end of given + /// path, no matter how many segments are left, even nothing. + /// + /// The name of the parameter can be omitted to define a path that matches + /// the required structure, but where the parameters are not required. + /// `:` will match a segment, and `*` will match an entire path. /// /// Here are some examples omitting the HTTP verb based endpoint selection: /// @@ -197,7 +198,9 @@ impl App { /// app.at("/"); /// app.at("/hello"); /// app.at("add_two/:num"); - /// app.at("static/:path*"); + /// app.at("files/:user/*"); + /// app.at("static/*path"); + /// app.at("static/:context/:"); /// ``` /// /// There is no fallback route matching, i.e. either a resource is a full From 60834dc6e763ba6701619d8db1d069408017dc3c Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Wed, 22 May 2019 00:49:25 +0530 Subject: [PATCH 42/95] fix err_fmt macro --- tide-core/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-core/src/error.rs b/tide-core/src/error.rs index fa5d0db22..a64f53edd 100644 --- a/tide-core/src/error.rs +++ b/tide-core/src/error.rs @@ -16,7 +16,7 @@ impl std::fmt::Display for StringError { #[macro_export] macro_rules! err_fmt { {$($t:tt)*} => { - crate::error::StringError(format!($($t)*)) + $crate::error::StringError(format!($($t)*)) } } From d187372e7a765d8bbbfde006eb18d0942d1ebf69 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Wed, 22 May 2019 00:50:22 +0530 Subject: [PATCH 43/95] fix querystring tests --- tide-querystring/src/lib.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tide-querystring/src/lib.rs b/tide-querystring/src/lib.rs index d83076a21..3fa9f2af5 100644 --- a/tide-querystring/src/lib.rs +++ b/tide-querystring/src/lib.rs @@ -1,3 +1,6 @@ +//! Crate that provides helpers and extensions for Tide +//! related to query strings. + #![feature(async_await)] #![warn( nonstandard_style, @@ -32,20 +35,20 @@ mod tests { use futures::executor::block_on; use http_service::Body; use http_service_mock::make_server; - use serde::de::Deserialize; + use serde::Deserialize; #[derive(Deserialize)] struct Params { msg: String, } - async fn handler(cx: crate::Context<()>) -> Result { + async fn handler(cx: tide::Context<()>) -> Result { let p = cx.url_query::()?; Ok(p.msg) } - fn app() -> crate::App<()> { - let mut app = crate::App::new(); + fn app() -> tide::App<()> { + let mut app = tide::App::new(); app.at("/").get(handler); app } From 676132e6c2f188c6670732058aa2cf05400c5c84 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Wed, 22 May 2019 00:59:52 +0530 Subject: [PATCH 44/95] add basic crate level doc --- tide-compression/src/lib.rs | 3 +++ tide-cookies/src/lib.rs | 3 +++ tide-core/src/lib.rs | 2 ++ tide-forms/src/lib.rs | 3 +++ tide-headers/src/lib.rs | 3 ++- tide-log/src/lib.rs | 4 ++-- tide-slog/src/lib.rs | 3 +++ 7 files changed, 18 insertions(+), 3 deletions(-) diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index ec4a989a4..31f7327c2 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -1,3 +1,6 @@ +//! Crate that provides helpers and/or middlewares for Tide +//! related to compression. + #![cfg_attr(feature = "nightly", feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![feature(async_await)] diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs index a2c37ef26..128b2d923 100644 --- a/tide-cookies/src/lib.rs +++ b/tide-cookies/src/lib.rs @@ -1,3 +1,6 @@ +//! Crate that provides helpers and/or middlewares for Tide +//! related to cookies. + #![feature(async_await)] #![warn( nonstandard_style, diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index c025d772e..2a38ab555 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -1,3 +1,5 @@ +//! Core types and traits from Tide + #![feature(async_await, existential_type)] #![warn( nonstandard_style, diff --git a/tide-forms/src/lib.rs b/tide-forms/src/lib.rs index e8829405d..4d8baf270 100644 --- a/tide-forms/src/lib.rs +++ b/tide-forms/src/lib.rs @@ -1,3 +1,6 @@ +//! Crate that provides helpers and extensions for Tide +//! related to forms. + #![feature(async_await)] #![warn( nonstandard_style, diff --git a/tide-headers/src/lib.rs b/tide-headers/src/lib.rs index 36b080567..1303ad1d0 100644 --- a/tide-headers/src/lib.rs +++ b/tide-headers/src/lib.rs @@ -1,5 +1,6 @@ -//! Crate that provides helpers, and/or middlewares for tide +//! Crate that provides helpers and/or middlewares for Tide //! related to http headers. + #![feature(async_await)] #![warn( nonstandard_style, diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index 88edf072b..9237d74b9 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -1,6 +1,6 @@ -//! Crate that provides helpers and/or middlewares for tide +//! Crate that provides helpers and/or middlewares for Tide //! related to logging. -//! + #![feature(async_await)] #![warn( nonstandard_style, diff --git a/tide-slog/src/lib.rs b/tide-slog/src/lib.rs index 1b1724fa7..04ef2e6ec 100644 --- a/tide-slog/src/lib.rs +++ b/tide-slog/src/lib.rs @@ -1,3 +1,6 @@ +//! Crate that provides helpers and/or middlewares for Tide +//! related to structured logging with slog. + #![feature(async_await)] #![warn( nonstandard_style, From d15bb7a026c0c179bec78e65213a6ae749645bf1 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Wed, 22 May 2019 01:01:08 +0530 Subject: [PATCH 45/95] cargo fmt --- src/lib.rs | 19 +++++++++++++++---- tide-core/src/internal.rs | 5 +++-- tide-core/src/lib.rs | 2 +- tide-forms/src/lib.rs | 7 +------ tide-querystring/src/lib.rs | 2 +- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cf3c600b2..a67c722f7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,12 +27,23 @@ pub use tide_cookies as cookies; #[doc(inline)] pub use tide_core::{ - response, App, Context, Endpoint, EndpointResult, Error, Response, Route, Server, err_fmt - // TODO: export Body once it's in turn exported by tide_core + err_fmt, + response, + App, + Context, + Endpoint, + EndpointResult, + Error, + Response, + Route, + Server, + // TODO: export Body once it's in turn exported by tide_core }; pub mod error { - pub use tide_core::error::{EndpointResult, Error, ResponseExt, ResultExt, ResultDynErrExt, StringError}; + pub use tide_core::error::{ + EndpointResult, Error, ResponseExt, ResultDynErrExt, ResultExt, StringError, + }; } pub use tide_forms as forms; @@ -48,4 +59,4 @@ pub mod middleware { #[cfg(feature = "cookies")] pub use tide_cookies::CookiesMiddleware; -} \ No newline at end of file +} diff --git a/tide-core/src/internal.rs b/tide-core/src/internal.rs index 3866fc5d0..9a2ad59f1 100644 --- a/tide-core/src/internal.rs +++ b/tide-core/src/internal.rs @@ -1,8 +1,9 @@ -//! For internal use. These APIs will never be stable and +//! For internal use. These APIs will never be stable and //! are meant to be used internally by the tide repo. use core::pin::Pin; use futures::future::Future; /// Convenience alias for pinned box of Future> + Send + 'static -pub type BoxTryFuture = Pin> + Send + 'static>>; \ No newline at end of file +pub type BoxTryFuture = + Pin> + Send + 'static>>; diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index 2a38ab555..ecdf21390 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -1,5 +1,5 @@ //! Core types and traits from Tide - + #![feature(async_await, existential_type)] #![warn( nonstandard_style, diff --git a/tide-forms/src/lib.rs b/tide-forms/src/lib.rs index 4d8baf270..67165c2e6 100644 --- a/tide-forms/src/lib.rs +++ b/tide-forms/src/lib.rs @@ -14,12 +14,7 @@ use http_service::Body; use multipart::server::Multipart; use std::io::Cursor; -use tide_core::{ - error::ResultExt, - Context, Response, - err_fmt, - internal::BoxTryFuture -}; +use tide_core::{err_fmt, error::ResultExt, internal::BoxTryFuture, Context, Response}; /// An extension trait for `Context`, providing form extraction. pub trait ContextExt { diff --git a/tide-querystring/src/lib.rs b/tide-querystring/src/lib.rs index 3fa9f2af5..b7ae83bdf 100644 --- a/tide-querystring/src/lib.rs +++ b/tide-querystring/src/lib.rs @@ -9,9 +9,9 @@ missing_debug_implementations )] -use tide_core::{error::Error, Context}; use http::StatusCode; use serde::Deserialize; +use tide_core::{error::Error, Context}; /// An extension trait for `Context`, providing query string deserialization. pub trait ContextExt<'de> { From c121673f87c8fe7ffe0cffccee7696a58e7772b7 Mon Sep 17 00:00:00 2001 From: "Richard Dodd (dodj)" Date: Tue, 21 May 2019 21:35:41 +0100 Subject: [PATCH 46/95] Fix links in README --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f2129f50b..f8297ef00 100644 --- a/README.md +++ b/README.md @@ -71,15 +71,15 @@ fn main() -> Result<(), std::io::Error> { **More Examples** -- [Hello World](https://github.com/rustasync/tide/blob/master/examples/src/hello.rs) -- [Messages](https://github.com/rustasync/tide/blob/master/examples/src/messages.rs) -- [Body Types](https://github.com/rustasync/tide/blob/master/examples/src/body_types.rs) -- [Multipart Form](https://github.com/rustasync/tide/blob/master/examples/src/multipart_form/mod.rs) -- [Catch All](https://github.com/rustasync/tide/blob/master/examples/src/catch_all.rs) -- [Cookies](https://github.com/rustasync/tide/blob/master/examples/src/cookies.rs) -- [Default Headers](https://github.com/rustasync/tide/blob/master/examples/src/default_headers.rs) -- [GraphQL](https://github.com/rustasync/tide/blob/master/examples/src/graphql.rs) -- [Staticfile](https://github.com/rustasync/tide/blob/master/examples/src/staticfile.rs) +- [Hello World](https://github.com/rustasync/tide/blob/master/examples/hello.rs) +- [Messages](https://github.com/rustasync/tide/blob/master/examples/messages.rs) +- [Body Types](https://github.com/rustasync/tide/blob/master/examples/body_types.rs) +- [Multipart Form](https://github.com/rustasync/tide/blob/master/examples/multipart_form/mod.rs) +- [Catch All](https://github.com/rustasync/tide/blob/master/examples/catch_all.rs) +- [Cookies](https://github.com/rustasync/tide/blob/master/examples/cookies.rs) +- [Default Headers](https://github.com/rustasync/tide/blob/master/examples/default_headers.rs) +- [GraphQL](https://github.com/rustasync/tide/blob/master/examples/graphql.rs) +- [Staticfile](https://github.com/rustasync/tide/blob/master/examples/staticfile.rs) ## Resources From 8ac86ec991fd85bb40c8caa1870d3c5f071ba861 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Wed, 22 May 2019 02:10:11 +0530 Subject: [PATCH 47/95] fix tide-slog keywords limit --- tide-slog/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index ca23079b8..dd00a8b04 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -4,7 +4,7 @@ authors = [ ] description = "Logging middleware for Tide based on slog" documentation = "https://docs.rs/tide-slog" -keywords = ["tide", "web", "async", "middleware", "logging", "slog"] +keywords = ["tide", "web", "middleware", "logging", "slog"] categories = [ "logging", "network-programming", From ce2167ac7449d457381dc76f5ecbbd51a61ef870 Mon Sep 17 00:00:00 2001 From: Maniarr Date: Wed, 22 May 2019 20:25:42 +0200 Subject: [PATCH 48/95] Rename Context to Context --- examples/graphql.rs | 16 ++++++++-------- src/querystring.rs | 2 +- tide-compression/src/lib.rs | 10 +++++----- tide-cookies/src/middleware.rs | 6 +++--- tide-core/src/app.rs | 20 ++++++++++---------- tide-core/src/context.rs | 4 ++-- tide-core/src/middleware.rs | 9 ++++++--- tide-core/src/router.rs | 2 +- tide-headers/src/lib.rs | 4 ++-- tide-log/src/lib.rs | 10 +++++----- tide-slog/src/lib.rs | 4 ++-- 11 files changed, 45 insertions(+), 42 deletions(-) diff --git a/examples/graphql.rs b/examples/graphql.rs index a78c71c00..f79527c12 100644 --- a/examples/graphql.rs +++ b/examples/graphql.rs @@ -8,19 +8,19 @@ use juniper::graphql_object; use std::sync::{atomic, Arc}; use tide::{error::ResultExt, response, App, Context, EndpointResult}; -// First, we define `Data` that holds accumulator state. This is accessible as App data in +// First, we define `State` that holds accumulator state. This is accessible as state in // Tide, and as executor context in Juniper. #[derive(Clone, Default)] -struct Data(Arc); +struct State(Arc); -impl juniper::Context for Data {} +impl juniper::Context for State {} // We define `Query` unit struct here. GraphQL queries will refer to this struct. The struct itself -// doesn't have any associated data (and there's no need to do so), but instead it exposes the +// doesn't have any associated state (and there's no need to do so), but instead it exposes the // accumulator state from the context. struct Query; -graphql_object!(Query: Data |&self| { +graphql_object!(Query: State |&self| { // GraphQL integers are signed and 32 bits long. field accumulator(&executor) -> i32 as "Current value of the accumulator" { executor.context().0.load(atomic::Ordering::Relaxed) as i32 @@ -31,7 +31,7 @@ graphql_object!(Query: Data |&self| { // `Query`, but it provides the way to "mutate" the accumulator state. struct Mutation; -graphql_object!(Mutation: Data |&self| { +graphql_object!(Mutation: State |&self| { field add(&executor, by: i32) -> i32 as "Add given value to the accumulator." { executor.context().0.fetch_add(by as isize, atomic::Ordering::Relaxed) as i32 + by } @@ -43,7 +43,7 @@ type Schema = juniper::RootNode<'static, Query, Mutation>; // Finally, we'll bridge between Tide and Juniper. `GraphQLRequest` from Juniper implements // `Deserialize`, so we use `Json` extractor to deserialize the request body. -async fn handle_graphql(mut cx: Context) -> EndpointResult { +async fn handle_graphql(mut cx: Context) -> EndpointResult { let query: juniper::http::GraphQLRequest = cx.body_json().await.client_err()?; let schema = Schema::new(Query, Mutation); let response = query.execute(&schema, cx.state()); @@ -58,7 +58,7 @@ async fn handle_graphql(mut cx: Context) -> EndpointResult { } fn main() { - let mut app = App::with_state(Data::default()); + let mut app = App::with_state(State::default()); app.at("/graphql").post(handle_graphql); app.run("127.0.0.1:8000").unwrap(); } diff --git a/src/querystring.rs b/src/querystring.rs index 883108a32..ba28b443b 100644 --- a/src/querystring.rs +++ b/src/querystring.rs @@ -7,7 +7,7 @@ pub trait ContextExt<'de> { fn url_query>(&'de self) -> Result; } -impl<'de, Data> ContextExt<'de> for Context { +impl<'de, State> ContextExt<'de> for Context { #[inline] fn url_query>(&'de self) -> Result { let query = self.uri().query(); diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index ec4a989a4..a162748a4 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -128,8 +128,8 @@ impl Compression { } } -impl Middleware for Compression { - fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { +impl Middleware for Compression { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { let encoding = match self.preferred_encoding(cx.headers()) { Ok(encoding) => encoding, @@ -212,11 +212,11 @@ impl Decompression { } } -impl Middleware for Decompression { +impl Middleware for Decompression { fn handle<'a>( &'a self, - mut cx: Context, - next: Next<'a, Data>, + mut cx: Context, + next: Next<'a, State>, ) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { match self.decode(cx.request_mut()) { diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index e8dafd243..9c34ff332 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -26,11 +26,11 @@ impl CookiesMiddleware { } } -impl Middleware for CookiesMiddleware { +impl Middleware for CookiesMiddleware { fn handle<'a>( &'a self, - mut cx: Context, - next: Next<'a, Data>, + mut cx: Context, + next: Next<'a, State>, ) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { let cookie_data = cx diff --git a/tide-core/src/app.rs b/tide-core/src/app.rs index e0e0549a0..484fd81db 100644 --- a/tide-core/src/app.rs +++ b/tide-core/src/app.rs @@ -133,7 +133,7 @@ use crate::{ pub struct App { router: Router, middleware: Vec>>, - data: State, + state: State, } impl App<()> { @@ -155,7 +155,7 @@ impl App { App { router: Router::new(), middleware: Vec::new(), - data: state, + state, } } @@ -229,7 +229,7 @@ impl App { pub fn into_http_service(self) -> Server { Server { router: Arc::new(self.router), - data: Arc::new(self.data), + state: Arc::new(self.state), middleware: Arc::new(self.middleware), } } @@ -273,7 +273,7 @@ impl App { #[allow(missing_debug_implementations)] pub struct Server { router: Arc>, - data: Arc, + state: Arc, middleware: Arc>>>, } @@ -291,12 +291,12 @@ impl HttpService for Server { let method = req.method().to_owned(); let router = self.router.clone(); let middleware = self.middleware.clone(); - let data = self.data.clone(); + let state = self.state.clone(); FutureExt::boxed(async move { let fut = { let Selection { endpoint, params } = router.route(&path, method); - let cx = Context::new(data, req, params); + let cx = Context::new(state, req, params); let next = Next { endpoint, @@ -319,19 +319,19 @@ mod tests { use super::*; use crate::{middleware::Next, router::Selection, Context, Response}; - fn simulate_request<'a, Data: Default + Clone + Send + Sync + 'static>( - app: &'a App, + fn simulate_request<'a, State: Default + Clone + Send + Sync + 'static>( + app: &'a App, path: &'a str, method: http::Method, ) -> BoxFuture<'a, Response> { let Selection { endpoint, params } = app.router.route(path, method.clone()); - let data = Arc::new(Data::default()); + let state = Arc::new(State::default()); let req = http::Request::builder() .method(method) .body(http_service::Body::empty()) .unwrap(); - let cx = Context::new(data, req, params); + let cx = Context::new(state, req, params); let next = Next { endpoint, next_middleware: &app.middleware, diff --git a/tide-core/src/context.rs b/tide-core/src/context.rs index 543ac8a5d..d3e1bacd5 100644 --- a/tide-core/src/context.rs +++ b/tide-core/src/context.rs @@ -3,7 +3,7 @@ use http_service::Body; use route_recognizer::Params; use std::{str::FromStr, sync::Arc}; -/// Data associated with a request-response lifecycle. +/// State associated with a request-response lifecycle. /// /// The `Context` gives endpoints access to basic information about the incoming /// request, route parameters, and various ways of accessing the request's body. @@ -60,7 +60,7 @@ impl Context { &mut self.request } - /// Access app-global data. + /// Access the state. pub fn state(&self) -> &State { &self.state } diff --git a/tide-core/src/middleware.rs b/tide-core/src/middleware.rs index 47d1caa13..2b881f27f 100644 --- a/tide-core/src/middleware.rs +++ b/tide-core/src/middleware.rs @@ -9,11 +9,14 @@ pub trait Middleware: 'static + Send + Sync { fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response>; } -impl Middleware for F +impl Middleware for F where - F: Send + Sync + 'static + for<'a> Fn(Context, Next<'a, Data>) -> BoxFuture<'a, Response>, + F: Send + + Sync + + 'static + + for<'a> Fn(Context, Next<'a, State>) -> BoxFuture<'a, Response>, { - fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { (self)(cx, next) } } diff --git a/tide-core/src/router.rs b/tide-core/src/router.rs index eb97a90ba..1ce768dad 100644 --- a/tide-core/src/router.rs +++ b/tide-core/src/router.rs @@ -62,7 +62,7 @@ impl Router { } } -fn not_found_endpoint(_cx: Context) -> BoxFuture<'static, Response> { +fn not_found_endpoint(_cx: Context) -> BoxFuture<'static, Response> { FutureExt::boxed(async move { http::Response::builder() .status(http::StatusCode::NOT_FOUND) diff --git a/tide-headers/src/lib.rs b/tide-headers/src/lib.rs index 36b080567..d5692bd19 100644 --- a/tide-headers/src/lib.rs +++ b/tide-headers/src/lib.rs @@ -49,8 +49,8 @@ impl DefaultHeaders { } } -impl Middleware for DefaultHeaders { - fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { +impl Middleware for DefaultHeaders { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { let mut res = next.run(cx).await; let headers = res.headers_mut(); diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index 88edf072b..cc0787657 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -47,10 +47,10 @@ impl RequestLogger { Self { target } } - async fn log_basic<'a, Data: Send + Sync + 'static>( + async fn log_basic<'a, State: Send + Sync + 'static>( &'a self, - ctx: Context, - next: Next<'a, Data>, + ctx: Context, + next: Next<'a, State>, ) -> Response { let path = ctx.uri().path().to_owned(); let method = ctx.method().as_str().to_owned(); @@ -70,8 +70,8 @@ impl RequestLogger { } } -impl Middleware for RequestLogger { - fn handle<'a>(&'a self, ctx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { +impl Middleware for RequestLogger { + fn handle<'a>(&'a self, ctx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { self.log_basic(ctx, next).await }) } } diff --git a/tide-slog/src/lib.rs b/tide-slog/src/lib.rs index 1b1724fa7..b0b782208 100644 --- a/tide-slog/src/lib.rs +++ b/tide-slog/src/lib.rs @@ -48,8 +48,8 @@ impl Default for RequestLogger { /// Stores information during request phase and logs information once the response /// is generated. -impl Middleware for RequestLogger { - fn handle<'a>(&'a self, cx: Context, next: Next<'a, Data>) -> BoxFuture<'a, Response> { +impl Middleware for RequestLogger { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { FutureExt::boxed(async move { let path = cx.uri().path().to_owned(); let method = cx.method().as_str().to_owned(); From 9fbd88f4a717eb08f184b112bd53f11d48058040 Mon Sep 17 00:00:00 2001 From: grey Date: Wed, 22 May 2019 15:38:15 -0700 Subject: [PATCH 49/95] propagate hyper error on serve failure --- tide-core/src/app.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tide-core/src/app.rs b/tide-core/src/app.rs index 484fd81db..d61988c37 100644 --- a/tide-core/src/app.rs +++ b/tide-core/src/app.rs @@ -257,11 +257,9 @@ impl App { .next() .ok_or(std::io::ErrorKind::InvalidInput)?; - // TODO: propagate the error from hyper http_service_hyper::serve(self.into_http_service(), addr) .await - .ok(); - Ok(()) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) } } From 279e0f05a0a24fba9fc192f1d7956ad60fa0cf24 Mon Sep 17 00:00:00 2001 From: nasa Date: Mon, 27 May 2019 20:03:16 +0900 Subject: [PATCH 50/95] Add doc comment (#250) * doc: Add doc comment to tide-core * doc: Add documantation to tide-cookie * doc: Add doc to tide-compression * doc: Add doc comment * fix doc links * fix path * doc: Add doc comment --- src/lib.rs | 7 ++++++- tide-compression/src/lib.rs | 5 ++++- tide-cookies/src/lib.rs | 5 ++++- tide-cookies/src/middleware.rs | 6 +++++- tide-core/src/app.rs | 4 ++++ tide-core/src/endpoint.rs | 2 +- tide-core/src/error.rs | 7 +++++-- tide-core/src/lib.rs | 9 ++++++++- tide-core/src/middleware.rs | 3 ++- tide-core/src/response.rs | 3 +++ tide-core/src/route.rs | 1 + tide-querystring/src/lib.rs | 1 + 12 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a67c722f7..5b8ef56ac 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,8 @@ nonstandard_style, rust_2018_idioms, future_incompatible, - missing_debug_implementations + missing_debug_implementations, + missing_docs )] //! @@ -41,6 +42,8 @@ pub use tide_core::{ }; pub mod error { + //! Module to export tide_core errors + pub use tide_core::error::{ EndpointResult, Error, ResponseExt, ResultDynErrExt, ResultExt, StringError, }; @@ -50,6 +53,8 @@ pub use tide_forms as forms; pub use tide_querystring as querystring; pub mod middleware { + //! Module to export tide_core middleware + // Core pub use tide_core::middleware::{Middleware, Next}; diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 721caa9bb..07c3c78ee 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -8,9 +8,12 @@ nonstandard_style, rust_2018_idioms, future_incompatible, - missing_debug_implementations + missing_debug_implementations, + missing_docs )] +//! Compression-related middleware for Tide + pub use accept_encoding::Encoding; use async_compression::stream; use futures::future::BoxFuture; diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs index 128b2d923..c1c72a651 100644 --- a/tide-cookies/src/lib.rs +++ b/tide-cookies/src/lib.rs @@ -6,9 +6,12 @@ nonstandard_style, rust_2018_idioms, future_incompatible, - missing_debug_implementations + missing_debug_implementations, + missing_docs )] +//! Cookie management for Tide web framework + mod data; mod middleware; diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 9c34ff332..41c3e10db 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -10,17 +10,21 @@ use tide_core::{ /// Middleware to work with cookies. /// -/// [`CookiesMiddleware`] along with [`ContextExt`](crate::data::ContextExt) provide smooth +/// [`CookiesMiddleware`] along with [`ContextExt`] provide smooth /// access to request cookies and setting/removing cookies from response. This leverages the /// [cookie](https://crates.io/crates/cookie) crate. /// This middleware parses cookies from request and caches them in the extension. Once the request /// is processed by endpoints and other middlewares, all the added and removed cookies are set on /// on the response. You will need to add this middle before any other middlewares that might need /// to access Cookies. +/// +/// [`CookiesMiddleware`]: crate::middleware::CookiesMiddleware +/// [`ContextExt`]: ../../tide/cookies/trait.ContextExt.html #[derive(Clone, Default, Debug)] pub struct CookiesMiddleware {} impl CookiesMiddleware { + /// CookieMiddleware constructor pub fn new() -> Self { Self {} } diff --git a/tide-core/src/app.rs b/tide-core/src/app.rs index 181ef649e..b036fb0d0 100644 --- a/tide-core/src/app.rs +++ b/tide-core/src/app.rs @@ -220,6 +220,8 @@ impl App { /// /// Middleware can only be added at the "top level" of an application, /// and is processed in the order in which it is applied. + /// + /// [`Middleware`]: crate::middleware::Middleware pub fn middleware(&mut self, m: impl Middleware) -> &mut Self { self.middleware.push(Arc::new(m)); self @@ -270,6 +272,8 @@ impl App { /// /// This type is useful only in conjunction with the [`HttpService`] trait, /// i.e. for hosting a Tide app within some custom HTTP server. +/// +/// [`HttpService`]: http_service::HttpService #[derive(Clone)] #[allow(missing_debug_implementations)] pub struct Server { diff --git a/tide-core/src/endpoint.rs b/tide-core/src/endpoint.rs index c7959b469..2b379295c 100644 --- a/tide-core/src/endpoint.rs +++ b/tide-core/src/endpoint.rs @@ -9,7 +9,7 @@ use crate::{response::IntoResponse, Context, Response}; /// directly by Tide users. /// /// In practice, endpoints are functions that take a `Context` as an argument and -/// return a type `T` that implements [`IntoResponse`]. +/// return a type `T` that implements [`IntoResponse`](crate::response::IntoResponse). /// /// # Examples /// diff --git a/tide-core/src/error.rs b/tide-core/src/error.rs index a64f53edd..5062939ca 100644 --- a/tide-core/src/error.rs +++ b/tide-core/src/error.rs @@ -1,9 +1,11 @@ -use http::{HttpTryFrom, Response, StatusCode}; -use http_service::Body; +//! Error and Result module use crate::response::IntoResponse; +use http::{HttpTryFrom, Response, StatusCode}; +use http_service::Body; #[derive(Debug)] +/// A string error, which can be display pub struct StringError(pub String); impl std::error::Error for StringError {} @@ -14,6 +16,7 @@ impl std::fmt::Display for StringError { } #[macro_export] +/// Macro that generates StringError immediately macro_rules! err_fmt { {$($t:tt)*} => { $crate::error::StringError(format!($($t)*)) diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index ecdf21390..4ede67a03 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -5,12 +5,19 @@ nonstandard_style, rust_2018_idioms, future_incompatible, - missing_debug_implementations + missing_debug_implementations, + missing_docs )] // TODO: Remove this after clippy bug due to async await is resolved. // ISSUE: https://github.com/rust-lang/rust-clippy/issues/3988 #![allow(clippy::needless_lifetimes)] +//! +//! Tide core api document +//! +//! The [`App`] docs are a good place to get started. +//! + mod app; mod context; mod endpoint; diff --git a/tide-core/src/middleware.rs b/tide-core/src/middleware.rs index 2b881f27f..12129edd0 100644 --- a/tide-core/src/middleware.rs +++ b/tide-core/src/middleware.rs @@ -1,6 +1,7 @@ +//! Middlewares + use crate::{endpoint::DynEndpoint, Context, Response}; use futures::future::BoxFuture; - use std::sync::Arc; /// Middleware that wraps around remaining middleware chain. diff --git a/tide-core/src/response.rs b/tide-core/src/response.rs index 90751b25d..0adea7e63 100644 --- a/tide-core/src/response.rs +++ b/tide-core/src/response.rs @@ -1,5 +1,8 @@ +//! Multiple types of response modules + use http_service::Body; +/// An Http response pub type Response = http_service::Response; /// Serialize `t` into a JSON-encoded response. diff --git a/tide-core/src/route.rs b/tide-core/src/route.rs index 0406e793a..dc5297073 100644 --- a/tide-core/src/route.rs +++ b/tide-core/src/route.rs @@ -37,6 +37,7 @@ impl<'a, State: 'static> Route<'a, State> { } } + /// Add endpoint nested routes pub fn nest(&mut self, f: impl FnOnce(&mut Route<'a, State>)) -> &mut Self { f(self); self diff --git a/tide-querystring/src/lib.rs b/tide-querystring/src/lib.rs index 48023f061..15e735a7f 100644 --- a/tide-querystring/src/lib.rs +++ b/tide-querystring/src/lib.rs @@ -15,6 +15,7 @@ use tide_core::{error::Error, Context}; /// An extension trait for `Context`, providing query string deserialization. pub trait ContextExt<'de> { + /// Analyze url and extract query parameters fn url_query>(&'de self) -> Result; } From 7c2046a99bdb0053a5ba4b13770e24421fea7889 Mon Sep 17 00:00:00 2001 From: Allen Date: Wed, 5 Jun 2019 16:46:51 -0700 Subject: [PATCH 51/95] add test that checks for empty body on HEAD req (#179) * add test that checks for empty body on HEAD req * update test currently not working since http-service-mock doesn't exhibit correct behavior yet --- tests/head_response_empty_body.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/head_response_empty_body.rs diff --git a/tests/head_response_empty_body.rs b/tests/head_response_empty_body.rs new file mode 100644 index 000000000..40dfc414b --- /dev/null +++ b/tests/head_response_empty_body.rs @@ -0,0 +1,23 @@ +#![feature(async_await)] + +use futures::executor::block_on; +use http_service::Body; +use http_service_mock::make_server; +use tide::Context; + +async fn ok(_cx: Context<()>) -> String { + String::from("this shouldn't exist in the body of a HEAD response") +} + +#[test] +fn head_response_empty() { + let mut app = tide::App::new(); + app.at("/").get(ok); + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::head("/").body(Body::empty()).unwrap(); + let res = server.simulate(req).unwrap(); + let body = block_on(res.into_body().into_vec()).unwrap(); + dbg!(&String::from_utf8(body)); + //assert!(body.is_empty()); +} From 250482859623118cd7e5281146596247340406cd Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Thu, 6 Jun 2019 01:48:54 +0200 Subject: [PATCH 52/95] Add middleware for catching panics (#265) --- Cargo.toml | 1 + tide-panic/Cargo.toml | 15 ++++++++ tide-panic/LICENSE-APACHE | 1 + tide-panic/LICENSE-MIT | 1 + tide-panic/src/catch_unwind.rs | 65 ++++++++++++++++++++++++++++++++++ tide-panic/src/lib.rs | 18 ++++++++++ 6 files changed, 101 insertions(+) create mode 100644 tide-panic/Cargo.toml create mode 120000 tide-panic/LICENSE-APACHE create mode 120000 tide-panic/LICENSE-MIT create mode 100644 tide-panic/src/catch_unwind.rs create mode 100644 tide-panic/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index f977500a5..543edf1b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ members = [ "tide-log", "tide-querystring", "tide-slog", + "tide-panic", ] [patch.crates-io] diff --git a/tide-panic/Cargo.toml b/tide-panic/Cargo.toml new file mode 100644 index 000000000..0937c822c --- /dev/null +++ b/tide-panic/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "tide-panic" +version = "0.1.0" +edition = "2018" +authors = ["Tide Developers"] +description = "Advanced panic support for Tide" +documentation = "https://docs.rs/tide-panic" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rustasync/tide" + +[dependencies] +futures-preview = "0.3.0-alpha.16" +http = "0.1" +http-service = "0.2.0" +tide-core = { path = "../tide-core" } diff --git a/tide-panic/LICENSE-APACHE b/tide-panic/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/tide-panic/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/tide-panic/LICENSE-MIT b/tide-panic/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/tide-panic/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/tide-panic/src/catch_unwind.rs b/tide-panic/src/catch_unwind.rs new file mode 100644 index 000000000..eb5726a7f --- /dev/null +++ b/tide-panic/src/catch_unwind.rs @@ -0,0 +1,65 @@ +use futures::future::{BoxFuture, FutureExt, TryFutureExt}; +use http::status::StatusCode; +use std::{ + any::Any, + panic::{AssertUnwindSafe, RefUnwindSafe}, +}; +use tide_core::{ + middleware::{Middleware, Next}, + response::IntoResponse, + Context, Response, +}; + +/// A [`Middleware`] that will catch any panics from later middleware or handlers and return a +/// response to the client. +/// +/// It is **not** recommended to use this middleware for a general try/catch mechanism. The +/// [`Result`] type is more appropriate to use for middleware/handlers that can fail on a regular +/// basis. Additionally, this middleware is not guaranteed to catch all panics, see the "Notes" +/// section in the [`std::panic::catch_unwind`] docs. +pub struct CatchUnwind { + f: Box) -> Response + Send + Sync>, +} + +impl CatchUnwind { + /// Create a [`CatchUnwind`] which will respond with [`StatusCode::INTERNAL_SERVER_ERROR`] when + /// any panic is caught. + pub fn new() -> Self { + Self::with_response(|_| { + "Internal server error" + .with_status(StatusCode::INTERNAL_SERVER_ERROR) + .into_response() + }) + } + + /// Create a [`CatchUnwind`] with a custom function to generate the response, the function will + /// be passed the caught panic. + pub fn with_response( + response: impl Fn(Box) -> Response + Send + Sync + 'static, + ) -> Self { + Self { + f: Box::new(response), + } + } +} + +impl Middleware for CatchUnwind { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { + AssertUnwindSafe(next.run(cx)) + .catch_unwind() + .unwrap_or_else(move |err| (self.f)(err)) + .boxed() + } +} + +impl Default for CatchUnwind { + fn default() -> Self { + Self::new() + } +} + +impl std::fmt::Debug for CatchUnwind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CatchUnwind").finish() + } +} diff --git a/tide-panic/src/lib.rs b/tide-panic/src/lib.rs new file mode 100644 index 000000000..530f264b0 --- /dev/null +++ b/tide-panic/src/lib.rs @@ -0,0 +1,18 @@ +#![feature(async_await, doc_cfg)] +#![warn( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations, + missing_docs +)] + +//! Advanced panic support for Tide applications. +//! +//! These middleware should not generally be necessary, they are provided for situations in which +//! Tide's default panic handling is not usable by your application. Before using these you should +//! have a good understanding of how the different components involved in [`std::panic`] works. + +mod catch_unwind; + +pub use crate::catch_unwind::CatchUnwind; From 1fb4ab3c4b19416bbcd5b9d0fedb8bc737ccce64 Mon Sep 17 00:00:00 2001 From: nasa Date: Thu, 6 Jun 2019 21:11:20 +0900 Subject: [PATCH 53/95] Implemented CORS header handler middleware (#262) * feat: Add cors middleware * test: Add cors test code * feat: export CorsMiddleware * feat: Add cors example * $cargo fmt * doc: move example/cors.rs * doc: Add README * doc: Add doc comment * fix example doc comment * fix: Changed type to option * feat: Add credentials header at preflight request * fix: Attach an expose header when requesting preflight * $cargo fmt * fix: remove debug pring * refactor: move build preflight response * fix: Remove echo_back option * fix: fix type OPTION -> OPTIONS * refactor: tide-cors to optional dependence * $cargo fmt * refactor: imple arg to generic argument * fix typo * refactor: using 'match' --- Cargo.toml | 5 +- src/lib.rs | 7 + tide-cors/Cargo.toml | 24 +++ tide-cors/README.md | 38 +++++ tide-cors/examples/cors.rs | 18 +++ tide-cors/src/lib.rs | 54 +++++++ tide-cors/src/middleware.rs | 285 ++++++++++++++++++++++++++++++++++++ 7 files changed, 430 insertions(+), 1 deletion(-) create mode 100644 tide-cors/Cargo.toml create mode 100644 tide-cors/README.md create mode 100644 tide-cors/examples/cors.rs create mode 100644 tide-cors/src/lib.rs create mode 100644 tide-cors/src/middleware.rs diff --git a/Cargo.toml b/Cargo.toml index 543edf1b6..4f6ae3f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,9 @@ repository = "https://github.com/rustasync/tide" version = "0.2.0" [features] -default = ["hyper", "cookies"] +default = ["hyper", "cookies", "cors"] cookies = ["tide-cookies"] +cors = ["tide-cors"] hyper = ["tide-core/http-service-hyper"] [dependencies] @@ -28,6 +29,7 @@ futures-preview = "0.3.0-alpha.16" http = "0.1" http-service = "0.2.0" tide-cookies = { path = "./tide-cookies", optional = true } +tide-cors = { path = "./tide-cors", optional = true } tide-core = { path = "./tide-core" } tide-headers = { path = "./tide-headers" } tide-log = { path = "./tide-log" } @@ -55,6 +57,7 @@ members = [ "tide-compression", "tide-cookies", "tide-core", + "tide-cors", "tide-forms", "tide-headers", "tide-log", diff --git a/src/lib.rs b/src/lib.rs index 5b8ef56ac..244b3e735 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,10 @@ pub use http; #[doc(inline)] pub use tide_cookies as cookies; +#[cfg(feature = "cors")] +#[doc(inline)] +pub use tide_cors as cors; + #[doc(inline)] pub use tide_core::{ err_fmt, @@ -62,6 +66,9 @@ pub mod middleware { pub use tide_headers::DefaultHeaders; pub use tide_log::RequestLogger; + #[cfg(feature = "cors")] + pub use tide_cors::CorsMiddleware; + #[cfg(feature = "cookies")] pub use tide_cookies::CookiesMiddleware; } diff --git a/tide-cors/Cargo.toml b/tide-cors/Cargo.toml new file mode 100644 index 000000000..cbfd06be2 --- /dev/null +++ b/tide-cors/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "tide-cors" +version = "0.2.0" +authors = [ + "Tide Developers", +] +description = "Cors middleware and extensions for Tide" +documentation = "https://docs.rs/tide-cors" +readme = "README.md" +repository = "https://github.com/rustasync/tide" +license = "MIT OR Apache-2.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +futures-preview = "0.3.0-alpha.16" +http = "0.1" +http-service = "0.2.0" +tide-core = { path = "../tide-core" } + +[dev-dependencies] +tide = { path = "../" } +http-service-mock = "0.2.0" diff --git a/tide-cors/README.md b/tide-cors/README.md new file mode 100644 index 000000000..b83932197 --- /dev/null +++ b/tide-cors/README.md @@ -0,0 +1,38 @@ +# tide-cors + +This crate provides cors-related middleware for Tide. + +## Examples + +Examples are in the `/examples` folder of this crate. + +```rust +#![feature(async_await)] + +use http::header::HeaderValue; +use tide::middleware::CorsMiddleware; + +fn main() { + let mut app = tide::App::new(); + + app.middleware( + CorsMiddleware::new() + .allow_origin(HeaderValue::from_static("*")) + .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), + ); + + app.at("/").get(async move |_| "Hello, world!"); + + app.run("127.0.0.1:8000").unwrap(); +} +``` + +**Simple Example** + +You can test the simple example by running `cargo run --example cors` while in this crate's directory, and then running this script in the browser console: + +```console +fetch("http://127.0.0.1:8000") +``` + +You will probably get a browser alert when running without cors middleware diff --git a/tide-cors/examples/cors.rs b/tide-cors/examples/cors.rs new file mode 100644 index 000000000..1cbab2c99 --- /dev/null +++ b/tide-cors/examples/cors.rs @@ -0,0 +1,18 @@ +#![feature(async_await)] + +use http::header::HeaderValue; +use tide::middleware::CorsMiddleware; + +fn main() { + let mut app = tide::App::new(); + + app.middleware( + CorsMiddleware::new() + .allow_origin(HeaderValue::from_static("*")) + .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), + ); + + app.at("/").get(async move |_| "Hello, world!"); + + app.run("127.0.0.1:8000").unwrap(); +} diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs new file mode 100644 index 000000000..ae867300f --- /dev/null +++ b/tide-cors/src/lib.rs @@ -0,0 +1,54 @@ +//! Cors middleware and extensions for Tide +//! +//! # tide-cors +//! +//! This crate provides cors-related middleware for Tide. +//! +//! ## Examples +//! +//! Examples are in the `/examples` folder of this crate. +//! +//! ```rust, no_run +//! #![feature(async_await)] +//! +//! use http::header::HeaderValue; +//! use tide::middleware::CorsMiddleware; +//! +//! fn main() { +//! let mut app = tide::App::new(); +//! +//! app.middleware( +//! CorsMiddleware::new() +//! .allow_origin(HeaderValue::from_static("*")) +//! .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), +//! ); +//! +//! app.at("/").get(async move |_| "Hello, world!"); +//! +//! app.run("127.0.0.1:8000").unwrap(); +//! } +//! ``` +//! +//! **Simple Example** +//! +//! You can test the simple example by running `cargo run --example cors` while in this crate's directory, and then running this script in the browser console: +//! +//! ```console +//! fetch("http://127.0.0.1:8000") +//! ``` +//! +//! You will probably get a browser alert when running without cors middleware +//! + +#![feature(async_await)] +#![warn( + nonstandard_style, + rust_2018_idioms, + future_incompatible, + missing_debug_implementations, + missing_docs +)] + +mod middleware; + +pub use self::middleware::CorsMiddleware; diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs new file mode 100644 index 000000000..6a9952b46 --- /dev/null +++ b/tide-cors/src/middleware.rs @@ -0,0 +1,285 @@ +//! Cors middleware + +use futures::future::BoxFuture; +use futures::prelude::*; +use http::header::HeaderValue; +use http::{header, Method, StatusCode}; +use http_service::Body; +use tide_core::{ + middleware::{Middleware, Next}, + Context, Response, +}; + +/// Middleware for CORS +/// +/// # Example +/// +/// ```rust +///use http::header::HeaderValue; +///use tide::middleware::CorsMiddleware; +/// +///CorsMiddleware::new() +/// .allow_origin(HeaderValue::from_static("*")) +/// .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")) +/// .allow_credentials(false); +/// ``` +#[derive(Clone, Debug, Hash)] +pub struct CorsMiddleware { + allow_credentials: Option, + allow_headers: HeaderValue, + allow_methods: HeaderValue, + allow_origin: HeaderValue, + expose_headers: Option, + max_age: HeaderValue, +} + +pub const DEFAULT_MAX_AGE: &str = "86400"; +pub const DEFAULT_METHODS: &str = "GET, POST, OPTIONS"; +pub const WILDCARD: &str = "*"; + +impl CorsMiddleware { + /// Creates a new Cors middleware. + pub fn new() -> Self { + Self { + allow_credentials: None, + allow_headers: HeaderValue::from_static(WILDCARD), + allow_methods: HeaderValue::from_static(DEFAULT_METHODS), + allow_origin: HeaderValue::from_static(WILDCARD), + expose_headers: None, + max_age: HeaderValue::from_static(DEFAULT_MAX_AGE), + } + } + + /// Set allow_credentials and return new CorsMiddleware + pub fn allow_credentials(mut self, allow_credentials: bool) -> Self { + self.allow_credentials = match HeaderValue::from_str(&allow_credentials.to_string()) { + Ok(header) => Some(header), + Err(_) => None, + }; + self + } + + /// Set allow_headers and return new CorsMiddleware + pub fn allow_headers>(mut self, headers: T) -> Self { + self.allow_headers = headers.into(); + self + } + + /// Set max_age and return new CorsMiddleware + pub fn max_age>(mut self, max_age: T) -> Self { + self.max_age = max_age.into(); + self + } + + /// Set allow_methods and return new CorsMiddleware + pub fn allow_methods>(mut self, methods: T) -> Self { + self.allow_methods = methods.into(); + self + } + + /// Set allow_origin and return new CorsMiddleware + pub fn allow_origin>(mut self, origin: T) -> Self { + self.allow_origin = origin.into(); + self + } + + /// Set expose_headers and return new CorsMiddleware + pub fn expose_headers>(mut self, headers: T) -> Self { + self.expose_headers = Some(headers.into()); + self + } + + fn build_preflight_response(&self) -> http::response::Response { + let mut response = http::Response::builder() + .status(StatusCode::OK) + .header( + header::ACCESS_CONTROL_ALLOW_ORIGIN, + self.allow_origin.clone(), + ) + .header( + header::ACCESS_CONTROL_ALLOW_METHODS, + self.allow_methods.clone(), + ) + .header( + header::ACCESS_CONTROL_ALLOW_HEADERS, + self.allow_headers.clone(), + ) + .header(header::ACCESS_CONTROL_MAX_AGE, self.max_age.clone()) + .body(Body::empty()) + .unwrap(); + + if let Some(allow_credentials) = self.allow_credentials.clone() { + response + .headers_mut() + .append(header::ACCESS_CONTROL_ALLOW_CREDENTIALS, allow_credentials); + } + + if let Some(expose_headers) = self.expose_headers.clone() { + response + .headers_mut() + .append(header::ACCESS_CONTROL_EXPOSE_HEADERS, expose_headers); + } + + response + } +} + +impl Middleware for CorsMiddleware { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { + FutureExt::boxed(async move { + // Return results immediately upon preflight request + if cx.method() == Method::OPTIONS { + return self.build_preflight_response(); + } + + let mut response = next.run(cx).await; + let headers = response.headers_mut(); + + headers.append( + header::ACCESS_CONTROL_ALLOW_ORIGIN, + self.allow_origin.clone(), + ); + + if let Some(allow_credentials) = self.allow_credentials.clone() { + headers.append(header::ACCESS_CONTROL_ALLOW_CREDENTIALS, allow_credentials); + } + response + }) + } +} + +impl Default for CorsMiddleware { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod test { + use super::*; + use http::header::HeaderValue; + use http_service::Body; + use http_service_mock::make_server; + + const ALLOW_ORIGIN: &str = "example.com"; + const ALLOW_METHODS: &str = "GET, POST, OPTIONS, DELETE"; + const EXPOSE_HEADER: &str = "X-My-Custom-Header"; + + const ENDPOINT: &str = "/cors"; + + fn app() -> tide_core::App<()> { + let mut app = tide_core::App::new(); + app.at(ENDPOINT).get(async move |_| "Hello World"); + + app + } + + fn request() -> http::Request { + http::Request::get(ENDPOINT) + .header(http::header::ORIGIN, ALLOW_ORIGIN) + .method(http::method::Method::GET) + .body(Body::empty()) + .unwrap() + } + + #[test] + fn preflight_request() { + let mut app = app(); + app.middleware( + CorsMiddleware::new() + .allow_origin(HeaderValue::from_static(ALLOW_ORIGIN)) + .allow_methods(HeaderValue::from_static(ALLOW_METHODS)) + .expose_headers(HeaderValue::from_static(EXPOSE_HEADER)) + .allow_credentials(true), + ); + + let mut server = make_server(app.into_http_service()).unwrap(); + + let req = http::Request::get(ENDPOINT) + .header(http::header::ORIGIN, ALLOW_ORIGIN) + .method(http::method::Method::OPTIONS) + .body(Body::empty()) + .unwrap(); + + let res = server.simulate(req).unwrap(); + + assert_eq!(res.status(), 200); + + assert_eq!( + res.headers().get("access-control-allow-origin").unwrap(), + ALLOW_ORIGIN + ); + assert_eq!( + res.headers().get("access-control-allow-methods").unwrap(), + ALLOW_METHODS + ); + assert_eq!( + res.headers().get("access-control-allow-headers").unwrap(), + WILDCARD + ); + assert_eq!( + res.headers().get("access-control-max-age").unwrap(), + DEFAULT_MAX_AGE + ); + + assert_eq!( + res.headers() + .get("access-control-allow-credentials") + .unwrap(), + "true" + ); + } + #[test] + fn default_cors_middleware() { + let mut app = app(); + app.middleware(CorsMiddleware::new()); + + let mut server = make_server(app.into_http_service()).unwrap(); + let res = server.simulate(request()).unwrap(); + + assert_eq!(res.status(), 200); + + assert_eq!( + res.headers().get("access-control-allow-origin").unwrap(), + "*" + ); + } + + #[test] + fn custom_cors_middleware() { + let mut app = app(); + app.middleware( + CorsMiddleware::new() + .allow_origin(HeaderValue::from_static(ALLOW_ORIGIN)) + .allow_credentials(false) + .allow_methods(HeaderValue::from_static(ALLOW_METHODS)) + .expose_headers(HeaderValue::from_static(EXPOSE_HEADER)), + ); + + let mut server = make_server(app.into_http_service()).unwrap(); + let res = server.simulate(request()).unwrap(); + + assert_eq!(res.status(), 200); + assert_eq!( + res.headers().get("access-control-allow-origin").unwrap(), + ALLOW_ORIGIN + ); + } + + #[test] + fn credentials_true() { + let mut app = app(); + app.middleware(CorsMiddleware::new().allow_credentials(true)); + + let mut server = make_server(app.into_http_service()).unwrap(); + let res = server.simulate(request()).unwrap(); + + assert_eq!(res.status(), 200); + assert_eq!( + res.headers() + .get("access-control-allow-credentials") + .unwrap(), + "true" + ); + } +} From 4486ba04e9d7fcebe7419a26a3b53c14842a2613 Mon Sep 17 00:00:00 2001 From: Miles Granger Date: Thu, 6 Jun 2019 20:52:54 +0200 Subject: [PATCH 54/95] Add templating example with tera (#267) --- Cargo.toml | 1 + examples/templates/tera-hello-world.html | 15 +++++++ examples/templating_tera.rs | 53 ++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 examples/templates/tera-hello-world.html create mode 100644 examples/templating_tera.rs diff --git a/Cargo.toml b/Cargo.toml index 4f6ae3f20..460c4f653 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ mime = "0.3.13" mime_guess = "2.0.0-alpha.6" percent-encoding = "1.0.1" serde = { version = "1.0.91", features = ["derive"] } +tera = "0.11" tide-log = { path = "./tide-log" } env_logger = "0.6.1" log4rs = "0.8.3" diff --git a/examples/templates/tera-hello-world.html b/examples/templates/tera-hello-world.html new file mode 100644 index 000000000..0dc05a7a3 --- /dev/null +++ b/examples/templates/tera-hello-world.html @@ -0,0 +1,15 @@ + + + {{ page_title }} + + + +
    + {% for point in points %} +
  • + {{ point }} +
  • + {% endfor %} +
+ + diff --git a/examples/templating_tera.rs b/examples/templating_tera.rs new file mode 100644 index 000000000..442d9ae3f --- /dev/null +++ b/examples/templating_tera.rs @@ -0,0 +1,53 @@ +#![feature(async_await)] + +use tera::{self, compile_templates}; +use tide::{self, App, Context, EndpointResult, Error}; + +// AppState to pass with context and will hold +// the interface to the tera rendering engine +struct AppState { + template: tera::Tera, +} + +// Render some data into the 'tera-hello-world.html template in examples/templates directory +async fn index(ctx: Context) -> EndpointResult { + // Create the context for the template + let mut context = tera::Context::new(); + context.insert("page_title", "Hello from Tera templating!"); + context.insert("points", &vec!["point1", "point2"]); + + // Render the variables into the template + let s = ctx + .state() + .template + .render("tera-hello-world.html", &context) + .map_err(|err| { + // Map the tera::Error into a Tide error + let resp = http::Response::builder() + .status(500) + .body(err.description().into()) + .unwrap(); + Error::from(resp) + })?; + + // Build normal response, putting the rendered string into bytes -> Body + let resp = http::Response::builder() + .header(http::header::CONTENT_TYPE, mime::TEXT_HTML.as_ref()) + .status(http::StatusCode::OK) + .body(s.as_bytes().into()) + .expect("Failed to build response"); + Ok(resp) +} + +fn main() -> Result<(), std::io::Error> { + let template_dir = format!("{}/examples/templates/*", env!("CARGO_MANIFEST_DIR")); + + let state = AppState { + template: compile_templates!(&template_dir), + }; + + let mut app = App::with_state(state); + app.at("/").get(index); + app.run("127.0.0.1:8000")?; + Ok(()) +} From a80315169900743932c21a30c0545442128726db Mon Sep 17 00:00:00 2001 From: Allen Date: Thu, 6 Jun 2019 16:24:13 -0700 Subject: [PATCH 55/95] Update lib.rs reduce redundant compression subcrate docs --- tide-compression/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 07c3c78ee..0f3551e4e 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -12,8 +12,6 @@ missing_docs )] -//! Compression-related middleware for Tide - pub use accept_encoding::Encoding; use async_compression::stream; use futures::future::BoxFuture; From 994ee1c1bb344e819444ff73791e651266d6952e Mon Sep 17 00:00:00 2001 From: Allen Date: Fri, 7 Jun 2019 03:03:24 -0700 Subject: [PATCH 56/95] reduce redundancy in docs and make consistent (#272) also adds some extra example commands in tide-compression README --- Cargo.toml | 2 +- src/lib.rs | 11 ++++------- tide-compression/README.md | 7 +++++-- tide-cookies/src/lib.rs | 2 -- tide-core/src/lib.rs | 6 ------ tide-cors/README.md | 8 ++++---- tide-cors/src/lib.rs | 13 ++++--------- tide-panic/src/lib.rs | 12 ++++++------ 8 files changed, 24 insertions(+), 37 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 460c4f653..27b714889 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,9 +62,9 @@ members = [ "tide-forms", "tide-headers", "tide-log", + "tide-panic", "tide-querystring", "tide-slog", - "tide-panic", ] [patch.crates-io] diff --git a/src/lib.rs b/src/lib.rs index 244b3e735..69afca565 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +//! Welcome to Tide. +//! +//! The [`App`](struct.App.html) docs are a good place to get started. + #![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![feature(async_await, existential_type)] @@ -9,13 +13,6 @@ missing_docs )] -//! -//! Welcome to Tide. -//! -//! The [`App`](struct.App.html) docs are a good place to get started. -//! -//! - #[cfg(test)] #[doc(include = "../README.md")] const _README: () = (); diff --git a/tide-compression/README.md b/tide-compression/README.md index 4c8eb8b10..fc19a1351 100644 --- a/tide-compression/README.md +++ b/tide-compression/README.md @@ -8,9 +8,12 @@ Examples are in the `/examples` folder of this crate. __Simple Example__ -You can test the simple example by running `cargo run --example simple` while in this crate's directory, and then running either of the following commands: +You can test the simple example by running `cargo run --example simple` while in this crate's directory, and then running any variety of the following commands: ```console $ curl -v http://127.0.0.1:8000/ -$ echo 'why hello there' | gzip | curl -v --compressed -H 'Content-Encoding: gzip' http://127.0.0.1:8000/echo --data-binary @- +$ curl -v -H 'Accept-Encoding: br' http://127.0.0.1:8000/ +$ echo 'hello there' | gzip | curl -v --compressed -H 'Content-Encoding: gzip' http://127.0.0.1:8000/echo --data-binary @- +$ echo 'general kenobi' | brotli | curl -v --compressed -H 'Content-Encoding: br' http://127.0.0.1:8000/echo --data-binary @- +$ echo 'you are a bold one' | zstd | curl -v --compressed -H 'Content-Encoding: zstd' http://127.0.0.1:8000/echo --data-binary @- ``` diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs index c1c72a651..18645641d 100644 --- a/tide-cookies/src/lib.rs +++ b/tide-cookies/src/lib.rs @@ -10,8 +10,6 @@ missing_docs )] -//! Cookie management for Tide web framework - mod data; mod middleware; diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index 4ede67a03..f67178a22 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -12,12 +12,6 @@ // ISSUE: https://github.com/rust-lang/rust-clippy/issues/3988 #![allow(clippy::needless_lifetimes)] -//! -//! Tide core api document -//! -//! The [`App`] docs are a good place to get started. -//! - mod app; mod context; mod endpoint; diff --git a/tide-cors/README.md b/tide-cors/README.md index b83932197..62be88f93 100644 --- a/tide-cors/README.md +++ b/tide-cors/README.md @@ -6,7 +6,7 @@ This crate provides cors-related middleware for Tide. Examples are in the `/examples` folder of this crate. -```rust +```rust,no_run #![feature(async_await)] use http::header::HeaderValue; @@ -27,12 +27,12 @@ fn main() { } ``` -**Simple Example** +__Simple Example__ You can test the simple example by running `cargo run --example cors` while in this crate's directory, and then running this script in the browser console: ```console -fetch("http://127.0.0.1:8000") +$ fetch("http://127.0.0.1:8000") ``` -You will probably get a browser alert when running without cors middleware +You will probably get a browser alert when running without cors middleware. diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs index ae867300f..c2fe3215e 100644 --- a/tide-cors/src/lib.rs +++ b/tide-cors/src/lib.rs @@ -1,14 +1,10 @@ -//! Cors middleware and extensions for Tide -//! -//! # tide-cors -//! //! This crate provides cors-related middleware for Tide. //! //! ## Examples //! //! Examples are in the `/examples` folder of this crate. //! -//! ```rust, no_run +//! ```rust,no_run //! #![feature(async_await)] //! //! use http::header::HeaderValue; @@ -29,16 +25,15 @@ //! } //! ``` //! -//! **Simple Example** +//! __Simple Example__ //! //! You can test the simple example by running `cargo run --example cors` while in this crate's directory, and then running this script in the browser console: //! //! ```console -//! fetch("http://127.0.0.1:8000") +//! $ fetch("http://127.0.0.1:8000") //! ``` //! -//! You will probably get a browser alert when running without cors middleware -//! +//! You will probably get a browser alert when running without cors middleware. #![feature(async_await)] #![warn( diff --git a/tide-panic/src/lib.rs b/tide-panic/src/lib.rs index 530f264b0..3174a2a83 100644 --- a/tide-panic/src/lib.rs +++ b/tide-panic/src/lib.rs @@ -1,3 +1,9 @@ +//! Advanced panic support for Tide applications. +//! +//! These middleware should not generally be necessary, they are provided for situations in which +//! Tide's default panic handling is not usable by your application. Before using these you should +//! have a good understanding of how the different components involved in [`std::panic`] works. + #![feature(async_await, doc_cfg)] #![warn( nonstandard_style, @@ -7,12 +13,6 @@ missing_docs )] -//! Advanced panic support for Tide applications. -//! -//! These middleware should not generally be necessary, they are provided for situations in which -//! Tide's default panic handling is not usable by your application. Before using these you should -//! have a good understanding of how the different components involved in [`std::panic`] works. - mod catch_unwind; pub use crate::catch_unwind::CatchUnwind; From ae8926557439e1fc95863ee2fcb21052a32b3a46 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 19 Jun 2019 16:54:29 +0300 Subject: [PATCH 57/95] Workaround for issue #278: works around Rust internal compiler error. --- tide-cookies/src/middleware.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 41c3e10db..5778d7cd8 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -44,7 +44,7 @@ impl Middleware for CookiesMiddleware { let cookie_jar = cookie_data.content.clone(); - cx.extensions_mut().insert(cookie_data); + let _ = cx.extensions_mut().insert(cookie_data); let mut res = next.run(cx).await; let headers = res.headers_mut(); for cookie in cookie_jar.read().unwrap().delta() { From f0d667dde5bbe48e0f1930d1499382c284b2fcc5 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 21 Jun 2019 14:28:55 +0300 Subject: [PATCH 58/95] Added a comment explaining the workaround for solving issue 278. --- tide-cookies/src/middleware.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 5778d7cd8..f2e52afc2 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -44,6 +44,9 @@ impl Middleware for CookiesMiddleware { let cookie_jar = cookie_data.content.clone(); + + // The `let _ = ...` is a workaround for issue: https://github.com/rustasync/tide/issues/278 + // Solution is according to suggestion in https://github.com/rust-lang/rust/issues/61579#issuecomment-500436524 let _ = cx.extensions_mut().insert(cookie_data); let mut res = next.run(cx).await; let headers = res.headers_mut(); From 1505f91871febfa7ffd469462e107968862d7fab Mon Sep 17 00:00:00 2001 From: real Date: Fri, 21 Jun 2019 14:29:19 +0300 Subject: [PATCH 59/95] Bumped rust version in .travis.yml to nightly-2019-06-02. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a15187c4..cb734fa3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: rust -rust: nightly-2019-05-09 +rust: nightly-2019-06-02 cache: cargo before_script: From 4bc805bc559f17200e2e23e02c9f6b62895468ee Mon Sep 17 00:00:00 2001 From: real Date: Fri, 21 Jun 2019 18:44:46 +0300 Subject: [PATCH 60/95] cargo fmt --- tide-cookies/src/middleware.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index f2e52afc2..4d6b85aee 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -44,7 +44,6 @@ impl Middleware for CookiesMiddleware { let cookie_jar = cookie_data.content.clone(); - // The `let _ = ...` is a workaround for issue: https://github.com/rustasync/tide/issues/278 // Solution is according to suggestion in https://github.com/rust-lang/rust/issues/61579#issuecomment-500436524 let _ = cx.extensions_mut().insert(cookie_data); From 8f80e0c784867fec1eb5f8f86ce465430b09e2df Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 24 Jun 2019 16:03:16 +0530 Subject: [PATCH 61/95] Core isolation - part 4 (#258) * extract router; minimalize tide_core * cargo fmt * minor fixes * refactor error mod; Next constructor * cargo fmt * cleanup error type * fix clippy warnings * move router back in; remove err_fmt * fix cors example * move cors example * clippy fixes * basic documentation; more clippy fixes * router: refactor `Selection` * fix cors example * revert cors to default * Cargo.toml: add empty line before EOF --- Cargo.toml | 14 +- {tide-cors/examples => examples}/cors.rs | 8 + {tide-core/src => src}/app.rs | 24 +- src/lib.rs | 26 +- tide-core/src/router.rs => src/router/core.rs | 46 ++-- src/router/mod.rs | 5 + {tide-core/src => src/router}/route.rs | 8 +- tide-cookies/src/middleware.rs | 4 +- tide-core/Cargo.toml | 11 +- tide-core/src/context.rs | 9 +- tide-core/src/endpoint.rs | 8 +- tide-core/src/error.rs | 237 ++++++++++-------- tide-core/src/internal.rs | 10 +- tide-core/src/lib.rs | 12 +- tide-core/src/middleware.rs | 16 +- tide-core/src/response.rs | 4 +- tide-cors/src/lib.rs | 9 +- tide-cors/src/middleware.rs | 6 +- tide-forms/src/lib.rs | 10 +- tide-headers/Cargo.toml | 2 +- tide-log/Cargo.toml | 2 +- tide-querystring/Cargo.toml | 2 +- tide-querystring/src/lib.rs | 1 - 23 files changed, 251 insertions(+), 223 deletions(-) rename {tide-cors/examples => examples}/cors.rs (67%) rename {tide-core/src => src}/app.rs (96%) rename tide-core/src/router.rs => src/router/core.rs (64%) create mode 100644 src/router/mod.rs rename {tide-core/src => src/router}/route.rs (94%) diff --git a/Cargo.toml b/Cargo.toml index 27b714889..6a9e816f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,12 +22,17 @@ version = "0.2.0" default = ["hyper", "cookies", "cors"] cookies = ["tide-cookies"] cors = ["tide-cors"] -hyper = ["tide-core/http-service-hyper"] +hyper = ["http-service-hyper"] [dependencies] futures-preview = "0.3.0-alpha.16" http = "0.1" http-service = "0.2.0" +http-service-hyper = { version = "0.2.0", optional = true } +# Routing +fnv = "1.0.6" +route-recognizer = "0.1.12" +# Tide components tide-cookies = { path = "./tide-cookies", optional = true } tide-cors = { path = "./tide-cors", optional = true } tide-core = { path = "./tide-core" } @@ -39,19 +44,20 @@ tide-querystring = { path = "./tide-querystring" } [dev-dependencies] bytes = "0.4.12" cookie = { version = "0.12", features = ["percent-encode"] } +env_logger = "0.6.1" futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } http-service-mock = "0.2.0" juniper = "0.12.0" +log = "0.4.6" +log4rs = "0.8.3" mime = "0.3.13" mime_guess = "2.0.0-alpha.6" percent-encoding = "1.0.1" serde = { version = "1.0.91", features = ["derive"] } tera = "0.11" +# Tide components tide-log = { path = "./tide-log" } -env_logger = "0.6.1" -log4rs = "0.8.3" -log = "0.4.6" [workspace] members = [ diff --git a/tide-cors/examples/cors.rs b/examples/cors.rs similarity index 67% rename from tide-cors/examples/cors.rs rename to examples/cors.rs index 1cbab2c99..c0c93ddbc 100644 --- a/tide-cors/examples/cors.rs +++ b/examples/cors.rs @@ -16,3 +16,11 @@ fn main() { app.run("127.0.0.1:8000").unwrap(); } + +// You can test this by running the following in your browser: +// +// ```console +// $ fetch("http://127.0.0.1:8000") +// ``` +// +// You will probably get a browser alert when running without cors middleware. diff --git a/tide-core/src/app.rs b/src/app.rs similarity index 96% rename from tide-core/src/app.rs rename to src/app.rs index b036fb0d0..1d9304b0d 100644 --- a/tide-core/src/app.rs +++ b/src/app.rs @@ -5,8 +5,8 @@ use std::sync::Arc; use crate::{ middleware::{Middleware, Next}, - router::{Router, Selection}, - Context, Route, + router::{Route, Router}, + Context, }; /// The entry point for building a Tide application. @@ -77,7 +77,6 @@ use crate::{ /// /// ```rust, no_run /// #![feature(async_await)] -/// #[macro_use] extern crate serde_derive; /// /// use http::status::StatusCode; /// use serde::{Deserialize, Serialize}; @@ -300,14 +299,9 @@ impl HttpService for Server { FutureExt::boxed(async move { let fut = { - let Selection { endpoint, params } = router.route(&path, method); + let (endpoint, params) = router.route(&path, method).into_components(); let cx = Context::new(state, req, params); - - let next = Next { - endpoint, - next_middleware: &middleware, - }; - + let next = Next::new(endpoint, &middleware); next.run(cx) }; @@ -322,14 +316,14 @@ mod tests { use std::sync::Arc; use super::*; - use crate::{middleware::Next, router::Selection, Context, Response}; + use crate::{middleware::Next, Context, Response}; fn simulate_request<'a, State: Default + Clone + Send + Sync + 'static>( app: &'a App, path: &'a str, method: http::Method, ) -> BoxFuture<'a, Response> { - let Selection { endpoint, params } = app.router.route(path, method.clone()); + let (endpoint, params) = app.router.route(path, method.clone()).into_components(); let state = Arc::new(State::default()); let req = http::Request::builder() @@ -337,11 +331,7 @@ mod tests { .body(http_service::Body::empty()) .unwrap(); let cx = Context::new(state, req, params); - let next = Next { - endpoint, - next_middleware: &app.middleware, - }; - + let next = Next::new(endpoint, &app.middleware); next.run(cx) } diff --git a/src/lib.rs b/src/lib.rs index 69afca565..894515225 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,11 @@ const _README: () = (); pub use http; +mod app; +mod router; + +pub use app::{App, Server}; + #[cfg(feature = "cookies")] #[doc(inline)] pub use tide_cookies as cookies; @@ -28,26 +33,11 @@ pub use tide_cookies as cookies; pub use tide_cors as cors; #[doc(inline)] -pub use tide_core::{ - err_fmt, - response, - App, - Context, - Endpoint, - EndpointResult, - Error, - Response, - Route, - Server, - // TODO: export Body once it's in turn exported by tide_core -}; +pub use tide_core::{response, Body, Context, Endpoint, EndpointResult, Error, Response}; pub mod error { - //! Module to export tide_core errors - - pub use tide_core::error::{ - EndpointResult, Error, ResponseExt, ResultDynErrExt, ResultExt, StringError, - }; + //! Error types re-exported from `tide-core` + pub use tide_core::error::{Error, ResponseExt, ResultDynErrExt, ResultExt, StringError}; } pub use tide_forms as forms; diff --git a/tide-core/src/router.rs b/src/router/core.rs similarity index 64% rename from tide-core/src/router.rs rename to src/router/core.rs index 1ce768dad..3dafa9b05 100644 --- a/tide-core/src/router.rs +++ b/src/router/core.rs @@ -1,32 +1,32 @@ +//! Router core types + use fnv::FnvHashMap; use futures::future::BoxFuture; use futures::prelude::*; use http_service::Body; use route_recognizer::{Match, Params, Router as MethodRouter}; -use crate::{ - endpoint::{DynEndpoint, Endpoint}, - Context, Response, -}; +use tide_core::{internal::DynEndpoint, Context, Endpoint, Response}; /// The routing table used by `App` /// /// Internally, we have a separate state machine per http method; indexing /// by the method first allows the table itself to be more efficient. #[allow(missing_debug_implementations)] -pub(crate) struct Router { +#[derive(Default)] +pub struct Router { method_map: FnvHashMap>>>, } -/// The result of routing a URL -pub(crate) struct Selection<'a, State> { - pub(crate) endpoint: &'a DynEndpoint, - pub(crate) params: Params, +#[allow(missing_debug_implementations)] +pub struct Selection<'a, State> { + endpoint: &'a DynEndpoint, + params: Params, } impl Router { - pub(crate) fn new() -> Router { - Router { + pub(crate) fn new() -> Self { + Self { method_map: FnvHashMap::default(), } } @@ -38,30 +38,36 @@ impl Router { .add(path, Box::new(move |cx| ep.call(cx).boxed())) } - pub(crate) fn route(&self, path: &str, method: http::Method) -> Selection<'_, State> { + pub fn route(&self, path: &str, method: http::Method) -> Selection<'_, State> { if let Some(Match { handler, params }) = self .method_map .get(&method) .and_then(|r| r.recognize(path).ok()) { - Selection { - endpoint: &**handler, - params, - } + Selection::new(&**handler, params) } else if method == http::Method::HEAD { // If it is a HTTP HEAD request then check if there is a callback in the endpoints map // if not then fallback to the behavior of HTTP GET else proceed as usual self.route(path, http::Method::GET) } else { - Selection { - endpoint: ¬_found_endpoint, - params: Params::new(), - } + Selection::new(¬_found_endpoint, Params::new()) } } } +impl<'a, State> Selection<'a, State> { + /// Create a new Selection + pub(crate) fn new(endpoint: &'a DynEndpoint, params: Params) -> Self { + Self { endpoint, params } + } + + /// Break Selection into it's components + pub fn into_components(self) -> (&'a DynEndpoint, Params) { + (self.endpoint, self.params) + } +} + fn not_found_endpoint(_cx: Context) -> BoxFuture<'static, Response> { FutureExt::boxed(async move { http::Response::builder() diff --git a/src/router/mod.rs b/src/router/mod.rs new file mode 100644 index 000000000..380bc62cd --- /dev/null +++ b/src/router/mod.rs @@ -0,0 +1,5 @@ +mod core; +mod route; + +pub use self::core::{Router, Selection}; +pub use route::Route; diff --git a/tide-core/src/route.rs b/src/router/route.rs similarity index 94% rename from tide-core/src/route.rs rename to src/router/route.rs index dc5297073..5862dc608 100644 --- a/tide-core/src/route.rs +++ b/src/router/route.rs @@ -1,4 +1,6 @@ -use crate::{router::Router, Endpoint}; +use tide_core::Endpoint; + +use super::core::Router; /// A handle to a route. /// @@ -15,8 +17,8 @@ pub struct Route<'a, State> { } impl<'a, State: 'static> Route<'a, State> { - pub(crate) fn new(router: &'a mut Router, path: String) -> Route<'a, State> { - Route { router, path } + pub fn new(router: &'a mut Router, path: String) -> Self { + Self { router, path } } /// Extend the route with the given `path`. diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 4d6b85aee..85bbd2404 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -102,8 +102,8 @@ mod tests { cx.set_cookie(Cookie::new("C2", "V2")).unwrap(); } - fn app() -> tide_core::App<()> { - let mut app = tide_core::App::new(); + fn app() -> tide::App<()> { + let mut app = tide::App::new(); app.middleware(CookiesMiddleware::new()); app.at("/get").get(retrieve_cookie); diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index 137b65f38..b32bc4a5c 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -11,22 +11,13 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/rustasync/tide" [dependencies] -fnv = "1.0.6" futures-preview = "0.3.0-alpha.16" http = "0.1" http-service = "0.2.0" -route-recognizer = "0.1.12" serde = "1.0.91" serde_json = "1.0.39" - -[dependencies.http-service-hyper] -optional = true -version = "0.2.0" +route-recognizer = "0.1.12" [dev-dependencies] tide = { path = "../" } serde_derive = "1.0.91" - -[features] -default = ["hyper"] -hyper = ["http-service-hyper"] diff --git a/tide-core/src/context.rs b/tide-core/src/context.rs index d3e1bacd5..ced4c1df0 100644 --- a/tide-core/src/context.rs +++ b/tide-core/src/context.rs @@ -18,12 +18,9 @@ pub struct Context { } impl Context { - pub(crate) fn new( - state: Arc, - request: http::Request, - route_params: Params, - ) -> Context { - Context { + /// Create a new Context + pub fn new(state: Arc, request: http::Request, route_params: Params) -> Self { + Self { state, request, route_params, diff --git a/tide-core/src/endpoint.rs b/tide-core/src/endpoint.rs index 2b379295c..1c97fb7bf 100644 --- a/tide-core/src/endpoint.rs +++ b/tide-core/src/endpoint.rs @@ -1,7 +1,7 @@ use futures::future::{BoxFuture, Future}; use futures::prelude::*; -use crate::{response::IntoResponse, Context, Response}; +use crate::{error::Error, response::IntoResponse, Context, Response}; /// A Tide endpoint. /// @@ -57,9 +57,6 @@ pub trait Endpoint: Send + Sync + 'static { fn call(&self, cx: Context) -> Self::Fut; } -pub(crate) type DynEndpoint = - dyn (Fn(Context) -> BoxFuture<'static, Response>) + 'static + Send + Sync; - impl Endpoint for F where F: Fn(Context) -> Fut, @@ -72,3 +69,6 @@ where FutureExt::boxed(async move { fut.await.into_response() }) } } + +/// A convenient `Result` instantiation appropriate for most endpoints. +pub type EndpointResult = Result; diff --git a/tide-core/src/error.rs b/tide-core/src/error.rs index 5062939ca..af460ad45 100644 --- a/tide-core/src/error.rs +++ b/tide-core/src/error.rs @@ -1,135 +1,160 @@ -//! Error and Result module +//! Error types -use crate::response::IntoResponse; -use http::{HttpTryFrom, Response, StatusCode}; -use http_service::Body; +pub use ext::{ResponseExt, ResultDynErrExt, ResultExt}; +pub use types::{Cause, Error, StringError}; -#[derive(Debug)] -/// A string error, which can be display -pub struct StringError(pub String); -impl std::error::Error for StringError {} +mod types { + use http::StatusCode; + use http_service::{Body, Response}; -impl std::fmt::Display for StringError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - self.0.fmt(f) - } -} + use crate::response::IntoResponse; -#[macro_export] -/// Macro that generates StringError immediately -macro_rules! err_fmt { - {$($t:tt)*} => { - $crate::error::StringError(format!($($t)*)) + /// A generic endpoint error, which can be converted into a response. + #[derive(Debug)] + pub struct Error { + resp: Response, } -} - -/// A convenient `Result` instantiation appropriate for most endpoints. -pub type EndpointResult> = Result; - -/// A generic endpoint error, which can be converted into a response. -#[derive(Debug)] -pub struct Error { - resp: Response, -} -impl IntoResponse for Error { - fn into_response(self) -> Response { - self.resp + impl IntoResponse for Error { + fn into_response(self) -> Response { + self.resp + } } -} -struct Cause(Box); + impl From for Error { + fn from(resp: Response) -> Error { + Error { resp } + } + } -impl From> for Error { - fn from(resp: Response) -> Error { - Error { resp } + impl From for Error { + fn from(status: StatusCode) -> Error { + let resp = http::Response::builder() + .status(status) + .body(Body::empty()) + .unwrap(); + Error { resp } + } } -} -impl From for Error { - fn from(status: StatusCode) -> Error { - let resp = Response::builder() - .status(status) - .body(Body::empty()) - .unwrap(); - Error { resp } + /// `Cause` type that is used for error nesting + #[derive(Debug)] + pub struct Cause(Box); + + impl Cause { + /// Create a new cause from boxed std Error + pub fn new(error: Box) -> Self { + Self(error) + } + + /// Access inner std error + #[allow(clippy::borrowed_box)] + pub fn inner_ref(&self) -> &Box { + &self.0 + } + + /// Get the original std error out + pub fn into_inner(self) -> Box { + self.0 + } } -} -/// Extends the `Response` type with a method to extract error causes when applicable. -pub trait ResponseExt { - /// Extract the cause of the unsuccessful response, if any - fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)>; -} + /// A simple error type that wraps a String + #[derive(Debug)] + pub struct StringError(pub String); + impl std::error::Error for StringError {} -impl ResponseExt for Response { - fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { - self.extensions().get().map(|Cause(c)| &**c) + impl std::fmt::Display for StringError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { + self.0.fmt(f) + } } } -/// Extends the `Result` type with convenient methods for constructing Tide errors. -pub trait ResultExt: Sized { - /// Convert to an `EndpointResult`, treating the `Err` case as a client - /// error (response code 400). - fn client_err(self) -> EndpointResult { - self.with_err_status(400) - } +mod ext { + use http::{HttpTryFrom, Response, StatusCode}; + use http_service::Body; - /// Convert to an `EndpointResult`, treating the `Err` case as a server - /// error (response code 500). - fn server_err(self) -> EndpointResult { - self.with_err_status(500) - } + use super::types::{Cause, Error}; + use crate::endpoint::EndpointResult; - /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom response status. - fn with_err_status(self, status: S) -> EndpointResult - where - StatusCode: HttpTryFrom; -} + /// Extends the `Response` type with a method to extract error causes when applicable. + pub trait ResponseExt { + /// Extract the cause of the unsuccessful response, if any + fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)>; + } -impl ResultExt for std::result::Result { - fn with_err_status(self, status: S) -> EndpointResult - where - StatusCode: HttpTryFrom, - { - let r = self.map_err(|e| Box::new(e) as Box); - r.with_err_status(status) + impl ResponseExt for Response { + fn err_cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { + self.extensions().get().map(|c: &Cause| &**c.inner_ref()) + } } -} -/// Extends the `Result` type using `std::error::Error` trait object as the error type with -/// convenient methods for constructing Tide errors. -pub trait ResultDynErrExt: Sized { - /// Convert to an `EndpointResult`, treating the `Err` case as a client - /// error (response code 400). - fn client_err(self) -> EndpointResult { - self.with_err_status(400) + /// Extends the `Result` type with convenient methods for constructing Tide errors. + pub trait ResultExt: Sized { + /// Convert to an `EndpointResult`, treating the `Err` case as a client + /// error (response code 400). + fn client_err(self) -> EndpointResult { + self.with_err_status(400) + } + + /// Convert to an `EndpointResult`, treating the `Err` case as a server + /// error (response code 500). + fn server_err(self) -> EndpointResult { + self.with_err_status(500) + } + + /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom response status. + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom; } - /// Convert to an `EndpointResult`, treating the `Err` case as a server - /// error (response code 500). - fn server_err(self) -> EndpointResult { - self.with_err_status(500) + impl ResultExt for std::result::Result { + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom, + { + let r = self.map_err(|e| Box::new(e) as Box); + r.with_err_status(status) + } } - /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom response status. - fn with_err_status(self, status: S) -> EndpointResult - where - StatusCode: HttpTryFrom; -} + /// Extends the `Result` type using `std::error::Error` trait object as the error type with + /// convenient methods for constructing Tide errors. + pub trait ResultDynErrExt: Sized { + /// Convert to an `EndpointResult`, treating the `Err` case as a client + /// error (response code 400). + fn client_err(self) -> EndpointResult { + self.with_err_status(400) + } + + /// Convert to an `EndpointResult`, treating the `Err` case as a server + /// error (response code 500). + fn server_err(self) -> EndpointResult { + self.with_err_status(500) + } + + /// Convert to an `EndpointResult`, wrapping the `Err` case with a custom response status. + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom; + } -impl ResultDynErrExt for std::result::Result> { - fn with_err_status(self, status: S) -> EndpointResult - where - StatusCode: HttpTryFrom, - { - self.map_err(|e| Error { - resp: Response::builder() - .status(status) - .extension(Cause(e)) - .body(Body::empty()) - .unwrap(), - }) + impl ResultDynErrExt for std::result::Result> { + fn with_err_status(self, status: S) -> EndpointResult + where + StatusCode: HttpTryFrom, + { + self.map_err(|e| { + Error::from( + Response::builder() + .status(status) + .extension(Cause::new(e)) + .body(Body::empty()) + .unwrap(), + ) + }) + } } } diff --git a/tide-core/src/internal.rs b/tide-core/src/internal.rs index 9a2ad59f1..2a58bd247 100644 --- a/tide-core/src/internal.rs +++ b/tide-core/src/internal.rs @@ -2,8 +2,14 @@ //! are meant to be used internally by the tide repo. use core::pin::Pin; -use futures::future::Future; +use futures::future::{BoxFuture, Future}; + +use crate::{Context, Response}; /// Convenience alias for pinned box of Future> + Send + 'static pub type BoxTryFuture = - Pin> + Send + 'static>>; + Pin> + Send + 'static>>; + +/// Convenience alias that's used to take loose functions as an Endpoint +pub type DynEndpoint = + dyn (Fn(Context) -> BoxFuture<'static, Response>) + 'static + Send + Sync; diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index f67178a22..e1ee54c66 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -12,23 +12,19 @@ // ISSUE: https://github.com/rust-lang/rust-clippy/issues/3988 #![allow(clippy::needless_lifetimes)] -mod app; mod context; mod endpoint; + pub mod error; pub mod middleware; pub mod response; -mod route; -mod router; // Internal shared API for limited use across crates in our repo pub mod internal; pub use crate::{ - app::{App, Server}, context::Context, - endpoint::Endpoint, - error::{EndpointResult, Error}, - response::Response, - route::Route, + endpoint::{Endpoint, EndpointResult}, + error::Error, + response::{Body, Response}, }; diff --git a/tide-core/src/middleware.rs b/tide-core/src/middleware.rs index 12129edd0..851ba9da6 100644 --- a/tide-core/src/middleware.rs +++ b/tide-core/src/middleware.rs @@ -1,6 +1,6 @@ -//! Middlewares +//! Middleware types -use crate::{endpoint::DynEndpoint, Context, Response}; +use crate::{internal::DynEndpoint, Context, Response}; use futures::future::BoxFuture; use std::sync::Arc; @@ -25,11 +25,19 @@ where /// The remainder of a middleware chain, including the endpoint. #[allow(missing_debug_implementations)] pub struct Next<'a, State> { - pub(crate) endpoint: &'a DynEndpoint, - pub(crate) next_middleware: &'a [Arc>], + endpoint: &'a DynEndpoint, + next_middleware: &'a [Arc>], } impl<'a, State: 'static> Next<'a, State> { + /// Create a new instance + pub fn new(endpoint: &'a DynEndpoint, next: &'a [Arc>]) -> Self { + Self { + endpoint, + next_middleware: next, + } + } + /// Asynchronously execute the remaining middleware chain. pub fn run(mut self, cx: Context) -> BoxFuture<'a, Response> { if let Some((current, next)) = self.next_middleware.split_first() { diff --git a/tide-core/src/response.rs b/tide-core/src/response.rs index 0adea7e63..f93c05855 100644 --- a/tide-core/src/response.rs +++ b/tide-core/src/response.rs @@ -1,6 +1,6 @@ -//! Multiple types of response modules +//! Response types -use http_service::Body; +pub use http_service::Body; /// An Http response pub type Response = http_service::Response; diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs index c2fe3215e..9772cbe16 100644 --- a/tide-cors/src/lib.rs +++ b/tide-cors/src/lib.rs @@ -2,13 +2,11 @@ //! //! ## Examples //! -//! Examples are in the `/examples` folder of this crate. -//! //! ```rust,no_run //! #![feature(async_await)] //! //! use http::header::HeaderValue; -//! use tide::middleware::CorsMiddleware; +//! use tide_cors::CorsMiddleware; //! //! fn main() { //! let mut app = tide::App::new(); @@ -24,10 +22,7 @@ //! app.run("127.0.0.1:8000").unwrap(); //! } //! ``` -//! -//! __Simple Example__ -//! -//! You can test the simple example by running `cargo run --example cors` while in this crate's directory, and then running this script in the browser console: +//! You can test this by running the following in your browser: //! //! ```console //! $ fetch("http://127.0.0.1:8000") diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs index 6a9952b46..a3d253cb5 100644 --- a/tide-cors/src/middleware.rs +++ b/tide-cors/src/middleware.rs @@ -16,7 +16,7 @@ use tide_core::{ /// /// ```rust ///use http::header::HeaderValue; -///use tide::middleware::CorsMiddleware; +///use tide_cors::CorsMiddleware; /// ///CorsMiddleware::new() /// .allow_origin(HeaderValue::from_static("*")) @@ -167,8 +167,8 @@ mod test { const ENDPOINT: &str = "/cors"; - fn app() -> tide_core::App<()> { - let mut app = tide_core::App::new(); + fn app() -> tide::App<()> { + let mut app = tide::App::new(); app.at(ENDPOINT).get(async move |_| "Hello World"); app diff --git a/tide-forms/src/lib.rs b/tide-forms/src/lib.rs index 67165c2e6..6f25d5e07 100644 --- a/tide-forms/src/lib.rs +++ b/tide-forms/src/lib.rs @@ -14,7 +14,11 @@ use http_service::Body; use multipart::server::Multipart; use std::io::Cursor; -use tide_core::{err_fmt, error::ResultExt, internal::BoxTryFuture, Context, Response}; +use tide_core::{ + error::{ResultExt, StringError}, + internal::BoxTryFuture, + Context, Response, +}; /// An extension trait for `Context`, providing form extraction. pub trait ContextExt { @@ -31,7 +35,7 @@ impl ContextExt for Context { FutureExt::boxed(async move { let body = body.into_vec().await.client_err()?; Ok(serde_urlencoded::from_bytes(&body) - .map_err(|e| err_fmt!("could not decode form: {}", e)) + .map_err(|e| StringError(format!("could not decode form: {}", e))) .client_err()?) }) } @@ -49,7 +53,7 @@ impl ContextExt for Context { FutureExt::boxed(async move { let body = body.into_vec().await.client_err()?; let boundary = boundary - .ok_or_else(|| err_fmt!("no boundary found")) + .ok_or_else(|| StringError("no boundary found".to_string())) .client_err()?; Ok(Multipart::with_body(Cursor::new(body), boundary)) }) diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index 294bc7791..889b7da80 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -16,7 +16,7 @@ readme = "README.md" repository = "https://github.com/rustasync/tide" version = "0.1.0" - [dependencies] +[dependencies] tide-core = { path = "../tide-core" } futures-preview = "0.3.0-alpha.16" http = "0.1" diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml index 4a2074b85..365c088d9 100644 --- a/tide-log/Cargo.toml +++ b/tide-log/Cargo.toml @@ -17,7 +17,7 @@ readme = "README.md" repository = "https://github.com/rustasync/tide" version = "0.1.0" - [dependencies] +[dependencies] tide-core = { path = "../tide-core" } futures-preview = "0.3.0-alpha.16" http = "0.1" diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index 5f5bbbd95..f32db6246 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -16,7 +16,7 @@ readme = "README.md" repository = "https://github.com/rustasync/tide" version = "0.1.0" - [dependencies] +[dependencies] tide-core = { path = "../tide-core" } futures-preview = "0.3.0-alpha.16" http = "0.1" diff --git a/tide-querystring/src/lib.rs b/tide-querystring/src/lib.rs index 15e735a7f..17a1795a2 100644 --- a/tide-querystring/src/lib.rs +++ b/tide-querystring/src/lib.rs @@ -20,7 +20,6 @@ pub trait ContextExt<'de> { } impl<'de, State> ContextExt<'de> for Context { - #[inline] fn url_query>(&'de self) -> Result { let query = self.uri().query(); if query.is_none() { From 2e063ae9f89ce90a1b629eb3475f4b82c7d94190 Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Thu, 4 Jul 2019 12:09:32 +0200 Subject: [PATCH 62/95] Add example running on top of runtime (#283) --- Cargo.toml | 1 + examples/runtime.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 examples/runtime.rs diff --git a/Cargo.toml b/Cargo.toml index 6a9e816f2..ae4d7dd0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ mime_guess = "2.0.0-alpha.6" percent-encoding = "1.0.1" serde = { version = "1.0.91", features = ["derive"] } tera = "0.11" +runtime = "0.3.0-alpha.6" # Tide components tide-log = { path = "./tide-log" } diff --git a/examples/runtime.rs b/examples/runtime.rs new file mode 100644 index 000000000..e1accc5fd --- /dev/null +++ b/examples/runtime.rs @@ -0,0 +1,29 @@ +#![feature(async_await)] + +/// An example of how to run a Tide service on top of `runtime`, this also shows the pieces +/// necessary if you wish to run a service on some other executor/IO source. + +#[runtime::main] +async fn main() -> Result<(), Box> { + // First, we create a simple hello world application + let mut app = tide::App::new(); + app.at("/").get(async move |_| "Hello, world!"); + + // Instead of using `App::run` to start the application, which implicitly uses a default + // http-service server, we need to configure a custom server with the executor and IO source we + // want it to use and then run the Tide service on it. + + // Turn the `tide::App` into a generic `http_service::HttpService` + let http_service = app.into_http_service(); + + // Build an `http_service_hyper::Server` using runtime's `TcpListener` and `Spawn` instances + // instead of hyper's defaults. + let mut listener = runtime::net::TcpListener::bind("127.0.0.1:8000")?; + let server = http_service_hyper::Server::builder(listener.incoming()) + .with_spawner(runtime::task::Spawner::new()); + + // Serve the Tide service on the configured server, and wait for it to complete + server.serve(http_service).await?; + + Ok(()) +} From a74cc28223b5be4bdbeb943f05821cc07432cd73 Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Thu, 4 Jul 2019 12:10:45 +0200 Subject: [PATCH 63/95] Disable default-features everywhere (#282) --- Cargo.toml | 16 ++++++++-------- tide-compression/Cargo.toml | 4 ++-- tide-cookies/Cargo.toml | 4 ++-- tide-core/Cargo.toml | 2 +- tide-forms/Cargo.toml | 4 ++-- tide-headers/Cargo.toml | 4 ++-- tide-log/Cargo.toml | 4 ++-- tide-querystring/Cargo.toml | 4 ++-- tide-slog/Cargo.toml | 6 +++--- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ae4d7dd0d..709cd6a64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,13 +33,13 @@ http-service-hyper = { version = "0.2.0", optional = true } fnv = "1.0.6" route-recognizer = "0.1.12" # Tide components -tide-cookies = { path = "./tide-cookies", optional = true } -tide-cors = { path = "./tide-cors", optional = true } -tide-core = { path = "./tide-core" } -tide-headers = { path = "./tide-headers" } -tide-log = { path = "./tide-log" } -tide-forms = { path = "./tide-forms" } -tide-querystring = { path = "./tide-querystring" } +tide-cookies = { path = "./tide-cookies", optional = true, default-features = false } +tide-cors = { path = "./tide-cors", optional = true, default-features = false } +tide-core = { path = "./tide-core", default-features = false } +tide-headers = { path = "./tide-headers", default-features = false } +tide-log = { path = "./tide-log", default-features = false } +tide-forms = { path = "./tide-forms", default-features = false } +tide-querystring = { path = "./tide-querystring", default-features = false } [dev-dependencies] bytes = "0.4.12" @@ -58,7 +58,7 @@ serde = { version = "1.0.91", features = ["derive"] } tera = "0.11" runtime = "0.3.0-alpha.6" # Tide components -tide-log = { path = "./tide-log" } +tide-log = { path = "./tide-log", default-features = false } [workspace] members = [ diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml index 395fff270..d8416f3c4 100644 --- a/tide-compression/Cargo.toml +++ b/tide-compression/Cargo.toml @@ -14,7 +14,7 @@ repository = "https://github.com/rustasync/tide" version = "0.1.0" [dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } accept-encoding = "0.2.0-alpha.2" bytes = "0.4.12" futures-preview = "0.3.0-alpha.16" @@ -27,5 +27,5 @@ features = ["stream", "gzip", "zlib", "brotli", "zstd"] version = "0.1.0-alpha.1" [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } http-service-mock = "0.2.0" diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index 6c0742f4e..d2a479a80 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -15,8 +15,8 @@ cookie = { version = "0.12", features = ["percent-encode"] } futures-preview = "0.3.0-alpha.16" http = "0.1" http-service = "0.2.0" -tide-core = { path = "../tide-core" } +tide-core = { path = "../tide-core", default-features = false } [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } http-service-mock = "0.2.0" diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index b32bc4a5c..8a061e47d 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -19,5 +19,5 @@ serde_json = "1.0.39" route-recognizer = "0.1.12" [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } serde_derive = "1.0.91" diff --git a/tide-forms/Cargo.toml b/tide-forms/Cargo.toml index 3b5fe4a44..def9a04fe 100644 --- a/tide-forms/Cargo.toml +++ b/tide-forms/Cargo.toml @@ -17,7 +17,7 @@ repository = "https://github.com/rustasync/tide" version = "0.1.0" [dependencies] -tide-core = { path = "../tide-core" } +tide-core = { path = "../tide-core", default-features = false } http-service = "0.2.0" futures-preview = "0.3.0-alpha.16" http = "0.1" @@ -27,5 +27,5 @@ serde = { version = "1.0.91", features = ["derive"] } serde_urlencoded = "0.5.5" [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index 889b7da80..a55ca8dbd 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -17,10 +17,10 @@ repository = "https://github.com/rustasync/tide" version = "0.1.0" [dependencies] -tide-core = { path = "../tide-core" } +tide-core = { path = "../tide-core", default-features = false } futures-preview = "0.3.0-alpha.16" http = "0.1" log = "0.4.6" [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml index 365c088d9..b4dbb66f1 100644 --- a/tide-log/Cargo.toml +++ b/tide-log/Cargo.toml @@ -18,10 +18,10 @@ repository = "https://github.com/rustasync/tide" version = "0.1.0" [dependencies] -tide-core = { path = "../tide-core" } +tide-core = { path = "../tide-core", default-features = false } futures-preview = "0.3.0-alpha.16" http = "0.1" log = "0.4.6" [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index f32db6246..a97b6af9b 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -17,7 +17,7 @@ repository = "https://github.com/rustasync/tide" version = "0.1.0" [dependencies] -tide-core = { path = "../tide-core" } +tide-core = { path = "../tide-core", default-features = false } futures-preview = "0.3.0-alpha.16" http = "0.1" log = "0.4.6" @@ -25,7 +25,7 @@ serde = { version = "1.0.91", features = ["derive"] } serde_urlencoded = "0.5.5" [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } http-service = "0.2.0" http-service-mock = "0.2.0" diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index dd00a8b04..e1080b90c 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -17,8 +17,8 @@ readme = "README.md" repository = "https://github.com/rustasync/tide" version = "0.1.0" - [dependencies] -tide-core = { path = "../tide-core" } +[dependencies] +tide-core = { path = "../tide-core", default-features = false } futures-preview = "0.3.0-alpha.16" http = "0.1" log = "0.4.6" @@ -27,4 +27,4 @@ slog-async = "2.3.0" slog-term = "2.4.0" [dev-dependencies] -tide = { path = "../" } +tide = { path = "../", default-features = false } From d17b4f022b2dfb922ba2742c6e64696ecd45f6d8 Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Thu, 4 Jul 2019 18:15:58 +0200 Subject: [PATCH 64/95] Update for futures alpha.17 (#286) --- Cargo.toml | 4 ++-- src/app.rs | 3 +-- src/router/core.rs | 2 +- tide-compression/Cargo.toml | 2 +- tide-compression/src/lib.rs | 5 ++--- tide-cookies/Cargo.toml | 2 +- tide-cookies/src/middleware.rs | 3 +-- tide-core/Cargo.toml | 2 +- tide-core/src/endpoint.rs | 3 +-- tide-cors/Cargo.toml | 2 +- tide-cors/src/middleware.rs | 4 ++-- tide-forms/Cargo.toml | 2 +- tide-forms/src/lib.rs | 5 ++--- tide-headers/Cargo.toml | 2 +- tide-headers/src/lib.rs | 3 +-- tide-log/Cargo.toml | 2 +- tide-log/src/lib.rs | 4 ++-- tide-panic/Cargo.toml | 2 +- tide-querystring/Cargo.toml | 2 +- tide-slog/Cargo.toml | 2 +- tide-slog/src/lib.rs | 3 +-- 21 files changed, 26 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 709cd6a64..834121f84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ cors = ["tide-cors"] hyper = ["http-service-hyper"] [dependencies] -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" http-service = "0.2.0" http-service-hyper = { version = "0.2.0", optional = true } @@ -46,7 +46,7 @@ bytes = "0.4.12" cookie = { version = "0.12", features = ["percent-encode"] } env_logger = "0.6.1" futures-fs = "0.0.5" -futures-util-preview = { version = "0.3.0-alpha.16", features = ["compat"] } +futures-util-preview = { version = "0.3.0-alpha.17", features = ["compat"] } http-service-mock = "0.2.0" juniper = "0.12.0" log = "0.4.6" diff --git a/src/app.rs b/src/app.rs index 1d9304b0d..03f1c5f1a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,4 @@ use futures::future::{self, BoxFuture}; -use futures::prelude::*; use http_service::HttpService; use std::sync::Arc; @@ -297,7 +296,7 @@ impl HttpService for Server { let middleware = self.middleware.clone(); let state = self.state.clone(); - FutureExt::boxed(async move { + Box::pin(async move { let fut = { let (endpoint, params) = router.route(&path, method).into_components(); let cx = Context::new(state, req, params); diff --git a/src/router/core.rs b/src/router/core.rs index 3dafa9b05..a4814ce3b 100644 --- a/src/router/core.rs +++ b/src/router/core.rs @@ -69,7 +69,7 @@ impl<'a, State> Selection<'a, State> { } fn not_found_endpoint(_cx: Context) -> BoxFuture<'static, Response> { - FutureExt::boxed(async move { + Box::pin(async move { http::Response::builder() .status(http::StatusCode::NOT_FOUND) .body(Body::empty()) diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml index d8416f3c4..ea9fbac65 100644 --- a/tide-compression/Cargo.toml +++ b/tide-compression/Cargo.toml @@ -17,7 +17,7 @@ version = "0.1.0" tide = { path = "../", default-features = false } accept-encoding = "0.2.0-alpha.2" bytes = "0.4.12" -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" http-service = "0.2.0" diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 0f3551e4e..326d6e0da 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -15,7 +15,6 @@ pub use accept_encoding::Encoding; use async_compression::stream; use futures::future::BoxFuture; -use futures::prelude::*; use http::{header::CONTENT_ENCODING, status::StatusCode, HeaderMap}; use http_service::{Body, Request}; use tide::{ @@ -134,7 +133,7 @@ impl Compression { impl Middleware for Compression { fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { - FutureExt::boxed(async move { + Box::pin(async move { let encoding = match self.preferred_encoding(cx.headers()) { Ok(encoding) => encoding, Err(e) => return e.into_response(), @@ -222,7 +221,7 @@ impl Middleware for Decompression { mut cx: Context, next: Next<'a, State>, ) -> BoxFuture<'a, Response> { - FutureExt::boxed(async move { + Box::pin(async move { match self.decode(cx.request_mut()) { Ok(_) => (), Err(e) => return e.into_response(), diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index d2a479a80..6263cd801 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/rustasync/tide" [dependencies] cookie = { version = "0.12", features = ["percent-encode"] } -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" http-service = "0.2.0" tide-core = { path = "../tide-core", default-features = false } diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index 85bbd2404..b6fd93b2c 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -1,6 +1,5 @@ use crate::data::CookieData; use futures::future::BoxFuture; -use futures::prelude::*; use http::header::HeaderValue; use tide_core::{ @@ -36,7 +35,7 @@ impl Middleware for CookiesMiddleware { mut cx: Context, next: Next<'a, State>, ) -> BoxFuture<'a, Response> { - FutureExt::boxed(async move { + Box::pin(async move { let cookie_data = cx .extensions_mut() .remove() diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index 8a061e47d..5e716352d 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/rustasync/tide" [dependencies] -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" http-service = "0.2.0" serde = "1.0.91" diff --git a/tide-core/src/endpoint.rs b/tide-core/src/endpoint.rs index 1c97fb7bf..d4381db73 100644 --- a/tide-core/src/endpoint.rs +++ b/tide-core/src/endpoint.rs @@ -1,5 +1,4 @@ use futures::future::{BoxFuture, Future}; -use futures::prelude::*; use crate::{error::Error, response::IntoResponse, Context, Response}; @@ -66,7 +65,7 @@ where type Fut = BoxFuture<'static, Response>; fn call(&self, cx: Context) -> Self::Fut { let fut = (self)(cx); - FutureExt::boxed(async move { fut.await.into_response() }) + Box::pin(async move { fut.await.into_response() }) } } diff --git a/tide-cors/Cargo.toml b/tide-cors/Cargo.toml index cbfd06be2..a917181e6 100644 --- a/tide-cors/Cargo.toml +++ b/tide-cors/Cargo.toml @@ -14,7 +14,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" http-service = "0.2.0" tide-core = { path = "../tide-core" } diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs index a3d253cb5..52f4d5d76 100644 --- a/tide-cors/src/middleware.rs +++ b/tide-cors/src/middleware.rs @@ -1,7 +1,7 @@ //! Cors middleware use futures::future::BoxFuture; -use futures::prelude::*; + use http::header::HeaderValue; use http::{header, Method, StatusCode}; use http_service::Body; @@ -126,7 +126,7 @@ impl CorsMiddleware { impl Middleware for CorsMiddleware { fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { - FutureExt::boxed(async move { + Box::pin(async move { // Return results immediately upon preflight request if cx.method() == Method::OPTIONS { return self.build_preflight_response(); diff --git a/tide-forms/Cargo.toml b/tide-forms/Cargo.toml index def9a04fe..2eb066141 100644 --- a/tide-forms/Cargo.toml +++ b/tide-forms/Cargo.toml @@ -19,7 +19,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } http-service = "0.2.0" -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" multipart = { version = "0.16.1", features = ["server"], default-features = false } diff --git a/tide-forms/src/lib.rs b/tide-forms/src/lib.rs index 6f25d5e07..534e199f5 100644 --- a/tide-forms/src/lib.rs +++ b/tide-forms/src/lib.rs @@ -9,7 +9,6 @@ missing_debug_implementations )] -use futures::prelude::*; use http_service::Body; use multipart::server::Multipart; use std::io::Cursor; @@ -32,7 +31,7 @@ pub trait ContextExt { impl ContextExt for Context { fn body_form(&mut self) -> BoxTryFuture { let body = self.take_body(); - FutureExt::boxed(async move { + Box::pin(async move { let body = body.into_vec().await.client_err()?; Ok(serde_urlencoded::from_bytes(&body) .map_err(|e| StringError(format!("could not decode form: {}", e))) @@ -50,7 +49,7 @@ impl ContextExt for Context { let body = self.take_body(); - FutureExt::boxed(async move { + Box::pin(async move { let body = body.into_vec().await.client_err()?; let boundary = boundary .ok_or_else(|| StringError("no boundary found".to_string())) diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index a55ca8dbd..19dbd770c 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -18,7 +18,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" diff --git a/tide-headers/src/lib.rs b/tide-headers/src/lib.rs index 3795a3f97..e7b1dfd43 100644 --- a/tide-headers/src/lib.rs +++ b/tide-headers/src/lib.rs @@ -10,7 +10,6 @@ )] use futures::future::BoxFuture; -use futures::prelude::*; use log::trace; use http::{ @@ -52,7 +51,7 @@ impl DefaultHeaders { impl Middleware for DefaultHeaders { fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { - FutureExt::boxed(async move { + Box::pin(async move { let mut res = next.run(cx).await; let headers = res.headers_mut(); for (key, value) in self.headers.iter() { diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml index b4dbb66f1..2f4d7ce49 100644 --- a/tide-log/Cargo.toml +++ b/tide-log/Cargo.toml @@ -19,7 +19,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index 496d58fb1..48123de6c 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -10,7 +10,7 @@ )] use futures::future::BoxFuture; -use futures::prelude::*; + use log::{info, trace}; use tide_core::{ @@ -72,6 +72,6 @@ impl RequestLogger { impl Middleware for RequestLogger { fn handle<'a>(&'a self, ctx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { - FutureExt::boxed(async move { self.log_basic(ctx, next).await }) + Box::pin(async move { self.log_basic(ctx, next).await }) } } diff --git a/tide-panic/Cargo.toml b/tide-panic/Cargo.toml index 0937c822c..07e5fad0d 100644 --- a/tide-panic/Cargo.toml +++ b/tide-panic/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/rustasync/tide" [dependencies] -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" http-service = "0.2.0" tide-core = { path = "../tide-core" } diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index a97b6af9b..25e5044c7 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -18,7 +18,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" serde = { version = "1.0.91", features = ["derive"] } diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index e1080b90c..47b619cd4 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -19,7 +19,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.16" +futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" slog = "2.4.1" diff --git a/tide-slog/src/lib.rs b/tide-slog/src/lib.rs index 4df5ad6bb..a1493c02f 100644 --- a/tide-slog/src/lib.rs +++ b/tide-slog/src/lib.rs @@ -14,7 +14,6 @@ use slog_async; use slog_term; use futures::future::BoxFuture; -use futures::prelude::*; use tide_core::{ middleware::{Middleware, Next}, @@ -53,7 +52,7 @@ impl Default for RequestLogger { /// is generated. impl Middleware for RequestLogger { fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { - FutureExt::boxed(async move { + Box::pin(async move { let path = cx.uri().path().to_owned(); let method = cx.method().as_str().to_owned(); trace!(self.inner, "IN => {} {}", method, path); From 25de413863e270ae47aed6dc09e2f634923071c2 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 26 May 2019 17:58:27 +0200 Subject: [PATCH 65/95] Rewrite tide-slog to setup a per-request logger instance and support slog-scope --- .travis.yml | 5 ++ tide-slog/Cargo.toml | 19 ++++-- tide-slog/src/lib.rs | 85 ++++++++---------------- tide-slog/src/per_request_logger.rs | 89 ++++++++++++++++++++++++++ tide-slog/src/request_logger.rs | 74 +++++++++++++++++++++ tide-slog/src/set_slog_scope_logger.rs | 51 +++++++++++++++ 6 files changed, 259 insertions(+), 64 deletions(-) create mode 100644 tide-slog/src/per_request_logger.rs create mode 100644 tide-slog/src/request_logger.rs create mode 100644 tide-slog/src/set_slog_scope_logger.rs diff --git a/.travis.yml b/.travis.yml index cb734fa3c..8e56b7e2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,3 +54,8 @@ matrix: - name: cargo test script: - cargo test -Zmtime-on-use --all --verbose + + - name: cargo test --all-features + script: + - cargo test -Zmtime-on-use --all-features + - cargo test -Zmtime-on-use --manifest-path tide-slog/Cargo.toml --all-features diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index 47b619cd4..126ab08c0 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -1,7 +1,5 @@ [package] -authors = [ - "Tide Developers" -] +authors = ["Tide Developers"] description = "Logging middleware for Tide based on slog" documentation = "https://docs.rs/tide-slog" keywords = ["tide", "web", "middleware", "logging", "slog"] @@ -17,14 +15,23 @@ readme = "README.md" repository = "https://github.com/rustasync/tide" version = "0.1.0" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg docrs"] + +[features] +scope = ["slog-scope", "slog-scope-futures"] + [dependencies] tide-core = { path = "../tide-core", default-features = false } futures-preview = "0.3.0-alpha.17" http = "0.1" -log = "0.4.6" slog = "2.4.1" -slog-async = "2.3.0" -slog-term = "2.4.0" +slog-scope = { version = "4.1.1", optional = true } +slog-scope-futures = { version = "0.1.1", optional = true } [dev-dependencies] tide = { path = "../", default-features = false } +uuid = { version = "0.7.4", default-features = false, features = ["v4"] } +slog-stdlog = "3.0.2" +slog-scope = "4.1.1" diff --git a/tide-slog/src/lib.rs b/tide-slog/src/lib.rs index a1493c02f..3f8b2acbf 100644 --- a/tide-slog/src/lib.rs +++ b/tide-slog/src/lib.rs @@ -1,6 +1,7 @@ //! Crate that provides helpers and/or middlewares for Tide //! related to structured logging with slog. +#![cfg_attr(docrs, feature(doc_cfg))] #![feature(async_await)] #![warn( nonstandard_style, @@ -9,65 +10,33 @@ missing_debug_implementations )] -use slog::{info, o, trace, Drain}; -use slog_async; -use slog_term; - -use futures::future::BoxFuture; - -use tide_core::{ - middleware::{Middleware, Next}, - Context, Response, -}; - -/// RequestLogger based on slog.SimpleLogger -#[derive(Debug)] -pub struct RequestLogger { - // drain: dyn slog::Drain, - inner: slog::Logger, -} - -impl RequestLogger { - pub fn new() -> Self { - Default::default() - } - - pub fn with_logger(logger: slog::Logger) -> Self { - Self { inner: logger } - } -} - -impl Default for RequestLogger { - fn default() -> Self { - let decorator = slog_term::TermDecorator::new().build(); - let drain = slog_term::CompactFormat::new(decorator).build().fuse(); - let drain = slog_async::Async::new(drain).build().fuse(); - - let log = slog::Logger::root(drain, o!()); - Self { inner: log } - } +mod per_request_logger; +mod request_logger; +#[cfg(feature = "scope")] +mod set_slog_scope_logger; + +pub use per_request_logger::PerRequestLogger; +pub use request_logger::RequestLogger; +#[cfg(feature = "scope")] +pub use set_slog_scope_logger::SetSlogScopeLogger; + +use tide_core::Context; + +/// An extension to [`Context`] that provides access to a per-request [`slog::Logger`] +pub trait ContextExt { + /// Returns a [`slog::Logger`] scoped to this request. + /// + /// # Panics + /// + /// Will panic if no [`PerRequestLogger`] middleware has been used to setup the request scoped + /// logger. + fn logger(&self) -> &slog::Logger; } -/// Stores information during request phase and logs information once the response -/// is generated. -impl Middleware for RequestLogger { - fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { - Box::pin(async move { - let path = cx.uri().path().to_owned(); - let method = cx.method().as_str().to_owned(); - trace!(self.inner, "IN => {} {}", method, path); - let start = std::time::Instant::now(); - let res = next.run(cx).await; - let status = res.status(); - info!( - self.inner, - "{} {} {} {}ms", - method, - path, - status.as_str(), - start.elapsed().as_millis() - ); - res - }) +impl ContextExt for Context { + fn logger(&self) -> &slog::Logger { + self.extensions() + .get::() + .expect("PerRequestLogger must be used to populate request logger") } } diff --git a/tide-slog/src/per_request_logger.rs b/tide-slog/src/per_request_logger.rs new file mode 100644 index 000000000..822983cac --- /dev/null +++ b/tide-slog/src/per_request_logger.rs @@ -0,0 +1,89 @@ +use futures::future::BoxFuture; +use tide_core::{ + middleware::{Middleware, Next}, + Context, Response, +}; + +/// Middleware that injects a per-request [`slog::Logger`] onto the request [`Context`]. +pub struct PerRequestLogger { + setup: Box) -> slog::Logger) + Send + Sync + 'static>, +} + +impl PerRequestLogger { + /// Initialize this middleware with a function to create a per-request logger. + /// + /// # Examples + /// + /// ## Adding a base16 encoded per-request UUID onto the logger context + /// + /// ``` + /// use slog::o; + /// + /// let mut app = tide::App::new(); + /// + /// let request_id = || uuid::Uuid::new_v4().to_simple().to_string(); + /// + /// let root_logger = slog::Logger::root(slog::Discard, o!()); + /// app.middleware(tide_slog::PerRequestLogger::with_setup(move |_cx| root_logger.new(o! { + /// "request" => request_id(), + /// }))); + /// ``` + /// + /// ## Taking an externally provided request id from headers for the logger context + /// + /// ``` + /// use slog::o; + /// + /// let mut app = tide::App::new(); + /// + /// let root_logger = slog::Logger::root(slog::Discard, o!()); + /// app.middleware(tide_slog::PerRequestLogger::with_setup(move |cx| root_logger.new(o! { + /// "request" => cx.headers().get("Request-Id").unwrap().to_str().unwrap().to_owned(), + /// }))); + /// ``` + pub fn with_setup( + setup: impl (Fn(&mut Context) -> slog::Logger) + Send + Sync + 'static, + ) -> Self { + Self { + setup: Box::new(setup), + } + } + + /// Initialize this middleware with a logger that will provided to each request. + /// + /// # Examples + /// + /// ``` + /// use slog::o; + /// + /// let mut app = tide::App::new(); + /// + /// let root_logger = slog::Logger::root(slog::Discard, o!()); + /// app.middleware(tide_slog::PerRequestLogger::with_logger(root_logger)); + /// ``` + pub fn with_logger(logger: slog::Logger) -> Self { + Self { + setup: Box::new(move |_cx| logger.clone()), + } + } +} + +impl Middleware for PerRequestLogger { + fn handle<'a>( + &'a self, + mut cx: Context, + next: Next<'a, State>, + ) -> BoxFuture<'a, Response> { + let logger = (self.setup)(&mut cx); + cx.extensions_mut().insert(logger); + next.run(cx) + } +} + +impl std::fmt::Debug for PerRequestLogger { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PerRequestLogger") + .field("setup", &"[closure]") + .finish() + } +} diff --git a/tide-slog/src/request_logger.rs b/tide-slog/src/request_logger.rs new file mode 100644 index 000000000..f10682dea --- /dev/null +++ b/tide-slog/src/request_logger.rs @@ -0,0 +1,74 @@ +use crate::ContextExt; +use futures::future::BoxFuture; +use slog::{info, trace}; +use tide_core::{ + middleware::{Middleware, Next}, + Context, Response, +}; + +/// Middleware that logs minimal request details to the current request's [`slog::Logger`]. +/// +/// Relies on having a [`PerRequestLogger`][crate::PerRequestLogger] middleware instance setup +/// beforehand to get the logger from. +/// +/// # Examples +/// +/// ``` +/// use slog::o; +/// +/// let mut app = tide::App::new(); +/// +/// let root_logger = slog::Logger::root(slog::Discard, o!()); +/// app.middleware(tide_slog::PerRequestLogger::with_logger(root_logger)); +/// app.middleware(tide_slog::RequestLogger::new()); +/// ``` +#[derive(Debug)] +pub struct RequestLogger { + // In case we want to make this configurable in the future + _reserved: (), +} + +impl RequestLogger { + /// Create a new [`RequestLogger`] instance. + pub fn new() -> Self { + Self { _reserved: () } + } +} + +impl Middleware for RequestLogger { + fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { + Box::pin(async move { + let logger = cx.logger().clone(); + let path = cx.uri().path().to_owned(); + let method = cx.method().as_str().to_owned(); + + trace!( + logger, + "IN => {method} {path}", + method = &method, + path = &path + ); + + let start = std::time::Instant::now(); + let res = next.run(cx).await; + let status = res.status(); + + info!( + logger, + "{method} {path} {status} {elapsed}ms", + method = &method, + path = &path, + status = status.as_str(), + elapsed = start.elapsed().as_millis(), + ); + + res + }) + } +} + +impl Default for RequestLogger { + fn default() -> Self { + Self::new() + } +} diff --git a/tide-slog/src/set_slog_scope_logger.rs b/tide-slog/src/set_slog_scope_logger.rs new file mode 100644 index 000000000..ec771126f --- /dev/null +++ b/tide-slog/src/set_slog_scope_logger.rs @@ -0,0 +1,51 @@ +use crate::ContextExt; +use futures::future::{BoxFuture, FutureExt as _}; +use slog_scope_futures::FutureExt as _; +use tide_core::{ + middleware::{Middleware, Next}, + Response, +}; + +#[cfg_attr(docrs, doc(cfg(feature = "scope")))] +/// Middleware that ensures the current request's [`slog::Logger`] will be accessible using +/// [`slog-scope::logger`] during all following processing of the request. +/// +/// Relies on having a [`PerRequestLogger`][crate::PerRequestLogger] middleware instance setup +/// beforehand to get the logger from. +/// +/// This can be used along with [`slog-stdlog`](https://docs.rs/slog-stdlog/) to +/// integrate per-request logging with middleware that use [`log`](https://docs.rs/log)`. +/// +/// # Examples +/// +/// ``` +/// use slog::o; +/// +/// let root_logger = slog::Logger::root(slog::Discard, o!()); +/// +/// let _guard = slog_scope::set_global_logger(root_logger.clone()); +/// slog_stdlog::init()?; +/// +/// let mut app = tide::App::new(); +/// +/// app.middleware(tide_slog::PerRequestLogger::with_logger(root_logger)); +/// app.middleware(tide_slog::SetSlogScopeLogger); +/// +/// // The default tide request logger uses `log`, but since we are using `slog-stdlog` and run +/// // `SetSlogScopeLogger` first it will be redirected into the per-request logger instance. +/// app.middleware(tide::middleware::RequestLogger::new()); +/// # Ok::<(), Box>(()) +/// ``` +#[derive(Debug)] +pub struct SetSlogScopeLogger; + +impl Middleware for SetSlogScopeLogger { + fn handle<'a>( + &'a self, + cx: tide_core::Context, + next: Next<'a, State>, + ) -> BoxFuture<'a, Response> { + let logger = cx.logger().clone(); + next.run(cx).with_logger(logger).boxed() + } +} From 36c15fd4ca67fcb269e7bc87d2ceb6eeb8826483 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 9 Jul 2019 11:05:26 -0300 Subject: [PATCH 66/95] Add async_closure feature gate where needed (#288) --- .travis.yml | 2 +- examples/cors.rs | 2 +- examples/default_headers.rs | 2 +- examples/hello.rs | 2 +- examples/hello_envlog.rs | 2 +- examples/hello_logrs.rs | 2 +- examples/messages.rs | 4 ++-- examples/runtime.rs | 2 +- src/app.rs | 6 +++--- src/lib.rs | 2 +- tests/wildcard.rs | 2 +- tide-cors/src/lib.rs | 4 ++-- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8e56b7e2f..3ce7396a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: rust -rust: nightly-2019-06-02 +rust: nightly-2019-07-08 cache: cargo before_script: diff --git a/examples/cors.rs b/examples/cors.rs index c0c93ddbc..9cabb8efd 100644 --- a/examples/cors.rs +++ b/examples/cors.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, async_closure)] use http::header::HeaderValue; use tide::middleware::CorsMiddleware; diff --git a/examples/default_headers.rs b/examples/default_headers.rs index 70f4a8d54..8b54e6af3 100644 --- a/examples/default_headers.rs +++ b/examples/default_headers.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, async_closure)] use tide::middleware::DefaultHeaders; diff --git a/examples/hello.rs b/examples/hello.rs index edcf106e2..2528188ba 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, async_closure)] fn main() { let mut app = tide::App::new(); app.at("/").get(async move |_| "Hello, world!"); diff --git a/examples/hello_envlog.rs b/examples/hello_envlog.rs index d57a5a4bd..df60bf10b 100644 --- a/examples/hello_envlog.rs +++ b/examples/hello_envlog.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, async_closure)] fn main() { env_logger::from_env(env_logger::Env::default().default_filter_or("info")).init(); let mut app = tide::App::new(); diff --git a/examples/hello_logrs.rs b/examples/hello_logrs.rs index d32f2696e..c21f98627 100644 --- a/examples/hello_logrs.rs +++ b/examples/hello_logrs.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, async_closure)] fn main() { use log::LevelFilter; use log4rs::append::console::ConsoleAppender; diff --git a/examples/messages.rs b/examples/messages.rs index 023528c89..823ff0631 100644 --- a/examples/messages.rs +++ b/examples/messages.rs @@ -51,7 +51,7 @@ async fn set_message(mut cx: Context) -> EndpointResult<()> { if cx.state().set(id, msg) { Ok(()) } else { - Err(StatusCode::NOT_FOUND)? + Err(StatusCode::NOT_FOUND.into()) } } @@ -60,7 +60,7 @@ async fn get_message(cx: Context) -> EndpointResult { if let Some(msg) = cx.state().get(id) { Ok(response::json(msg)) } else { - Err(StatusCode::NOT_FOUND)? + Err(StatusCode::NOT_FOUND.into()) } } diff --git a/examples/runtime.rs b/examples/runtime.rs index e1accc5fd..feb35958e 100644 --- a/examples/runtime.rs +++ b/examples/runtime.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, async_closure)] /// An example of how to run a Tide service on top of `runtime`, this also shows the pieces /// necessary if you wish to run a service on some other executor/IO source. diff --git a/src/app.rs b/src/app.rs index 03f1c5f1a..8ac66d818 100644 --- a/src/app.rs +++ b/src/app.rs @@ -30,7 +30,7 @@ use crate::{ /// on `127.0.0.1:8000` with: /// /// ```rust, no_run -/// #![feature(async_await)] +/// #![feature(async_await, async_closure)] /// /// let mut app = tide::App::new(); /// app.at("/hello").get(async move |_| "Hello, world!"); @@ -45,7 +45,7 @@ use crate::{ /// segments as parameters to endpoints: /// /// ```rust, no_run -/// #![feature(async_await)] +/// #![feature(async_await, async_closure)] /// /// use tide::error::ResultExt; /// @@ -166,7 +166,7 @@ impl App { /// respective endpoint of the selected resource. Example: /// /// ```rust,no_run - /// # #![feature(async_await)] + /// # #![feature(async_await, async_closure)] /// # let mut app = tide::App::new(); /// app.at("/").get(async move |_| "Hello, world!"); /// ``` diff --git a/src/lib.rs b/src/lib.rs index 894515225..eceffdc04 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ #![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] -#![feature(async_await, existential_type)] +#![feature(async_await, async_closure, existential_type)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tests/wildcard.rs b/tests/wildcard.rs index 01c364620..d99576de3 100644 --- a/tests/wildcard.rs +++ b/tests/wildcard.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, async_closure)] use futures::executor::block_on; use http_service::Body; diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs index 9772cbe16..92fe073c4 100644 --- a/tide-cors/src/lib.rs +++ b/tide-cors/src/lib.rs @@ -3,7 +3,7 @@ //! ## Examples //! //! ```rust,no_run -//! #![feature(async_await)] +//! #![feature(async_await, async_closure)] //! //! use http::header::HeaderValue; //! use tide_cors::CorsMiddleware; @@ -30,7 +30,7 @@ //! //! You will probably get a browser alert when running without cors middleware. -#![feature(async_await)] +#![feature(async_await, async_closure)] #![warn( nonstandard_style, rust_2018_idioms, From e63086ab363b86931b91f674bbd2e18faf711b1d Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 15 Jul 2019 18:29:57 +0900 Subject: [PATCH 67/95] Remove usage of async_closure --- README.md | 2 +- examples/cors.rs | 4 ++-- examples/default_headers.rs | 4 ++-- examples/hello.rs | 4 ++-- examples/hello_envlog.rs | 4 ++-- examples/hello_logrs.rs | 4 ++-- examples/runtime.rs | 4 ++-- rfcs/001-app-new.md | 4 ++-- src/app.rs | 42 ++++++++++++++++++------------------- src/lib.rs | 2 +- tests/wildcard.rs | 4 ++-- tide-cors/README.md | 2 +- tide-cors/src/lib.rs | 6 +++--- tide-cors/src/middleware.rs | 2 +- 14 files changed, 44 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index f8297ef00..d57a569f0 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Ecosystem WG, and **not ready for production use yet**. fn main() -> Result<(), std::io::Error> { let mut app = tide::App::new(); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); Ok(app.run("127.0.0.1:8000")?) } ``` diff --git a/examples/cors.rs b/examples/cors.rs index 9cabb8efd..f32afd271 100644 --- a/examples/cors.rs +++ b/examples/cors.rs @@ -1,4 +1,4 @@ -#![feature(async_await, async_closure)] +#![feature(async_await)] use http::header::HeaderValue; use tide::middleware::CorsMiddleware; @@ -12,7 +12,7 @@ fn main() { .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), ); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/default_headers.rs b/examples/default_headers.rs index 8b54e6af3..f4ff40268 100644 --- a/examples/default_headers.rs +++ b/examples/default_headers.rs @@ -1,4 +1,4 @@ -#![feature(async_await, async_closure)] +#![feature(async_await)] use tide::middleware::DefaultHeaders; @@ -11,7 +11,7 @@ fn main() { .header("X-Server", "Tide"), ); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/hello.rs b/examples/hello.rs index 2528188ba..1ceac0961 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,6 +1,6 @@ -#![feature(async_await, async_closure)] +#![feature(async_await)] fn main() { let mut app = tide::App::new(); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/hello_envlog.rs b/examples/hello_envlog.rs index df60bf10b..a96c39bac 100644 --- a/examples/hello_envlog.rs +++ b/examples/hello_envlog.rs @@ -1,8 +1,8 @@ -#![feature(async_await, async_closure)] +#![feature(async_await)] fn main() { env_logger::from_env(env_logger::Env::default().default_filter_or("info")).init(); let mut app = tide::App::new(); app.middleware(tide::middleware::RequestLogger::new()); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/hello_logrs.rs b/examples/hello_logrs.rs index c21f98627..49bf8ac61 100644 --- a/examples/hello_logrs.rs +++ b/examples/hello_logrs.rs @@ -1,4 +1,4 @@ -#![feature(async_await, async_closure)] +#![feature(async_await)] fn main() { use log::LevelFilter; use log4rs::append::console::ConsoleAppender; @@ -13,6 +13,6 @@ fn main() { let mut app = tide::App::new(); app.middleware(tide::middleware::RequestLogger::new()); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.run("127.0.0.1:8000").unwrap(); } diff --git a/examples/runtime.rs b/examples/runtime.rs index feb35958e..034091306 100644 --- a/examples/runtime.rs +++ b/examples/runtime.rs @@ -1,4 +1,4 @@ -#![feature(async_await, async_closure)] +#![feature(async_await)] /// An example of how to run a Tide service on top of `runtime`, this also shows the pieces /// necessary if you wish to run a service on some other executor/IO source. @@ -7,7 +7,7 @@ async fn main() -> Result<(), Box> { // First, we create a simple hello world application let mut app = tide::App::new(); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); // Instead of using `App::run` to start the application, which implicitly uses a default // http-service server, we need to configure a custom server with the executor and IO source we diff --git a/rfcs/001-app-new.md b/rfcs/001-app-new.md index f8cff3830..6e8e30bf6 100644 --- a/rfcs/001-app-new.md +++ b/rfcs/001-app-new.md @@ -52,7 +52,7 @@ __no state__ fn main() -> Result<(), failure::Error> { let mut app = tide::App::new(); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.serve("127.0.0.1:8000")?; } ``` @@ -68,7 +68,7 @@ struct State { fn main() -> Result<(), failure::Error> { let mut app = tide::App::with_state(State::default()); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.serve("127.0.0.1:8000")?; } ``` diff --git a/src/app.rs b/src/app.rs index 8ac66d818..0c6baff94 100644 --- a/src/app.rs +++ b/src/app.rs @@ -30,10 +30,10 @@ use crate::{ /// on `127.0.0.1:8000` with: /// /// ```rust, no_run -/// #![feature(async_await, async_closure)] +/// #![feature(async_await)] /// /// let mut app = tide::App::new(); -/// app.at("/hello").get(async move |_| "Hello, world!"); +/// app.at("/hello").get(|_| async move { "Hello, world!" }); /// app.run("127.0.0.1:8000"); /// ``` /// @@ -45,7 +45,7 @@ use crate::{ /// segments as parameters to endpoints: /// /// ```rust, no_run -/// #![feature(async_await, async_closure)] +/// #![feature(async_await)] /// /// use tide::error::ResultExt; /// @@ -63,7 +63,7 @@ use crate::{ /// /// app.at("/hello/:user").get(hello); /// app.at("/goodbye/:user").get(goodbye); -/// app.at("/").get(async move |_| { +/// app.at("/").get(|_| async move { /// "Use /hello/{your name} or /goodbye/{your name}" /// }); /// @@ -166,9 +166,9 @@ impl App { /// respective endpoint of the selected resource. Example: /// /// ```rust,no_run - /// # #![feature(async_await, async_closure)] + /// # #![feature(async_await)] /// # let mut app = tide::App::new(); - /// app.at("/").get(async move |_| "Hello, world!"); + /// app.at("/").get(|_| async move { "Hello, world!" }); /// ``` /// /// A path is comprised of zero or many segments, i.e. non-empty strings @@ -337,9 +337,9 @@ mod tests { #[test] fn simple_static() { let mut router = App::new(); - router.at("/").get(async move |_| "/"); - router.at("/foo").get(async move |_| "/foo"); - router.at("/foo/bar").get(async move |_| "/foo/bar"); + router.at("/").get(|_| async move { "/" }); + router.at("/foo").get(|_| async move { "/foo" }); + router.at("/foo/bar").get(|_| async move { "/foo/bar" }); for path in &["/", "/foo", "/foo/bar"] { let res = block_on(simulate_request(&router, path, http::Method::GET)); @@ -351,23 +351,23 @@ mod tests { #[test] fn nested_static() { let mut router = App::new(); - router.at("/a").get(async move |_| "/a"); + router.at("/a").get(|_| async move { "/a" }); router.at("/b").nest(|router| { - router.at("/").get(async move |_| "/b"); - router.at("/a").get(async move |_| "/b/a"); - router.at("/b").get(async move |_| "/b/b"); + router.at("/").get(|_| async move { "/b" }); + router.at("/a").get(|_| async move { "/b/a" }); + router.at("/b").get(|_| async move { "/b/b" }); router.at("/c").nest(|router| { - router.at("/a").get(async move |_| "/b/c/a"); - router.at("/b").get(async move |_| "/b/c/b"); + router.at("/a").get(|_| async move { "/b/c/a" }); + router.at("/b").get(|_| async move { "/b/c/b" }); }); - router.at("/d").get(async move |_| "/b/d"); + router.at("/d").get(|_| async move { "/b/d" }); }); router.at("/a/a").nest(|router| { - router.at("/a").get(async move |_| "/a/a/a"); - router.at("/b").get(async move |_| "/a/a/b"); + router.at("/a").get(|_| async move { "/a/a/a" }); + router.at("/b").get(|_| async move { "/a/a/b" }); }); router.at("/a/b").nest(|router| { - router.at("/").get(async move |_| "/a/b"); + router.at("/").get(|_| async move { "/a/b" }); }); for failing_path in &["/", "/a/a", "/a/b/a"] { @@ -393,9 +393,9 @@ mod tests { fn multiple_methods() { let mut router = App::new(); router.at("/a").nest(|router| { - router.at("/b").get(async move |_| "/a/b GET"); + router.at("/b").get(|_| async move { "/a/b GET" }); }); - router.at("/a/b").post(async move |_| "/a/b POST"); + router.at("/a/b").post(|_| async move { "/a/b POST" }); for (path, method) in &[("/a/b", http::Method::GET), ("/a/b", http::Method::POST)] { let res = block_on(simulate_request(&router, path, method.clone())); diff --git a/src/lib.rs b/src/lib.rs index eceffdc04..894515225 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ #![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] -#![feature(async_await, async_closure, existential_type)] +#![feature(async_await, existential_type)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tests/wildcard.rs b/tests/wildcard.rs index d99576de3..02f8330e6 100644 --- a/tests/wildcard.rs +++ b/tests/wildcard.rs @@ -1,4 +1,4 @@ -#![feature(async_await, async_closure)] +#![feature(async_await)] use futures::executor::block_on; use http_service::Body; @@ -169,7 +169,7 @@ fn invalid_wildcard() { #[test] fn nameless_wildcard() { let mut app = tide::App::new(); - app.at("/echo/:").get(async move |_| ""); + app.at("/echo/:").get(|_| async move { "" }); let mut server = make_server(app.into_http_service()).unwrap(); diff --git a/tide-cors/README.md b/tide-cors/README.md index 62be88f93..d59f42d06 100644 --- a/tide-cors/README.md +++ b/tide-cors/README.md @@ -21,7 +21,7 @@ fn main() { .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), ); - app.at("/").get(async move |_| "Hello, world!"); + app.at("/").get(|_| async move { "Hello, world!" }); app.run("127.0.0.1:8000").unwrap(); } diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs index 92fe073c4..b7eaf44a8 100644 --- a/tide-cors/src/lib.rs +++ b/tide-cors/src/lib.rs @@ -3,7 +3,7 @@ //! ## Examples //! //! ```rust,no_run -//! #![feature(async_await, async_closure)] +//! #![feature(async_await)] //! //! use http::header::HeaderValue; //! use tide_cors::CorsMiddleware; @@ -17,7 +17,7 @@ //! .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), //! ); //! -//! app.at("/").get(async move |_| "Hello, world!"); +//! app.at("/").get(|_| async move { "Hello, world!" }); //! //! app.run("127.0.0.1:8000").unwrap(); //! } @@ -30,7 +30,7 @@ //! //! You will probably get a browser alert when running without cors middleware. -#![feature(async_await, async_closure)] +#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs index 52f4d5d76..7027034f0 100644 --- a/tide-cors/src/middleware.rs +++ b/tide-cors/src/middleware.rs @@ -169,7 +169,7 @@ mod test { fn app() -> tide::App<()> { let mut app = tide::App::new(); - app.at(ENDPOINT).get(async move |_| "Hello World"); + app.at(ENDPOINT).get(|_| async move { "Hello World" }); app } From 3eb630f52b6066944fbef3e088715d277cb3af97 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 2 Jul 2019 07:55:44 -0700 Subject: [PATCH 68/95] Set StatusCode for an empty response from `()` to `204` --- tide-cookies/src/middleware.rs | 6 +++--- tide-core/src/response.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tide-cookies/src/middleware.rs b/tide-cookies/src/middleware.rs index b6fd93b2c..3ee13a21c 100644 --- a/tide-cookies/src/middleware.rs +++ b/tide-cookies/src/middleware.rs @@ -133,7 +133,7 @@ mod tests { #[test] fn successfully_set_cookie() { let res = make_request("/set"); - assert_eq!(res.status(), 200); + assert_eq!(res.status(), 204); let test_cookie_header = res.headers().get(http::header::SET_COOKIE).unwrap(); assert_eq!( test_cookie_header.to_str().unwrap(), @@ -144,7 +144,7 @@ mod tests { #[test] fn successfully_remove_cookie() { let res = make_request("/remove"); - assert_eq!(res.status(), 200); + assert_eq!(res.status(), 204); let test_cookie_header = res.headers().get(http::header::SET_COOKIE).unwrap(); assert!(test_cookie_header .to_str() @@ -160,7 +160,7 @@ mod tests { #[test] fn successfully_set_multiple_cookies() { let res = make_request("/multi"); - assert_eq!(res.status(), 200); + assert_eq!(res.status(), 204); let cookie_header = res.headers().get_all(http::header::SET_COOKIE); let mut iter = cookie_header.iter(); diff --git a/tide-core/src/response.rs b/tide-core/src/response.rs index f93c05855..1853afdb3 100644 --- a/tide-core/src/response.rs +++ b/tide-core/src/response.rs @@ -38,7 +38,7 @@ pub trait IntoResponse: Send + Sized { impl IntoResponse for () { fn into_response(self) -> Response { http::Response::builder() - .status(http::status::StatusCode::OK) + .status(http::status::StatusCode::NO_CONTENT) .body(Body::empty()) .unwrap() } From 7e2adb3b99e2b9c9fa09a742f5b855256921878f Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Thu, 18 Jul 2019 07:37:34 +0200 Subject: [PATCH 69/95] Add doc example showing query parameter extraction --- tide-querystring/src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tide-querystring/src/lib.rs b/tide-querystring/src/lib.rs index 17a1795a2..67208431a 100644 --- a/tide-querystring/src/lib.rs +++ b/tide-querystring/src/lib.rs @@ -14,6 +14,23 @@ use serde::Deserialize; use tide_core::{error::Error, Context}; /// An extension trait for `Context`, providing query string deserialization. +/// +/// # Example +/// +/// Turning the query parameters into a `HashMap`: +/// +/// ``` +/// #![feature(async_await)] +/// +/// # use std::collections::HashMap; +/// use tide::querystring::ContextExt; +/// +/// let mut app = tide::App::new(); +/// app.at("/").get(|cx: tide::Context<()>| async move { +/// let map: HashMap = cx.url_query().unwrap(); +/// format!("{:?}", map) +/// }); +/// ``` pub trait ContextExt<'de> { /// Analyze url and extract query parameters fn url_query>(&'de self) -> Result; From b77a242531ab60154aecb5589f969617f6810785 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2019 05:59:39 +0000 Subject: [PATCH 70/95] Update juniper requirement from 0.12.0 to 0.13.0 Updates the requirements on [juniper](https://github.com/graphql-rust/juniper) to permit the latest version. - [Release notes](https://github.com/graphql-rust/juniper/releases) - [Commits](https://github.com/graphql-rust/juniper/commits) Signed-off-by: dependabot-preview[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 834121f84..d489950ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ env_logger = "0.6.1" futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.17", features = ["compat"] } http-service-mock = "0.2.0" -juniper = "0.12.0" +juniper = "0.13.0" log = "0.4.6" log4rs = "0.8.3" mime = "0.3.13" From 9a9b10a6fa7ad3aebbebd7a2404ac4ddc4c17ab7 Mon Sep 17 00:00:00 2001 From: nasa Date: Mon, 22 Jul 2019 18:54:05 +0900 Subject: [PATCH 71/95] Cors middleware extension (#275) * feat: Add AllowOrigin enum * fix build_preflight_request * feat: Add to handle origin method * feat: Add origin validation * test: Add test code * refactor: Rename AllowOrigin to CorsOrigin * refactor: cargo fmt + fix clippy * Update tide-cors/src/middleware.rs Co-Authored-By: Yoshua Wuyts * Update tide-cors/src/middleware.rs Co-Authored-By: Yoshua Wuyts --- examples/cors.rs | 4 +- src/lib.rs | 2 +- tide-cors/src/lib.rs | 6 +- tide-cors/src/middleware.rs | 166 +++++++++++++++++++++++++++++++++--- 4 files changed, 158 insertions(+), 20 deletions(-) diff --git a/examples/cors.rs b/examples/cors.rs index f32afd271..a62fc0450 100644 --- a/examples/cors.rs +++ b/examples/cors.rs @@ -1,14 +1,14 @@ #![feature(async_await)] use http::header::HeaderValue; -use tide::middleware::CorsMiddleware; +use tide::middleware::{CorsMiddleware, CorsOrigin}; fn main() { let mut app = tide::App::new(); app.middleware( CorsMiddleware::new() - .allow_origin(HeaderValue::from_static("*")) + .allow_origin(CorsOrigin::from("*")) .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), ); diff --git a/src/lib.rs b/src/lib.rs index 894515225..713c99778 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ pub mod middleware { pub use tide_log::RequestLogger; #[cfg(feature = "cors")] - pub use tide_cors::CorsMiddleware; + pub use tide_cors::{CorsMiddleware, CorsOrigin}; #[cfg(feature = "cookies")] pub use tide_cookies::CookiesMiddleware; diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs index b7eaf44a8..17356897a 100644 --- a/tide-cors/src/lib.rs +++ b/tide-cors/src/lib.rs @@ -6,14 +6,14 @@ //! #![feature(async_await)] //! //! use http::header::HeaderValue; -//! use tide_cors::CorsMiddleware; +//! use tide::middleware::{CorsMiddleware, CorsOrigin}; //! //! fn main() { //! let mut app = tide::App::new(); //! //! app.middleware( //! CorsMiddleware::new() -//! .allow_origin(HeaderValue::from_static("*")) +//! .allow_origin(CorsOrigin::from("*")) //! .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")), //! ); //! @@ -41,4 +41,4 @@ mod middleware; -pub use self::middleware::CorsMiddleware; +pub use self::middleware::{CorsMiddleware, CorsOrigin}; diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs index 7027034f0..2b979564e 100644 --- a/tide-cors/src/middleware.rs +++ b/tide-cors/src/middleware.rs @@ -16,10 +16,10 @@ use tide_core::{ /// /// ```rust ///use http::header::HeaderValue; -///use tide_cors::CorsMiddleware; +///use tide::middleware::{CorsOrigin, CorsMiddleware}; /// ///CorsMiddleware::new() -/// .allow_origin(HeaderValue::from_static("*")) +/// .allow_origin(CorsOrigin::from("*")) /// .allow_methods(HeaderValue::from_static("GET, POST, OPTIONS")) /// .allow_credentials(false); /// ``` @@ -28,11 +28,53 @@ pub struct CorsMiddleware { allow_credentials: Option, allow_headers: HeaderValue, allow_methods: HeaderValue, - allow_origin: HeaderValue, + allow_origin: CorsOrigin, expose_headers: Option, max_age: HeaderValue, } +/// allow_origin enum +#[derive(Clone, Debug, Hash, PartialEq)] +pub enum CorsOrigin { + /// Wildcard. Accept all origin requests + Any, + /// Set a single allow_origin target + Exact(String), + /// Set multiple allow_origin targets + List(Vec), +} + +impl From for CorsOrigin { + fn from(s: String) -> Self { + if s == "*" { + return CorsOrigin::Any; + } + CorsOrigin::Exact(s) + } +} + +impl From<&str> for CorsOrigin { + fn from(s: &str) -> Self { + CorsOrigin::from(s.to_string()) + } +} + +impl From> for CorsOrigin { + fn from(list: Vec) -> Self { + if list.len() == 1 { + return Self::from(list[0].clone()); + } + + CorsOrigin::List(list) + } +} + +impl From> for CorsOrigin { + fn from(list: Vec<&str>) -> Self { + CorsOrigin::from(list.iter().map(|s| s.to_string()).collect::>()) + } +} + pub const DEFAULT_MAX_AGE: &str = "86400"; pub const DEFAULT_METHODS: &str = "GET, POST, OPTIONS"; pub const WILDCARD: &str = "*"; @@ -44,7 +86,7 @@ impl CorsMiddleware { allow_credentials: None, allow_headers: HeaderValue::from_static(WILDCARD), allow_methods: HeaderValue::from_static(DEFAULT_METHODS), - allow_origin: HeaderValue::from_static(WILDCARD), + allow_origin: CorsOrigin::Any, expose_headers: None, max_age: HeaderValue::from_static(DEFAULT_MAX_AGE), } @@ -78,7 +120,7 @@ impl CorsMiddleware { } /// Set allow_origin and return new CorsMiddleware - pub fn allow_origin>(mut self, origin: T) -> Self { + pub fn allow_origin>(mut self, origin: T) -> Self { self.allow_origin = origin.into(); self } @@ -89,13 +131,10 @@ impl CorsMiddleware { self } - fn build_preflight_response(&self) -> http::response::Response { + fn build_preflight_response(&self, origin: &HeaderValue) -> http::response::Response { let mut response = http::Response::builder() .status(StatusCode::OK) - .header( - header::ACCESS_CONTROL_ALLOW_ORIGIN, - self.allow_origin.clone(), - ) + .header::<_, HeaderValue>(header::ACCESS_CONTROL_ALLOW_ORIGIN, origin.clone()) .header( header::ACCESS_CONTROL_ALLOW_METHODS, self.allow_methods.clone(), @@ -122,14 +161,57 @@ impl CorsMiddleware { response } + + /// Look at origin of request and determine allow_origin + fn response_origin>(&self, origin: T) -> Option { + let origin = origin.into(); + if !self.is_valid_origin(origin.clone()) { + return None; + } + + match self.allow_origin { + CorsOrigin::Any => Some(HeaderValue::from_static(WILDCARD)), + _ => Some(origin), + } + } + + /// Determine if origin is appropriate + fn is_valid_origin>(&self, origin: T) -> bool { + let origin = match origin.into().to_str() { + Ok(s) => s.to_string(), + Err(_) => return false, + }; + + match &self.allow_origin { + CorsOrigin::Any => true, + CorsOrigin::Exact(s) => s == &origin, + CorsOrigin::List(list) => list.contains(&origin), + } + } } impl Middleware for CorsMiddleware { fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { Box::pin(async move { + let origin = if let Some(origin) = cx.request().headers().get(header::ORIGIN) { + origin.clone() + } else { + return http::Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Body::empty()) + .unwrap(); + }; + + if !self.is_valid_origin(&origin) { + return http::Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body(Body::empty()) + .unwrap(); + } + // Return results immediately upon preflight request if cx.method() == Method::OPTIONS { - return self.build_preflight_response(); + return self.build_preflight_response(&origin); } let mut response = next.run(cx).await; @@ -137,7 +219,7 @@ impl Middleware for CorsMiddleware { headers.append( header::ACCESS_CONTROL_ALLOW_ORIGIN, - self.allow_origin.clone(), + self.response_origin(origin).unwrap(), ); if let Some(allow_credentials) = self.allow_credentials.clone() { @@ -187,7 +269,7 @@ mod test { let mut app = app(); app.middleware( CorsMiddleware::new() - .allow_origin(HeaderValue::from_static(ALLOW_ORIGIN)) + .allow_origin(CorsOrigin::from(ALLOW_ORIGIN)) .allow_methods(HeaderValue::from_static(ALLOW_METHODS)) .expose_headers(HeaderValue::from_static(EXPOSE_HEADER)) .allow_credentials(true), @@ -250,7 +332,7 @@ mod test { let mut app = app(); app.middleware( CorsMiddleware::new() - .allow_origin(HeaderValue::from_static(ALLOW_ORIGIN)) + .allow_origin(CorsOrigin::from(ALLOW_ORIGIN)) .allow_credentials(false) .allow_methods(HeaderValue::from_static(ALLOW_METHODS)) .expose_headers(HeaderValue::from_static(EXPOSE_HEADER)), @@ -282,4 +364,60 @@ mod test { "true" ); } + #[test] + fn set_allow_origin_list() { + let mut app = app(); + let origins = vec![ALLOW_ORIGIN, "foo.com", "bar.com"]; + app.middleware(CorsMiddleware::new().allow_origin(origins.clone())); + let mut server = make_server(app.into_http_service()).unwrap(); + + for origin in origins { + let request = http::Request::get(ENDPOINT) + .header(http::header::ORIGIN, origin) + .method(http::method::Method::GET) + .body(Body::empty()) + .unwrap(); + + let res = server.simulate(request).unwrap(); + + assert_eq!(res.status(), 200); + assert_eq!( + res.headers().get("access-control-allow-origin").unwrap(), + origin + ); + } + } + + #[test] + fn not_set_origin_header() { + let mut app = app(); + app.middleware(CorsMiddleware::new()); + + let request = http::Request::get(ENDPOINT) + .method(http::method::Method::GET) + .body(Body::empty()) + .unwrap(); + + let mut server = make_server(app.into_http_service()).unwrap(); + let res = server.simulate(request).unwrap(); + + assert_eq!(res.status(), 400); + } + + #[test] + fn unauthorized_origin() { + let mut app = app(); + app.middleware(CorsMiddleware::new().allow_origin(ALLOW_ORIGIN)); + + let request = http::Request::get(ENDPOINT) + .header(http::header::ORIGIN, "unauthorize-origin.net") + .method(http::method::Method::GET) + .body(Body::empty()) + .unwrap(); + + let mut server = make_server(app.into_http_service()).unwrap(); + let res = server.simulate(request).unwrap(); + + assert_eq!(res.status(), 401); + } } From 3a7601f8a4e1fd171f26114a51d1e852d088adb7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2019 05:32:11 +0000 Subject: [PATCH 72/95] Update percent-encoding requirement from 1.0.1 to 2.0.0 Updates the requirements on [percent-encoding](https://github.com/servo/rust-url) to permit the latest version. - [Release notes](https://github.com/servo/rust-url/releases) - [Commits](https://github.com/servo/rust-url/compare/percent-encoding-v1.0.1...percent-encoding-v2.0.0) Signed-off-by: dependabot-preview[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d489950ae..2033075dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ log = "0.4.6" log4rs = "0.8.3" mime = "0.3.13" mime_guess = "2.0.0-alpha.6" -percent-encoding = "1.0.1" +percent-encoding = "2.0.0" serde = { version = "1.0.91", features = ["derive"] } tera = "0.11" runtime = "0.3.0-alpha.6" From dfef176a1a0d20a72629bb92bf86820f75ac56e6 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Fri, 26 Jul 2019 16:04:57 +0200 Subject: [PATCH 73/95] remove http-service patches (#297) * remove http-service patches Signed-off-by: Yoshua Wuyts * try fix build Signed-off-by: Yoshua Wuyts --- .travis.yml | 1 - Cargo.toml | 11 +++-------- tide-compression/Cargo.toml | 4 ++-- tide-cookies/Cargo.toml | 4 ++-- tide-core/Cargo.toml | 2 +- tide-cors/Cargo.toml | 4 ++-- tide-forms/Cargo.toml | 2 +- tide-querystring/Cargo.toml | 5 ++--- 8 files changed, 13 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3ce7396a8..59c9c9586 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: rust rust: nightly-2019-07-08 -cache: cargo before_script: - > diff --git a/Cargo.toml b/Cargo.toml index 2033075dc..92f137689 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,8 +27,8 @@ hyper = ["http-service-hyper"] [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.2.0" -http-service-hyper = { version = "0.2.0", optional = true } +http-service = "0.3.0" +http-service-hyper = { version = "0.4.0", optional = true } # Routing fnv = "1.0.6" route-recognizer = "0.1.12" @@ -47,7 +47,7 @@ cookie = { version = "0.12", features = ["percent-encode"] } env_logger = "0.6.1" futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.17", features = ["compat"] } -http-service-mock = "0.2.0" +http-service-mock = "0.3.0" juniper = "0.13.0" log = "0.4.6" log4rs = "0.8.3" @@ -73,8 +73,3 @@ members = [ "tide-querystring", "tide-slog", ] - -[patch.crates-io] -http-service = { git = "https://github.com/rustasync/http-service", branch = "master" } -http-service-hyper = { git = "https://github.com/rustasync/http-service", branch = "master" } -http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "master" } diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml index ea9fbac65..4e701c48f 100644 --- a/tide-compression/Cargo.toml +++ b/tide-compression/Cargo.toml @@ -19,7 +19,7 @@ accept-encoding = "0.2.0-alpha.2" bytes = "0.4.12" futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.2.0" +http-service = "0.3.0" [dependencies.async-compression] default-features = false @@ -28,4 +28,4 @@ version = "0.1.0-alpha.1" [dev-dependencies] tide = { path = "../", default-features = false } -http-service-mock = "0.2.0" +http-service-mock = "0.3.0" diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index 6263cd801..e18553183 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -14,9 +14,9 @@ repository = "https://github.com/rustasync/tide" cookie = { version = "0.12", features = ["percent-encode"] } futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.2.0" +http-service = "0.3.0" tide-core = { path = "../tide-core", default-features = false } [dev-dependencies] tide = { path = "../", default-features = false } -http-service-mock = "0.2.0" +http-service-mock = "0.3.0" diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index 5e716352d..c5dde08fd 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/rustasync/tide" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.2.0" +http-service = "0.3.0" serde = "1.0.91" serde_json = "1.0.39" route-recognizer = "0.1.12" diff --git a/tide-cors/Cargo.toml b/tide-cors/Cargo.toml index a917181e6..ed774dfff 100644 --- a/tide-cors/Cargo.toml +++ b/tide-cors/Cargo.toml @@ -16,9 +16,9 @@ edition = "2018" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.2.0" +http-service = "0.3.0" tide-core = { path = "../tide-core" } [dev-dependencies] tide = { path = "../" } -http-service-mock = "0.2.0" +http-service-mock = "0.3.0" diff --git a/tide-forms/Cargo.toml b/tide-forms/Cargo.toml index 2eb066141..cc7f15c97 100644 --- a/tide-forms/Cargo.toml +++ b/tide-forms/Cargo.toml @@ -18,7 +18,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -http-service = "0.2.0" +http-service = "0.3.0" futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index 25e5044c7..ee0366e88 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -26,6 +26,5 @@ serde_urlencoded = "0.5.5" [dev-dependencies] tide = { path = "../", default-features = false } -http-service = "0.2.0" -http-service-mock = "0.2.0" - +http-service = "0.3.0" +http-service-mock = "0.3.0" From 738c8705ba7cac066884119d494354e198a3ad4c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2019 05:43:37 +0000 Subject: [PATCH 74/95] Update serde_urlencoded requirement from 0.5.5 to 0.6.0 Updates the requirements on [serde_urlencoded](https://github.com/nox/serde_urlencoded) to permit the latest version. - [Release notes](https://github.com/nox/serde_urlencoded/releases) - [Commits](https://github.com/nox/serde_urlencoded/compare/v0.5.5...v0.6.0) Signed-off-by: dependabot-preview[bot] --- tide-forms/Cargo.toml | 2 +- tide-querystring/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tide-forms/Cargo.toml b/tide-forms/Cargo.toml index cc7f15c97..cd2ca5349 100644 --- a/tide-forms/Cargo.toml +++ b/tide-forms/Cargo.toml @@ -24,7 +24,7 @@ http = "0.1" log = "0.4.6" multipart = { version = "0.16.1", features = ["server"], default-features = false } serde = { version = "1.0.91", features = ["derive"] } -serde_urlencoded = "0.5.5" +serde_urlencoded = "0.6.0" [dev-dependencies] tide = { path = "../", default-features = false } diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index ee0366e88..8fedfedce 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -22,7 +22,7 @@ futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" serde = { version = "1.0.91", features = ["derive"] } -serde_urlencoded = "0.5.5" +serde_urlencoded = "0.6.0" [dev-dependencies] tide = { path = "../", default-features = false } From dd0bcfe9b0e83e7f6b924797ef254fa5882e0cc3 Mon Sep 17 00:00:00 2001 From: Nicholas Young Date: Mon, 5 Aug 2019 09:29:26 -0600 Subject: [PATCH 75/95] querystring: replace dependency serde_urlencoded with serde_qs (#299) --- tide-querystring/Cargo.toml | 2 +- tide-querystring/src/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index 8fedfedce..f59f2f6e0 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -22,7 +22,7 @@ futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" serde = { version = "1.0.91", features = ["derive"] } -serde_urlencoded = "0.6.0" +serde_qs = "0.5.0" [dev-dependencies] tide = { path = "../", default-features = false } diff --git a/tide-querystring/src/lib.rs b/tide-querystring/src/lib.rs index 67208431a..409217700 100644 --- a/tide-querystring/src/lib.rs +++ b/tide-querystring/src/lib.rs @@ -42,8 +42,7 @@ impl<'de, State> ContextExt<'de> for Context { if query.is_none() { return Err(Error::from(StatusCode::BAD_REQUEST)); } - Ok(serde_urlencoded::from_str(query.unwrap()) - .map_err(|_| Error::from(StatusCode::BAD_REQUEST))?) + Ok(serde_qs::from_str(query.unwrap()).map_err(|_| Error::from(StatusCode::BAD_REQUEST))?) } } From 7dfb4b89c30628c000251a3e3241ea1959e6bf0f Mon Sep 17 00:00:00 2001 From: Damir Vandic Date: Fri, 9 Aug 2019 20:00:52 +0200 Subject: [PATCH 76/95] Fix clippy error in static file example --- examples/staticfile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/staticfile.rs b/examples/staticfile.rs index d712aceb8..c1040887b 100644 --- a/examples/staticfile.rs +++ b/examples/staticfile.rs @@ -68,7 +68,7 @@ impl StaticFile { } }; - let mime = mime_guess::guess_mime_type(path); + let mime = mime_guess::from_path(path).first_or_octet_stream(); let mime_str = mime.as_ref(); let size = meta.len(); From 702e0f43e6af8bc18a6d75006c2e624c5d341e37 Mon Sep 17 00:00:00 2001 From: ibaryshnikov Date: Fri, 9 Aug 2019 16:33:42 +0300 Subject: [PATCH 77/95] removed existential_type feature --- src/lib.rs | 2 +- tide-core/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 713c99778..ebb0e72bd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ #![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] -#![feature(async_await, existential_type)] +#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index e1ee54c66..b61097996 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -1,6 +1,6 @@ //! Core types and traits from Tide -#![feature(async_await, existential_type)] +#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, From a407732f12716eb6c71355c775d2e6b5c625d3a7 Mon Sep 17 00:00:00 2001 From: ibaryshnikov Date: Tue, 13 Aug 2019 03:55:13 +0300 Subject: [PATCH 78/95] updated route-recognizer to 0.1.13 --- Cargo.toml | 2 +- tide-core/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 92f137689..a545e934a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ http-service = "0.3.0" http-service-hyper = { version = "0.4.0", optional = true } # Routing fnv = "1.0.6" -route-recognizer = "0.1.12" +route-recognizer = "0.1.13" # Tide components tide-cookies = { path = "./tide-cookies", optional = true, default-features = false } tide-cors = { path = "./tide-cors", optional = true, default-features = false } diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index c5dde08fd..fc077a80c 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -16,7 +16,7 @@ http = "0.1" http-service = "0.3.0" serde = "1.0.91" serde_json = "1.0.39" -route-recognizer = "0.1.12" +route-recognizer = "0.1.13" [dev-dependencies] tide = { path = "../", default-features = false } From 25581ae660dc8cc5059f72f0fa2e3be0aaa7f6f0 Mon Sep 17 00:00:00 2001 From: ibaryshnikov Date: Fri, 16 Aug 2019 16:32:04 +0300 Subject: [PATCH 79/95] added patch.crates-io for runtime --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index a545e934a..46f7db41e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,3 +73,7 @@ members = [ "tide-querystring", "tide-slog", ] + +[patch.crates-io.runtime] +git = "https://github.com/rustasync/runtime" +rev = "f5ac4fb" From c815f72a5a9a17626535186f261205028f63511d Mon Sep 17 00:00:00 2001 From: ibaryshnikov Date: Fri, 16 Aug 2019 16:57:08 +0300 Subject: [PATCH 80/95] updated toolchain to nightly-2019-07-29 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 59c9c9586..dc1fc8eee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: rust -rust: nightly-2019-07-08 +rust: nightly-2019-07-29 before_script: - > From cd201eb536a8e8d5fe7d34b78e373a49104519f3 Mon Sep 17 00:00:00 2001 From: ibaryshnikov Date: Fri, 16 Aug 2019 17:07:55 +0300 Subject: [PATCH 81/95] updated toolchain to nightly-2019-07-31 because of missing rustfmt --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dc1fc8eee..6ea64efe2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: rust -rust: nightly-2019-07-29 +rust: nightly-2019-07-31 before_script: - > From 369faffe66b7fa3d789f094319839e8effe02040 Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Wed, 21 Aug 2019 11:27:38 +0200 Subject: [PATCH 82/95] Fix tide-slog docs.rs metadata --- tide-slog/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index 126ab08c0..4539acac3 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -17,7 +17,7 @@ version = "0.1.0" [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg docrs"] +rustdoc-args = ["--cfg", "docrs"] [features] scope = ["slog-scope", "slog-scope-futures"] From 23b8719d05228a91647b200666b8e07589d9d11e Mon Sep 17 00:00:00 2001 From: Nicholas Young Date: Wed, 21 Aug 2019 09:21:22 -0600 Subject: [PATCH 83/95] Upgrade mime_guess to version 2.0.1 (#308) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 46f7db41e..6aecfc3e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ juniper = "0.13.0" log = "0.4.6" log4rs = "0.8.3" mime = "0.3.13" -mime_guess = "2.0.0-alpha.6" +mime_guess = "2.0.1" percent-encoding = "2.0.0" serde = { version = "1.0.91", features = ["derive"] } tera = "0.11" From 958f2a73a63f29c9ea9aa260507eed74c6b9d0b6 Mon Sep 17 00:00:00 2001 From: Artem Vorotnikov Date: Wed, 21 Aug 2019 18:30:58 +0300 Subject: [PATCH 84/95] Bump http-service dependency in tide-panic, set CI to nightly-2019-08-21, remove async_await feature flag everywhere (#309) --- .travis.yml | 2 +- Cargo.toml | 6 +++--- README.md | 2 -- examples/body_types.rs | 1 - examples/catch_all.rs | 1 - examples/cookies.rs | 1 - examples/cors.rs | 2 -- examples/default_headers.rs | 2 -- examples/graphql.rs | 1 - examples/hello.rs | 1 - examples/hello_envlog.rs | 1 - examples/hello_logrs.rs | 1 - examples/messages.rs | 2 -- examples/multipart_form/mod.rs | 1 - examples/runtime.rs | 2 -- examples/staticfile.rs | 2 -- examples/templating_tera.rs | 2 -- rfcs/001-app-new.md | 4 ---- src/app.rs | 7 ------- src/lib.rs | 1 - tests/head_response_empty_body.rs | 2 -- tests/wildcard.rs | 2 -- tide-compression/Cargo.toml | 4 ++-- tide-compression/examples/simple.rs | 1 - tide-compression/src/lib.rs | 1 - tide-cookies/Cargo.toml | 4 ++-- tide-cookies/src/lib.rs | 1 - tide-core/Cargo.toml | 2 +- tide-core/src/endpoint.rs | 5 +---- tide-core/src/lib.rs | 1 - tide-cors/Cargo.toml | 4 ++-- tide-cors/README.md | 2 -- tide-cors/src/lib.rs | 3 --- tide-forms/Cargo.toml | 2 +- tide-forms/src/lib.rs | 1 - tide-headers/src/lib.rs | 1 - tide-log/src/lib.rs | 1 - tide-panic/Cargo.toml | 2 +- tide-panic/src/lib.rs | 2 +- tide-querystring/Cargo.toml | 4 ++-- tide-querystring/src/lib.rs | 3 --- tide-slog/src/lib.rs | 1 - 42 files changed, 17 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ea64efe2..c4a55e0ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: rust -rust: nightly-2019-07-31 +rust: nightly-2019-08-21 before_script: - > diff --git a/Cargo.toml b/Cargo.toml index 6aecfc3e8..aece7a07d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,8 +27,8 @@ hyper = ["http-service-hyper"] [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.3.0" -http-service-hyper = { version = "0.4.0", optional = true } +http-service = "0.3.1" +http-service-hyper = { version = "0.3.1", optional = true } # Routing fnv = "1.0.6" route-recognizer = "0.1.13" @@ -47,7 +47,7 @@ cookie = { version = "0.12", features = ["percent-encode"] } env_logger = "0.6.1" futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.17", features = ["compat"] } -http-service-mock = "0.3.0" +http-service-mock = "0.3.1" juniper = "0.13.0" log = "0.4.6" log4rs = "0.8.3" diff --git a/README.md b/README.md index d57a569f0..728baedc1 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,6 @@ Ecosystem WG, and **not ready for production use yet**. **Hello World** ```rust,no_run -#![feature(async_await)] - fn main() -> Result<(), std::io::Error> { let mut app = tide::App::new(); app.at("/").get(|_| async move { "Hello, world!" }); diff --git a/examples/body_types.rs b/examples/body_types.rs index 18269bfb0..999f5859b 100644 --- a/examples/body_types.rs +++ b/examples/body_types.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] use serde::{Deserialize, Serialize}; use tide::{ error::ResultExt, diff --git a/examples/catch_all.rs b/examples/catch_all.rs index 7ff1980d5..bfb864d6f 100644 --- a/examples/catch_all.rs +++ b/examples/catch_all.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] use tide::Context; async fn echo_path(cx: Context<()>) -> String { diff --git a/examples/cookies.rs b/examples/cookies.rs index 92820e6a8..3dd07a054 100644 --- a/examples/cookies.rs +++ b/examples/cookies.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] use cookie::Cookie; use tide::{cookies::ContextExt, middleware::CookiesMiddleware, Context}; diff --git a/examples/cors.rs b/examples/cors.rs index a62fc0450..0393fdd65 100644 --- a/examples/cors.rs +++ b/examples/cors.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use http::header::HeaderValue; use tide::middleware::{CorsMiddleware, CorsOrigin}; diff --git a/examples/default_headers.rs b/examples/default_headers.rs index f4ff40268..48374035f 100644 --- a/examples/default_headers.rs +++ b/examples/default_headers.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use tide::middleware::DefaultHeaders; fn main() { diff --git a/examples/graphql.rs b/examples/graphql.rs index f79527c12..23c4792de 100644 --- a/examples/graphql.rs +++ b/examples/graphql.rs @@ -2,7 +2,6 @@ // a look at [the Juniper book]. // // [the Juniper book]: https://graphql-rust.github.io/ -#![feature(async_await)] use http::status::StatusCode; use juniper::graphql_object; use std::sync::{atomic, Arc}; diff --git a/examples/hello.rs b/examples/hello.rs index 1ceac0961..061bee0eb 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] fn main() { let mut app = tide::App::new(); app.at("/").get(|_| async move { "Hello, world!" }); diff --git a/examples/hello_envlog.rs b/examples/hello_envlog.rs index a96c39bac..da44e0e83 100644 --- a/examples/hello_envlog.rs +++ b/examples/hello_envlog.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] fn main() { env_logger::from_env(env_logger::Env::default().default_filter_or("info")).init(); let mut app = tide::App::new(); diff --git a/examples/hello_logrs.rs b/examples/hello_logrs.rs index 49bf8ac61..87bc1b5a9 100644 --- a/examples/hello_logrs.rs +++ b/examples/hello_logrs.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] fn main() { use log::LevelFilter; use log4rs::append::console::ConsoleAppender; diff --git a/examples/messages.rs b/examples/messages.rs index 823ff0631..10b047ae4 100644 --- a/examples/messages.rs +++ b/examples/messages.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use http::status::StatusCode; use serde::{Deserialize, Serialize}; use std::sync::Mutex; diff --git a/examples/multipart_form/mod.rs b/examples/multipart_form/mod.rs index 0abef7c48..bf6acc4a4 100644 --- a/examples/multipart_form/mod.rs +++ b/examples/multipart_form/mod.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] use serde::{Deserialize, Serialize}; use std::io::Read; use tide::{forms::ContextExt, response, App, Context, EndpointResult}; diff --git a/examples/runtime.rs b/examples/runtime.rs index 034091306..fa8d2f95e 100644 --- a/examples/runtime.rs +++ b/examples/runtime.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - /// An example of how to run a Tide service on top of `runtime`, this also shows the pieces /// necessary if you wish to run a service on some other executor/IO source. diff --git a/examples/staticfile.rs b/examples/staticfile.rs index c1040887b..26b311e60 100644 --- a/examples/staticfile.rs +++ b/examples/staticfile.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use bytes::Bytes; use futures_fs::FsPool; use futures_util::compat::*; diff --git a/examples/templating_tera.rs b/examples/templating_tera.rs index 442d9ae3f..aae1c37b4 100644 --- a/examples/templating_tera.rs +++ b/examples/templating_tera.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use tera::{self, compile_templates}; use tide::{self, App, Context, EndpointResult, Error}; diff --git a/rfcs/001-app-new.md b/rfcs/001-app-new.md index 6e8e30bf6..c19c24b48 100644 --- a/rfcs/001-app-new.md +++ b/rfcs/001-app-new.md @@ -48,8 +48,6 @@ renamed to `Context::state`. __no state__ ```rust -#![feature(async_await)] - fn main() -> Result<(), failure::Error> { let mut app = tide::App::new(); app.at("/").get(|_| async move { "Hello, world!" }); @@ -59,8 +57,6 @@ fn main() -> Result<(), failure::Error> { __with state__ ```rust -#![feature(async_await)] - #[derive(Default)] struct State { /* db connection goes here */ diff --git a/src/app.rs b/src/app.rs index 0c6baff94..83914b379 100644 --- a/src/app.rs +++ b/src/app.rs @@ -30,8 +30,6 @@ use crate::{ /// on `127.0.0.1:8000` with: /// /// ```rust, no_run -/// #![feature(async_await)] -/// /// let mut app = tide::App::new(); /// app.at("/hello").get(|_| async move { "Hello, world!" }); /// app.run("127.0.0.1:8000"); @@ -45,8 +43,6 @@ use crate::{ /// segments as parameters to endpoints: /// /// ```rust, no_run -/// #![feature(async_await)] -/// /// use tide::error::ResultExt; /// /// async fn hello(cx: tide::Context<()>) -> tide::EndpointResult { @@ -75,8 +71,6 @@ use crate::{ /// # Application state /// /// ```rust, no_run -/// #![feature(async_await)] -/// /// use http::status::StatusCode; /// use serde::{Deserialize, Serialize}; /// use std::sync::Mutex; @@ -166,7 +160,6 @@ impl App { /// respective endpoint of the selected resource. Example: /// /// ```rust,no_run - /// # #![feature(async_await)] /// # let mut app = tide::App::new(); /// app.at("/").get(|_| async move { "Hello, world!" }); /// ``` diff --git a/src/lib.rs b/src/lib.rs index ebb0e72bd..a60d9b2f5 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ #![cfg_attr(any(feature = "nightly", test), feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tests/head_response_empty_body.rs b/tests/head_response_empty_body.rs index 40dfc414b..4db3ddd31 100644 --- a/tests/head_response_empty_body.rs +++ b/tests/head_response_empty_body.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use futures::executor::block_on; use http_service::Body; use http_service_mock::make_server; diff --git a/tests/wildcard.rs b/tests/wildcard.rs index 02f8330e6..be5119d4d 100644 --- a/tests/wildcard.rs +++ b/tests/wildcard.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use futures::executor::block_on; use http_service::Body; use http_service_mock::make_server; diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml index 4e701c48f..12b194265 100644 --- a/tide-compression/Cargo.toml +++ b/tide-compression/Cargo.toml @@ -19,7 +19,7 @@ accept-encoding = "0.2.0-alpha.2" bytes = "0.4.12" futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.3.0" +http-service = "0.3.1" [dependencies.async-compression] default-features = false @@ -28,4 +28,4 @@ version = "0.1.0-alpha.1" [dev-dependencies] tide = { path = "../", default-features = false } -http-service-mock = "0.3.0" +http-service-mock = "0.3.1" diff --git a/tide-compression/examples/simple.rs b/tide-compression/examples/simple.rs index 73484eac0..8a9849d39 100644 --- a/tide-compression/examples/simple.rs +++ b/tide-compression/examples/simple.rs @@ -1,4 +1,3 @@ -#![feature(async_await)] use tide::{App, Context}; use tide_compression::{Compression, Decompression, Encoding}; diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 326d6e0da..18ba3c9a5 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -3,7 +3,6 @@ #![cfg_attr(feature = "nightly", feature(external_doc))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))] -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index e18553183..a6a28325d 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -14,9 +14,9 @@ repository = "https://github.com/rustasync/tide" cookie = { version = "0.12", features = ["percent-encode"] } futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.3.0" +http-service = "0.3.1" tide-core = { path = "../tide-core", default-features = false } [dev-dependencies] tide = { path = "../", default-features = false } -http-service-mock = "0.3.0" +http-service-mock = "0.3.1" diff --git a/tide-cookies/src/lib.rs b/tide-cookies/src/lib.rs index 18645641d..0d4130e74 100644 --- a/tide-cookies/src/lib.rs +++ b/tide-cookies/src/lib.rs @@ -1,7 +1,6 @@ //! Crate that provides helpers and/or middlewares for Tide //! related to cookies. -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index fc077a80c..e27d17d01 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/rustasync/tide" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.3.0" +http-service = "0.3.1" serde = "1.0.91" serde_json = "1.0.39" route-recognizer = "0.1.13" diff --git a/tide-core/src/endpoint.rs b/tide-core/src/endpoint.rs index d4381db73..dca8afd79 100644 --- a/tide-core/src/endpoint.rs +++ b/tide-core/src/endpoint.rs @@ -13,14 +13,11 @@ use crate::{error::Error, response::IntoResponse, Context, Response}; /// # Examples /// /// Endpoints are implemented as asynchronous functions that make use of language features -/// currently only available in Rust Nightly. For this reason, we have to explicitly enable -/// those features with `#![feature(async_await)]`. To keep examples concise, -/// the attribute will be omitted in most of the documentation. +/// currently only available in Rust Nightly. /// /// A simple endpoint that is invoked on a `GET` request and returns a `String`: /// /// ```rust, no_run -/// # #![feature(async_await)] /// async fn hello(_cx: tide::Context<()>) -> String { /// String::from("hello") /// } diff --git a/tide-core/src/lib.rs b/tide-core/src/lib.rs index b61097996..31daf5d17 100644 --- a/tide-core/src/lib.rs +++ b/tide-core/src/lib.rs @@ -1,6 +1,5 @@ //! Core types and traits from Tide -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-cors/Cargo.toml b/tide-cors/Cargo.toml index ed774dfff..8712cbe13 100644 --- a/tide-cors/Cargo.toml +++ b/tide-cors/Cargo.toml @@ -16,9 +16,9 @@ edition = "2018" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.3.0" +http-service = "0.3.1" tide-core = { path = "../tide-core" } [dev-dependencies] tide = { path = "../" } -http-service-mock = "0.3.0" +http-service-mock = "0.3.1" diff --git a/tide-cors/README.md b/tide-cors/README.md index d59f42d06..54fac43a0 100644 --- a/tide-cors/README.md +++ b/tide-cors/README.md @@ -7,8 +7,6 @@ This crate provides cors-related middleware for Tide. Examples are in the `/examples` folder of this crate. ```rust,no_run -#![feature(async_await)] - use http::header::HeaderValue; use tide::middleware::CorsMiddleware; diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs index 17356897a..fb1322671 100644 --- a/tide-cors/src/lib.rs +++ b/tide-cors/src/lib.rs @@ -3,8 +3,6 @@ //! ## Examples //! //! ```rust,no_run -//! #![feature(async_await)] -//! //! use http::header::HeaderValue; //! use tide::middleware::{CorsMiddleware, CorsOrigin}; //! @@ -30,7 +28,6 @@ //! //! You will probably get a browser alert when running without cors middleware. -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-forms/Cargo.toml b/tide-forms/Cargo.toml index cd2ca5349..af6f15fe6 100644 --- a/tide-forms/Cargo.toml +++ b/tide-forms/Cargo.toml @@ -18,7 +18,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -http-service = "0.3.0" +http-service = "0.3.1" futures-preview = "0.3.0-alpha.17" http = "0.1" log = "0.4.6" diff --git a/tide-forms/src/lib.rs b/tide-forms/src/lib.rs index 534e199f5..01c476b99 100644 --- a/tide-forms/src/lib.rs +++ b/tide-forms/src/lib.rs @@ -1,7 +1,6 @@ //! Crate that provides helpers and extensions for Tide //! related to forms. -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-headers/src/lib.rs b/tide-headers/src/lib.rs index e7b1dfd43..7e1d85c83 100644 --- a/tide-headers/src/lib.rs +++ b/tide-headers/src/lib.rs @@ -1,7 +1,6 @@ //! Crate that provides helpers and/or middlewares for Tide //! related to http headers. -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-log/src/lib.rs b/tide-log/src/lib.rs index 48123de6c..cdba3f396 100644 --- a/tide-log/src/lib.rs +++ b/tide-log/src/lib.rs @@ -1,7 +1,6 @@ //! Crate that provides helpers and/or middlewares for Tide //! related to logging. -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-panic/Cargo.toml b/tide-panic/Cargo.toml index 07e5fad0d..6df8b8411 100644 --- a/tide-panic/Cargo.toml +++ b/tide-panic/Cargo.toml @@ -11,5 +11,5 @@ repository = "https://github.com/rustasync/tide" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1" -http-service = "0.2.0" +http-service = "0.3.1" tide-core = { path = "../tide-core" } diff --git a/tide-panic/src/lib.rs b/tide-panic/src/lib.rs index 3174a2a83..22edc12ee 100644 --- a/tide-panic/src/lib.rs +++ b/tide-panic/src/lib.rs @@ -4,7 +4,7 @@ //! Tide's default panic handling is not usable by your application. Before using these you should //! have a good understanding of how the different components involved in [`std::panic`] works. -#![feature(async_await, doc_cfg)] +#![feature(doc_cfg)] #![warn( nonstandard_style, rust_2018_idioms, diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index f59f2f6e0..354ccb653 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -26,5 +26,5 @@ serde_qs = "0.5.0" [dev-dependencies] tide = { path = "../", default-features = false } -http-service = "0.3.0" -http-service-mock = "0.3.0" +http-service = "0.3.1" +http-service-mock = "0.3.1" diff --git a/tide-querystring/src/lib.rs b/tide-querystring/src/lib.rs index 409217700..86e65e8ff 100644 --- a/tide-querystring/src/lib.rs +++ b/tide-querystring/src/lib.rs @@ -1,7 +1,6 @@ //! Crate that provides helpers and extensions for Tide //! related to query strings. -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, @@ -20,8 +19,6 @@ use tide_core::{error::Error, Context}; /// Turning the query parameters into a `HashMap`: /// /// ``` -/// #![feature(async_await)] -/// /// # use std::collections::HashMap; /// use tide::querystring::ContextExt; /// diff --git a/tide-slog/src/lib.rs b/tide-slog/src/lib.rs index 3f8b2acbf..916180e36 100644 --- a/tide-slog/src/lib.rs +++ b/tide-slog/src/lib.rs @@ -2,7 +2,6 @@ //! related to structured logging with slog. #![cfg_attr(docrs, feature(doc_cfg))] -#![feature(async_await)] #![warn( nonstandard_style, rust_2018_idioms, From c41ed8407da13bd2db77af9357befb0b334f344a Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 22 Aug 2019 01:09:03 +0900 Subject: [PATCH 85/95] Update slog-stdlog to 4.0 (#314) --- tide-slog/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index 4539acac3..21aa181b0 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -33,5 +33,5 @@ slog-scope-futures = { version = "0.1.1", optional = true } [dev-dependencies] tide = { path = "../", default-features = false } uuid = { version = "0.7.4", default-features = false, features = ["v4"] } -slog-stdlog = "3.0.2" +slog-stdlog = "4.0" slog-scope = "4.1.1" From 336c6ef5ac718b60c58aa57d8dd2f3f0e19e82d4 Mon Sep 17 00:00:00 2001 From: Ivo Georgiev Date: Sun, 25 Aug 2019 14:44:10 +0200 Subject: [PATCH 86/95] CORS middleware: no origin header should be treated as an empty origin header --- tide-cors/src/middleware.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs index 2b979564e..80497a481 100644 --- a/tide-cors/src/middleware.rs +++ b/tide-cors/src/middleware.rs @@ -193,14 +193,12 @@ impl CorsMiddleware { impl Middleware for CorsMiddleware { fn handle<'a>(&'a self, cx: Context, next: Next<'a, State>) -> BoxFuture<'a, Response> { Box::pin(async move { - let origin = if let Some(origin) = cx.request().headers().get(header::ORIGIN) { - origin.clone() - } else { - return http::Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::empty()) - .unwrap(); - }; + let origin = cx + .request() + .headers() + .get(header::ORIGIN) + .cloned() + .unwrap_or(HeaderValue::from_static("")); if !self.is_valid_origin(&origin) { return http::Response::builder() From f56a27dc9745139a8ea1a285affa5e3dcf74b435 Mon Sep 17 00:00:00 2001 From: Ivo Georgiev Date: Sun, 25 Aug 2019 14:52:48 +0200 Subject: [PATCH 87/95] CORS middleware: update test --- tide-cors/src/middleware.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs index 80497a481..2bb21f40d 100644 --- a/tide-cors/src/middleware.rs +++ b/tide-cors/src/middleware.rs @@ -399,7 +399,7 @@ mod test { let mut server = make_server(app.into_http_service()).unwrap(); let res = server.simulate(request).unwrap(); - assert_eq!(res.status(), 400); + assert_eq!(res.status(), 200); } #[test] From 87807a7071385239153828e8cce7ad221336f565 Mon Sep 17 00:00:00 2001 From: Ivo Georgiev Date: Sun, 25 Aug 2019 15:32:39 +0200 Subject: [PATCH 88/95] CORS middleware: fix clippy --- tide-cors/src/middleware.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tide-cors/src/middleware.rs b/tide-cors/src/middleware.rs index 2bb21f40d..2a5a8be0a 100644 --- a/tide-cors/src/middleware.rs +++ b/tide-cors/src/middleware.rs @@ -198,7 +198,7 @@ impl Middleware for CorsMiddleware { .headers() .get(header::ORIGIN) .cloned() - .unwrap_or(HeaderValue::from_static("")); + .unwrap_or_else(|| HeaderValue::from_static("")); if !self.is_valid_origin(&origin) { return http::Response::builder() From af0b900bc447eb4410874752c9a7a35b9be79561 Mon Sep 17 00:00:00 2001 From: Ilya Baryshnikov Date: Thu, 29 Aug 2019 17:13:17 -0700 Subject: [PATCH 89/95] updated runtime to 0.3.0-alpha.7, removed patch for crates.io (#319) --- Cargo.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aece7a07d..75085cc28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ mime_guess = "2.0.1" percent-encoding = "2.0.0" serde = { version = "1.0.91", features = ["derive"] } tera = "0.11" -runtime = "0.3.0-alpha.6" +runtime = "0.3.0-alpha.7" # Tide components tide-log = { path = "./tide-log", default-features = false } @@ -73,7 +73,3 @@ members = [ "tide-querystring", "tide-slog", ] - -[patch.crates-io.runtime] -git = "https://github.com/rustasync/runtime" -rev = "f5ac4fb" From e38eb38eee7255cf77a2b4084cb2d86a7523970f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2019 05:39:55 +0000 Subject: [PATCH 90/95] Update env_logger requirement from 0.6.1 to 0.7.0 Updates the requirements on [env_logger](https://github.com/sebasmagri/env_logger) to permit the latest version. - [Release notes](https://github.com/sebasmagri/env_logger/releases) - [Changelog](https://github.com/sebasmagri/env_logger/blob/master/CHANGELOG.md) - [Commits](https://github.com/sebasmagri/env_logger/compare/v0.6.1...v0.7.0) Signed-off-by: dependabot-preview[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 75085cc28..e4803cde4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ tide-querystring = { path = "./tide-querystring", default-features = false } [dev-dependencies] bytes = "0.4.12" cookie = { version = "0.12", features = ["percent-encode"] } -env_logger = "0.6.1" +env_logger = "0.7.0" futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.17", features = ["compat"] } http-service-mock = "0.3.1" From 8281f3844ba00e7f02799212b4b8e12c86d6feb8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2019 05:59:33 +0000 Subject: [PATCH 91/95] Update juniper requirement from 0.13.0 to 0.14.0 Updates the requirements on [juniper](https://github.com/graphql-rust/juniper) to permit the latest version. - [Release notes](https://github.com/graphql-rust/juniper/releases) - [Commits](https://github.com/graphql-rust/juniper/compare/juniper-0.13.1...juniper-v0.14.0) Signed-off-by: dependabot-preview[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e4803cde4..d0e79c2b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ env_logger = "0.7.0" futures-fs = "0.0.5" futures-util-preview = { version = "0.3.0-alpha.17", features = ["compat"] } http-service-mock = "0.3.1" -juniper = "0.13.0" +juniper = "0.14.0" log = "0.4.6" log4rs = "0.8.3" mime = "0.3.13" From de9f51e12593463d46c85867ec21b09cf6d7565d Mon Sep 17 00:00:00 2001 From: Artem Vorotnikov Date: Fri, 16 Aug 2019 16:12:16 +0300 Subject: [PATCH 92/95] Port to Tokio 0.2 --- Cargo.toml | 11 +++---- README.md | 5 ++-- examples/body_types.rs | 5 ++-- examples/catch_all.rs | 5 ++-- examples/cookies.rs | 5 ++-- examples/cors.rs | 5 ++-- examples/default_headers.rs | 5 ++-- examples/graphql.rs | 5 ++-- examples/hello.rs | 5 ++-- examples/hello_envlog.rs | 5 ++-- examples/hello_logrs.rs | 5 ++-- examples/messages.rs | 5 ++-- examples/multipart_form/mod.rs | 5 ++-- examples/staticfile.rs | 22 +++++++------- examples/templating_tera.rs | 6 ++-- src/app.rs | 46 ++++++++++++----------------- tide-compression/Cargo.toml | 9 +++--- tide-compression/README.md | 1 - tide-compression/examples/simple.rs | 5 ++-- tide-cookies/Cargo.toml | 6 ++-- tide-core/Cargo.toml | 4 +-- tide-core/src/endpoint.rs | 10 ++++--- tide-cors/Cargo.toml | 6 ++-- tide-cors/README.md | 5 ++-- tide-cors/src/lib.rs | 3 +- tide-forms/Cargo.toml | 4 +-- tide-headers/Cargo.toml | 2 +- tide-log/Cargo.toml | 2 +- tide-panic/Cargo.toml | 4 +-- tide-querystring/Cargo.toml | 6 ++-- tide-slog/Cargo.toml | 2 +- 31 files changed, 113 insertions(+), 101 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d0e79c2b4..ac9d811c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,10 +25,10 @@ cors = ["tide-cors"] hyper = ["http-service-hyper"] [dependencies] -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" -http-service = "0.3.1" -http-service-hyper = { version = "0.3.1", optional = true } +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } +http-service-hyper = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2", optional = true } # Routing fnv = "1.0.6" route-recognizer = "0.1.13" @@ -46,8 +46,8 @@ bytes = "0.4.12" cookie = { version = "0.12", features = ["percent-encode"] } env_logger = "0.7.0" futures-fs = "0.0.5" -futures-util-preview = { version = "0.3.0-alpha.17", features = ["compat"] } -http-service-mock = "0.3.1" +futures-util-preview = { version = "0.3.0-alpha.18", features = ["compat"] } +http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } juniper = "0.14.0" log = "0.4.6" log4rs = "0.8.3" @@ -59,6 +59,7 @@ tera = "0.11" runtime = "0.3.0-alpha.7" # Tide components tide-log = { path = "./tide-log", default-features = false } +tokio = "0.2.0-alpha.4" [workspace] members = [ diff --git a/README.md b/README.md index 728baedc1..49535e870 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,11 @@ Ecosystem WG, and **not ready for production use yet**. **Hello World** ```rust,no_run -fn main() -> Result<(), std::io::Error> { +#[tokio::main] +async fn main() -> Result<(), std::io::Error> { let mut app = tide::App::new(); app.at("/").get(|_| async move { "Hello, world!" }); - Ok(app.run("127.0.0.1:8000")?) + app.serve("127.0.0.1:8000").await } ``` diff --git a/examples/body_types.rs b/examples/body_types.rs index 999f5859b..dca1a0831 100644 --- a/examples/body_types.rs +++ b/examples/body_types.rs @@ -35,7 +35,8 @@ async fn echo_form(mut cx: Context<()>) -> EndpointResult { Ok(forms::form(msg)) } -fn main() { +#[tokio::main] +async fn main() { let mut app = App::new(); app.at("/echo/string").post(echo_string); @@ -43,5 +44,5 @@ fn main() { app.at("/echo/json").post(echo_json); app.at("/echo/form").post(echo_form); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/catch_all.rs b/examples/catch_all.rs index bfb864d6f..a1906eb24 100644 --- a/examples/catch_all.rs +++ b/examples/catch_all.rs @@ -5,8 +5,9 @@ async fn echo_path(cx: Context<()>) -> String { format!("Your path is: {}", path) } -fn main() { +#[tokio::main] +async fn main() { let mut app = tide::App::new(); app.at("/echo_path/*path").get(echo_path); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/cookies.rs b/examples/cookies.rs index 3dd07a054..8c28f997b 100644 --- a/examples/cookies.rs +++ b/examples/cookies.rs @@ -14,12 +14,13 @@ async fn remove_cookie(mut cx: Context<()>) { cx.remove_cookie(Cookie::named("hello")).unwrap(); } -fn main() { +#[tokio::main] +async fn main() { let mut app = tide::App::new(); app.middleware(CookiesMiddleware::new()); app.at("/").get(retrieve_cookie); app.at("/set").get(set_cookie); app.at("/remove").get(remove_cookie); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/cors.rs b/examples/cors.rs index 0393fdd65..3a9edc7cf 100644 --- a/examples/cors.rs +++ b/examples/cors.rs @@ -1,7 +1,8 @@ use http::header::HeaderValue; use tide::middleware::{CorsMiddleware, CorsOrigin}; -fn main() { +#[tokio::main] +async fn main() { let mut app = tide::App::new(); app.middleware( @@ -12,7 +13,7 @@ fn main() { app.at("/").get(|_| async move { "Hello, world!" }); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } // You can test this by running the following in your browser: diff --git a/examples/default_headers.rs b/examples/default_headers.rs index 48374035f..abd4ef277 100644 --- a/examples/default_headers.rs +++ b/examples/default_headers.rs @@ -1,6 +1,7 @@ use tide::middleware::DefaultHeaders; -fn main() { +#[tokio::main] +async fn main() { let mut app = tide::App::new(); app.middleware( @@ -11,5 +12,5 @@ fn main() { app.at("/").get(|_| async move { "Hello, world!" }); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/graphql.rs b/examples/graphql.rs index 23c4792de..8ce57ad0c 100644 --- a/examples/graphql.rs +++ b/examples/graphql.rs @@ -56,8 +56,9 @@ async fn handle_graphql(mut cx: Context) -> EndpointResult { Ok(resp) } -fn main() { +#[tokio::main] +async fn main() { let mut app = App::with_state(State::default()); app.at("/graphql").post(handle_graphql); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/hello.rs b/examples/hello.rs index 061bee0eb..f66088c8e 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,5 +1,6 @@ -fn main() { +#[tokio::main] +async fn main() { let mut app = tide::App::new(); app.at("/").get(|_| async move { "Hello, world!" }); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/hello_envlog.rs b/examples/hello_envlog.rs index da44e0e83..d85b2d6b4 100644 --- a/examples/hello_envlog.rs +++ b/examples/hello_envlog.rs @@ -1,7 +1,8 @@ -fn main() { +#[tokio::main] +async fn main() { env_logger::from_env(env_logger::Env::default().default_filter_or("info")).init(); let mut app = tide::App::new(); app.middleware(tide::middleware::RequestLogger::new()); app.at("/").get(|_| async move { "Hello, world!" }); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/hello_logrs.rs b/examples/hello_logrs.rs index 87bc1b5a9..612bd3086 100644 --- a/examples/hello_logrs.rs +++ b/examples/hello_logrs.rs @@ -1,4 +1,5 @@ -fn main() { +#[tokio::main] +async fn main() { use log::LevelFilter; use log4rs::append::console::ConsoleAppender; use log4rs::config::{Appender, Config, Root}; @@ -13,5 +14,5 @@ fn main() { let mut app = tide::App::new(); app.middleware(tide::middleware::RequestLogger::new()); app.at("/").get(|_| async move { "Hello, world!" }); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/messages.rs b/examples/messages.rs index 10b047ae4..9587b08c5 100644 --- a/examples/messages.rs +++ b/examples/messages.rs @@ -62,9 +62,10 @@ async fn get_message(cx: Context) -> EndpointResult { } } -fn main() { +#[tokio::main] +async fn main() { let mut app = App::with_state(Database::default()); app.at("/message").post(new_message); app.at("/message/:id").get(get_message).post(set_message); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/multipart_form/mod.rs b/examples/multipart_form/mod.rs index bf6acc4a4..e9628e5c2 100644 --- a/examples/multipart_form/mod.rs +++ b/examples/multipart_form/mod.rs @@ -54,10 +54,11 @@ async fn upload_file(mut cx: Context<()>) -> EndpointResult { Ok(response::json(message)) } -pub fn run() { +#[tokio::main] +pub async fn main() { let mut app = App::new(); app.at("/upload_file").post(upload_file); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } // Test with: diff --git a/examples/staticfile.rs b/examples/staticfile.rs index 26b311e60..c3cee9848 100644 --- a/examples/staticfile.rs +++ b/examples/staticfile.rs @@ -1,12 +1,12 @@ use bytes::Bytes; -use futures_fs::FsPool; -use futures_util::compat::*; +use futures::prelude::*; use http::{ header::{self, HeaderMap}, StatusCode, }; use http_service::Body; use tide::{App, Context, EndpointResult, Response}; +use tokio::codec::Decoder; use std::path::{Component, Path, PathBuf}; use std::{fs, io}; @@ -17,7 +17,6 @@ const DEFAULT_5XX_BODY: &[u8] = b"I'm broken, apparently." as &[_]; /// Simple static file handler for Tide inspired from https://github.com/iron/staticfile. #[derive(Clone)] struct StaticFile { - fs_pool: FsPool, root: PathBuf, } @@ -29,10 +28,7 @@ impl StaticFile { // warn maybe? } - StaticFile { - root, - fs_pool: FsPool::default(), - } + StaticFile { root } } fn stream_bytes(&self, actual_path: &str, headers: &HeaderMap) -> Result { @@ -76,9 +72,12 @@ impl StaticFile { .header(header::CONTENT_TYPE, mime_str) .header(header::CONTENT_LENGTH, size); - let stream = self.fs_pool.read(PathBuf::from(path), Default::default()); + let stream = tokio::fs::File::open(PathBuf::from(path)) + .map_ok(|file| tokio::codec::BytesCodec::new().framed(file)) + .try_flatten_stream() + .map_ok(From::from); Ok(response - .body(Body::from_stream(stream.compat())) + .body(Body::from_stream(stream)) .expect("invalid request?")) } @@ -119,8 +118,9 @@ async fn handle_path(ctx: Context) -> EndpointResult { }) } -fn main() { +#[tokio::main] +async fn main() { let mut app = App::with_state(StaticFile::new("./")); app.at("/*").get(handle_path); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/examples/templating_tera.rs b/examples/templating_tera.rs index aae1c37b4..10e296dd1 100644 --- a/examples/templating_tera.rs +++ b/examples/templating_tera.rs @@ -37,7 +37,8 @@ async fn index(ctx: Context) -> EndpointResult { Ok(resp) } -fn main() -> Result<(), std::io::Error> { +#[tokio::main] +async fn main() -> Result<(), std::io::Error> { let template_dir = format!("{}/examples/templates/*", env!("CARGO_MANIFEST_DIR")); let state = AppState { @@ -46,6 +47,7 @@ fn main() -> Result<(), std::io::Error> { let mut app = App::with_state(state); app.at("/").get(index); - app.run("127.0.0.1:8000")?; + app.serve("127.0.0.1:8000").await?; + Ok(()) } diff --git a/src/app.rs b/src/app.rs index 83914b379..436c50bb4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -30,9 +30,12 @@ use crate::{ /// on `127.0.0.1:8000` with: /// /// ```rust, no_run -/// let mut app = tide::App::new(); -/// app.at("/hello").get(|_| async move { "Hello, world!" }); -/// app.run("127.0.0.1:8000"); +/// #[tokio::main] +/// async fn main() { +/// let mut app = tide::App::new(); +/// app.at("/hello").get(|_| async move { "Hello, world!" }); +/// app.serve("127.0.0.1:8000").await.unwrap(); +/// } /// ``` /// /// # Routing and parameters @@ -55,15 +58,18 @@ use crate::{ /// Ok(format!("Goodbye, {}.", user)) /// } /// -/// let mut app = tide::App::new(); +/// #[tokio::main] +/// async fn main() { +/// let mut app = tide::App::new(); /// -/// app.at("/hello/:user").get(hello); -/// app.at("/goodbye/:user").get(goodbye); -/// app.at("/").get(|_| async move { -/// "Use /hello/{your name} or /goodbye/{your name}" -/// }); +/// app.at("/hello/:user").get(hello); +/// app.at("/goodbye/:user").get(goodbye); +/// app.at("/").get(|_| async move { +/// "Use /hello/{your name} or /goodbye/{your name}" +/// }); /// -/// app.run("127.0.0.1:8000"); +/// app.serve("127.0.0.1:8000").await.unwrap(); +/// } /// ``` /// /// You can learn more about routing in the [`App::at`] documentation. @@ -113,11 +119,12 @@ use crate::{ /// } /// } /// -/// fn main() { +/// #[tokio::main] +/// async fn main() { /// let mut app = App::with_state(Database::default()); /// app.at("/message").post(new_message); /// app.at("/message/:id").get(get_message); -/// app.run("127.0.0.1:8000").unwrap(); +/// app.serve("127.0.0.1:8000").await.unwrap(); /// } /// ``` @@ -230,21 +237,6 @@ impl App { } } - /// Run the app at the given address. - /// - /// Blocks the calling thread indefinitely. - #[cfg(feature = "hyper")] - pub fn run(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> { - let addr = addr - .to_socket_addrs()? - .next() - .ok_or(std::io::ErrorKind::InvalidInput)?; - - println!("Server is listening on: http://{}", addr); - http_service_hyper::run(self.into_http_service(), addr); - Ok(()) - } - /// Asynchronously serve the app at the given address. #[cfg(feature = "hyper")] pub async fn serve(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> { diff --git a/tide-compression/Cargo.toml b/tide-compression/Cargo.toml index 12b194265..e1fd0d1b7 100644 --- a/tide-compression/Cargo.toml +++ b/tide-compression/Cargo.toml @@ -17,15 +17,16 @@ version = "0.1.0" tide = { path = "../", default-features = false } accept-encoding = "0.2.0-alpha.2" bytes = "0.4.12" -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" -http-service = "0.3.1" +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } [dependencies.async-compression] default-features = false features = ["stream", "gzip", "zlib", "brotli", "zstd"] -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.3" [dev-dependencies] tide = { path = "../", default-features = false } -http-service-mock = "0.3.1" +tokio = "0.2.0-alpha.2" +http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } diff --git a/tide-compression/README.md b/tide-compression/README.md index fc19a1351..73c7370fd 100644 --- a/tide-compression/README.md +++ b/tide-compression/README.md @@ -15,5 +15,4 @@ $ curl -v http://127.0.0.1:8000/ $ curl -v -H 'Accept-Encoding: br' http://127.0.0.1:8000/ $ echo 'hello there' | gzip | curl -v --compressed -H 'Content-Encoding: gzip' http://127.0.0.1:8000/echo --data-binary @- $ echo 'general kenobi' | brotli | curl -v --compressed -H 'Content-Encoding: br' http://127.0.0.1:8000/echo --data-binary @- -$ echo 'you are a bold one' | zstd | curl -v --compressed -H 'Content-Encoding: zstd' http://127.0.0.1:8000/echo --data-binary @- ``` diff --git a/tide-compression/examples/simple.rs b/tide-compression/examples/simple.rs index 8a9849d39..f586cac7c 100644 --- a/tide-compression/examples/simple.rs +++ b/tide-compression/examples/simple.rs @@ -11,11 +11,12 @@ async fn echo_bytes(mut cx: Context<()>) -> Vec { cx.body_bytes().await.unwrap() } -fn main() { +#[tokio::main] +async fn main() { let mut app = App::new(); app.at("/").get(lorem_ipsum); app.at("/echo").post(echo_bytes); app.middleware(Compression::with_default(Encoding::Brotli)); app.middleware(Decompression::new()); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } diff --git a/tide-cookies/Cargo.toml b/tide-cookies/Cargo.toml index a6a28325d..5fbf57854 100644 --- a/tide-cookies/Cargo.toml +++ b/tide-cookies/Cargo.toml @@ -12,11 +12,11 @@ repository = "https://github.com/rustasync/tide" [dependencies] cookie = { version = "0.12", features = ["percent-encode"] } -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" -http-service = "0.3.1" +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } tide-core = { path = "../tide-core", default-features = false } [dev-dependencies] tide = { path = "../", default-features = false } -http-service-mock = "0.3.1" +http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } diff --git a/tide-core/Cargo.toml b/tide-core/Cargo.toml index e27d17d01..a2e294004 100644 --- a/tide-core/Cargo.toml +++ b/tide-core/Cargo.toml @@ -11,9 +11,9 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/rustasync/tide" [dependencies] -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" -http-service = "0.3.1" +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } serde = "1.0.91" serde_json = "1.0.39" route-recognizer = "0.1.13" diff --git a/tide-core/src/endpoint.rs b/tide-core/src/endpoint.rs index dca8afd79..7cc48b08a 100644 --- a/tide-core/src/endpoint.rs +++ b/tide-core/src/endpoint.rs @@ -22,10 +22,11 @@ use crate::{error::Error, response::IntoResponse, Context, Response}; /// String::from("hello") /// } /// -/// fn main() { +/// #[tokio::main] +/// async fn main() { /// let mut app = tide::App::new(); /// app.at("/hello").get(hello); -/// app.run("127.0.0.1:8000").unwrap() +/// app.serve("127.0.0.1:8000").await.unwrap() /// } /// ``` /// @@ -37,10 +38,11 @@ use crate::{error::Error, response::IntoResponse, Context, Response}; /// futures::future::ready(String::from("hello")) /// } /// -/// fn main() { +/// #[tokio::main] +/// async fn main() { /// let mut app = tide::App::new(); /// app.at("/hello").get(hello); -/// app.run("127.0.0.1:8000").unwrap() +/// app.serve("127.0.0.1:8000").await.unwrap() /// } /// ``` /// diff --git a/tide-cors/Cargo.toml b/tide-cors/Cargo.toml index 8712cbe13..a3e9ed240 100644 --- a/tide-cors/Cargo.toml +++ b/tide-cors/Cargo.toml @@ -14,11 +14,11 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" -http-service = "0.3.1" +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } tide-core = { path = "../tide-core" } [dev-dependencies] tide = { path = "../" } -http-service-mock = "0.3.1" +http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } diff --git a/tide-cors/README.md b/tide-cors/README.md index 54fac43a0..85a19e8d3 100644 --- a/tide-cors/README.md +++ b/tide-cors/README.md @@ -10,7 +10,8 @@ Examples are in the `/examples` folder of this crate. use http::header::HeaderValue; use tide::middleware::CorsMiddleware; -fn main() { +#[tokio::main] +async fn main() { let mut app = tide::App::new(); app.middleware( @@ -21,7 +22,7 @@ fn main() { app.at("/").get(|_| async move { "Hello, world!" }); - app.run("127.0.0.1:8000").unwrap(); + app.serve("127.0.0.1:8000").await.unwrap(); } ``` diff --git a/tide-cors/src/lib.rs b/tide-cors/src/lib.rs index fb1322671..356908548 100644 --- a/tide-cors/src/lib.rs +++ b/tide-cors/src/lib.rs @@ -6,6 +6,7 @@ //! use http::header::HeaderValue; //! use tide::middleware::{CorsMiddleware, CorsOrigin}; //! +//! #[tokio::main] //! fn main() { //! let mut app = tide::App::new(); //! @@ -17,7 +18,7 @@ //! //! app.at("/").get(|_| async move { "Hello, world!" }); //! -//! app.run("127.0.0.1:8000").unwrap(); +//! app.serve("127.0.0.1:8000").await.unwrap(); //! } //! ``` //! You can test this by running the following in your browser: diff --git a/tide-forms/Cargo.toml b/tide-forms/Cargo.toml index af6f15fe6..a96a64992 100644 --- a/tide-forms/Cargo.toml +++ b/tide-forms/Cargo.toml @@ -18,8 +18,8 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -http-service = "0.3.1" -futures-preview = "0.3.0-alpha.17" +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } +futures-preview = "0.3.0-alpha.18" http = "0.1" log = "0.4.6" multipart = { version = "0.16.1", features = ["server"], default-features = false } diff --git a/tide-headers/Cargo.toml b/tide-headers/Cargo.toml index 19dbd770c..b954fb6dd 100644 --- a/tide-headers/Cargo.toml +++ b/tide-headers/Cargo.toml @@ -18,7 +18,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" log = "0.4.6" diff --git a/tide-log/Cargo.toml b/tide-log/Cargo.toml index 2f4d7ce49..60fcee847 100644 --- a/tide-log/Cargo.toml +++ b/tide-log/Cargo.toml @@ -19,7 +19,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" log = "0.4.6" diff --git a/tide-panic/Cargo.toml b/tide-panic/Cargo.toml index 6df8b8411..cbb3543c1 100644 --- a/tide-panic/Cargo.toml +++ b/tide-panic/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/rustasync/tide" [dependencies] -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" -http-service = "0.3.1" +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } tide-core = { path = "../tide-core" } diff --git a/tide-querystring/Cargo.toml b/tide-querystring/Cargo.toml index 354ccb653..b46d12c8d 100644 --- a/tide-querystring/Cargo.toml +++ b/tide-querystring/Cargo.toml @@ -18,7 +18,7 @@ version = "0.1.0" [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" log = "0.4.6" serde = { version = "1.0.91", features = ["derive"] } @@ -26,5 +26,5 @@ serde_qs = "0.5.0" [dev-dependencies] tide = { path = "../", default-features = false } -http-service = "0.3.1" -http-service-mock = "0.3.1" +http-service = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } +http-service-mock = { git = "https://github.com/rustasync/http-service", branch = "tokio-0.2" } diff --git a/tide-slog/Cargo.toml b/tide-slog/Cargo.toml index 21aa181b0..03d19f33c 100644 --- a/tide-slog/Cargo.toml +++ b/tide-slog/Cargo.toml @@ -24,7 +24,7 @@ scope = ["slog-scope", "slog-scope-futures"] [dependencies] tide-core = { path = "../tide-core", default-features = false } -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1" slog = "2.4.1" slog-scope = { version = "4.1.1", optional = true } From a69d98da388c61cd274c6defcdada41341818b2f Mon Sep 17 00:00:00 2001 From: Artem Vorotnikov Date: Wed, 2 Oct 2019 17:59:02 +0300 Subject: [PATCH 93/95] Remove external docs so as to build on beta --- .travis.yml | 12 ++++-------- src/lib.rs | 6 ------ tide-compression/src/lib.rs | 2 -- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4a55e0ea..5f0f9df5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: rust -rust: nightly-2019-08-21 +rust: beta before_script: - > @@ -16,7 +16,6 @@ matrix: env: [CACHE_NAME=docs] script: - RUSTDOCFLAGS=-Dwarnings cargo doc - -Zmtime-on-use --all --all-features --exclude tide --no-deps @@ -35,7 +34,6 @@ matrix: - rustup component add clippy script: - cargo clippy - -Zmtime-on-use --all --all-targets -- -Dwarnings @@ -43,18 +41,16 @@ matrix: env: [CACHE_NAME=no-default-features] script: - cargo build - -Zmtime-on-use --manifest-path tide-core/Cargo.toml --no-default-features - cargo build - -Zmtime-on-use --no-default-features - name: cargo test script: - - cargo test -Zmtime-on-use --all --verbose + - cargo test --all --verbose - name: cargo test --all-features script: - - cargo test -Zmtime-on-use --all-features - - cargo test -Zmtime-on-use --manifest-path tide-slog/Cargo.toml --all-features + - cargo test --all-features + - cargo test --manifest-path tide-slog/Cargo.toml --all-features diff --git a/src/lib.rs b/src/lib.rs index a60d9b2f5..1a96ffb37 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ //! //! The [`App`](struct.App.html) docs are a good place to get started. -#![cfg_attr(any(feature = "nightly", test), feature(external_doc))] -#![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![warn( nonstandard_style, rust_2018_idioms, @@ -12,10 +10,6 @@ missing_docs )] -#[cfg(test)] -#[doc(include = "../README.md")] -const _README: () = (); - pub use http; mod app; diff --git a/tide-compression/src/lib.rs b/tide-compression/src/lib.rs index 18ba3c9a5..f1685b53b 100644 --- a/tide-compression/src/lib.rs +++ b/tide-compression/src/lib.rs @@ -1,8 +1,6 @@ //! Crate that provides helpers and/or middlewares for Tide //! related to compression. -#![cfg_attr(feature = "nightly", feature(external_doc))] -#![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![warn( nonstandard_style, rust_2018_idioms, From 9f9bdd6a2ad4571ab1c8c302aa8371d1c7488599 Mon Sep 17 00:00:00 2001 From: Artem Vorotnikov Date: Mon, 7 Oct 2019 17:26:23 +0300 Subject: [PATCH 94/95] Remove feature flag --- tide-panic/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tide-panic/src/lib.rs b/tide-panic/src/lib.rs index 22edc12ee..a528a66fb 100644 --- a/tide-panic/src/lib.rs +++ b/tide-panic/src/lib.rs @@ -4,7 +4,6 @@ //! Tide's default panic handling is not usable by your application. Before using these you should //! have a good understanding of how the different components involved in [`std::panic`] works. -#![feature(doc_cfg)] #![warn( nonstandard_style, rust_2018_idioms, From 2a9dedebcd26b6eca1b8ae2200c9988007861b86 Mon Sep 17 00:00:00 2001 From: Artem Vorotnikov Date: Mon, 7 Oct 2019 17:26:38 +0300 Subject: [PATCH 95/95] Cut the runtime example for now --- examples/runtime.rs | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 examples/runtime.rs diff --git a/examples/runtime.rs b/examples/runtime.rs deleted file mode 100644 index fa8d2f95e..000000000 --- a/examples/runtime.rs +++ /dev/null @@ -1,27 +0,0 @@ -/// An example of how to run a Tide service on top of `runtime`, this also shows the pieces -/// necessary if you wish to run a service on some other executor/IO source. - -#[runtime::main] -async fn main() -> Result<(), Box> { - // First, we create a simple hello world application - let mut app = tide::App::new(); - app.at("/").get(|_| async move { "Hello, world!" }); - - // Instead of using `App::run` to start the application, which implicitly uses a default - // http-service server, we need to configure a custom server with the executor and IO source we - // want it to use and then run the Tide service on it. - - // Turn the `tide::App` into a generic `http_service::HttpService` - let http_service = app.into_http_service(); - - // Build an `http_service_hyper::Server` using runtime's `TcpListener` and `Spawn` instances - // instead of hyper's defaults. - let mut listener = runtime::net::TcpListener::bind("127.0.0.1:8000")?; - let server = http_service_hyper::Server::builder(listener.incoming()) - .with_spawner(runtime::task::Spawner::new()); - - // Serve the Tide service on the configured server, and wait for it to complete - server.serve(http_service).await?; - - Ok(()) -}