0.8.0: add user configuration.
This commit is contained in:
parent
53b47ad522
commit
c2e35fcf5c
4 changed files with 112 additions and 21 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
/target
|
/target
|
||||||
/src/content
|
/src/content
|
||||||
index.html
|
index.html
|
||||||
|
*settings.toml
|
||||||
|
|
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -2,10 +2,17 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "frostwalker"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17cbf58e19f2bda088d8c4c95a46b41895375e15a2d63dd686a4273f8c43d46b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "herb"
|
name = "herb"
|
||||||
version = "0.7.3"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"frostwalker",
|
||||||
"packeteer",
|
"packeteer",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "herb"
|
name = "herb"
|
||||||
version = "0.7.3"
|
version = "0.8.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
frostwalker = "0.1.1"
|
||||||
packeteer = { version = "0.5.2", features = ["http1"] }
|
packeteer = { version = "0.5.2", features = ["http1"] }
|
||||||
|
|
108
src/main.rs
108
src/main.rs
|
@ -6,6 +6,7 @@ use std::fs::File;
|
||||||
use std::string::{String};
|
use std::string::{String};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use packeteer::http1::*;
|
use packeteer::http1::*;
|
||||||
|
use frostwalker;
|
||||||
use packeteer::{generate_kvheader, unwrap_url_into_segments};
|
use packeteer::{generate_kvheader, unwrap_url_into_segments};
|
||||||
|
|
||||||
struct Resource {
|
struct Resource {
|
||||||
|
@ -18,10 +19,24 @@ struct Resource {
|
||||||
struct GetPageResult {
|
struct GetPageResult {
|
||||||
is500: bool,
|
is500: bool,
|
||||||
is502: bool,
|
is502: bool,
|
||||||
|
is403: bool,
|
||||||
contents: Vec<u8>,
|
contents: Vec<u8>,
|
||||||
iscgi: bool,
|
iscgi: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Settings {
|
||||||
|
cgi: bool,
|
||||||
|
index_generation: bool,
|
||||||
|
address: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings {
|
||||||
|
fn new() -> Settings {
|
||||||
|
return Settings { cgi: true, index_generation: true, address: "0.0.0.0:8080".to_string()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn process_cgi(filename: String) -> Option<Vec<u8>> {
|
fn process_cgi(filename: String) -> Option<Vec<u8>> {
|
||||||
// This is gonna be the boggiest implementation of CGI that anyone
|
// This is gonna be the boggiest implementation of CGI that anyone
|
||||||
// has ever seen in the history of the fucking world
|
// has ever seen in the history of the fucking world
|
||||||
|
@ -154,9 +169,6 @@ fn detect_media_type(filename: String) -> String {
|
||||||
"txt" => "text/plain".to_string(),
|
"txt" => "text/plain".to_string(),
|
||||||
"html" => "text/html".to_string(),
|
"html" => "text/html".to_string(),
|
||||||
"htm" => "text/html".to_string(),
|
"htm" => "text/html".to_string(),
|
||||||
"cgi" => "text/html".to_string(),
|
|
||||||
".error_server_404" => "text/html".to_string(),
|
|
||||||
".error_server_501" => "text/html".to_string(),
|
|
||||||
_ => "application/octet-stream".to_string(),
|
_ => "application/octet-stream".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +207,7 @@ fn generate_index(directory: String) -> String {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_page(filename: String) -> GetPageResult {
|
fn get_page(filename: String, settings: Settings) -> GetPageResult {
|
||||||
|
|
||||||
// The loaded page should be left immutable as it does
|
// The loaded page should be left immutable as it does
|
||||||
// not need to be modified by the server.
|
// not need to be modified by the server.
|
||||||
|
@ -204,16 +216,30 @@ fn get_page(filename: String) -> GetPageResult {
|
||||||
let checks = check_if_path_exists(path.clone());
|
let checks = check_if_path_exists(path.clone());
|
||||||
let index = check_if_dir(path.clone());
|
let index = check_if_dir(path.clone());
|
||||||
|
|
||||||
let mut resultstruct = GetPageResult { is500: false, is502: false, contents: vec![], iscgi: false };
|
let mut resultstruct = GetPageResult { is500: false, is502: false, is403: false, contents: vec![], iscgi: false };
|
||||||
|
|
||||||
println!("{} {} {}", path, checks, index);
|
println!("{} {} {}", path, checks, index);
|
||||||
|
|
||||||
if checks == true && index == false {
|
if checks == true && index == false {
|
||||||
if path.contains(".") != true && path.contains(".cgi?") != true {
|
if path.contains(".") != true && path.contains(".cgi?") != true {
|
||||||
let result = generate_index(filename);
|
let result;
|
||||||
|
if settings.index_generation == false {
|
||||||
|
result = "<!DOCTYPE HTML><html><body><h1>403 Forbidden</h1><p>You do not have permission to access this resource</p></body></html>".to_string();
|
||||||
|
resultstruct.is403 = true;
|
||||||
|
} else {
|
||||||
|
result = generate_index(filename);
|
||||||
|
}
|
||||||
|
|
||||||
resultstruct.contents = result.to_string().into_bytes();
|
resultstruct.contents = result.to_string().into_bytes();
|
||||||
return resultstruct;
|
return resultstruct;
|
||||||
} else if path.contains(".cgi?") {
|
} else if path.contains(".cgi?") {
|
||||||
|
if settings.cgi == false {
|
||||||
|
let result = "<!DOCTYPE HTML><html><body><h1>403 Forbidden</h1><p>You do not have permission to access this resource</p></body></html>".to_string();
|
||||||
|
resultstruct.contents = result.into_bytes();
|
||||||
|
resultstruct.is403 = true;
|
||||||
|
return resultstruct;
|
||||||
|
}
|
||||||
|
|
||||||
let result = process_cgi(filename);
|
let result = process_cgi(filename);
|
||||||
if result.is_some() {
|
if result.is_some() {
|
||||||
resultstruct.contents = result.unwrap();
|
resultstruct.contents = result.unwrap();
|
||||||
|
@ -228,6 +254,13 @@ fn get_page(filename: String) -> GetPageResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
if filename.contains(".cgi") {
|
if filename.contains(".cgi") {
|
||||||
|
if settings.cgi == false {
|
||||||
|
let result = "<!DOCTYPE HTML><html><body><h1>403 Forbidden</h1><p>You do not have permission to access this resource</p></body></html>".to_string();
|
||||||
|
resultstruct.contents = result.into_bytes();
|
||||||
|
resultstruct.is403 = true;
|
||||||
|
return resultstruct;
|
||||||
|
}
|
||||||
|
|
||||||
let result = process_cgi(filename);
|
let result = process_cgi(filename);
|
||||||
if result.is_some() {
|
if result.is_some() {
|
||||||
resultstruct.contents = result.unwrap();
|
resultstruct.contents = result.unwrap();
|
||||||
|
@ -253,7 +286,13 @@ fn get_page(filename: String) -> GetPageResult {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if filename == "index.html" {
|
if filename == "index.html" {
|
||||||
let newresult = generate_index(".".to_string());
|
let newresult;
|
||||||
|
if settings.index_generation == false {
|
||||||
|
newresult = "<!DOCTYPE HTML><html><body><h1>403 Forbidden</h1><p>You do not have permission to access this resource</p></body></html>".to_string();
|
||||||
|
resultstruct.is403 = true;
|
||||||
|
} else {
|
||||||
|
newresult = generate_index(".".to_string());
|
||||||
|
}
|
||||||
resultstruct.contents = newresult.to_string().into_bytes();
|
resultstruct.contents = newresult.to_string().into_bytes();
|
||||||
return resultstruct;
|
return resultstruct;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +313,7 @@ fn grab_time() -> String{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn process_request(request: Vec<u8>) -> Resource {
|
fn process_request(request: Vec<u8>, settings: Settings) -> Resource {
|
||||||
let input = String::from_utf8_lossy(&request).to_string();
|
let input = String::from_utf8_lossy(&request).to_string();
|
||||||
let prerequest = construct_request(&input);
|
let prerequest = construct_request(&input);
|
||||||
let request;
|
let request;
|
||||||
|
@ -317,6 +356,12 @@ fn process_request(request: Vec<u8>) -> Resource {
|
||||||
cgipathraw = format!("{}/{}", cgipathraw, seg);
|
cgipathraw = format!("{}/{}", cgipathraw, seg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if settings.cgi == false {
|
||||||
|
let newcontents = "<!DOCTYPE HTML><html><body><h1>403 Forbidden</h1><p>You do not have permission to access this resource</p></body></html>".to_string().into_bytes();
|
||||||
|
let resource = Resource { contents: newcontents, status_code: 403, mime: "text/html".to_string(), iscgi: false };
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
let contents = process_cgi_with_path(cgipathraw, segclone, cgiscript);
|
let contents = process_cgi_with_path(cgipathraw, segclone, cgiscript);
|
||||||
if contents.is_some() {
|
if contents.is_some() {
|
||||||
let resource = Resource { contents: contents.unwrap(), status_code: 200, mime: "text/html".to_string(), iscgi: true };
|
let resource = Resource { contents: contents.unwrap(), status_code: 200, mime: "text/html".to_string(), iscgi: true };
|
||||||
|
@ -353,7 +398,7 @@ fn process_request(request: Vec<u8>) -> Resource {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Did you want to see chars.as_str().to_string()?
|
// Did you want to see chars.as_str().to_string()?
|
||||||
let rescontents = get_page(output.to_string());
|
let rescontents = get_page(output.to_string(), settings.clone());
|
||||||
let mut resource = Resource { contents: rescontents.contents, status_code: 200, mime: detect_media_type(output.split("?").collect::<Vec<&str>>()[0].to_string()), iscgi: false };
|
let mut resource = Resource { contents: rescontents.contents, status_code: 200, mime: detect_media_type(output.split("?").collect::<Vec<&str>>()[0].to_string()), iscgi: false };
|
||||||
if rescontents.is500 {
|
if rescontents.is500 {
|
||||||
resource.status_code = 500;
|
resource.status_code = 500;
|
||||||
|
@ -365,6 +410,11 @@ fn process_request(request: Vec<u8>) -> Resource {
|
||||||
resource.mime = "text/html".to_string();
|
resource.mime = "text/html".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rescontents.is403 {
|
||||||
|
resource.status_code = 403;
|
||||||
|
resource.mime = "text/html".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
if rescontents.iscgi {
|
if rescontents.iscgi {
|
||||||
resource.iscgi = true;
|
resource.iscgi = true;
|
||||||
}
|
}
|
||||||
|
@ -373,7 +423,7 @@ fn process_request(request: Vec<u8>) -> Resource {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serve(mut stream: TcpStream) {
|
fn serve(mut stream: TcpStream, settings: Settings) {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
println!("Stream thread created.");
|
println!("Stream thread created.");
|
||||||
let mut request = Vec::new();
|
let mut request = Vec::new();
|
||||||
|
@ -382,7 +432,7 @@ fn serve(mut stream: TcpStream) {
|
||||||
.read_until(b'\n', &mut request)
|
.read_until(b'\n', &mut request)
|
||||||
.expect("Failed to read from stream!");
|
.expect("Failed to read from stream!");
|
||||||
|
|
||||||
let resource = process_request(request);
|
let resource = process_request(request, settings.clone());
|
||||||
|
|
||||||
let mut response_constructed = generate_response(resource.status_code, "");
|
let mut response_constructed = generate_response(resource.status_code, "");
|
||||||
response_constructed.headers.push(generate_kvheader("Content-Type", &resource.mime));
|
response_constructed.headers.push(generate_kvheader("Content-Type", &resource.mime));
|
||||||
|
@ -409,13 +459,45 @@ fn serve(mut stream: TcpStream) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_settings() -> Settings {
|
||||||
|
let string = fs::read_to_string("../settings.toml");
|
||||||
|
if string.is_err() {
|
||||||
|
return Settings::new();
|
||||||
|
}
|
||||||
|
let parsed = frostwalker::parse(&string.unwrap());
|
||||||
|
if parsed.is_err() {
|
||||||
|
return Settings::new();
|
||||||
|
}
|
||||||
|
let hashmap = parsed.unwrap();
|
||||||
|
let mut settings = Settings::new();
|
||||||
|
if hashmap.get("cgi").is_some() {
|
||||||
|
if hashmap.get("cgi").unwrap_or(&"".to_string()).parse::<bool>().is_ok() {
|
||||||
|
settings.cgi = hashmap.get("cgi").unwrap_or(&"true".to_string()).parse::<bool>().unwrap_or(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hashmap.get("index_generation").is_some() {
|
||||||
|
println!("a");
|
||||||
|
if hashmap.get("index_generation").unwrap_or(&"".to_string()).parse::<bool>().is_ok() {
|
||||||
|
settings.index_generation = hashmap.get("index_generation").unwrap_or(&"true".to_string()).parse::<bool>().unwrap_or(true);
|
||||||
|
println!("{}", settings.index_generation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hashmap.get("address").is_some() {
|
||||||
|
settings.address = hashmap.get("address").unwrap_or(&"0.0.0.0:8080".to_string()).to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let listen = TcpListener::bind("0.0.0.0:8080")?;
|
let settings = process_settings();
|
||||||
|
let listen = TcpListener::bind(settings.address.clone())?;
|
||||||
|
|
||||||
for stream in listen.incoming() {
|
for stream in listen.incoming() {
|
||||||
println!("Serving incoming stream.");
|
println!("Serving incoming stream.");
|
||||||
serve(stream?);
|
serve(stream?, settings.clone());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue