mirror of https://github.com/rwf2/Rocket.git
Cleaned up response -> split into files. Started form example.
There's something going on with Hyper. When a 303 (see other) response is sent in response to a POST, the browser does a GET to the location header. Hyper somehow misreads the method parameter here, resulting in a route failer. I need to MITM the connection to see exactly what the browser is sending and what Hyper is receiving to see who's wrong.
This commit is contained in:
parent
cddc92f870
commit
fb8fdc3bc2
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "forms"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Sergio Benitez <sb@sergio.bz>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { path = "../../lib" }
|
||||||
|
rocket_macros = { path = "../../macros" }
|
|
@ -0,0 +1,39 @@
|
||||||
|
#![feature(plugin)]
|
||||||
|
#![plugin(rocket_macros)]
|
||||||
|
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
use rocket::Rocket;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Error as IOError;
|
||||||
|
use rocket::response::Redirect;
|
||||||
|
|
||||||
|
#[route(GET, path = "/")]
|
||||||
|
fn index() -> File {
|
||||||
|
File::open("static/index.html").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[route(GET, path = "/<file>")]
|
||||||
|
fn files(file: &str) -> Result<File, IOError> {
|
||||||
|
File::open(format!("static/{}", file))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[route(GET, path = "/user/<username>")]
|
||||||
|
fn user_page(username: &str) -> String {
|
||||||
|
format!("This is {}'s page.", username)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Actually look at form parameters.
|
||||||
|
#[route(POST, path = "/login")]
|
||||||
|
fn login() -> Result<Redirect, &'static str> {
|
||||||
|
if true {
|
||||||
|
Ok(Redirect::other("/user/some_name"))
|
||||||
|
} else {
|
||||||
|
Err("Sorry, the username and password are invalid.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let rocket = Rocket::new("localhost", 8000);
|
||||||
|
rocket.mount_and_launch("/", routes![index, files, user_page, login]);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<h1>Login</h1>
|
||||||
|
|
||||||
|
<form action="/login" method="post" accept-charset="utf-8">
|
||||||
|
Username:<input type="text" name="username">
|
||||||
|
Password:<input type="password" name="password">
|
||||||
|
<input type="submit" value="Login">
|
||||||
|
</form>
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "optional_result"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Sergio Benitez <sb@sergio.bz>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { path = "../../lib" }
|
||||||
|
rocket_macros = { path = "../../macros" }
|
|
@ -0,0 +1,23 @@
|
||||||
|
#![feature(plugin)]
|
||||||
|
#![plugin(rocket_macros)]
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
use rocket::Rocket;
|
||||||
|
use rocket::response::Redirect;
|
||||||
|
|
||||||
|
#[route(GET, path = "/users/<name>")]
|
||||||
|
fn user(name: &str) -> Result<&'static str, Redirect> {
|
||||||
|
match name {
|
||||||
|
"Sergio" => Ok("Hello, Sergio!"),
|
||||||
|
_ => Err(Redirect::to("/users/login"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[route(GET, path = "/users/login")]
|
||||||
|
fn login() -> &'static str {
|
||||||
|
"Hi! That user doesn't exist. Maybe you need to log in?"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Rocket::new("localhost", 8000).mount_and_launch("/", routes![user, login]);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "optional_result"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Sergio Benitez <sb@sergio.bz>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { path = "../../lib" }
|
||||||
|
rocket_macros = { path = "../../macros" }
|
|
@ -0,0 +1,18 @@
|
||||||
|
#![feature(plugin)]
|
||||||
|
#![plugin(rocket_macros)]
|
||||||
|
|
||||||
|
extern crate rocket;
|
||||||
|
use rocket::Rocket;
|
||||||
|
|
||||||
|
#[route(GET, path = "/users/<name>")]
|
||||||
|
fn user(name: &str) -> Option<&'static str> {
|
||||||
|
if name == "Sergio" {
|
||||||
|
Some("Hello, Sergio!")
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Rocket::new("localhost", 8000).mount_and_launch("/", routes![user]);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#![feature(str_char)]
|
#![feature(str_char)]
|
||||||
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate term_painter;
|
extern crate term_painter;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
|
@ -12,10 +13,10 @@ pub mod router;
|
||||||
|
|
||||||
pub use method::Method;
|
pub use method::Method;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use response::{Response, HypResponse, HypFresh, Responder};
|
|
||||||
pub use request::Request;
|
pub use request::Request;
|
||||||
pub use param::FromParam;
|
pub use param::FromParam;
|
||||||
pub use router::Router;
|
pub use router::Router;
|
||||||
|
pub use response::{Response, HypResponse, Responder, HypFresh};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
|
@ -27,7 +28,8 @@ use hyper::Server;
|
||||||
|
|
||||||
pub type Handler<'a> = fn(Request) -> Response<'a>;
|
pub type Handler<'a> = fn(Request) -> Response<'a>;
|
||||||
|
|
||||||
// TODO: Figure out if having Handler<'static> there is a good idea.
|
// TODO: Figure out if using 'static for Handler is a good idea.
|
||||||
|
// TODO: Merge this `Route` and route::Route, somewhow.
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub path: &'static str,
|
pub path: &'static str,
|
||||||
|
@ -35,7 +37,8 @@ pub struct Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
pub fn new(method: Method, path: &'static str, handler: Handler<'static>) -> Route {
|
pub fn new(method: Method, path: &'static str, handler: Handler<'static>)
|
||||||
|
-> Route {
|
||||||
Route {
|
Route {
|
||||||
method: method,
|
method: method,
|
||||||
path: path,
|
path: path,
|
||||||
|
@ -50,7 +53,6 @@ impl<'a> fmt::Display for Route {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct Rocket {
|
pub struct Rocket {
|
||||||
address: &'static str,
|
address: &'static str,
|
||||||
port: isize,
|
port: isize,
|
||||||
|
@ -60,9 +62,10 @@ pub struct Rocket {
|
||||||
impl HypHandler for Rocket {
|
impl HypHandler for Rocket {
|
||||||
fn handle<'a, 'k>(&'a self, req: HypRequest<'a, 'k>,
|
fn handle<'a, 'k>(&'a self, req: HypRequest<'a, 'k>,
|
||||||
res: HypResponse<'a, HypFresh>) {
|
res: HypResponse<'a, HypFresh>) {
|
||||||
|
println!("{} {:?} {:?}", White.paint("Incoming:"),
|
||||||
|
Green.paint(&req.method), Blue.paint(&req.uri));
|
||||||
if let RequestUri::AbsolutePath(uri_string) = req.uri {
|
if let RequestUri::AbsolutePath(uri_string) = req.uri {
|
||||||
if let Some(method) = Method::from_hyp(req.method) {
|
if let Some(method) = Method::from_hyp(req.method) {
|
||||||
println!("Request: {:?}", uri_string);
|
|
||||||
let uri_str = uri_string.as_str();
|
let uri_str = uri_string.as_str();
|
||||||
let route = self.router.route(method, uri_str);
|
let route = self.router.route(method, uri_str);
|
||||||
let mut response = route.map_or(Response::not_found(), |route| {
|
let mut response = route.map_or(Response::not_found(), |route| {
|
||||||
|
@ -71,11 +74,15 @@ impl HypHandler for Rocket {
|
||||||
(route.handler)(request)
|
(route.handler)(request)
|
||||||
});
|
});
|
||||||
|
|
||||||
return response.body.respond(res);
|
println!("{}", Green.paint("\t=> Dispatched request."));
|
||||||
}
|
return response.respond(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Response::not_found().body.respond(res);
|
println!("{}", Yellow.paint("\t=> Debug: Method::from_hyp failed!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{}", Red.paint("\t=> Dispatch failed. Returning 404."));
|
||||||
|
Response::not_found().respond(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,14 @@ impl Method {
|
||||||
pub fn from_hyp(method: HypMethod) -> Option<Method> {
|
pub fn from_hyp(method: HypMethod) -> Option<Method> {
|
||||||
match method {
|
match method {
|
||||||
HypMethod::Get => Some(Get),
|
HypMethod::Get => Some(Get),
|
||||||
|
HypMethod::Put => Some(Put),
|
||||||
|
HypMethod::Post => Some(Post),
|
||||||
|
HypMethod::Delete => Some(Delete),
|
||||||
|
HypMethod::Options => Some(Options),
|
||||||
|
HypMethod::Head => Some(Head),
|
||||||
|
HypMethod::Trace => Some(Trace),
|
||||||
|
HypMethod::Connect => Some(Connect),
|
||||||
|
HypMethod::Patch => Some(Patch),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
pub use hyper::server::Response as HypResponse;
|
|
||||||
pub use hyper::net::Fresh as HypFresh;
|
|
||||||
|
|
||||||
use hyper::status::StatusCode;
|
|
||||||
use hyper::header;
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::fs::File;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
pub struct Response<'a> {
|
|
||||||
pub body: Box<Responder + 'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Response<'a> {
|
|
||||||
pub fn new<T: Responder + 'a>(body: T) -> Response<'a> {
|
|
||||||
Response {
|
|
||||||
body: Box::new(body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn empty() -> Response<'a> {
|
|
||||||
Response {
|
|
||||||
body: Box::new(Empty::new(StatusCode::Ok))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn not_found() -> Response<'a> {
|
|
||||||
Response {
|
|
||||||
body: Box::new(Empty::new(StatusCode::NotFound))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn server_error() -> Response<'a> {
|
|
||||||
Response {
|
|
||||||
body: Box::new(Empty::new(StatusCode::InternalServerError))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Responder {
|
|
||||||
fn respond<'a>(&mut self, mut res: HypResponse<'a, HypFresh>);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Empty {
|
|
||||||
status: StatusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Empty {
|
|
||||||
fn new(status: StatusCode) -> Empty {
|
|
||||||
Empty {
|
|
||||||
status: status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Responder for Empty {
|
|
||||||
fn respond<'a>(&mut self, mut res: HypResponse<'a, HypFresh>) {
|
|
||||||
res.headers_mut().set(header::ContentLength(0));
|
|
||||||
*(res.status_mut()) = self.status;
|
|
||||||
|
|
||||||
let mut stream = res.start().unwrap();
|
|
||||||
stream.write_all(b"").unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Responder for &'a str {
|
|
||||||
fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
|
||||||
res.send(self.as_bytes()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Responder for String {
|
|
||||||
fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
|
||||||
res.send(self.as_bytes()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Responder for File {
|
|
||||||
fn respond<'b>(&mut self, mut res: HypResponse<'b, HypFresh>) {
|
|
||||||
let size = self.metadata().unwrap().len();
|
|
||||||
|
|
||||||
res.headers_mut().set(header::ContentLength(size));
|
|
||||||
*(res.status_mut()) = StatusCode::Ok;
|
|
||||||
|
|
||||||
let mut v = Vec::new();
|
|
||||||
self.read_to_end(&mut v).unwrap();
|
|
||||||
|
|
||||||
let mut stream = res.start().unwrap();
|
|
||||||
stream.write_all(&v).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waiting for RFC #1210: impl specialization. It's not quite stable yet.
|
|
||||||
// impl<T: Responder, E: fmt::Display + fmt::Debug> Responder for Result<T, E> {
|
|
||||||
// fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
|
||||||
// if self.is_err() {
|
|
||||||
// println!("Response error: {}", self.as_ref().err().unwrap());
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// self.as_mut().unwrap().respond(res);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
|
|
||||||
// prepend with `default` when using impl specialization
|
|
||||||
fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
|
||||||
if self.is_err() {
|
|
||||||
println!("Error: {:?}", self.as_ref().err().unwrap());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.as_mut().unwrap().respond(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Allow streamed responses.
|
|
||||||
// const CHUNK_SIZE: u32 = 4096;
|
|
||||||
// pub struct Stream<T: Read>(T);
|
|
||||||
// impl<T> Responder for Stream<T> {
|
|
||||||
// fn respond<'a>(&self, mut r: HypResponse<'a, HypFresh>) {
|
|
||||||
// r.headers_mut().set(header::TransferEncoding(vec![Encoding::Chunked]));
|
|
||||||
// *(r.status_mut()) = StatusCode::Ok;
|
|
||||||
// let mut stream = r.start();
|
|
||||||
|
|
||||||
// r.write()
|
|
||||||
// Response {
|
|
||||||
// status: StatusCode::Ok,
|
|
||||||
// headers: headers,
|
|
||||||
// body: Body::Stream(r)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
use response::*;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
pub struct Empty(StatusCode);
|
||||||
|
|
||||||
|
impl Empty {
|
||||||
|
pub fn new(status: StatusCode) -> Empty {
|
||||||
|
Empty(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Responder for Empty {
|
||||||
|
fn respond<'a>(&mut self, mut res: HypResponse<'a, HypFresh>) {
|
||||||
|
res.headers_mut().set(header::ContentLength(0));
|
||||||
|
*(res.status_mut()) = self.0;
|
||||||
|
|
||||||
|
let mut stream = res.start().unwrap();
|
||||||
|
stream.write_all(b"").unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
mod empty;
|
||||||
|
mod responder;
|
||||||
|
mod redirect;
|
||||||
|
|
||||||
|
pub use self::responder::Responder;
|
||||||
|
pub use self::empty::Empty;
|
||||||
|
pub use self::redirect::Redirect;
|
||||||
|
|
||||||
|
pub use hyper::server::Response as HypResponse;
|
||||||
|
pub use hyper::net::Fresh as HypFresh;
|
||||||
|
pub use hyper::status::StatusCode;
|
||||||
|
pub use hyper::header;
|
||||||
|
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
pub struct Response<'a>(Box<Responder + 'a>);
|
||||||
|
|
||||||
|
impl<'a> Response<'a> {
|
||||||
|
pub fn new<T: Responder + 'a>(body: T) -> Response<'a> {
|
||||||
|
Response(Box::new(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Response<'a> {
|
||||||
|
Response(Box::new(Empty::new(StatusCode::Ok)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn not_found() -> Response<'a> {
|
||||||
|
Response(Box::new(Empty::new(StatusCode::NotFound)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn server_error() -> Response<'a> {
|
||||||
|
Response(Box::new(Empty::new(StatusCode::InternalServerError)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for Response<'a> {
|
||||||
|
type Target = Box<Responder + 'a>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DerefMut for Response<'a> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Box<Responder + 'a> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
use response::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Redirect(StatusCode, String);
|
||||||
|
|
||||||
|
impl Redirect {
|
||||||
|
pub fn to(uri: &str) -> Redirect {
|
||||||
|
Redirect(StatusCode::TemporaryRedirect, String::from(uri))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn created(uri: &str) -> Redirect {
|
||||||
|
Redirect(StatusCode::Created, String::from(uri))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn other(uri: &str) -> Redirect {
|
||||||
|
Redirect(StatusCode::SeeOther, String::from(uri))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn permanent(uri: &str) -> Redirect {
|
||||||
|
Redirect(StatusCode::PermanentRedirect, String::from(uri))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Responder for Redirect {
|
||||||
|
fn respond<'b>(&mut self, mut res: HypResponse<'b, HypFresh>) {
|
||||||
|
res.headers_mut().set(header::ContentLength(0));
|
||||||
|
res.headers_mut().set(header::Location(self.1.clone()));
|
||||||
|
*(res.status_mut()) = self.0;
|
||||||
|
res.send(b"").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
use response::*;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub trait Responder {
|
||||||
|
fn respond<'a>(&mut self, mut res: HypResponse<'a, HypFresh>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Responder for &'a str {
|
||||||
|
fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
||||||
|
res.send(self.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Responder for String {
|
||||||
|
fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
||||||
|
res.send(self.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Should we set a content-type here? Safari needs text/html to render.
|
||||||
|
impl Responder for File {
|
||||||
|
fn respond<'b>(&mut self, mut res: HypResponse<'b, HypFresh>) {
|
||||||
|
let size = self.metadata().unwrap().len();
|
||||||
|
|
||||||
|
res.headers_mut().set(header::ContentLength(size));
|
||||||
|
*(res.status_mut()) = StatusCode::Ok;
|
||||||
|
|
||||||
|
let mut v = Vec::new();
|
||||||
|
self.read_to_end(&mut v).unwrap();
|
||||||
|
|
||||||
|
let mut stream = res.start().unwrap();
|
||||||
|
stream.write_all(&v).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Responder> Responder for Option<T> {
|
||||||
|
fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
||||||
|
if self.is_none() {
|
||||||
|
println!("Option is none.");
|
||||||
|
// TODO: Should this be a 404 or 500?
|
||||||
|
return Empty::new(StatusCode::NotFound).respond(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.as_mut().unwrap().respond(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
|
||||||
|
// prepend with `default` when using impl specialization
|
||||||
|
default fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
||||||
|
if self.is_err() {
|
||||||
|
println!("Error: {:?}", self.as_ref().err().unwrap());
|
||||||
|
// TODO: Should this be a 404 or 500?
|
||||||
|
return Empty::new(StatusCode::NotFound).respond(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.as_mut().unwrap().respond(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
|
||||||
|
fn respond<'b>(&mut self, res: HypResponse<'b, HypFresh>) {
|
||||||
|
match self {
|
||||||
|
&mut Ok(ref mut responder) => responder.respond(res),
|
||||||
|
&mut Err(ref mut responder) => responder.respond(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
// TODO: Allow streamed responses.
|
||||||
|
// const CHUNK_SIZE: u32 = 4096;
|
||||||
|
// pub struct Stream<T: Read>(T);
|
||||||
|
// impl<T> Responder for Stream<T> {
|
||||||
|
// fn respond<'a>(&self, mut r: HypResponse<'a, HypFresh>) {
|
||||||
|
// r.headers_mut().set(header::TransferEncoding(vec![Encoding::Chunked]));
|
||||||
|
// *(r.status_mut()) = StatusCode::Ok;
|
||||||
|
// let mut stream = r.start();
|
||||||
|
|
||||||
|
// r.write()
|
||||||
|
// Response {
|
||||||
|
// status: StatusCode::Ok,
|
||||||
|
// headers: headers,
|
||||||
|
// body: Body::Stream(r)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -42,7 +42,7 @@ impl Router {
|
||||||
let num_components = path.components().count();
|
let num_components = path.components().count();
|
||||||
if let Some(routes) = self.routes.get(&(method, num_components)) {
|
if let Some(routes) = self.routes.get(&(method, num_components)) {
|
||||||
for route in routes.iter().filter(|r| r.collides_with(uri)) {
|
for route in routes.iter().filter(|r| r.collides_with(uri)) {
|
||||||
println!("Matched {} to: {}", uri, route);
|
println!("\t=> Matched {} to: {}", uri, route);
|
||||||
if let None = matched_route {
|
if let None = matched_route {
|
||||||
matched_route = Some(route);
|
matched_route = Some(route);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use super::Collider; // :D
|
||||||
use std::path::Component;
|
use std::path::Component;
|
||||||
use Handler;
|
use Handler;
|
||||||
|
|
||||||
|
// TODO: Add ranking to routes. Give static routes higher rank by default.
|
||||||
// FIXME: Take in the handler! Or maybe keep that in `Router`?
|
// FIXME: Take in the handler! Or maybe keep that in `Router`?
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
method: Method,
|
method: Method,
|
||||||
|
@ -50,7 +51,7 @@ impl Route {
|
||||||
// FIXME: This is dirty (the comp_to_str and the RootDir thing). Might need
|
// FIXME: This is dirty (the comp_to_str and the RootDir thing). Might need
|
||||||
// to have my own wrapper arround path strings.
|
// to have my own wrapper arround path strings.
|
||||||
// FIXME: Decide whether a component has to be fully variable or not. That
|
// FIXME: Decide whether a component has to be fully variable or not. That
|
||||||
// is, whether you can have: /a<a>b/
|
// is, whether you can have: /a<a>b/ or even /<a>:<b>/
|
||||||
// TODO: Don't return a Vec...take in an &mut [&'a str] (no alloc!)
|
// TODO: Don't return a Vec...take in an &mut [&'a str] (no alloc!)
|
||||||
pub fn get_params<'a>(&self, uri: &'a str) -> Vec<&'a str> {
|
pub fn get_params<'a>(&self, uri: &'a str) -> Vec<&'a str> {
|
||||||
let mut result = Vec::with_capacity(self.component_count());
|
let mut result = Vec::with_capacity(self.component_count());
|
||||||
|
|
|
@ -58,7 +58,7 @@ fn get_route_params(ecx: &mut ExtCtxt, meta_item: &MetaItem) -> Params {
|
||||||
let params: &Vec<P<MetaItem>> = match meta_item.node {
|
let params: &Vec<P<MetaItem>> = match meta_item.node {
|
||||||
MetaItemKind::List(_, ref params) => params,
|
MetaItemKind::List(_, ref params) => params,
|
||||||
_ => ecx.span_fatal(meta_item.span,
|
_ => ecx.span_fatal(meta_item.span,
|
||||||
"incorrect use of macro. correct form is: #[demo(...)]"),
|
"Incorrect use of macro. correct form is: #[route(...)]"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure we can unwrap the k = v params.
|
// Ensure we can unwrap the k = v params.
|
||||||
|
@ -117,7 +117,6 @@ fn method_variant_to_expr(ecx: &ExtCtxt, method: Method) -> P<Expr> {
|
||||||
|
|
||||||
pub fn get_fn_params(ecx: &ExtCtxt, sp: Span, path: &str,
|
pub fn get_fn_params(ecx: &ExtCtxt, sp: Span, path: &str,
|
||||||
fn_decl: &FnDecl) -> Vec<String> {
|
fn_decl: &FnDecl) -> Vec<String> {
|
||||||
|
|
||||||
debug!("FUNCTION: {:?}", fn_decl);
|
debug!("FUNCTION: {:?}", fn_decl);
|
||||||
|
|
||||||
let mut seen = HashSet::new();
|
let mut seen = HashSet::new();
|
||||||
|
@ -125,6 +124,7 @@ pub fn get_fn_params(ecx: &ExtCtxt, sp: Span, path: &str,
|
||||||
let mut matching = false;
|
let mut matching = false;
|
||||||
|
|
||||||
// Collect all of the params in the path and insert into HashSet.
|
// Collect all of the params in the path and insert into HashSet.
|
||||||
|
// TODO: Move this logic into main library.
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
for (i, c) in path.char_indices() {
|
for (i, c) in path.char_indices() {
|
||||||
match c {
|
match c {
|
||||||
|
@ -147,6 +147,7 @@ pub fn get_fn_params(ecx: &ExtCtxt, sp: Span, path: &str,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This should stay here, though.
|
||||||
// Ensure every param in the function declaration is in `path`. Also add
|
// Ensure every param in the function declaration is in `path`. Also add
|
||||||
// each param name in the declaration to the result vector.
|
// each param name in the declaration to the result vector.
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
|
|
Loading…
Reference in New Issue