Refactor path splitting in router

This commit is contained in:
Magnus Hoff 2017-10-14 15:13:03 +02:00
parent f23695312e
commit 4756441064

View file

@ -16,7 +16,7 @@ lazy_static! {
let mut lookup_map = HashMap::new(); let mut lookup_map = HashMap::new();
lookup_map.insert( lookup_map.insert(
"/_changes".to_string(), "_changes".to_string(),
Box::new(|state: &State| Box::new(|state: &State|
// TODO Use query arguments to fill in the `before` parameter below // TODO Use query arguments to fill in the `before` parameter below
Box::new(ChangesResource::new(state.clone(), None)) as BoxResource Box::new(ChangesResource::new(state.clone(), None)) as BoxResource
@ -24,31 +24,31 @@ lazy_static! {
); );
lookup_map.insert( lookup_map.insert(
"/_sitemap".to_string(), "_sitemap".to_string(),
Box::new(|state: &State| Box::new(|state: &State|
Box::new(SitemapResource::new(state.clone())) as BoxResource Box::new(SitemapResource::new(state.clone())) as BoxResource
) as ResourceFn ) as ResourceFn
); );
lookup_map.insert( lookup_map.insert(
"/_new".to_string(), "_new".to_string(),
Box::new(|state: &State| Box::new(|state: &State|
Box::new(NewArticleResource::new(state.clone(), None)) as BoxResource Box::new(NewArticleResource::new(state.clone(), None)) as BoxResource
) as ResourceFn ) as ResourceFn
); );
lookup_map.insert( lookup_map.insert(
format!("/_assets/style-{}.css", StyleCss::checksum()), format!("_assets/style-{}.css", StyleCss::checksum()),
Box::new(|_: &State| Box::new(StyleCss) as BoxResource) as ResourceFn Box::new(|_: &State| Box::new(StyleCss) as BoxResource) as ResourceFn
); );
lookup_map.insert( lookup_map.insert(
format!("/_assets/script-{}.js", ScriptJs::checksum()), format!("_assets/script-{}.js", ScriptJs::checksum()),
Box::new(|_: &State| Box::new(ScriptJs) as BoxResource) as ResourceFn Box::new(|_: &State| Box::new(ScriptJs) as BoxResource) as ResourceFn
); );
lookup_map.insert( lookup_map.insert(
format!("/_assets/amatic-sc-v9-latin-regular.woff"), format!("_assets/amatic-sc-v9-latin-regular.woff"),
Box::new(|_: &State| Box::new(AmaticFont) as BoxResource) as ResourceFn Box::new(|_: &State| Box::new(AmaticFont) as BoxResource) as ResourceFn
); );
@ -61,37 +61,33 @@ pub struct WikiLookup {
state: State state: State
} }
fn split_one(path: &str) -> Result<(::std::borrow::Cow<str>, Option<&str>), ::std::str::Utf8Error> {
let mut split = path.splitn(2, '/');
let head = split.next().expect("At least one item must be returned");
let head = percent_decode(head.as_bytes()).decode_utf8()?;
let tail = split.next();
Ok((head, tail))
}
impl WikiLookup { impl WikiLookup {
pub fn new(state: State) -> WikiLookup { pub fn new(state: State) -> WikiLookup {
WikiLookup { state } WikiLookup { state }
} }
}
impl Lookup for WikiLookup { fn reserved_lookup(&self, path: &str, _query: Option<&str>) -> <Self as Lookup>::Future {
type Resource = BoxResource; Box::new(finished(
type Error = Box<::std::error::Error + Send + Sync>; LOOKUP_MAP.get(path).map(|x| x(&self.state))
type Future = Box<Future<Item = Option<Self::Resource>, Error = Self::Error>>; ))
}
fn lookup(&self, path: &str, query: Option<&str>) -> Self::Future { fn article_lookup(&self, path: &str, query: Option<&str>) -> <Self as Lookup>::Future {
assert!(path.starts_with("/")); let (slug, tail) = match split_one(path) {
if path.starts_with("/_") {
// Reserved namespace
return Box::new(finished(
LOOKUP_MAP.get(path).map(|x| x(&self.state))
));
}
let mut split = path[1..].split('/');
let slug = split.next().expect("Always at least one element");
let slug = match percent_decode(slug.as_bytes()).decode_utf8() {
Ok(x) => x, Ok(x) => x,
Err(x) => return Box::new(failed(x.into())) Err(x) => return Box::new(failed(x.into())),
}.to_string(); };
if split.next() != None { if tail.is_some() {
// Currently disallow any URLs of the form /slug/... // Currently disallow any URLs of the form /slug/...
return Box::new(finished(None)); return Box::new(finished(None));
} }
@ -106,6 +102,7 @@ impl Lookup for WikiLookup {
let state = self.state.clone(); let state = self.state.clone();
let edit = query == Some("edit"); let edit = query == Some("edit");
let slug = slug.into_owned();
use state::SlugLookup; use state::SlugLookup;
Box::new(self.state.lookup_slug(slug.clone()) Box::new(self.state.lookup_slug(slug.clone())
@ -120,3 +117,20 @@ impl Lookup for WikiLookup {
) )
} }
} }
impl Lookup for WikiLookup {
type Resource = BoxResource;
type Error = Box<::std::error::Error + Send + Sync>;
type Future = Box<Future<Item = Option<Self::Resource>, Error = Self::Error>>;
fn lookup(&self, path: &str, query: Option<&str>) -> Self::Future {
assert!(path.starts_with("/"));
let path = &path[1..];
if path.starts_with("_") {
self.reserved_lookup(path, query)
} else {
self.article_lookup(path, query)
}
}
}