1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct PerformanceConfig {
11 pub max_memory_mb: usize,
13 pub max_operations_per_batch: usize,
15 pub cache_size_mb: usize,
17 pub enable_streaming: bool,
19 pub max_concurrent_ops: usize,
21 pub operation_timeout_ms: u64,
23}
24
25impl Default for PerformanceConfig {
26 fn default() -> Self {
27 Self {
28 max_memory_mb: 512,
29 max_operations_per_batch: 1000,
30 cache_size_mb: 64,
31 enable_streaming: true,
32 max_concurrent_ops: 4,
33 operation_timeout_ms: 30000,
34 }
35 }
36}
37
38impl PerformanceConfig {
39 pub fn minimal() -> Self {
41 Self {
42 max_memory_mb: 64,
43 max_operations_per_batch: 100,
44 cache_size_mb: 8,
45 enable_streaming: false,
46 max_concurrent_ops: 1,
47 operation_timeout_ms: 10000,
48 }
49 }
50
51 pub fn high_performance() -> Self {
53 Self {
54 max_memory_mb: 2048,
55 max_operations_per_batch: 10000,
56 cache_size_mb: 256,
57 enable_streaming: true,
58 max_concurrent_ops: 16,
59 operation_timeout_ms: 60000,
60 }
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct SecurityConfig {
67 pub allowed_schemes: Vec<String>,
69 pub max_url_length: usize,
71 pub block_external_resources: bool,
73 pub sanitize_content: bool,
75 pub max_block_size: usize,
77}
78
79impl Default for SecurityConfig {
80 fn default() -> Self {
81 Self {
82 allowed_schemes: vec!["http".to_string(), "https".to_string(), "data".to_string()],
83 max_url_length: 2048,
84 block_external_resources: false,
85 sanitize_content: true,
86 max_block_size: 1024 * 1024, }
88 }
89}
90
91impl SecurityConfig {
92 pub fn strict() -> Self {
94 Self {
95 allowed_schemes: vec!["https".to_string()],
96 max_url_length: 1024,
97 block_external_resources: true,
98 sanitize_content: true,
99 max_block_size: 256 * 1024, }
101 }
102
103 pub fn validate_url(&self, url: &str) -> Result<(), String> {
105 if url.len() > self.max_url_length {
106 return Err(format!(
107 "URL exceeds maximum length of {} characters",
108 self.max_url_length
109 ));
110 }
111
112 let scheme = url.split(':').next().unwrap_or("");
114 if !self.allowed_schemes.contains(&scheme.to_lowercase()) {
115 return Err(format!(
116 "URL scheme '{}' is not allowed. Allowed schemes: {:?}",
117 scheme, self.allowed_schemes
118 ));
119 }
120
121 if url.contains("..") {
123 return Err("Path traversal attempts are not allowed".to_string());
124 }
125
126 Ok(())
127 }
128}
129
130#[derive(Debug, Clone, Default, Serialize, Deserialize)]
132pub struct EngineConfig {
133 pub performance: PerformanceConfig,
134 pub security: SecurityConfig,
135}
136
137impl EngineConfig {
138 pub fn new() -> Self {
139 Self::default()
140 }
141
142 pub fn with_performance(mut self, config: PerformanceConfig) -> Self {
143 self.performance = config;
144 self
145 }
146
147 pub fn with_security(mut self, config: SecurityConfig) -> Self {
148 self.security = config;
149 self
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_default_config() {
159 let config = EngineConfig::default();
160 assert_eq!(config.performance.max_memory_mb, 512);
161 assert!(config
162 .security
163 .allowed_schemes
164 .contains(&"https".to_string()));
165 }
166
167 #[test]
168 fn test_minimal_config() {
169 let config = PerformanceConfig::minimal();
170 assert!(config.max_memory_mb < 100);
171 assert!(!config.enable_streaming);
172 }
173
174 #[test]
175 fn test_high_performance_config() {
176 let config = PerformanceConfig::high_performance();
177 assert!(config.max_memory_mb > 1000);
178 assert!(config.max_concurrent_ops > 8);
179 }
180
181 #[test]
182 fn test_strict_security() {
183 let config = SecurityConfig::strict();
184 assert!(config.block_external_resources);
185 assert_eq!(config.allowed_schemes.len(), 1);
186 }
187
188 #[test]
189 fn test_url_validation() {
190 let config = SecurityConfig::default();
191
192 assert!(config.validate_url("https://example.com/image.jpg").is_ok());
194 assert!(config.validate_url("http://example.com/file").is_ok());
195 assert!(config.validate_url("data:image/png;base64,abc123").is_ok());
196
197 assert!(config.validate_url("ftp://example.com/file").is_err());
199
200 assert!(config
202 .validate_url("https://example.com/../etc/passwd")
203 .is_err());
204 }
205
206 #[test]
207 fn test_url_length_limit() {
208 let config = SecurityConfig {
209 max_url_length: 50,
210 ..Default::default()
211 };
212
213 let short_url = "https://example.com/a";
214 let long_url = "https://example.com/".to_string() + &"a".repeat(100);
215
216 assert!(config.validate_url(short_url).is_ok());
217 assert!(config.validate_url(&long_url).is_err());
218 }
219}