|
| 1 | +use std::time::Duration; |
| 2 | + |
| 3 | +use crate::vm::{VmError, VmResult}; |
| 4 | + |
| 5 | +/// Bounded network policy for the built-in HTTP client and future streaming adapters. |
| 6 | +#[derive(Clone, Debug, PartialEq, Eq)] |
| 7 | +pub struct HttpConfig { |
| 8 | + pub allowed_schemes: Vec<String>, |
| 9 | + pub allowed_hosts: Vec<String>, |
| 10 | + pub allowed_ports: Vec<u16>, |
| 11 | + pub max_redirects: usize, |
| 12 | + pub max_request_body_bytes: usize, |
| 13 | + /// Maximum number of caller-supplied request header fields. Client-managed |
| 14 | + /// fields such as `Host` are outside this extension surface. |
| 15 | + pub max_request_header_count: usize, |
| 16 | + /// Maximum serialized size of the caller-supplied request header block. |
| 17 | + /// Every field contributes `name + ": " + value + "\\r\\n"`; the final |
| 18 | + /// terminating `"\\r\\n"` is included as well. |
| 19 | + pub max_request_header_bytes: usize, |
| 20 | + pub max_response_body_bytes: usize, |
| 21 | + pub connect_timeout: Duration, |
| 22 | + pub request_timeout: Duration, |
| 23 | + pub allow_private_ips: bool, |
| 24 | + pub max_stream_item_bytes: usize, |
| 25 | + pub max_stream_total_bytes: usize, |
| 26 | + pub max_sse_line_bytes: usize, |
| 27 | + pub max_stream_duration: Duration, |
| 28 | + pub stream_idle_timeout: Duration, |
| 29 | +} |
| 30 | + |
| 31 | +impl HttpConfig { |
| 32 | + /// Validates limits that must remain positive for every streaming adapter. |
| 33 | + pub fn validate(&self) -> VmResult<()> { |
| 34 | + let positive_limits = [ |
| 35 | + ("max_stream_item_bytes", self.max_stream_item_bytes), |
| 36 | + ("max_stream_total_bytes", self.max_stream_total_bytes), |
| 37 | + ("max_sse_line_bytes", self.max_sse_line_bytes), |
| 38 | + ]; |
| 39 | + if let Some((name, _)) = positive_limits.iter().find(|(_, value)| *value == 0) { |
| 40 | + return Err(VmError::HostError(format!( |
| 41 | + "HTTP configuration field '{name}' must be positive" |
| 42 | + ))); |
| 43 | + } |
| 44 | + let positive_header_limits = [ |
| 45 | + ("max_request_header_count", self.max_request_header_count), |
| 46 | + ("max_request_header_bytes", self.max_request_header_bytes), |
| 47 | + ]; |
| 48 | + if let Some((name, _)) = positive_header_limits.iter().find(|(_, value)| *value == 0) { |
| 49 | + return Err(VmError::HostError(format!( |
| 50 | + "HTTP configuration field '{name}' must be positive" |
| 51 | + ))); |
| 52 | + } |
| 53 | + let positive_timeouts = [ |
| 54 | + ("connect_timeout", self.connect_timeout), |
| 55 | + ("request_timeout", self.request_timeout), |
| 56 | + ("max_stream_duration", self.max_stream_duration), |
| 57 | + ("stream_idle_timeout", self.stream_idle_timeout), |
| 58 | + ]; |
| 59 | + if let Some((name, _)) = positive_timeouts |
| 60 | + .iter() |
| 61 | + .find(|(_, timeout)| timeout.is_zero()) |
| 62 | + { |
| 63 | + return Err(VmError::HostError(format!( |
| 64 | + "HTTP configuration field '{name}' must be positive" |
| 65 | + ))); |
| 66 | + } |
| 67 | + if let Some((name, _)) = positive_timeouts |
| 68 | + .iter() |
| 69 | + .find(|(_, timeout)| std::time::Instant::now().checked_add(*timeout).is_none()) |
| 70 | + { |
| 71 | + return Err(VmError::HostError(format!( |
| 72 | + "HTTP configuration field '{name}' is too large" |
| 73 | + ))); |
| 74 | + } |
| 75 | + Ok(()) |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +impl Default for HttpConfig { |
| 80 | + fn default() -> Self { |
| 81 | + Self { |
| 82 | + allowed_schemes: vec!["https".to_string()], |
| 83 | + allowed_hosts: Vec::new(), |
| 84 | + allowed_ports: Vec::new(), |
| 85 | + max_redirects: 5, |
| 86 | + max_request_body_bytes: 1024 * 1024, |
| 87 | + max_request_header_count: 100, |
| 88 | + max_request_header_bytes: 64 * 1024, |
| 89 | + max_response_body_bytes: 8 * 1024 * 1024, |
| 90 | + connect_timeout: Duration::from_secs(10), |
| 91 | + request_timeout: Duration::from_secs(30), |
| 92 | + allow_private_ips: false, |
| 93 | + max_stream_item_bytes: 1024 * 1024, |
| 94 | + max_stream_total_bytes: 64 * 1024 * 1024, |
| 95 | + max_sse_line_bytes: 64 * 1024, |
| 96 | + max_stream_duration: Duration::from_secs(5 * 60), |
| 97 | + stream_idle_timeout: Duration::from_secs(30), |
| 98 | + } |
| 99 | + } |
| 100 | +} |
0 commit comments