mirror of https://github.com/rwf2/Rocket.git
Remove Session in favor of private cookies. New testing API.
Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
This commit is contained in:
parent
504a7fe583
commit
b8ba7b855f
11
Cargo.toml
11
Cargo.toml
|
@ -8,28 +8,25 @@ members = [
|
|||
"contrib/",
|
||||
"examples/cookies",
|
||||
"examples/errors",
|
||||
"examples/extended_validation",
|
||||
"examples/forms",
|
||||
"examples/form_validation",
|
||||
"examples/hello_person",
|
||||
"examples/query_params",
|
||||
"examples/hello_world",
|
||||
"examples/manual_routes",
|
||||
"examples/optional_redirect",
|
||||
"examples/optional_result",
|
||||
"examples/redirect",
|
||||
"examples/static_files",
|
||||
"examples/todo",
|
||||
"examples/content_types",
|
||||
"examples/hello_ranks",
|
||||
"examples/ranking",
|
||||
"examples/testing",
|
||||
"examples/from_request",
|
||||
"examples/request_guard",
|
||||
"examples/stream",
|
||||
"examples/json",
|
||||
"examples/msgpack",
|
||||
"examples/handlebars_templates",
|
||||
"examples/form_kitchen_sink",
|
||||
"examples/config",
|
||||
"examples/hello_alt_methods",
|
||||
"examples/raw_upload",
|
||||
"examples/pastebin",
|
||||
"examples/state",
|
||||
|
@ -37,6 +34,6 @@ members = [
|
|||
"examples/uuid",
|
||||
"examples/session",
|
||||
"examples/raw_sqlite",
|
||||
"examples/hello_tls",
|
||||
"examples/tls",
|
||||
"examples/fairings",
|
||||
]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use rocket::{self, State};
|
||||
use rocket::fairing::AdHoc;
|
||||
use rocket::config::{self, Config, Environment};
|
||||
use rocket::http::{Method, Status};
|
||||
use rocket::http::Status;
|
||||
use rocket::LoggingLevel;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
|
||||
struct LocalConfig(Config);
|
||||
|
||||
|
@ -55,8 +55,6 @@ pub fn test_config(environment: Environment) {
|
|||
// environment in `ignite()`. We'll read this back in the handler to config.
|
||||
::std::env::set_var("ROCKET_ENV", environment.to_string());
|
||||
|
||||
// FIXME: launch fairings aren't run during tests since...the Rocket isn't
|
||||
// being launch
|
||||
let rocket = rocket::ignite()
|
||||
.attach(AdHoc::on_attach(|rocket| {
|
||||
println!("Attaching local config.");
|
||||
|
@ -65,7 +63,7 @@ pub fn test_config(environment: Environment) {
|
|||
}))
|
||||
.mount("/", routes![check_config]);
|
||||
|
||||
let mut request = MockRequest::new(Method::Get, "/check_config");
|
||||
let response = request.dispatch_with(&rocket);
|
||||
let client = Client::new(rocket).unwrap();
|
||||
let response = client.get("/check_config").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::rocket;
|
|||
use super::serde_json;
|
||||
use super::Person;
|
||||
use rocket::http::{Accept, ContentType, Header, MediaType, Method, Status};
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
|
||||
fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String)
|
||||
where H: Into<Header<'static>>
|
||||
|
@ -10,9 +10,9 @@ fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String)
|
|||
let rocket = rocket::ignite()
|
||||
.mount("/hello", routes![super::get_hello, super::post_hello])
|
||||
.catch(errors![super::not_found]);
|
||||
let mut request = MockRequest::new(method, uri).header(header);
|
||||
let mut response = request.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket).unwrap();
|
||||
let mut response = client.req(method, uri).header(header).dispatch();
|
||||
assert_eq!(response.status(), status);
|
||||
assert_eq!(response.body_string(), Some(body));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::*;
|
||||
use rocket_contrib::Template;
|
||||
|
||||
|
@ -9,11 +9,12 @@ const TEMPLATE_ROOT: &'static str = "templates/";
|
|||
|
||||
#[test]
|
||||
fn test_submit() {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Method::Post, "/submit")
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let response = client.post("/submit")
|
||||
.header(ContentType::Form)
|
||||
.body("message=Hello from Rocket!");
|
||||
let response = request.dispatch_with(&rocket);
|
||||
.body("message=Hello from Rocket!")
|
||||
.dispatch();
|
||||
|
||||
let cookie_headers: Vec<_> = response.headers().get("Set-Cookie").collect();
|
||||
let location_headers: Vec<_> = response.headers().get("Location").collect();
|
||||
|
||||
|
@ -23,33 +24,26 @@ fn test_submit() {
|
|||
}
|
||||
|
||||
fn test_body(optional_cookie: Option<Cookie<'static>>, expected_body: String) {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Method::Get, "/");
|
||||
|
||||
// Attach a cookie if one is given.
|
||||
if let Some(cookie) = optional_cookie {
|
||||
request = request.cookie(cookie);
|
||||
}
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut response = match optional_cookie {
|
||||
Some(cookie) => client.get("/").cookie(cookie).dispatch(),
|
||||
None => client.get("/").dispatch(),
|
||||
};
|
||||
|
||||
let mut response = request.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string(), Some(expected_body));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_index() {
|
||||
// Render the template with an empty context to test against.
|
||||
// Render the template with an empty context.
|
||||
let mut context: HashMap<&str, &str> = HashMap::new();
|
||||
let template = Template::show(TEMPLATE_ROOT, "index", &context).unwrap();
|
||||
|
||||
// Test the route without sending the "message" cookie.
|
||||
test_body(None, template);
|
||||
|
||||
// Render the template with a context that contains the message.
|
||||
context.insert("message", "Hello from Rocket!");
|
||||
|
||||
// Test the route with the "message" cookie.
|
||||
let cookie = Cookie::new("message", "Hello from Rocket!");
|
||||
let template = Template::show(TEMPLATE_ROOT, "index", &context).unwrap();
|
||||
test_body(Some(cookie), template);
|
||||
test_body(Some(Cookie::new("message", "Hello from Rocket!")), template);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::{Method, Status};
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
fn test(uri: &str, status: Status, body: String) {
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![super::hello])
|
||||
.catch(errors![super::not_found]);
|
||||
let mut req = MockRequest::new(Method::Get, uri);
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket).unwrap();
|
||||
let mut response = client.get(uri).dispatch();
|
||||
assert_eq!(response.status(), status);
|
||||
assert_eq!(response.body_string(), Some(body));
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "extended_validation"
|
||||
version = "0.0.0"
|
||||
workspace = "../../"
|
||||
|
||||
[dependencies]
|
||||
rocket = { path = "../../lib" }
|
||||
rocket_codegen = { path = "../../codegen" }
|
|
@ -1,46 +1,38 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
#[test]
|
||||
fn rewrite_get_put() {
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.body_string(), Some("Hello, fairings!".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn counts() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Issue 1 GET request.
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
req.dispatch_with(&rocket);
|
||||
client.get("/").dispatch();
|
||||
|
||||
// Check the GET count, taking into account _this_ GET request.
|
||||
let mut req = MockRequest::new(Get, "/counts");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = client.get("/counts").dispatch();
|
||||
assert_eq!(response.body_string(), Some("Get: 2\nPost: 0".into()));
|
||||
|
||||
// Issue 1 more GET request and a POST.
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
req.dispatch_with(&rocket);
|
||||
let mut req = MockRequest::new(Post, "/");
|
||||
req.dispatch_with(&rocket);
|
||||
client.get("/").dispatch();
|
||||
client.post("/").dispatch();
|
||||
|
||||
// Check the counts.
|
||||
let mut req = MockRequest::new(Get, "/counts");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = client.get("/counts").dispatch();
|
||||
assert_eq!(response.body_string(), Some("Get: 4\nPost: 1".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Ensure the token is '123', which is what we have in `Rocket.toml`.
|
||||
let mut req = MockRequest::new(Get, "/token");
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
let mut res = client.get("/token").dispatch();
|
||||
assert_eq!(res.body_string(), Some("123".into()));
|
||||
}
|
||||
|
|
|
@ -33,19 +33,19 @@ impl<'v> FromFormValue<'v> for FormOption {
|
|||
}
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
struct FormInput {
|
||||
struct FormInput<'r> {
|
||||
checkbox: bool,
|
||||
number: usize,
|
||||
#[form(field = "type")]
|
||||
radio: FormOption,
|
||||
password: String,
|
||||
password: &'r RawStr,
|
||||
#[form(field = "textarea")]
|
||||
text_area: String,
|
||||
select: FormOption,
|
||||
}
|
||||
|
||||
#[post("/", data = "<sink>")]
|
||||
fn sink(sink: Result<Form<FormInput>, Option<String>>) -> String {
|
||||
fn sink<'r>(sink: Result<Form<'r, FormInput<'r>>, Option<String>>) -> String {
|
||||
match sink {
|
||||
Ok(form) => format!("{:?}", form.get()),
|
||||
Err(Some(f)) => format!("Invalid form input: {}", f),
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use std::fmt;
|
||||
use super::{rocket, FormInput, FormOption};
|
||||
|
||||
use rocket::Rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::ContentType;
|
||||
use rocket::http::Method::*;
|
||||
|
||||
impl fmt::Display for FormOption {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -16,167 +14,169 @@ impl fmt::Display for FormOption {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_form_eq(rocket: &Rocket, form_str: &str, expected: String) {
|
||||
let mut req = MockRequest::new(Post, "/")
|
||||
fn assert_form_eq(client: &Client, form_str: &str, expected: String) {
|
||||
let mut res = client.post("/")
|
||||
.header(ContentType::Form)
|
||||
.body(form_str);
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
.body(form_str)
|
||||
.dispatch();
|
||||
|
||||
assert_eq!(res.body_string(), Some(expected));
|
||||
}
|
||||
|
||||
fn assert_valid_form(rocket: &Rocket, input: &FormInput) {
|
||||
fn assert_valid_form(client: &Client, input: &FormInput) {
|
||||
let f = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
|
||||
input.checkbox, input.number, input.radio, input.password,
|
||||
input.text_area, input.select);
|
||||
assert_form_eq(rocket, &f, format!("{:?}", input));
|
||||
assert_form_eq(client, &f, format!("{:?}", input));
|
||||
}
|
||||
|
||||
fn assert_valid_raw_form(rocket: &Rocket, form_str: &str, input: &FormInput) {
|
||||
assert_form_eq(rocket, form_str, format!("{:?}", input));
|
||||
fn assert_valid_raw_form(client: &Client, form_str: &str, input: &FormInput) {
|
||||
assert_form_eq(client, form_str, format!("{:?}", input));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_forms() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut input = FormInput {
|
||||
checkbox: true,
|
||||
number: 310,
|
||||
radio: FormOption::A,
|
||||
password: "beep".to_string(),
|
||||
password: "beep".into(),
|
||||
text_area: "bop".to_string(),
|
||||
select: FormOption::B
|
||||
};
|
||||
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
|
||||
input.checkbox = false;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
|
||||
input.number = 0;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
input.number = 120;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
input.number = 133;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
|
||||
input.radio = FormOption::B;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
input.radio = FormOption::C;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
|
||||
input.password = "".to_string();
|
||||
assert_valid_form(&rocket, &input);
|
||||
input.password = "----90138490285u2o3hndslkv".to_string();
|
||||
assert_valid_form(&rocket, &input);
|
||||
input.password = "hi".to_string();
|
||||
assert_valid_form(&rocket, &input);
|
||||
input.password = "".into();
|
||||
assert_valid_form(&client, &input);
|
||||
input.password = "----90138490285u2o3hndslkv".into();
|
||||
assert_valid_form(&client, &input);
|
||||
input.password = "hi".into();
|
||||
assert_valid_form(&client, &input);
|
||||
|
||||
input.text_area = "".to_string();
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
input.text_area = "----90138490285u2o3hndslkv".to_string();
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
input.text_area = "hey".to_string();
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
|
||||
input.select = FormOption::A;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
input.select = FormOption::C;
|
||||
assert_valid_form(&rocket, &input);
|
||||
assert_valid_form(&client, &input);
|
||||
|
||||
// checkbox need not be present; defaults to false; accepts 'on' and 'off'
|
||||
assert_valid_raw_form(&rocket,
|
||||
assert_valid_raw_form(&client,
|
||||
"number=133&type=c&password=hi&textarea=hey&select=c",
|
||||
&input);
|
||||
|
||||
assert_valid_raw_form(&rocket,
|
||||
assert_valid_raw_form(&client,
|
||||
"checkbox=off&number=133&type=c&password=hi&textarea=hey&select=c",
|
||||
&input);
|
||||
|
||||
input.checkbox = true;
|
||||
assert_valid_raw_form(&rocket,
|
||||
assert_valid_raw_form(&client,
|
||||
"checkbox=on&number=133&type=c&password=hi&textarea=hey&select=c",
|
||||
&input);
|
||||
}
|
||||
|
||||
fn assert_invalid_form(rocket: &Rocket, vals: &mut [&str; 6]) {
|
||||
fn assert_invalid_form(client: &Client, vals: &mut [&str; 6]) {
|
||||
let s = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
|
||||
vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
|
||||
assert_form_eq(rocket, &s, format!("Invalid form input: {}", s));
|
||||
assert_form_eq(client, &s, format!("Invalid form input: {}", s));
|
||||
*vals = ["true", "1", "a", "hi", "hey", "b"];
|
||||
}
|
||||
|
||||
fn assert_invalid_raw_form(rocket: &Rocket, form_str: &str) {
|
||||
assert_form_eq(rocket, form_str, format!("Invalid form input: {}", form_str));
|
||||
fn assert_invalid_raw_form(client: &Client, form_str: &str) {
|
||||
assert_form_eq(client, form_str, format!("Invalid form input: {}", form_str));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_semantically_invalid_forms() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut form_vals = ["true", "1", "a", "hi", "hey", "b"];
|
||||
|
||||
form_vals[0] = "not true";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[0] = "bing";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[0] = "true0";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[0] = " false";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
|
||||
form_vals[1] = "-1";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[1] = "1e10";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[1] = "-1-1";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[1] = "NaN";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
|
||||
form_vals[2] = "A";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[2] = "B";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[2] = "d";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[2] = "100";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[2] = "";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
|
||||
// password and textarea are always valid, so we skip them
|
||||
form_vals[5] = "A";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[5] = "b ";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[5] = "d";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[5] = "-a";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
form_vals[5] = "";
|
||||
assert_invalid_form(&rocket, &mut form_vals);
|
||||
assert_invalid_form(&client, &mut form_vals);
|
||||
|
||||
// now forms with missing fields
|
||||
assert_invalid_raw_form(&rocket, "number=10&type=a&password=hi&textarea=hey");
|
||||
assert_invalid_raw_form(&rocket, "number=10&radio=a&password=hi&textarea=hey&select=b");
|
||||
assert_invalid_raw_form(&rocket, "number=10&password=hi&select=b");
|
||||
assert_invalid_raw_form(&rocket, "number=10&select=b");
|
||||
assert_invalid_raw_form(&rocket, "password=hi&select=b");
|
||||
assert_invalid_raw_form(&rocket, "password=hi");
|
||||
assert_invalid_raw_form(&rocket, "");
|
||||
assert_invalid_raw_form(&client, "number=10&type=a&password=hi&textarea=hey");
|
||||
assert_invalid_raw_form(&client, "number=10&radio=a&password=hi&textarea=hey&select=b");
|
||||
assert_invalid_raw_form(&client, "number=10&password=hi&select=b");
|
||||
assert_invalid_raw_form(&client, "number=10&select=b");
|
||||
assert_invalid_raw_form(&client, "password=hi&select=b");
|
||||
assert_invalid_raw_form(&client, "password=hi");
|
||||
assert_invalid_raw_form(&client, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_structurally_invalid_forms() {
|
||||
let rocket = rocket();
|
||||
assert_invalid_raw_form(&rocket, "==&&&&&&==");
|
||||
assert_invalid_raw_form(&rocket, "a&=b");
|
||||
assert_invalid_raw_form(&rocket, "=");
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
assert_invalid_raw_form(&client, "==&&&&&&==");
|
||||
assert_invalid_raw_form(&client, "a&=b");
|
||||
assert_invalid_raw_form(&client, "=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_bad_utf8() {
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
unsafe {
|
||||
let bad_str = ::std::str::from_utf8_unchecked(b"a=\xff");
|
||||
assert_form_eq(&rocket(), bad_str, "Form input was invalid UTF8.".into());
|
||||
assert_form_eq(&client, bad_str, "Form input was invalid UTF8.".into());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "optional_result"
|
||||
name = "form_validation"
|
||||
version = "0.0.0"
|
||||
workspace = "../../"
|
||||
|
|
@ -1,24 +1,20 @@
|
|||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::http::{ContentType, Status};
|
||||
|
||||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{ContentType, Status};
|
||||
|
||||
fn test_login<T>(user: &str, pass: &str, age: &str, status: Status, body: T)
|
||||
where T: Into<Option<&'static str>>
|
||||
{
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let query = format!("username={}&password={}&age={}", user, pass, age);
|
||||
|
||||
let mut req = MockRequest::new(Post, "/login")
|
||||
let mut response = client.post("/login")
|
||||
.header(ContentType::Form)
|
||||
.body(&query);
|
||||
.body(&query)
|
||||
.dispatch();
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), status);
|
||||
|
||||
let body_str = response.body_string();
|
||||
if let Some(expected_str) = body.into() {
|
||||
let body_str = response.body_string();
|
||||
assert!(body_str.map_or(false, |s| s.contains(expected_str)));
|
||||
}
|
||||
}
|
||||
|
@ -48,12 +44,12 @@ fn test_invalid_age() {
|
|||
}
|
||||
|
||||
fn check_bad_form(form_str: &str, status: Status) {
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new(Post, "/login")
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let response = client.post("/login")
|
||||
.header(ContentType::Form)
|
||||
.body(form_str);
|
||||
.body(form_str)
|
||||
.dispatch();
|
||||
|
||||
let response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), status);
|
||||
}
|
||||
|
||||
|
@ -82,5 +78,6 @@ fn test_bad_form_missing_fields() {
|
|||
|
||||
#[test]
|
||||
fn test_bad_form_additional_fields() {
|
||||
check_bad_form("username=Sergio&password=pass&age=30&addition=1", Status::UnprocessableEntity);
|
||||
check_bad_form("username=Sergio&password=pass&age=30&addition=1",
|
||||
Status::UnprocessableEntity);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
use rocket::response::NamedFile;
|
||||
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> io::Result<NamedFile> {
|
||||
NamedFile::open("static/index.html")
|
||||
}
|
||||
|
||||
#[get("/<file..>", rank = 5)]
|
||||
fn files(file: PathBuf) -> io::Result<NamedFile> {
|
||||
NamedFile::open(Path::new("static/").join(file))
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
#![feature(plugin, custom_derive)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
||||
mod files;
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
use rocket::request::Form;
|
||||
use rocket::response::Redirect;
|
||||
use rocket::http::RawStr;
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct UserLogin<'r> {
|
||||
username: &'r RawStr,
|
||||
password: String,
|
||||
age: Result<usize, &'r RawStr>,
|
||||
}
|
||||
|
||||
#[post("/login", data = "<user_form>")]
|
||||
fn login<'a>(user_form: Form<'a, UserLogin<'a>>) -> Result<Redirect, String> {
|
||||
let user = user_form.get();
|
||||
match user.age {
|
||||
Ok(age) if age < 21 => return Err(format!("Sorry, {} is too young!", age)),
|
||||
Ok(age) if age > 120 => return Err(format!("Are you sure you're {}?", age)),
|
||||
Err(e) => return Err(format!("'{}' is not a valid integer.", e)),
|
||||
Ok(_) => { /* Move along, adult. */ }
|
||||
};
|
||||
|
||||
if user.username == "Sergio" {
|
||||
match user.password.as_str() {
|
||||
"password" => Ok(Redirect::to("/user/Sergio")),
|
||||
_ => Err("Wrong password!".to_string())
|
||||
}
|
||||
} else {
|
||||
Err(format!("Unrecognized user, '{}'.", user.username))
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/user/<username>")]
|
||||
fn user_page(username: String) -> String {
|
||||
format!("This is {}'s page.", username)
|
||||
}
|
||||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite()
|
||||
.mount("/", routes![files::index, files::files, user_page, login])
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket().launch();
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::http::{ContentType, Status};
|
||||
|
||||
use super::rocket;
|
||||
|
||||
fn test_login(username: &str, password: &str, age: isize, status: Status,
|
||||
body: Option<&'static str>) {
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new(Post, "/login")
|
||||
.header(ContentType::Form)
|
||||
.body(&format!("username={}&password={}&age={}", username, password, age));
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let body_str = response.body_string();
|
||||
|
||||
println!("Checking: {:?}/{:?}/{:?}/{:?}", username, password, age, body_str);
|
||||
assert_eq!(response.status(), status);
|
||||
|
||||
if let Some(string) = body {
|
||||
assert!(body_str.map_or(true, |s| s.contains(string)));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_login() {
|
||||
test_login("Sergio", "password", 30, Status::SeeOther, None);
|
||||
}
|
||||
|
||||
const OK: Status = self::Status::Ok;
|
||||
|
||||
#[test]
|
||||
fn test_bad_login() {
|
||||
test_login("Sergio", "password", 20, OK, Some("Sorry, 20 is too young!"));
|
||||
test_login("Sergio", "password", 200, OK, Some("Are you sure you're 200?"));
|
||||
test_login("Sergio", "jk", -100, OK, Some("'-100' is not a valid integer."));
|
||||
test_login("Sergio", "ok", 30, OK, Some("Wrong password!"));
|
||||
test_login("Mike", "password", 30, OK, Some("Unrecognized user, 'Mike'."));
|
||||
}
|
||||
|
||||
fn check_bad_form(form_str: &str, status: Status) {
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new(Post, "/login")
|
||||
.header(ContentType::Form)
|
||||
.body(form_str);
|
||||
|
||||
let response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), status);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_form() {
|
||||
check_bad_form("&", Status::BadRequest);
|
||||
check_bad_form("=", Status::BadRequest);
|
||||
check_bad_form("&&&===&", Status::BadRequest);
|
||||
|
||||
check_bad_form("username=Sergio", Status::UnprocessableEntity);
|
||||
check_bad_form("username=Sergio&", Status::UnprocessableEntity);
|
||||
check_bad_form("username=Sergio&pass=something", Status::UnprocessableEntity);
|
||||
check_bad_form("user=Sergio&password=something", Status::UnprocessableEntity);
|
||||
check_bad_form("password=something", Status::UnprocessableEntity);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
<h1>Login</h1>
|
||||
|
||||
<form action="/login" method="post" accept-charset="utf-8">
|
||||
Username:<input type="text" name="username">
|
||||
Password:<input type="password" name="password">
|
||||
Age:<input type="number" name="age">
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "from_request"
|
||||
version = "0.0.0"
|
||||
workspace = "../../"
|
||||
|
||||
[dependencies]
|
||||
rocket = { path = "../../lib" }
|
||||
rocket_codegen = { path = "../../codegen" }
|
|
@ -1,17 +1,15 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::{Client, LocalResponse};
|
||||
use rocket::http::Method::*;
|
||||
use rocket::http::Status;
|
||||
use rocket::Response;
|
||||
use rocket_contrib::Template;
|
||||
|
||||
const TEMPLATE_ROOT: &'static str = "templates/";
|
||||
|
||||
macro_rules! dispatch {
|
||||
($method:expr, $path:expr, $test_fn:expr) => ({
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new($method, $path);
|
||||
$test_fn(req.dispatch_with(&rocket));
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
$test_fn(client.req($method, $path).dispatch());
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -19,7 +17,7 @@ macro_rules! dispatch {
|
|||
fn test_root() {
|
||||
// Check that the redirect works.
|
||||
for method in &[Get, Head] {
|
||||
dispatch!(*method, "/", |mut response: Response| {
|
||||
dispatch!(*method, "/", |mut response: LocalResponse| {
|
||||
assert_eq!(response.status(), Status::SeeOther);
|
||||
assert!(response.body().is_none());
|
||||
|
||||
|
@ -30,7 +28,7 @@ fn test_root() {
|
|||
|
||||
// Check that other request methods are not accepted (and instead caught).
|
||||
for method in &[Post, Put, Delete, Options, Trace, Connect, Patch] {
|
||||
dispatch!(*method, "/", |mut response: Response| {
|
||||
dispatch!(*method, "/", |mut response: LocalResponse| {
|
||||
let mut map = ::std::collections::HashMap::new();
|
||||
map.insert("path", "/");
|
||||
let expected = Template::show(TEMPLATE_ROOT, "error/404", &map).unwrap();
|
||||
|
@ -44,7 +42,7 @@ fn test_root() {
|
|||
#[test]
|
||||
fn test_name() {
|
||||
// Check that the /hello/<name> route works.
|
||||
dispatch!(Get, "/hello/Jack", |mut response: Response| {
|
||||
dispatch!(Get, "/hello/Jack", |mut response: LocalResponse| {
|
||||
let context = super::TemplateContext {
|
||||
name: "Jack".to_string(),
|
||||
items: vec!["One", "Two", "Three"].iter().map(|s| s.to_string()).collect()
|
||||
|
@ -59,7 +57,7 @@ fn test_name() {
|
|||
#[test]
|
||||
fn test_404() {
|
||||
// Check that the error catcher works.
|
||||
dispatch!(Get, "/hello/", |mut response: Response| {
|
||||
dispatch!(Get, "/hello/", |mut response: LocalResponse| {
|
||||
let mut map = ::std::collections::HashMap::new();
|
||||
map.insert("path", "/hello/");
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "hello_alt_methods"
|
||||
version = "0.0.0"
|
||||
workspace = "../../"
|
||||
|
||||
[dependencies]
|
||||
rocket = { path = "../../lib" }
|
||||
rocket_codegen = { path = "../../codegen" }
|
|
@ -1,26 +0,0 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
||||
use std::io;
|
||||
|
||||
use rocket::response::NamedFile;
|
||||
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> io::Result<NamedFile> {
|
||||
NamedFile::open("static/index.html")
|
||||
}
|
||||
|
||||
#[put("/")]
|
||||
fn put() -> &'static str {
|
||||
"Hello, PUT request!"
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket::ignite()
|
||||
.mount("/", routes![index, put])
|
||||
.launch();
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method;
|
||||
use rocket::http::Status;
|
||||
|
||||
fn test(method: Method, status: Status, body_prefix: Option<&str>) {
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![super::index, super::put]);
|
||||
|
||||
let mut req = MockRequest::new(method, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
|
||||
assert_eq!(response.status(), status);
|
||||
if let Some(expected_body_string) = body_prefix {
|
||||
let body_str = response.body_string().unwrap();
|
||||
assert!(body_str.starts_with(expected_body_string));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hello_world_alt_methods() {
|
||||
test(Method::Get, Status::Ok, Some("<!DOCTYPE html>"));
|
||||
test(Method::Put, Status::Ok, Some("Hello, PUT request!"));
|
||||
test(Method::Post, Status::NotFound, None);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Hello Alt Methods</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/" method="post" accept-charset="utf-8">
|
||||
<input type="hidden" name="_method" id="_method" value="put" />
|
||||
<input type="submit" name="Submit" id="Submit" value="submit" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -1,20 +1,19 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
fn client() -> Client {
|
||||
Client::new(rocket::ignite().mount("/", routes![super::hello, super::hi])).unwrap()
|
||||
}
|
||||
|
||||
fn test(uri: &str, expected: String) {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::hello, super::hi]);
|
||||
let mut req = MockRequest::new(Get, uri);
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.body_string(), Some(expected));
|
||||
let client = client();
|
||||
assert_eq!(client.get(uri).dispatch().body_string(), Some(expected));
|
||||
}
|
||||
|
||||
fn test_404(uri: &str) {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::hello, super::hi]);
|
||||
let mut req = MockRequest::new(Get, uri);
|
||||
let response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
let client = client();
|
||||
assert_eq!(client.get(uri).dispatch().status(), Status::NotFound);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
#[test]
|
||||
fn hello_world() {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::hello]);
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket).unwrap();
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.body_string(), Some("Hello, world!".into()));
|
||||
}
|
||||
|
|
|
@ -1,95 +1,72 @@
|
|||
use rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::Response;
|
||||
|
||||
macro_rules! run_test {
|
||||
($rocket: expr, $req:expr, $test_fn:expr) => ({
|
||||
let mut req = $req;
|
||||
$test_fn(req.dispatch_with($rocket));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_get_put() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Try to get a message with an ID that doesn't exist.
|
||||
let req = MockRequest::new(Get, "/message/99").header(ContentType::JSON);
|
||||
run_test!(&rocket, req, |mut response: Response| {
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
let mut res = client.get("/message/99").header(ContentType::JSON).dispatch();
|
||||
assert_eq!(res.status(), Status::NotFound);
|
||||
|
||||
let body = response.body().unwrap().into_string().unwrap();
|
||||
let body = res.body_string().unwrap();
|
||||
assert!(body.contains("error"));
|
||||
assert!(body.contains("Resource was not found."));
|
||||
});
|
||||
|
||||
// Try to get a message with an invalid ID.
|
||||
let req = MockRequest::new(Get, "/message/hi").header(ContentType::JSON);
|
||||
run_test!(&rocket, req, |mut response: Response| {
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
let body = response.body().unwrap().into_string().unwrap();
|
||||
let mut res = client.get("/message/hi").header(ContentType::JSON).dispatch();
|
||||
let body = res.body_string().unwrap();
|
||||
assert_eq!(res.status(), Status::NotFound);
|
||||
assert!(body.contains("error"));
|
||||
});
|
||||
|
||||
// Try to put a message without a proper body.
|
||||
let req = MockRequest::new(Put, "/message/80").header(ContentType::JSON);
|
||||
run_test!(&rocket, req, |response: Response| {
|
||||
assert_eq!(response.status(), Status::BadRequest);
|
||||
});
|
||||
let res = client.put("/message/80").header(ContentType::JSON).dispatch();
|
||||
assert_eq!(res.status(), Status::BadRequest);
|
||||
|
||||
// Try to put a message for an ID that doesn't exist.
|
||||
let req = MockRequest::new(Put, "/message/80")
|
||||
let res = client.put("/message/80")
|
||||
.header(ContentType::JSON)
|
||||
.body(r#"{ "contents": "Bye bye, world!" }"#);
|
||||
.body(r#"{ "contents": "Bye bye, world!" }"#)
|
||||
.dispatch();
|
||||
|
||||
run_test!(&rocket, req, |response: Response| {
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
});
|
||||
assert_eq!(res.status(), Status::NotFound);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn post_get_put_get() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Check that a message with ID 1 doesn't exist.
|
||||
let req = MockRequest::new(Get, "/message/1").header(ContentType::JSON);
|
||||
run_test!(&rocket, req, |response: Response| {
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
});
|
||||
let res = client.get("/message/1").header(ContentType::JSON).dispatch();
|
||||
assert_eq!(res.status(), Status::NotFound);
|
||||
|
||||
// Add a new message with ID 1.
|
||||
let req = MockRequest::new(Post, "/message/1")
|
||||
let res = client.post("/message/1")
|
||||
.header(ContentType::JSON)
|
||||
.body(r#"{ "contents": "Hello, world!" }"#);
|
||||
.body(r#"{ "contents": "Hello, world!" }"#)
|
||||
.dispatch();
|
||||
|
||||
run_test!(&rocket, req, |response: Response| {
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
});
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
|
||||
// Check that the message exists with the correct contents.
|
||||
let req = MockRequest::new(Get, "/message/1") .header(ContentType::JSON);
|
||||
run_test!(&rocket, req, |mut response: Response| {
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.body().unwrap().into_string().unwrap();
|
||||
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch();
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
let body = res.body().unwrap().into_string().unwrap();
|
||||
assert!(body.contains("Hello, world!"));
|
||||
});
|
||||
|
||||
// Change the message contents.
|
||||
let req = MockRequest::new(Put, "/message/1")
|
||||
let res = client.put("/message/1")
|
||||
.header(ContentType::JSON)
|
||||
.body(r#"{ "contents": "Bye bye, world!" }"#);
|
||||
.body(r#"{ "contents": "Bye bye, world!" }"#)
|
||||
.dispatch();
|
||||
|
||||
run_test!(&rocket, req, |response: Response| {
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
});
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
|
||||
// Check that the message exists with the updated contents.
|
||||
let req = MockRequest::new(Get, "/message/1") .header(ContentType::JSON);
|
||||
run_test!(&rocket, req, |mut response: Response| {
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.body().unwrap().into_string().unwrap();
|
||||
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch();
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
let body = res.body().unwrap().into_string().unwrap();
|
||||
assert!(!body.contains("Hello, world!"));
|
||||
assert!(body.contains("Bye bye, world!"));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
use super::rocket;
|
||||
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
use rocket::http::Method::*;
|
||||
|
||||
#[test]
|
||||
fn test_push_pop() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
|
||||
let mut req = MockRequest::new(Put, "/push?description=test1");
|
||||
let response = req.dispatch_with(&rocket);
|
||||
let response = client.put("/push?description=test1").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
|
||||
let mut req = MockRequest::new(Get, "/pop");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = client.get("/pop").dispatch();
|
||||
assert_eq!(response.body_string(), Some("test1".to_string()));
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
use super::*;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{ContentType, Status};
|
||||
use rocket::http::Method::*;
|
||||
|
||||
fn test(uri: &str, content_type: ContentType, status: Status, body: String) {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Get, uri).header(content_type);
|
||||
let mut response = request.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket()).unwrap();;
|
||||
let mut response = client.get(uri).header(content_type).dispatch();
|
||||
assert_eq!(response.status(), status);
|
||||
assert_eq!(response.body_string(), Some(body));
|
||||
}
|
||||
|
@ -34,21 +31,21 @@ fn test_echo() {
|
|||
|
||||
#[test]
|
||||
fn test_upload() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();;
|
||||
let expected_body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, \
|
||||
sed do eiusmod tempor incididunt ut labore et dolore \
|
||||
magna aliqua".to_string();
|
||||
|
||||
// Upload the body.
|
||||
let mut request = MockRequest::new(Post, "/upload")
|
||||
let response = client.post("/upload")
|
||||
.header(ContentType::Plain)
|
||||
.body(&expected_body);
|
||||
let response = request.dispatch_with(&rocket);
|
||||
.body(&expected_body)
|
||||
.dispatch();
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
|
||||
// Ensure we get back the same body.
|
||||
let mut request = MockRequest::new(Get, "/upload");
|
||||
let mut response = request.dispatch_with(&rocket);
|
||||
let mut response = client.get("/upload").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string(), Some(expected_body));
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::Response;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Message {
|
||||
|
@ -10,35 +8,26 @@ struct Message {
|
|||
contents: String
|
||||
}
|
||||
|
||||
macro_rules! run_test {
|
||||
($rocket: expr, $req:expr, $test_fn:expr) => ({
|
||||
let mut req = $req;
|
||||
$test_fn(req.dispatch_with($rocket));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msgpack_get() {
|
||||
let rocket = rocket();
|
||||
let req = MockRequest::new(Get, "/message/1").header(ContentType::MsgPack);
|
||||
run_test!(&rocket, req, |mut response: Response| {
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.body().unwrap().into_bytes().unwrap();
|
||||
// Represents a message of `[1, "Hello, world!"]`
|
||||
assert_eq!(&body, &[146, 1, 173, 72, 101, 108, 108, 111, 44, 32, 119, 111,
|
||||
114, 108, 100, 33]);
|
||||
});
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut res = client.get("/message/1").header(ContentType::MsgPack).dispatch();
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
|
||||
// Check that the message is `[1, "Hello, world!"]`
|
||||
assert_eq!(&res.body_bytes().unwrap(),
|
||||
&[146, 1, 173, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msgpack_post() {
|
||||
let rocket = rocket();
|
||||
let req = MockRequest::new(Post, "/message")
|
||||
// Dispatch request with a message of `[2, "Goodbye, world!"]`.
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut res = client.post("/message")
|
||||
.header(ContentType::MsgPack)
|
||||
// Represents a message of `[2, "Goodbye, world!"]`
|
||||
.body(&[146, 2, 175, 71, 111, 111, 100, 98, 121, 101, 44, 32, 119, 111, 114, 108, 100, 33]);
|
||||
run_test!(&rocket, req, |mut response: Response| {
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body().unwrap().into_string().unwrap(), "Goodbye, world!");
|
||||
});
|
||||
.body(&[146, 2, 175, 71, 111, 111, 100, 98, 121, 101, 44, 32, 119, 111, 114, 108, 100, 33])
|
||||
.dispatch();
|
||||
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
assert_eq!(res.body_string(), Some("Goodbye, world!".into()));
|
||||
}
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::{Method, Status};
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
fn test_200(uri: &str, expected_body: &str) {
|
||||
fn client() -> Client {
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![super::root, super::user, super::login]);
|
||||
let mut request = MockRequest::new(Method::Get, uri);
|
||||
let mut response = request.dispatch_with(&rocket);
|
||||
Client::new(rocket).unwrap()
|
||||
|
||||
}
|
||||
|
||||
fn test_200(uri: &str, expected_body: &str) {
|
||||
let client = client();
|
||||
let mut response = client.get(uri).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string(), Some(expected_body.to_string()));
|
||||
}
|
||||
|
||||
fn test_303(uri: &str, expected_location: &str) {
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![super::root, super::user, super::login]);
|
||||
let mut request = MockRequest::new(Method::Get, uri);
|
||||
let response = request.dispatch_with(&rocket);
|
||||
let client = client();
|
||||
let response = client.get(uri).dispatch();
|
||||
let location_headers: Vec<_> = response.headers().get("Location").collect();
|
||||
|
||||
assert_eq!(response.status(), Status::SeeOther);
|
||||
assert_eq!(location_headers, vec![expected_location]);
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
extern crate rocket;
|
||||
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
use rocket::http::RawStr;
|
||||
|
||||
#[get("/users/<name>")]
|
||||
fn user(name: &RawStr) -> Option<&'static str> {
|
||||
if name == "Sergio" {
|
||||
Some("Hello, Sergio!")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket::ignite().mount("/", routes![user]).launch();
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::{Method, Status};
|
||||
|
||||
#[test]
|
||||
fn test_200() {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::user]);
|
||||
let mut request = MockRequest::new(Method::Get, "/users/Sergio");
|
||||
let mut response = request.dispatch_with(&rocket);
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string(), Some("Hello, Sergio!".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_404() {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::user]);
|
||||
let mut request = MockRequest::new(Method::Get, "/users/unknown");
|
||||
let response = request.dispatch_with(&rocket);
|
||||
|
||||
// Only test the status because the body is the default 404.
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
use super::{rocket, index};
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::Rocket;
|
||||
|
||||
fn extract_id(from: &str) -> Option<String> {
|
||||
from.rfind('/').map(|i| &from[(i + 1)..]).map(|s| s.trim_right().to_string())
|
||||
|
@ -10,56 +8,52 @@ fn extract_id(from: &str) -> Option<String> {
|
|||
|
||||
#[test]
|
||||
fn check_index() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Ensure the index returns what we expect.
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
||||
assert_eq!(response.body_string(), Some(index().into()))
|
||||
}
|
||||
|
||||
fn upload_paste(rocket: &Rocket, body: &str) -> String {
|
||||
let mut req = MockRequest::new(Post, "/").body(body);
|
||||
let mut response = req.dispatch_with(rocket);
|
||||
fn upload_paste(client: &Client, body: &str) -> String {
|
||||
let mut response = client.post("/").body(body).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
||||
extract_id(&response.body_string().unwrap()).unwrap()
|
||||
}
|
||||
|
||||
|
||||
fn download_paste(rocket: &Rocket, id: &str) -> String {
|
||||
let mut req = MockRequest::new(Get, format!("/{}", id));
|
||||
let mut response = req.dispatch_with(rocket);
|
||||
fn download_paste(client: &Client, id: &str) -> String {
|
||||
let mut response = client.get(format!("/{}", id)).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
response.body_string().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pasting() {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Do a trivial upload, just to make sure it works.
|
||||
let body_1 = "Hello, world!";
|
||||
let id_1 = upload_paste(&rocket, body_1);
|
||||
assert_eq!(download_paste(&rocket, &id_1), body_1);
|
||||
let id_1 = upload_paste(&client, body_1);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
|
||||
// Make sure we can keep getting that paste.
|
||||
assert_eq!(download_paste(&rocket, &id_1), body_1);
|
||||
assert_eq!(download_paste(&rocket, &id_1), body_1);
|
||||
assert_eq!(download_paste(&rocket, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
|
||||
// Upload some unicode.
|
||||
let body_2 = "こんにちは";
|
||||
let id_2 = upload_paste(&rocket, body_2);
|
||||
assert_eq!(download_paste(&rocket, &id_2), body_2);
|
||||
let id_2 = upload_paste(&client, body_2);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
|
||||
// Make sure we can get both pastes.
|
||||
assert_eq!(download_paste(&rocket, &id_1), body_1);
|
||||
assert_eq!(download_paste(&rocket, &id_2), body_2);
|
||||
assert_eq!(download_paste(&rocket, &id_1), body_1);
|
||||
assert_eq!(download_paste(&rocket, &id_2), body_2);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
|
||||
// Now a longer upload.
|
||||
let body_3 = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
|
||||
|
@ -69,8 +63,8 @@ fn pasting() {
|
|||
in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
|
||||
officia deserunt mollit anim id est laborum.";
|
||||
let id_3 = upload_paste(&rocket, body_3);
|
||||
assert_eq!(download_paste(&rocket, &id_3), body_3);
|
||||
assert_eq!(download_paste(&rocket, &id_1), body_1);
|
||||
assert_eq!(download_paste(&rocket, &id_2), body_2);
|
||||
let id_3 = upload_paste(&client, body_3);
|
||||
assert_eq!(download_paste(&client, &id_3), body_3);
|
||||
assert_eq!(download_paste(&client, &id_1), body_1);
|
||||
assert_eq!(download_paste(&client, &id_2), body_2);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::{Client, LocalResponse as Response};
|
||||
use rocket::http::Status;
|
||||
use rocket::Response;
|
||||
|
||||
macro_rules! run_test {
|
||||
($query:expr, $test_fn:expr) => ({
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![super::hello]);
|
||||
|
||||
let mut request = MockRequest::new(Get, format!("/hello{}", $query));
|
||||
$test_fn(request.dispatch_with(&rocket));
|
||||
let client = Client::new(rocket).unwrap();
|
||||
$test_fn(client.get(format!("/hello{}", $query)).dispatch());
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "forms"
|
||||
name = "ranking"
|
||||
version = "0.0.0"
|
||||
workspace = "../../"
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
fn test(uri: &str, expected: String) {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::hello, super::hi]);
|
||||
let mut req = MockRequest::new(Get, uri);
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let client = Client::new(rocket).unwrap();
|
||||
let mut response = client.get(uri).dispatch();
|
||||
assert_eq!(response.body_string(), Some(expected));
|
||||
}
|
||||
|
|
@ -1,12 +1,9 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
#[test]
|
||||
fn hello() {
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.body_string(), Some("Rocketeer".into()));
|
||||
}
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::http::Method::*;
|
||||
|
||||
use std::io::Read;
|
||||
use std::fs::File;
|
||||
use std::fs::{self, File};
|
||||
|
||||
const UPLOAD_CONTENTS: &str = "Hey! I'm going to be uploaded. :D Yay!";
|
||||
|
||||
#[test]
|
||||
fn test_index() {
|
||||
let rocket = super::rocket();
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
let mut res = client.get("/").dispatch();
|
||||
assert_eq!(res.body_string(), Some(super::index().to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_upload() {
|
||||
const UPLOAD_CONTENTS: &str = "Hey! I'm going to be uploaded. :D Yay!";
|
||||
|
||||
let rocket = super::rocket();
|
||||
let mut req = MockRequest::new(Post, "/upload")
|
||||
.header(ContentType::Plain)
|
||||
.body(UPLOAD_CONTENTS);
|
||||
// Delete the upload file before we begin.
|
||||
let _ = fs::remove_file("/tmp/upload.txt");
|
||||
|
||||
// Do the upload. Make sure we get the expected results.
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
let mut res = client.post("/upload")
|
||||
.header(ContentType::Plain)
|
||||
.body(UPLOAD_CONTENTS)
|
||||
.dispatch();
|
||||
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
assert_eq!(res.body_string(), Some(UPLOAD_CONTENTS.len().to_string()));
|
||||
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::Response;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
macro_rules! run_test {
|
||||
($path:expr, $test_fn:expr) => ({
|
||||
fn client() -> Client {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::root, super::login]);
|
||||
let mut request = MockRequest::new(Get, format!($path));
|
||||
|
||||
$test_fn(request.dispatch_with(&rocket));
|
||||
})
|
||||
Client::new(rocket).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_root() {
|
||||
run_test!("/", |mut response: Response| {
|
||||
let client = client();
|
||||
let mut response = client.get("/").dispatch();
|
||||
|
||||
assert!(response.body().is_none());
|
||||
assert_eq!(response.status(), Status::SeeOther);
|
||||
for h in response.headers().iter() {
|
||||
|
@ -25,14 +21,11 @@ fn test_root() {
|
|||
_ => { /* let these through */ }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_login() {
|
||||
run_test!("/login", |mut response: Response| {
|
||||
assert_eq!(response.body_string(),
|
||||
Some("Hi! Please log in before continuing.".to_string()));
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
});
|
||||
let client = client();
|
||||
let mut r = client.get("/login").dispatch();
|
||||
assert_eq!(r.body_string(), Some("Hi! Please log in before continuing.".into()));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "hello_ranks"
|
||||
name = "request_guard"
|
||||
version = "0.0.0"
|
||||
workspace = "../../"
|
||||
|
|
@ -28,27 +28,27 @@ fn header_count(header_count: HeaderCount) -> String {
|
|||
format!("Your request contained {} headers!", header_count)
|
||||
}
|
||||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite().mount("/", routes![header_count])
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket::ignite().mount("/", routes![header_count]).launch();
|
||||
rocket().launch();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Header;
|
||||
|
||||
fn test_header_count<'h>(headers: Vec<Header<'static>>) {
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![super::header_count]);
|
||||
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
let mut req = client.get("/");
|
||||
for header in headers.iter().cloned() {
|
||||
req = req.header(header);
|
||||
req.add_header(header);
|
||||
}
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = req.dispatch();
|
||||
let expect = format!("Your request contained {} headers!", headers.len());
|
||||
assert_eq!(response.body_string(), Some(expect));
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_n_headers() {
|
||||
for i in 0..50 {
|
||||
let headers = (0..i).map(|n| Header::new(n.to_string(), n.to_string()))
|
||||
let headers = (0..i)
|
||||
.map(|n| Header::new(n.to_string(), n.to_string()))
|
||||
.collect();
|
||||
|
||||
test_header_count(headers);
|
|
@ -9,7 +9,7 @@ use std::collections::HashMap;
|
|||
use rocket::Outcome;
|
||||
use rocket::request::{self, Form, FlashMessage, FromRequest, Request};
|
||||
use rocket::response::{Redirect, Flash};
|
||||
use rocket::http::{Cookie, Session};
|
||||
use rocket::http::{Cookie, Cookies};
|
||||
use rocket_contrib::Template;
|
||||
|
||||
#[derive(FromForm)]
|
||||
|
@ -25,8 +25,8 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
|
|||
type Error = ();
|
||||
|
||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<User, ()> {
|
||||
let user = request.session()
|
||||
.get("user_id")
|
||||
let user = request.cookies()
|
||||
.get_private("user_id")
|
||||
.and_then(|cookie| cookie.value().parse().ok())
|
||||
.map(|id| User(id));
|
||||
|
||||
|
@ -38,9 +38,9 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
|
|||
}
|
||||
|
||||
#[post("/login", data = "<login>")]
|
||||
fn login(mut session: Session, login: Form<Login>) -> Flash<Redirect> {
|
||||
fn login(mut cookies: Cookies, login: Form<Login>) -> Flash<Redirect> {
|
||||
if login.get().username == "Sergio" && login.get().password == "password" {
|
||||
session.set(Cookie::new("user_id", 1.to_string()));
|
||||
cookies.add_private(Cookie::new("user_id", 1.to_string()));
|
||||
Flash::success(Redirect::to("/"), "Successfully logged in.")
|
||||
} else {
|
||||
Flash::error(Redirect::to("/login"), "Invalid username/password.")
|
||||
|
@ -48,8 +48,8 @@ fn login(mut session: Session, login: Form<Login>) -> Flash<Redirect> {
|
|||
}
|
||||
|
||||
#[post("/logout")]
|
||||
fn logout(mut session: Session) -> Flash<Redirect> {
|
||||
session.remove(Cookie::named("user_id"));
|
||||
fn logout(mut cookies: Cookies) -> Flash<Redirect> {
|
||||
cookies.remove_private(Cookie::named("user_id"));
|
||||
Flash::success(Redirect::to("/login"), "Successfully logged out.")
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ fn index() -> Redirect {
|
|||
|
||||
fn main() {
|
||||
rocket::ignite()
|
||||
.attach(Template::fairing())
|
||||
.mount("/", routes![index, user_index, login, logout, login_user, login_page])
|
||||
.launch();
|
||||
}
|
||||
|
|
|
@ -1,32 +1,28 @@
|
|||
use rocket::Rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
fn register_hit(rocket: &Rocket) {
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let response = req.dispatch_with(&rocket);
|
||||
fn register_hit(client: &Client) {
|
||||
let response = client.get("/").dispatch();;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
}
|
||||
|
||||
fn get_count(rocket: &Rocket) -> usize {
|
||||
let mut req = MockRequest::new(Get, "/count");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
fn get_count(client: &Client) -> usize {
|
||||
let mut response = client.get("/count").dispatch();
|
||||
response.body_string().and_then(|s| s.parse().ok()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count() {
|
||||
let rocket = super::rocket();
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
|
||||
// Count should start at 0.
|
||||
assert_eq!(get_count(&rocket), 0);
|
||||
assert_eq!(get_count(&client), 0);
|
||||
|
||||
for _ in 0..99 { register_hit(&rocket); }
|
||||
assert_eq!(get_count(&rocket), 99);
|
||||
for _ in 0..99 { register_hit(&client); }
|
||||
assert_eq!(get_count(&client), 99);
|
||||
|
||||
register_hit(&rocket);
|
||||
assert_eq!(get_count(&rocket), 100);
|
||||
register_hit(&client);
|
||||
assert_eq!(get_count(&client), 100);
|
||||
}
|
||||
|
||||
// Cargo runs each test in parallel on different threads. We use all of these
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
use super::rocket;
|
||||
|
@ -10,10 +9,8 @@ use super::rocket;
|
|||
fn test_query_file<T> (path: &str, file: T, status: Status)
|
||||
where T: Into<Option<&'static str>>
|
||||
{
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new(Get, &path);
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut response = client.get(path).dispatch();
|
||||
assert_eq!(response.status(), status);
|
||||
|
||||
let body_data = response.body().and_then(|body| body.into_bytes());
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
#[test]
|
||||
fn test_root() {
|
||||
let rocket = super::rocket();
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
let mut res = client.get("/").dispatch();
|
||||
|
||||
// Check that we have exactly 25,000 'a'.
|
||||
let res_str = res.body_string().unwrap();
|
||||
|
@ -26,9 +24,8 @@ fn test_file() {
|
|||
file.write_all(CONTENTS.as_bytes()).expect("write to big_file");
|
||||
|
||||
// Get the big file contents, hopefully.
|
||||
let rocket = super::rocket();
|
||||
let mut req = MockRequest::new(Get, "/big_file");
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
let mut res = client.get("/big_file").dispatch();
|
||||
assert_eq!(res.body_string(), Some(CONTENTS.into()));
|
||||
|
||||
// Delete the 'big_file'.
|
||||
|
|
|
@ -8,22 +8,24 @@ fn hello() -> &'static str {
|
|||
"Hello, world!"
|
||||
}
|
||||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite().mount("/", routes![hello])
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket::ignite().mount("/", routes![hello]).launch();
|
||||
rocket().launch();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
use rocket::http::Method::*;
|
||||
|
||||
#[test]
|
||||
fn test_hello() {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::hello]);
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string(), Some("Hello, world!".into()));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "hello_tls"
|
||||
name = "tls"
|
||||
version = "0.0.0"
|
||||
workspace = "../../"
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
#[test]
|
||||
fn hello_world() {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::hello]);
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket).unwrap();
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.body_string(), Some("Hello, world!".into()));
|
||||
}
|
|
@ -5,8 +5,7 @@ use super::task::Task;
|
|||
use self::parking_lot::Mutex;
|
||||
use self::rand::{Rng, thread_rng};
|
||||
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
// We use a lock to synchronize between tests so DB operations don't collide.
|
||||
|
@ -15,9 +14,10 @@ use rocket::http::{Status, ContentType};
|
|||
static DB_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
macro_rules! run_test {
|
||||
(|$rocket:ident, $conn:ident| $block:expr) => ({
|
||||
(|$client:ident, $conn:ident| $block:expr) => ({
|
||||
let _lock = DB_LOCK.lock();
|
||||
let ($rocket, db) = super::rocket();
|
||||
let (rocket, db) = super::rocket();
|
||||
let $client = Client::new(rocket).expect("Rocket client");
|
||||
let $conn = db.expect("failed to get database connection for testing");
|
||||
$block
|
||||
})
|
||||
|
@ -25,15 +25,15 @@ macro_rules! run_test {
|
|||
|
||||
#[test]
|
||||
fn test_insertion_deletion() {
|
||||
run_test!(|rocket, conn| {
|
||||
run_test!(|client, conn| {
|
||||
// Get the tasks before making changes.
|
||||
let init_tasks = Task::all(&conn);
|
||||
|
||||
// Issue a request to insert a new task.
|
||||
let mut req = MockRequest::new(Post, "/todo")
|
||||
client.post("/todo")
|
||||
.header(ContentType::Form)
|
||||
.body("description=My+first+task");
|
||||
req.dispatch_with(&rocket);
|
||||
.body("description=My+first+task")
|
||||
.dispatch();
|
||||
|
||||
// Ensure we have one more task in the database.
|
||||
let new_tasks = Task::all(&conn);
|
||||
|
@ -45,8 +45,7 @@ fn test_insertion_deletion() {
|
|||
|
||||
// Issue a request to delete the task.
|
||||
let id = new_tasks[0].id.unwrap();
|
||||
let mut req = MockRequest::new(Delete, format!("/todo/{}", id));
|
||||
req.dispatch_with(&rocket);
|
||||
client.delete(format!("/todo/{}", id)).dispatch();
|
||||
|
||||
// Ensure it's gone.
|
||||
let final_tasks = Task::all(&conn);
|
||||
|
@ -59,24 +58,22 @@ fn test_insertion_deletion() {
|
|||
|
||||
#[test]
|
||||
fn test_toggle() {
|
||||
run_test!(|rocket, conn| {
|
||||
run_test!(|client, conn| {
|
||||
// Issue a request to insert a new task; ensure it's not yet completed.
|
||||
let mut req = MockRequest::new(Post, "/todo")
|
||||
client.post("/todo")
|
||||
.header(ContentType::Form)
|
||||
.body("description=test_for_completion");
|
||||
req.dispatch_with(&rocket);
|
||||
.body("description=test_for_completion")
|
||||
.dispatch();
|
||||
|
||||
let task = Task::all(&conn)[0].clone();
|
||||
assert_eq!(task.completed, false);
|
||||
|
||||
// Issue a request to toggle the task; ensure it is completed.
|
||||
let mut req = MockRequest::new(Put, format!("/todo/{}", task.id.unwrap()));
|
||||
req.dispatch_with(&rocket);
|
||||
client.put(format!("/todo/{}", task.id.unwrap())).dispatch();
|
||||
assert_eq!(Task::all(&conn)[0].completed, true);
|
||||
|
||||
// Issue a request to toggle the task; ensure it's not completed again.
|
||||
let mut req = MockRequest::new(Put, format!("/todo/{}", task.id.unwrap()));
|
||||
req.dispatch_with(&rocket);
|
||||
client.put(format!("/todo/{}", task.id.unwrap())).dispatch();
|
||||
assert_eq!(Task::all(&conn)[0].completed, false);
|
||||
})
|
||||
}
|
||||
|
@ -86,7 +83,7 @@ fn test_many_insertions() {
|
|||
const ITER: usize = 100;
|
||||
|
||||
let mut rng = thread_rng();
|
||||
run_test!(|rocket, conn| {
|
||||
run_test!(|client, conn| {
|
||||
// Get the number of tasks initially.
|
||||
let init_num = Task::all(&conn).len();
|
||||
let mut descs = Vec::new();
|
||||
|
@ -94,10 +91,10 @@ fn test_many_insertions() {
|
|||
for i in 0..ITER {
|
||||
// Issue a request to insert a new task with a random description.
|
||||
let desc: String = rng.gen_ascii_chars().take(12).collect();
|
||||
let mut req = MockRequest::new(Post, "/todo")
|
||||
client.post("/todo")
|
||||
.header(ContentType::Form)
|
||||
.body(format!("description={}", desc));
|
||||
req.dispatch_with(&rocket);
|
||||
.body(format!("description={}", desc))
|
||||
.dispatch();
|
||||
|
||||
// Record the description we choose for this iteration.
|
||||
descs.insert(0, desc);
|
||||
|
@ -115,32 +112,34 @@ fn test_many_insertions() {
|
|||
|
||||
#[test]
|
||||
fn test_bad_form_submissions() {
|
||||
run_test!(|rocket, _conn| {
|
||||
run_test!(|client, _conn| {
|
||||
// Submit an empty form. We should get a 422 but no flash error.
|
||||
let mut req = MockRequest::new(Post, "/todo").header(ContentType::Form);
|
||||
let res = req.dispatch_with(&rocket);
|
||||
assert_eq!(res.status(), Status::UnprocessableEntity);
|
||||
let res = client.post("/todo")
|
||||
.header(ContentType::Form)
|
||||
.dispatch();
|
||||
|
||||
let mut cookies = res.headers().get("Set-Cookie");
|
||||
assert_eq!(res.status(), Status::UnprocessableEntity);
|
||||
assert!(!cookies.any(|value| value.contains("error")));
|
||||
|
||||
// Submit a form with an empty description.
|
||||
let mut req = MockRequest::new(Post, "/todo")
|
||||
// Submit a form with an empty description. We look for 'error' in the
|
||||
// cookies which corresponds to flash message being set as an error.
|
||||
let res = client.post("/todo")
|
||||
.header(ContentType::Form)
|
||||
.body("description=");
|
||||
.body("description=")
|
||||
.dispatch();
|
||||
|
||||
// We look for 'error' in the cookies which corresponds to flash message
|
||||
// being set as an error.
|
||||
let res = req.dispatch_with(&rocket);
|
||||
let mut cookies = res.headers().get("Set-Cookie");
|
||||
assert!(cookies.any(|value| value.contains("error")));
|
||||
|
||||
// Submit a form without a description. Expect a 422 but no flash error.
|
||||
let mut req = MockRequest::new(Post, "/todo")
|
||||
let res = client.post("/todo")
|
||||
.header(ContentType::Form)
|
||||
.body("evil=smile");
|
||||
let res = req.dispatch_with(&rocket);
|
||||
assert_eq!(res.status(), Status::UnprocessableEntity);
|
||||
.body("evil=smile")
|
||||
.dispatch();
|
||||
|
||||
let mut cookies = res.headers().get("Set-Cookie");
|
||||
assert_eq!(res.status(), Status::UnprocessableEntity);
|
||||
assert!(!cookies.any(|value| value.contains("error")));
|
||||
})
|
||||
}
|
||||
|
|
|
@ -39,8 +39,11 @@ fn people(id: UUID) -> Result<String, String> {
|
|||
.ok_or(format!("Person not found for UUID: {}", id))?)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite()
|
||||
.mount("/", routes![people])
|
||||
.launch();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket().launch();
|
||||
}
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
use super::rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
fn test(uri: &str, expected: &str) {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::people]);
|
||||
|
||||
let mut req = MockRequest::new(Get, uri);
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut res = client.get(uri).dispatch();
|
||||
assert_eq!(res.body_string(), Some(expected.into()));
|
||||
}
|
||||
|
||||
fn test_404(uri: &str) {
|
||||
let rocket = rocket::ignite().mount("/", routes![super::people]);
|
||||
|
||||
let mut req = MockRequest::new(Get, uri);
|
||||
let res = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let res = client.get(uri).dispatch();
|
||||
assert_eq!(res.status(), Status::NotFound);
|
||||
}
|
||||
|
||||
|
@ -26,8 +19,7 @@ fn test_people() {
|
|||
test("/people/7f205202-7ba1-4c39-b2fc-3e630722bf9f", "We found: Lacy");
|
||||
test("/people/4da34121-bc7d-4fc1-aee6-bf8de0795333", "We found: Bob");
|
||||
test("/people/ad962969-4e3d-4de7-ac4a-2d86d6d10839", "We found: George");
|
||||
|
||||
test("/people/e18b3a5c-488f-4159-a240-2101e0da19fd", "Person not found for UUID: e18b3a5c-488f-4159-a240-2101e0da19fd");
|
||||
|
||||
test("/people/e18b3a5c-488f-4159-a240-2101e0da19fd",
|
||||
"Person not found for UUID: e18b3a5c-488f-4159-a240-2101e0da19fd");
|
||||
test_404("/people/invalid_uuid");
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ log = "0.3"
|
|||
url = "1"
|
||||
toml = { version = "0.2", default-features = false }
|
||||
num_cpus = "1"
|
||||
state = "0.2.1"
|
||||
state = "0.2.2"
|
||||
time = "0.1"
|
||||
memchr = "1"
|
||||
base64 = "0.5.2"
|
||||
|
@ -32,7 +32,7 @@ pear = "0.0.8"
|
|||
pear_codegen = "0.0.8"
|
||||
rustls = { version = "0.8.0", optional = true }
|
||||
cookie = { version = "0.8.1", features = ["percent-encode", "secure"] }
|
||||
hyper = { version = "0.10.9", default-features = false }
|
||||
hyper = { version = "0.10.11", default-features = false }
|
||||
ordermap = "0.2"
|
||||
|
||||
[dependencies.hyper-rustls]
|
||||
|
|
|
@ -13,8 +13,7 @@ fn post() -> &'static str { "post" }
|
|||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
let config = Config::new(Environment::Production).unwrap();
|
||||
rocket::custom(config, false)
|
||||
.mount("/", routes![get, post])
|
||||
rocket::custom(config, false).mount("/", routes![get, post])
|
||||
}
|
||||
|
||||
mod benches {
|
||||
|
@ -22,35 +21,34 @@ mod benches {
|
|||
|
||||
use super::rocket;
|
||||
use self::test::Bencher;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Accept, ContentType};
|
||||
|
||||
#[bench]
|
||||
fn accept_format(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Get, "/").header(Accept::JSON);
|
||||
b.iter(|| { request.dispatch_with(&rocket); });
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut request = client.get("/").header(Accept::JSON);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn wrong_accept_format(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Get, "/").header(Accept::HTML);
|
||||
b.iter(|| { request.dispatch_with(&rocket); });
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut request = client.get("/").header(Accept::HTML);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn content_type_format(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Post, "/").header(ContentType::JSON);
|
||||
b.iter(|| { request.dispatch_with(&rocket); });
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut request = client.post("/").header(ContentType::JSON);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn wrong_content_type_format(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Post, "/").header(ContentType::Plain);
|
||||
b.iter(|| { request.dispatch_with(&rocket); });
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut request = client.post("/").header(ContentType::Plain);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,36 +35,35 @@ mod benches {
|
|||
|
||||
use super::rocket;
|
||||
use self::test::Bencher;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Accept, ContentType};
|
||||
|
||||
#[bench]
|
||||
fn accept_format(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut requests = vec![];
|
||||
requests.push(MockRequest::new(Get, "/").header(Accept::JSON));
|
||||
requests.push(MockRequest::new(Get, "/").header(Accept::HTML));
|
||||
requests.push(MockRequest::new(Get, "/").header(Accept::Plain));
|
||||
requests.push(client.get("/").header(Accept::JSON));
|
||||
requests.push(client.get("/").header(Accept::HTML));
|
||||
requests.push(client.get("/").header(Accept::Plain));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.dispatch_with(&rocket);
|
||||
request.mut_dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn content_type_format(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut requests = vec![];
|
||||
requests.push(MockRequest::new(Post, "/").header(ContentType::JSON));
|
||||
requests.push(MockRequest::new(Post, "/").header(ContentType::HTML));
|
||||
requests.push(MockRequest::new(Post, "/").header(ContentType::Plain));
|
||||
requests.push(client.post("/").header(ContentType::JSON));
|
||||
requests.push(client.post("/").header(ContentType::HTML));
|
||||
requests.push(client.post("/").header(ContentType::Plain));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.dispatch_with(&rocket);
|
||||
request.mut_dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -49,82 +49,82 @@ mod benches {
|
|||
|
||||
use super::{hello_world_rocket, rocket};
|
||||
use self::test::Bencher;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Method::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_hello_world(b: &mut Bencher) {
|
||||
let rocket = hello_world_rocket();
|
||||
let mut request = MockRequest::new(Get, "/");
|
||||
let client = Client::new(hello_world_rocket()).unwrap();
|
||||
let mut request = client.get("/");
|
||||
|
||||
b.iter(|| {
|
||||
request.dispatch_with(&rocket);
|
||||
request.mut_dispatch();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_single_get_index(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let mut request = MockRequest::new(Get, "/");
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut request = client.get("/");
|
||||
|
||||
b.iter(|| {
|
||||
request.dispatch_with(&rocket);
|
||||
request.mut_dispatch();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_get_put_post_index(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Hold all of the requests we're going to make during the benchmark.
|
||||
let mut requests = vec![];
|
||||
requests.push(MockRequest::new(Get, "/"));
|
||||
requests.push(MockRequest::new(Put, "/"));
|
||||
requests.push(MockRequest::new(Post, "/"));
|
||||
requests.push(client.get("/"));
|
||||
requests.push(client.put("/"));
|
||||
requests.push(client.post("/"));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.dispatch_with(&rocket);
|
||||
request.mut_dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_dynamic(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Hold all of the requests we're going to make during the benchmark.
|
||||
let mut requests = vec![];
|
||||
requests.push(MockRequest::new(Get, "/abc"));
|
||||
requests.push(MockRequest::new(Get, "/abcdefg"));
|
||||
requests.push(MockRequest::new(Get, "/123"));
|
||||
requests.push(client.get("/abc"));
|
||||
requests.push(client.get("/abcdefg"));
|
||||
requests.push(client.get("/123"));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.dispatch_with(&rocket);
|
||||
request.mut_dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_simple_routing(b: &mut Bencher) {
|
||||
let rocket = rocket();
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
|
||||
// Hold all of the requests we're going to make during the benchmark.
|
||||
let mut requests = vec![];
|
||||
for route in rocket.routes() {
|
||||
let request = MockRequest::new(route.method, route.path.path());
|
||||
for route in client.rocket().routes() {
|
||||
let request = client.req(route.method, route.path.path());
|
||||
requests.push(request);
|
||||
}
|
||||
|
||||
// A few more for the dynamic route.
|
||||
requests.push(MockRequest::new(Get, "/abc"));
|
||||
requests.push(MockRequest::new(Get, "/abcdefg"));
|
||||
requests.push(MockRequest::new(Get, "/123"));
|
||||
requests.push(client.get("/abc"));
|
||||
requests.push(client.get("/abcdefg"));
|
||||
requests.push(client.get("/123"));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.dispatch_with(&rocket);
|
||||
request.mut_dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -112,6 +112,69 @@ impl Config {
|
|||
Config::default(env, cwd.as_path().join("Rocket.custom.toml"))
|
||||
}
|
||||
|
||||
/// Returns a builder for `Config` structure where the default parameters
|
||||
/// are set to those of the development environment. The root configuration
|
||||
/// directory is set to the current working directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the current directory cannot be retrieved, a `BadCWD` error is
|
||||
/// returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::{Config, Environment};
|
||||
///
|
||||
/// let mut my_config = Config::development().unwrap();
|
||||
/// my_config.set_port(1001);
|
||||
/// ```
|
||||
pub fn development() -> Result<Config> {
|
||||
Config::new(Environment::Development)
|
||||
}
|
||||
|
||||
/// Creates a new configuration using the default parameters from the
|
||||
/// staging environment. The root configuration directory is set to the
|
||||
/// current working directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the current directory cannot be retrieved, a `BadCWD` error is
|
||||
/// returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::{Config, Environment};
|
||||
///
|
||||
/// let mut my_config = Config::staging().expect("cwd");
|
||||
/// my_config.set_port(1001);
|
||||
/// ```
|
||||
pub fn staging() -> Result<Config> {
|
||||
Config::new(Environment::Staging)
|
||||
}
|
||||
|
||||
/// Creates a new configuration using the default parameters from the
|
||||
/// production environment. The root configuration directory is set to the
|
||||
/// current working directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the current directory cannot be retrieved, a `BadCWD` error is
|
||||
/// returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::config::{Config, Environment};
|
||||
///
|
||||
/// let mut my_config = Config::production().expect("cwd");
|
||||
/// my_config.set_port(1001);
|
||||
/// ```
|
||||
pub fn production() -> Result<Config> {
|
||||
Config::new(Environment::Production)
|
||||
}
|
||||
|
||||
/// Returns the default configuration for the environment `env` given that
|
||||
/// the configuration was stored at `config_path`. If `config_path` is not
|
||||
/// an absolute path, an `Err` of `ConfigError::BadFilePath` is returned.
|
||||
|
|
|
@ -66,8 +66,7 @@ impl Data {
|
|||
/// the data in a request.
|
||||
pub fn open(mut self) -> DataStream {
|
||||
let buffer = ::std::mem::replace(&mut self.buffer, vec![]);
|
||||
let empty_stream = Cursor::new(vec![])
|
||||
.chain(NetStream::Local(Cursor::new(vec![])));
|
||||
let empty_stream = Cursor::new(vec![]).chain(NetStream::Empty);
|
||||
|
||||
// FIXME: Insert a `BufReader` in front of the `NetStream` with capacity
|
||||
// 4096. We need the new `Chain` methods to get the inner reader to
|
||||
|
@ -205,9 +204,9 @@ impl Data {
|
|||
}
|
||||
|
||||
/// This creates a `data` object from a local data source `data`.
|
||||
#[inline]
|
||||
pub(crate) fn local(data: Vec<u8>) -> Data {
|
||||
let empty_stream = Cursor::new(vec![])
|
||||
.chain(NetStream::Local(Cursor::new(vec![])));
|
||||
let empty_stream = Cursor::new(vec![]).chain(NetStream::Empty);
|
||||
|
||||
Data {
|
||||
buffer: data,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::io::{self, Cursor};
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, Shutdown};
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub enum NetStream {
|
|||
Http(HttpStream),
|
||||
#[cfg(feature = "tls")]
|
||||
Https(HttpsStream),
|
||||
Local(Cursor<Vec<u8>>)
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl io::Read for NetStream {
|
||||
|
@ -25,9 +25,10 @@ impl io::Read for NetStream {
|
|||
trace_!("NetStream::read()");
|
||||
let res = match *self {
|
||||
Http(ref mut stream) => stream.read(buf),
|
||||
Local(ref mut stream) => stream.read(buf),
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.read(buf)
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.read(buf),
|
||||
Empty => Ok(0),
|
||||
};
|
||||
|
||||
trace_!("NetStream::read() -- complete");
|
||||
res
|
||||
}
|
||||
|
@ -39,8 +40,8 @@ impl io::Write for NetStream {
|
|||
trace_!("NetStream::write()");
|
||||
match *self {
|
||||
Http(ref mut stream) => stream.write(buf),
|
||||
Local(ref mut stream) => stream.write(buf),
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.write(buf)
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.write(buf),
|
||||
Empty => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,8 +49,8 @@ impl io::Write for NetStream {
|
|||
fn flush(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
Http(ref mut stream) => stream.flush(),
|
||||
Local(ref mut stream) => stream.flush(),
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.flush()
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.flush(),
|
||||
Empty => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +61,7 @@ impl NetworkStream for NetStream {
|
|||
match *self {
|
||||
Http(ref mut stream) => stream.peer_addr(),
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.peer_addr(),
|
||||
Local(_) => Err(io::Error::from(io::ErrorKind::AddrNotAvailable)),
|
||||
Empty => Err(io::Error::from(io::ErrorKind::AddrNotAvailable)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +70,7 @@ impl NetworkStream for NetStream {
|
|||
match *self {
|
||||
Http(ref stream) => stream.set_read_timeout(dur),
|
||||
#[cfg(feature = "tls")] Https(ref stream) => stream.set_read_timeout(dur),
|
||||
Local(_) => Ok(()),
|
||||
Empty => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ impl NetworkStream for NetStream {
|
|||
match *self {
|
||||
Http(ref stream) => stream.set_write_timeout(dur),
|
||||
#[cfg(feature = "tls")] Https(ref stream) => stream.set_write_timeout(dur),
|
||||
Local(_) => Ok(()),
|
||||
Empty => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +88,7 @@ impl NetworkStream for NetStream {
|
|||
match *self {
|
||||
Http(ref mut stream) => stream.close(how),
|
||||
#[cfg(feature = "tls")] Https(ref mut stream) => stream.close(how),
|
||||
Local(_) => Ok(()),
|
||||
Empty => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,23 @@
|
|||
use http::Header;
|
||||
|
||||
use std::fmt;
|
||||
use std::cell::RefMut;
|
||||
|
||||
pub use cookie::{Cookie, CookieJar, Iter, CookieBuilder, Delta};
|
||||
pub use cookie::{Cookie, Key, CookieJar};
|
||||
use cookie::{SameSite, Delta};
|
||||
|
||||
use cookie::{PrivateJar, Key};
|
||||
use http::Header;
|
||||
|
||||
impl<'a, 'c> From<&'a Cookie<'c>> for Header<'static> {
|
||||
fn from(cookie: &Cookie) -> Header<'static> {
|
||||
Header::new("Set-Cookie", cookie.encoded().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Cookies<'a> {
|
||||
Jarred(RefMut<'a, CookieJar>),
|
||||
Jarred(RefMut<'a, CookieJar>, &'a Key),
|
||||
Empty(CookieJar)
|
||||
}
|
||||
|
||||
impl<'a> Cookies<'a> {
|
||||
pub(crate) fn new(jar: RefMut<'a, CookieJar>) -> Cookies<'a> {
|
||||
Cookies::Jarred(jar)
|
||||
#[inline]
|
||||
pub(crate) fn new(jar: RefMut<'a, CookieJar>, key: &'a Key) -> Cookies<'a> {
|
||||
Cookies::Jarred(jar, key)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn empty() -> Cookies<'static> {
|
||||
Cookies::Empty(CookieJar::new())
|
||||
}
|
||||
|
@ -34,41 +29,82 @@ impl<'a> Cookies<'a> {
|
|||
|
||||
pub fn get(&self, name: &str) -> Option<&Cookie<'static>> {
|
||||
match *self {
|
||||
Cookies::Jarred(ref jar) => jar.get(name),
|
||||
Cookies::Jarred(ref jar, _) => jar.get(name),
|
||||
Cookies::Empty(_) => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_private(&mut self, name: &str) -> Option<Cookie<'static>> {
|
||||
match *self {
|
||||
Cookies::Jarred(ref mut jar, key) => jar.private(key).get(name),
|
||||
Cookies::Empty(_) => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, cookie: Cookie<'static>) {
|
||||
if let Cookies::Jarred(ref mut jar) = *self {
|
||||
if let Cookies::Jarred(ref mut jar, _) = *self {
|
||||
jar.add(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_private(&mut self, mut cookie: Cookie<'static>) {
|
||||
cookie.set_http_only(true);
|
||||
|
||||
if cookie.path().is_none() {
|
||||
cookie.set_path("/");
|
||||
}
|
||||
|
||||
if cookie.same_site().is_none() {
|
||||
cookie.set_same_site(SameSite::Strict);
|
||||
}
|
||||
|
||||
if let Cookies::Jarred(ref mut jar, key) = *self {
|
||||
jar.private(key).add(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, cookie: Cookie<'static>) {
|
||||
if let Cookies::Jarred(ref mut jar) = *self {
|
||||
if let Cookies::Jarred(ref mut jar, _) = *self {
|
||||
jar.remove(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn private(&mut self, key: &Key) -> PrivateJar {
|
||||
match *self {
|
||||
Cookies::Jarred(ref mut jar) => jar.private(key),
|
||||
Cookies::Empty(ref mut jar) => jar.private(key)
|
||||
pub fn remove_private(&mut self, mut cookie: Cookie<'static>) {
|
||||
if cookie.path().is_none() {
|
||||
cookie.set_path("/");
|
||||
}
|
||||
|
||||
if let Cookies::Jarred(ref mut jar, key) = *self {
|
||||
jar.private(key).remove(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter {
|
||||
pub fn iter<'s>(&'s self) -> impl Iterator<Item=&'s Cookie<'static>> {
|
||||
match *self {
|
||||
Cookies::Jarred(ref jar) => jar.iter(),
|
||||
Cookies::Jarred(ref jar, _) => jar.iter(),
|
||||
Cookies::Empty(ref jar) => jar.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn delta(&self) -> Delta {
|
||||
match *self {
|
||||
Cookies::Jarred(ref jar) => jar.delta(),
|
||||
Cookies::Jarred(ref jar, _) => jar.delta(),
|
||||
Cookies::Empty(ref jar) => jar.delta()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Cookies<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Cookies::Jarred(ref jar, _) => write!(f, "{:?}", jar),
|
||||
Cookies::Empty(ref jar) => write!(f, "{:?}", jar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'c> From<&'a Cookie<'c>> for Header<'static> {
|
||||
fn from(cookie: &Cookie) -> Header<'static> {
|
||||
Header::new("Set-Cookie", cookie.encoded().to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ pub mod uri;
|
|||
#[macro_use]
|
||||
mod known_media_types;
|
||||
mod cookies;
|
||||
mod session;
|
||||
mod method;
|
||||
mod media_type;
|
||||
mod content_type;
|
||||
|
@ -36,5 +35,5 @@ pub use self::header::{Header, HeaderMap};
|
|||
pub use self::raw_str::RawStr;
|
||||
|
||||
pub use self::media_type::MediaType;
|
||||
pub use self::cookies::*;
|
||||
pub use self::session::*;
|
||||
pub use self::cookies::{Cookie, Cookies};
|
||||
pub(crate) use self::cookies::{Key, CookieJar};
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
use std::cell::{RefCell, RefMut};
|
||||
|
||||
use time::{self, Duration};
|
||||
use cookie::{Cookie, CookieJar, Delta};
|
||||
pub use cookie::Key;
|
||||
|
||||
use http::{Header, Cookies};
|
||||
|
||||
const SESSION_PREFIX: &'static str = "__sess_";
|
||||
|
||||
pub struct Session<'a> {
|
||||
cookies: RefCell<Cookies<'a>>,
|
||||
key: &'a Key
|
||||
}
|
||||
|
||||
impl<'a> Session<'a> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new(jar: RefMut<'a, CookieJar>, key: &'a Key) -> Session<'a> {
|
||||
Session { cookies: RefCell::new(Cookies::new(jar)), key: key }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn empty(key: &'a Key) -> Session<'a> {
|
||||
Session { cookies: RefCell::new(Cookies::empty()), key: key }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn header_for(cookie: &Cookie) -> Header<'static> {
|
||||
Header::new("Set-Cookie", format!("{}{}", SESSION_PREFIX, cookie))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn parse_cookie(cookie_str: &str) -> Option<Cookie<'static>> {
|
||||
if !cookie_str.starts_with(SESSION_PREFIX) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Cookie::parse(&cookie_str[SESSION_PREFIX.len()..]).ok()
|
||||
.map(|c| c.into_owned())
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Option<Cookie<'static>> {
|
||||
self.cookies.borrow_mut().private(&self.key).get(name)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, mut cookie: Cookie<'static>) {
|
||||
cookie.set_http_only(true);
|
||||
|
||||
if cookie.path().is_none() {
|
||||
cookie.set_path("/");
|
||||
}
|
||||
|
||||
// TODO: Should this be configurable?
|
||||
if cookie.max_age().is_none() && cookie.expires().is_none() {
|
||||
let session_lifetime = Duration::hours(3);
|
||||
cookie.set_max_age(session_lifetime);
|
||||
cookie.set_expires(time::now() + session_lifetime);
|
||||
}
|
||||
|
||||
self.cookies.get_mut().private(&self.key).add(cookie)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, mut cookie: Cookie<'static>) {
|
||||
if cookie.path().is_none() {
|
||||
cookie.set_path("/");
|
||||
}
|
||||
|
||||
self.cookies.get_mut().private(&self.key).remove(cookie)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn delta(&mut self) -> Delta {
|
||||
self.cookies.get_mut().delta()
|
||||
}
|
||||
}
|
|
@ -117,7 +117,7 @@ extern crate ordermap;
|
|||
#[cfg(test)] #[macro_use] extern crate lazy_static;
|
||||
|
||||
#[doc(hidden)] #[macro_use] pub mod logger;
|
||||
pub mod testing;
|
||||
pub mod local;
|
||||
pub mod http;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
@ -140,6 +140,7 @@ mod ext;
|
|||
#[doc(hidden)] pub use codegen::{StaticRouteInfo, StaticCatchInfo};
|
||||
#[doc(inline)] pub use outcome::Outcome;
|
||||
#[doc(inline)] pub use data::Data;
|
||||
#[doc(inline)] pub use config::Config;
|
||||
pub use router::Route;
|
||||
pub use request::{Request, State};
|
||||
pub use error::{Error, LaunchError};
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
use {Rocket, Request};
|
||||
use local::LocalRequest;
|
||||
use http::Method;
|
||||
use http::uri::URI;
|
||||
use error::LaunchError;
|
||||
|
||||
pub struct Client {
|
||||
rocket: Rocket,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
#[inline]
|
||||
pub fn new(rocket: Rocket) -> Result<Client, LaunchError> {
|
||||
if let Some(err) = rocket.prelaunch_check() {
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
Ok(Client {
|
||||
rocket: rocket,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn rocket(&self) -> &Rocket {
|
||||
&self.rocket
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn req<'c, 'u: 'c, U>(&'c self, method: Method, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<URI<'u>>
|
||||
{
|
||||
let request = Request::new(&self.rocket, method, uri);
|
||||
LocalRequest::new(&self.rocket, request)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get<'c, 'u: 'c, U: Into<URI<'u>>>(&'c self, uri: U) -> LocalRequest<'c> {
|
||||
self.req(Method::Get, uri)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn put<'c, 'u: 'c, U: Into<URI<'u>>>(&'c self, uri: U) -> LocalRequest<'c> {
|
||||
self.req(Method::Put, uri)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn post<'c, 'u: 'c, U: Into<URI<'u>>>(&'c self, uri: U) -> LocalRequest<'c> {
|
||||
self.req(Method::Post, uri)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn delete<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<URI<'u>>
|
||||
{
|
||||
self.req(Method::Delete, uri)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn options<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<URI<'u>>
|
||||
{
|
||||
self.req(Method::Options, uri)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn head<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<URI<'u>>
|
||||
{
|
||||
self.req(Method::Head, uri)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn patch<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<URI<'u>>
|
||||
{
|
||||
self.req(Method::Patch, uri)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
//! Structures for local dispatching of requests, primarily for testing.
|
||||
//!
|
||||
//! This module allows for simple request dispatching against a local,
|
||||
//! non-networked instance of Rocket. The primary use of this module is to unit
|
||||
//! and integration test Rocket applications by crafting requests, dispatching
|
||||
//! them, and verifying the response.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! This module contains a [`Client`] structure that is used to create
|
||||
//! [`LocalRequest`] structures that can be dispatched against a given
|
||||
//! [`Rocket`] instance. Usage is straightforward:
|
||||
//!
|
||||
//! 1. Construct a `Rocket` instance that represents the application.
|
||||
//!
|
||||
//! ```rust
|
||||
//! let rocket = rocket::ignite();
|
||||
//! # let _ = rocket;
|
||||
//! ```
|
||||
//!
|
||||
//! 2. Construct a `Client` using the `Rocket` instance.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! let client = Client::new(rocket).expect("valid rocket instance");
|
||||
//! # let _ = client;
|
||||
//! ```
|
||||
//!
|
||||
//! 3. Construct requests using the `Client` instance.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! # let client = Client::new(rocket).unwrap();
|
||||
//! let req = client.get("/");
|
||||
//! # let _ = req;
|
||||
//! ```
|
||||
//!
|
||||
//! 3. Dispatch the request to retrieve the response.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! # let client = Client::new(rocket).unwrap();
|
||||
//! # let req = client.get("/");
|
||||
//! let response = req.dispatch();
|
||||
//! # let _ = response;
|
||||
//! ```
|
||||
//!
|
||||
//! All together and in idiomatic fashion, this might look like:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use rocket::local::Client;
|
||||
//!
|
||||
//! let client = Client::new(rocket::ignite()).expect("valid rocket");
|
||||
//! let response = client.post("/")
|
||||
//! .body("Hello, world!")
|
||||
//! .dispatch();
|
||||
//! # let _ = response;
|
||||
//! ```
|
||||
//!
|
||||
//! # Unit/Integration Testing
|
||||
//!
|
||||
//! This module can be used to test a Rocket application by constructing
|
||||
//! requests via `Client` and validating the resulting response. As an example,
|
||||
//! consider the following complete "Hello, world!" application, with testing.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(plugin)]
|
||||
//! #![plugin(rocket_codegen)]
|
||||
//!
|
||||
//! extern crate rocket;
|
||||
//!
|
||||
//! #[get("/")]
|
||||
//! fn hello() -> &'static str {
|
||||
//! "Hello, world!"
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() { }
|
||||
//! #[cfg(test)]
|
||||
//! mod test {
|
||||
//! use super::{rocket, hello};
|
||||
//! use rocket::local::Client;
|
||||
//!
|
||||
//! #[test]
|
||||
//! fn test_hello_world() {
|
||||
//! // Construct a client to use for dispatching requests.
|
||||
//! let client = Client::new(rocket::ignite().mount("/", routes![hello]));
|
||||
//!
|
||||
//! // Dispatch a request to 'GET /' and validate the response.
|
||||
//! let mut response = client.get("/").dispatch();
|
||||
//! assert_eq!(response.body_string(), Some("Hello, world!".into()));
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`Client`]: /rocket/local/struct.Client.html
|
||||
//! [`LocalRequest`]: /rocket/local/struct.LocalRequest.html
|
||||
//! [`Rocket`]: /rocket/struct.Rocket.html
|
||||
//!
|
||||
|
||||
mod request;
|
||||
mod client;
|
||||
|
||||
pub use self::request::{LocalResponse, LocalRequest};
|
||||
pub use self::client::Client;
|
|
@ -0,0 +1,265 @@
|
|||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::mem::transmute;
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use {Rocket, Request, Response, Data};
|
||||
use http::{Header, Cookie};
|
||||
|
||||
pub struct LocalRequest<'c> {
|
||||
rocket: &'c Rocket,
|
||||
ptr: *mut Request<'c>,
|
||||
request: Rc<Request<'c>>,
|
||||
data: Vec<u8>
|
||||
}
|
||||
|
||||
pub struct LocalResponse<'c> {
|
||||
_request: Rc<Request<'c>>,
|
||||
response: Response<'c>,
|
||||
}
|
||||
|
||||
impl<'c> Deref for LocalResponse<'c> {
|
||||
type Target = Response<'c>;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Response<'c> {
|
||||
&self.response
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c> DerefMut for LocalResponse<'c> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Response<'c> {
|
||||
&mut self.response
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c> LocalRequest<'c> {
|
||||
#[inline(always)]
|
||||
pub fn new(rocket: &'c Rocket, request: Request<'c>) -> LocalRequest<'c> {
|
||||
let mut req = Rc::new(request);
|
||||
let ptr = Rc::get_mut(&mut req).unwrap() as *mut Request;
|
||||
LocalRequest { rocket: rocket, ptr: ptr, request: req, data: vec![] }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner(&self) -> &Request<'c> {
|
||||
&*self.request
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn request(&mut self) -> &mut Request<'c> {
|
||||
unsafe { &mut *self.ptr }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn dispatch(mut self) -> LocalResponse<'c> {
|
||||
let req = unsafe { transmute(self.request()) };
|
||||
let response = self.rocket.dispatch(req, Data::local(self.data));
|
||||
|
||||
LocalResponse {
|
||||
_request: self.request,
|
||||
response: response
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mut_dispatch(&mut self) -> LocalResponse<'c> {
|
||||
let data = ::std::mem::replace(&mut self.data, vec![]);
|
||||
let req = unsafe { transmute(self.request()) };
|
||||
let response = self.rocket.dispatch(req, Data::local(data));
|
||||
|
||||
LocalResponse {
|
||||
_request: self.request.clone(),
|
||||
response: response
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn cloned_dispatch(&self) -> LocalResponse<'c> {
|
||||
let cloned = (*self.request).clone();
|
||||
let mut req = LocalRequest::new(self.rocket, cloned);
|
||||
req.data = self.data.clone();
|
||||
req.dispatch()
|
||||
}
|
||||
|
||||
/// Add a header to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let client = Client::new(rocket::ignite()).unwrap();
|
||||
/// let req = client.get("/").header(ContentType::JSON);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn header<H: Into<Header<'static>>>(mut self, header: H) -> Self {
|
||||
self.request().add_header(header.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a header to this request without consuming `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// let client = Client::new(rocket::ignite()).unwrap();
|
||||
/// let mut req = client.get("/");
|
||||
/// req.add_header(ContentType::JSON);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn add_header<H: Into<Header<'static>>>(&mut self, header: H) {
|
||||
self.request().add_header(header.into());
|
||||
}
|
||||
|
||||
/// Set the remote address of this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the remote address to "8.8.8.8:80":
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// let client = Client::new(rocket::ignite()).unwrap();
|
||||
/// let address = "8.8.8.8:80".parse().unwrap();
|
||||
/// let req = client.get("/").remote(address);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn remote(mut self, address: SocketAddr) -> Self {
|
||||
self.request().set_remote(address);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a cookie to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` cookie:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// let client = Client::new(rocket::ignite()).unwrap();
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = client.get("/")
|
||||
/// .cookie(Cookie::new("username", "sb"))
|
||||
/// .cookie(Cookie::new("user_id", format!("{}", 12)));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cookie(self, cookie: Cookie<'static>) -> Self {
|
||||
self.request.cookies().add(cookie);
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: For CGI, we want to be able to set the body to be stdin without
|
||||
// actually reading everything into a vector. Can we allow that here while
|
||||
// keeping the simplicity? Looks like it would require us to reintroduce a
|
||||
// NetStream::Local(Box<Read>) or something like that.
|
||||
|
||||
/// Set the body (data) of the request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the body to be a JSON structure; also sets the Content-Type.
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// let client = Client::new(rocket::ignite()).unwrap();
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = client.post("/")
|
||||
/// .header(ContentType::JSON)
|
||||
/// .body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self {
|
||||
self.data = body.as_ref().into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c> fmt::Debug for LocalRequest<'c> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.request, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c> fmt::Debug for LocalResponse<'c> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.response, f)
|
||||
}
|
||||
}
|
||||
|
||||
// fn test() {
|
||||
// use local::Client;
|
||||
|
||||
// let rocket = Rocket::ignite();
|
||||
// let res = {
|
||||
// let mut client = Client::new(rocket).unwrap();
|
||||
// client.get("/").dispatch()
|
||||
// };
|
||||
|
||||
// // let client = Client::new(rocket).unwrap();
|
||||
// // let res1 = client.get("/").dispatch();
|
||||
// // let res2 = client.get("/").dispatch();
|
||||
// }
|
||||
|
||||
// fn test() {
|
||||
// use local::Client;
|
||||
|
||||
// let rocket = Rocket::ignite();
|
||||
// let res = {
|
||||
// Client::new(rocket).unwrap()
|
||||
// .get("/").dispatch();
|
||||
// };
|
||||
|
||||
// // let client = Client::new(rocket).unwrap();
|
||||
// // let res1 = client.get("/").dispatch();
|
||||
// // let res2 = client.get("/").dispatch();
|
||||
// }
|
||||
|
||||
// fn test() {
|
||||
// use local::Client;
|
||||
|
||||
// let rocket = Rocket::ignite();
|
||||
// let client = Client::new(rocket).unwrap();
|
||||
|
||||
// let res = {
|
||||
// let x = client.get("/").dispatch();
|
||||
// let y = client.get("/").dispatch();
|
||||
// };
|
||||
|
||||
// let x = client;
|
||||
// }
|
||||
|
||||
// fn test() {
|
||||
// use local::Client;
|
||||
|
||||
// let rocket1 = Rocket::ignite();
|
||||
// let rocket2 = Rocket::ignite();
|
||||
|
||||
// let client1 = Client::new(rocket1).unwrap();
|
||||
// let client2 = Client::new(rocket2).unwrap();
|
||||
|
||||
// let res = {
|
||||
// let mut res1 = client1.get("/");
|
||||
// res1.set_client(&client2);
|
||||
// res1
|
||||
// };
|
||||
|
||||
// drop(client1);
|
||||
// }
|
|
@ -6,7 +6,7 @@ use request::Request;
|
|||
use outcome::{self, IntoOutcome};
|
||||
use outcome::Outcome::*;
|
||||
|
||||
use http::{Status, ContentType, Accept, Method, Cookies, Session};
|
||||
use http::{Status, ContentType, Accept, Method, Cookies};
|
||||
use http::uri::URI;
|
||||
|
||||
/// Type alias for the `Outcome` of a `FromRequest` conversion.
|
||||
|
@ -236,14 +236,6 @@ impl<'a, 'r> FromRequest<'a, 'r> for Cookies<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'r> FromRequest<'a, 'r> for Session<'a> {
|
||||
type Error = ();
|
||||
|
||||
fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
Success(request.session())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'r> FromRequest<'a, 'r> for &'a Accept {
|
||||
type Error = ();
|
||||
|
||||
|
|
|
@ -4,32 +4,26 @@ use std::fmt;
|
|||
use std::str;
|
||||
|
||||
use yansi::Paint;
|
||||
|
||||
use state::{Container, Storage};
|
||||
|
||||
use error::Error;
|
||||
use super::{FromParam, FromSegments, FromRequest, Outcome};
|
||||
|
||||
use rocket::Rocket;
|
||||
use router::Route;
|
||||
use config::{Config, Limits};
|
||||
use http::uri::{URI, Segments};
|
||||
use http::{Method, Header, HeaderMap, Cookies, Session, CookieJar};
|
||||
use error::Error;
|
||||
use http::{Method, Header, HeaderMap, Cookies, CookieJar};
|
||||
use http::{RawStr, ContentType, Accept, MediaType};
|
||||
use http::hyper;
|
||||
|
||||
struct PresetState<'r> {
|
||||
// The running Rocket instances configuration.
|
||||
config: &'r Config,
|
||||
// The managed state of the running Rocket instance.
|
||||
state: &'r Container,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct RequestState<'r> {
|
||||
preset: Option<PresetState<'r>>,
|
||||
config: &'r Config,
|
||||
state: &'r Container,
|
||||
params: RefCell<Vec<(usize, usize)>>,
|
||||
route: Cell<Option<&'r Route>>,
|
||||
cookies: RefCell<CookieJar>,
|
||||
session: RefCell<CookieJar>,
|
||||
accept: Storage<Option<Accept>>,
|
||||
content_type: Storage<Option<ContentType>>,
|
||||
}
|
||||
|
@ -41,6 +35,7 @@ struct RequestState<'r> {
|
|||
/// [FromRequest](/rocket/request/trait.FromRequest.html) implementations. It
|
||||
/// contains all of the information for a given web request except for the body
|
||||
/// data. This includes the HTTP method, URI, cookies, headers, and more.
|
||||
#[derive(Clone)]
|
||||
pub struct Request<'r> {
|
||||
method: Method,
|
||||
uri: URI<'r>,
|
||||
|
@ -53,45 +48,45 @@ impl<'r> Request<'r> {
|
|||
/// Create a new `Request` with the given `method` and `uri`. The `uri`
|
||||
/// parameter can be of any type that implements `Into<URI>` including
|
||||
/// `&str` and `String`; it must be a valid absolute URI.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let request = Request::new(Method::Get, "/uri");
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new<'s: 'r, U: Into<URI<'s>>>(method: Method, uri: U) -> Request<'r> {
|
||||
pub(crate) fn new<'s: 'r, U: Into<URI<'s>>>(rocket: &'r Rocket,
|
||||
method: Method,
|
||||
uri: U) -> Request<'r> {
|
||||
Request {
|
||||
method: method,
|
||||
uri: uri.into(),
|
||||
headers: HeaderMap::new(),
|
||||
remote: None,
|
||||
state: RequestState {
|
||||
preset: None,
|
||||
config: &rocket.config,
|
||||
state: &rocket.state,
|
||||
route: Cell::new(None),
|
||||
params: RefCell::new(Vec::new()),
|
||||
cookies: RefCell::new(CookieJar::new()),
|
||||
session: RefCell::new(CookieJar::new()),
|
||||
accept: Storage::new(),
|
||||
content_type: Storage::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn example<F: Fn(&mut Request)>(method: Method, uri: &str, f: F) {
|
||||
let rocket = Rocket::custom(Config::development().unwrap(), true);
|
||||
let mut request = Request::new(&rocket, method, uri);
|
||||
f(&mut request);
|
||||
}
|
||||
|
||||
/// Retrieve the method from `self`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// # use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// let request = Request::new(Method::Get, "/uri");
|
||||
/// # Request::example(Method::Get, "/uri", |request| {
|
||||
/// assert_eq!(request.method(), Method::Get);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn method(&self) -> Method {
|
||||
|
@ -103,14 +98,15 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// # use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// let mut request = Request::new(Method::Get, "/uri");
|
||||
/// # Request::example(Method::Get, "/uri", |request| {
|
||||
/// assert_eq!(request.method(), Method::Get);
|
||||
///
|
||||
/// request.set_method(Method::Post);
|
||||
/// assert_eq!(request.method(), Method::Post);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn set_method(&mut self, method: Method) {
|
||||
|
@ -122,11 +118,11 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// let request = Request::new(Method::Get, "/uri");
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// # Request::example(Method::Get, "/uri", |request| {
|
||||
/// assert_eq!(request.uri().as_str(), "/uri");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn uri(&self) -> &URI {
|
||||
|
@ -140,13 +136,12 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// let mut request = Request::new(Method::Get, "/uri");
|
||||
///
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// # Request::example(Method::Get, "/uri", |mut request| {
|
||||
/// request.set_uri("/hello/Sergio?type=greeting");
|
||||
/// assert_eq!(request.uri().as_str(), "/hello/Sergio?type=greeting");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn set_uri<'u: 'r, U: Into<URI<'u>>>(&mut self, uri: U) {
|
||||
|
@ -161,11 +156,11 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// let request = Request::new(Method::Get, "/uri");
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// # Request::example(Method::Get, "/uri", |request| {
|
||||
/// assert!(request.remote().is_none());
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn remote(&self) -> Option<SocketAddr> {
|
||||
|
@ -179,17 +174,17 @@ impl<'r> Request<'r> {
|
|||
/// Set the remote address to be 127.0.0.1:8000:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// use std::net::{SocketAddr, IpAddr, Ipv4Addr};
|
||||
///
|
||||
/// let mut request = Request::new(Method::Get, "/uri");
|
||||
///
|
||||
/// # Request::example(Method::Get, "/uri", |mut request| {
|
||||
/// let (ip, port) = (IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000);
|
||||
/// let localhost = SocketAddr::new(ip, port);
|
||||
/// request.set_remote(localhost);
|
||||
///
|
||||
/// assert_eq!(request.remote(), Some(localhost));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn set_remote(&mut self, address: SocketAddr) {
|
||||
|
@ -202,12 +197,12 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// let request = Request::new(Method::Get, "/uri");
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// # Request::example(Method::Get, "/uri", |request| {
|
||||
/// let header_map = request.headers();
|
||||
/// assert!(header_map.is_empty());
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn headers(&self) -> &HeaderMap<'r> {
|
||||
|
@ -219,18 +214,20 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::{Method, ContentType};
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// let mut request = Request::new(Method::Get, "/uri");
|
||||
/// # Request::example(Method::Get, "/uri", |mut request| {
|
||||
/// assert!(request.headers().is_empty());
|
||||
///
|
||||
/// request.add_header(ContentType::HTML);
|
||||
/// assert!(request.headers().contains("Content-Type"));
|
||||
/// assert_eq!(request.headers().len(), 1);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn add_header<H: Into<Header<'r>>>(&mut self, header: H) {
|
||||
pub fn add_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) {
|
||||
self.headers.add(header.into());
|
||||
}
|
||||
|
||||
|
@ -240,10 +237,11 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::{Method, ContentType};
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// let mut request = Request::new(Method::Get, "/uri");
|
||||
/// # Request::example(Method::Get, "/uri", |mut request| {
|
||||
/// assert!(request.headers().is_empty());
|
||||
///
|
||||
/// request.add_header(ContentType::Any);
|
||||
|
@ -251,13 +249,14 @@ impl<'r> Request<'r> {
|
|||
///
|
||||
/// request.replace_header(ContentType::PNG);
|
||||
/// assert_eq!(request.headers().get_one("Content-Type"), Some("image/png"));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn replace_header<H: Into<Header<'r>>>(&mut self, header: H) {
|
||||
pub fn replace_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) {
|
||||
self.headers.replace(header.into());
|
||||
}
|
||||
|
||||
/// Returns a borrow to the cookies in `self`.
|
||||
/// Returns a wrapped borrow to the cookies in `self`.
|
||||
///
|
||||
/// Note that `Cookies` implements internal mutability, so this method
|
||||
/// allows you to get _and_ set cookies in `self`.
|
||||
|
@ -267,17 +266,18 @@ impl<'r> Request<'r> {
|
|||
/// Add a new cookie to a request's cookies:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::{Cookie, Method};
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// let request = Request::new(Method::Get, "/uri");
|
||||
/// # Request::example(Method::Get, "/uri", |mut request| {
|
||||
/// request.cookies().add(Cookie::new("key", "val"));
|
||||
/// request.cookies().add(Cookie::new("ans", format!("life: {}", 38 + 4)));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cookies(&self) -> Cookies {
|
||||
match self.state.cookies.try_borrow_mut() {
|
||||
Ok(jar) => Cookies::new(jar),
|
||||
Ok(jar) => Cookies::new(jar, self.state.config.secret_key()),
|
||||
Err(_) => {
|
||||
error_!("Multiple `Cookies` instances are active at once.");
|
||||
info_!("An instance of `Cookies` must be dropped before another \
|
||||
|
@ -288,21 +288,6 @@ impl<'r> Request<'r> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn session(&self) -> Session {
|
||||
let key = self.preset().config.secret_key();
|
||||
match self.state.session.try_borrow_mut() {
|
||||
Ok(jar) => Session::new(jar, key),
|
||||
Err(_) => {
|
||||
error_!("Multiple `Session` instances are active at once.");
|
||||
info_!("An instance of `Session` must be dropped before another \
|
||||
can be retrieved.");
|
||||
warn_!("The retrieved `Session` instance will be empty.");
|
||||
Session::empty(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Content-Type header of `self`. If the header is not present,
|
||||
/// returns `None`. The Content-Type header is cached after the first call
|
||||
/// to this function. As a result, subsequent calls will always return the
|
||||
|
@ -311,20 +296,22 @@ impl<'r> Request<'r> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::{Method, ContentType};
|
||||
///
|
||||
/// let mut request = Request::new(Method::Get, "/uri");
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// # Request::example(Method::Get, "/uri", |mut request| {
|
||||
/// assert_eq!(request.content_type(), None);
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::Request;
|
||||
/// use rocket::http::{Method, ContentType};
|
||||
/// # use rocket::Request;
|
||||
/// # use rocket::http::Method;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// let mut request = Request::new(Method::Get, "/uri");
|
||||
/// # Request::example(Method::Get, "/uri", |mut request| {
|
||||
/// request.add_header(ContentType::JSON);
|
||||
/// assert_eq!(request.content_type(), Some(&ContentType::JSON));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn content_type(&self) -> Option<&ContentType> {
|
||||
|
@ -361,7 +348,7 @@ impl<'r> Request<'r> {
|
|||
|
||||
/// Get the limits.
|
||||
pub fn limits(&self) -> &'r Limits {
|
||||
&self.preset().config.limits
|
||||
&self.state.config.limits
|
||||
}
|
||||
|
||||
/// Get the current route, if any.
|
||||
|
@ -463,17 +450,6 @@ impl<'r> Request<'r> {
|
|||
Some(Segments(&path[i..j]))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn preset(&self) -> &PresetState<'r> {
|
||||
match self.state.preset {
|
||||
Some(ref state) => state,
|
||||
None => {
|
||||
error_!("Internal Rocket error: preset state is unset!");
|
||||
panic!("Please report this error to the GitHub issue tracker.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set `self`'s parameters given that the route used to reach this request
|
||||
/// was `route`. This should only be used internally by `Rocket` as improper
|
||||
/// use may result in out of bounds indexing.
|
||||
|
@ -490,12 +466,6 @@ impl<'r> Request<'r> {
|
|||
self.state.cookies = RefCell::new(jar);
|
||||
}
|
||||
|
||||
/// Replace all of the session cookie in `self` with those in `jar`.
|
||||
#[inline]
|
||||
pub(crate) fn set_session(&mut self, jar: CookieJar) {
|
||||
self.state.session = RefCell::new(jar);
|
||||
}
|
||||
|
||||
/// Try to derive some guarded value from `self`.
|
||||
#[inline(always)]
|
||||
pub fn guard<'a, T: FromRequest<'a, 'r>>(&'a self) -> Outcome<T, T::Error> {
|
||||
|
@ -505,17 +475,12 @@ impl<'r> Request<'r> {
|
|||
/// Get the managed state T, if it exists. For internal use only!
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_state<T: Send + Sync + 'static>(&self) -> Option<&'r T> {
|
||||
self.preset().state.try_get()
|
||||
}
|
||||
|
||||
/// Set the precomputed state. For internal use only!
|
||||
#[inline(always)]
|
||||
pub(crate) fn set_preset(&mut self, config: &'r Config, state: &'r Container) {
|
||||
self.state.preset = Some(PresetState { config, state });
|
||||
self.state.state.try_get()
|
||||
}
|
||||
|
||||
/// Convert from Hyper types into a Rocket Request.
|
||||
pub(crate) fn from_hyp(h_method: hyper::Method,
|
||||
pub(crate) fn from_hyp(rocket: &'r Rocket,
|
||||
h_method: hyper::Method,
|
||||
h_headers: hyper::header::Headers,
|
||||
h_uri: hyper::RequestUri,
|
||||
h_addr: SocketAddr,
|
||||
|
@ -533,13 +498,12 @@ impl<'r> Request<'r> {
|
|||
};
|
||||
|
||||
// Construct the request object.
|
||||
let mut request = Request::new(method, uri);
|
||||
let mut request = Request::new(rocket, method, uri);
|
||||
request.set_remote(h_addr);
|
||||
|
||||
// Set the request cookies, if they exist.
|
||||
if let Some(cookie_headers) = h_headers.get_raw("Cookie") {
|
||||
let mut cookie_jar = CookieJar::new();
|
||||
let mut session_jar = CookieJar::new();
|
||||
for header in cookie_headers {
|
||||
let raw_str = match ::std::str::from_utf8(header) {
|
||||
Ok(string) => string,
|
||||
|
@ -547,16 +511,13 @@ impl<'r> Request<'r> {
|
|||
};
|
||||
|
||||
for cookie_str in raw_str.split(";").map(|s| s.trim()) {
|
||||
if let Some(cookie) = Session::parse_cookie(cookie_str) {
|
||||
session_jar.add_original(cookie);
|
||||
} else if let Some(cookie) = Cookies::parse_cookie(cookie_str) {
|
||||
if let Some(cookie) = Cookies::parse_cookie(cookie_str) {
|
||||
cookie_jar.add_original(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.set_cookies(cookie_jar);
|
||||
request.set_session(session_jar);
|
||||
}
|
||||
|
||||
// Set the rest of the headers.
|
||||
|
@ -575,6 +536,17 @@ impl<'r> Request<'r> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'r> fmt::Debug for Request<'r> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Request")
|
||||
.field("method", &self.method)
|
||||
.field("uri", &self.uri)
|
||||
.field("headers", &self.headers())
|
||||
.field("remote", &self.remote())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> fmt::Display for Request<'r> {
|
||||
/// Pretty prints a Request. This is primarily used by Rocket's logging
|
||||
/// infrastructure.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use Request;
|
||||
use {Rocket, Request, Config};
|
||||
use http::hyper;
|
||||
|
||||
macro_rules! assert_headers {
|
||||
|
@ -20,7 +20,9 @@ macro_rules! assert_headers {
|
|||
$(expected.entry($key).or_insert(vec![]).append(&mut vec![$($value),+]);)+
|
||||
|
||||
// Dispatch the request and check that the headers are what we expect.
|
||||
let req = Request::from_hyp(h_method, h_headers, h_uri, h_addr).unwrap();
|
||||
let config = Config::development().unwrap();
|
||||
let r = Rocket::custom(config, true);
|
||||
let req = Request::from_hyp(&r, h_method, h_headers, h_uri, h_addr).unwrap();
|
||||
let actual_headers = req.headers();
|
||||
for (key, values) in expected.iter() {
|
||||
let actual: Vec<_> = actual_headers.get(key).collect();
|
||||
|
|
|
@ -903,7 +903,29 @@ impl<'r> Response<'r> {
|
|||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn body_string(&mut self) -> Option<String> {
|
||||
self.take_body().and_then(|b| b.into_string())
|
||||
self.take_body().and_then(Body::into_string)
|
||||
}
|
||||
|
||||
/// Consumes `self's` body and reads it into a `Vec` of `u8` bytes. If
|
||||
/// `self` doesn't have a body or reading fails returns `None`. Note that
|
||||
/// `self`'s `body` is consumed after a call to this method.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io::Cursor;
|
||||
/// use rocket::Response;
|
||||
///
|
||||
/// let mut response = Response::new();
|
||||
/// assert!(response.body().is_none());
|
||||
///
|
||||
/// response.set_sized_body(Cursor::new("hi!"));
|
||||
/// assert_eq!(response.body_bytes(), Some(vec![0x68, 0x69, 0x21]));
|
||||
/// assert!(response.body().is_none());
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn body_bytes(&mut self) -> Option<Vec<u8>> {
|
||||
self.take_body().and_then(Body::into_bytes)
|
||||
}
|
||||
|
||||
/// Moves the body of `self` out and returns it, if there is one, leaving no
|
||||
|
|
|
@ -21,19 +21,19 @@ use outcome::Outcome;
|
|||
use error::{Error, LaunchError, LaunchErrorKind};
|
||||
use fairing::{Fairing, Fairings};
|
||||
|
||||
use http::{Method, Status, Header, Session};
|
||||
use http::{Method, Status, Header};
|
||||
use http::hyper::{self, header};
|
||||
use http::uri::URI;
|
||||
|
||||
/// The main `Rocket` type: used to mount routes and catchers and launch the
|
||||
/// application.
|
||||
pub struct Rocket {
|
||||
config: Config,
|
||||
pub(crate) config: Config,
|
||||
router: Router,
|
||||
default_catchers: HashMap<u16, Catcher>,
|
||||
catchers: HashMap<u16, Catcher>,
|
||||
state: Container,
|
||||
fairings: Fairings
|
||||
pub(crate) state: Container,
|
||||
fairings: Fairings,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -50,11 +50,12 @@ impl hyper::Handler for Rocket {
|
|||
let (h_addr, h_method, h_headers, h_uri, _, h_body) = hyp_req.deconstruct();
|
||||
|
||||
// Convert the Hyper request into a Rocket request.
|
||||
let mut req = match Request::from_hyp(h_method, h_headers, h_uri, h_addr) {
|
||||
let req_res = Request::from_hyp(self, h_method, h_headers, h_uri, h_addr);
|
||||
let mut req = match req_res {
|
||||
Ok(req) => req,
|
||||
Err(e) => {
|
||||
error!("Bad incoming request: {}", e);
|
||||
let dummy = Request::new(Method::Get, URI::new("<unknown>"));
|
||||
let dummy = Request::new(self, Method::Get, URI::new("<unknown>"));
|
||||
let r = self.handle_error(Status::InternalServerError, &dummy);
|
||||
return self.issue_response(r, res);
|
||||
}
|
||||
|
@ -209,16 +210,12 @@ impl Rocket {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Explain this `UnsafeCell` business at a macro level.
|
||||
#[inline]
|
||||
pub(crate) fn dispatch<'s, 'r>(&'s self,
|
||||
request: &'r mut Request<'s>,
|
||||
data: Data) -> Response<'r> {
|
||||
info!("{}:", request);
|
||||
|
||||
// Inform the request about all of the precomputed state.
|
||||
request.set_preset(&self.config, &self.state);
|
||||
|
||||
// Do a bit of preprocessing before routing; run the attached fairings.
|
||||
self.preprocess_request(request, &data);
|
||||
self.fairings.handle_request(request, &data);
|
||||
|
@ -226,16 +223,11 @@ impl Rocket {
|
|||
// Route the request to get a response.
|
||||
let mut response = match self.route(request, data) {
|
||||
Outcome::Success(mut response) => {
|
||||
// A user's route responded! Set the regular cookies.
|
||||
// A user's route responded! Set the cookies.
|
||||
for cookie in request.cookies().delta() {
|
||||
response.adjoin_header(cookie);
|
||||
}
|
||||
|
||||
// And now the session cookies.
|
||||
for cookie in request.session().delta() {
|
||||
response.adjoin_header(Session::header_for(cookie));
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
Outcome::Forward(data) => {
|
||||
|
|
|
@ -131,6 +131,8 @@ mod tests {
|
|||
use std::str::FromStr;
|
||||
|
||||
use super::Collider;
|
||||
use rocket::Rocket;
|
||||
use config::Config;
|
||||
use request::Request;
|
||||
use data::Data;
|
||||
use handler::Outcome;
|
||||
|
@ -368,7 +370,8 @@ mod tests {
|
|||
fn req_route_mt_collide<S1, S2>(m: Method, mt1: S1, mt2: S2) -> bool
|
||||
where S1: Into<Option<&'static str>>, S2: Into<Option<&'static str>>
|
||||
{
|
||||
let mut req = Request::new(m, "/");
|
||||
let rocket = Rocket::custom(Config::development().unwrap(), true);
|
||||
let mut req = Request::new(&rocket, m, "/");
|
||||
if let Some(mt_str) = mt1.into() {
|
||||
if m.supports_payload() {
|
||||
req.replace_header(mt_str.parse::<ContentType>().unwrap());
|
||||
|
@ -425,7 +428,8 @@ mod tests {
|
|||
}
|
||||
|
||||
fn req_route_path_collide(a: &'static str, b: &'static str) -> bool {
|
||||
let req = Request::new(Get, a.to_string());
|
||||
let rocket = Rocket::custom(Config::development().unwrap(), true);
|
||||
let req = Request::new(&rocket, Get, a.to_string());
|
||||
let route = Route::ranked(0, Get, b.to_string(), dummy_handler);
|
||||
route.collides_with(&req)
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ impl Router {
|
|||
mod test {
|
||||
use super::{Router, Route};
|
||||
|
||||
use rocket::Rocket;
|
||||
use config::Config;
|
||||
use http::Method;
|
||||
use http::Method::*;
|
||||
use http::uri::URI;
|
||||
|
@ -159,7 +161,8 @@ mod test {
|
|||
}
|
||||
|
||||
fn route<'a>(router: &'a Router, method: Method, uri: &str) -> Option<&'a Route> {
|
||||
let request = Request::new(method, URI::new(uri));
|
||||
let rocket = Rocket::custom(Config::development().unwrap(), true);
|
||||
let request = Request::new(&rocket, method, URI::new(uri));
|
||||
let matches = router.route(&request);
|
||||
if matches.len() > 0 {
|
||||
Some(matches[0])
|
||||
|
@ -169,7 +172,8 @@ mod test {
|
|||
}
|
||||
|
||||
fn matches<'a>(router: &'a Router, method: Method, uri: &str) -> Vec<&'a Route> {
|
||||
let request = Request::new(method, URI::new(uri));
|
||||
let rocket = Rocket::custom(Config::development().unwrap(), true);
|
||||
let request = Request::new(&rocket, method, URI::new(uri));
|
||||
router.route(&request)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,274 +0,0 @@
|
|||
//! A tiny module for testing Rocket applications.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! The testing methadology is simple:
|
||||
//!
|
||||
//! 1. Construct a `Rocket` instance.
|
||||
//! 2. Construct a request.
|
||||
//! 3. Dispatch the request using the Rocket instance.
|
||||
//! 4. Inspect, validate, and verify the response.
|
||||
//!
|
||||
//! ## Construct a `Rocket` Instance
|
||||
//!
|
||||
//! Constructing a `Rocket` instance for testing is identical to constructing
|
||||
//! one for launching, except you should not call the `launch` method. That is,
|
||||
//! use `rocket::ignite`, then mount routes and catchers. That's it!
|
||||
//!
|
||||
//! ## Construct a (Mock)Request
|
||||
//!
|
||||
//! The [MockRequest](struct.MockRequest.html) object enables the creation of an
|
||||
//! HTTP request without using any networking. A `MockRequest` object is
|
||||
//! constructed using the builder pattern. For example, the following code
|
||||
//! builds a request for submitting a login form with three fields:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use rocket::http::Method::*;
|
||||
//! use rocket::http::ContentType;
|
||||
//! use rocket::testing::MockRequest;
|
||||
//!
|
||||
//! let (username, password, age) = ("user", "password", 32);
|
||||
//! MockRequest::new(Post, "/login")
|
||||
//! .header(ContentType::Form)
|
||||
//! .body(&format!("username={}&password={}&age={}", username, password, age));
|
||||
//! ```
|
||||
//!
|
||||
//! ## Dispatch and Validate
|
||||
//!
|
||||
//! Finally, requests can be dispatched using the
|
||||
//! [dispatch_with](struct.MockRequest.html#method.dispatch_with) method on the
|
||||
//! contructed `MockRequest` instance. The method returns the body of the
|
||||
//! response. At present, the API does not allow for headers in the response to
|
||||
//! be examined.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! The following is an example of a complete application with testing.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(plugin)]
|
||||
//! #![plugin(rocket_codegen)]
|
||||
//!
|
||||
//! extern crate rocket;
|
||||
//!
|
||||
//! #[get("/")]
|
||||
//! fn hello() -> &'static str {
|
||||
//! "Hello, world!"
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() { }
|
||||
//! #[cfg(test)]
|
||||
//! mod test {
|
||||
//! use super::rocket;
|
||||
//! use rocket::testing::MockRequest;
|
||||
//! use rocket::http::Method::*;
|
||||
//!
|
||||
//! #[test]
|
||||
//! fn test_hello_world() {
|
||||
//! let rocket = rocket::ignite().mount("/", routes![super::hello]);
|
||||
//! let mut req = MockRequest::new(Get, "/");
|
||||
//! let mut response = req.dispatch_with(&rocket);
|
||||
//!
|
||||
//! // Check that the body contains the string we expect.
|
||||
//! assert_eq!(response.body_string(), Some("Hello, world!".into()));
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use ::{Rocket, Request, Response, Data};
|
||||
use error::LaunchError;
|
||||
use http::{Method, Status, Header, Cookie};
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
/// A type for mocking requests for testing Rocket applications.
|
||||
pub struct MockRequest<'r> {
|
||||
prechecked: Option<&'r Rocket>,
|
||||
request: Request<'r>,
|
||||
data: Data
|
||||
}
|
||||
|
||||
impl<'r> MockRequest<'r> {
|
||||
/// Constructs a new mocked request with the given `method` and `uri`.
|
||||
#[inline]
|
||||
pub fn new<S: AsRef<str>>(method: Method, uri: S) -> Self {
|
||||
MockRequest {
|
||||
prechecked: None,
|
||||
request: Request::new(method, uri.as_ref().to_string()),
|
||||
data: Data::local(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a header to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::http::Method::*;
|
||||
/// use rocket::testing::MockRequest;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = MockRequest::new(Get, "/").header(ContentType::JSON);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn header<H: Into<Header<'static>>>(mut self, header: H) -> Self {
|
||||
self.request.add_header(header.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a header to this request without consuming `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::http::Method::*;
|
||||
/// use rocket::testing::MockRequest;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// let mut req = MockRequest::new(Get, "/");
|
||||
/// req.add_header(ContentType::JSON);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn add_header<H: Into<Header<'static>>>(&mut self, header: H) {
|
||||
self.request.add_header(header.into());
|
||||
}
|
||||
|
||||
/// Set the remote address of this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the remote address to "8.8.8.8:80":
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::http::Method::*;
|
||||
/// use rocket::testing::MockRequest;
|
||||
///
|
||||
/// let address = "8.8.8.8:80".parse().unwrap();
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = MockRequest::new(Get, "/").remote(address);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn remote(mut self, address: SocketAddr) -> Self {
|
||||
self.request.set_remote(address);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a cookie to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` cookie:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::http::Method::*;
|
||||
/// use rocket::testing::MockRequest;
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = MockRequest::new(Get, "/")
|
||||
/// .cookie(Cookie::new("username", "sb"))
|
||||
/// .cookie(Cookie::new("user_id", format!("{}", 12)));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cookie(self, cookie: Cookie<'static>) -> Self {
|
||||
self.request.cookies().add(cookie);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the body (data) of the request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the body to be a JSON structure; also sets the Content-Type.
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::http::Method::*;
|
||||
/// use rocket::testing::MockRequest;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = MockRequest::new(Post, "/")
|
||||
/// .header(ContentType::JSON)
|
||||
/// .body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self {
|
||||
self.data = Data::local(body.as_ref().into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns `Some` if there an error checking `rocket`. Returns `None` if
|
||||
/// there's no error and dispatching can continue.
|
||||
fn precheck(&mut self, rocket: &'r Rocket) -> Option<LaunchError> {
|
||||
// Check if we've already prechecked some `Rocket` instance.
|
||||
if let Some(r) = self.prechecked {
|
||||
// Check if the one we've prechecked is indeed `rocket`. This does a
|
||||
// straight pointer comparison. If they're the same, then we know
|
||||
// that the instance must not have changed since we kept an
|
||||
// immutable borrow to it from the precheck.
|
||||
if (r as *const Rocket) == (rocket as *const Rocket) {
|
||||
return None
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(err) = rocket.prelaunch_check() {
|
||||
return Some(err);
|
||||
}
|
||||
|
||||
self.prechecked = Some(rocket);
|
||||
None
|
||||
}
|
||||
|
||||
/// Dispatch this request using a given instance of Rocket.
|
||||
///
|
||||
/// It is possible that the supplied `rocket` instance contains malformed
|
||||
/// input such as colliding or invalid routes or failed fairings. When this
|
||||
/// is the case, the returned `Response` will contain a status of
|
||||
/// `InternalServerError`, and the body will contain the error that
|
||||
/// occurred. In all other cases, the returned `Response` will be that of
|
||||
/// the application.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Dispatch to a Rocket instance with the `"Hello, world!"` example
|
||||
/// mounted:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// #
|
||||
/// #[get("/")]
|
||||
/// fn hello() -> &'static str {
|
||||
/// "Hello, world!"
|
||||
/// }
|
||||
///
|
||||
/// use rocket::testing::MockRequest;
|
||||
/// use rocket::http::Method::*;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let rocket = rocket::ignite().mount("/", routes![hello]);
|
||||
/// let mut req = MockRequest::new(Get, "/");
|
||||
/// let mut response = req.dispatch_with(&rocket);
|
||||
///
|
||||
/// assert_eq!(response.body_string(), Some("Hello, world!".into()));
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn dispatch_with<'s>(&'s mut self, rocket: &'r Rocket) -> Response<'s> {
|
||||
if let Some(err) = self.precheck(rocket) {
|
||||
return Response::build()
|
||||
.status(Status::InternalServerError)
|
||||
.sized_body(::std::io::Cursor::new(err.to_string()))
|
||||
.finalize()
|
||||
}
|
||||
|
||||
let data = ::std::mem::replace(&mut self.data, Data::local(vec![]));
|
||||
rocket.dispatch(&mut self.request, data)
|
||||
}
|
||||
}
|
|
@ -18,31 +18,28 @@ fn bug(form_data: Form<FormData>) -> &'static str {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
#[test]
|
||||
fn method_eval() {
|
||||
let rocket = rocket::ignite().mount("/", routes![bug]);
|
||||
|
||||
let mut req = MockRequest::new(Post, "/")
|
||||
let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap();
|
||||
let mut response = client.post("/")
|
||||
.header(ContentType::Form)
|
||||
.body("_method=patch&form_data=Form+data");
|
||||
.body("_method=patch&form_data=Form+data")
|
||||
.dispatch();
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.body_string(), Some("OK".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_passes_through() {
|
||||
let rocket = rocket::ignite().mount("/", routes![bug]);
|
||||
|
||||
let mut req = MockRequest::new(Get, "/")
|
||||
let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap();
|
||||
let response = client.get("/")
|
||||
.header(ContentType::Form)
|
||||
.body("_method=patch&form_data=Form+data");
|
||||
.body("_method=patch&form_data=Form+data")
|
||||
.dispatch();
|
||||
|
||||
let response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,17 @@ fn bug(form_data: Form<FormData>) -> String {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::ContentType;
|
||||
use rocket::http::Status;
|
||||
|
||||
fn check_decoding(raw: &str, decoded: &str) {
|
||||
let rocket = rocket::ignite().mount("/", routes![bug]);
|
||||
let mut req = MockRequest::new(Post, "/")
|
||||
let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap();
|
||||
let mut response = client.post("/")
|
||||
.header(ContentType::Form)
|
||||
.body(format!("form_data={}", raw));
|
||||
.body(format!("form_data={}", raw))
|
||||
.dispatch();
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(Some(decoded.to_string()), response.body_string());
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
use rocket::Route;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::response::Body;
|
||||
|
||||
|
@ -35,12 +34,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn auto_head() {
|
||||
let rocket = rocket::ignite().mount("/", routes());
|
||||
|
||||
let mut req = MockRequest::new(Head, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
|
||||
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap();
|
||||
let mut response = client.head("/").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
|
||||
if let Some(body) = response.body() {
|
||||
match body {
|
||||
Body::Sized(_, n) => assert_eq!(n, "Hello, world!".len() as u64),
|
||||
|
@ -49,27 +46,23 @@ mod tests {
|
|||
|
||||
assert_eq!(body.into_string(), Some("".to_string()));
|
||||
} else {
|
||||
panic!("Expected an empty body!")
|
||||
panic!("Expected a non-empty body!")
|
||||
}
|
||||
|
||||
|
||||
let content_type: Vec<_> = response.headers().get("Content-Type").collect();
|
||||
assert_eq!(content_type, vec![ContentType::Plain.to_string()]);
|
||||
|
||||
let mut req = MockRequest::new(Head, "/empty");
|
||||
let response = req.dispatch_with(&rocket);
|
||||
let response = client.head("empty").dispatch();
|
||||
assert_eq!(response.status(), Status::NoContent);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_head() {
|
||||
let rocket = rocket::ignite().mount("/", routes());
|
||||
let mut req = MockRequest::new(Head, "/other");
|
||||
let response = req.dispatch_with(&rocket);
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap();
|
||||
let response = client.head("/other").dispatch();
|
||||
|
||||
let content_type: Vec<_> = response.headers().get("Content-Type").collect();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(content_type, vec![ContentType::JSON.to_string()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ fn index(form: Form<Simple>) -> String {
|
|||
mod limits_tests {
|
||||
use rocket;
|
||||
use rocket::config::{Environment, Config, Limits};
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
fn rocket_with_forms_limit(limit: u64) -> rocket::Rocket {
|
||||
|
@ -32,45 +31,45 @@ mod limits_tests {
|
|||
|
||||
#[test]
|
||||
fn large_enough() {
|
||||
let rocket = rocket_with_forms_limit(128);
|
||||
let mut req = MockRequest::new(Post, "/")
|
||||
let client = Client::new(rocket_with_forms_limit(128)).unwrap();
|
||||
let mut response = client.post("/")
|
||||
.body("value=Hello+world")
|
||||
.header(ContentType::Form);
|
||||
.header(ContentType::Form)
|
||||
.dispatch();
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.body_string(), Some("Hello world".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn just_large_enough() {
|
||||
let rocket = rocket_with_forms_limit(17);
|
||||
let mut req = MockRequest::new(Post, "/")
|
||||
let client = Client::new(rocket_with_forms_limit(17)).unwrap();
|
||||
let mut response = client.post("/")
|
||||
.body("value=Hello+world")
|
||||
.header(ContentType::Form);
|
||||
.header(ContentType::Form)
|
||||
.dispatch();
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.body_string(), Some("Hello world".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn much_too_small() {
|
||||
let rocket = rocket_with_forms_limit(4);
|
||||
let mut req = MockRequest::new(Post, "/")
|
||||
let client = Client::new(rocket_with_forms_limit(4)).unwrap();
|
||||
let response = client.post("/")
|
||||
.body("value=Hello+world")
|
||||
.header(ContentType::Form);
|
||||
.header(ContentType::Form)
|
||||
.dispatch();
|
||||
|
||||
let response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), Status::BadRequest);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contracted() {
|
||||
let rocket = rocket_with_forms_limit(10);
|
||||
let mut req = MockRequest::new(Post, "/")
|
||||
let client = Client::new(rocket_with_forms_limit(10)).unwrap();
|
||||
let mut response = client.post("/")
|
||||
.body("value=Hello+world")
|
||||
.header(ContentType::Form);
|
||||
.header(ContentType::Form)
|
||||
.dispatch();
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.body_string(), Some("Hell".into()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
use rocket::Rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
fn rocket() -> Rocket {
|
||||
|
@ -39,14 +38,14 @@ mod tests {
|
|||
|
||||
macro_rules! check_dispatch {
|
||||
($mount:expr, $ct:expr, $body:expr) => (
|
||||
let rocket = rocket();
|
||||
let mut req = MockRequest::new(Post, $mount);
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut req = client.post($mount);
|
||||
let ct: Option<ContentType> = $ct;
|
||||
if let Some(ct) = ct {
|
||||
req.add_header(ct);
|
||||
}
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = req.dispatch();
|
||||
let body_str = response.body_string();
|
||||
let body: Option<&'static str> = $body;
|
||||
match body {
|
||||
|
|
|
@ -20,27 +20,24 @@ fn second() -> &'static str {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use rocket::Rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
fn assert_no_collision(rocket: &Rocket) {
|
||||
let mut req = MockRequest::new(Get, "/?field=query");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
fn assert_no_collision(rocket: Rocket) {
|
||||
let client = Client::new(rocket).unwrap();
|
||||
let mut response = client.get("/?field=query").dispatch();
|
||||
assert_eq!(response.body_string(), Some("query".into()));
|
||||
|
||||
let mut req = MockRequest::new(Get, "/");
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.body_string(), Some("no query".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_query_collisions() {
|
||||
let rocket = rocket::ignite().mount("/", routes![first, second]);
|
||||
assert_no_collision(&rocket);
|
||||
assert_no_collision(rocket);
|
||||
|
||||
let rocket = rocket::ignite().mount("/", routes![second, first]);
|
||||
assert_no_collision(&rocket);
|
||||
assert_no_collision(rocket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,15 +12,13 @@ fn not_found() -> Redirect {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
#[test]
|
||||
fn error_catcher_redirect() {
|
||||
let rocket = rocket::ignite().catch(errors![not_found]);
|
||||
let mut req = MockRequest::new(Get, "/unknown");
|
||||
let response = req.dispatch_with(&rocket);
|
||||
let client = Client::new(rocket::ignite().catch(errors![not_found])).unwrap();
|
||||
let response = client.get("/unknown").dispatch();
|
||||
println!("Response:\n{:?}", response);
|
||||
|
||||
let location: Vec<_> = response.headers().get("location").collect();
|
||||
|
|
|
@ -12,8 +12,7 @@ fn get_ip(remote: SocketAddr) -> String {
|
|||
|
||||
mod remote_rewrite_tests {
|
||||
use super::*;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::http::{Header, Status};
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
@ -21,21 +20,19 @@ mod remote_rewrite_tests {
|
|||
const KNOWN_IP: &'static str = "127.0.0.1:8000";
|
||||
|
||||
fn check_ip(header: Option<Header<'static>>, ip: Option<String>) {
|
||||
let address: SocketAddr = KNOWN_IP.parse().unwrap();
|
||||
let port = address.port();
|
||||
let addr: SocketAddr = KNOWN_IP.parse().unwrap();
|
||||
|
||||
let rocket = rocket::ignite().mount("/", routes![get_ip]);
|
||||
let mut req = MockRequest::new(Get, "/").remote(address);
|
||||
if let Some(header) = header {
|
||||
req.add_header(header);
|
||||
}
|
||||
let c = Client::new(rocket::ignite().mount("/", routes![get_ip])).unwrap();
|
||||
let mut response = match header {
|
||||
Some(header) => c.get("/").header(header).remote(addr).dispatch(),
|
||||
None => c.get("/").remote(addr).dispatch()
|
||||
};
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body_str = response.body_string();
|
||||
let body = response.body_string();
|
||||
match ip {
|
||||
Some(ip) => assert_eq!(body_str, Some(format!("{}:{}", ip, port))),
|
||||
None => assert_eq!(body_str, Some(KNOWN_IP.into()))
|
||||
Some(ip) => assert_eq!(body, Some(format!("{}:{}", ip, addr.port()))),
|
||||
None => assert_eq!(body, Some(KNOWN_IP.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,14 +13,10 @@ fn files(route: &Route, path: PathBuf) -> String {
|
|||
|
||||
mod route_guard_tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
use rocket::Rocket;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
|
||||
fn assert_path(rocket: &Rocket, path: &str) {
|
||||
let mut req = MockRequest::new(Get, path);
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
fn assert_path(client: &Client, path: &str) {
|
||||
let mut res = client.get(path).dispatch();
|
||||
assert_eq!(res.body_string(), Some(path.into()));
|
||||
}
|
||||
|
||||
|
@ -30,9 +26,10 @@ mod route_guard_tests {
|
|||
.mount("/first", routes![files])
|
||||
.mount("/second", routes![files]);
|
||||
|
||||
assert_path(&rocket, "/first/some/path");
|
||||
assert_path(&rocket, "/second/some/path");
|
||||
assert_path(&rocket, "/first/second/b/c");
|
||||
assert_path(&rocket, "/second/a/b/c");
|
||||
let client = Client::new(rocket).unwrap();
|
||||
assert_path(&client, "/first/some/path");
|
||||
assert_path(&client, "/second/some/path");
|
||||
assert_path(&client, "/first/second/b/c");
|
||||
assert_path(&client, "/second/a/b/c");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ fn dual(user: String, path: Segments) -> String {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::local::Client;
|
||||
|
||||
#[test]
|
||||
fn segments_works() {
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![test, two, one_two, none, dual])
|
||||
.mount("/point", routes![test, two, one_two, dual]);
|
||||
let client = Client::new(rocket).unwrap();
|
||||
|
||||
// We construct a path that matches each of the routes above. We ensure the
|
||||
// prefix is stripped, confirming that dynamic segments are working.
|
||||
|
@ -48,9 +48,7 @@ mod tests {
|
|||
"/static", "/point/static"]
|
||||
{
|
||||
let path = "this/is/the/path/we/want";
|
||||
let mut req = MockRequest::new(Get, format!("{}/{}", prefix, path));
|
||||
|
||||
let mut response = req.dispatch_with(&rocket);
|
||||
let mut response = client.get(format!("{}/{}", prefix, path)).dispatch();
|
||||
assert_eq!(response.body_string(), Some(path.into()));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue