//! router aims to handle correctly the request corresponding to the target //! it implements all the logic to build an `HTTPResponse` use super::{HTTPRequest, HTTPResponse, HTTPStatusCode}; use crate::stores::FileStore; use crate::stores::Store; use lazy_static::lazy_static; use std::collections::HashMap; use std::future::Future; use std::pin::Pin; type FuturePinned = Pin>>; type Handler = fn(HTTPRequest) -> FuturePinned; fn handle_get(request: HTTPRequest) -> FuturePinned { Box::pin(async move { // TODO: path to `store.txt` must not be hardcoded, should be in a config file and load at runtime let mut store = FileStore::new("tests/data/store.txt".to_string()); match &request.body { Some(ref b) => { let is_auth = store.is_auth(&b.get_data()).await; if !is_auth { return HTTPResponse::as_403(); } HTTPResponse::as_200() } None => HTTPResponse::as_400(), } }) } /// validates the token by checking: /// * expiration time fn handle_validate(request: HTTPRequest) -> FuturePinned { Box::pin(async move { match &request.body { Some(ref _b) => { // TODO: impl the JWT validation HTTPResponse::as_200() } None => HTTPResponse::as_400(), } }) } lazy_static! { /// defines the map between the URL and its associated callback /// each authorized targets must implement a function returning `FuturePinned` // TODO: a macro should be implemented to mask the implementation details static ref HTTP_METHODS: HashMap<&'static str, Handler> = HashMap::from( [ ("/get/", handle_get as Handler), ("/validate/", handle_validate as Handler) ] ); } pub struct Router; impl Router { pub async fn route(&self, request_str: &str) -> HTTPResponse { let request = HTTPRequest::from(request_str); let target = request.start_line.get_target(); match HTTP_METHODS.get(target.as_str()) { Some(f) => f(request).await, None => HTTPResponse::as_404(), } } } // this MUST be used like a Singleton pub const ROUTER: Router = Router {}; #[tokio::test] async fn test_route() { let router: &Router = &ROUTER; let request_str = "POST /get/ HTTP/1.1\r\n\r\n"; let response: HTTPResponse = router.route(request_str).await; assert_eq!( HTTPStatusCode::Http400, response.status_line.get_status_code() ); }