Add documentation and example

Change Fn to FnOnce to allow for moving and consuming
This commit is contained in:
Yong Wen Chua 2017-07-24 11:31:49 +08:00
parent 23cf7df415
commit 9de966bb29
8 changed files with 290 additions and 14 deletions

View File

@ -1,4 +1,4 @@
#![feature(plugin, custom_derive)]
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate rocket_cors;

View File

@ -1,4 +1,4 @@
#![feature(plugin, custom_derive)]
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate rocket_cors;
@ -23,7 +23,7 @@ fn responder_options(cors: Guard) -> Responder<()> {
}
/// Using a `Response` instead of a `Responder`. You generally won't have to do this.
#[get("/responder")]
#[get("/response")]
fn response(cors: Guard) -> Response {
let mut response = Response::new();
response.set_sized_body(Cursor::new("Hello CORS!"));
@ -32,7 +32,7 @@ fn response(cors: Guard) -> Response {
/// You need to define an OPTIONS route for preflight checks.
/// These routes can just return the unit type `()`
#[options("/responder")]
#[options("/response")]
fn response_options(cors: Guard) -> Response {
let response = Response::new();
cors.response(response)

94
examples/manual.rs Normal file
View File

@ -0,0 +1,94 @@
#![feature(plugin, conservative_impl_trait)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate rocket_cors;
use std::io::Cursor;
use rocket::{State, Response};
use rocket::http::Method;
use rocket::response::Responder;
use rocket_cors::{Cors, AllowedOrigins, AllowedHeaders};
/// Using a borrowed Cors
#[get("/")]
fn borrowed<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
options.inner().respond_borrowed(
|guard| guard.responder("Hello CORS"),
)
}
/// You need to define an OPTIONS route for preflight checks.
/// These routes can just return the unit type `()`
#[options("/")]
fn borrowed_options<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
options.inner().respond_borrowed(
|guard| guard.responder(()),
)
}
/// Using a `Response` instead of a `Responder`. You generally won't have to do this.
#[get("/response")]
fn response<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
let mut response = Response::new();
response.set_sized_body(Cursor::new("Hello CORS!"));
options.inner().respond_borrowed(
move |guard| guard.response(response),
)
}
/// You need to define an OPTIONS route for preflight checks.
/// These routes can just return the unit type `()`
#[options("/response")]
fn response_options<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
options.inner().respond_borrowed(
move |guard| guard.response(Response::new()),
)
}
/// Create and use an ad-hoc Cors
#[get("/owned")]
fn owned<'r>() -> impl Responder<'r> {
let options = cors_options();
options.respond_owned(|guard| guard.responder("Hello CORS"))
}
/// You need to define an OPTIONS route for preflight checks.
/// These routes can just return the unit type `()`
#[options("/owned")]
fn owned_options<'r>() -> impl Responder<'r> {
let options = cors_options();
options.respond_owned(|guard| guard.responder(()))
}
fn cors_options() -> Cors {
let (allowed_origins, failed_origins) = AllowedOrigins::some(&["https://www.acme.com"]);
assert!(failed_origins.is_empty());
// You can also deserialize this
rocket_cors::Cors {
allowed_origins: allowed_origins,
allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
allow_credentials: true,
..Default::default()
}
}
fn main() {
rocket::ignite()
.mount(
"/",
routes![
borrowed,
borrowed_options,
response,
response_options,
owned,
owned_options,
],
)
.manage(cors_options())
.launch();
}

View File

@ -61,7 +61,7 @@
//!
//! - Fairing (should only used exclusively)
//! - Request Guard
//! - Truly Manual (not supported yet, [#13](https://github.com/lawliet89/rocket_cors/issues/13))
//! - Truly Manual
//!
//! Unfortunately, you cannot mix and match Fairing with any other of the methods, due to the
//! limitation of Rocket's fairing API. That is, the checks for Fairing will always happen first,
@ -213,7 +213,189 @@
//!
//! ## Truly Manual
//!
//! This is not supported yet. See [#13](https://github.com/lawliet89/rocket_cors/issues/13).
//! This mode is the most difficult to use but offers the most amount of flexibility.
//! You might have to understand how the library works internally to know how to use this mode.
//! In exchange, you can selectively choose which routes to offer CORS protection to, and you
//! can mix and match CORS settings for the routes. You can combine usage of this mode with
//! "guard" to offer a mix of ease of use and flexibility.
//!
//! You really do not need to use this unless you have a truly ad-hoc need to respond to CORS
//! differently in a route. For example, you have a `ping` endpoint that allows all origins but
//! the rest of your routes do not.
//!
//! ### Handler
//!
//! This mode requires that you pass in a closure that will be lazily evaluated once a CORS request
//! has been validated. If validation fails, the closure will not be run. You should put any code
//! that has any side effects or with an appreciable computation cost inside this handler.
//!
//! ### Steps to perform:
//! - Your crate will need to enable the
//! [`conservative_impl_trait`](https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md)
//! feature. You can use `#![feature(conservative_impl_trait)]` at your crate root.
//! Otherwise, the return type of your routes will be unspecifiable.
//! - You will first need to have a `Cors` struct ready. This struct can be borrowed with a lifetime
//! at least as long as `'r` which is the lifetime of a Rocket request. `'static` works too.
//! In this case, you might as well use the `Guard` method above and place the `Cors` struct in
//! Rocket's [state](https://rocket.rs/guide/state/).
//! Alternatively, you can create a `Cors` struct directly in the route.
//! - Your routes will need to have a `'r` lifetime and return `impl Responder<'r>`.
//! - Using the `Cors` struct, use either the
//! [`respond_owned`](struct.Cors.html#method.respond_owned) or
//! [`respond_borrowed`](struct.Cors.html#method.respond_borrowed) function and pass in a handler
//! that will be executed once CORS validation is successful.
//! - Your handler will be passed a [`Guard`](struct.Guard.html) which you will have to use to
//! add CORS headers into your own response.
//! - You will have to manually define your own `OPTIONS` routes.
//!
//! ### Notes about route lifetime
//! It is unfortunate that you have to manually specify the `'r` lifetimes in your routes.
//! Leaving out the lifetime will result in a
//! [compiler panic](https://github.com/rust-lang/rust/issues/43380). Even if the panic is fixed,
//! it is not known if we can exclude the lifetime because lifetimes are _elided_ in Rust,
//! not inferred.
//!
//! ### Owned example
//! This is the most likely scenario when you want to have manual CORS validation. You can use this
//! when the settings you want to use for a route is not the same as the rest of the application
//! (which you might have put in Rocket's state).
//!
//! ```rust,no_run
//! #![feature(plugin, conservative_impl_trait)]
//! #![plugin(rocket_codegen)]
//! extern crate rocket;
//! extern crate rocket_cors;
//!
//! use rocket::http::Method;
//! use rocket::response::Responder;
//! use rocket_cors::{Cors, AllowedOrigins, AllowedHeaders};
//!
//! /// Create and use an ad-hoc Cors
//! #[get("/owned")]
//! fn owned<'r>() -> impl Responder<'r> {
//! let options = cors_options();
//! options.respond_owned(|guard| guard.responder("Hello CORS"))
//! }
//!
//! /// You need to define an OPTIONS route for preflight checks.
//! /// These routes can just return the unit type `()`
//! #[options("/owned")]
//! fn owned_options<'r>() -> impl Responder<'r> {
//! let options = cors_options();
//! options.respond_owned(|guard| guard.responder(()))
//! }
//!
//! fn cors_options() -> Cors {
//! let (allowed_origins, failed_origins) = AllowedOrigins::some(&["https://www.acme.com"]);
//! assert!(failed_origins.is_empty());
//!
//! // You can also deserialize this
//! rocket_cors::Cors {
//! allowed_origins: allowed_origins,
//! allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
//! allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
//! allow_credentials: true,
//! ..Default::default()
//! }
//! }
//!
//! fn main() {
//! rocket::ignite()
//! .mount(
//! "/",
//! routes![
//! owned,
//! owned_options,
//! ],
//! )
//! .manage(cors_options())
//! .launch();
//! }
//! ```
//!
//! ### Borrowed Example
//! You might want to borrow the `Cors` struct from Rocket's state, for example. Unless you have
//! special handling, you might want to use the Guard method instead which has less hassle.
//!
//! ```rust,no_run
//! #![feature(plugin, conservative_impl_trait)]
//! #![plugin(rocket_codegen)]
//! extern crate rocket;
//! extern crate rocket_cors;
//!
//! use std::io::Cursor;
//!
//! use rocket::{State, Response};
//! use rocket::http::Method;
//! use rocket::response::Responder;
//! use rocket_cors::{Cors, AllowedOrigins, AllowedHeaders};
//!
//! /// Using a borrowed Cors
//! #[get("/")]
//! fn borrowed<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
//! options.inner().respond_borrowed(
//! |guard| guard.responder("Hello CORS"),
//! )
//! }
//!
//! /// You need to define an OPTIONS route for preflight checks.
//! /// These routes can just return the unit type `()`
//! #[options("/")]
//! fn borrowed_options<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
//! options.inner().respond_borrowed(
//! |guard| guard.responder(()),
//! )
//! }
//!
//! /// Using a `Response` instead of a `Responder`. You generally won't have to do this.
//! #[get("/response")]
//! fn response<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
//! let mut response = Response::new();
//! response.set_sized_body(Cursor::new("Hello CORS!"));
//!
//! options.inner().respond_borrowed(
//! move |guard| guard.response(response),
//! )
//! }
//!
//! /// You need to define an OPTIONS route for preflight checks.
//! /// These routes can just return the unit type `()`
//! #[options("/response")]
//! fn response_options<'r>(options: State<'r, Cors>) -> impl Responder<'r> {
//! options.inner().respond_borrowed(
//! move |guard| guard.response(Response::new()),
//! )
//! }
//!
//! fn cors_options() -> Cors {
//! let (allowed_origins, failed_origins) = AllowedOrigins::some(&["https://www.acme.com"]);
//! assert!(failed_origins.is_empty());
//!
//! // You can also deserialize this
//! rocket_cors::Cors {
//! allowed_origins: allowed_origins,
//! allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
//! allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
//! allow_credentials: true,
//! ..Default::default()
//! }
//! }
//!
//! fn main() {
//! rocket::ignite()
//! .mount(
//! "/",
//! routes![
//! borrowed,
//! borrowed_options,
//! response,
//! response_options,
//! ],
//! )
//! .manage(cors_options())
//! .launch();
//! }
//! ```
#![allow(
legacy_directory_ownership,
@ -850,7 +1032,7 @@ impl Cors {
/// See the documentation at the [crate root](index.html) for usage information.
pub fn respond_owned<'r, F, R>(self, handler: F) -> Result<ManualResponder<'r, F, R>, Error>
where
F: Fn(Guard<'r>) -> R + 'r,
F: FnOnce(Guard<'r>) -> R + 'r,
R: response::Responder<'r>,
{
self.validate()?;
@ -874,7 +1056,7 @@ impl Cors {
handler: F,
) -> Result<ManualResponder<'r, F, R>, Error>
where
F: Fn(Guard<'r>) -> R + 'r,
F: FnOnce(Guard<'r>) -> R + 'r,
R: response::Responder<'r>,
{
self.validate()?;
@ -1178,7 +1360,7 @@ pub struct ManualResponder<'r, F, R> {
impl<'r, F, R> ManualResponder<'r, F, R>
where
F: Fn(Guard<'r>) -> R + 'r,
F: FnOnce(Guard<'r>) -> R + 'r,
R: response::Responder<'r>,
{
/// Create a new manual responder by passing in either a borrowed or owned `Cors` option.
@ -1202,7 +1384,7 @@ where
impl<'r, F, R> response::Responder<'r> for ManualResponder<'r, F, R>
where
F: Fn(Guard<'r>) -> R + 'r,
F: FnOnce(Guard<'r>) -> R + 'r,
R: response::Responder<'r>,
{
fn respond_to(self, request: &Request) -> response::Result<'r> {

View File

@ -1,6 +1,6 @@
//! This crate tests using rocket_cors using Fairings
#![feature(plugin, custom_derive)]
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate hyper;
extern crate rocket;

View File

@ -1,6 +1,6 @@
//! This crate tests using rocket_cors using the per-route handling with request guard
#![feature(plugin, custom_derive)]
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate hyper;
extern crate rocket;

View File

@ -1,5 +1,5 @@
//! This crate tests that all the request headers are parsed correctly in the round trip
#![feature(plugin, custom_derive)]
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate hyper;
extern crate rocket;

View File

@ -1,6 +1,6 @@
//! This crate tests using rocket_cors using manual mode
#![feature(plugin, custom_derive, conservative_impl_trait)]
#![feature(plugin, conservative_impl_trait)]
#![plugin(rocket_codegen)]
extern crate hyper;
extern crate rocket;