diff --git a/codegen/src/decorators/derive_form.rs b/codegen/src/decorators/derive_form.rs index a3f1df84..00182a22 100644 --- a/codegen/src/decorators/derive_form.rs +++ b/codegen/src/decorators/derive_form.rs @@ -172,7 +172,8 @@ fn from_form_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substruct $ident = match ::rocket::request::FromFormValue::from_form_value(v) { Ok(v) => Some(v), Err(e) => { - println!("\tError parsing form val '{}': {:?}", $id_str, e); + println!(" => Error parsing form val '{}': {:?}", + $id_str, e); $return_err_stmt } }; @@ -187,7 +188,8 @@ fn from_form_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substruct match k { $arms _ => { - println!("\t{}={} has no matching field in struct.", k, v); + println!(" => {}={} has no matching field in struct.", + k, v); $return_err_stmt } }; @@ -206,7 +208,7 @@ fn from_form_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substruct failure_conditions.push(quote_tokens!(cx, if $ident.is_none() && <$ty as ::rocket::request::FromFormValue>::default().is_none() { - println!("\t'{}' did not parse.", stringify!($ident)); + println!(" => '{}' did not parse.", stringify!($ident)); true } else { false } )); diff --git a/codegen/src/decorators/route.rs b/codegen/src/decorators/route.rs index 98492b54..8f2883b0 100644 --- a/codegen/src/decorators/route.rs +++ b/codegen/src/decorators/route.rs @@ -94,8 +94,11 @@ impl RouteGenerateExt for RouteParams { let expr = quote_expr!(ecx, match ::std::str::from_utf8(_req.data.as_slice()) { Ok(s) => s, - Err(_) => return ::rocket::Response::new( - ::rocket::response::Empty::bad_request("form isn't utf8")) + Err(_) => { + println!(" => Form is not valid UTF8."); + return ::rocket::Response::failed( + ::rocket::http::StatusCode::BadRequest); + } } ); @@ -226,7 +229,7 @@ fn generic_route_decorator(known_method: Option>, $query_statement $param_statements let result = $user_fn_name($fn_arguments); - ::rocket::Response::new(result) + ::rocket::Response::complete(result) } ).unwrap()); diff --git a/examples/manual_routes/src/main.rs b/examples/manual_routes/src/main.rs index 08f94225..77ba3922 100644 --- a/examples/manual_routes/src/main.rs +++ b/examples/manual_routes/src/main.rs @@ -1,6 +1,10 @@ extern crate rocket; +use std::io; +use std::fs::File; + use rocket::{Request, Response, Route, Data}; +use rocket::http::StatusCode; use rocket::request::FromParam; use rocket::http::Method::*; @@ -9,17 +13,35 @@ fn forward(_req: &Request, data: Data) -> Response<'static> { } fn hi(_req: &Request, _: Data) -> Response<'static> { - Response::new("Hello!") + Response::complete("Hello!") } fn name<'a>(req: &'a Request, _: Data) -> Response<'a> { - Response::new(req.get_param(0).unwrap_or("unnamed")) + Response::complete(req.get_param(0).unwrap_or("unnamed")) } -#[allow(dead_code)] fn echo_url<'a>(req: &'a Request, _: Data) -> Response<'a> { let param = req.uri().as_str().split_at(6).1; - Response::new(String::from_param(param)) + Response::complete(String::from_param(param)) +} + +fn upload(req: &Request, data: Data) -> Response { + if !req.content_type().is_text() { + return Response::failed(StatusCode::BadRequest); + } + + let file = File::create("upload.txt"); + if let Ok(mut file) = file { + if io::copy(&mut data.open(), &mut file).is_ok() { + return Response::complete("Upload successful."); + } + + println!(" => Failed copying."); + Response::failed(StatusCode::InternalServerError) + } else { + println!(" => Couldn't open file: {:?}", file.unwrap_err()); + Response::failed(StatusCode::InternalServerError) + } } fn main() { @@ -28,9 +50,10 @@ fn main() { let echo = Route::new(Get, "/", echo_url); let name = Route::new(Get, "/", name); + let upload_route = Route::new(Post, "/upload", upload); rocket::ignite() - .mount("/", vec![always_forward, hello]) + .mount("/", vec![always_forward, hello, upload_route]) .mount("/hello", vec![name.clone()]) .mount("/hi", vec![name]) .mount("/echo:", vec![echo]) diff --git a/examples/manual_routes/upload.txt b/examples/manual_routes/upload.txt new file mode 100644 index 00000000..e69de29b diff --git a/lib/src/http/content_type.rs b/lib/src/http/content_type.rs index 6e9984cd..f02e24ae 100644 --- a/lib/src/http/content_type.rs +++ b/lib/src/http/content_type.rs @@ -79,6 +79,9 @@ impl ContentType { } } + /// Returns true if the content type is plain text, i.e.: `text/plain`. + is_some!(is_text: Text/Plain); + /// Returns true if the content type is JSON, i.e: `application/json`. is_some!(json, is_json: Application/Json); diff --git a/lib/src/request/data.rs b/lib/src/request/data.rs index 392757ec..012eed93 100644 --- a/lib/src/request/data.rs +++ b/lib/src/request/data.rs @@ -1,7 +1,4 @@ use std::io::{BufRead, Read, Cursor, BufReader}; -use std::net::TcpStream; - -use request::Request; pub struct Data { stream: Cursor>, @@ -9,11 +6,11 @@ pub struct Data { } impl Data { - fn open(self) -> impl BufRead { + pub fn open(self) -> impl BufRead { Cursor::new(self.buffer).chain(BufReader::new(self.stream)) } - fn peek(&self) -> &[u8] { + pub fn peek(&self) -> &[u8] { &self.buffer } diff --git a/lib/src/response/failure.rs b/lib/src/response/failure.rs new file mode 100644 index 00000000..d2babd4d --- /dev/null +++ b/lib/src/response/failure.rs @@ -0,0 +1,17 @@ +use response::{ResponseOutcome, Outcome, Responder}; +use http::hyper::{FreshHyperResponse, StatusCode}; + +pub struct Failure(StatusCode); + +impl Failure { + #[inline(always)] + pub fn new(status: StatusCode) -> Failure { + Failure(status) + } +} + +impl Responder for Failure { + fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> { + Outcome::Forward((self.0, res)) + } +} diff --git a/lib/src/response/mod.rs b/lib/src/response/mod.rs index ae971612..f6ce0775 100644 --- a/lib/src/response/mod.rs +++ b/lib/src/response/mod.rs @@ -5,6 +5,7 @@ mod with_status; mod flash; mod named_file; mod stream; +mod failure; pub mod data; @@ -16,6 +17,7 @@ pub use self::flash::Flash; pub use self::named_file::NamedFile; pub use self::stream::Stream; pub use self::data::Content; +pub use self::failure::Failure; pub use outcome::Outcome; use std::fmt; @@ -33,7 +35,7 @@ pub enum Response<'a> { impl<'a> Response<'a> { #[inline(always)] - pub fn new(body: T) -> Response<'a> { + pub fn complete(body: T) -> Response<'a> { Response::Complete(Box::new(body)) } @@ -42,10 +44,15 @@ impl<'a> Response<'a> { Response::Forward(data) } + #[inline(always)] + pub fn failed(code: StatusCode) -> Response<'static> { + Response::complete(Failure::new(code)) + } + #[inline(always)] pub fn with_raw_status(status: u16, body: T) -> Response<'a> { let status_code = StatusCode::from_u16(status); - Response::new(StatusResponse::new(status_code, body)) + Response::complete(StatusResponse::new(status_code, body)) } #[doc(hidden)] diff --git a/lib/src/router/collider.rs b/lib/src/router/collider.rs index 16693e65..7c758d44 100644 --- a/lib/src/router/collider.rs +++ b/lib/src/router/collider.rs @@ -60,7 +60,7 @@ mod tests { type SimpleRoute = (Method, &'static str); fn dummy_handler(_req: &Request, _: Data) -> Response<'static> { - Response::new("hi") + Response::complete("hi") } fn m_collide(a: SimpleRoute, b: SimpleRoute) -> bool { diff --git a/lib/src/router/mod.rs b/lib/src/router/mod.rs index 2b396b93..1b61b0f1 100644 --- a/lib/src/router/mod.rs +++ b/lib/src/router/mod.rs @@ -75,7 +75,7 @@ mod test { use {Response, Request, Data}; fn dummy_handler(_req: &Request, _: Data) -> Response<'static> { - Response::new("hi") + Response::complete("hi") } fn router_with_routes(routes: &[&'static str]) -> Router {