feat: #2 impl an HTTPResponse + update tests
This commit is contained in:
parent
35cc483774
commit
2c7418f333
@ -1,3 +1,5 @@
|
|||||||
pub mod request;
|
pub mod request;
|
||||||
|
pub mod response;
|
||||||
|
|
||||||
pub use request::handle_request;
|
pub use request::handle_request;
|
||||||
|
pub use response::HTTPResponse;
|
||||||
|
|||||||
98
src/handlers/response.rs
Normal file
98
src/handlers/response.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
//! response handles the incoming request parsed `HTTPRequest`
|
||||||
|
//! it will check if the `HTTPRequest` is valid and build an HTTPResponse corresponding to the HTTP
|
||||||
|
//! message specs. see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages
|
||||||
|
//! NOTE: only few parts of the specification has been implemented
|
||||||
|
|
||||||
|
use json;
|
||||||
|
|
||||||
|
use crate::handlers::request::{HTTPRequest, HTTPVersion};
|
||||||
|
|
||||||
|
enum HTTPStatusCode {
|
||||||
|
Http200,
|
||||||
|
Http400,
|
||||||
|
Http404,
|
||||||
|
Http500,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<String> for HTTPStatusCode {
|
||||||
|
fn into(self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Http200 => "200".to_string(),
|
||||||
|
Self::Http400 => "400".to_string(),
|
||||||
|
Self::Http404 => "404".to_string(),
|
||||||
|
Self::Http500 => "500".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HTTPStatusLine {
|
||||||
|
version: HTTPVersion,
|
||||||
|
status_code: HTTPStatusCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HTTPStatusLine {
|
||||||
|
fn default() -> HTTPStatusLine {
|
||||||
|
HTTPStatusLine {
|
||||||
|
version: HTTPVersion::Http1_1,
|
||||||
|
status_code: HTTPStatusCode::Http400,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<String> for HTTPStatusLine {
|
||||||
|
fn into(self) -> String {
|
||||||
|
let version: String = self.version.into();
|
||||||
|
let status_code: String = self.status_code.into();
|
||||||
|
format! {"{} {}", version, status_code}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HTTPResponse {
|
||||||
|
status_line: HTTPStatusLine,
|
||||||
|
body: json::JsonValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HTTPResponse {
|
||||||
|
fn default() -> Self {
|
||||||
|
HTTPResponse {
|
||||||
|
status_line: HTTPStatusLine::default(),
|
||||||
|
body: json::parse(r#"{"error": "the incoming request is not valid"}"#).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<HTTPRequest> for HTTPResponse {
|
||||||
|
fn from(request: HTTPRequest) -> Self {
|
||||||
|
let mut response = HTTPResponse::default();
|
||||||
|
if !request.is_valid() {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = json::parse(
|
||||||
|
r#"{"token": "header.payload.signature", "refresh": "header.payload.signature"}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
response.status_line.version = request.start_line.version;
|
||||||
|
response.status_line.status_code = HTTPStatusCode::Http200;
|
||||||
|
response.body = body;
|
||||||
|
|
||||||
|
response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<String> for HTTPResponse {
|
||||||
|
fn into(self) -> String {
|
||||||
|
// move `self.body` into a new var
|
||||||
|
let b = self.body;
|
||||||
|
let body: String = json::stringify(b);
|
||||||
|
|
||||||
|
let status_line: String = self.status_line.into();
|
||||||
|
format!(
|
||||||
|
"{}\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
|
||||||
|
status_line,
|
||||||
|
body.len(),
|
||||||
|
body
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/main.rs
21
src/main.rs
@ -1,13 +1,11 @@
|
|||||||
mod handlers;
|
mod handlers;
|
||||||
|
|
||||||
use std::io::prelude::*;
|
|
||||||
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
net::{TcpListener, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
};
|
};
|
||||||
|
|
||||||
use handlers::handle_request;
|
use handlers::{handle_request, HTTPResponse};
|
||||||
|
|
||||||
const SERVER_URL: &str = "127.0.0.1:9000";
|
const SERVER_URL: &str = "127.0.0.1:9000";
|
||||||
|
|
||||||
@ -29,20 +27,9 @@ async fn handle_connection(mut stream: TcpStream) {
|
|||||||
let request_string = std::str::from_utf8(&buffer[0..n]).unwrap();
|
let request_string = std::str::from_utf8(&buffer[0..n]).unwrap();
|
||||||
let request = handle_request(request_string);
|
let request = handle_request(request_string);
|
||||||
|
|
||||||
if request.is_valid() {
|
let response = HTTPResponse::from(request);
|
||||||
let contents = "{\"status\": \"ok\"}";
|
let response_str: String = response.into();
|
||||||
let response = format!(
|
|
||||||
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
|
|
||||||
contents.len(),
|
|
||||||
contents
|
|
||||||
);
|
|
||||||
|
|
||||||
stream.write(response.as_bytes()).await.unwrap();
|
stream.write(response_str.as_bytes()).await.unwrap();
|
||||||
stream.flush().await.unwrap();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = "HTTP/1.1 400 OK\r\n\r\n".to_string();
|
|
||||||
stream.write(response.as_bytes()).await.unwrap();
|
|
||||||
stream.flush().await.unwrap();
|
stream.flush().await.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,8 @@ do
|
|||||||
echo "bad http status code : ${http_response}, expect 200"
|
echo "bad http status code : ${http_response}, expect 200"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $(cat response.txt | jq -r '.[]') != "ok" ]
|
if [ "$(cat response.txt | jq -r '.token')" != "header.payload.signature" ]
|
||||||
then
|
then
|
||||||
echo "bad data returned, expect : ok"
|
echo "bad data returned, expect : ok"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@ -12,7 +12,6 @@ platformdirs==2.5.2
|
|||||||
pluggy==1.0.0
|
pluggy==1.0.0
|
||||||
py==1.11.0
|
py==1.11.0
|
||||||
pyparsing==3.0.9
|
pyparsing==3.0.9
|
||||||
pytest==7.1.3
|
|
||||||
requests==2.28.1
|
requests==2.28.1
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
urllib3==1.26.12
|
urllib3==1.26.12
|
||||||
|
|||||||
@ -1,34 +1,49 @@
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
URL = "https://dev.thegux.fr"
|
URL = "https://dev.thegux.fr"
|
||||||
|
|
||||||
|
|
||||||
def test_get_target():
|
class TestResponse(TestCase):
|
||||||
resp = requests.post(URL + "/get/", json={"username": "toto", "password": "tata"})
|
def test_get_target(self):
|
||||||
assert resp.status_code == 200, "bad status code returned"
|
resp = requests.post(
|
||||||
assert resp.json() is not None, "response data can't be empty"
|
URL + "/get/", json={"username": "toto", "password": "tata"}
|
||||||
assert resp.json()["status"] == "ok", "bad status returned"
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200, "bad status code returned")
|
||||||
|
self.assertIsNotNone(resp.json(), "response data can't be empty")
|
||||||
|
self.assertEqual(
|
||||||
|
resp.json()["token"], "header.payload.signature", "bad status returned"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_validate_target(self):
|
||||||
|
resp = requests.post(
|
||||||
|
URL + "/validate/", json={"username": "toto", "password": "tata"}
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200, "bad status code returned")
|
||||||
|
self.assertIsNotNone(resp.json(), "response data can't be empty")
|
||||||
|
self.assertEqual(
|
||||||
|
resp.json()["token"], "header.payload.signature", "bad status returned"
|
||||||
|
)
|
||||||
|
|
||||||
def test_validate_target():
|
def test_refresh_target(self):
|
||||||
resp = requests.post(
|
resp = requests.post(
|
||||||
URL + "/validate/", json={"username": "toto", "password": "tata"}
|
URL + "/refresh/", json={"username": "toto", "password": "tata"}
|
||||||
)
|
)
|
||||||
assert resp.status_code == 200, "bad status code returned"
|
self.assertEqual(resp.status_code, 200, "bad status code returned")
|
||||||
assert resp.json() is not None, "response data can't be empty"
|
self.assertIsNotNone(resp.json(), "response data can't be empty")
|
||||||
assert resp.json()["status"] == "ok", "bad status returned"
|
self.assertEqual(
|
||||||
|
resp.json()["token"], "header.payload.signature", "bad status returned"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_bad_target(self):
|
||||||
def test_refresh_target():
|
resp = requests.post(
|
||||||
resp = requests.post(
|
URL + "/token/", json={"username": "toto", "password": "tata"}
|
||||||
URL + "/refresh/", json={"username": "toto", "password": "tata"}
|
)
|
||||||
)
|
self.assertEqual(resp.status_code, 400, "bad status code returned")
|
||||||
assert resp.status_code == 200, "bad status code returned"
|
self.assertIsNotNone(resp.json(), "response data must not be empty")
|
||||||
assert resp.json() is not None, "response data can't be empty"
|
self.assertEqual(
|
||||||
assert resp.json()["status"] == "ok", "bad status returned"
|
resp.json()["error"],
|
||||||
|
"the incoming request is not valid",
|
||||||
|
"invalid error message returned",
|
||||||
def test_bad_target():
|
)
|
||||||
resp = requests.post(URL + "/token/", json={"username": "toto", "password": "tata"})
|
|
||||||
assert resp.status_code == 400, "bad status code returned"
|
|
||||||
assert resp.text == "", "response data must be empty"
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user