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 fn get_this_name() -> String {
14 return String::from("main/server/response_parser");
15 }
16
17
18 fn get_server_name() -> String { return String::from("Athena-Engine") }
20
21
22 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 pub struct ResponseCookies {
34 pub name : String,
35 pub value : String,
36 pub path : String
37 }
38
39 pub struct ResponseBody {
41 pub body_str: Option<String>
42 }
43
44 #[derive(PartialEq)]
46 pub enum IsResponseDataCreateSuccess {
47 SUCCESS, FAIL
48 }
49
50 #[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 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 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 pub fn default_response_header_writer() -> HashMap<String, String> {
159 let mut header : HashMap<String, String> = HashMap::new();
160
161 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 header.insert(String::from("Server"), get_server_name());
189 header.insert(String::from("Connection"), String::from("close"));
191 header.insert(String::from("Pragma"), String::from("no-cache"));
193 header.insert(String::from("Content-Type"), String::from("text/html; charset=UTF-8"));
195 header.insert(String::from("Content-Language"), String::from("ko-KR"));
197 header.insert(String::from("Access-Control-Allow-Origin"), String::from("*"));
199
200 return header;
201 }
202
203
204
205 pub fn default_response_writer(request : &Request, cookies : Option<Vec<ResponseCookies>>, input_header : Option<HashMap<String, String>>) -> Response {
223 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 let mut response_http_version : HttpVersion = HttpVersion::HTTP_1_1;
235 let mut response_code : HttpStateCode = HttpStateCode::HTTP_200;
237 let mut response_body : ResponseBody = ResponseBody {
239 body_str: None
240 };
241
242 match &request.method {
244 Some(method) => {
245 if method != &Method::NOT_SUPPORTED {
247 match &request.http_version {
249 Some(http_version) => {
250 if http_version != &HttpVersion::NOT_SUPPORTED {
252 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 response.cookies = cookies;
267
268 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 let page_read_data : PageFileReadInfo = read_page(String::from(path));
282 if page_read_data.is_success == IsPageFileReadSuccess::SUCCESS { response_code = HttpStateCode::HTTP_200;
285 response_body.body_str = page_read_data.value;
286 }else if page_read_data.is_success == IsPageFileReadSuccess::FAIL { response_code = HttpStateCode::HTTP_400;
288 response_body.body_str = Some(default_body_writer(&response_code));
289 }else { response_code = HttpStateCode::HTTP_404;
291 response_body.body_str = Some(default_body_writer(&response_code))
292 }
293 },
294 None => { response_code = HttpStateCode::HTTP_404;
296 response_body.body_str = Some(default_body_writer(&response_code));
297 }
298 }
299 }else { response.is_success = IsResponseDataCreateSuccess::FAIL;
301 }
302 },
303 None => { response.is_success = IsResponseDataCreateSuccess::FAIL;
305 }
306 };
307 }else { response.is_success = IsResponseDataCreateSuccess::FAIL;
309 }
310 }
311 None => { response.is_success = IsResponseDataCreateSuccess::FAIL;
313 }
314 }
315
316 let mut header : HashMap<String, String> = default_response_header_writer();
318
319 header.insert(String::from("Content-Disposition"), String::from("inline"));
321 header.insert(String::from("Cache-Control"), String::from("no-cache"));
323 match input_header {
325 Some(input) => {
326 for (key, value) in input {
327 header.insert(key, value);
329 }
330 },
331 None => {}
332 }
333
334 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 response.body = Some(response_body);
347
348 response.response_code = Some(response_code);
350 response.http_version = Some(response_http_version);
351 response.headers = Some(header);
352
353 println!("{}", log_text_writer(String::from("Default response packet creation succeeded."), get_this_name(), LogTypeTag::INFO));
355
356 return response;
358 }
359
360
361 pub fn response_parser(response : Response) -> String {
363 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 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 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 return response_str;
413 }
414
415
416 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}