AthenaEngine/server/
response_parser.rs

1pub mod response_parser {
2    use std::collections::HashMap;
3    use std::fmt::format;
4    use std::io::Bytes;
5    use chrono::{Datelike, DateTime, Timelike, Utc};
6    use crate::log::{log_text_writer, LogTypeTag};
7    use crate::server::request_parser::request_parser::{http_version_classify_original, HttpVersion, Method, Request};
8    use crate::server::page_manager::page_manager::{PageFileReadInfo, read_page};
9    use crate::server::page_manager::page_manager::IsPageFileReadSuccess;
10
11
12    /// 현재 파일 정보 반환
13    fn get_this_name() -> String {
14        return String::from("main/server/response_parser");
15    }
16
17
18    /// 서버 이름 반환
19    fn get_server_name() -> String { return String::from("Athena-Engine") }
20
21
22    /// Response 데이터
23    pub struct Response {
24        pub is_success: IsResponseDataCreateSuccess,
25        pub response_code: Option<HttpStateCode>,
26        pub http_version: Option<HttpVersion>,
27        pub headers: Option<HashMap<String, String>>,
28        pub cookies: Option<Vec<ResponseCookies>>,
29        pub body: Option<ResponseBody>
30    }
31
32    /// Response 쿠키 데이터
33    pub struct ResponseCookies {
34        pub name : String,
35        pub value : String,
36        pub path : String
37    }
38
39    /// Response body 데이터
40    pub struct ResponseBody {
41        pub body_str: Option<String>
42    }
43
44    /// 페이지 HTML 정보 불러오기 작업 성공 여부 Enum
45    #[derive(PartialEq)]
46    pub enum IsResponseDataCreateSuccess {
47        SUCCESS, FAIL
48    }
49
50    /// HTTP 상태 응답 코드
51    #[derive(PartialEq)]
52    pub enum HttpStateCode {
53        HTTP_110,
54        HTTP_111,
55
56        HTTP_200,
57        HTTP_300,
58        HTTP_301,
59        HTTP_302,
60        HTTP_303,
61        HTTP_304,
62        HTTP_307,
63        HTTP_308,
64        HTTP_310,
65
66        HTTP_400,
67        HTTP_401,
68        HTTP_402,
69        HTTP_403,
70        HTTP_404,
71        HTTP_405,
72        HTTP_406,
73        HTTP_407,
74        HTTP_408,
75        HTTP_409,
76        HTTP_410,
77        HTTP_411,
78        HTTP_412,
79        HTTP_413,
80        HTTP_414,
81        HTTP_415,
82        HTTP_416,
83        HTTP_417,
84        HTTP_418,
85        HTTP_420,
86        HTTP_422,
87        HTTP_423,
88        HTTP_424,
89        HTTP_425,
90        HTTP_426,
91        HTTP_428,
92        HTTP_429,
93        HTTP_431,
94
95        HTTP_500,
96    }
97    
98
99    /// HTTP 상태 변환기
100    pub fn default_http_state_writer(http_code : &HttpStateCode) -> &'static str {
101        return match http_code {
102            HttpStateCode::HTTP_110 => "110 Connection Timed Out",
103            HttpStateCode::HTTP_111 => "111 Connection refused",
104            HttpStateCode::HTTP_200 => "200 OK",
105            HttpStateCode::HTTP_300 => "300 Multiple Choice",
106            HttpStateCode::HTTP_303 => "303 See Other",
107            HttpStateCode::HTTP_304 => "304 Not Modified",
108            HttpStateCode::HTTP_307 => "307 Temporary Redirect",
109            HttpStateCode::HTTP_308 => "308 Permanent Redirect",
110            HttpStateCode::HTTP_301 => "301 Moved Permanently",
111            HttpStateCode::HTTP_302 => "302 Found",
112            HttpStateCode::HTTP_310 => "310 Too many redirects",
113            HttpStateCode::HTTP_400 => "400 Bad Request",
114            HttpStateCode::HTTP_404 => "404 Not Found",
115            HttpStateCode::HTTP_500 => "500 Internal Server Error",
116            HttpStateCode::HTTP_401 => "401 Unauthorized",
117            HttpStateCode::HTTP_402 => "402 Payment Required",
118            HttpStateCode::HTTP_403 => "403 Forbidden",
119            HttpStateCode::HTTP_405 => "405 Method Not Allowed",
120            HttpStateCode::HTTP_406 => "406 Not Acceptable",
121            HttpStateCode::HTTP_407 => "407 Proxy Authentication Required",
122            HttpStateCode::HTTP_408 => "408 Request Timeout",
123            HttpStateCode::HTTP_409 => "409 Conflict",
124            HttpStateCode::HTTP_410 => "410 Gone",
125            HttpStateCode::HTTP_411 => "411 Length Required",
126            HttpStateCode::HTTP_412 => "412 Precondition Failed",
127            HttpStateCode::HTTP_413 => "413 Request Entity Too Large",
128            HttpStateCode::HTTP_414 => "414 Request-URI Too Long",
129            HttpStateCode::HTTP_415 => "415 Unsupported Media Type",
130            HttpStateCode::HTTP_416 => "Requested Range Not Satisfiable",
131            HttpStateCode::HTTP_417 => "Expectation Failed",
132            HttpStateCode::HTTP_418 => "I'm a teapot (RFC 2324)",
133            HttpStateCode::HTTP_420 => "Enhance Your Calm (Twitter)",
134            HttpStateCode::HTTP_422 => "422 Unprocessable Entity (WebDAV)",
135            HttpStateCode::HTTP_423 => "423 Locked (WebDAV)",
136            HttpStateCode::HTTP_424 => "424 Failed Dependency (WebDAV)",
137            HttpStateCode::HTTP_425 => "425 Reserved for WebDAV",
138            HttpStateCode::HTTP_426 => "426 Upgrade Required",
139            HttpStateCode::HTTP_428 => "428 Precondition Required",
140            HttpStateCode::HTTP_429 => "429 Too Many Requests",
141            HttpStateCode::HTTP_431 => "431 Request Header Fields Too Large",
142        };
143    }
144
145
146    /// 기본 응답 Body 생성기
147    pub fn default_body_writer(http_code : &HttpStateCode) -> String {
148        let mut template = String::from("<head><title>#Result#</title><body>#Result#</body></head>");
149        let replace_tag = String::from("#Result#");
150
151        template = template.replace(&replace_tag, default_http_state_writer(http_code));
152
153        return template;
154    }
155
156
157    /// 기본 응답 Header 생성기
158    pub fn default_response_header_writer() -> HashMap<String, String> {
159        let mut header : HashMap<String, String> = HashMap::new();
160
161        // 헤더 데이터 설정 - Date
162        let header_setting_date: DateTime<Utc> = Utc::now();
163        let header_setting_date_month_to_str : &str = match header_setting_date.month() {
164            1 => "Jun",
165            2 => "Feb",
166            3 => "Mar",
167            4 => "Apr",
168            5 => "May",
169            6 => "Jun",
170            7 => "Jul",
171            8 => "Aug",
172            9 => "Sep",
173            10 => "Oct",
174            11 => "Nov",
175            12 => "Dec",
176            _ => "Jun"
177        };
178        header.insert(String::from("Date"),
179                      String::from(format!("{}, {:0>2} {} {} {:0>2}:{:0>2}:{:0>2} GMT",
180                                           header_setting_date.weekday(),
181                                           header_setting_date.day(),
182                                           header_setting_date_month_to_str,
183                                           header_setting_date.year(),
184                                           header_setting_date.hour(),
185                                           header_setting_date.minute(),
186                                           header_setting_date.second())));
187        // 헤더 데이터 설정 - Server
188        header.insert(String::from("Server"), get_server_name());
189        // 헤더 데이터 설정 - Connection
190        header.insert(String::from("Connection"), String::from("close"));
191        // 헤더 데이터 설정 - Connection
192        header.insert(String::from("Pragma"), String::from("no-cache"));
193        // 헤더 데이터 설정 - Content-Type
194        header.insert(String::from("Content-Type"), String::from("text/html; charset=UTF-8"));
195        // 헤더 데이터 설정 - Content-Language
196        header.insert(String::from("Content-Language"), String::from("ko-KR"));
197        // 헤더 데이터 설정 - Access-Control-Allow-Origin
198        header.insert(String::from("Access-Control-Allow-Origin"), String::from("*"));
199
200        return header;
201    }
202
203
204
205    /// HTTP Response 응답 패킷 데이터 생성
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// default_response_writer(&request, None, None)
211    /// ```
212    ///
213    /// # Argument
214    /// request : HTTP 응답 데이터
215    ///
216    /// cookies : 응답 헤더에 추가할 쿠키
217    ///
218    /// input_header : 응답 헤더 추가 작성
219    ///
220    /// # Return
221    /// Response 구조체
222    pub fn default_response_writer(request : &Request, cookies : Option<Vec<ResponseCookies>>, input_header : Option<HashMap<String, String>>) -> Response {
223        // 반환 데이터 초기화
224        let mut response : Response = Response {
225            is_success: IsResponseDataCreateSuccess::SUCCESS,
226            response_code: None,
227            http_version: None,
228            headers: None,
229            cookies: None,
230            body: None
231        };
232
233        // 데이터 생성 - HTTP 응답 코드
234        let mut response_http_version : HttpVersion = HttpVersion::HTTP_1_1;
235        // 데이터 생성 - HTTP 응답 코드
236        let mut response_code : HttpStateCode = HttpStateCode::HTTP_200;
237        // 데이터 생성 - HTTP 응답 Body
238        let mut response_body : ResponseBody = ResponseBody {
239            body_str: None
240        };
241
242        // Method 데이터 추출
243        match &request.method {
244            Some(method) => {
245                // Method 지원 여부 확인
246                if method != &Method::NOT_SUPPORTED {
247                    // 데이터 추출 - HTTP 버전
248                    match &request.http_version {
249                        Some(http_version) => {
250                            // HTTP 버전 지원 여부 확인
251                            if http_version != &HttpVersion::NOT_SUPPORTED {
252                                // 데이터 삽입 - HTTP Version
253                                match &request.http_version {
254                                    None => {}
255                                    Some(version) => {
256                                        response_http_version = match version {
257                                            HttpVersion::HTTP_1_0 => HttpVersion::HTTP_1_0,
258                                            HttpVersion::HTTP_1_1 => HttpVersion::HTTP_1_1,
259                                            HttpVersion::HTTP_2_0 => HttpVersion::HTTP_2_0,
260                                            HttpVersion::NOT_SUPPORTED => HttpVersion::HTTP_1_1
261                                        };
262                                    }
263                                }
264
265                                // 데이터 삽입 - Cookies
266                                response.cookies = cookies;
267
268                                // 요청 페이지 읽기
269                                match &request.target {
270                                    Some(request_page) => {
271                                        let path;
272
273                                        if request_page.contains("?") {
274                                            let mut split: Vec<&str> = request_page.split("?").collect();
275                                            path = String::from(split[0]);
276                                        }else {
277                                            path = String::from(request_page);
278                                        }
279
280                                        // 페이지 정보 불러오기
281                                        let page_read_data : PageFileReadInfo = read_page(String::from(path));
282                                        // 성공 여부 확인
283                                        if page_read_data.is_success == IsPageFileReadSuccess::SUCCESS { // 페이지 읽기 성공
284                                            response_code = HttpStateCode::HTTP_200;
285                                            response_body.body_str = page_read_data.value;
286                                        }else if page_read_data.is_success == IsPageFileReadSuccess::FAIL { // 400 오류 발생
287                                            response_code = HttpStateCode::HTTP_400;
288                                            response_body.body_str = Some(default_body_writer(&response_code));
289                                        }else { // 404 오류 발생
290                                            response_code = HttpStateCode::HTTP_404;
291                                            response_body.body_str = Some(default_body_writer(&response_code))
292                                        }
293                                    },
294                                    None => { // 404 오류 발생
295                                        response_code = HttpStateCode::HTTP_404;
296                                        response_body.body_str = Some(default_body_writer(&response_code));
297                                    }
298                                }
299                            }else { // 426 오류 발생
300                                response.is_success = IsResponseDataCreateSuccess::FAIL;
301                            }
302                        },
303                        None => { // 426 오류 발생
304                            response.is_success = IsResponseDataCreateSuccess::FAIL;
305                        }
306                    };
307                }else { // 426 오류 발생
308                    response.is_success = IsResponseDataCreateSuccess::FAIL;
309                }
310            }
311            None => { // 426 오류 발생
312                response.is_success = IsResponseDataCreateSuccess::FAIL;
313            }
314        }
315
316        // 헤더 데이터 HashMap
317        let mut header : HashMap<String, String> = default_response_header_writer();
318
319        // 헤더 데이터 추가 - Content-Disposition
320        header.insert(String::from("Content-Disposition"), String::from("inline"));
321        // 헤더 데이터 추가 - Cache-Control
322        header.insert(String::from("Cache-Control"), String::from("no-cache"));
323        // Header 추가
324        match input_header {
325            Some(input) => {
326                for (key, value) in input {
327                    // 헤더 데이터 추가
328                    header.insert(key, value);
329                }
330            },
331            None => {}
332        }
333
334        // 헤더 데이터 추가 - Content-Length
335        match &response_body.body_str {
336            Some(body) => {
337                header.insert(String::from("Content-Length"), body.len().to_string());
338                header.insert(String::from("Accept-Ranges"), String::from("bytes"));
339            },
340            None => {
341                header.insert(String::from("Content-Length"), String::from("0"));
342            }
343        };
344
345        // Body 설정
346        response.body = Some(response_body);
347
348        // Response 데이터 설정
349        response.response_code = Some(response_code);
350        response.http_version = Some(response_http_version);
351        response.headers = Some(header);
352
353        // 로그 출력
354        println!("{}", log_text_writer(String::from("Default response packet creation succeeded."), get_this_name(), LogTypeTag::INFO));
355
356        // 데이터 반환
357        return response;
358    }
359
360
361    /// 응답 Struct 를 String 형식으로 변환
362    pub fn response_parser(response : Response) -> String {
363        // 기본 Response
364        let default_response = String::from("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nDate: Wed, 14 Dec 2022 00:25:57 GMT\r\nAccess-Control-Allow-Origin: *\r\nContent-Disposition: inline\r\nContent-Language: ko-KR");
365        // Response 생성
366        let mut response_str = String::new();
367        if response.is_success == IsResponseDataCreateSuccess::SUCCESS {
368            match &response.http_version {
369                Some(http_version) => {
370                    match &response.response_code {
371                        Some(response_code) => {
372                            match &response.headers {
373                                Some(response_header) => {
374                                    let mut header : String = String::new();
375                                    for (response_header_key, response_header_value) in response_header {
376                                        let line : String = format!("{}: {}\r\n", response_header_key, response_header_value);
377                                        header.push_str(&line);
378                                    }
379
380                                    // 쿠키 설정
381                                    match &response.cookies {
382                                        Some(cookies) => {
383                                            for cookie in cookies {
384                                                let line = String::from(format!("Set-Cookie: {}={}; Path={}\r\n", cookie.name, cookie.value, cookie.path));
385                                                header.push_str(&line);
386                                            }
387                                        },
388                                        None => {}
389                                    }
390
391                                    response_str = response_format(http_version, response_code, header, response.body);
392                                }
393                                None => {
394                                    return default_response;
395                                }
396                            }
397                        },
398                        None => {
399                            return default_response;
400                        }
401                    }
402                },
403                None => {
404                    return default_response;
405                }
406            }
407        }else {
408            return default_response;
409        }
410
411        // 데이터 반환
412        return response_str;
413    }
414
415
416    /// Response 문자열 형식으로 변환
417    fn response_format(http_version : &HttpVersion, response_code : &HttpStateCode, header_str : String, body : Option<ResponseBody>) -> String {
418        return match body {
419            Some(body) => {
420                match &body.body_str {
421                    Some(body) => {
422                        String::from(
423                            format!("{} {}\r\n{}\r\n{}",
424                                    http_version_classify_original(http_version),
425                                    default_http_state_writer(response_code),
426                                    header_str,
427                                    body))
428                    },
429                    None => {
430                        String::from(
431                            format!("{} {}\r\n{}",
432                                    http_version_classify_original(http_version),
433                                    default_http_state_writer(response_code),
434                                    header_str))
435                    }
436                }
437            }
438            None => {
439                String::from(
440                    format!("{} {}\r\n{}",
441                            http_version_classify_original(http_version),
442                            default_http_state_writer(response_code),
443                            header_str))
444            }
445        }
446    }
447}