tokio
This commit is contained in:
parent
772cb421cb
commit
e2e5138faf
8 changed files with 474 additions and 75 deletions
280
Cargo.lock
generated
280
Cargo.lock
generated
|
|
@ -2,6 +2,286 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.177"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multiplayer-game"
|
name = "multiplayer-game"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.5.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"parking_lot",
|
||||||
|
"pin-project-lite",
|
||||||
|
"signal-hook-registry",
|
||||||
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.61.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
tokio = { version = "1.48.0", features = ["net", "fs", "signal", "process", "io-std", "full"] }
|
||||||
|
|
|
||||||
11
public/index.css
Normal file
11
public/index.css
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
body {
|
||||||
|
background-color: #121212;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #025da9;
|
||||||
|
}
|
||||||
13
public/index.html
Normal file
13
public/index.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/public/index.css">
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<title>Hello World!</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>HTTP server testing</h1>
|
||||||
|
<p>Lorem ipsum</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
125
src/main.rs
125
src/main.rs
|
|
@ -1,54 +1,97 @@
|
||||||
mod request;
|
mod request;
|
||||||
mod response;
|
mod response;
|
||||||
mod shared_enums;
|
mod shared_enums;
|
||||||
|
mod websoket_connection;
|
||||||
|
|
||||||
use std::{
|
use std::time::Duration;
|
||||||
io::{BufReader, Write},
|
use std::{path::Path, str::FromStr};
|
||||||
net::TcpListener,
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
use tokio::time;
|
||||||
|
|
||||||
|
use crate::websoket_connection::WebsocketConnection;
|
||||||
use crate::{
|
use crate::{
|
||||||
request::Connection,
|
request::{Connection, ServerPath},
|
||||||
response::{Response, ResponseCode, ResponseHeader},
|
response::{Response, ResponseCode, ResponseHeader},
|
||||||
shared_enums::{Content, ContentType},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
#[tokio::main]
|
||||||
let listener = TcpListener::bind("127.0.0.1:8080")?;
|
async fn main() -> tokio::io::Result<()> {
|
||||||
for incoming_stream in listener.incoming() {
|
let listener = TcpListener::bind("127.0.0.1:8080").await?;
|
||||||
let mut stream = incoming_stream?;
|
loop {
|
||||||
stream.set_read_timeout(Some(Duration::from_millis(500)))?;
|
let (stream, _) = listener.accept().await?;
|
||||||
|
|
||||||
loop {
|
tokio::spawn(handle_connection(stream));
|
||||||
let reader = BufReader::new(&stream);
|
|
||||||
let req = match request::Request::from_bufreader(reader) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(_) => break,
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("{req:?}");
|
|
||||||
|
|
||||||
let response = match req.path.to_matchable().as_slice(){
|
|
||||||
["css.css"] => Response::new().with_code(ResponseCode::Ok).with_data(b"body{background-color: #121212;} h1{color: #ffffff;} p{color: #025da9;}".to_vec()).with_header(ResponseHeader::ContentType(Content::new(ContentType::Text(shared_enums::TextType::Css)))),
|
|
||||||
|
|
||||||
_ => Response::new()
|
|
||||||
.with_code(ResponseCode::Ok)
|
|
||||||
.with_data(b"<!doctype html><html lang=\"en\"><head><link rel=\"stylesheet\" href=\"css.css\"><meta charset=\"UTF-8\"/><title>Hello World!</title></head><body><h1>HTTP server testing</h1><p>Lorem ipsum</p></body></html>".to_vec())
|
|
||||||
.with_header(ResponseHeader::ContentType(Content::html_utf8())).with_header(ResponseHeader::Connection(Connection::KeepAlive)),
|
|
||||||
};
|
|
||||||
|
|
||||||
response.respond(&mut stream)?;
|
|
||||||
|
|
||||||
stream.flush()?;
|
|
||||||
|
|
||||||
if req.headers.contains(&request::RequestHeader::Connection(
|
|
||||||
request::Connection::Close,
|
|
||||||
)) {
|
|
||||||
println!("Connection closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_connection(stream: TcpStream) -> tokio::io::Result<()> {
|
||||||
|
if let Some(ws) = handle_http_connection(stream).await? {
|
||||||
|
handle_websocket(ws).await?
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_http_connection(
|
||||||
|
mut stream: TcpStream,
|
||||||
|
) -> tokio::io::Result<Option<websoket_connection::WebsocketConnection>> {
|
||||||
|
loop {
|
||||||
|
let req = match time::timeout(
|
||||||
|
Duration::from_millis(500),
|
||||||
|
request::Request::from_bufreader(&mut stream),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Ok(r)) => r,
|
||||||
|
Ok(Err(_)) => {
|
||||||
|
println!("Wrong request");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
println!("Timed out");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{req:?}");
|
||||||
|
|
||||||
|
let response = match req.path.to_matchable().as_slice() {
|
||||||
|
["public", file] => {
|
||||||
|
match Response::from_file(Path::new(format!("./public/{file}").as_str())) {
|
||||||
|
Ok(resp) => resp,
|
||||||
|
Err(_) => Response::new().with_code(ResponseCode::NotFound),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["websocket"] => {
|
||||||
|
return Ok(Some(WebsocketConnection::initialize_connection(req)?));
|
||||||
|
}
|
||||||
|
[] => Response::new()
|
||||||
|
.with_code(ResponseCode::PermanentRedirect)
|
||||||
|
.with_header(ResponseHeader::Connection(Connection::KeepAlive))
|
||||||
|
.with_header(ResponseHeader::Location(
|
||||||
|
ServerPath::from_str("/public/index.html").unwrap(),
|
||||||
|
)),
|
||||||
|
|
||||||
|
_ => Response::new().with_code(ResponseCode::NotFound),
|
||||||
|
};
|
||||||
|
|
||||||
|
response.respond(&mut stream).await?;
|
||||||
|
|
||||||
|
stream.flush().await?;
|
||||||
|
|
||||||
|
if req.headers.contains(&request::RequestHeader::Connection(
|
||||||
|
request::Connection::Close,
|
||||||
|
)) {
|
||||||
|
println!("Connection closed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_websocket(mut web_socket: WebsocketConnection) -> tokio::io::Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
use std::{
|
use std::str::FromStr;
|
||||||
io::{self, BufRead, BufReader, Read, Take},
|
|
||||||
net::TcpStream,
|
use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader, Take};
|
||||||
str::FromStr,
|
use tokio::net::TcpStream;
|
||||||
};
|
|
||||||
|
|
||||||
use crate::shared_enums::Content;
|
use crate::shared_enums::Content;
|
||||||
|
|
||||||
|
|
@ -56,8 +55,8 @@ pub struct Upgrade {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Upgrade {
|
impl FromStr for Upgrade {
|
||||||
type Err = io::Error;
|
type Err = tokio::io::Error;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(_s: &str) -> Result<Self, Self::Err> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +68,7 @@ pub enum Protocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for RequestHeader {
|
impl FromStr for RequestHeader {
|
||||||
type Err = io::Error;
|
type Err = tokio::io::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let header_split: Vec<&str> = s.split(": ").collect();
|
let header_split: Vec<&str> = s.split(": ").collect();
|
||||||
|
|
@ -83,7 +82,7 @@ impl FromStr for RequestHeader {
|
||||||
value
|
value
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(Content::from_str)
|
.map(Content::from_str)
|
||||||
.collect::<Result<Vec<Content>, io::Error>>()?,
|
.collect::<Result<Vec<Content>, tokio::io::Error>>()?,
|
||||||
)),
|
)),
|
||||||
"Connection" => Ok(RequestHeader::Connection(match *value {
|
"Connection" => Ok(RequestHeader::Connection(match *value {
|
||||||
"close" => Connection::Close,
|
"close" => Connection::Close,
|
||||||
|
|
@ -95,15 +94,15 @@ impl FromStr for RequestHeader {
|
||||||
value
|
value
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(Upgrade::from_str)
|
.map(Upgrade::from_str)
|
||||||
.collect::<Result<Vec<Upgrade>, io::Error>>()?,
|
.collect::<Result<Vec<Upgrade>, tokio::io::Error>>()?,
|
||||||
)),
|
)),
|
||||||
_ => Ok(RequestHeader::Other {
|
_ => Ok(RequestHeader::Other {
|
||||||
name: (*header_type).into(),
|
name: (*header_type).into(),
|
||||||
value: (*value).into(),
|
value: (*value).into(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
_ => Err(io::Error::new(
|
_ => Err(tokio::io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
tokio::io::ErrorKind::InvalidData,
|
||||||
"Invalid header-type",
|
"Invalid header-type",
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
@ -111,10 +110,12 @@ impl FromStr for RequestHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
pub fn from_bufreader(buffer: BufReader<&TcpStream>) -> io::Result<Self> {
|
pub async fn from_bufreader(buffer: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
|
let buffer = BufReader::new(buffer);
|
||||||
|
|
||||||
let mut limited_buffer = buffer.take(MAX_LINE_WIDTH);
|
let mut limited_buffer = buffer.take(MAX_LINE_WIDTH);
|
||||||
|
|
||||||
let first_line = Self::read_line(&mut limited_buffer)?;
|
let first_line = Self::read_line(&mut limited_buffer).await?;
|
||||||
let parsed_first_line = Self::parse_first_line(first_line)?;
|
let parsed_first_line = Self::parse_first_line(first_line)?;
|
||||||
|
|
||||||
use std::collections::hash_set::HashSet;
|
use std::collections::hash_set::HashSet;
|
||||||
|
|
@ -124,7 +125,7 @@ impl Request {
|
||||||
let mut headers = vec![];
|
let mut headers = vec![];
|
||||||
|
|
||||||
for _ in 0..MAX_HEADER_COUNT {
|
for _ in 0..MAX_HEADER_COUNT {
|
||||||
let current_line = Self::read_line(&mut limited_buffer)?;
|
let current_line = Self::read_line(&mut limited_buffer).await?;
|
||||||
|
|
||||||
if current_line.is_empty() || current_line == "\r\n" {
|
if current_line.is_empty() || current_line == "\r\n" {
|
||||||
break;
|
break;
|
||||||
|
|
@ -138,8 +139,8 @@ impl Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !header_set.insert(discriminant(headers.last().unwrap())) {
|
if !header_set.insert(discriminant(headers.last().unwrap())) {
|
||||||
return Err(io::Error::new(
|
return Err(tokio::io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
tokio::io::ErrorKind::InvalidData,
|
||||||
"Multiple headers of the same type",
|
"Multiple headers of the same type",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -154,13 +155,16 @@ impl Request {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_line(buffer: &mut Take<BufReader<&TcpStream>>) -> io::Result<String> {
|
async fn read_line(buffer: &mut Take<BufReader<&mut TcpStream>>) -> tokio::io::Result<String> {
|
||||||
let mut read_buffer = vec![];
|
let mut read_buffer = vec![];
|
||||||
buffer.set_limit(MAX_LINE_WIDTH);
|
buffer.set_limit(MAX_LINE_WIDTH);
|
||||||
buffer.read_until(b'\n', &mut read_buffer)?;
|
buffer.read_until(b'\n', &mut read_buffer).await?;
|
||||||
|
|
||||||
if read_buffer.len() < 2 {
|
if read_buffer.len() < 2 {
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid line"));
|
return Err(tokio::io::Error::new(
|
||||||
|
tokio::io::ErrorKind::InvalidData,
|
||||||
|
"Invalid line",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
read_buffer.remove(read_buffer.len() - 1);
|
read_buffer.remove(read_buffer.len() - 1);
|
||||||
|
|
@ -169,7 +173,7 @@ impl Request {
|
||||||
Ok(String::from_utf8_lossy(&read_buffer).to_string())
|
Ok(String::from_utf8_lossy(&read_buffer).to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_first_line(line: String) -> io::Result<(Method, ServerPath, String)> {
|
fn parse_first_line(line: String) -> tokio::io::Result<(Method, ServerPath, String)> {
|
||||||
let splitted_line: Vec<&str> = line.split_whitespace().collect();
|
let splitted_line: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
|
||||||
match splitted_line.as_slice() {
|
match splitted_line.as_slice() {
|
||||||
|
|
@ -178,8 +182,8 @@ impl Request {
|
||||||
ServerPath::from_str(path)?,
|
ServerPath::from_str(path)?,
|
||||||
"HTTP/1.1".to_string(),
|
"HTTP/1.1".to_string(),
|
||||||
)),
|
)),
|
||||||
_ => Err(io::Error::new(
|
_ => Err(tokio::io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
tokio::io::ErrorKind::InvalidData,
|
||||||
"Incorrect HTTP first line",
|
"Incorrect HTTP first line",
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +203,7 @@ impl ServerPath {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for ServerPath {
|
impl FromStr for ServerPath {
|
||||||
type Err = io::Error;
|
type Err = tokio::io::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let get_path = |path: &&str| {
|
let get_path = |path: &&str| {
|
||||||
|
|
@ -239,7 +243,10 @@ impl FromStr for ServerPath {
|
||||||
query: Some(query_parsed.into_boxed_slice()),
|
query: Some(query_parsed.into_boxed_slice()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid path")),
|
_ => Err(tokio::io::Error::new(
|
||||||
|
tokio::io::ErrorKind::InvalidData,
|
||||||
|
"Invalid path",
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +265,7 @@ pub enum Method {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Method {
|
impl FromStr for Method {
|
||||||
type Err = io::Error;
|
type Err = tokio::io::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s {
|
match s {
|
||||||
|
|
@ -271,8 +278,8 @@ impl FromStr for Method {
|
||||||
"PATCH" => Ok(Self::Patch),
|
"PATCH" => Ok(Self::Patch),
|
||||||
"PUT" => Ok(Self::Put),
|
"PUT" => Ok(Self::Put),
|
||||||
"TRACE" => Ok(Self::Trace),
|
"TRACE" => Ok(Self::Trace),
|
||||||
_ => Err(io::Error::new(
|
_ => Err(tokio::io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
tokio::io::ErrorKind::InvalidData,
|
||||||
"Invalid HTTP method",
|
"Invalid HTTP method",
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
use std::{
|
use std::{ffi::OsStr, path::Path};
|
||||||
io::{self, Write},
|
|
||||||
net::TcpStream,
|
use crate::{
|
||||||
|
request::{Connection, ServerPath},
|
||||||
|
shared_enums::{Content, ContentType},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{request::Connection, shared_enums::Content};
|
use tokio::io::{self, AsyncWriteExt};
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
http_version: Box<str>,
|
http_version: Box<str>,
|
||||||
|
|
@ -13,7 +16,7 @@ pub struct Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
pub fn respond(self, stream: &mut TcpStream) -> Result<(), io::Error> {
|
pub async fn respond(self, stream: &mut TcpStream) -> Result<(), io::Error> {
|
||||||
let binding = self.to_str();
|
let binding = self.to_str();
|
||||||
let mut output = binding.as_bytes().to_vec();
|
let mut output = binding.as_bytes().to_vec();
|
||||||
output.extend_from_slice(b"\r\n");
|
output.extend_from_slice(b"\r\n");
|
||||||
|
|
@ -24,7 +27,7 @@ impl Response {
|
||||||
output.extend_from_slice(&self.data);
|
output.extend_from_slice(&self.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.write_all(output.as_slice())?;
|
stream.write_all(output.as_slice()).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +83,32 @@ impl Response {
|
||||||
data: self.data,
|
data: self.data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_file(path: &Path) -> io::Result<Self> {
|
||||||
|
let bytes = std::fs::read(path)?;
|
||||||
|
|
||||||
|
let content_type = match path.extension() {
|
||||||
|
Some(a) if a == OsStr::new("html") => {
|
||||||
|
ContentType::Text(crate::shared_enums::TextType::Html)
|
||||||
|
}
|
||||||
|
Some(a) if a == OsStr::new("css") => {
|
||||||
|
ContentType::Text(crate::shared_enums::TextType::Css)
|
||||||
|
}
|
||||||
|
Some(_) | None => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Looking for a wrong file",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
http_version: "HTTP/1.1".into(),
|
||||||
|
code: ResponseCode::Ok,
|
||||||
|
headers: vec![ResponseHeader::ContentType(Content::new(content_type))],
|
||||||
|
data: bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ResponseCode {
|
pub enum ResponseCode {
|
||||||
|
|
@ -219,6 +248,7 @@ pub enum ResponseHeader {
|
||||||
ContentType(Content),
|
ContentType(Content),
|
||||||
CacheControl(CacheControl),
|
CacheControl(CacheControl),
|
||||||
Connection(Connection),
|
Connection(Connection),
|
||||||
|
Location(ServerPath),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseHeader {
|
impl ResponseHeader {
|
||||||
|
|
@ -228,6 +258,7 @@ impl ResponseHeader {
|
||||||
R::ContentType(content) => format!("Content-Type: {}", content.to_str()).into(),
|
R::ContentType(content) => format!("Content-Type: {}", content.to_str()).into(),
|
||||||
R::CacheControl(c) => format!("Cache-Control: {}", c.to_str()).into(),
|
R::CacheControl(c) => format!("Cache-Control: {}", c.to_str()).into(),
|
||||||
R::Connection(c) => format!("Connection: {}", c.to_str()).into(),
|
R::Connection(c) => format!("Connection: {}", c.to_str()).into(),
|
||||||
|
R::Location(l) => format!("Location: /{}", l.path.join("/")).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
src/websoket_connection.rs
Normal file
13
src/websoket_connection.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
use crate::request::Request;
|
||||||
|
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
|
pub struct WebsocketConnection {
|
||||||
|
steam: TcpStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebsocketConnection {
|
||||||
|
pub fn initialize_connection(req: Request) -> tokio::io::Result<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue