1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use crate::http::CRLF;
use regex::Regex;
use serde::Serialize;
use std::{fmt, str};

#[derive(Debug, Serialize)]
pub struct Header {
    pub name: String,
    pub value: String,
}

impl fmt::Display for Header {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {}", self.name, self.value)
    }
}

#[derive(Debug, Serialize)]
pub struct Headers {
    pub content_length: usize,
    pub raw: String,
    pub parsed: Vec<Header>,
}

impl Headers {
    pub fn new(buffer: Vec<u8>) -> Self {
        let raw = stringify(&buffer);
        let mut content_length: usize = 0;
        let content_length_op = get_content_length(&raw);
        if let Some(val) = content_length_op {
            content_length = val;
        }
        Headers {
            content_length,
            raw: raw.clone(),
            parsed: parse(raw),
        }
    }

    pub fn from_string(raw: String) -> Self {
        let mut content_length: usize = 0;
        let content_length_op = get_content_length(&raw);
        if let Some(val) = content_length_op {
            content_length = val;
        }
        Headers {
            content_length,
            raw: raw.clone(),
            parsed: parse(raw),
        }
    }

    pub fn change_host(self, target: &str) -> Self {
        let raw = change_host(self.raw, target);
        Headers {
            raw: raw.clone(),
            parsed: parse(raw),
            content_length: self.content_length,
        }
    }
}

/// Parse headers
fn parse(heads: String) -> Vec<Header> {
    let mut res: Vec<Header> = vec![];
    let heads = heads.split(CRLF);
    for h in heads {
        // TODO check it reg
        let reg_name = Regex::new(r"^.+: ").unwrap();
        let capts_name = reg_name.captures(h);
        if let None = capts_name {
            continue;
        }
        let capts_name = capts_name.unwrap();
        let name = capts_name
            .get(0)
            .unwrap()
            .as_str()
            .to_string()
            // FIXME
            .replace(": ", "");

        let reg_value = Regex::new(r": *.*$").unwrap();
        let capts_value = reg_value.captures(h);
        if let None = capts_value {
            res.push(Header {
                name,
                value: "".to_string(),
            });
            continue;
        }
        let capts_value = capts_value.unwrap();
        let value = capts_value
            .get(0)
            .unwrap()
            .as_str()
            .to_string()
            .replace(": ", "");
        res.push(Header { name, value });
    }
    res
}

/// Stringify headers
fn stringify(heads: &Vec<u8>) -> String {
    let s = str::from_utf8(heads);
    match s {
        Ok(val) => val.to_string(),
        Err(err) => {
            println!("Failed to stringify headers: {:?}", err);
            "".to_string()
        }
    }
}

/// For change request headers host to host of target
fn change_host(heads: String, target: &str) -> String {
    let reg = Regex::new(r"Host: *.*\r\n").unwrap();
    let capts = reg.captures(heads.as_str());
    if let None = capts {
        return heads;
    }
    let capts = capts.unwrap();
    let old_host = capts.get(0).unwrap().as_str();
    heads.replace(old_host, format!("Host: {}\r\n", target).as_str())
}

/// Parse content length from request headers
pub fn get_content_length(src: &String) -> Option<usize> {
    let low = Regex::new(r"(c|C)ontent-(l|L)ength:\s*\d+")
        .unwrap()
        .captures(&src);

    #[allow(unused_assignments)]
    let mut check: Option<&str> = None;
    if let Some(v) = low {
        let low = v.get(0).unwrap();
        check = Some(low.as_str());
    }

    if let None = check {
        return None;
    }

    let cont_len = check.unwrap();

    let num = Regex::new(r"\d+").unwrap().captures(cont_len);
    if let None = num {
        return None;
    }
    let capts = num.unwrap();
    let num = capts.get(0);
    let num_str = num.unwrap().as_str();
    let num = num_str.parse::<usize>();
    if let Err(e) = num {
        println!("Failed parse content lenght from str: {}: {}", num_str, e);
        return None;
    }
    Some(num.unwrap())
}