Skip to content

Commit a1ea656

Browse files
authored
Feature/v0.3 (#13)
* Add keep-alive support * improved response returns * Squashed commit of the following: commit df77476 Author: Alberto Ruiz <[email protected]> Date: Thu Oct 31 12:54:46 2024 +0100 update readme commit 765cb63 Author: Alberto Ruiz <[email protected]> Date: Tue Oct 29 12:56:02 2024 +0100 add load balancer to threads commit f179c7d Author: Alberto Ruiz <[email protected]> Date: Fri Oct 25 17:44:37 2024 +0200 add request to worker queue early ROAD TO 100K commit ed838da Author: Alberto Ruiz <[email protected]> Date: Fri Oct 11 17:23:27 2024 +0200 minor improvements commit d9577bb Author: Alberto Ruiz <[email protected]> Date: Thu Oct 10 12:05:39 2024 +0200 fix poc 1 commit 58e653b Author: Alberto Ruiz <[email protected]> Date: Thu Oct 10 12:01:07 2024 +0200 poc 1 * v0.3 - Major refactor - cache has its own module - brew improvements (this will be replaced by hteacup)
1 parent a69ee61 commit a1ea656

12 files changed

+531
-336
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
[package]
22
name = "hteapot"
3-
version = "0.2.6"
4-
exclude = [
5-
"hteapot.toml",
6-
"public/",
7-
"readme.md"
8-
]
3+
version = "0.3.0"
4+
exclude = ["hteapot.toml", "public/", "readme.md"]
95
license = "MIT"
106
keywords = ["HTTP", "HTTP-SERVER"]
117
description = "HTeaPot is a lightweight HTTP server library designed to be easy to use and extend."
@@ -17,9 +13,7 @@ authors = ["Alb Ruiz G. <[email protected]>"]
1713

1814
[lib]
1915
name = "hteapot"
20-
path = "src/hteapot.rs"
16+
path = "src/hteapot/mod.rs"
2117

2218
[[bin]]
2319
name = "hteapot"
24-
25-

config.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
[HTEAPOT]
22
port = 8081
33
host = "0.0.0.0"
4+
threads = 4
45
root = "public"
5-
threads = 5
66
cache = true
7-
cache_ttl = 3600
7+
cache_ttl = 36
88
[proxy]
99
"/test" = "http://example.com"
1010
"/google" = "http://google.com"
11+
"/myip" = "http://ifconfig.co"
1112
# "/" = "http://ifconfig.co" # this will override all the proxys and local request

readme.md

+25-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
[Spanish](docs/readme-es.md) | English
44

5-
HteaPot is a simple HTTP server written in Rust. It allows you to serve static files and handle basic HTTP requests.
5+
HteaPot is a simple HTTP server written in Rust. It allows you to serve static files and handle
6+
HTTP requests.
7+
It´s also a library to write http applictions like an api
68

79
# Features
810

@@ -33,13 +35,33 @@ You can configure the server using a TOML file. Here's an example configuration:
3335
```toml
3436
[HTEAPOT]
3537
port = 8081 # The port on which the server will listen for incoming connections.
36-
host = "localhost" # The host address to bind the server to.
38+
host = "localhost" # The host address to bind the server to.
3739
root = "public" # The root directory from which to serve files.
3840
```
41+
42+
# Library use
43+
44+
For use hteapot as a library in rust
45+
1. Install the library
46+
```bash
47+
$ cargo add hteapot
48+
```
49+
50+
2. Then you can use it in your project
51+
```Rust
52+
use hteapot::{HttpStatus, Hteapot};
53+
54+
fn main() {
55+
let server = Hteapot::new("localhost", 8081);
56+
teapot.listen(move|req| {
57+
}
58+
```
59+
60+
3961
# Contributing
4062

4163
Contributions are welcome! Feel free to open issues or submit pull requests.
4264

4365
# License
4466

45-
This project is licensed under the MIT License - see the LICENSE file for details.
67+
This project is licensed under the MIT License - see the LICENSE file for details.

src/brew.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
net::TcpStream,
77
};
88

9+
#[derive(Debug)]
910
struct Url {
1011
scheme: String,
1112
domain: String,
@@ -27,7 +28,11 @@ fn parse_url(url: &str) -> Result<Url, &str> {
2728
_ => "80",
2829
}
2930
};
30-
let (domain, path) = domain_path.split_once('/').unwrap();
31+
let (domain, path) = match domain_path.split_once('/') {
32+
Some((a, b)) => (a, b),
33+
None => (domain_path, ""),
34+
};
35+
3136
Ok(Url {
3237
scheme: prefix.to_string(),
3338
domain: domain.to_string(),
@@ -51,21 +56,19 @@ pub fn fetch(url: &str) -> Result<Vec<u8>, &str> {
5156
return Err("Error fetching");
5257
}
5358
let mut client = client.unwrap();
54-
let http_request = format!("GET /{} HTTP/1.1\r\nHost: {}\r\n\r\n", url.path, url.domain);
59+
let http_request = format!(
60+
"GET /{} HTTP/1.1\nHost: {}\nConnection: Close\n\n",
61+
url.path, url.domain
62+
);
5563
client.write(http_request.as_bytes()).unwrap();
64+
let _ = client.flush();
5665
let mut full_buffer: Vec<u8> = Vec::new();
5766
let mut buffer = [0; 1024];
5867
loop {
5968
match client.read(&mut buffer) {
6069
Ok(0) => break,
61-
Ok(n) => {
62-
if n == 0 {
63-
break;
64-
}
70+
Ok(_n) => {
6571
full_buffer.extend(buffer.iter().cloned());
66-
if buffer.last().unwrap() == &0 {
67-
break;
68-
}
6972
}
7073
Err(_) => break,
7174
}

src/cache.rs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Written by Alberto Ruiz, 2024-11-05
2+
// Config module: handles application configuration setup and parsing.
3+
// This module defines structs and functions to load and validate
4+
// configuration settings from files, environment variables, or other sources.
5+
use std::collections::HashMap;
6+
use std::time;
7+
use std::time::SystemTime;
8+
9+
pub struct Cache {
10+
//TODO: consider make it generic
11+
data: HashMap<String, (Vec<u8>, u64)>,
12+
max_ttl: u64,
13+
}
14+
15+
impl Cache {
16+
pub fn new(max_ttl: u64) -> Self {
17+
Cache {
18+
data: HashMap::new(),
19+
max_ttl,
20+
}
21+
}
22+
23+
fn validate_ttl(&self, ttl: u64) -> bool {
24+
let now = SystemTime::now();
25+
let since_epoch = now
26+
.duration_since(time::UNIX_EPOCH)
27+
.expect("Time went backwards");
28+
let secs = since_epoch.as_secs();
29+
secs < ttl
30+
}
31+
32+
fn get_ttl(&self) -> u64 {
33+
let now = SystemTime::now();
34+
let since_epoch = now
35+
.duration_since(time::UNIX_EPOCH)
36+
.expect("Time went backwards");
37+
let secs = since_epoch.as_secs();
38+
secs + self.max_ttl
39+
}
40+
41+
pub fn set(&mut self, key: String, data: Vec<u8>) {
42+
self.data.insert(key, (data, self.get_ttl()));
43+
}
44+
45+
pub fn get(&mut self, key: String) -> Option<Vec<u8>> {
46+
let r = self.data.get(&key);
47+
if r.is_some() {
48+
let (data, ttl) = r.unwrap();
49+
if self.validate_ttl(*ttl) {
50+
Some(data.clone())
51+
} else {
52+
self.data.remove(&key);
53+
None
54+
}
55+
} else {
56+
None
57+
}
58+
}
59+
}

src/config.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,13 @@ pub fn toml_parser(content: &str) -> HashMap<String, TOMLSchema> {
9696
map
9797
}
9898

99+
#[derive(Debug)]
99100
pub struct Config {
100101
pub port: u16, // Port number to listen
101102
pub host: String, // Host name or IP
102103
pub root: String, // Root directory to serve files
103104
pub cache: bool,
104-
pub cache_ttl: u64,
105+
pub cache_ttl: u16,
105106
pub threads: u16,
106107
pub index: String, // Index file to serve by default
107108
//pub error: String, // Error file to serve when a file is not found

src/hteapot/methods.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#[derive(Debug, PartialEq, Eq, Hash)]
2+
pub enum HttpMethod {
3+
GET,
4+
POST,
5+
PUT,
6+
DELETE,
7+
PATCH,
8+
HEAD,
9+
OPTIONS,
10+
TRACE,
11+
CONNECT,
12+
Other(String),
13+
}
14+
15+
impl HttpMethod {
16+
pub fn from_str(method: &str) -> HttpMethod {
17+
match method {
18+
"GET" => HttpMethod::GET,
19+
"POST" => HttpMethod::POST,
20+
"PUT" => HttpMethod::PUT,
21+
"DELETE" => HttpMethod::DELETE,
22+
"PATCH" => HttpMethod::PATCH,
23+
"HEAD" => HttpMethod::HEAD,
24+
"OPTIONS" => HttpMethod::OPTIONS,
25+
"TRACE" => HttpMethod::TRACE,
26+
"CONNECT" => HttpMethod::CONNECT,
27+
_ => Self::Other(method.to_string()),
28+
}
29+
}
30+
pub fn to_str(&self) -> &str {
31+
match self {
32+
HttpMethod::GET => "GET",
33+
HttpMethod::POST => "POST",
34+
HttpMethod::PUT => "PUT",
35+
HttpMethod::DELETE => "DELETE",
36+
HttpMethod::PATCH => "PATCH",
37+
HttpMethod::HEAD => "HEAD",
38+
HttpMethod::OPTIONS => "OPTIONS",
39+
HttpMethod::TRACE => "TRACE",
40+
HttpMethod::CONNECT => "CONNECT",
41+
HttpMethod::Other(method) => method.as_str(),
42+
}
43+
}
44+
}
45+
46+
// #[derive(Clone, Copy)]
47+
// pub enum Protocol {
48+
// HTTP,
49+
// HTTPS,
50+
// }

0 commit comments

Comments
 (0)