Implement dynamic content via CGI and fix media type detection errors with server error pages.
This commit is contained in:
parent
8088fcdde6
commit
736c1e6546
4 changed files with 100 additions and 35 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
/src/content
|
||||||
|
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
128
src/main.rs
128
src/main.rs
|
@ -5,40 +5,85 @@ 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 ext_index = filename.to_string().find(".").unwrap();
|
let path = filename.to_string();
|
||||||
let test = ext_index + 1;
|
let paths = check_if_path_exists(path);
|
||||||
let ext = &filename[test..];
|
let path = filename.to_string();
|
||||||
|
let dir = check_if_dir(path);
|
||||||
|
|
||||||
match ext {
|
if paths == true && dir == false && filename.contains(".") == false {
|
||||||
"aac" => "audio/aac".to_string(),
|
return "text/html".to_string();
|
||||||
"avi" => "video/x-msvideo".to_string(),
|
} else {
|
||||||
"bmp" => "image/bmp".to_string(),
|
let ext_index = filename.to_string().find(".").unwrap();
|
||||||
"bz2" => "application/x-bzip2".to_string(),
|
let test = ext_index + 1;
|
||||||
"css" => "text/css".to_string(),
|
let ext = &filename[test..];
|
||||||
"gz" => "application/gzip".to_string(),
|
|
||||||
"gif" => "image/gif".to_string(),
|
if filename[test..].contains("cgi") { return "text/html".to_string(); }
|
||||||
"png" => "image/png".to_string(),
|
|
||||||
"pdf" => "application/pdf".to_string(),
|
match ext {
|
||||||
"jpeg" => "image/jpeg".to_string(),
|
"aac" => "audio/aac".to_string(),
|
||||||
"jpg" => "image/jpeg".to_string(),
|
"avi" => "video/x-msvideo".to_string(),
|
||||||
"js" => "text/javascript".to_string(),
|
"bmp" => "image/bmp".to_string(),
|
||||||
"mid" => "audio/midi".to_string(),
|
"bz2" => "application/x-bzip2".to_string(),
|
||||||
"midi" => "audio/midi".to_string(),
|
"css" => "text/css".to_string(),
|
||||||
"mp3" => "audio/mpeg".to_string(),
|
"gz" => "application/gzip".to_string(),
|
||||||
"mp4" => "video/mp4".to_string(),
|
"gif" => "image/gif".to_string(),
|
||||||
"mpeg" => "video/mpeg".to_string(),
|
"png" => "image/png".to_string(),
|
||||||
"ogg" => "audio/ogg".to_string(),
|
"pdf" => "application/pdf".to_string(),
|
||||||
"oga" => "audio/ogg".to_string(),
|
"jpeg" => "image/jpeg".to_string(),
|
||||||
"ogv" => "video/ogg".to_string(),
|
"jpg" => "image/jpeg".to_string(),
|
||||||
"opus" => "audio/opus".to_string(),
|
"js" => "text/javascript".to_string(),
|
||||||
"txt" => "text/plain".to_string(),
|
"mid" => "audio/midi".to_string(),
|
||||||
"html" => "text/html".to_string(),
|
"midi" => "audio/midi".to_string(),
|
||||||
"htm" => "text/html".to_string(),
|
"mp3" => "audio/mpeg".to_string(),
|
||||||
_ => "application/octet-stream".to_string(),
|
"mp4" => "video/mp4".to_string(),
|
||||||
|
"mpeg" => "video/mpeg".to_string(),
|
||||||
|
"ogg" => "audio/ogg".to_string(),
|
||||||
|
"oga" => "audio/ogg".to_string(),
|
||||||
|
"ogv" => "video/ogg".to_string(),
|
||||||
|
"opus" => "audio/opus".to_string(),
|
||||||
|
"txt" => "text/plain".to_string(),
|
||||||
|
"html" => "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(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue