feat: #1 add HTTPStartLine struct to parse request start line + some fixes
This commit is contained in:
parent
2e097bbedb
commit
3afe437143
@ -4,72 +4,118 @@
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum HTTPVersion {
|
pub enum HTTPVersion {
|
||||||
HTTP1,
|
Http1,
|
||||||
HTTP2,
|
//http2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<String> for HTTPVersion {
|
impl Into<String> for HTTPVersion {
|
||||||
fn into(self) -> String {
|
fn into(self) -> String {
|
||||||
match self {
|
match self {
|
||||||
HTTP1 => "HTTP/1.1".to_string(),
|
Self::Http1 => "HTTP/1.1".to_string(),
|
||||||
HTTP2 => "HTTP/2.2".to_string(),
|
//Self::Http2 => "HTTP/2.2".to_string(),
|
||||||
_ => "UNKNOWN".to_string(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request defined the HTTP request
|
|
||||||
// TODO: method, target, version must be set in new struct : `HTTPStartLine`
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HTTPRequest {
|
pub struct HTTPStartLine {
|
||||||
pub method: String,
|
pub method: String,
|
||||||
pub target: String,
|
pub target: String,
|
||||||
pub version: HTTPVersion,
|
pub version: HTTPVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTTPRequest {
|
impl HTTPStartLine {
|
||||||
// associated function to build a new HTTPRequest
|
|
||||||
fn new(method: String, target: String, version: HTTPVersion) -> Self {
|
fn new(method: String, target: String, version: HTTPVersion) -> Self {
|
||||||
HTTPRequest {
|
HTTPStartLine {
|
||||||
method,
|
method,
|
||||||
target,
|
target,
|
||||||
version,
|
version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(request: &str) -> Result<Self, &str> {
|
fn parse(start_line: &str) -> Result<Self, &str> {
|
||||||
// declare a new `request` var to borrow to &str `request`
|
// declare a new `start_line` var to borrow to &str `start_line`
|
||||||
let request = request.to_string();
|
let start_line = start_line.to_string();
|
||||||
|
|
||||||
let request_parts: Vec<&str> = request.split(" ").collect();
|
let parts: Vec<&str> = start_line.split(" ").collect();
|
||||||
if request_parts.len() < 3 {
|
if parts.len() < 3 {
|
||||||
return Err("unable to parse the request correctly");
|
return Err("unable to parse the start correctly");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(HTTPRequest::new(
|
// TODO: parse correctly the different parts (using regex ?)
|
||||||
request_parts[0].to_string(),
|
Ok(HTTPStartLine::new(
|
||||||
request_parts[1].to_string(),
|
parts[0].to_string(),
|
||||||
HTTPVersion::HTTP1,
|
parts[1].to_string(),
|
||||||
|
HTTPVersion::Http1,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid(self) -> bool {
|
fn is_valid(self) -> bool {
|
||||||
return self.method != "" && self.target != "";
|
return self.method != "" && self.target != "";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: to be tested
|
impl Default for HTTPStartLine {
|
||||||
pub fn start_line(self) -> String {
|
fn default() -> Self {
|
||||||
|
HTTPStartLine {
|
||||||
|
method: "".to_string(),
|
||||||
|
target: "".to_string(),
|
||||||
|
version: HTTPVersion::Http1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<String> for HTTPStartLine {
|
||||||
|
fn into(self) -> String {
|
||||||
let version: String = self.version.into();
|
let version: String = self.version.into();
|
||||||
return format!("{} {} {}", self.method, self.target, version);
|
return format!("{} {} {}", self.method, self.target, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request defined the HTTP request
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HTTPRequest {
|
||||||
|
pub start_line: HTTPStartLine,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTTPRequest {
|
||||||
|
// associated function to build a new HTTPRequest
|
||||||
|
fn new(start_line: HTTPStartLine) -> Self {
|
||||||
|
HTTPRequest { start_line }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// parse parses the request by spliting the incoming request with the separator `\r\n`
|
||||||
|
fn parse(request: &str) -> Result<HTTPRequest, &str> {
|
||||||
|
// declare a new `request` var to borrow to &str `request`
|
||||||
|
let request = request.to_string();
|
||||||
|
|
||||||
|
let request_parts: Vec<&str> = request.split("\r\n").collect();
|
||||||
|
println!("request part : {:?}", request_parts);
|
||||||
|
// TODO: increase the check to 3 to match the request (for now only the start_line)
|
||||||
|
if request_parts.len() < 1 {
|
||||||
|
return Err("unable to parse the request correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut request = HTTPRequest::default();
|
||||||
|
|
||||||
|
let start_line = HTTPStartLine::parse(request_parts[0]);
|
||||||
|
match start_line {
|
||||||
|
Ok(v) => request.start_line = v,
|
||||||
|
Err(e) => eprintln!("error occured while parsing start_line err={}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid(self) -> bool {
|
||||||
|
return self.start_line.is_valid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for HTTPRequest {
|
impl Default for HTTPRequest {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
HTTPRequest {
|
HTTPRequest {
|
||||||
method: "".to_string(),
|
start_line: HTTPStartLine::default(),
|
||||||
target: "".to_string(),
|
|
||||||
version: HTTPVersion::HTTP1,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,8 +138,12 @@ pub fn handle_request(request: &str) -> HTTPRequest {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handle_request() {
|
fn test_handle_request() {
|
||||||
let test_cases: [(&str, bool); 5] = [
|
let test_cases: [(&str, bool); 6] = [
|
||||||
("GET / HTTP/1.1", true),
|
("GET / HTTP/1.1", true),
|
||||||
|
(
|
||||||
|
"OPTIONS /admin/2 HTTP/\r\nContent-Type: application/json",
|
||||||
|
true,
|
||||||
|
), // intentionally add HTTP with no version number
|
||||||
("POST HTTP/1.1", false),
|
("POST HTTP/1.1", false),
|
||||||
("", false),
|
("", false),
|
||||||
("fjlqskjd /oks?id=65 HTTP/2", true),
|
("fjlqskjd /oks?id=65 HTTP/2", true),
|
||||||
|
|||||||
@ -1,13 +1,9 @@
|
|||||||
mod handlers;
|
mod handlers;
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
|
|
||||||
use async_std::task;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use handlers::handle_request;
|
use handlers::handle_request;
|
||||||
|
|
||||||
// TODO: must be set in a conf file
|
// TODO: must be set in a conf file
|
||||||
@ -28,14 +24,12 @@ async fn handle_connection(mut stream: TcpStream) {
|
|||||||
let mut buffer = [0; 1024];
|
let mut buffer = [0; 1024];
|
||||||
stream.read(&mut buffer).unwrap();
|
stream.read(&mut buffer).unwrap();
|
||||||
|
|
||||||
let get = b"GET / HTTP/1.1\r\n";
|
|
||||||
|
|
||||||
// transform buffer bytes array into `String`
|
// transform buffer bytes array into `String`
|
||||||
let buffer_string = String::from_utf8_lossy(&buffer);
|
let buffer_string = String::from_utf8_lossy(&buffer);
|
||||||
let request = handle_request(&buffer_string);
|
let request = handle_request(&buffer_string);
|
||||||
|
|
||||||
// TODO: `Response` struct must be implemented
|
// TODO: `Response` struct must be implemented
|
||||||
let status_line = if request.target == "/".to_string() {
|
let status_line = if request.start_line.target == "/".to_string() {
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
} else {
|
} else {
|
||||||
"HTTP/1.1 404 NOT FOUND\r\n"
|
"HTTP/1.1 404 NOT FOUND\r\n"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user