Skip to content

Commit

Permalink
Auto merge of #280 - Ryman:only_server_data, r=cburgdorf
Browse files Browse the repository at this point in the history
feat(server): shared data between requests and plugins for Response

I've ripped out the core from #272 and decided we should just push separate crates for now until the implementation for Session/Cookies has settled. This allows more breaking changes to the session/cookies implementations as we experiment without requiring a load of version bumps to nickel itself. It's more work for us to manage, but should be better for users 👍 

I've also added a default type for the typeparam, so breakage in client crates should be minimal (until they start using the dataparam!) and only really affect people who've written library level stuff.

r? @cburgdorf @simonpersson
  • Loading branch information
homu committed Sep 10, 2015
2 parents a340fb5 + fc35544 commit dabfce8
Show file tree
Hide file tree
Showing 21 changed files with 276 additions and 198 deletions.
6 changes: 3 additions & 3 deletions examples/macro_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ struct Person {
}

//this is an example middleware function that just logs each request
fn logger<'a>(request: &mut Request, response: Response<'a>) -> MiddlewareResult<'a> {
fn logger<'a, D>(request: &mut Request<D>, response: Response<'a, D>) -> MiddlewareResult<'a, D> {
println!("logging request: {:?}", request.origin.uri);
Ok(Continue(response))
}

//this is how to overwrite the default error handler to handle 404 cases with a custom view
fn custom_404<'a>(err: &mut NickelError, _req: &mut Request) -> Action {
fn custom_404<'a, D>(err: &mut NickelError<D>, _req: &mut Request<D>) -> Action {
if let Some(ref mut res) = err.stream {
if res.status() == NotFound {
let _ = res.write_all(b"<h1>Call the police!</h1>");
Expand Down Expand Up @@ -122,7 +122,7 @@ fn main() {
));

// issue #20178
let custom_handler: fn(&mut NickelError, &mut Request) -> Action = custom_404;
let custom_handler: fn(&mut NickelError<()>, &mut Request<()>) -> Action = custom_404;

server.handle_error(custom_handler);

Expand Down
4 changes: 2 additions & 2 deletions src/default_error_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use std::io::Write;
#[derive(Clone, Copy)]
pub struct DefaultErrorHandler;

impl ErrorHandler for DefaultErrorHandler {
fn handle_error(&self, err: &mut NickelError, _req: &mut Request) -> Action {
impl<D> ErrorHandler<D> for DefaultErrorHandler {
fn handle_error(&self, err: &mut NickelError<D>, _req: &mut Request<D>) -> Action {
if let Some(ref mut res) = err.stream {
let msg : &[u8] = match res.status() {
NotFound => b"Not Found",
Expand Down
13 changes: 6 additions & 7 deletions src/favicon_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use hyper::uri::RequestUri::AbsolutePath;
use hyper::method::Method::{Get, Head, Options};
use hyper::status::StatusCode;
use hyper::header;
use hyper::net;

use request::Request;
use response::Response;
Expand All @@ -18,9 +17,9 @@ pub struct FaviconHandler {
icon_path: PathBuf, // Is it useful to log where in-memory favicon came from every request?
}

impl Middleware for FaviconHandler {
fn invoke<'a, 'server>(&'a self, req: &mut Request<'a, 'server>, res: Response<'a, net::Fresh>)
-> MiddlewareResult<'a> {
impl<D> Middleware<D> for FaviconHandler {
fn invoke<'a, 'server>(&'a self, req: &mut Request<'a, 'server, D>, res: Response<'a, D>)
-> MiddlewareResult<'a, D> {
if FaviconHandler::is_favicon_request(req) {
self.handle_request(req, res)
} else {
Expand Down Expand Up @@ -53,14 +52,14 @@ impl FaviconHandler {
}

#[inline]
pub fn is_favicon_request(req: &Request) -> bool {
pub fn is_favicon_request<D>(req: &Request<D>) -> bool {
match req.origin.uri {
AbsolutePath(ref path) => &**path == "/favicon.ico",
_ => false
}
}

pub fn handle_request<'a>(&self, req: &Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
pub fn handle_request<'a, D>(&self, req: &Request<D>, mut res: Response<'a, D>) -> MiddlewareResult<'a, D> {
match req.origin.method {
Get | Head => {
self.send_favicon(req, res)
Expand All @@ -78,7 +77,7 @@ impl FaviconHandler {
}
}

pub fn send_favicon<'a, 'server>(&self, req: &Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
pub fn send_favicon<'a, D>(&self, req: &Request<D>, mut res: Response<'a, D>) -> MiddlewareResult<'a, D> {
debug!("{:?} {:?}", req.origin.method, self.icon_path.display());
res.set(MediaType::Ico);
res.send(&*self.icon)
Expand Down
7 changes: 4 additions & 3 deletions src/json_body_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ use std::io::{Read, ErrorKind};
// Plugin boilerplate
struct JsonBodyParser;
impl Key for JsonBodyParser { type Value = String; }
impl<'mw, 'conn> Plugin<Request<'mw, 'conn>> for JsonBodyParser {

impl<'mw, 'conn, D> Plugin<Request<'mw, 'conn, D>> for JsonBodyParser {
type Error = io::Error;

fn eval(req: &mut Request) -> Result<String, io::Error> {
fn eval(req: &mut Request<D>) -> Result<String, io::Error> {
let mut s = String::new();
try!(req.origin.read_to_string(&mut s));
Ok(s)
Expand All @@ -22,7 +23,7 @@ pub trait JsonBody {
fn json_as<T: Decodable>(&mut self) -> Result<T, io::Error>;
}

impl<'mw, 'conn> JsonBody for Request<'mw, 'conn> {
impl<'mw, 'conn, D> JsonBody for Request<'mw, 'conn, D> {
fn json_as<T: Decodable>(&mut self) -> Result<T, io::Error> {
self.get_ref::<JsonBodyParser>().and_then(|parsed|
json::decode::<T>(&*parsed).map_err(|err|
Expand Down
10 changes: 5 additions & 5 deletions src/macros/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ macro_rules! _middleware_inner {
use $crate::{MiddlewareResult,Responder, Response, Request};

#[inline(always)]
fn restrict<'mw, R: Responder>(r: R, res: Response<'mw>)
-> MiddlewareResult<'mw> {
fn restrict<'mw, D, R: Responder<D>>(r: R, res: Response<'mw, D>)
-> MiddlewareResult<'mw, D> {
res.send(r)
}

// Inference fails due to thinking it's a (&Request, Response) with
// different mutability requirements
#[inline(always)]
fn restrict_closure<F>(f: F) -> F
fn restrict_closure<F, D>(f: F) -> F
where F: for<'r, 'mw, 'conn>
Fn(&'r mut Request<'mw, 'conn>, Response<'mw>)
-> MiddlewareResult<'mw> + Send + Sync { f }
Fn(&'r mut Request<'mw, 'conn, D>, Response<'mw, D>)
-> MiddlewareResult<'mw, D> + Send + Sync { f }

restrict_closure(move |as_pat!($req), $res_binding| {
restrict(as_block!({$($b)+}), $res)
Expand Down
38 changes: 19 additions & 19 deletions src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use hyper::net;

pub use self::Action::{Continue, Halt};

pub type MiddlewareResult<'mw> = Result<Action<Response<'mw, net::Fresh>,
Response<'mw, net::Streaming>>,
NickelError<'mw>>;
pub type MiddlewareResult<'mw, D> = Result<Action<Response<'mw, D, net::Fresh>,
Response<'mw, D, net::Streaming>>,
NickelError<'mw, D>>;

pub enum Action<T=(), U=()> {
Continue(T),
Expand All @@ -16,43 +16,43 @@ pub enum Action<T=(), U=()> {

// the usage of + Send is weird here because what we really want is + Static
// but that's not possible as of today. We have to use + Send for now.
pub trait Middleware: Send + 'static + Sync {
fn invoke<'mw, 'conn>(&'mw self, _req: &mut Request<'mw, 'conn>, res: Response<'mw, net::Fresh>) -> MiddlewareResult<'mw> {
pub trait Middleware<D>: Send + 'static + Sync {
fn invoke<'mw, 'conn>(&'mw self, _req: &mut Request<'mw, 'conn, D>, res: Response<'mw, D, net::Fresh>) -> MiddlewareResult<'mw, D> {
Ok(Continue(res))
}
}

impl<T> Middleware for T where T: for<'r, 'mw, 'conn> Fn(&'r mut Request<'mw, 'conn>, Response<'mw>) -> MiddlewareResult<'mw> + Send + Sync + 'static {
fn invoke<'mw, 'conn>(&'mw self, req: &mut Request<'mw, 'conn>, res: Response<'mw>) -> MiddlewareResult<'mw> {
impl<T, D> Middleware<D> for T where T: for<'r, 'mw, 'conn> Fn(&'r mut Request<'mw, 'conn, D>, Response<'mw, D>) -> MiddlewareResult<'mw, D> + Send + Sync + 'static {
fn invoke<'mw, 'conn>(&'mw self, req: &mut Request<'mw, 'conn, D>, res: Response<'mw, D>) -> MiddlewareResult<'mw, D> {
(*self)(req, res)
}
}

pub trait ErrorHandler: Send + 'static + Sync {
fn handle_error(&self, &mut NickelError, &mut Request) -> Action;
pub trait ErrorHandler<D>: Send + 'static + Sync {
fn handle_error(&self, &mut NickelError<D>, &mut Request<D>) -> Action;
}

impl ErrorHandler for fn(&mut NickelError, &mut Request) -> Action {
fn handle_error(&self, err: &mut NickelError, req: &mut Request) -> Action {
impl<D: 'static> ErrorHandler<D> for fn(&mut NickelError<D>, &mut Request<D>) -> Action {
fn handle_error(&self, err: &mut NickelError<D>, req: &mut Request<D>) -> Action {
(*self)(err, req)
}
}

pub struct MiddlewareStack {
handlers: Vec<Box<Middleware + Send + Sync>>,
error_handlers: Vec<Box<ErrorHandler + Send + Sync>>
pub struct MiddlewareStack<D=()> {
handlers: Vec<Box<Middleware<D> + Send + Sync>>,
error_handlers: Vec<Box<ErrorHandler<D> + Send + Sync>>
}

impl MiddlewareStack {
pub fn add_middleware<T: Middleware> (&mut self, handler: T) {
impl<D: 'static> MiddlewareStack<D> {
pub fn add_middleware<T: Middleware<D>> (&mut self, handler: T) {
self.handlers.push(Box::new(handler));
}

pub fn add_error_handler<T: ErrorHandler> (&mut self, handler: T) {
pub fn add_error_handler<T: ErrorHandler<D>> (&mut self, handler: T) {
self.error_handlers.push(Box::new(handler));
}

pub fn invoke<'mw, 'conn>(&'mw self, mut req: Request<'mw, 'conn>, mut res: Response<'mw>) {
pub fn invoke<'mw, 'conn>(&'mw self, mut req: Request<'mw, 'conn, D>, mut res: Response<'mw, D>) {
for handler in self.handlers.iter() {
match handler.invoke(&mut req, res) {
Ok(Halt(res)) => {
Expand Down Expand Up @@ -92,7 +92,7 @@ impl MiddlewareStack {
}
}

pub fn new () -> MiddlewareStack {
pub fn new () -> MiddlewareStack<D> {
MiddlewareStack{
handlers: Vec::new(),
error_handlers: Vec::new()
Expand Down
22 changes: 11 additions & 11 deletions src/mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use hyper::uri::RequestUri::AbsolutePath;

use std::mem;

pub trait Mountable {
fn mount<S: Into<String>, M: Middleware>(&mut self, mount_point: S, middleware: M);
pub trait Mountable<D> {
fn mount<S: Into<String>, M: Middleware<D>>(&mut self, mount_point: S, middleware: M);
}

impl Mountable for Nickel {
///
impl<D> Mountable<D> for Nickel<D>
where D: Send + Sync + 'static {
/// A trait that makes mounting more convenient. Works the same as
/// manually adding a `Mount` middleware.
///
Expand All @@ -27,17 +27,17 @@ impl Mountable for Nickel {
///
/// # Panics
/// Panics if mount_point does not have a leading and trailing slash.
fn mount<S: Into<String>, M: Middleware>(&mut self, mount_point: S, middleware: M) {
fn mount<S: Into<String>, M: Middleware<D>>(&mut self, mount_point: S, middleware: M) {
self.utilize(Mount::new(mount_point, middleware));
}
}

pub struct Mount<M: Middleware> {
pub struct Mount<M> {
mount_point: String,
middleware: M
}

impl<M: Middleware> Mount<M> {
impl<M> Mount<M> {
///
/// Creates a new middleware that mounts a middleware at a mount point.
/// An incoming request that matches the mount point will be forwareded to
Expand All @@ -63,7 +63,7 @@ impl<M: Middleware> Mount<M> {
pub fn new<S: Into<String>>(mount_point: S, middleware: M) -> Mount<M> {
let mount_point: String = mount_point.into();
match (mount_point.chars().last(), mount_point.chars().nth(0)) {
(Some('/'), Some('/')) =>
(Some('/'), Some('/')) =>
Mount {
mount_point: mount_point,
middleware: middleware
Expand All @@ -73,9 +73,9 @@ impl<M: Middleware> Mount<M> {
}
}

impl<M: Middleware> Middleware for Mount<M> {
fn invoke<'mw, 'conn>(&'mw self, req: &mut Request<'mw, 'conn>, res: Response<'mw>)
-> MiddlewareResult<'mw> {
impl<D, M: Middleware<D>> Middleware<D> for Mount<M> {
fn invoke<'mw, 'conn>(&'mw self, req: &mut Request<'mw, 'conn, D>, res: Response<'mw, D>)
-> MiddlewareResult<'mw, D> {
let subpath = match req.origin.uri {
AbsolutePath(ref path) if path.starts_with(&*self.mount_point) => {
AbsolutePath(format!("/{}", &path[self.mount_point.len()..]))
Expand Down
37 changes: 24 additions & 13 deletions src/nickel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,41 @@ use default_error_handler::DefaultErrorHandler;

/// Nickel is the application object. It's the surface that
/// holds all public APIs.
pub struct Nickel{
middleware_stack: MiddlewareStack,
pub struct Nickel<D: Sync + Send + 'static = ()> {
middleware_stack: MiddlewareStack<D>,
data: D
}

impl HttpRouter for Nickel {
fn add_route<M: Into<Matcher>, H: Middleware>(&mut self, method: Method, matcher: M, handler: H) -> &mut Self {
impl<D: Sync + Send + 'static> HttpRouter<D> for Nickel<D> {
fn add_route<M: Into<Matcher>, H: Middleware<D>>(&mut self, method: Method, matcher: M, handler: H) -> &mut Self {
let mut router = Router::new();
router.add_route(method, matcher, handler);
self.utilize(router);
self
}
}

impl Nickel {
impl Nickel<()> {
/// Creates an instance of Nickel with default error handling.
pub fn new() -> Nickel {
pub fn new() -> Nickel<()> {
Nickel::with_data(())
}
}

impl<D: Sync + Send + 'static> Nickel<D> {
/// Creates an instance of Nickel with default error handling and custom data.
pub fn with_data(data: D) -> Nickel<D> {
let mut middleware_stack = MiddlewareStack::new();

// Hook up the default error handler by default. Users are
// free to cancel it out from their custom error handler if
// they don't like the default behaviour.
middleware_stack.add_error_handler(DefaultErrorHandler);

Nickel { middleware_stack: middleware_stack }
Nickel {
middleware_stack: middleware_stack,
data: data
}
}

/// Registers a middleware handler which will be invoked among other middleware
Expand All @@ -57,7 +68,7 @@ impl Nickel {
/// });
/// # }
/// ```
pub fn utilize<T: Middleware>(&mut self, handler: T){
pub fn utilize<T: Middleware<D>>(&mut self, handler: T){
self.middleware_stack.add_middleware(handler);
}

Expand All @@ -77,7 +88,7 @@ impl Nickel {
/// use nickel::{NickelError, Action};
/// use nickel::status::StatusCode::NotFound;
///
/// fn error_handler(err: &mut NickelError, _req: &mut Request) -> Action {
/// fn error_handler<D>(err: &mut NickelError<D>, _req: &mut Request<D>) -> Action {
/// if let Some(ref mut res) = err.stream {
/// if res.status() == NotFound {
/// let _ = res.write_all(b"<h1>Call the police!</h1>");
Expand All @@ -90,12 +101,12 @@ impl Nickel {
///
/// let mut server = Nickel::new();
///
/// let ehandler: fn(&mut NickelError, &mut Request) -> Action = error_handler;
/// let ehandler: fn(&mut NickelError<()>, &mut Request<()>) -> Action = error_handler;
///
/// server.handle_error(ehandler)
/// # }
/// ```
pub fn handle_error<T: ErrorHandler>(&mut self, handler: T){
pub fn handle_error<T: ErrorHandler<D>>(&mut self, handler: T){
self.middleware_stack.add_error_handler(handler);
}

Expand All @@ -118,7 +129,7 @@ impl Nickel {
/// server.utilize(router);
/// }
/// ```
pub fn router() -> Router {
pub fn router() -> Router<D> {
Router::new()
}

Expand All @@ -140,7 +151,7 @@ impl Nickel {
(StatusCode::NotFound, "File Not Found")
});

let server = Server::new(self.middleware_stack);
let server = Server::new(self.middleware_stack, self.data);
let listener = server.serve(addr).unwrap();

println!("Listening on http://{}", listener.socket);
Expand Down
Loading

0 comments on commit dabfce8

Please sign in to comment.