rework to use packeteer and fix status codes, clean up code

This commit is contained in:
abbie 2023-10-19 11:24:36 +01:00
parent 021b1826b6
commit 9b8eee2a23
Signed by: threeoh6000
GPG key ID: 801FE4AD456E922C
4 changed files with 50 additions and 41 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/target /target
/src/content /src/content
index.html

9
Cargo.lock generated
View file

@ -5,3 +5,12 @@ version = 3
[[package]] [[package]]
name = "herb" name = "herb"
version = "0.4.2" version = "0.4.2"
dependencies = [
"packeteer",
]
[[package]]
name = "packeteer"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "582fc2c3395c690f0d079658b1acc23848b294f5a0753c54675011f09a0ec815"

View file

@ -1,8 +1,9 @@
[package] [package]
name = "herb" name = "herb"
version = "0.4.2" version = "0.5.0"
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
packeteer = { version = "0.5.1", features = ["http1"] }

View file

@ -4,6 +4,14 @@ use std::net::{TcpListener, TcpStream};
use std::fs; use std::fs;
use std::string::{String}; use std::string::{String};
use std::process::Command; use std::process::Command;
use packeteer::http1::*;
use packeteer::generate_kvheader;
struct Resource {
contents: String,
status_code: i32,
mime: String,
}
fn process_cgi(filename: String) -> String { fn process_cgi(filename: String) -> String {
// This is gonna be the boggiest implementation of CGI that anyone // This is gonna be the boggiest implementation of CGI that anyone
@ -27,7 +35,7 @@ fn process_cgi(filename: String) -> String {
if query != "" { if query != "" {
output = Command::new(format!("./{}", script)) output = Command::new(format!("./{}", script))
.env("GATEWAY_INTERFACE", "CGI/1.1") .env("GATEWAY_INTERFACE", "CGI/1.1")
.env("SERVER_SOFTWARE", "Herb/0.4.2") .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION")))
.env("REQUEST_METHOD", "GET") .env("REQUEST_METHOD", "GET")
.env("QUERY_STRING", query) .env("QUERY_STRING", query)
.env("SCRIPT_NAME", script) .env("SCRIPT_NAME", script)
@ -36,7 +44,7 @@ fn process_cgi(filename: String) -> String {
} else { } else {
output = Command::new(format!("./{}", script)) output = Command::new(format!("./{}", script))
.env("GATEWAY_INTERFACE", "CGI/1.1") .env("GATEWAY_INTERFACE", "CGI/1.1")
.env("SERVER_SOFTWARE", "Herb/0.4.2") .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION")))
.env("REQUEST_METHOD", "GET") .env("REQUEST_METHOD", "GET")
.env("SCRIPT_NAME", script) .env("SCRIPT_NAME", script)
.output() .output()
@ -91,7 +99,7 @@ fn detect_media_type(filename: String) -> String {
"htm" => "text/html".to_string(), "htm" => "text/html".to_string(),
"cgi" => "text/html".to_string(), "cgi" => "text/html".to_string(),
".error_server_404" => "text/html".to_string(), ".error_server_404" => "text/html".to_string(),
".error_server_503" => "text/html".to_string(), ".error_server_501" => "text/html".to_string(),
_ => "application/octet-stream".to_string(), _ => "application/octet-stream".to_string(),
} }
} }
@ -126,7 +134,7 @@ fn generate_index(directory: String) -> String {
index = format!("{}<br/><a href={}>{:#?}</a>", index, format!("\"./{}\"", file.as_ref().unwrap().path().display().to_string()), file.unwrap().file_name()); index = format!("{}<br/><a href={}>{:#?}</a>", index, format!("\"./{}\"", file.as_ref().unwrap().path().display().to_string()), file.unwrap().file_name());
} }
return format!("{}<hr/>Generated by herb 0.4.2", index).to_string(); return format!("{}<hr/>Generated by herb {}", index, env!("CARGO_PKG_VERSION")).to_string();
} }
@ -136,10 +144,8 @@ fn get_page(filename: String) -> String {
// not need to be modified by the server. // not need to be modified by the server.
let path = filename.to_string(); let path = filename.to_string();
let checks = check_if_path_exists(path); let checks = check_if_path_exists(path.clone());
let path = filename.to_string(); let index = check_if_dir(path.clone());
let index = check_if_dir(path);
let path = filename.to_string();
println!("{} {} {}", path, checks, index); println!("{} {} {}", path, checks, index);
@ -153,13 +159,7 @@ fn get_page(filename: String) -> String {
} }
} }
if filename == ".error_server_404" { if filename.contains(".cgi") {
let result = "<!DOCTYPE HTML><html><body><h1>404 Not Found</h1><p>The resource you are trying to locate cannot be accessed!</p></body></html>";
return result.to_string();
} else if filename == ".error_server_503" {
let result = "<!DOCTYPE HTML><html><body><h1>503 Not Implemented</h1><p>The request sent by your web browser cannot be handled by this server software.</p></body></html>";
return result.to_string();
} else if filename.contains(".cgi") {
let result = process_cgi(filename); let result = process_cgi(filename);
return result.to_string(); return result.to_string();
} else { } else {
@ -178,11 +178,11 @@ fn grab_time() -> String{
.output() .output()
.expect("failed to execute process"); .expect("failed to execute process");
return String::from_utf8_lossy(&output.stdout).to_string(); return String::from_utf8_lossy(&output.stdout).to_string().replace("'","").replace("\n","");
} }
fn process_request(request: Vec<u8>) -> String { fn process_request(request: Vec<u8>) -> Resource {
let mut input = String::from_utf8_lossy(&request).to_string(); let mut input = String::from_utf8_lossy(&request).to_string();
let debug = false; let debug = false;
@ -215,7 +215,8 @@ fn process_request(request: Vec<u8>) -> String {
let path = chars.as_str().to_string(); let path = chars.as_str().to_string();
if exists == false && path.contains(".cgi?") == false { if exists == false && path.contains(".cgi?") == false {
output = ".error_server_404"; let resource = Resource { contents: "<!DOCTYPE HTML><html><body><h1>404 Not Found</h1><p>The resource you are trying to locate cannot be accessed!</p></body></html>".to_string(), status_code: 404, mime: "text/html".to_string() };
return resource;
} else { } else {
let path = chars.as_str().to_string(); let path = chars.as_str().to_string();
let dir = check_if_dir(path); let dir = check_if_dir(path);
@ -235,12 +236,18 @@ fn process_request(request: Vec<u8>) -> String {
} else { } else {
// It's get_page()'s problem now. // It's get_page()'s problem now.
let resource = Resource { contents: "<!DOCTYPE HTML><html><body><h1>501 Not Implemented</h1><p>The request sent by your web browser cannot be handled by this server software.</p></body></html>".to_string(), status_code: 501, mime: "text/html".to_string() };
println!("Stream sent unhandlable request."); println!("Stream sent unhandlable request.");
output = ".error_server_503"; return resource;
} }
// Did you want to see chars.as_str().to_string()? // Did you want to see chars.as_str().to_string()?
return output.to_string(); let mut resource = Resource { contents: get_page(output.to_string()), status_code: 200, mime: detect_media_type(output.to_string()) };
if resource.contents.contains("500 Internal Server Error") {
resource.status_code = 500;
resource.mime = "text/html".to_string();
}
return resource;
} }
@ -255,34 +262,25 @@ fn serve(mut stream: TcpStream) {
let resource = process_request(request); let resource = process_request(request);
// Haha, bodged my way around Rust's ownership paradigm! // let contents = get_page(resource.clone());
let mime; // let header = "HTTP/1.1 200 OK\r\n";
// let content_type = format!("Content-Type: {}\r\n", mime);
// let server = format!("Server: herb/{}\r\n", env!("CARGO_PKG_VERSION"));
// let extra_fields;
if resource.to_string().contains(".error") { let mut response_constructed = generate_response(resource.status_code, &resource.contents);
mime = "text/html".to_string(); response_constructed.headers.push(generate_kvheader("Content-Type", &resource.mime));
} else { response_constructed.headers.push(generate_kvheader("Server", &format!("herb/{}", env!("CARGO_PKG_VERSION"))));
mime = detect_media_type(resource.to_string());
}
let contents = get_page(resource);
let header = "HTTP/1.1 200 OK\r\n";
let content_type = format!("Content-Type: {}\r\n", mime);
let server = "Server: Herb/0.4.2\r\n";
let extra_fields;
if cfg!(unix) { if cfg!(unix) {
let mut time = format!("Date: {}\r\n", grab_time()); response_constructed.headers.push(generate_kvheader("Date", &grab_time()))
time = time.replace("'","");
extra_fields = format!("{}{}\r\n", server, time);
} else { } else {
// I don't have a Windows or macOS box to test anything on // I don't have a Windows or macOS box to test anything on
// which means others are gonna have to deal with it :/ // which means others are gonna have to deal with it :/
extra_fields = format!("{}\r\n", server);
} }
let response = format!("{}{}{}{}", header, content_type, extra_fields, contents);
stream.write(response.as_bytes()).unwrap(); println!("{:#?}", response_constructed);
stream.write(unpack_response(response_constructed).as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
}); });
} }