2016-08-26 08:55:11 +00:00
|
|
|
use std::io::{Read};
|
|
|
|
use std::cell::RefCell;
|
2016-08-27 01:37:28 +00:00
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
use term_painter::Color::*;
|
|
|
|
use term_painter::ToStyle;
|
2016-08-26 08:55:11 +00:00
|
|
|
|
2016-03-15 03:43:52 +00:00
|
|
|
use error::Error;
|
2016-09-08 07:02:17 +00:00
|
|
|
use param::{FromParam, FromSegments};
|
2016-07-16 04:09:08 +00:00
|
|
|
use method::Method;
|
2016-03-15 03:43:52 +00:00
|
|
|
|
2016-08-26 08:55:11 +00:00
|
|
|
use content_type::ContentType;
|
|
|
|
use hyper::uri::RequestUri as HyperRequestUri;
|
|
|
|
use hyper::header;
|
|
|
|
use router::URIBuf;
|
|
|
|
use router::URI;
|
|
|
|
use router::Route;
|
|
|
|
|
|
|
|
// Hyper stuff.
|
2016-09-12 01:57:04 +00:00
|
|
|
use request::{Cookies, HyperCookie, HyperHeaders, HyperRequest};
|
2016-08-26 08:55:11 +00:00
|
|
|
|
2016-03-22 05:04:39 +00:00
|
|
|
pub struct Request<'a> {
|
2016-07-16 04:09:08 +00:00
|
|
|
pub method: Method,
|
2016-08-26 08:55:11 +00:00
|
|
|
pub uri: URIBuf, // FIXME: Should be URI (without Hyper).
|
|
|
|
pub data: Vec<u8>, // FIXME: Don't read this! (bad Hyper.)
|
2016-09-12 01:57:04 +00:00
|
|
|
cookies: Cookies,
|
2016-08-26 08:55:11 +00:00
|
|
|
headers: HyperHeaders, // This sucks.
|
2016-09-12 01:57:04 +00:00
|
|
|
params: RefCell<Option<Vec<&'a str>>>, // This also sucks.
|
2016-03-22 05:04:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Request<'a> {
|
2016-09-12 01:57:04 +00:00
|
|
|
// FIXME: Don't do the from_param parsing here. I think. Not sure. Decide.
|
2016-09-07 06:24:20 +00:00
|
|
|
pub fn get_param<T: FromParam<'a>>(&self, n: usize) -> Result<T, Error> {
|
2016-08-26 08:55:11 +00:00
|
|
|
let params = self.params.borrow();
|
|
|
|
if params.is_none() || n >= params.as_ref().unwrap().len() {
|
2016-09-08 07:02:17 +00:00
|
|
|
debug!("{} is >= param count {}", n, params.as_ref().unwrap().len());
|
2016-08-26 08:55:11 +00:00
|
|
|
Err(Error::NoKey)
|
|
|
|
} else {
|
|
|
|
T::from_param(params.as_ref().unwrap()[n])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 01:57:04 +00:00
|
|
|
pub fn cookies<'r>(&'r self) -> &'r Cookies {
|
|
|
|
&self.cookies
|
|
|
|
}
|
|
|
|
|
2016-09-08 07:02:17 +00:00
|
|
|
/// i is the index of the first segment to consider
|
|
|
|
pub fn get_segments<'r: 'a, T: FromSegments<'a>>(&'r self, i: usize)
|
|
|
|
-> Result<T, Error> {
|
|
|
|
if i >= self.uri().segment_count() {
|
|
|
|
debug!("{} is >= segment count {}", i, self.uri().segment_count());
|
|
|
|
Err(Error::NoKey)
|
|
|
|
} else {
|
|
|
|
// TODO: Really want to do self.uri.segments().skip(i).into_inner(),
|
|
|
|
// but the std lib doesn't implement it for Skip.
|
|
|
|
let mut segments = self.uri.segments();
|
|
|
|
for _ in segments.by_ref().take(i) { /* do nothing */ }
|
|
|
|
T::from_segments(segments)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-26 08:55:11 +00:00
|
|
|
pub fn mock(method: Method, uri: &str) -> Request {
|
2016-03-22 05:04:39 +00:00
|
|
|
Request {
|
2016-08-26 08:55:11 +00:00
|
|
|
params: RefCell::new(None),
|
2016-07-16 04:09:08 +00:00
|
|
|
method: method,
|
2016-09-12 01:57:04 +00:00
|
|
|
cookies: Cookies::new(&[]),
|
2016-08-26 08:55:11 +00:00
|
|
|
uri: URIBuf::from(uri),
|
|
|
|
data: vec![],
|
|
|
|
headers: HyperHeaders::new()
|
2016-03-22 05:04:39 +00:00
|
|
|
}
|
Something works! A simple hacked-up handler, that is.
At the moment, I simply install the first route I see into the Rocket struct
directly. This is quite terrible. What's worse is that I assume that the Route's
path and handler are static! The handler, actually, does have to be static, but
its response may have whatever (valid) lifetime, though I'm not sure anything
but `static makes sense. I'll think about it.
In any case, the weird `static` restrictions need to be removed, and I need to
think about which lifetimes are safe here. IE: Must all routes be static? Can I
use a closure as a route? (that'd be neat). If so, how do we make that work?
In any case, it's nice to see SOMETHING work. Yay!
2016-03-15 07:41:22 +00:00
|
|
|
}
|
|
|
|
|
2016-08-26 08:55:11 +00:00
|
|
|
// FIXME: Get rid of Hyper.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn headers(&self) -> &HyperHeaders {
|
|
|
|
&self.headers
|
2016-03-15 03:43:52 +00:00
|
|
|
}
|
|
|
|
|
2016-08-27 12:10:29 +00:00
|
|
|
// FIXME: This should be an Option. Not all requests have content types.
|
2016-08-26 08:55:11 +00:00
|
|
|
pub fn content_type(&self) -> ContentType {
|
|
|
|
let hyp_ct = self.headers().get::<header::ContentType>();
|
|
|
|
hyp_ct.map_or(ContentType::any(), |ct| ContentType::from(&ct.0))
|
|
|
|
}
|
|
|
|
|
2016-09-08 07:02:17 +00:00
|
|
|
/// Returns the first content-type accepted by this request.
|
|
|
|
pub fn accepts(&self) -> ContentType {
|
|
|
|
let accept = self.headers().get::<header::Accept>();
|
|
|
|
accept.map_or(ContentType::any(), |accept| {
|
|
|
|
let items = &accept.0;
|
|
|
|
if items.len() < 1 {
|
|
|
|
return ContentType::any();
|
|
|
|
} else {
|
|
|
|
return ContentType::from(items[0].item.clone())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-08-26 08:55:11 +00:00
|
|
|
pub fn uri(&'a self) -> URI<'a> {
|
|
|
|
self.uri.as_uri()
|
|
|
|
}
|
|
|
|
|
2016-09-08 07:02:17 +00:00
|
|
|
// FIXME: Don't need a refcell for this.
|
2016-08-26 08:55:11 +00:00
|
|
|
pub fn set_params(&'a self, route: &Route) {
|
|
|
|
*self.params.borrow_mut() = Some(route.get_params(self.uri.as_uri()))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
pub fn set_content_type(&mut self, ct: ContentType) {
|
|
|
|
let hyper_ct = header::ContentType(ct.into());
|
|
|
|
self.headers.set::<header::ContentType>(hyper_ct)
|
|
|
|
}
|
|
|
|
|
2016-08-27 01:37:28 +00:00
|
|
|
pub fn from_hyp<'h, 'k>(hyper_req: HyperRequest<'h, 'k>)
|
|
|
|
-> Result<Request<'a>, String> {
|
2016-08-26 08:55:11 +00:00
|
|
|
let (_, h_method, h_headers, h_uri, _, mut h_body) = hyper_req.deconstruct();
|
|
|
|
|
|
|
|
let uri = match h_uri {
|
|
|
|
HyperRequestUri::AbsolutePath(s) => URIBuf::from(s),
|
2016-08-27 01:37:28 +00:00
|
|
|
_ => return Err(format!("Bad URI: {}", h_uri))
|
|
|
|
};
|
|
|
|
|
|
|
|
let method = match Method::from_hyp(&h_method) {
|
|
|
|
Some(m) => m,
|
|
|
|
_ => return Err(format!("Bad method: {}", h_method))
|
2016-08-26 08:55:11 +00:00
|
|
|
};
|
|
|
|
|
2016-09-12 01:57:04 +00:00
|
|
|
let cookies = match h_headers.get::<HyperCookie>() {
|
|
|
|
// TODO: What to do about key?
|
|
|
|
Some(cookie) => cookie.to_cookie_jar(&[]),
|
|
|
|
None => Cookies::new(&[])
|
|
|
|
};
|
|
|
|
|
2016-08-26 08:55:11 +00:00
|
|
|
// FIXME: GRRR.
|
|
|
|
let mut data = vec![];
|
|
|
|
h_body.read_to_end(&mut data).unwrap();
|
|
|
|
|
2016-08-27 01:37:28 +00:00
|
|
|
let request = Request {
|
2016-08-26 08:55:11 +00:00
|
|
|
params: RefCell::new(None),
|
2016-08-27 01:37:28 +00:00
|
|
|
method: method,
|
2016-09-12 01:57:04 +00:00
|
|
|
cookies: cookies,
|
2016-08-26 08:55:11 +00:00
|
|
|
uri: uri,
|
|
|
|
data: data,
|
|
|
|
headers: h_headers,
|
2016-08-27 01:37:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(request)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'r> fmt::Display for Request<'r> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{} {}", Green.paint(&self.method), Blue.paint(&self.uri))
|
2016-03-15 03:43:52 +00:00
|
|
|
}
|
|
|
|
}
|