mirror of https://github.com/rwf2/Rocket.git
parent
f86b1cd775
commit
71419933a5
|
@ -191,6 +191,11 @@ fn from_form_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substruct
|
||||||
for (k, v) in ::rocket::request::FormItems($arg) {
|
for (k, v) in ::rocket::request::FormItems($arg) {
|
||||||
match k {
|
match k {
|
||||||
$arms
|
$arms
|
||||||
|
field if field == "_method" => {
|
||||||
|
/* This is a Rocket-specific field. If the user hasn't asked
|
||||||
|
* for it, just let it go by without error. This should stay
|
||||||
|
* in sync with Rocket::preprocess. */
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!(" => {}={} has no matching field in struct.",
|
println!(" => {}={} has no matching field in struct.",
|
||||||
k, v);
|
k, v);
|
||||||
|
|
|
@ -47,6 +47,12 @@ struct DefaultInput<'r> {
|
||||||
arg: Option<&'r str>,
|
arg: Option<&'r str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, FromForm)]
|
||||||
|
struct ManualMethod<'r> {
|
||||||
|
_method: Option<&'r str>,
|
||||||
|
done: bool
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Same number of arguments: simple case.
|
// Same number of arguments: simple case.
|
||||||
let task = TodoTask::from_form_string("description=Hello&completed=on");
|
let task = TodoTask::from_form_string("description=Hello&completed=on");
|
||||||
|
@ -59,6 +65,13 @@ fn main() {
|
||||||
let task = TodoTask::from_form_string("other=a&description=Hello&completed=on");
|
let task = TodoTask::from_form_string("other=a&description=Hello&completed=on");
|
||||||
assert!(task.is_err());
|
assert!(task.is_err());
|
||||||
|
|
||||||
|
// Ensure _method isn't required.
|
||||||
|
let task = TodoTask::from_form_string("_method=patch&description=Hello&completed=off");
|
||||||
|
assert_eq!(task, Ok(TodoTask {
|
||||||
|
description: "Hello".to_string(),
|
||||||
|
completed: false
|
||||||
|
}));
|
||||||
|
|
||||||
let form_string = &[
|
let form_string = &[
|
||||||
"password=testing", "checkbox=off", "checkbox=on", "number=10",
|
"password=testing", "checkbox=off", "checkbox=on", "number=10",
|
||||||
"checkbox=off", "textarea=", "select=a", "radio=c",
|
"checkbox=off", "textarea=", "select=a", "radio=c",
|
||||||
|
@ -79,4 +92,18 @@ fn main() {
|
||||||
assert_eq!(default, Ok(DefaultInput {
|
assert_eq!(default, Ok(DefaultInput {
|
||||||
arg: None
|
arg: None
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Ensure _method can be captured if desired.
|
||||||
|
let manual = ManualMethod::from_form_string("_method=put&done=true");
|
||||||
|
assert_eq!(manual, Ok(ManualMethod {
|
||||||
|
_method: Some("put"),
|
||||||
|
done: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
// And ignored when not present.
|
||||||
|
let manual = ManualMethod::from_form_string("done=true");
|
||||||
|
assert_eq!(manual, Ok(ManualMethod {
|
||||||
|
_method: None,
|
||||||
|
done: true
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,9 +38,14 @@ use error::Error;
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// When deriving `FromForm`, every field in the structure must implement
|
/// When deriving `FromForm`, every field in the structure must implement
|
||||||
/// [FromFormValue](trait.FromFormValue.html). If you implement `FormForm`
|
/// [FromFormValue](trait.FromFormValue.html).
|
||||||
/// yourself, use the [FormItems](struct.FormItems.html) iterator to iterate
|
///
|
||||||
/// through the form key/value pairs.
|
/// # Implementing
|
||||||
|
///
|
||||||
|
/// If you implement `FormForm` yourself, use the
|
||||||
|
/// [FormItems](struct.FormItems.html) iterator to iterate through the form
|
||||||
|
/// key/value pairs. Be aware that form fields that are typically hidden from
|
||||||
|
/// your application, such as `_method`, will be present while iterating.
|
||||||
pub trait FromForm<'f>: Sized {
|
pub trait FromForm<'f>: Sized {
|
||||||
/// The associated error to be returned when parsing fails.
|
/// The associated error to be returned when parsing fails.
|
||||||
type Error;
|
type Error;
|
||||||
|
|
|
@ -75,7 +75,7 @@ impl Rocket {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn issue_response(&self, mut response: Response, hyp_res: hyper::FreshResponse) {
|
fn issue_response(&self, mut response: Response, hyp_res: hyper::FreshResponse) {
|
||||||
// Add the 'rocket' server header, and write out the response.
|
// Add the 'rocket' server header, and write out the response.
|
||||||
// TODO: If removing Hyper, write out `Data` header too.
|
// TODO: If removing Hyper, write out `Date` header too.
|
||||||
response.set_header(header::Server("rocket".to_string()));
|
response.set_header(header::Server("rocket".to_string()));
|
||||||
|
|
||||||
match self.write_response(response, hyp_res) {
|
match self.write_response(response, hyp_res) {
|
||||||
|
@ -134,7 +134,8 @@ impl Rocket {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preprocess the request for Rocket-specific things. At this time, we're
|
/// Preprocess the request for Rocket-specific things. At this time, we're
|
||||||
/// only checking for _method in forms.
|
/// only checking for _method in forms. Keep this in-sync with derive_form
|
||||||
|
/// when preprocessing form fields.
|
||||||
fn preprocess_request(&self, req: &mut Request, data: &Data) {
|
fn preprocess_request(&self, req: &mut Request, data: &Data) {
|
||||||
// Check if this is a form and if the form contains the special _method
|
// Check if this is a form and if the form contains the special _method
|
||||||
// field which we use to reinterpret the request's method.
|
// field which we use to reinterpret the request's method.
|
||||||
|
@ -176,7 +177,7 @@ impl Rocket {
|
||||||
// convince it to give us another mutable reference.
|
// convince it to give us another mutable reference.
|
||||||
// FIXME: Pay the cost to copy Request into UnsafeCell? Pay the
|
// FIXME: Pay the cost to copy Request into UnsafeCell? Pay the
|
||||||
// cost to use RefCell? Move the call to `issue_response` here
|
// cost to use RefCell? Move the call to `issue_response` here
|
||||||
// to move Request and move directly into a RefCell?
|
// to move Request and move directly into an UnsafeCell?
|
||||||
let request: &'r mut Request = unsafe {
|
let request: &'r mut Request = unsafe {
|
||||||
&mut *(request as *const Request as *mut Request)
|
&mut *(request as *const Request as *mut Request)
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
#![feature(plugin, custom_derive)]
|
||||||
|
#![plugin(rocket_codegen)]
|
||||||
|
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
use rocket::request::Form;
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct FormData {
|
||||||
|
form_data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[patch("/", data = "<form_data>")]
|
||||||
|
fn bug(form_data: Form<FormData>) -> &'static str {
|
||||||
|
assert_eq!("Form data", &form_data.get().form_data);
|
||||||
|
"OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
use rocket::testing::MockRequest;
|
||||||
|
use rocket::http::Method::*;
|
||||||
|
use rocket::http::ContentType;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn method_eval() {
|
||||||
|
let rocket = rocket::ignite().mount("/", routes![bug]);
|
||||||
|
|
||||||
|
let mut req = MockRequest::new(Patch, "/")
|
||||||
|
.header(ContentType::Form)
|
||||||
|
.body("_method=patch&form_data=Form+data");
|
||||||
|
|
||||||
|
let mut response = req.dispatch_with(&rocket);
|
||||||
|
let body_str = response.body().and_then(|b| b.into_string());
|
||||||
|
assert_eq!(body_str, Some("OK".to_string()));
|
||||||
|
}
|
Loading…
Reference in New Issue