mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-19 06:04:40 +01:00
add acceptable guard (#2265)
This commit is contained in:
parent
d97bd7ec17
commit
d708a4de6d
@ -5,7 +5,9 @@
|
|||||||
- Add `ContentDisposition::attachment` constructor. [#2867]
|
- Add `ContentDisposition::attachment` constructor. [#2867]
|
||||||
- Add `ErrorHandlers::default_handler()` (as well as `default_handler_{server, client}()`) to make registering handlers for groups of response statuses easier. [#2784]
|
- Add `ErrorHandlers::default_handler()` (as well as `default_handler_{server, client}()`) to make registering handlers for groups of response statuses easier. [#2784]
|
||||||
- Add `Logger::custom_response_replace()`. [#2631]
|
- Add `Logger::custom_response_replace()`. [#2631]
|
||||||
|
- Add `guard::Acceptable` for matching against `Accept` header mime types. [#2265]
|
||||||
|
|
||||||
|
[#2265]: https://github.com/actix/actix-web/pull/2265
|
||||||
[#2631]: https://github.com/actix/actix-web/pull/2631
|
[#2631]: https://github.com/actix/actix-web/pull/2631
|
||||||
[#2784]: https://github.com/actix/actix-web/pull/2784
|
[#2784]: https://github.com/actix/actix-web/pull/2784
|
||||||
[#2867]: https://github.com/actix/actix-web/pull/2867
|
[#2867]: https://github.com/actix/actix-web/pull/2867
|
||||||
|
99
actix-web/src/guard/acceptable.rs
Normal file
99
actix-web/src/guard/acceptable.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use super::{Guard, GuardContext};
|
||||||
|
use crate::http::header::Accept;
|
||||||
|
|
||||||
|
/// A guard that verifies that an `Accept` header is present and it contains a compatible MIME type.
|
||||||
|
///
|
||||||
|
/// An exception is that matching `*/*` must be explicitly enabled because most browsers send this
|
||||||
|
/// as part of their `Accept` header for almost every request.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// use actix_web::{guard::Acceptable, web, HttpResponse};
|
||||||
|
///
|
||||||
|
/// web::resource("/images")
|
||||||
|
/// .guard(Acceptable::new(mime::IMAGE_STAR))
|
||||||
|
/// .default_service(web::to(|| async {
|
||||||
|
/// HttpResponse::Ok().body("only called when images responses are acceptable")
|
||||||
|
/// }));
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Acceptable {
|
||||||
|
mime: mime::Mime,
|
||||||
|
|
||||||
|
/// Wether to match `*/*` mime type.
|
||||||
|
///
|
||||||
|
/// Defaults to false because it's not very useful otherwise.
|
||||||
|
match_star_star: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Acceptable {
|
||||||
|
/// Constructs new `Acceptable` guard with the given `mime` type/pattern.
|
||||||
|
pub fn new(mime: mime::Mime) -> Self {
|
||||||
|
Self {
|
||||||
|
mime,
|
||||||
|
match_star_star: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows `*/*` in the `Accept` header to pass the guard check.
|
||||||
|
pub fn match_star_star(mut self) -> Self {
|
||||||
|
self.match_star_star = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Guard for Acceptable {
|
||||||
|
fn check(&self, ctx: &GuardContext<'_>) -> bool {
|
||||||
|
let accept = match ctx.header::<Accept>() {
|
||||||
|
Some(hdr) => hdr,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_type = self.mime.type_();
|
||||||
|
let target_subtype = self.mime.subtype();
|
||||||
|
|
||||||
|
for mime in accept.0.into_iter().map(|q| q.item) {
|
||||||
|
return match (mime.type_(), mime.subtype()) {
|
||||||
|
(typ, subtype) if typ == target_type && subtype == target_subtype => true,
|
||||||
|
(typ, mime::STAR) if typ == target_type => true,
|
||||||
|
(mime::STAR, mime::STAR) if self.match_star_star => true,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::{http::header, test::TestRequest};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_acceptable() {
|
||||||
|
let req = TestRequest::default().to_srv_request();
|
||||||
|
assert!(!Acceptable::new(mime::APPLICATION_JSON).check(&req.guard_ctx()));
|
||||||
|
|
||||||
|
let req = TestRequest::default()
|
||||||
|
.insert_header((header::ACCEPT, "application/json"))
|
||||||
|
.to_srv_request();
|
||||||
|
assert!(Acceptable::new(mime::APPLICATION_JSON).check(&req.guard_ctx()));
|
||||||
|
|
||||||
|
let req = TestRequest::default()
|
||||||
|
.insert_header((header::ACCEPT, "text/html, application/json"))
|
||||||
|
.to_srv_request();
|
||||||
|
assert!(Acceptable::new(mime::APPLICATION_JSON).check(&req.guard_ctx()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_acceptable_star() {
|
||||||
|
let req = TestRequest::default()
|
||||||
|
.insert_header((header::ACCEPT, "text/html, */*;q=0.8"))
|
||||||
|
.to_srv_request();
|
||||||
|
|
||||||
|
assert!(Acceptable::new(mime::APPLICATION_JSON)
|
||||||
|
.match_star_star()
|
||||||
|
.check(&req.guard_ctx()));
|
||||||
|
}
|
||||||
|
}
|
@ -56,6 +56,9 @@ use actix_http::{header, uri::Uri, Extensions, Method as HttpMethod, RequestHead
|
|||||||
|
|
||||||
use crate::{http::header::Header, service::ServiceRequest, HttpMessage as _};
|
use crate::{http::header::Header, service::ServiceRequest, HttpMessage as _};
|
||||||
|
|
||||||
|
mod acceptable;
|
||||||
|
pub use self::acceptable::Acceptable;
|
||||||
|
|
||||||
/// Provides access to request parts that are useful during routing.
|
/// Provides access to request parts that are useful during routing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GuardContext<'a> {
|
pub struct GuardContext<'a> {
|
Loading…
x
Reference in New Issue
Block a user