user_agent_parser/
request_guards.rs1use std::borrow::Cow;
2
3use rocket::{
4 outcome::Outcome,
5 request::{FromRequest, Outcome as OutcomeResult, Request},
6};
7
8use crate::{UserAgentParser, models::*};
9
10const NOT_MANAGED: &str = "a `UserAgentParser` is not managed by Rocket; add \
11 `.manage(UserAgentParser::from_path(..))` when building the instance";
12
13fn from_request_user_agent<'r>(request: &'r Request<'_>) -> UserAgent<'r> {
14 let user_agent: Option<Cow<'r, str>> =
15 request.headers().get("user-agent").next().map(Cow::from);
16
17 UserAgent {
18 user_agent,
19 }
20}
21
22#[rocket::async_trait]
23impl<'r> FromRequest<'r> for UserAgent<'r> {
24 type Error = ();
25
26 async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
27 Outcome::Success(from_request_user_agent(request))
28 }
29}
30
31#[rocket::async_trait]
32impl<'r> FromRequest<'r> for &UserAgent<'r> {
33 type Error = ();
34
35 async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
36 let cache = request.local_cache(|| from_request_user_agent(request).into_owned());
37
38 Outcome::Success(cache)
39 }
40}
41
42macro_rules! impl_from_request {
44 ($model:ident, $parse:ident) => {
45 #[rocket::async_trait]
46 impl<'r> FromRequest<'r> for $model<'r> {
47 type Error = ();
48
49 async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
50 Outcome::Success(parse(request))
51 }
52 }
53
54 #[rocket::async_trait]
55 impl<'r> FromRequest<'r> for &$model<'r> {
56 type Error = ();
57
58 async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
59 let cache = request.local_cache_async(async { parse(request).into_owned() }).await;
60
61 Outcome::Success(cache)
62 }
63 }
64
65 fn parse<'r>(request: &'r Request<'_>) -> $model<'r> {
66 let user_agent_parser = request.rocket().state::<UserAgentParser>().expect(NOT_MANAGED);
67
68 match request.headers().get("user-agent").next() {
69 Some(user_agent) => user_agent_parser.$parse(user_agent),
70 None => $model::default(),
71 }
72 }
73 };
74}
75
76mod product {
78 use super::*;
79
80 impl_from_request!(Product, parse_product);
81}
82
83mod os {
84 use super::*;
85
86 impl_from_request!(OS, parse_os);
87}
88
89mod device {
90 use super::*;
91
92 impl_from_request!(Device, parse_device);
93}
94
95mod cpu {
96 use super::*;
97
98 impl_from_request!(CPU, parse_cpu);
99}
100
101mod engine {
102 use super::*;
103
104 impl_from_request!(Engine, parse_engine);
105}