api_scanner/scanner/common/
http_utils.rs1use std::collections::HashMap;
2
3use serde_json::Value;
4
5use crate::http_client::HttpResponse;
6
7pub fn get_content_type(headers: &HashMap<String, String>) -> String {
8 headers
9 .get("content-type")
10 .map(|s| s.to_ascii_lowercase())
11 .unwrap_or_default()
12}
13
14pub fn is_json_content_type(content_type: &str) -> bool {
15 let media_type = content_type
16 .split(';')
17 .next()
18 .unwrap_or(content_type)
19 .trim();
20
21 media_type
22 .as_bytes()
23 .windows(4)
24 .any(|window| window.eq_ignore_ascii_case(b"json"))
25}
26
27pub fn is_html_content_type(content_type: &str) -> bool {
28 let lower = content_type.to_ascii_lowercase();
29 lower.contains("text/html") || lower.contains("application/xhtml")
30}
31
32pub fn is_json_response(headers: &HashMap<String, String>, body: &str) -> bool {
33 let ct = get_content_type(headers);
34 is_json_content_type(&ct) || serde_json::from_str::<Value>(body).is_ok()
35}
36
37pub fn parse_json_body(body: &str, content_type: Option<&str>) -> Option<Value> {
38 let parsed = serde_json::from_str::<Value>(body).ok();
39 let is_json = content_type.map(is_json_content_type).unwrap_or(false);
40
41 if is_json || parsed.is_some() {
42 parsed
43 } else {
44 None
45 }
46}
47
48pub fn parse_json_response(resp: &HttpResponse) -> Option<Value> {
49 parse_json_body(
50 &resp.body,
51 resp.headers.get("content-type").map(|s| s.as_str()),
52 )
53}