libsubconverter/utils/
url.rs

1//! URL encoding/decoding utilities
2
3
4/// Encodes a string using URL encoding
5///
6/// # Arguments
7/// * `input` - The string to encode
8///
9/// # Returns
10/// * String containing the URL-encoded input
11///
12/// # Examples
13/// ```
14/// use subconverter_rs::utils::url::url_encode;
15///
16/// let encoded = url_encode("Hello World!");
17/// assert_eq!(encoded, "Hello%20World%21");
18/// ```
19pub fn url_encode(input: &str) -> String {
20    urlencoding::encode(input).into_owned()
21}
22
23/// Decodes a URL-encoded string
24///
25/// # Arguments
26/// * `input` - The URL-encoded string to decode
27///
28/// # Returns
29/// * String containing the decoded input
30/// * Returns the original string if decoding fails
31///
32/// # Examples
33/// ```
34/// use subconverter_rs::utils::url::url_decode;
35///
36/// let decoded = url_decode("Hello%20World%21");
37/// assert_eq!(decoded, "Hello World!");
38/// ```
39pub fn url_decode(input: &str) -> String {
40    urlencoding::decode(input)
41        .map(|cow| cow.into_owned())
42        .unwrap_or_else(|_| input.to_string())
43}
44
45/// Extracts a parameter value from a URL query string
46///
47/// # Arguments
48/// * `url_params` - The URL query string containing parameters
49/// * `param_name` - The name of the parameter to extract
50///
51/// # Returns
52/// * String containing the parameter value if found, or an empty string if not found
53///
54/// # Examples
55/// ```
56/// use subconverter_rs::utils::url::get_url_arg;
57///
58/// let query = "host=example.com&port=443&mode=ws";
59/// assert_eq!(get_url_arg(query, "host"), "example.com");
60/// assert_eq!(get_url_arg(query, "port"), "443");
61/// assert_eq!(get_url_arg(query, "unknown"), "");
62/// ```
63pub fn get_url_arg(url_params: &str, param_name: &str) -> String {
64    let pattern = format!("{}=", param_name);
65    let mut pos = url_params.len();
66
67    while pos > 0 {
68        // Find the pattern starting from pos, moving backward
69        if let Some(found_pos) = url_params[..pos].rfind(&pattern) {
70            // Check if this is a proper parameter boundary
71            if found_pos == 0
72                || url_params.as_bytes()[found_pos - 1] == b'&'
73                || url_params.as_bytes()[found_pos - 1] == b'?'
74            {
75                // Extract the value
76                let start = found_pos + pattern.len();
77                let end = match url_params[start..].find('&') {
78                    Some(ampersand_pos) => start + ampersand_pos,
79                    None => url_params.len(),
80                };
81                return url_params[start..end].to_string();
82            }
83            // Move position backward to continue searching
84            pos = found_pos;
85        } else {
86            // Pattern not found
87            break;
88        }
89
90        // Prevent unsigned integer underflow
91        if pos == 0 {
92            break;
93        }
94        pos -= 1;
95    }
96
97    // Parameter not found
98    String::new()
99}