Some updated documentation + working on domain-matching
    
    
      
        Getty Ritter
        9 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(); |