mirror of https://github.com/fafhrd91/actix-web
update docs and changelog
This commit is contained in:
parent
53ae8ec1ba
commit
0a28772e7b
10
CHANGES.md
10
CHANGES.md
|
@ -1,6 +1,16 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
### Added
|
||||||
|
- `guard::GuardContext` for use with the `Guard` trait. [#2552]
|
||||||
|
- `ServiceRequest::guard_ctx` for obtaining a guard context. [#2552]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- `Guard` trait now receives a `&GuardContext`. [#2552]
|
||||||
|
- `guard::fn_guard` functions now receives a `&GuardContext`. [#2552]
|
||||||
|
- Some guards now return `impl Guard` and their concrete types are made private: `guard::{Not, Header}` and all the method guards. [#2552]
|
||||||
|
|
||||||
|
[#2552]: https://github.com/actix/actix-web/pull/2552
|
||||||
|
|
||||||
|
|
||||||
## 4.0.0-beta.16 - 2021-12-27
|
## 4.0.0-beta.16 - 2021-12-27
|
||||||
|
|
292
src/guard.rs
292
src/guard.rs
|
@ -1,25 +1,66 @@
|
||||||
//! Route guards.
|
//! Route guards.
|
||||||
//!
|
//!
|
||||||
//! Guards are one of the ways how actix-web router chooses a handler service. In essence it is just
|
//! Guards are used during routing to help select a matching service or handler using some aspect of
|
||||||
//! a function that accepts a reference to a `RequestHead` instance and returns a boolean. It is
|
//! the request; though guards should not be used for path matching since it is a built-in function
|
||||||
//! possible to add guards to *scopes*, *resources* and *routes*. Actix provide several guards by
|
//! of the Actix Web router.
|
||||||
//! default, like various HTTP methods, header, etc. To become a guard, type must implement the
|
|
||||||
//! `Guard` trait. Simple functions could be guards as well.
|
|
||||||
//!
|
//!
|
||||||
//! Guards can not modify the request object. But it is possible to store extra attributes on a
|
//! Guards can be used on [`Scope`]s, [`Resource`]s, [`Route`]s, and other custom services.
|
||||||
//! request by using the `Extensions` container. Extensions containers are available via the
|
|
||||||
//! `RequestHead::extensions()` method.
|
|
||||||
//!
|
//!
|
||||||
|
//! Fundamentally, a guard is a predicate function that receives a reference to a request context
|
||||||
|
//! object and returns a boolean; true if the request _should_ be handled by the guarded service
|
||||||
|
//! or handler. This interface is defined by the [`Guard`] trait.
|
||||||
|
//!
|
||||||
|
//! Commonly-used guards are provided in this module as well as way of creating a guard from a
|
||||||
|
//! closure ([`fn_guard`]). The [`Not`], [`Any`], and [`All`] guards are noteworthy, as they can be
|
||||||
|
//! used to compose other guards in a more flexible and semantic way than calling `.guard(...)` on
|
||||||
|
//! services multiple times (which might have different combining behavior than you want).
|
||||||
|
//!
|
||||||
|
//! Guards can not modify anything about the request. However, it is possible to store extra
|
||||||
|
//! attributes in the request-local data container obtained with [`GuardContext::req_data_mut`].
|
||||||
|
//!
|
||||||
|
//! Guards can prevent resource definitions from overlapping (resulting in some inaccessible routes)
|
||||||
|
//! where they otherwise would when only considering paths. See the virtual hosting example below.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//! In the following code, the `/guarded` resource has one defined route whose handler will only be
|
||||||
|
//! called if the request method is `POST` and there is a request header with name and value equal
|
||||||
|
//! to `x-guarded` and `secret`, respectively.
|
||||||
//! ```
|
//! ```
|
||||||
//! use actix_web::{web, http, dev, guard, App, HttpResponse};
|
//! use actix_web::{web, http::Method, guard, App, HttpResponse};
|
||||||
//!
|
//!
|
||||||
//! App::new().service(web::resource("/index.html").route(
|
//! web::resource("/guarded").route(
|
||||||
//! web::route()
|
//! web::route()
|
||||||
//! .guard(guard::Post())
|
//! .guard(guard::Any(guard::Get()).or(guard::Post()))
|
||||||
//! .guard(guard::fn_guard(|ctx| ctx.head().method == http::Method::GET))
|
//! .guard(guard::Header("x-guarded", "secret"))
|
||||||
//! .to(|| HttpResponse::MethodNotAllowed()))
|
//! .to(|| HttpResponse::Ok())
|
||||||
//! );
|
//! );
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Guards can be used to set up some form of [virtual hosting] within a single app.
|
||||||
|
//! Overlapping scope prefixes are usually discouraged, but when combined with non-overlapping guard
|
||||||
|
//! definitions they become safe to use in this way. Without these host guards, only routes under
|
||||||
|
//! the first-to-be-defined scope would be accessible. You can test this locally using `127.0.0.1`
|
||||||
|
//! and `localhost` as the `Host` guards.
|
||||||
|
//! ```
|
||||||
|
//! use actix_web::{web, http::Method, guard, App, HttpResponse};
|
||||||
|
//!
|
||||||
|
//! App::new()
|
||||||
|
//! .service(
|
||||||
|
//! web::scope("")
|
||||||
|
//! .guard(guard::Host("www.rust-lang.org"))
|
||||||
|
//! .default_service(web::to(|| HttpResponse::Ok().body("marketing site"))),
|
||||||
|
//! )
|
||||||
|
//! .service(
|
||||||
|
//! web::scope("")
|
||||||
|
//! .guard(guard::Host("play.rust-lang.org"))
|
||||||
|
//! .default_service(web::to(|| HttpResponse::Ok().body("playground frontend"))),
|
||||||
|
//! );
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! [`Scope`]: crate::Scope::guard()
|
||||||
|
//! [`Resource`]: crate::Resource::guard()
|
||||||
|
//! [`Route`]: crate::Route::guard()
|
||||||
|
//! [virtual hosting]: https://en.wikipedia.org/wiki/Virtual_hosting
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefMut},
|
cell::{Ref, RefMut},
|
||||||
|
@ -31,35 +72,37 @@ use actix_http::{header, uri::Uri, Extensions, Method as HttpMethod, RequestHead
|
||||||
|
|
||||||
use crate::service::ServiceRequest;
|
use crate::service::ServiceRequest;
|
||||||
|
|
||||||
|
/// Provides access to request parts that are useful during routing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GuardContext<'a> {
|
pub struct GuardContext<'a> {
|
||||||
pub(crate) req: &'a ServiceRequest,
|
pub(crate) req: &'a ServiceRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GuardContext<'a> {
|
impl<'a> GuardContext<'a> {
|
||||||
|
/// Returns reference to the request head.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn head(&self) -> &RequestHead {
|
pub fn head(&self) -> &RequestHead {
|
||||||
self.req.head()
|
self.req.head()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns reference to the request-local data container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn req_data(&self) -> Ref<'a, Extensions> {
|
pub fn req_data(&self) -> Ref<'a, Extensions> {
|
||||||
self.req.req_data()
|
self.req.req_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns mutable reference to the request-local data container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn req_data_mut(&self) -> RefMut<'a, Extensions> {
|
pub fn req_data_mut(&self) -> RefMut<'a, Extensions> {
|
||||||
self.req.req_data_mut()
|
self.req.req_data_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait defines resource guards. Guards are used for route selection.
|
/// Interface for routing guards.
|
||||||
///
|
///
|
||||||
/// Guards can not modify the request object. But it is possible to store extra attributes on a
|
/// See [module level documentation](self) for more.
|
||||||
/// request by using the `Extensions` container. Extensions containers are available via the
|
|
||||||
/// `RequestHead::extensions()` method.
|
|
||||||
pub trait Guard {
|
pub trait Guard {
|
||||||
/// Check if request matches predicate
|
/// Returns true if predicate condition is met for a given request.
|
||||||
fn check(&self, ctx: &GuardContext<'_>) -> bool;
|
fn check(&self, ctx: &GuardContext<'_>) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,20 +112,17 @@ impl Guard for Rc<dyn Guard> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create guard object for supplied function.
|
/// Creates a guard using the given function.
|
||||||
///
|
///
|
||||||
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{guard, web, App, HttpResponse};
|
/// use actix_web::{guard, web, HttpResponse};
|
||||||
///
|
///
|
||||||
/// App::new().service(
|
|
||||||
/// web::resource("/index.html").route(
|
|
||||||
/// web::route()
|
/// web::route()
|
||||||
/// .guard(guard::fn_guard(|ctx| {
|
/// .guard(guard::fn_guard(|ctx| {
|
||||||
/// ctx.head().headers().contains_key("content-type")
|
/// ctx.head().headers().contains_key("content-type")
|
||||||
/// }))
|
/// }))
|
||||||
/// .to(|| HttpResponse::MethodNotAllowed()),
|
/// .to(|| HttpResponse::Ok());
|
||||||
/// ),
|
|
||||||
/// );
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn fn_guard<F>(f: F) -> impl Guard
|
pub fn fn_guard<F>(f: F) -> impl Guard
|
||||||
where
|
where
|
||||||
|
@ -113,14 +153,16 @@ where
|
||||||
|
|
||||||
/// Return guard that matches if any of supplied guards.
|
/// Return guard that matches if any of supplied guards.
|
||||||
///
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// The handler below will be called for either request method `GET` or `POST`.
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{web, guard, App, HttpResponse};
|
/// use actix_web::{web, guard, App, HttpResponse};
|
||||||
///
|
///
|
||||||
/// App::new().service(web::resource("/index.html").route(
|
|
||||||
/// web::route()
|
/// web::route()
|
||||||
/// .guard(guard::Any(guard::Get()).or(guard::Post()))
|
/// .guard(
|
||||||
/// .to(|| HttpResponse::MethodNotAllowed()))
|
/// guard::Any(guard::Get())
|
||||||
/// );
|
/// .or(guard::Post()))
|
||||||
|
/// .to(|| HttpResponse::Ok());
|
||||||
/// ```
|
/// ```
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Any<F: Guard + 'static>(guard: F) -> AnyGuard {
|
pub fn Any<F: Guard + 'static>(guard: F) -> AnyGuard {
|
||||||
|
@ -154,17 +196,20 @@ impl Guard for AnyGuard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return guard that matches if all of the supplied guards.
|
/// Creates a guard that matches if all of the supplied guards.
|
||||||
///
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// The handler below will only be called if the request method is `GET` **and** the specified
|
||||||
|
/// header name and value match exactly.
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{guard, web, App, HttpResponse};
|
/// use actix_web::{guard, web, HttpResponse};
|
||||||
///
|
///
|
||||||
/// App::new().service(web::resource("/index.html").route(
|
|
||||||
/// web::route()
|
/// web::route()
|
||||||
/// .guard(
|
/// .guard(
|
||||||
/// guard::All(guard::Get()).and(guard::Header("content-type", "text/plain")))
|
/// guard::All(guard::Get())
|
||||||
/// .to(|| HttpResponse::MethodNotAllowed()))
|
/// .and(guard::Header("accept", "text/plain"))
|
||||||
/// );
|
/// )
|
||||||
|
/// .to(|| HttpResponse::Ok());
|
||||||
/// ```
|
/// ```
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn All<F: Guard + 'static>(guard: F) -> AllGuard {
|
pub fn All<F: Guard + 'static>(guard: F) -> AllGuard {
|
||||||
|
@ -197,20 +242,37 @@ impl Guard for AllGuard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return guard that matches if supplied guard does not match.
|
/// Wraps a guard and inverts the outcome of it's `Guard` implementation.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// The handler below will be called for any request method apart from `GET`.
|
||||||
|
/// ```
|
||||||
|
/// use actix_web::{guard, web, HttpResponse};
|
||||||
|
///
|
||||||
|
/// web::route()
|
||||||
|
/// .guard(guard::Not(guard::Get()))
|
||||||
|
/// .to(|| HttpResponse::Ok());
|
||||||
|
/// ```
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Not<F: Guard + 'static>(guard: F) -> impl Guard {
|
pub fn Not<G: Guard>(guard: G) -> NotGuard<G> {
|
||||||
NotGuard(Box::new(guard))
|
NotGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NotGuard(Box<dyn Guard>);
|
#[doc(hidden)]
|
||||||
|
pub struct NotGuard<G>(G);
|
||||||
|
|
||||||
impl Guard for NotGuard {
|
impl<G: Guard> Guard for NotGuard<G> {
|
||||||
fn check(&self, ctx: &GuardContext<'_>) -> bool {
|
fn check(&self, ctx: &GuardContext<'_>) -> bool {
|
||||||
!self.0.check(ctx)
|
!self.0.check(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Predicate to match specified HTTP method.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn Method(method: HttpMethod) -> impl Guard {
|
||||||
|
MethodGuard(method)
|
||||||
|
}
|
||||||
|
|
||||||
/// HTTP method guard.
|
/// HTTP method guard.
|
||||||
struct MethodGuard(HttpMethod);
|
struct MethodGuard(HttpMethod);
|
||||||
|
|
||||||
|
@ -220,67 +282,39 @@ impl Guard for MethodGuard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Guard to match *GET* HTTP method.
|
macro_rules! method_guard {
|
||||||
#[allow(non_snake_case)]
|
($method_fn:ident, $method_const:ident) => {
|
||||||
pub fn Get() -> impl Guard {
|
paste::paste! {
|
||||||
MethodGuard(HttpMethod::GET)
|
#[doc = " Creates a guard that matches the `" $method_const "` request method."]
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
#[doc = " The route in this example will only respond to `" $method_const "` requests."]
|
||||||
|
/// ```
|
||||||
|
/// use actix_web::{guard, web, HttpResponse};
|
||||||
|
///
|
||||||
|
/// web::route()
|
||||||
|
#[doc = " .guard(guard::" $method_fn "())"]
|
||||||
|
/// .to(|| HttpResponse::Ok());
|
||||||
|
/// ```
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn $method_fn() -> impl Guard {
|
||||||
|
MethodGuard(HttpMethod::$method_const)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Predicate to match *POST* HTTP method.
|
method_guard!(Get, GET);
|
||||||
#[allow(non_snake_case)]
|
method_guard!(Post, POST);
|
||||||
pub fn Post() -> impl Guard {
|
method_guard!(Put, PUT);
|
||||||
MethodGuard(HttpMethod::POST)
|
method_guard!(Delete, DELETE);
|
||||||
}
|
method_guard!(Head, HEAD);
|
||||||
|
method_guard!(Options, OPTIONS);
|
||||||
|
method_guard!(Connect, CONNECT);
|
||||||
|
method_guard!(Patch, PATCH);
|
||||||
|
method_guard!(Trace, TRACE);
|
||||||
|
|
||||||
/// Predicate to match *PUT* HTTP method.
|
/// Creates a guard that matches if request contains given header name and value.
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Put() -> impl Guard {
|
|
||||||
MethodGuard(HttpMethod::PUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate to match *DELETE* HTTP method.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Delete() -> impl Guard {
|
|
||||||
MethodGuard(HttpMethod::DELETE)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate to match *HEAD* HTTP method.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Head() -> impl Guard {
|
|
||||||
MethodGuard(HttpMethod::HEAD)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate to match *OPTIONS* HTTP method.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Options() -> impl Guard {
|
|
||||||
MethodGuard(HttpMethod::OPTIONS)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate to match *CONNECT* HTTP method.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Connect() -> impl Guard {
|
|
||||||
MethodGuard(HttpMethod::CONNECT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate to match *PATCH* HTTP method.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Patch() -> impl Guard {
|
|
||||||
MethodGuard(HttpMethod::PATCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate to match *TRACE* HTTP method.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Trace() -> impl Guard {
|
|
||||||
MethodGuard(HttpMethod::TRACE)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Predicate to match specified HTTP method.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn Method(method: HttpMethod) -> impl Guard {
|
|
||||||
MethodGuard(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return predicate that matches if request contains specified header and value.
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Header(name: &'static str, value: &'static str) -> impl Guard {
|
pub fn Header(name: &'static str, value: &'static str) -> impl Guard {
|
||||||
HeaderGuard(
|
HeaderGuard(
|
||||||
|
@ -289,7 +323,6 @@ pub fn Header(name: &'static str, value: &'static str) -> impl Guard {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
struct HeaderGuard(header::HeaderName, header::HeaderValue);
|
struct HeaderGuard(header::HeaderName, header::HeaderValue);
|
||||||
|
|
||||||
impl Guard for HeaderGuard {
|
impl Guard for HeaderGuard {
|
||||||
|
@ -302,19 +335,33 @@ impl Guard for HeaderGuard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return predicate that matches if request contains specified Host name.
|
/// Creates a guard that matches requests targetting a specific host.
|
||||||
///
|
///
|
||||||
|
/// # Matching Host
|
||||||
|
/// This guard will:
|
||||||
|
/// - match against the `Host` header, if present;
|
||||||
|
/// - fall-back to matching against the request target's host, if present;
|
||||||
|
/// - return false if host cannot be determined;
|
||||||
|
///
|
||||||
|
/// # Matching Scheme
|
||||||
|
/// Optionally, this guard can match against the host's scheme. Set the scheme for matching using
|
||||||
|
/// `Host(host).scheme(protocol)`. If the request's scheme cannot be determined, it will not prevent
|
||||||
|
/// the guard from matching successfully.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// The [module-level documentation](self) has an example of virtual hosting using `Host` guards.
|
||||||
|
///
|
||||||
|
/// The example below additionally guards on the host URI's scheme. This could allow routing to
|
||||||
|
/// different handlers for `http:` vs `https:` visitors; to redirect, for example.
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{web, guard::Host, App, HttpResponse};
|
/// use actix_web::{web, guard::Host, HttpResponse};
|
||||||
///
|
///
|
||||||
/// App::new().service(
|
/// web::scope("/admin")
|
||||||
/// web::resource("/index.html")
|
/// .guard(Host("admin.rust-lang.org").scheme("https"))
|
||||||
/// .guard(Host("www.rust-lang.org"))
|
/// .default_service(web::to(|| HttpResponse::Ok().body("admin connection is secure")));
|
||||||
/// .to(|| HttpResponse::MethodNotAllowed())
|
|
||||||
/// );
|
|
||||||
/// ```
|
/// ```
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Host<H: AsRef<str>>(host: H) -> HostGuard {
|
pub fn Host(host: impl AsRef<str>) -> HostGuard {
|
||||||
HostGuard {
|
HostGuard {
|
||||||
host: host.as_ref().to_string(),
|
host: host.as_ref().to_string(),
|
||||||
scheme: None,
|
scheme: None,
|
||||||
|
@ -326,8 +373,7 @@ fn get_host_uri(req: &RequestHead) -> Option<Uri> {
|
||||||
.get(header::HOST)
|
.get(header::HOST)
|
||||||
.and_then(|host_value| host_value.to_str().ok())
|
.and_then(|host_value| host_value.to_str().ok())
|
||||||
.or_else(|| req.uri.host())
|
.or_else(|| req.uri.host())
|
||||||
.map(|host| host.parse().ok())
|
.and_then(|host| host.parse().ok())
|
||||||
.and_then(|host_success| host_success)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -346,26 +392,34 @@ impl HostGuard {
|
||||||
|
|
||||||
impl Guard for HostGuard {
|
impl Guard for HostGuard {
|
||||||
fn check(&self, ctx: &GuardContext<'_>) -> bool {
|
fn check(&self, ctx: &GuardContext<'_>) -> bool {
|
||||||
let req_host_uri = if let Some(uri) = get_host_uri(ctx.head()) {
|
// parse host URI from header or request target
|
||||||
uri
|
let req_host_uri = match get_host_uri(ctx.head()) {
|
||||||
} else {
|
Some(uri) => uri,
|
||||||
return false;
|
|
||||||
|
// no match if host cannot be determined
|
||||||
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(uri_host) = req_host_uri.host() {
|
match req_host_uri.host() {
|
||||||
if self.host != uri_host {
|
// fall through to scheme checks
|
||||||
return false;
|
Some(uri_host) if self.host == uri_host => {}
|
||||||
}
|
|
||||||
} else {
|
// Either:
|
||||||
return false;
|
// - request's host does not match guard's host;
|
||||||
|
// - It was possible that the parsed URI from request target did not contain a host.
|
||||||
|
_ => return false,
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref scheme) = self.scheme {
|
if let Some(ref scheme) = self.scheme {
|
||||||
if let Some(ref req_host_uri_scheme) = req_host_uri.scheme_str() {
|
if let Some(ref req_host_uri_scheme) = req_host_uri.scheme_str() {
|
||||||
return scheme == req_host_uri_scheme;
|
return scheme == req_host_uri_scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: is the the correct behavior?
|
||||||
|
// falls through if scheme cannot be determined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all conditions passed
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/route.rs
17
src/route.rs
|
@ -67,9 +67,9 @@ pub struct RouteService {
|
||||||
impl RouteService {
|
impl RouteService {
|
||||||
// TODO: does this need to take &mut ?
|
// TODO: does this need to take &mut ?
|
||||||
pub fn check(&self, req: &mut ServiceRequest) -> bool {
|
pub fn check(&self, req: &mut ServiceRequest) -> bool {
|
||||||
for guard in self.guards.iter() {
|
|
||||||
let guard_ctx = req.guard_ctx();
|
let guard_ctx = req.guard_ctx();
|
||||||
|
|
||||||
|
for guard in self.guards.iter() {
|
||||||
if !guard.check(&guard_ctx) {
|
if !guard.check(&guard_ctx) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@ impl Service<ServiceRequest> for RouteService {
|
||||||
impl Route {
|
impl Route {
|
||||||
/// Add method guard to the route.
|
/// Add method guard to the route.
|
||||||
///
|
///
|
||||||
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use actix_web::*;
|
/// # use actix_web::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
|
@ -113,6 +114,7 @@ impl Route {
|
||||||
|
|
||||||
/// Add guard to the route.
|
/// Add guard to the route.
|
||||||
///
|
///
|
||||||
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use actix_web::*;
|
/// # use actix_web::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
|
@ -146,16 +148,13 @@ impl Route {
|
||||||
/// format!("Welcome {}!", info.username)
|
/// format!("Welcome {}!", info.username)
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
|
||||||
/// let app = App::new().service(
|
/// let app = App::new().service(
|
||||||
/// web::resource("/{username}/index.html") // <- define path parameters
|
/// web::resource("/{username}/index.html") // <- define path parameters
|
||||||
/// .route(web::get().to(index)) // <- register handler
|
/// .route(web::get().to(index)) // <- register handler
|
||||||
/// );
|
/// );
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// It is possible to use multiple extractors for one handler function.
|
/// It is possible to use multiple extractors for one handler function.
|
||||||
///
|
|
||||||
/// ```
|
/// ```
|
||||||
/// # use std::collections::HashMap;
|
/// # use std::collections::HashMap;
|
||||||
/// # use serde::Deserialize;
|
/// # use serde::Deserialize;
|
||||||
|
@ -167,16 +166,18 @@ impl Route {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// /// extract path info using serde
|
/// /// extract path info using serde
|
||||||
/// async fn index(path: web::Path<Info>, query: web::Query<HashMap<String, String>>, body: web::Json<Info>) -> String {
|
/// async fn index(
|
||||||
|
/// path: web::Path<Info>,
|
||||||
|
/// query: web::Query<HashMap<String, String>>,
|
||||||
|
/// body: web::Json<Info>
|
||||||
|
/// ) -> String {
|
||||||
/// format!("Welcome {}!", path.username)
|
/// format!("Welcome {}!", path.username)
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
|
||||||
/// let app = App::new().service(
|
/// let app = App::new().service(
|
||||||
/// web::resource("/{username}/index.html") // <- define path parameters
|
/// web::resource("/{username}/index.html") // <- define path parameters
|
||||||
/// .route(web::get().to(index))
|
/// .route(web::get().to(index))
|
||||||
/// );
|
/// );
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn to<F, Args>(mut self, handler: F) -> Self
|
pub fn to<F, Args>(mut self, handler: F) -> Self
|
||||||
where
|
where
|
||||||
|
@ -202,7 +203,7 @@ impl Route {
|
||||||
/// type Error = Infallible;
|
/// type Error = Infallible;
|
||||||
/// type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
/// type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||||
///
|
///
|
||||||
/// always_ready!();
|
/// dev::always_ready!();
|
||||||
///
|
///
|
||||||
/// fn call(&self, req: ServiceRequest) -> Self::Future {
|
/// fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||||
/// let (req, _) = req.into_parts();
|
/// let (req, _) = req.into_parts();
|
||||||
|
|
Loading…
Reference in New Issue