Merge branch 'feature/improve-tcpstream' into develop
This commit is contained in:
commit
776b5094ee
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
/target
|
||||
simple-auth
|
||||
*.swp
|
||||
|
||||
tests/python/__pycache__
|
||||
tests/bash/response.txt
|
||||
|
||||
188
Cargo.lock
generated
188
Cargo.lock
generated
@ -135,6 +135,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.2.0"
|
||||
@ -155,6 +161,12 @@ version = "3.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
||||
|
||||
[[package]]
|
||||
name = "cache-padded"
|
||||
version = "1.2.0"
|
||||
@ -265,6 +277,15 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@ -310,6 +331,16 @@ version = "0.2.132"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
@ -326,6 +357,28 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.14.0"
|
||||
@ -338,6 +391,29 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
@ -382,6 +458,15 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
@ -399,6 +484,21 @@ version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple-auth"
|
||||
version = "0.1.0"
|
||||
@ -407,6 +507,7 @@ dependencies = [
|
||||
"json",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -418,6 +519,12 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.7"
|
||||
@ -439,6 +546,38 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.3"
|
||||
@ -467,6 +606,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.82"
|
||||
@ -573,3 +718,46 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
@ -9,6 +9,7 @@ edition = "2021"
|
||||
json = "0.12.4"
|
||||
lazy_static = "1.4.0"
|
||||
regex = "1"
|
||||
tokio = { version = "1.21.1", features = ["full"] }
|
||||
|
||||
[dependencies.async-std]
|
||||
version = "1.6"
|
||||
|
||||
@ -18,12 +18,13 @@ const HTTP_METHODS: [&'static str; 1] = ["POST"];
|
||||
const HTTP_TARGETS: [&'static str; 3] = ["/validate/", "/get/", "/refresh/"];
|
||||
|
||||
lazy_static! {
|
||||
static ref HTTP_VERSION_REGEX: Regex = Regex::new("^HTTP/(1.1|2)$").unwrap();
|
||||
static ref HTTP_VERSION_REGEX: Regex = Regex::new("^HTTP/(1.1|1.0|2)$").unwrap();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HTTPVersion {
|
||||
Http1,
|
||||
Http1_0,
|
||||
Http1_1,
|
||||
Http2,
|
||||
Unknown,
|
||||
}
|
||||
@ -31,7 +32,8 @@ pub enum HTTPVersion {
|
||||
impl Into<String> for HTTPVersion {
|
||||
fn into(self) -> String {
|
||||
match self {
|
||||
Self::Http1 => "HTTP/1.1".to_string(),
|
||||
Self::Http1_0 => "HTTP/1.0".to_string(),
|
||||
Self::Http1_1 => "HTTP/1.1".to_string(),
|
||||
Self::Http2 => "HTTP/2".to_string(),
|
||||
Self::Unknown => "UNKNOWN".to_string(),
|
||||
}
|
||||
@ -42,7 +44,8 @@ impl Into<String> for HTTPVersion {
|
||||
impl From<&String> for HTTPVersion {
|
||||
fn from(http_version: &String) -> Self {
|
||||
match http_version.as_str() {
|
||||
"HTTP/1.1" => Self::Http1,
|
||||
"HTTP/1.0" => Self::Http1_0,
|
||||
"HTTP/1.1" => Self::Http1_1,
|
||||
"HTTP/2" => Self::Http2,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
@ -85,7 +88,6 @@ impl HTTPStartLine {
|
||||
if !Self::check_target(&target) {
|
||||
return Err("target validation failed, unvalid target");
|
||||
}
|
||||
|
||||
if !Self::check_version(&version) {
|
||||
return Err("http version validation failed, unknown version");
|
||||
}
|
||||
@ -122,7 +124,7 @@ impl HTTPStartLine {
|
||||
HTTP_VERSION_REGEX.is_match(version)
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
pub fn is_valid(&self) -> bool {
|
||||
return self.method != "" && self.target != "";
|
||||
}
|
||||
}
|
||||
@ -234,7 +236,7 @@ impl HTTPRequest {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
pub fn is_valid(&self) -> bool {
|
||||
return self.start_line.is_valid();
|
||||
}
|
||||
}
|
||||
@ -272,7 +274,7 @@ fn test_handle_request() {
|
||||
is_valid: bool,
|
||||
}
|
||||
|
||||
let test_cases: [(String, Expect); 10] = [
|
||||
let test_cases: [(String, Expect); 11] = [
|
||||
(
|
||||
"POST /get/ HTTP/1.1\r\n\r\n".to_string(),
|
||||
Expect {
|
||||
@ -289,6 +291,14 @@ fn test_handle_request() {
|
||||
is_valid: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
"POST /validate/ HTTP/1.0\r\n\r\n".to_string(),
|
||||
Expect {
|
||||
start_line: "POST /validate/ HTTP/1.0".to_string(),
|
||||
body: None,
|
||||
is_valid: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
"GET / HTTP/1.1\r\n\r\n".to_string(),
|
||||
Expect {
|
||||
|
||||
54
src/main.rs
54
src/main.rs
@ -1,45 +1,47 @@
|
||||
mod handlers;
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::net::TcpListener;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::{TcpListener, TcpStream},
|
||||
};
|
||||
|
||||
use handlers::handle_request;
|
||||
|
||||
// TODO: must be set in a conf file
|
||||
const SERVER_URL: &str = "127.0.0.1:9000";
|
||||
|
||||
// switch to an asynchronous main function
|
||||
#[async_std::main]
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let listener = TcpListener::bind(SERVER_URL).unwrap();
|
||||
println!("server is listening at {}", SERVER_URL);
|
||||
for stream in listener.incoming() {
|
||||
let stream = stream.unwrap();
|
||||
let listener = TcpListener::bind(SERVER_URL).await.unwrap();
|
||||
|
||||
loop {
|
||||
let (stream, _) = listener.accept().await.unwrap();
|
||||
handle_connection(stream).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_connection(mut stream: TcpStream) {
|
||||
let mut buffer = [0; 1024];
|
||||
stream.read(&mut buffer).unwrap();
|
||||
let mut buffer: [u8; 1024] = [0; 1024];
|
||||
let n = stream.read(&mut buffer).await.unwrap();
|
||||
|
||||
// transform buffer bytes array into `String`
|
||||
let buffer_string = String::from_utf8_lossy(&buffer);
|
||||
let request = handle_request(&buffer_string);
|
||||
let request_string = std::str::from_utf8(&buffer[0..n]).unwrap();
|
||||
let request = handle_request(request_string);
|
||||
|
||||
// TODO: `Response` struct must be implemented
|
||||
let status_line = if request.start_line.target == "/".to_string() {
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
} else {
|
||||
"HTTP/1.1 404 NOT FOUND\r\n"
|
||||
};
|
||||
if request.is_valid() {
|
||||
let contents = "{\"status\": \"ok\"}";
|
||||
let response = format!(
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
|
||||
contents.len(),
|
||||
contents
|
||||
);
|
||||
|
||||
let content_type = "Content-Type: application/json\r\n\r\n";
|
||||
let json = r#"{"access_token":"AAAAAAAAAAAA.BBBBBBBBBB.CCCCCCCCCC","refresh_token": "DDDDDDDDDDD.EEEEEEEEEEE.FFFFF"}"#;
|
||||
let response = format!("{status_line}{content_type}{json}\n");
|
||||
stream.write(response.as_bytes()).await.unwrap();
|
||||
stream.flush().await.unwrap();
|
||||
return;
|
||||
}
|
||||
|
||||
println!("return status code : {}", status_line);
|
||||
stream.write(response.as_bytes()).unwrap();
|
||||
stream.flush().unwrap();
|
||||
let response = "HTTP/1.1 400 OK\r\n\r\n".to_string();
|
||||
stream.write(response.as_bytes()).await.unwrap();
|
||||
stream.flush().await.unwrap();
|
||||
}
|
||||
|
||||
36
tests/bash/curling.bash
Executable file
36
tests/bash/curling.bash
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######################################
|
||||
#
|
||||
# A simple curl test on a deployed app
|
||||
#
|
||||
#######################################
|
||||
|
||||
URL="https://dev.thegux.fr"
|
||||
|
||||
for i in {0..10}
|
||||
do
|
||||
http_response=$(curl -s -o response.txt -w "%{http_code}" ${URL}/get/ -d '{"username":"toto", "password":"tutu"}')
|
||||
if [ $http_response != "200" ]
|
||||
then
|
||||
echo "bad http status code : ${http_response}, expect 200"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $(cat response.txt | jq -r '.[]') != "ok" ]
|
||||
then
|
||||
echo "bad data returned, expect : ok"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
for i in {0..10}
|
||||
do
|
||||
http_response=$(curl -s -o response.txt -w "%{http_code}" ${URL}/ge/ -d '{"username":"toto", "password":"tutu"}')
|
||||
if [ $http_response != "400" ]
|
||||
then
|
||||
echo "bad http status code : ${http_response}, expect 400"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
34
tests/python/test_requests.py
Normal file
34
tests/python/test_requests.py
Normal file
@ -0,0 +1,34 @@
|
||||
import requests
|
||||
|
||||
URL = "https://dev.thegux.fr"
|
||||
|
||||
|
||||
def test_get_target():
|
||||
resp = requests.post(URL + "/get/", json={"username": "toto", "password": "tata"})
|
||||
assert resp.status_code == 200, "bad status code returned"
|
||||
assert resp.json() is not None, "response data can't be empty"
|
||||
assert resp.json()["status"] == "ok", "bad status returned"
|
||||
|
||||
|
||||
def test_validate_target():
|
||||
resp = requests.post(
|
||||
URL + "/validate/", json={"username": "toto", "password": "tata"}
|
||||
)
|
||||
assert resp.status_code == 200, "bad status code returned"
|
||||
assert resp.json() is not None, "response data can't be empty"
|
||||
assert resp.json()["status"] == "ok", "bad status returned"
|
||||
|
||||
|
||||
def test_refresh_target():
|
||||
resp = requests.post(
|
||||
URL + "/refresh/", json={"username": "toto", "password": "tata"}
|
||||
)
|
||||
assert resp.status_code == 200, "bad status code returned"
|
||||
assert resp.json() is not None, "response data can't be empty"
|
||||
assert resp.json()["status"] == "ok", "bad status 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