http_type/response/
impl.rs

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
use super::{error::Error, r#type::Response};
use crate::StatusCode;
use http_constant::*;
use std::{borrow::Cow, collections::HashMap, io::Write, net::TcpStream};

impl Default for Response {
    fn default() -> Self {
        Self::new()
    }
}

impl Response {
    /// Creates a new instance of `Response`.
    ///
    /// # Returns
    /// - An initialized `Response` with default values.
    pub fn new() -> Self {
        Response {
            version: Cow::Borrowed(HTTP_VERSION_1_1),
            status_code: 200,
            reason_phrase: Cow::Borrowed(OK),
            headers: HashMap::new(),
            body: Vec::new(),
            response: Vec::new(),
        }
    }

    /// Sets the HTTP version for the response.
    ///
    /// # Parameters
    /// - `version`: The HTTP version to set (e.g., HTTP/1.1).
    ///
    /// # Returns
    /// - A mutable reference to the `Response` for chaining.
    pub fn version<S: Into<Cow<'static, str>>>(&mut self, version: S) -> &mut Self {
        self.version = version.into();
        self
    }

    /// Sets the HTTP status code for the response.
    ///
    /// # Parameters
    /// - `code`: The status code to set (e.g., 404).
    ///
    /// # Returns
    /// - A mutable reference to the `Response` for chaining.
    pub fn status_code(&mut self, code: usize) -> &mut Self {
        self.status_code = code;
        self.reason_phrase(StatusCode::phrase(code));
        self
    }

    /// Sets the reason phrase for the response.
    ///
    /// # Parameters
    /// - `phrase`: The reason phrase to set (e.g., Not Found).
    ///
    /// # Returns
    /// - A mutable reference to the `Response` for chaining.
    pub fn reason_phrase<S: Into<Cow<'static, str>>>(&mut self, phrase: S) -> &mut Self {
        self.reason_phrase = phrase.into();
        self
    }

    /// Adds a header to the response.
    ///
    /// # Parameters
    /// - `key`: The name of the header.
    /// - `value`: The value of the header.
    ///
    /// # Returns
    /// - A mutable reference to the `Response` for chaining.
    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
    where
        K: Into<Cow<'static, str>>,
        V: Into<Cow<'static, str>>,
    {
        self.headers.insert(key.into(), value.into());
        self
    }

    /// Sets the body of the response.
    ///
    /// # Parameters
    /// - `body`: The body content as a byte vector.
    ///
    /// # Returns
    /// - A mutable reference to the `Response` for chaining.
    pub fn body<B: Into<Vec<u8>>>(&mut self, body: B) -> &mut Self {
        self.body = body.into();
        self
    }

    /// Builds the full HTTP response as a byte vector.
    ///
    /// # Returns
    /// - The serialized HTTP response including headers and body.
    pub fn build(&mut self) -> Vec<u8> {
        let mut response_str: String = String::new();
        response_str.push_str(&format!(
            "{}{}{}{}{}{}",
            self.version, SPACE, self.status_code, SPACE, self.reason_phrase, HTTP_BR
        ));
        for (key, value) in &self.headers {
            response_str.push_str(&format!("{}{}{}{}", key, COLON_SPACE, value, HTTP_BR));
        }
        response_str.push_str(HTTP_BR);
        let mut response_bytes: Vec<u8> = response_str.into_bytes();
        response_bytes.extend_from_slice(&self.body);
        self.response = response_bytes.clone();
        response_bytes
    }

    /// Sends the HTTP response over a TCP stream.
    ///
    /// # Parameters
    /// - `stream`: A mutable reference to the `TcpStream` to send the response.
    ///
    /// # Returns
    /// - `Ok`: If the response is successfully sent.
    /// - `Err`: If an error occurs during sending.
    pub fn send(&mut self, mut stream: &TcpStream) -> Result<(), Error> {
        if self.response.is_empty() {
            self.response = self.build();
        }
        stream
            .write_all(&self.response)
            .map_err(|err| Error::ResponseError(err.to_string()))
            .and_then(|_| Ok(()))
    }
}