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
use extract::{Context, Error, Extract, Immediate}; use percent_encoding; use std::borrow::Cow; use util::BufStream; fn decode(s: &str) -> Result<String, Error> { percent_encoding::percent_decode(s.as_bytes()) .decode_utf8() .map(Cow::into_owned) .map_err(|e| Error::invalid_argument(&e)) } impl<B: BufStream> Extract<B> for String { type Future = Immediate<Self>; fn extract(ctx: &Context) -> Self::Future { use codegen::Source::*; match ctx.callsite().source() { Capture(idx) => { let path = ctx.request().uri().path(); let value = ctx.captures().get(*idx, path); Immediate::result(decode(value)) } Header(header_name) => { let value = match ctx.request().headers().get(header_name) { Some(value) => value, None => { return Immediate::err(Error::missing_argument()); } }; let r = value .to_str() .map(|s| s.to_string()) .map_err(|e| Error::invalid_argument(&e)); Immediate::result(r) } QueryString => { let query = ctx.request().uri().query().unwrap_or(""); Immediate::result(decode(query)) } Body => { unimplemented!(); } Unknown => { unimplemented!(); } } } } #[cfg(test)] mod test { use super::*; #[test] fn extract() { assert_eq!("hello, world", decode("hello,%20world").unwrap()); assert!(decode("%ff").unwrap_err().is_invalid_argument()); } }