Implement dynamic content via CGI and fix media type detection errors with server error pages.

This commit is contained in:
abbie 2021-12-26 17:29:34 +00:00
parent 8088fcdde6
commit 736c1e6546
No known key found for this signature in database
GPG key ID: 04DDE463F9200F87
4 changed files with 100 additions and 35 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target /target
/src/content

4
Cargo.lock generated
View file

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "herb" name = "herb"
version = "0.1.4" version = "0.3.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "herb" name = "herb"
version = "0.2.0" version = "0.3.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

View file

@ -5,14 +5,55 @@ use std::fs;
use std::string::{String}; use std::string::{String};
use std::process::Command; use std::process::Command;
fn process_cgi(filename: String) -> String {
// This is gonna be the boggiest implementation of CGI that anyone
// has ever seen in the history of the fucking world
let query;
let script;
if filename.contains("?") {
let vars = filename.to_string().find("?").unwrap();
let vars1 = vars + 1;
query = &filename[vars1..];
script = &filename[..vars];
println!("{} {}", query, script);
} else {
query = "";
script = &filename;
}
let output = Command::new(script)
.arg("GATEWAY_INTERFACE=\"CGI/1.1\"")
.arg("SERVER_SOFTWARE=\"Herb/0.3.0\"")
.arg("REQUEST_METHOD=\"GET\"")
.arg(format!("QUERY_STRING=\"{}\"", query))
.arg(format!("SCRIPT_NAME=\"{}\"", script))
.output()
.expect("failed to execute process");
let outputd = String::from_utf8_lossy(&output.stdout).to_string();
return outputd;
}
fn detect_media_type(filename: String) -> String { fn detect_media_type(filename: String) -> String {
// The Lynx terminal browser made me do this. // The Lynx terminal browser made me do this.
let path = filename.to_string();
let paths = check_if_path_exists(path);
let path = filename.to_string();
let dir = check_if_dir(path);
if paths == true && dir == false && filename.contains(".") == false {
return "text/html".to_string();
} else {
let ext_index = filename.to_string().find(".").unwrap(); let ext_index = filename.to_string().find(".").unwrap();
let test = ext_index + 1; let test = ext_index + 1;
let ext = &filename[test..]; let ext = &filename[test..];
if filename[test..].contains("cgi") { return "text/html".to_string(); }
match ext { match ext {
"aac" => "audio/aac".to_string(), "aac" => "audio/aac".to_string(),
"avi" => "video/x-msvideo".to_string(), "avi" => "video/x-msvideo".to_string(),
@ -38,8 +79,12 @@ 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_503" => "text/html".to_string(),
_ => "application/octet-stream".to_string(), _ => "application/octet-stream".to_string(),
} }
}
} }
@ -91,8 +136,13 @@ fn get_page(filename: String) -> String {
println!("{} {} {}", path, checks, index); println!("{} {} {}", path, checks, index);
if checks == true && index == false { if checks == true && index == false {
if path.contains(".") != true { if path.contains(".") != true && path.contains(".cgi?") != true {
let result = generate_index(filename); let result = generate_index(filename);
println!("balls");
return result.to_string();
} else if path.contains(".cgi?") {
let result = process_cgi(filename);
println!("quack");
return result.to_string(); return result.to_string();
} }
} }
@ -103,8 +153,13 @@ fn get_page(filename: String) -> String {
} else if filename == ".error_server_503" { } 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>"; 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(); return result.to_string();
} else if filename.contains(".cgi") {
let result = process_cgi(filename);
println!("cheese");
return result.to_string();
} else { } else {
let result = fs::read_to_string(filename); let result = fs::read_to_string(filename);
println!("e");
match result { match result {
Ok(i) => i.to_string(), Ok(i) => i.to_string(),
Err(_e) => "<!DOCTYPE HTML><html><body><h1>403 Forbidden</h1><p>The resource you are trying to access cannot be read by the server.</p></body></html>".to_string(), Err(_e) => "<!DOCTYPE HTML><html><body><h1>403 Forbidden</h1><p>The resource you are trying to access cannot be read by the server.</p></body></html>".to_string(),
@ -153,7 +208,9 @@ fn process_request(request: Vec<u8>) -> String {
chars.next(); chars.next();
let path = chars.as_str().to_string(); let path = chars.as_str().to_string();
let exists = check_if_path_exists(path); let exists = check_if_path_exists(path);
if exists == false { let path = chars.as_str().to_string();
if exists == false && path.contains(".cgi?") == false {
output = ".error_server_404"; output = ".error_server_404";
} else { } else {
let path = chars.as_str().to_string(); let path = chars.as_str().to_string();
@ -196,12 +253,17 @@ fn serve(mut stream: TcpStream) {
let resource = process_request(request); let resource = process_request(request);
// Haha, bodged my way around Rust's ownership paradigm! // Haha, bodged my way around Rust's ownership paradigm!
let mime = detect_media_type(resource.to_string()); let mime;
if resource.to_string().contains(".error") {
mime = "text/html".to_string();
} else {
mime = detect_media_type(resource.to_string());
}
let contents = get_page(resource); let contents = get_page(resource);
let header = "HTTP/1.1 200 OK\r\n"; let header = "HTTP/1.1 200 OK\r\n";
let content_type = format!("Content-Type: {}\r\n", mime); let content_type = format!("Content-Type: {}\r\n", mime);
let server = "Server: Herb/0.2.0\r\n"; let server = "Server: Herb/0.3.0\r\n";
let extra_fields; let extra_fields;
if cfg!(unix) { if cfg!(unix) {