use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::io::Read;
use hyper::server::request::Request;
use hyper::uri::RequestUri;
use hyper::method::Method;
use hyper::header::ContentType;
use mime::{Mime,TopLevel,SubLevel};
use serde_json::value::Value as JsonValue;
use formdata::FormData;
#[derive(Clone, Debug)]
pub struct RequestData {
pub fields: HashMap<String, String>,
pub json: Option<JsonValue>,
}
impl RequestData {
pub fn new() -> RequestData {
RequestData {
fields: HashMap::new(),
files: HashMap::new(),
json: None,
}
}
pub fn from_request(request: &mut Request) -> Result<RequestData, Error> {
let mut formdata = FormData::new();
let mut json: Option<JsonValue> = None;
match request.method {
Method::Get | Method::Head =>
formdata.fields = try2!(get_query_parameters(request)),
_ => {
let (toplevel,sublevel) = {
let content_type: Option<&ContentType> = request.headers.get();
if content_type.is_some() {
let content_type = content_type.unwrap().clone();
let ContentType(Mime(toplevel,sublevel,_)) = content_type;
(toplevel,sublevel)
} else {
(TopLevel::Text, SubLevel::Plain)
}
};
match (toplevel,sublevel) {
(TopLevel::Multipart, SubLevel::FormData) => {
let boundary = try2!(
::formdata::get_multipart_boundary(&request.headers));
formdata = try2!(
::formdata::parse_multipart(request, boundary));
},
(TopLevel::Application, SubLevel::WwwFormUrlEncoded) => {
formdata.fields = try2!(get_body_parameters(request));
},
(TopLevel::Application, SubLevel::Json) => {
json = Some(try2!(get_json_from_body(request)));
}
_ => { }
}
}
}
let mut request_data = RequestData::from_formdata(formdata);
request_data.json = json;
Ok(request_data)
}
fn from_formdata(formdata: FormData) -> RequestData {
let mut map = RequestData::new();
for (name,value) in formdata.fields.into_iter() {
if &name[name.len()-2 ..] == "[]" {
let key=(&name[..name.len()-2]).to_owned();
let mut dummy = false; if let Entry::Occupied(o) = map.fields.entry(key.clone()) {
*o.into_mut() = format!("{}\u{2028}{}", o.get(), value);
dummy = true;
}
if dummy == false {
map.fields.insert(key, value);
}
}
else {
map.fields.insert(name, value);
}
}
for (name,file) in formdata.files.into_iter() {
let localfile = LocalFile::from_uploaded_file(file);
map.files.insert(name, localfile);
}
map
}
}
pub fn get_query_parameters(request: &Request)
-> Result<Vec<(String,String)>,Error>
{
let pqf: &String = match request.uri {
RequestUri::AbsolutePath(ref path) => path,
_ => return Err(new_error!(Kind::UnsupportedUriFormat,
"non-AbsolutePath format detected"))
};
let url = try2!(::url::Url::parse( &*format!("http://host{}", pqf) ));
Ok(url.query_pairs()
.map(|(a,b)| (a.into_owned(), b.into_owned()))
.collect())
}
pub fn get_body_parameters(request: &mut Request)
-> Result<Vec<(String,String)>,Error>
{
let mut body: Vec<u8> = Vec::new();
try2!( request.read_to_end(&mut body),
"Unable to read request body" );
let url = try2!(::url::Url::parse( &*format!("http://host?{}",
try2!(::std::str::from_utf8(&*body))) ));
Ok(url.query_pairs()
.map(|(a,b)| (a.into_owned(), b.into_owned()))
.collect())
}
fn get_json_from_body(request: &mut Request) -> Result<JsonValue, Error>
{
let mut body: Vec<u8> = Vec::new();
try2!( request.read_to_end(&mut body),
"Unable to read request body" );
::serde_json::from_str( &*try2!(String::from_utf8(body)) ).map_err(|e| From::from(e))
}