mirror of
https://github.com/rwf2/Rocket.git
synced 2025-01-09 03:02:45 +00:00
4c6562cd29
This allows responses to be sent to the client even when data is only partially read, significantly improving the experience for the client from one with a "connection closed" error to one with a proper response. The consequence is a lifetime in 'Data'. Though other non-lifetime-introducing solutions exist, the introduction of a lifetime to 'Data' is a longstanding desire as it prevents smuggling 'Data' into a longer-lived context. Use of 'Data' in that context was unspecified with various runtime consequences. The addition of a lifetime bound by the request prevents this error statically. In summary, the changes are: * Clients receive responses even when data isn't fully read. * 'Data' becomes 'Data<'r>'. 'FromData' changes accordingly. * Route 'Outcome's are strictly tied to the request lifetime. Tangentially, the invalid length form field validation error message has improved to format length in byte units if it exceeds 1024.
89 lines
2.7 KiB
Rust
89 lines
2.7 KiB
Rust
#[macro_use] extern crate rocket;
|
|
|
|
use rocket::{Request, Rocket, Route, Catcher, Build, route, catcher};
|
|
use rocket::data::Data;
|
|
use rocket::http::{Method, Status};
|
|
use rocket::local::blocking::Client;
|
|
|
|
#[get("/panic")]
|
|
fn panic_route() -> &'static str {
|
|
panic!("Panic in route")
|
|
}
|
|
|
|
#[catch(404)]
|
|
fn panic_catcher() -> &'static str {
|
|
panic!("Panic in catcher")
|
|
}
|
|
|
|
#[catch(500)]
|
|
fn ise() -> &'static str {
|
|
"Hey, sorry! :("
|
|
}
|
|
|
|
fn pre_future_route<'r>(_: &'r Request<'_>, _: Data<'r>) -> route::BoxFuture<'r> {
|
|
panic!("hey now...");
|
|
}
|
|
|
|
fn rocket() -> Rocket<Build> {
|
|
rocket::build()
|
|
.mount("/", routes![panic_route])
|
|
.mount("/", vec![Route::new(Method::Get, "/pre", pre_future_route)])
|
|
}
|
|
|
|
#[test]
|
|
fn catches_route_panic() {
|
|
let rocket = rocket().register("/", catchers![panic_catcher, ise]);
|
|
let client = Client::debug(rocket).unwrap();
|
|
let response = client.get("/panic").dispatch();
|
|
assert_eq!(response.status(), Status::InternalServerError);
|
|
assert_eq!(response.into_string().unwrap(), "Hey, sorry! :(");
|
|
}
|
|
|
|
#[test]
|
|
fn catches_catcher_panic() {
|
|
let rocket = rocket().register("/", catchers![panic_catcher, ise]);
|
|
let client = Client::debug(rocket).unwrap();
|
|
let response = client.get("/noroute").dispatch();
|
|
assert_eq!(response.status(), Status::InternalServerError);
|
|
assert_eq!(response.into_string().unwrap(), "Hey, sorry! :(");
|
|
}
|
|
|
|
#[test]
|
|
fn catches_double_panic() {
|
|
#[catch(500)]
|
|
fn double_panic() {
|
|
panic!("so, so sorry...")
|
|
}
|
|
|
|
let rocket = rocket().register("/", catchers![panic_catcher, double_panic]);
|
|
let client = Client::debug(rocket).unwrap();
|
|
let response = client.get("/noroute").dispatch();
|
|
assert_eq!(response.status(), Status::InternalServerError);
|
|
assert!(response.into_string().unwrap().contains("Rocket"));
|
|
}
|
|
|
|
#[test]
|
|
fn catches_early_route_panic() {
|
|
let rocket = rocket().register("/", catchers![panic_catcher, ise]);
|
|
let client = Client::debug(rocket).unwrap();
|
|
let response = client.get("/pre").dispatch();
|
|
assert_eq!(response.status(), Status::InternalServerError);
|
|
assert_eq!(response.into_string().unwrap(), "Hey, sorry! :(");
|
|
}
|
|
|
|
#[test]
|
|
fn catches_early_catcher_panic() {
|
|
fn pre_future_catcher<'r>(_: Status, _: &'r Request) -> catcher::BoxFuture<'r> {
|
|
panic!("a panicking pre-future catcher")
|
|
}
|
|
|
|
let rocket = rocket()
|
|
.register("/", vec![Catcher::new(404, pre_future_catcher)])
|
|
.register("/", catchers![ise]);
|
|
|
|
let client = Client::debug(rocket).unwrap();
|
|
let response = client.get("/idontexist").dispatch();
|
|
assert_eq!(response.status(), Status::InternalServerError);
|
|
assert_eq!(response.into_string().unwrap(), "Hey, sorry! :(");
|
|
}
|