libsubconverter/utils/
http.rs

1use case_insensitive_string::CaseInsensitiveString;
2use std::collections::HashMap;
3
4// Import platform-specific implementations
5#[cfg(not(target_arch = "wasm32"))]
6mod platform {
7    pub use crate::utils::http_std::*;
8}
9
10#[cfg(target_arch = "wasm32")]
11mod platform {
12    pub use crate::utils::http_wasm::*;
13}
14
15// Re-export platform-specific implementations
16pub use platform::*;
17
18/// Asynchronous function that returns only the body content if status is 2xx,
19/// otherwise treats as error
20/// This provides backward compatibility with code expecting only successful responses
21pub async fn web_get_content_async(
22    url: &str,
23    proxy_config: &ProxyConfig,
24    headers: Option<&HashMap<CaseInsensitiveString, String>>,
25) -> Result<String, String> {
26    match web_get_async(url, proxy_config, headers).await {
27        Ok(response) => {
28            if (200..300).contains(&response.status) {
29                Ok(response.body)
30            } else {
31                Err(format!("HTTP error {}: {}", response.status, response.body))
32            }
33        }
34        Err(e) => Err(e.message),
35    }
36}
37
38/// Extract subscription info from HTTP headers
39///
40/// # Arguments
41/// * `headers` - HTTP response headers
42///
43/// # Returns
44/// * Subscription info string with key-value pairs
45pub fn get_sub_info_from_header(headers: &HashMap<String, String>) -> String {
46    let mut sub_info = String::new();
47
48    // Extract upload and download
49    let mut upload: u64 = 0;
50    let mut download: u64 = 0;
51    let mut total: u64 = 0;
52    let mut expire: String = String::new();
53
54    // Look for subscription-userinfo header
55    if let Some(userinfo) = headers.get("subscription-userinfo") {
56        for info_item in userinfo.split(';') {
57            let info_item = info_item.trim();
58            if info_item.starts_with("upload=") {
59                if let Ok(value) = info_item[7..].parse::<u64>() {
60                    upload = value;
61                }
62            } else if info_item.starts_with("download=") {
63                if let Ok(value) = info_item[9..].parse::<u64>() {
64                    download = value;
65                }
66            } else if info_item.starts_with("total=") {
67                if let Ok(value) = info_item[6..].parse::<u64>() {
68                    total = value;
69                }
70            } else if info_item.starts_with("expire=") {
71                expire = info_item[7..].to_string();
72            }
73        }
74    }
75
76    // Add traffic info
77    if upload > 0 || download > 0 {
78        sub_info.push_str(&format!("upload={}, download={}", upload, download));
79    }
80
81    // Add total traffic
82    if total > 0 {
83        if !sub_info.is_empty() {
84            sub_info.push_str(", ");
85        }
86        sub_info.push_str(&format!("total={}", total));
87    }
88
89    // Add expiry info
90    if !expire.is_empty() {
91        if !sub_info.is_empty() {
92            sub_info.push_str(", ");
93        }
94        sub_info.push_str(&format!("expire={}", expire));
95    }
96
97    sub_info
98}
99
100/// Get subscription info from response headers with additional formatting
101///
102/// # Arguments
103/// * `headers` - HTTP response headers
104/// * `sub_info` - Mutable string to append info to
105///
106/// # Returns
107/// * `true` if info was extracted, `false` otherwise
108pub fn get_sub_info_from_response(
109    headers: &HashMap<String, String>,
110    sub_info: &mut String,
111) -> bool {
112    let header_info = get_sub_info_from_header(headers);
113    if !header_info.is_empty() {
114        if !sub_info.is_empty() {
115            sub_info.push_str(", ");
116        }
117        sub_info.push_str(&header_info);
118        true
119    } else {
120        false
121    }
122}