Skip to main content

arara_cgi/
request.rs

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}