1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! Middleware for retrying "failed" requests.
use crate::;
use future;
use retry;
// This constant comes from the IC specification:
// > If provided, the value must not exceed 2MB
const HTTP_MAX_SIZE: u64 = 2_000_000;
/// Double the request `max_response_bytes` in case the error indicates the response was too big.
///
/// The value for `max_response_bytes` will be doubled until one of the following conditions happen:
/// 1. Either the response is `Ok` or the error is not due to the response being too big;
/// 2. Or, the maximum value of 2MB (`2_000_000`) is reached.
///
/// # Examples
///
/// ```rust
/// use canhttp::{
/// Client, http::HttpRequest, HttpsOutcallError, IcError, MaxResponseBytesRequestExtension,
/// retry::DoubleMaxResponseBytes
/// };
/// use ic_error_types::RejectCode;
/// use tower::{Service, ServiceBuilder, ServiceExt};
///
/// fn response_is_too_large_error() -> IcError {
/// let error = IcError::CallRejected {
/// code: RejectCode::SysFatal,
/// message: "Http body exceeds size limit".to_string(),
/// };
/// assert!(error.is_response_too_large());
/// error
/// }
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use assert_matches::assert_matches;
/// let mut service = ServiceBuilder::new()
/// .retry(DoubleMaxResponseBytes)
/// .service_fn(|request: HttpRequest| async move {
/// match request.get_max_response_bytes() {
/// Some(max_response_bytes) if max_response_bytes >= 8192 => Ok(()),
/// _ => Err::<(), IcError>(response_is_too_large_error()),
/// }
/// });
///
/// let request = http::Request::post("https://internetcomputer.org/")
/// .max_response_bytes(0)
/// .body(vec![])
/// .unwrap();
///
/// // This will effectively do 4 calls with the following max_response_bytes values: 0, 2048, 4096, 8192.
/// let response = service.ready().await?.call(request).await;
///
/// assert_matches!(response, Ok(()));
/// # Ok(())
/// # }
/// ```
;