rocket_etag_if_none_match/
lib.rs

1/*!
2# Etag `if-none-match` Request Guard for Rocket Framework
3
4This crate provides a request guard used for getting `if-none-match` header.
5
6See `examples`.
7*/
8
9pub extern crate entity_tag;
10
11use entity_tag::EntityTag;
12use rocket::{
13    outcome::Outcome,
14    request::{self, FromRequest, Request},
15};
16
17/// The request guard used for getting `if-none-match` header.
18#[derive(Debug, Clone, Default)]
19pub struct EtagIfNoneMatch<'r> {
20    pub etag: Option<EntityTag<'r>>,
21}
22
23#[rocket::async_trait]
24impl<'r> FromRequest<'r> for EtagIfNoneMatch<'r> {
25    type Error = ();
26
27    async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
28        let raw_etag: Option<&str> = request.headers().get("if-none-match").next(); // Only fetch the first one.
29
30        let etag = raw_etag.map(|raw_etag| EntityTag::from_str(raw_etag).ok()).unwrap_or(None);
31
32        Outcome::Success(EtagIfNoneMatch {
33            etag,
34        })
35    }
36}
37
38#[rocket::async_trait]
39impl<'r> FromRequest<'r> for &'r EtagIfNoneMatch<'r> {
40    type Error = ();
41
42    async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
43        Outcome::Success(request.local_cache(|| {
44            let raw_etag: Option<&str> = request.headers().get("if-none-match").next(); // Only fetch the first one.
45
46            let etag =
47                raw_etag.map(|raw_etag| EntityTag::from_string(raw_etag).ok()).unwrap_or(None);
48
49            EtagIfNoneMatch {
50                etag,
51            }
52        }))
53    }
54}
55
56impl<'r> EtagIfNoneMatch<'r> {
57    /// For weak comparison two entity-tags are equivalent if their opaque-tags match character-by-character, regardless of either or both being tagged as "weak".
58    pub fn weak_eq(&self, other_etag: &EntityTag) -> bool {
59        match &self.etag {
60            Some(etag) => etag.weak_eq(other_etag),
61            None => false,
62        }
63    }
64
65    /// For strong comparison two entity-tags are equivalent if both are not weak and their opaque-tags match character-by-character.
66    pub fn strong_eq(&self, other_etag: &EntityTag) -> bool {
67        match &self.etag {
68            Some(etag) => etag.strong_eq(other_etag),
69            None => false,
70        }
71    }
72}