1use std::collections::HashMap;
2use std::env;
3use std::io::{self, Read};
4
5use crate::error::{CgiError, CgiErrorKind};
6
7pub enum Method {
8 GET,
9 HEAD,
10 OPTIONS,
11 TRACE,
12 PUT,
13 DELETE,
14 POST,
15 PATCH,
16 CONNECT,
17
18 OTHER(&'static str)
19}
20
21pub struct Request {
22 pub method: Method,
23 pub path: &'static str,
24 pub body: Option<String>,
25 pub headers: HashMap<String, String>
26}
27
28
29pub fn new_request() -> Result<Request, CgiError> {
30 let method = {
31 let method_str = env::var("REQUEST_METHOD");
32 if method_str.is_err() {
33 return Err(CgiError::new("REQUEST_METHOD enviroment variable was not found", CgiErrorKind::RequestMethodNodFound))
34 }
35
36 match method_str.unwrap().leak() as &'static str {
37 "GET" => Method::GET,
38 "HEAD" => Method::HEAD,
39 "OPTIONS" => Method::OPTIONS,
40 "TRACE" => Method::TRACE,
41 "PUT" => Method::PUT,
42 "DELETE" => Method::DELETE,
43 "POST" => Method::POST,
44 "PATCH" => Method::PATCH,
45 "CONNECT" => Method::CONNECT,
46
47 other => {
48 if other.is_empty() {
49 return Err(CgiError::new("method is empty", CgiErrorKind::EmptyContent))
50 } else {
51 Method::OTHER(other)
52 }
53 }
54 }
55 };
56
57 let path = env::var("PATH_INFO");
58 if path.is_err() {
59 return Err(CgiError::new("PATH_INFO enviroment variable was not found", CgiErrorKind::PathInfoNotFound));
60 }
61 let path = path.unwrap().leak();
62 if path.is_empty() {
63 return Err(CgiError::new("path is empty", CgiErrorKind::EmptyContent))
64 }
65
66 let body_len_str = env::var("CONTENT_LENGTH");
67 let body_len: u64;
68 match body_len_str {
69 Ok(body_len_str) => {
70 body_len = body_len_str.parse().unwrap();
71 }
72
73 Err(_) => return Err(CgiError::new("CONTENT_LENGTH enviroment variable was not found", CgiErrorKind::ContentLengthNotFound))
74 }
75
76 let body = {
77 let mut body_buffer = String::new();
78 let io_result = io::stdin()
79 .take(body_len)
80 .read_to_string(&mut body_buffer);
81
82 if io_result.is_err() {
83 return Err(CgiError::new("failed to read body input", CgiErrorKind::InputBodyFail))
84 }
85 drop(io_result);
86
87 if body_buffer.is_empty() {
88 None
89 } else {
90 Some(body_buffer)
91 }
92 };
93
94 let mut headers = HashMap::new();
95 for (key, value) in env::vars() {
96 if key.starts_with("HTTP_") && key.len() >= 5 {
97 headers.insert(key, value);
98 }
99 }
100
101 Ok(Request {
102 method: method,
103 path: path,
104 body: body,
105 headers: headers
106 })
107}