Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo] I wanted an empty line below.

# 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" }
Expand All @@ -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 = [
Expand Down
8 changes: 8 additions & 0 deletions tide-cors/examples/cors.rs → examples/cors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
24 changes: 7 additions & 17 deletions tide-core/src/app.rs → src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -300,14 +299,9 @@ impl<State: Sync + Send + 'static> HttpService for Server<State> {

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)
};

Expand All @@ -322,26 +316,22 @@ 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<State>,
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()
.method(method)
.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)
}

Expand Down
26 changes: 8 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
46 changes: 26 additions & 20 deletions tide-core/src/router.rs → src/router/core.rs
Original file line number Diff line number Diff line change
@@ -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<State> {
#[derive(Default)]
pub struct Router<State> {
method_map: FnvHashMap<http::Method, MethodRouter<Box<DynEndpoint<State>>>>,
}

/// The result of routing a URL
pub(crate) struct Selection<'a, State> {
pub(crate) endpoint: &'a DynEndpoint<State>,
pub(crate) params: Params,
#[allow(missing_debug_implementations)]
pub struct Selection<'a, State> {
endpoint: &'a DynEndpoint<State>,
params: Params,
}

impl<State: 'static> Router<State> {
pub(crate) fn new() -> Router<State> {
Router {
pub(crate) fn new() -> Self {
Self {
method_map: FnvHashMap::default(),
}
}
Expand All @@ -38,30 +38,36 @@ impl<State: 'static> Router<State> {
.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: &not_found_endpoint,
params: Params::new(),
}
Selection::new(&not_found_endpoint, Params::new())
}
}
}

impl<'a, State> Selection<'a, State> {
/// Create a new Selection
pub(crate) fn new(endpoint: &'a DynEndpoint<State>, params: Params) -> Self {
Self { endpoint, params }
}

/// Break Selection into it's components
pub fn into_components(self) -> (&'a DynEndpoint<State>, Params) {
(self.endpoint, self.params)
}
}

fn not_found_endpoint<State>(_cx: Context<State>) -> BoxFuture<'static, Response> {
FutureExt::boxed(async move {
http::Response::builder()
Expand Down
5 changes: 5 additions & 0 deletions src/router/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod core;
mod route;

pub use self::core::{Router, Selection};
pub use route::Route;
8 changes: 5 additions & 3 deletions tide-core/src/route.rs → src/router/route.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{router::Router, Endpoint};
use tide_core::Endpoint;

use super::core::Router;

/// A handle to a route.
///
Expand All @@ -15,8 +17,8 @@ pub struct Route<'a, State> {
}

impl<'a, State: 'static> Route<'a, State> {
pub(crate) fn new(router: &'a mut Router<State>, path: String) -> Route<'a, State> {
Route { router, path }
pub fn new(router: &'a mut Router<State>, path: String) -> Self {
Self { router, path }
}

/// Extend the route with the given `path`.
Expand Down
4 changes: 2 additions & 2 deletions tide-cookies/src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,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);
Expand Down
11 changes: 1 addition & 10 deletions tide-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
9 changes: 3 additions & 6 deletions tide-core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,9 @@ pub struct Context<State> {
}

impl<State> Context<State> {
pub(crate) fn new(
state: Arc<State>,
request: http::Request<Body>,
route_params: Params,
) -> Context<State> {
Context {
/// Create a new Context
pub fn new(state: Arc<State>, request: http::Request<Body>, route_params: Params) -> Self {
Self {
state,
request,
route_params,
Expand Down
8 changes: 4 additions & 4 deletions tide-core/src/endpoint.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand Down Expand Up @@ -57,9 +57,6 @@ pub trait Endpoint<State>: Send + Sync + 'static {
fn call(&self, cx: Context<State>) -> Self::Fut;
}

pub(crate) type DynEndpoint<State> =
dyn (Fn(Context<State>) -> BoxFuture<'static, Response>) + 'static + Send + Sync;

impl<State, F: Send + Sync + 'static, Fut> Endpoint<State> for F
where
F: Fn(Context<State>) -> Fut,
Expand All @@ -72,3 +69,6 @@ where
FutureExt::boxed(async move { fut.await.into_response() })
}
}

/// A convenient `Result` instantiation appropriate for most endpoints.
pub type EndpointResult<T = Response> = Result<T, Error>;
Loading