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
132
133
134
135
use std::collections::HashMap;
type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
#[derive(Debug)]
pub struct GetRequest {
    pub path: String,
    pub parameters: HashMap<String, Vec<String>>,
}

#[derive(Debug)]
pub struct PostRequest {
    pub path: String,
    pub bytes: Vec<u8>,
}

#[derive(Debug)]
pub enum Request {
    Get(GetRequest),
    Post(PostRequest),
}

impl Request {
    pub async fn from_lambda(req: netlify_lambda_http::Request) -> Result<Request, Error> {
        match req.method() {
            &http::Method::GET => Ok(Request::Get(utils::get_request_to_raw(&req))),
            &http::Method::POST => match utils::post_request_to_raw(req) {
                Ok(post) => Ok(Request::Post(post)),
                Err(err) => Err(Box::new(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    err,
                ))),
            },
            _ => {
                println!("Unmatched request type");
                Err(Box::new(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    "Unmatched request type!",
                )))
            }
        }
    }

    pub async fn from_hyper(req: hyper::Request<hyper::Body>) -> Result<Request, Error> {
        match req.method() {
            &http::Method::GET => {
                let path = req.uri().path().to_owned();

                let parameters = match req.uri().query() {
                    Some(parameters) => {
                        let parameters: HashMap<String, String> =
                            url::form_urlencoded::parse(parameters.as_bytes())
                                .into_owned()
                                .collect();
                        let parameters: HashMap<String, Vec<String>> =
                            parameters.into_iter().map(|(k, v)| (k, vec![v])).collect();
                        parameters
                    }
                    None => HashMap::new(),
                };

                Ok(Request::Get(GetRequest { path, parameters }))
            }
            &http::Method::POST => {
                let path = req.uri().path().to_owned();
                let bytes = hyper::body::to_bytes(req.into_body())
                    .await
                    .unwrap()
                    .to_vec();

                Ok(Request::Post(PostRequest { path, bytes }))
            }
            _ => Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                "Other method types are not supported",
            ))),
        }
    }
}

mod utils {
    use super::*;

    pub fn query_to_hashmap(query: &netlify_lambda_http::StrMap) -> HashMap<String, Vec<String>> {
        let mut hash = HashMap::new();
        for item in query.iter() {
            if let Some(values) = query.get_all(item.0) {
                hash.insert(
                    item.0.to_string(),
                    values.iter().map(|x| x.to_string()).collect(),
                );
            } else {
                hash.insert(item.0.to_string(), vec![]);
            }
        }

        hash
    }

    pub fn body_to_bytes(req: netlify_lambda_http::Request) -> Result<Vec<u8>, &'static str> {
        use aws_lambda_events::encodings::Body;
        let request = match req.into_body() {
            Body::Binary(v) => Ok(v),
            Body::Text(s) => Ok(s.into_bytes()),
            _ => Err("not found"),
        };
        request
    }

    pub fn request_to_path(request: &netlify_lambda_http::Request) -> String {
        let uri = request.uri();
        let path = uri.path();
        path.to_owned()
    }

    pub fn get_request_to_raw(request: &netlify_lambda_http::Request) -> GetRequest {
        use netlify_lambda_http::ext::RequestExt;
        GetRequest {
            path: request_to_path(&request),
            parameters: query_to_hashmap(&request.query_string_parameters()),
        }
    }

    pub fn post_request_to_raw(
        request: netlify_lambda_http::Request,
    ) -> Result<PostRequest, &'static str> {
        let path = request_to_path(&request);
        let bytes = match body_to_bytes(request) {
            Ok(bytes) => bytes,
            Err(err) => {
                return Err(err);
            }
        };
        let request = PostRequest { path, bytes };
        Ok(request)
    }
}