ccxt_core/http_client/config.rs
1use crate::circuit_breaker::CircuitBreakerConfig;
2use crate::config::ProxyConfig;
3use crate::error::{ConfigValidationError, ValidationResult};
4use crate::retry_strategy::RetryConfig;
5use std::time::Duration;
6
7/// HTTP request configuration
8#[derive(Debug, Clone)]
9pub struct HttpConfig {
10 /// Request timeout
11 pub timeout: Duration,
12 /// TCP connection timeout (default: 10 seconds)
13 pub connect_timeout: Duration,
14 /// Maximum retry attempts (deprecated, use `retry_config` instead)
15 #[deprecated(note = "Use retry_config instead")]
16 pub max_retries: u32,
17 /// Whether to enable verbose logging
18 pub verbose: bool,
19 /// Default User-Agent header value
20 pub user_agent: String,
21 /// Whether to include response headers in the result
22 pub return_response_headers: bool,
23 /// Optional proxy configuration
24 pub proxy: Option<ProxyConfig>,
25 /// Whether to enable rate limiting
26 pub enable_rate_limit: bool,
27 /// Optional retry configuration (uses default if `None`)
28 pub retry_config: Option<RetryConfig>,
29 /// Maximum response body size in bytes (default: 10MB)
30 ///
31 /// Responses exceeding this limit will be rejected with an `InvalidRequest` error.
32 /// This protects against malicious or abnormal responses that could exhaust memory.
33 pub max_response_size: usize,
34
35 /// Maximum request body size in bytes (default: 10MB)
36 ///
37 /// Request bodies exceeding this limit will be rejected BEFORE serialization.
38 /// This protects against DoS attacks via oversized request payloads.
39 pub max_request_size: usize,
40
41 /// Optional circuit breaker configuration.
42 ///
43 /// When enabled, the circuit breaker will track request failures and
44 /// automatically block requests to failing endpoints, allowing the
45 /// system to recover.
46 ///
47 /// Default: `None` (disabled for backward compatibility)
48 pub circuit_breaker: Option<CircuitBreakerConfig>,
49
50 /// Maximum number of idle connections per host in the connection pool.
51 ///
52 /// This controls how many keep-alive connections are maintained for each host.
53 /// Higher values improve performance for repeated requests to the same host
54 /// but consume more resources.
55 ///
56 /// Default: 10
57 pub pool_max_idle_per_host: usize,
58
59 /// Timeout for idle connections in the pool.
60 ///
61 /// Connections that have been idle longer than this duration will be closed.
62 /// This helps free up resources and avoid stale connections.
63 ///
64 /// Default: 90 seconds
65 pub pool_idle_timeout: Duration,
66}
67
68impl Default for HttpConfig {
69 fn default() -> Self {
70 Self {
71 timeout: Duration::from_secs(30),
72 connect_timeout: Duration::from_secs(10),
73 #[allow(deprecated)]
74 max_retries: 3,
75 verbose: false,
76 user_agent: "ccxt-rust/1.0".to_string(),
77 return_response_headers: false,
78 proxy: None,
79 enable_rate_limit: true,
80 retry_config: None,
81 max_response_size: 128 * 1024 * 1024, // 128MB default
82 max_request_size: 10 * 1024 * 1024, // 10MB default
83 circuit_breaker: None,
84 pool_max_idle_per_host: 10,
85 pool_idle_timeout: Duration::from_secs(90),
86 }
87 }
88}
89
90impl HttpConfig {
91 /// Validates the HTTP configuration parameters.
92 ///
93 /// # Returns
94 ///
95 /// Returns `Ok(ValidationResult)` if the configuration is valid.
96 /// The `ValidationResult` may contain warnings for suboptimal but valid configurations.
97 ///
98 /// Returns `Err(ConfigValidationError)` if the configuration is invalid.
99 ///
100 /// # Validation Rules
101 ///
102 /// - `timeout` > 5 minutes returns an error (excessive timeout)
103 /// - `timeout` < 1 second generates a warning (may cause frequent timeouts)
104 ///
105 /// # Example
106 ///
107 /// ```rust
108 /// use ccxt_core::http_client::HttpConfig;
109 /// use std::time::Duration;
110 ///
111 /// let config = HttpConfig::default();
112 /// let result = config.validate();
113 /// assert!(result.is_ok());
114 ///
115 /// let invalid_config = HttpConfig {
116 /// timeout: Duration::from_secs(600), // 10 minutes - too long
117 /// ..Default::default()
118 /// };
119 /// let result = invalid_config.validate();
120 /// assert!(result.is_err());
121 /// ```
122 pub fn validate(&self) -> std::result::Result<ValidationResult, ConfigValidationError> {
123 const MAX_REASONABLE_REQUEST_SIZE: usize = 100 * 1024 * 1024;
124
125 let mut warnings = Vec::new();
126 let max_timeout = Duration::from_secs(300);
127 if self.timeout > max_timeout {
128 return Err(ConfigValidationError::too_high(
129 "timeout",
130 format!("{:?}", self.timeout),
131 "5 minutes",
132 ));
133 }
134
135 if self.timeout < Duration::from_secs(1) {
136 warnings.push(format!(
137 "timeout {:?} is very short, may cause frequent timeouts",
138 self.timeout
139 ));
140 }
141
142 if self.max_request_size == 0 {
143 return Err(ConfigValidationError::invalid(
144 "max_request_size",
145 "max_request_size cannot be zero",
146 ));
147 }
148
149 if self.max_request_size > MAX_REASONABLE_REQUEST_SIZE {
150 return Err(ConfigValidationError::too_high(
151 "max_request_size",
152 format!("{}", self.max_request_size),
153 "100MB (104857600 bytes)",
154 ));
155 }
156
157 Ok(ValidationResult::with_warnings(warnings))
158 }
159}