Some updated documentation + working on domain-matching
Getty Ritter
8 years ago
4 | 4 | authors = ["Getty Ritter <gdritter@galois.com>"] |
5 | 5 | |
6 | 6 | [dependencies] |
7 |
hyper = " |
|
7 | hyper = "0.8.0" |
32 | 32 | host: which host to forward to; defaults to "localhost" |
33 | 33 | port: which port to forward to; defaults to "80" |
34 | 34 | conf: which path to forward to; defaults to "/dev/null" |
35 | resp: which HTTP response to issue; defaults to 303 | |
35 | 36 | ~~~ |
36 | 37 | |
37 | 38 | These are interpreted as follows: |
40 | 41 | both of them default to accepting anything, and both of them |
41 | 42 | allow their values to have the wildcard character `*`. |
42 | 43 | |
43 | - The `mode` field tells us _how_ to forward requests: right now, | |
44 | it can only contain the values `http` or `aloys`. If the mode is | |
45 | `http`, then Aloysius will forward the HTTP request to the server | |
46 | listening on the host `host` and the port `port`. If the mode is | |
47 | `aloys`, then Aloysius will recursively check the configuration | |
48 | directory at `conf`. | |
44 | - The `mode` field tells us _how_ to forward requests. There are | |
45 | three possible forwarding modes: | |
46 | - If the mode is `http`, then Aloysius will forward the HTTP | |
47 | request to the server listening on the host `host` and the | |
48 | port `port`. | |
49 | - If the mode is `aloys`, then Aloysius will recursively check | |
50 | the configuration directory at `conf`. | |
51 | - If the mode is `redir`, then Aloysius will respond with an | |
52 | HTTP response code as indicated in `resp` and redirect to | |
53 | the host as indicated in `host`. | |
49 | 54 | |
50 | 55 | ## Example Setups |
51 | 56 |
1 |
/home/gdritter/projects/ |
|
1 | /home/gdritter/projects/personal/httputils/sample/secondary_conf |
3 | 3 | |
4 | 4 | /// An `AloysError` is one of the errors that can occur in |
5 | 5 | /// the course of running an Aloys server. This might be |
6 |
/// an `IOError` from |
|
6 | /// an `IOError` from the stdlib, a `HyperError` from | |
7 | /// the hyper library, or an `AloysError` from us. | |
7 | 8 | #[derive(Debug)] |
8 | 9 | pub enum AloysError { |
9 | 10 | IOError(std::io::Error), |
11 | 12 | AloysError(String), |
12 | 13 | } |
13 | 14 | |
15 | /// Convenience function for constructing an `AloysError`. | |
14 | 16 | pub fn aloys_error<A>(s: String) -> Result<A, AloysError> { |
15 | 17 | Err(AloysError::AloysError(s)) |
16 | 18 | } |
35 | 35 | } |
36 | 36 | } |
37 | 37 | |
38 | pub fn path_for<'a>(req: &'a Request) -> Option<&'a str> { | |
38 | /// Get the absolute path of a URI, if possible. | |
39 | pub fn path_for<'a>(req: &'a Request) -> Option<String> { | |
39 | 40 | if let RequestUri::AbsolutePath(ref s) = req.uri { |
40 |
Some(s |
|
41 | Some(s.to_string()) | |
42 | } else if let RequestUri::AbsoluteUri(ref url) = req.uri { | |
43 | url.serialize_path() | |
41 | 44 | } else { |
42 | 45 | None |
43 | 46 | } |
44 | 47 | } |
48 | ||
49 | pub fn domain_for<'a>(req: &'a Request) -> Option<&'a str> { | |
50 | if let RequestUri::AbsoluteUri(ref url) = req.uri { | |
51 | url.domain() | |
52 | } else { | |
53 | None | |
54 | } | |
55 | } |
15 | 15 | |
16 | 16 | use error::{AloysError,aloys_error}; |
17 | 17 | use matching::do_match; |
18 |
use helper::{path_for, |
|
18 | use helper::{path_for,domain_for,with_file}; | |
19 | 19 | |
20 | 20 | #[derive(Debug, Clone)] |
21 | 21 | enum Delegate { |
43 | 43 | } |
44 | 44 | |
45 | 45 | impl Routes { |
46 | /// Take a path and load the route specifications contained there. | |
46 | 47 | fn load_paths(dir: &Path) -> Result<Routes,AloysError> { |
47 | 48 | let mut routes = vec![]; |
48 | 49 | for entry in try!(read_dir(dir)) { |
52 | 53 | Ok(Routes { routes: routes }) |
53 | 54 | } |
54 | 55 | |
56 | /// Given a request route it appropriately, or raise an error. | |
55 | 57 | fn dispatch(&self, req: &Request, res: Response<Fresh>) { |
56 | 58 | match self.find_delegate(&req) { |
57 | 59 | Some(delegate) => delegate.run(req, res), |
65 | 67 | for d in self.routes.iter() { |
66 | 68 | let mut matches = true; |
67 | 69 | if let Some(ref d) = d.for_domain { |
68 | // matches = matches && do_match(d, domain_for(req)); | |
70 | if let Some(domain) = domain_for(req) { | |
71 | matches = matches && do_match(d, domain); | |
72 | } | |
69 | 73 | } |
70 | 74 | if let Some(ref p) = d.for_path { |
71 | 75 | if let Some(req_path) = path_for(req) { |
72 |
matches = matches && do_match(p, |
|
76 | matches = matches && do_match(p, &req_path); | |
73 | 77 | } else { |
74 | 78 | matches = false; |
75 | 79 | } |
76 | 80 | } |
77 | 81 | if matches { |
82 | println!("using {:?}", d.conf_at); | |
78 | 83 | return Some(&d.delegate_to); |
79 | 84 | } |
80 | 85 | } |
90 | 95 | |
91 | 96 | impl RouteSpec { |
92 | 97 | fn from_path(dir: &Path) -> Result<RouteSpec,AloysError> { |
98 | println!("at dir {:?}", dir); | |
93 | 99 | let path = with_file(&dir.join("path"), |
94 | 100 | None, |
95 | 101 | |s| Some(s)); |
137 | 143 | &Delegate::Forward(ref fwd) => { |
138 | 144 | let _ = res.send(format!("[forward to {:?}:{:?}]", |
139 | 145 | fwd.domn, |
140 |
fwd.port |
|
146 | fwd.port, | |
147 | ).as_bytes()); | |
141 | 148 | }, |
142 | 149 | &Delegate::Defer(ref rts) => { |
143 | 150 | rts.dispatch(req, res); |
1 | 1 | /// Find out whether the `spec_str` matches the `string_str`. |
2 | 2 | /// The former can contain the wildcard character `*`. |
3 | /// | |
4 | /// # Examples | |
5 | /// | |
6 | /// ``` | |
7 | /// assert!(do_match("foo", "foo")); | |
8 | /// assert!(do_match("*o", "foo")); | |
9 | /// assert!(do_match("f*o", "foo")); | |
10 | /// assert!(do_match("f*", "foo")); | |
11 | /// ``` | |
3 | 12 | pub fn do_match(spec_str: &str, string_str: &str) -> bool { |
4 | 13 | let spec = spec_str.as_bytes(); |
5 | 14 | let string = string_str.as_bytes(); |