feat: #12 add async block in handlers (more readable) + fix tests

This commit is contained in:
landrigun 2022-10-10 14:59:29 +00:00
parent 53b5c7a65f
commit 71e3db0857
4 changed files with 45 additions and 23 deletions

View File

@ -1,6 +1,5 @@
//! response handles the incoming request parsed `HTTPRequest` //! response handles the incoming request parsed `HTTPRequest`
//! it will check if the `HTTPRequest` is valid and build an HTTPResponse corresponding to the HTTP //! it will build an HTTPResponse corresponding to the HTTP message specs. see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages
//! message specs. see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages
//! NOTE: only few parts of the specification has been implemented //! NOTE: only few parts of the specification has been implemented
use crate::http::request::HTTPVersion; use crate::http::request::HTTPVersion;

View File

@ -12,28 +12,48 @@ use std::pin::Pin;
type FuturePinned<HTTPResponse> = Pin<Box<dyn Future<Output = HTTPResponse>>>; type FuturePinned<HTTPResponse> = Pin<Box<dyn Future<Output = HTTPResponse>>>;
type Handler = fn(HTTPRequest) -> FuturePinned<HTTPResponse>; type Handler = fn(HTTPRequest) -> FuturePinned<HTTPResponse>;
async fn handle_get(request: HTTPRequest) -> HTTPResponse { fn handle_get(request: HTTPRequest) -> FuturePinned<HTTPResponse> {
// TODO: path to `store.txt` must not be hardcoded, should be in a config file and load at runtime Box::pin(async move {
let mut store = FileStore::new("tests/data/store.txt".to_string()); // TODO: path to `store.txt` must not be hardcoded, should be in a config file and load at runtime
match request.body { let mut store = FileStore::new("tests/data/store.txt".to_string());
Some(ref b) => { match &request.body {
let is_auth = store.is_auth(&b.get_data()).await; Some(ref b) => {
if !is_auth { let is_auth = store.is_auth(&b.get_data()).await;
return HTTPResponse::as_403(); if !is_auth {
return HTTPResponse::as_403();
}
HTTPResponse::as_200()
} }
HTTPResponse::as_200() None => HTTPResponse::as_400(),
} }
None => HTTPResponse::as_400(), })
}
} }
fn handle_get_pinned(request: HTTPRequest) -> FuturePinned<HTTPResponse> { /// validates the token by checking:
Box::pin(handle_get(request)) /// * expiration time
fn handle_validate(request: HTTPRequest) -> FuturePinned<HTTPResponse> {
Box::pin(async move {
match &request.body {
Some(ref _b) => {
// TODO: impl the JWT validation
HTTPResponse::as_200()
}
None => HTTPResponse::as_400(),
}
})
} }
lazy_static! { lazy_static! {
/// defines the map between the URL and its associated callback
/// each authorized targets must implement a function returning `FuturePinned<HTTPResponse>`
// TODO: a macro should be implemented to mask the implementation details
static ref HTTP_METHODS: HashMap<&'static str, Handler> = static ref HTTP_METHODS: HashMap<&'static str, Handler> =
HashMap::from([("/get/", handle_get_pinned as Handler),]); HashMap::from(
[
("/get/", handle_get as Handler),
("/validate/", handle_validate as Handler)
]
);
} }
pub struct Router; pub struct Router;

View File

@ -28,7 +28,7 @@ done
for i in {0..10} for i in {0..10}
do do
http_response=$(curl -s -o response.txt -w "%{http_code}" ${URL}/ge/ -d '{"username":"toto", "password":"tutu"}') http_response=$(curl -s -o response.txt -w "%{http_code}" ${URL}/ge/ -d '{"username":"toto", "password":"tutu"}')
if [ $http_response != "400" ] if [ $http_response != "404" ]
then then
echo "bad http status code : ${http_response}, expect 400" echo "bad http status code : ${http_response}, expect 400"
exit 1 exit 1

View File

@ -26,23 +26,26 @@ class TestResponse(TestCase):
resp.json()["token"], "header.payload.signature", "bad status returned" resp.json()["token"], "header.payload.signature", "bad status returned"
) )
# TODO: must be updated after implmenting `/refresh/` url handler
def test_refresh_target(self): def test_refresh_target(self):
resp = requests.post( resp = requests.post(
URL + "/refresh/", json={"username": "toto", "password": "tata"} URL + "/refresh/", json={"username": "toto", "password": "tata"}
) )
self.assertEqual(resp.status_code, 200, "bad status code returned") self.assertEqual(resp.status_code, 404, "bad status code returned")
self.assertIsNotNone(resp.json(), "response data can't be empty") self.assertIsNotNone(resp.json(), "response data can't be empty")
self.assertEqual( self.assertEqual(
resp.json()["token"], "header.payload.signature", "bad status returned" resp.json()["error"],
"the url requested does not exist",
"bad status returned",
) )
def test_no_credentials(self): def test_no_credentials(self):
resp = requests.post(URL + "/get/") resp = requests.post(URL + "/get/")
self.assertEqual(resp.status_code, 403, "bad status code returned") self.assertEqual(resp.status_code, 400, "bad status code returned")
self.assertIsNotNone(resp.json(), "response data must not be empty") self.assertIsNotNone(resp.json(), "response data must not be empty")
self.assertEqual( self.assertEqual(
resp.json()["error"], resp.json()["error"],
"invalid credentials", "the incoming request is not valid",
"invalid error message returned", "invalid error message returned",
) )
@ -62,10 +65,10 @@ class TestResponse(TestCase):
resp = requests.post( resp = requests.post(
URL + "/token/", json={"username": "toto", "password": "tata"} URL + "/token/", json={"username": "toto", "password": "tata"}
) )
self.assertEqual(resp.status_code, 400, "bad status code returned") self.assertEqual(resp.status_code, 404, "bad status code returned")
self.assertIsNotNone(resp.json(), "response data must not be empty") self.assertIsNotNone(resp.json(), "response data must not be empty")
self.assertEqual( self.assertEqual(
resp.json()["error"], resp.json()["error"],
"the incoming request is not valid", "the url requested does not exist",
"invalid error message returned", "invalid error message returned",
) )