1use std::sync::Arc;
2
3use http::{Method, StatusCode, Uri};
4
5use crate::WireError;
6
7pub trait RetryPolicy: Send + Sync + 'static {
8 fn should_retry(&self, ctx: &RetryContext<'_>) -> Option<&'static str>;
9}
10
11impl<T> RetryPolicy for Arc<T>
12where
13 T: RetryPolicy + ?Sized,
14{
15 fn should_retry(&self, ctx: &RetryContext<'_>) -> Option<&'static str> {
16 (**self).should_retry(ctx)
17 }
18}
19
20pub struct RetryContext<'a> {
21 error: &'a WireError,
22 attempt: u32,
23 is_body_replayable: bool,
24 request_method: &'a Method,
25}
26
27impl<'a> RetryContext<'a> {
28 pub fn new(
29 error: &'a WireError,
30 attempt: u32,
31 is_body_replayable: bool,
32 request_method: &'a Method,
33 ) -> Self {
34 Self {
35 error,
36 attempt,
37 is_body_replayable,
38 request_method,
39 }
40 }
41
42 pub fn error(&self) -> &'a WireError {
43 self.error
44 }
45
46 pub fn attempt(&self) -> u32 {
47 self.attempt
48 }
49
50 pub fn is_body_replayable(&self) -> bool {
51 self.is_body_replayable
52 }
53
54 pub fn request_method(&self) -> &'a Method {
55 self.request_method
56 }
57}
58
59pub trait RedirectPolicy: Send + Sync + 'static {
60 fn should_redirect(&self, ctx: &RedirectContext<'_>) -> RedirectDecision;
61}
62
63impl<T> RedirectPolicy for Arc<T>
64where
65 T: RedirectPolicy + ?Sized,
66{
67 fn should_redirect(&self, ctx: &RedirectContext<'_>) -> RedirectDecision {
68 (**self).should_redirect(ctx)
69 }
70}
71
72pub struct RedirectContext<'a> {
73 request_method: &'a Method,
74 request_uri: &'a Uri,
75 response_status: StatusCode,
76 location: &'a Uri,
77 redirect_count: u32,
78 is_body_replayable: bool,
79}
80
81impl<'a> RedirectContext<'a> {
82 pub fn new(
83 request_method: &'a Method,
84 request_uri: &'a Uri,
85 response_status: StatusCode,
86 location: &'a Uri,
87 redirect_count: u32,
88 is_body_replayable: bool,
89 ) -> Self {
90 Self {
91 request_method,
92 request_uri,
93 response_status,
94 location,
95 redirect_count,
96 is_body_replayable,
97 }
98 }
99
100 pub fn request_method(&self) -> &'a Method {
101 self.request_method
102 }
103
104 pub fn request_uri(&self) -> &'a Uri {
105 self.request_uri
106 }
107
108 pub fn response_status(&self) -> StatusCode {
109 self.response_status
110 }
111
112 pub fn location(&self) -> &'a Uri {
113 self.location
114 }
115
116 pub fn redirect_count(&self) -> u32 {
117 self.redirect_count
118 }
119
120 pub fn is_body_replayable(&self) -> bool {
121 self.is_body_replayable
122 }
123}
124
125pub enum RedirectDecision {
126 Follow,
127 Stop,
128 Error(WireError),
129}