forked from nickel-org/nickel.rs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmount.rs
91 lines (83 loc) · 2.97 KB
/
mount.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use nickel::Nickel;
use request::Request;
use response::Response;
use middleware::{Continue, Middleware, MiddlewareResult};
use hyper::uri::RequestUri::AbsolutePath;
use std::mem;
pub trait Mountable<D> {
fn mount<S: Into<String>, M: Middleware<D>>(&mut self, mount_point: S, middleware: M);
}
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.
///
///
/// # Examples
/// ```{rust}
/// use nickel::{Nickel, StaticFilesHandler, Mountable};
/// let mut server = Nickel::new();
///
/// server.mount("/static_files/", StaticFilesHandler::new("/path/to/serve/"));
/// ```
///
/// # Panics
/// Panics if mount_point does not have a leading and trailing slash.
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> {
mount_point: String,
middleware: 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
/// the mounted middleware, but with the path rewritten so that the mount
/// point appears to be the root from the perspective of the mounted
/// middleware. This can be useful in combination with the
/// `StaticFilesMiddleware`, for example.
///
///
/// # Examples
/// ```{rust}
/// use nickel::{Nickel, StaticFilesHandler, Mount};
/// let mut server = Nickel::new();
///
/// server.utilize(
/// Mount::new("/static_files/",
/// StaticFilesHandler::new("/path/to/serve/")
/// ));
/// ```
///
/// # Panics
/// Panics if mount_point does not have a leading and trailing slash.
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('/')) =>
Mount {
mount_point: mount_point,
middleware: middleware
},
_ => panic!("Mount points must have a leading and trailing slash.")
}
}
}
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()..]))
},
_ => return Ok(Continue(res))
};
let original = mem::replace(&mut req.origin.uri, subpath);
let result = self.middleware.invoke(req, res);
req.origin.uri = original;
result
}
}