1use async_trait::async_trait;
2use bytes::Bytes;
3use http::HeaderMap;
4use serde_json::Value;
5
6use super::parser::{ParseError, ParseResult, ParsedData, Parser};
7
8#[derive(Debug, Clone)]
27pub struct JSONParser {
28 pub allow_empty: bool,
30 pub strict: bool,
32}
33
34impl Default for JSONParser {
35 fn default() -> Self {
36 Self {
37 allow_empty: false,
38 strict: true, }
40 }
41}
42
43impl JSONParser {
44 pub fn new() -> Self {
56 Self::default()
57 }
58 pub fn allow_empty(mut self, allow: bool) -> Self {
68 self.allow_empty = allow;
69 self
70 }
71 pub fn strict(mut self, strict: bool) -> Self {
81 self.strict = strict;
82 self
83 }
84}
85
86#[async_trait]
87impl Parser for JSONParser {
88 fn media_types(&self) -> Vec<String> {
89 vec![
90 "application/json".to_string(),
91 "application/*+json".to_string(),
92 ]
93 }
94
95 async fn parse(
96 &self,
97 _content_type: Option<&str>,
98 body: Bytes,
99 _headers: &HeaderMap,
100 ) -> ParseResult<ParsedData> {
101 if body.is_empty() {
102 if self.allow_empty {
103 return Ok(ParsedData::Json(Value::Null));
104 } else {
105 return Err(ParseError::ParseError("Empty request body".to_string()));
106 }
107 }
108
109 match serde_json::from_slice::<Value>(&body) {
110 Ok(value) => {
111 if self.strict {
113 Self::validate_strict_json(&value)?;
114 }
115 Ok(ParsedData::Json(value))
116 }
117 Err(e) => Err(ParseError::ParseError(format!("Invalid JSON: {}", e))),
118 }
119 }
120}
121
122impl JSONParser {
123 fn validate_strict_json(value: &Value) -> ParseResult<()> {
131 match value {
132 Value::Number(n) => {
133 if let Some(f) = n.as_f64()
134 && !f.is_finite()
135 {
136 return Err(ParseError::ParseError(
137 "Non-finite float values (Infinity, -Infinity, NaN) are not allowed in strict mode".to_string()
138 ));
139 }
140 }
141 Value::Array(arr) => {
142 for item in arr {
143 Self::validate_strict_json(item)?;
144 }
145 }
146 Value::Object(obj) => {
147 for value in obj.values() {
148 Self::validate_strict_json(value)?;
149 }
150 }
151 _ => {}
152 }
153 Ok(())
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[tokio::test]
162 async fn test_json_parser_valid() {
163 let parser = JSONParser::new();
164 let body = Bytes::from(r#"{"name": "test", "value": 123}"#);
165 let headers = HeaderMap::new();
166
167 let result = parser
168 .parse(Some("application/json"), body, &headers)
169 .await
170 .unwrap();
171
172 match result {
173 ParsedData::Json(value) => {
174 assert_eq!(value["name"], "test");
175 assert_eq!(value["value"], 123);
176 }
177 _ => panic!("Expected JSON data"),
178 }
179 }
180
181 #[tokio::test]
182 async fn test_json_parser_invalid() {
183 let parser = JSONParser::new();
184 let body = Bytes::from(r#"{"invalid": json}"#);
185 let headers = HeaderMap::new();
186
187 let result = parser.parse(Some("application/json"), body, &headers).await;
188 assert!(result.is_err());
189 }
190
191 #[tokio::test]
192 async fn test_json_parser_empty_not_allowed() {
193 let parser = JSONParser::new();
194 let body = Bytes::new();
195 let headers = HeaderMap::new();
196
197 let result = parser.parse(Some("application/json"), body, &headers).await;
198 assert!(result.is_err());
199 }
200
201 #[tokio::test]
202 async fn test_json_parser_empty_allowed() {
203 let parser = JSONParser::new().allow_empty(true);
204 let body = Bytes::new();
205 let headers = HeaderMap::new();
206
207 let result = parser
208 .parse(Some("application/json"), body, &headers)
209 .await
210 .unwrap();
211
212 match result {
213 ParsedData::Json(Value::Null) => {}
214 _ => panic!("Expected null JSON value"),
215 }
216 }
217
218 #[test]
219 fn test_json_parser_media_types() {
220 let parser = JSONParser::new();
221 let media_types = parser.media_types();
222
223 assert!(media_types.contains(&"application/json".to_string()));
224 assert!(media_types.contains(&"application/*+json".to_string()));
225 }
226
227 #[tokio::test]
230 async fn test_json_float_strictness() {
231 let parser = JSONParser::new(); let headers = HeaderMap::new();
234
235 for value in ["Infinity", "-Infinity", "NaN"] {
239 let body = Bytes::from(value);
240 let result = parser.parse(Some("application/json"), body, &headers).await;
241 assert!(
242 result.is_err(),
243 "Expected error for {} (invalid JSON literal)",
244 value
245 );
246 }
247
248 let parser_non_strict = JSONParser::new().strict(false);
251 let valid_json = Bytes::from(r#"{"value": 1.0}"#);
252 let result = parser_non_strict
253 .parse(Some("application/json"), valid_json, &headers)
254 .await;
255 assert!(result.is_ok(), "Valid JSON should parse in non-strict mode");
256 }
257
258 #[tokio::test]
259 async fn test_json_edge_case_large_numbers() {
260 let parser = JSONParser::new();
262 let headers = HeaderMap::new();
263
264 let large_number = Bytes::from(r#"{"value": 1e308}"#);
266 let result = parser
267 .parse(Some("application/json"), large_number, &headers)
268 .await;
269 assert!(result.is_ok(), "Should parse very large finite numbers");
270
271 let large_negative = Bytes::from(r#"{"value": -1e308}"#);
273 let result = parser
274 .parse(Some("application/json"), large_negative, &headers)
275 .await;
276 assert!(result.is_ok(), "Should parse very large negative numbers");
277 }
278
279 #[tokio::test]
280 async fn test_json_edge_case_small_numbers() {
281 let parser = JSONParser::new();
283 let headers = HeaderMap::new();
284
285 let small_number = Bytes::from(r#"{"value": 2.2250738585072014e-308}"#);
287 let result = parser
288 .parse(Some("application/json"), small_number, &headers)
289 .await;
290 assert!(result.is_ok(), "Should parse very small finite numbers");
291
292 let small_negative = Bytes::from(r#"{"value": -2.2250738585072014e-308}"#);
294 let result = parser
295 .parse(Some("application/json"), small_negative, &headers)
296 .await;
297 assert!(result.is_ok(), "Should parse very small negative numbers");
298 }
299
300 #[tokio::test]
301 async fn test_json_scientific_notation() {
302 let parser = JSONParser::new();
304 let headers = HeaderMap::new();
305
306 let test_cases = vec![
307 r#"{"value": 1.5e10}"#, r#"{"value": 1.5E10}"#, r#"{"value": 1.5e+10}"#, r#"{"value": 1.5e-10}"#, r#"{"array": [1e5, 2e-5]}"#, ];
313
314 for test_case in test_cases {
315 let body = Bytes::from(test_case);
316 let result = parser.parse(Some("application/json"), body, &headers).await;
317 assert!(
318 result.is_ok(),
319 "Should parse scientific notation: {}",
320 test_case
321 );
322 }
323 }
324
325 #[tokio::test]
326 async fn test_json_nested_float_validation() {
327 let parser_strict = JSONParser::new(); let headers = HeaderMap::new();
330
331 let nested_infinity = Bytes::from(r#"{"outer": {"inner": Infinity}}"#);
334 let result = parser_strict
335 .parse(Some("application/json"), nested_infinity, &headers)
336 .await;
337 assert!(
338 result.is_err(),
339 "Nested Infinity literal should be rejected by serde_json"
340 );
341
342 let nested_valid = Bytes::from(r#"{"outer": {"inner": 123.456}}"#);
344 let result = parser_strict
345 .parse(Some("application/json"), nested_valid, &headers)
346 .await;
347 assert!(result.is_ok(), "Valid nested floats should be accepted");
348 }
349
350 #[tokio::test]
351 async fn test_json_array_float_validation() {
352 let parser_strict = JSONParser::new();
354 let parser_non_strict = JSONParser::new().strict(false);
355 let headers = HeaderMap::new();
356
357 let valid_array = Bytes::from(r#"[1.0, 2.5, 3.14159, 100.0]"#);
359 let result = parser_strict
360 .parse(Some("application/json"), valid_array.clone(), &headers)
361 .await;
362 assert!(result.is_ok(), "Valid float arrays should be accepted");
363
364 let result = parser_non_strict
365 .parse(Some("application/json"), valid_array, &headers)
366 .await;
367 assert!(
368 result.is_ok(),
369 "Valid float arrays should be accepted in non-strict mode"
370 );
371
372 let invalid_array = Bytes::from(r#"[1.0, Infinity, 3.0]"#);
374 let result = parser_strict
375 .parse(Some("application/json"), invalid_array.clone(), &headers)
376 .await;
377 assert!(
378 result.is_err(),
379 "Infinity literal in array should be rejected"
380 );
381
382 let result = parser_non_strict
383 .parse(Some("application/json"), invalid_array, &headers)
384 .await;
385 assert!(
386 result.is_err(),
387 "Infinity literal in array should be rejected even in non-strict mode"
388 );
389 }
390}