nucleus_http/
utils.rs

1use base64::{engine::general_purpose, Engine as _};
2use bytes::Bytes;
3use memchr::{memchr, memchr_iter};
4use rand::{distributions::Alphanumeric, thread_rng, Rng};
5use secrecy::SecretString;
6use std::collections::HashMap;
7
8pub fn generate_random_secret() -> SecretString {
9    let rand_string: String = thread_rng()
10        .sample_iter(&Alphanumeric)
11        .take(30)
12        .map(char::from)
13        .collect();
14
15    rand_string.into()
16}
17
18pub fn base64_encode(original: Vec<u8>) -> String {
19    general_purpose::STANDARD_NO_PAD.encode(original)
20}
21
22pub fn base64_decode(encoded: String) -> Result<Vec<u8>, anyhow::Error> {
23    Ok(general_purpose::STANDARD_NO_PAD.decode(encoded)?)
24}
25
26pub fn parse_query_string(query: &Bytes) -> Result<HashMap<String, String>, anyhow::Error> {
27    let mut map = HashMap::new();
28    if query.is_empty() {
29        return Ok(map);
30    }
31    //Each entry is split with &
32    let mut and_iter = memchr_iter(b'&', query);
33    let mut next_slice_start_at = 0;
34    let mut data_left = true;
35    while data_left {
36        let slice;
37        match and_iter.next() {
38            Some(next_and) => {
39                slice = query.slice(next_slice_start_at..next_and);
40                next_slice_start_at = next_and + 1;
41            }
42            None => {
43                //we are at the end
44                slice = query.slice(next_slice_start_at..);
45                data_left = false;
46            }
47        }
48        //each entry is key value pair split by =
49        if let Some(equal_i) = memchr(b'=', &slice) {
50            let key = String::from_utf8_lossy(&slice.slice(..equal_i)).to_string();
51            let value = String::from_utf8_lossy(&slice.slice(equal_i + 1..)).to_string();
52            map.insert(key, value);
53        } else {
54            return Err(anyhow::Error::msg("Invalid entry"));
55        }
56    }
57    Ok(map)
58}
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn test_query_string() {
65        let query_string = "flavor=vanilla&food=ice cream";
66        let query_bytes = Bytes::from_static(query_string.as_bytes());
67        let query = parse_query_string(&query_bytes).expect("Error Parsing Query String");
68        assert_eq!(
69            "vanilla",
70            query.get("flavor").expect("Flavor Missing in Map")
71        );
72        assert_eq!("ice cream", query.get("food").expect("Food Misisng in map"));
73    }
74}