diff --git a/Cargo.toml b/Cargo.toml index 5ef574d25..37a67364c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,40 +29,26 @@ docs = ["unstable"] unstable = [] [dependencies] +async-h1 = { version = "1.1.2", optional = true } async-sse = "2.1.0" +async-std = { version = "1.4.0", features = ["unstable"] } +cookie = { version = "0.12.0", features = ["percent-encode"]} http-types = "1.0.1" -async-h1 = { version = "1.1.2", optional = true } +kv-log-macro = "1.0.4" +mime = "0.3.14" +mime_guess = "2.0.3" route-recognizer = "0.1.13" serde = "1.0.102" serde_json = "1.0.41" serde_qs = "0.5.0" -async-std = { version = "1.4.0", features = ["unstable"] } -mime = "0.3.14" -cookie = { version = "0.12.0", features = ["percent-encode"]} -futures-core = "0.3.1" -futures = { version = "0.3.1", optional = true } -http = { version = "0.2.0", optional = true } -tokio = { version = "0.2.13", optional = true } -url = "2.1.1" -kv-log-macro = "1.0.4" -mime_guess = "2.0.3" [dev-dependencies] async-std = { version = "1.4.0", features = ["unstable", "attributes"] } -basic-cookies = "0.1.3" -bytes = "0.4.12" -futures-fs = "0.0.5" -futures-util = { version = "0.3.0", features = ["compat"] } +femme = "1.3.0" juniper = "0.14.1" -mime = "0.3.14" -mime_guess = "2.0.1" -percent-encoding = "2.1.0" +portpicker = "0.1.0" serde = { version = "1.0.102", features = ["derive"] } -structopt = "0.3.3" surf = "2.0.0-alpha.1" -futures = "0.3.1" -femme = "1.3.0" -portpicker = "0.1.0" [[test]] name = "nested" diff --git a/backup/examples/body_types.rs b/backup/examples/body_types.rs deleted file mode 100644 index 2bae7764b..000000000 --- a/backup/examples/body_types.rs +++ /dev/null @@ -1,47 +0,0 @@ -use serde::{Deserialize, Serialize}; -use tide::{ - error::ResultExt, - forms::{self, RequestExt}, - response, Request, Result, Server, -}; - -#[derive(Serialize, Deserialize, Clone, Debug)] -struct Message { - author: Option, - contents: String, -} - -async fn echo_string(mut cx: Request<()>) -> String { - let msg = cx.body_string().await.unwrap(); - println!("String: {}", msg); - msg -} - -async fn echo_bytes(mut cx: Request<()>) -> Vec { - let msg = cx.body_bytes().await.unwrap(); - println!("Bytes: {:?}", msg); - msg -} - -async fn echo_json(mut cx: Request<()>) -> Result { - let msg = cx.body_json().await.client_err()?; - println!("JSON: {:?}", msg); - Ok(response::json(msg)) -} - -async fn echo_form(mut cx: Request<()>) -> Result { - let msg = cx.body_form().await?; - println!("Form: {:?}", msg); - Ok(forms::form(msg)) -} - -fn main() { - let mut app = Server::new(); - - app.at("/echo/string").post(echo_string); - app.at("/echo/bytes").post(echo_bytes); - app.at("/echo/json").post(echo_json); - app.at("/echo/form").post(echo_form); - - app.run("127.0.0.1:8000").unwrap(); -} diff --git a/backup/examples/catch_all.rs b/backup/examples/catch_all.rs deleted file mode 100644 index b0efebc79..000000000 --- a/backup/examples/catch_all.rs +++ /dev/null @@ -1,12 +0,0 @@ -use tide::Request; - -async fn echo_path(cx: Request<()>) -> String { - let path: String = cx.param("path").unwrap(); - format!("Your path is: {}", path) -} - -fn main() { - let mut app = tide::Server::new(); - app.at("/echo_path/*path").get(echo_path); - app.run("127.0.0.1:8000").unwrap(); -} diff --git a/backup/examples/default_headers.rs b/backup/examples/default_headers.rs deleted file mode 100644 index 855dec8c3..000000000 --- a/backup/examples/default_headers.rs +++ /dev/null @@ -1,15 +0,0 @@ -use tide::middleware::DefaultHeaders; - -fn main() { - let mut app = tide::Server::new(); - - app.middleware( - DefaultHeaders::new() - .header("X-Version", "1.0.0") - .header("X-Server", "Tide"), - ); - - app.at("/").get(|_| async move { "Hello, world!" }); - - app.run("127.0.0.1:8000").unwrap(); -} diff --git a/backup/examples/graphql.rs b/backup/examples/graphql.rs deleted file mode 100644 index d38229fd3..000000000 --- a/backup/examples/graphql.rs +++ /dev/null @@ -1,64 +0,0 @@ -// This example uses Juniper to process GraphQL requests. If you're not familiar with Juniper, take -// a look at [the Juniper book]. -// -// [the Juniper book]: https://graphql-rust.github.io/ - -use http::status::StatusCode; -use juniper::graphql_object; -use std::sync::{atomic, Arc}; -use tide::{error::ResultExt, response, Request, Result, Server}; - -// First, we define `State` that holds accumulator state. This is accessible as Server data in -// Tide, and as executor context in Juniper. -#[derive(Clone, Default)] -struct State(Arc); - -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 -// accumulator state from the context. -struct Query; - -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 - } -}); - -// Here is `Mutation` unit struct. GraphQL mutations will refer to this struct. This is similar to -// `Query`, but it provides the way to "mutate" the accumulator state. -struct Mutation; - -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 - } -}); - -// Adding `Query` and `Mutation` together we get `Schema`, which describes, well, the whole GraphQL -// schema. -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: Request) -> Result { - let query: juniper::http::GraphQLRequest = cx.body_json().await.client_err()?; - let schema = Schema::new(Query, Mutation); - let response = query.execute(&schema, cx.state()); - let status = if response.is_ok() { - StatusCode::OK - } else { - StatusCode::BAD_REQUEST - }; - let mut resp = response::json(response); - *resp.status_mut() = status; - Ok(resp) -} - -fn main() { - let mut app = Server::with_state(State::default()); - app.at("/graphql").post(handle_graphql); - app.run("127.0.0.1:8000").unwrap(); -} diff --git a/backup/examples/messages.rs b/backup/examples/messages.rs deleted file mode 100644 index 4b19b3bd5..000000000 --- a/backup/examples/messages.rs +++ /dev/null @@ -1,70 +0,0 @@ -use http::status::StatusCode; -use serde::{Deserialize, Serialize}; -use std::sync::Mutex; -use tide::{Request, Result, ResultExt, Server}; - -#[derive(Default)] -struct Database { - contents: Mutex>, -} - -#[derive(Serialize, Deserialize, Clone)] -struct Message { - author: Option, - contents: String, -} - -impl Database { - fn insert(&self, msg: Message) -> usize { - let mut table = self.contents.lock().unwrap(); - table.push(msg); - table.len() - 1 - } - - fn get(&self, id: usize) -> Option { - self.contents.lock().unwrap().get(id).cloned() - } - - fn set(&self, id: usize, msg: Message) -> bool { - let mut table = self.contents.lock().unwrap(); - - if let Some(old_msg) = table.get_mut(id) { - *old_msg = msg; - true - } else { - false - } - } -} - -async fn new_message(mut cx: Request) -> Result { - let msg = cx.body_json().await.client_err()?; - Ok(cx.state().insert(msg).to_string()) -} - -async fn set_message(mut cx: Request) -> Result<()> { - let msg = cx.body_json().await.client_err()?; - let id = cx.param("id").client_err()?; - - if cx.state().set(id, msg) { - Ok(()) - } else { - Err(StatusCode::NOT_FOUND)? - } -} - -async fn get_message(cx: Request) -> Result { - let id = cx.param("id").client_err()?; - if let Some(msg) = cx.state().get(id) { - Ok(cx.body_json()) - } else { - Err(StatusCode::NOT_FOUND)? - } -} - -fn main() { - let mut app = Server::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(); -} diff --git a/backup/examples/multipart-form/main.rs b/backup/examples/multipart-form/main.rs deleted file mode 100644 index 36b6233d2..000000000 --- a/backup/examples/multipart-form/main.rs +++ /dev/null @@ -1,65 +0,0 @@ -// use serde::{Deserialize, Serialize}; -// use std::io::Read; -// use tide::{forms::RequestExt, response, Server, Request, Result}; - -// #[derive(Serialize, Deserialize, Clone)] -// struct Message { -// key1: Option, -// key2: Option, -// file: Option, -// } - -// async fn upload_file(mut cx: Request<()>) -> Result { -// // https://stackoverflow.com/questions/43424982/how-to-parse-multipart-forms-using-abonander-multipart-with-rocket -// let mut message = Message { -// key1: None, -// key2: None, -// file: None, -// }; - -// cx.body_multipart() -// .await? -// .foreach_entry(|mut entry| match &*entry.headers.name { -// "file" => { -// let mut vec = Vec::new(); -// entry.data.read_to_end(&mut vec).expect("can't read"); -// message.file = String::from_utf8(vec).ok(); -// println!("key file got"); -// } - -// "key1" => { -// let mut vec = Vec::new(); -// entry.data.read_to_end(&mut vec).expect("can't read"); -// message.key1 = String::from_utf8(vec).ok(); -// println!("key1 got"); -// } - -// "key2" => { -// let mut vec = Vec::new(); -// entry.data.read_to_end(&mut vec).expect("can't read"); -// message.key2 = String::from_utf8(vec).ok(); -// println!("key2 got"); -// } - -// _ => { -// // as multipart has a bug https://github.com/abonander/multipart/issues/114 -// // we manually do read_to_end here -// let mut _vec = Vec::new(); -// entry.data.read_to_end(&mut _vec).expect("can't read"); -// println!("key neglected"); -// } -// }) -// .expect("Unable to iterate multipart?"); - -// Ok(response::json(message)) -// } - -fn main() { - // let mut app = Server::new(); - // app.at("/upload_file").post(upload_file); - // app.run("127.0.0.1:8000").unwrap(); -} - -// Test with: -// curl -X POST http://localhost:8000/upload_file -H 'content-type: multipart/form-data' -F file=@examples/multipart-form/test.txt -// curl -X POST http://localhost:8000/upload_file -H 'content-type: multipart/form-data' -F key1=v1, -F key2=v2 diff --git a/backup/examples/multipart-form/test.txt b/backup/examples/multipart-form/test.txt deleted file mode 100644 index af27ff498..000000000 --- a/backup/examples/multipart-form/test.txt +++ /dev/null @@ -1 +0,0 @@ -This is a test file. \ No newline at end of file diff --git a/backup/examples/nested_router.rs b/backup/examples/nested_router.rs deleted file mode 100644 index a842cce00..000000000 --- a/backup/examples/nested_router.rs +++ /dev/null @@ -1,15 +0,0 @@ -use tide::Server; - -fn main() { - let mut app = Server::new(); - app.at("/gates").nest(|router| { - router - .at("/") - .get(|_| async move { "This is an area in front of the gates" }); - router.at("/open").get(|_| async move { "Open the gates!" }); - router - .at("/close") - .get(|_| async move { "Close the gates!" }); - }); - app.run("127.0.0.1:8000").unwrap(); -} diff --git a/backup/examples/staticfile.rs b/backup/examples/staticfile.rs deleted file mode 100644 index fa442caa1..000000000 --- a/backup/examples/staticfile.rs +++ /dev/null @@ -1,125 +0,0 @@ -use bytes::Bytes; -use futures_fs::FsPool; -use futures_util::compat::*; -use http::{ - header::{self, HeaderMap}, - StatusCode, -}; -use tide::{Body, Request, Response, Result, Server}; - -use std::path::{Component, Path, PathBuf}; -use std::{fs, io}; - -const DEFAULT_4XX_BODY: &[u8] = b"Oops! I can't find what you're looking for..." as &[_]; -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, -} - -impl StaticFile { - /// Creates a new instance of this handler. - pub fn new(root: impl AsRef) -> Self { - let root = PathBuf::from(root.as_ref()); - if !root.exists() { - // warn maybe? - } - - StaticFile { - root, - fs_pool: FsPool::default(), - } - } - - fn stream_bytes(&self, actual_path: &str, headers: &HeaderMap) -> io::Result { - let path = &self.get_path(actual_path); - let mut response = http::Response::builder(); - let meta = fs::metadata(path).ok(); - // 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("/") { - return Ok(response - .status(StatusCode::MOVED_PERMANENTLY) - .header(header::LOCATION, String::from(actual_path) + "/") - .body(Body::empty()) - .expect("failed to build redirect response?")); - } - - let index = Path::new(actual_path).join("index.html"); - return self.stream_bytes(&*index.to_string_lossy(), headers); - } - - // If the file doesn't exist, then bail out. - let meta = match meta { - Some(m) => m, - None => { - return Ok(response - .status(StatusCode::NOT_FOUND) - .header(header::CONTENT_TYPE, mime::TEXT_HTML.as_ref()) - .body(DEFAULT_4XX_BODY.into()) - .expect("failed to build static response?")) - } - }; - - let mime = mime_guess::from_path(path).first_or_octet_stream(); - let mime_str = mime.as_ref(); - let size = meta.len(); - - // We're done with the checks. Stream file! - response - .status(StatusCode::OK) - .header(header::CONTENT_TYPE, mime_str) - .header(header::CONTENT_LENGTH, size); - - let stream = self.fs_pool.read(PathBuf::from(path), Default::default()); - Ok(response - .body(Body::from_stream(stream.compat())) - .expect("invalid request?")) - } - - /// Percent-decode, normalize path components and return the final path joined with root. - /// See https://github.com/iron/staticfile/blob/master/src/requested_path.rs - fn get_path(&self, path: &str) -> PathBuf { - let rel_path = Path::new(path) - .components() - .fold(PathBuf::new(), |mut result, p| { - match p { - Component::Normal(x) => result.push({ - let s = x.to_str().unwrap_or(""); - &*percent_encoding::percent_decode(s.as_bytes()).decode_utf8_lossy() - }), - Component::ParentDir => { - result.pop(); - } - _ => (), // ignore any other component - } - - result - }); - - self.root.join(rel_path) - } -} - -async fn handle_path(ctx: Request) -> Result { - let path = ctx.uri().path(); - ctx.state() - .stream_bytes(path, ctx.headers()) - .or_else(|_err| { - Ok(http::Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .header(header::CONTENT_TYPE, mime::TEXT_HTML.as_ref()) - .body(Bytes::from(DEFAULT_5XX_BODY).into()) - .expect("failed to build static response?")) - }) -} - -fn main() { - let mut app = Server::with_state(StaticFile::new("./")); - app.at("/*").get(handle_path); - app.run("127.0.0.1:8000").unwrap(); -} diff --git a/src/cookies/middleware.rs b/src/cookies/middleware.rs index 5218175c6..11131ad8a 100644 --- a/src/cookies/middleware.rs +++ b/src/cookies/middleware.rs @@ -2,8 +2,8 @@ use crate::response::CookieEvent; use crate::utils::BoxFuture; use crate::{Middleware, Next, Request}; -use cookie::{Cookie, CookieJar}; -use http_types::headers; +use crate::http::cookies::{Cookie, CookieJar}; +use crate::http::headers; use std::sync::{Arc, RwLock}; diff --git a/src/endpoint.rs b/src/endpoint.rs index e83194527..65ee503e9 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -38,7 +38,7 @@ use crate::{Middleware, Request, Response}; /// ```no_run /// # use core::future::Future; /// fn hello(_req: tide::Request<()>) -> impl Future> { -/// futures::future::ready(Ok(String::from("hello"))) +/// async_std::future::ready(Ok(String::from("hello"))) /// } /// /// fn main() { diff --git a/src/lib.rs b/src/lib.rs index 745afbf45..dd38ba4d7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! //! __hello world__ //! ```no_run -//! # use futures::executor::block_on; +//! # use async_std::task::block_on; //! # fn main() -> Result<(), std::io::Error> { block_on(async { //! # //! let mut app = tide::new(); @@ -37,7 +37,7 @@ //! //! __echo server__ //! ```no_run -//! # use futures::executor::block_on; +//! # use async_std::task::block_on; //! # fn main() -> Result<(), std::io::Error> { block_on(async { //! # //! let mut app = tide::new(); @@ -49,7 +49,7 @@ //! //! __send and receive json__ //! ```no_run -//! # use futures::executor::block_on; +//! # use async_std::task::block_on; //! # fn main() -> Result<(), std::io::Error> { block_on(async { //! # use tide::{Request, Response}; //! # @@ -217,7 +217,7 @@ pub use http_types::{self as http, Body, Error, Status, StatusCode}; /// # Examples /// /// ```no_run -/// # use futures::executor::block_on; +/// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// let mut app = tide::new(); @@ -237,7 +237,7 @@ pub fn new() -> server::Server<()> { /// # Examples /// /// ```no_run -/// # use futures::executor::block_on; +/// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; diff --git a/src/redirect/mod.rs b/src/redirect/mod.rs index f1d63185d..2873fea91 100644 --- a/src/redirect/mod.rs +++ b/src/redirect/mod.rs @@ -3,7 +3,7 @@ //! # Examples //! //! ```no_run -//! # use futures::executor::block_on; +//! # use async_std::task::block_on; //! # fn main() -> Result<(), std::io::Error> { block_on(async { //! # //! use tide::redirect; diff --git a/src/redirect/permanent.rs b/src/redirect/permanent.rs index 03ca18155..2b98db46d 100644 --- a/src/redirect/permanent.rs +++ b/src/redirect/permanent.rs @@ -8,7 +8,7 @@ use crate::{Endpoint, Request, Response}; /// /// # Examples /// ```no_run -/// # use futures::executor::block_on; +/// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::redirect; diff --git a/src/redirect/temporary.rs b/src/redirect/temporary.rs index 9d3dc146c..461cc9992 100644 --- a/src/redirect/temporary.rs +++ b/src/redirect/temporary.rs @@ -8,7 +8,7 @@ use crate::{Endpoint, Request, Response}; /// /// # Examples /// ```no_run -/// # use futures::executor::block_on; +/// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::redirect; diff --git a/src/request.rs b/src/request.rs index f1cffb58a..714091b1f 100644 --- a/src/request.rs +++ b/src/request.rs @@ -1,4 +1,3 @@ -use cookie::Cookie; use route_recognizer::Params; use serde::Deserialize; @@ -9,6 +8,7 @@ use std::pin::Pin; use std::{str::FromStr, sync::Arc}; use crate::cookies::CookieData; +use crate::http::cookies::Cookie; use crate::http::headers::{HeaderName, HeaderValue}; use crate::http::{self, Method, StatusCode, Url, Version}; use crate::Response; @@ -45,7 +45,7 @@ impl Request { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; @@ -68,7 +68,7 @@ impl Request { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; @@ -91,7 +91,7 @@ impl Request { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; @@ -114,7 +114,7 @@ impl Request { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; @@ -196,7 +196,7 @@ impl Request { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; @@ -231,7 +231,7 @@ impl Request { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; diff --git a/src/response.rs b/src/response.rs index f1cd83d05..e4360aeb2 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,10 +1,10 @@ use async_std::io::prelude::*; use std::convert::TryFrom; -use cookie::Cookie; use mime::Mime; use serde::Serialize; +use crate::http::cookies::Cookie; use crate::http::headers::{HeaderName, HeaderValue}; use crate::http::{self, Body, StatusCode}; @@ -54,7 +54,7 @@ impl Response { /// /// ``` /// # use tide::{Response, Request, StatusCode}; - /// # fn canonicalize(uri: &url::Url) -> Option<&url::Url> { None } + /// # fn canonicalize(uri: &tide::http::Url) -> Option<&tide::http::Url> { None } /// # #[allow(dead_code)] /// async fn route_handler(request: Request<()>) -> tide::Result { /// if let Some(canonical_redirect) = canonicalize(request.uri()) { diff --git a/src/server.rs b/src/server.rs index 31c788406..5255f756d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -141,7 +141,7 @@ impl Server<()> { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// let mut app = tide::new(); @@ -169,7 +169,7 @@ impl Server { /// # Examples /// /// ```no_run - /// # use futures::executor::block_on; + /// # use async_std::task::block_on; /// # fn main() -> Result<(), std::io::Error> { block_on(async { /// # /// use tide::Request; diff --git a/tests/cookies.rs b/tests/cookies.rs index d66215a62..ff40089ef 100644 --- a/tests/cookies.rs +++ b/tests/cookies.rs @@ -1,6 +1,6 @@ -use cookie::Cookie; -use futures::executor::block_on; -use futures::AsyncReadExt; +use async_std::prelude::*; +use async_std::task::block_on; +use tide::http::cookies::Cookie; use tide::{Request, Response, Server, StatusCode}; diff --git a/tests/nested.rs b/tests/nested.rs index 3b2d6b56b..a58a1acf4 100644 --- a/tests/nested.rs +++ b/tests/nested.rs @@ -1,9 +1,11 @@ -use futures::future::BoxFuture; +use http_types::headers::{HeaderName, HeaderValue}; +use http_types::{Method, Request, Response, Url}; use std::str::FromStr; -use tide::http::headers::{HeaderName, HeaderValue}; -use tide::http::{Method, Request, Response, Url}; +use test_utils::BoxFuture; use tide::{Middleware, Next}; +mod test_utils; + #[async_std::test] async fn nested() { let mut inner = tide::new(); diff --git a/tests/querystring.rs b/tests/querystring.rs index d5b6d73ed..752b238b0 100644 --- a/tests/querystring.rs +++ b/tests/querystring.rs @@ -1,5 +1,5 @@ use async_std::prelude::*; -use futures::executor::block_on; +use async_std::task::block_on; use serde::Deserialize; use tide::{http, Request, Response, Server, StatusCode}; diff --git a/tests/response.rs b/tests/response.rs index 91af72d51..3a9928cf8 100644 --- a/tests/response.rs +++ b/tests/response.rs @@ -1,54 +1,54 @@ -// use futures::executor::block_on; -// use tide::*; - -// #[test] -// fn test_status() { -// let resp = "foo" -// .with_status(http::status::StatusCode::NOT_FOUND) -// .into_response(); -// assert_eq!(resp.status(), http::status::StatusCode::NOT_FOUND); -// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b"foo"); -// } - -// #[test] -// fn byte_vec_content_type() { -// let resp = String::from("foo").into_bytes().into_response(); -// assert_eq!(resp.headers()["Content-Type"], "application/octet-stream"); -// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b"foo"); -// } - -// #[test] -// fn string_content_type() { -// let resp = String::from("foo").into_response(); -// assert_eq!(resp.headers()["Content-Type"], "text/plain; charset=utf-8"); -// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b"foo"); -// } - -// #[test] -// fn json_content_type() { -// use std::collections::BTreeMap; - -// let mut map = BTreeMap::new(); -// map.insert(Some("a"), 2); -// map.insert(Some("b"), 4); -// map.insert(None, 6); - -// let resp = json(map); -// assert_eq!( -// resp.status(), -// http::status::StatusCode::INTERNAL_SERVER_ERROR -// ); -// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b""); - -// let mut map = BTreeMap::new(); -// map.insert("a", 2); -// map.insert("b", 4); -// map.insert("c", 6); - -// let resp = json(map); -// assert_eq!(resp.status(), http::status::StatusCode::OK); -// assert_eq!( -// block_on(resp.into_body().into_vec()).unwrap(), -// br##"{"a":2,"b":4,"c":6}"## -// ); -// } +// use async_std::task::block_on; +// use tide::*; + +// #[test] +// fn test_status() { +// let resp = "foo" +// .with_status(http::status::StatusCode::NOT_FOUND) +// .into_response(); +// assert_eq!(resp.status(), http::status::StatusCode::NOT_FOUND); +// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b"foo"); +// } + +// #[test] +// fn byte_vec_content_type() { +// let resp = String::from("foo").into_bytes().into_response(); +// assert_eq!(resp.headers()["Content-Type"], "application/octet-stream"); +// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b"foo"); +// } + +// #[test] +// fn string_content_type() { +// let resp = String::from("foo").into_response(); +// assert_eq!(resp.headers()["Content-Type"], "text/plain; charset=utf-8"); +// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b"foo"); +// } + +// #[test] +// fn json_content_type() { +// use std::collections::BTreeMap; + +// let mut map = BTreeMap::new(); +// map.insert(Some("a"), 2); +// map.insert(Some("b"), 4); +// map.insert(None, 6); + +// let resp = json(map); +// assert_eq!( +// resp.status(), +// http::status::StatusCode::INTERNAL_SERVER_ERROR +// ); +// assert_eq!(block_on(resp.into_body().into_vec()).unwrap(), b""); + +// let mut map = BTreeMap::new(); +// map.insert("a", 2); +// map.insert("b", 4); +// map.insert("c", 6); + +// let resp = json(map); +// assert_eq!(resp.status(), http::status::StatusCode::OK); +// assert_eq!( +// block_on(resp.into_body().into_vec()).unwrap(), +// br##"{"a":2,"b":4,"c":6}"## +// ); +// } diff --git a/tests/route_middleware.rs b/tests/route_middleware.rs index ef46ddb95..402f79082 100644 --- a/tests/route_middleware.rs +++ b/tests/route_middleware.rs @@ -1,9 +1,12 @@ -use futures::future::BoxFuture; use http_types::headers::HeaderName; use std::convert::TryInto; use tide::http::{self, Method}; use tide::Middleware; +use test_utils::BoxFuture; + +mod test_utils; + #[derive(Debug)] struct TestMiddleware(HeaderName, &'static str); diff --git a/tests/test_utils.rs b/tests/test_utils.rs index 6fff802f5..f7687a326 100644 --- a/tests/test_utils.rs +++ b/tests/test_utils.rs @@ -1,5 +1,15 @@ use portpicker::pick_unused_port; +use std::future::Future; +use std::pin::Pin; + +/// An owned dynamically typed [`Future`] for use in cases where you can't +/// statically type your result or need to add some indirection. +#[allow(dead_code)] +pub type BoxFuture<'a, T> = Pin + Send + 'a>>; + +/// Find an unused port. +#[allow(dead_code)] pub async fn find_port() -> u16 { pick_unused_port().expect("No ports free") } diff --git a/tests/wildcard.rs b/tests/wildcard.rs index e09c0d103..f4dcea81c 100644 --- a/tests/wildcard.rs +++ b/tests/wildcard.rs @@ -1,225 +1,225 @@ -// use futures::executor::block_on; -// use http_service::Body; -// use http_service_mock::make_server; -// use tide::{error::ResultExt, Request}; - -// async fn add_one(cx: Request<()>) -> Result { -// let num: i64 = cx.param("num").client_err()?; -// Ok((num + 1).to_string()) -// } - -// async fn add_two(cx: Request<()>) -> 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: Request<()>) -> Result { -// let path: String = cx.param("path").client_err()?; -// Ok(path) -// } - -// async fn echo_empty(cx: Request<()>) -> Result { -// let path: String = cx.param("").client_err()?; -// Ok(path) -// } - -// #[test] -// fn wildcard() { -// let mut app = tide::Server::new(); -// app.at("/add_one/:num").get(add_one); -// let mut server = make_server(app.into_http_service()).unwrap(); - -// let req = http::Request::get("/add_one/3") -// .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"4"); - -// let req = http::Request::get("/add_one/-7") -// .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"-6"); -// } - -// #[test] -// fn invalid_segment_error() { -// let mut app = tide::Server::new(); -// app.at("/add_one/:num").get(add_one); -// let mut server = make_server(app.into_http_service()).unwrap(); - -// let req = http::Request::get("/add_one/a") -// .body(Body::empty()) -// .unwrap(); -// let res = server.simulate(req).unwrap(); -// assert_eq!(res.status(), 400); -// } - -// #[test] -// fn not_found_error() { -// let mut app = tide::Server::new(); -// app.at("/add_one/:num").get(add_one); -// let mut server = make_server(app.into_http_service()).unwrap(); - -// let req = http::Request::get("/add_one/").body(Body::empty()).unwrap(); -// let res = server.simulate(req).unwrap(); -// assert_eq!(res.status(), 404); -// } - -// #[test] -// fn wildpath() { -// let mut app = tide::Server::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::Server::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::Server::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::Server::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::Server::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::Server::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::Server::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"); -// } +// use async_std::task::block_on; +// use http_service::Body; +// use http_service_mock::make_server; +// use tide::{error::ResultExt, Request}; + +// async fn add_one(cx: Request<()>) -> Result { +// let num: i64 = cx.param("num").client_err()?; +// Ok((num + 1).to_string()) +// } + +// async fn add_two(cx: Request<()>) -> 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: Request<()>) -> Result { +// let path: String = cx.param("path").client_err()?; +// Ok(path) +// } + +// async fn echo_empty(cx: Request<()>) -> Result { +// let path: String = cx.param("").client_err()?; +// Ok(path) +// } + +// #[test] +// fn wildcard() { +// let mut app = tide::Server::new(); +// app.at("/add_one/:num").get(add_one); +// let mut server = make_server(app.into_http_service()).unwrap(); + +// let req = http::Request::get("/add_one/3") +// .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"4"); + +// let req = http::Request::get("/add_one/-7") +// .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"-6"); +// } + +// #[test] +// fn invalid_segment_error() { +// let mut app = tide::Server::new(); +// app.at("/add_one/:num").get(add_one); +// let mut server = make_server(app.into_http_service()).unwrap(); + +// let req = http::Request::get("/add_one/a") +// .body(Body::empty()) +// .unwrap(); +// let res = server.simulate(req).unwrap(); +// assert_eq!(res.status(), 400); +// } + +// #[test] +// fn not_found_error() { +// let mut app = tide::Server::new(); +// app.at("/add_one/:num").get(add_one); +// let mut server = make_server(app.into_http_service()).unwrap(); + +// let req = http::Request::get("/add_one/").body(Body::empty()).unwrap(); +// let res = server.simulate(req).unwrap(); +// assert_eq!(res.status(), 404); +// } + +// #[test] +// fn wildpath() { +// let mut app = tide::Server::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::Server::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::Server::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::Server::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::Server::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::Server::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::Server::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"); +// }