tower_http/follow_redirect/policy/
or.rs1use super::{Action, Attempt, Policy};
2use http::Request;
3
4#[derive(Clone, Copy, Debug, Default)]
8pub struct Or<A, B> {
9 a: A,
10 b: B,
11}
12
13impl<A, B> Or<A, B> {
14 pub(crate) fn new<Bd, E>(a: A, b: B) -> Self
15 where
16 A: Policy<Bd, E>,
17 B: Policy<Bd, E>,
18 {
19 Or { a, b }
20 }
21}
22
23impl<Bd, E, A, B> Policy<Bd, E> for Or<A, B>
24where
25 A: Policy<Bd, E>,
26 B: Policy<Bd, E>,
27{
28 fn redirect(&mut self, attempt: &Attempt<'_>) -> Result<Action, E> {
29 match self.a.redirect(attempt) {
30 Ok(Action::Stop) | Err(_) => self.b.redirect(attempt),
31 a => a,
32 }
33 }
34
35 fn on_request(&mut self, request: &mut Request<Bd>) {
36 self.a.on_request(request);
37 self.b.on_request(request);
38 }
39
40 fn clone_body(&self, body: &Bd) -> Option<Bd> {
41 self.a.clone_body(body).or_else(|| self.b.clone_body(body))
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use http::Uri;
49
50 struct Taint<P> {
51 policy: P,
52 used: bool,
53 }
54
55 impl<P> Taint<P> {
56 fn new(policy: P) -> Self {
57 Taint {
58 policy,
59 used: false,
60 }
61 }
62 }
63
64 impl<B, E, P> Policy<B, E> for Taint<P>
65 where
66 P: Policy<B, E>,
67 {
68 fn redirect(&mut self, attempt: &Attempt<'_>) -> Result<Action, E> {
69 self.used = true;
70 self.policy.redirect(attempt)
71 }
72 }
73
74 #[test]
75 fn redirect() {
76 let attempt = Attempt {
77 status: Default::default(),
78 location: &Uri::from_static("*"),
79 previous: &Uri::from_static("*"),
80 };
81
82 let mut a = Taint::new(Action::Follow);
83 let mut b = Taint::new(Action::Follow);
84 let mut policy = Or::new::<(), ()>(&mut a, &mut b);
85 assert!(Policy::<(), ()>::redirect(&mut policy, &attempt)
86 .unwrap()
87 .is_follow());
88 assert!(a.used);
89 assert!(!b.used); let mut a = Taint::new(Action::Stop);
92 let mut b = Taint::new(Action::Follow);
93 let mut policy = Or::new::<(), ()>(&mut a, &mut b);
94 assert!(Policy::<(), ()>::redirect(&mut policy, &attempt)
95 .unwrap()
96 .is_follow());
97 assert!(a.used);
98 assert!(b.used);
99
100 let mut a = Taint::new(Action::Follow);
101 let mut b = Taint::new(Action::Stop);
102 let mut policy = Or::new::<(), ()>(&mut a, &mut b);
103 assert!(Policy::<(), ()>::redirect(&mut policy, &attempt)
104 .unwrap()
105 .is_follow());
106 assert!(a.used);
107 assert!(!b.used);
108
109 let mut a = Taint::new(Action::Stop);
110 let mut b = Taint::new(Action::Stop);
111 let mut policy = Or::new::<(), ()>(&mut a, &mut b);
112 assert!(Policy::<(), ()>::redirect(&mut policy, &attempt)
113 .unwrap()
114 .is_stop());
115 assert!(a.used);
116 assert!(b.used);
117 }
118}