0.7.2: Finish off CGI hopefully and add path resolving for PATH_STRING env
This commit is contained in:
parent
1656697a7c
commit
3fe3587236
5 changed files with 91 additions and 3 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -4,7 +4,7 @@ version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "herb"
|
name = "herb"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"packeteer",
|
"packeteer",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "herb"
|
name = "herb"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -11,5 +11,8 @@ herb is able to send all types of data to clients, including text, video, audio,
|
||||||
* Supports text and raw data, including PNGs and MP3s
|
* Supports text and raw data, including PNGs and MP3s
|
||||||
* Installable with curze
|
* Installable with curze
|
||||||
|
|
||||||
|
## Can herb run established CGI applications?
|
||||||
|
As of 0.7.2, herb's CGI implementation is fairly compliant and works with query strings _and_ paths. [Here's a screenshot of Cgit running under herb 0.7.2 displaying its own source code!](https://git.colean.cc/threeoh6000/herb/src/branch/master/cgit.png)
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
herb is licensed under [GNU General Public License version 3.](https://git.colean.cc/threeoh6000/herb/src/branch/master/LICENSE)
|
herb is licensed under [GNU General Public License version 3.](https://git.colean.cc/threeoh6000/herb/src/branch/master/LICENSE)
|
||||||
|
|
BIN
cgit.png
Normal file
BIN
cgit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
87
src/main.rs
87
src/main.rs
|
@ -6,7 +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 packeteer::{generate_kvheader, unwrap_url_into_segments};
|
use packeteer::{generate_kvheader, unwrap_url_into_segments, Url};
|
||||||
|
|
||||||
struct Resource {
|
struct Resource {
|
||||||
contents: Vec<u8>,
|
contents: Vec<u8>,
|
||||||
|
@ -63,6 +63,58 @@ fn process_cgi(filename: String) -> Option<Vec<u8>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_cgi_with_path(filename: String, segments: Vec<String>, location: i32) -> Option<Vec<u8>> {
|
||||||
|
let query: String;
|
||||||
|
let script = filename;
|
||||||
|
|
||||||
|
if segments[segments.len()-1].contains("?") {
|
||||||
|
let vars = segments[segments.len()-1].to_string().find("?").unwrap();
|
||||||
|
query = segments[segments.len()-1][vars..].to_string();
|
||||||
|
} else {
|
||||||
|
query = "".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
let mut path = "".to_string();
|
||||||
|
for seg in segments {
|
||||||
|
if !(i <= location) {
|
||||||
|
if path == "".to_string() {
|
||||||
|
path = format!("/{}", seg);
|
||||||
|
} else {
|
||||||
|
path = format!("{}/{}", path, seg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = format!("{}/", path);
|
||||||
|
|
||||||
|
let output;
|
||||||
|
if query != "".to_string() {
|
||||||
|
output = Command::new(format!("./{}", script))
|
||||||
|
.env("GATEWAY_INTERFACE", "CGI/1.1")
|
||||||
|
.env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION")))
|
||||||
|
.env("REQUEST_METHOD", "GET")
|
||||||
|
.env("QUERY_STRING", query)
|
||||||
|
.env("PATH_INFO", path)
|
||||||
|
.env("SCRIPT_NAME", script)
|
||||||
|
.output();
|
||||||
|
} else {
|
||||||
|
output = Command::new(format!("./{}", script))
|
||||||
|
.env("GATEWAY_INTERFACE", "CGI/1.1")
|
||||||
|
.env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION")))
|
||||||
|
.env("REQUEST_METHOD", "GET")
|
||||||
|
.env("PATH_INFO", path)
|
||||||
|
.env("SCRIPT_NAME", script)
|
||||||
|
.output();
|
||||||
|
}
|
||||||
|
if output.is_ok() {
|
||||||
|
return Some(output.unwrap().stdout);
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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.
|
||||||
|
@ -242,7 +294,40 @@ fn process_request(request: Vec<u8>) -> Resource {
|
||||||
println!("Stream sent GET request.");
|
println!("Stream sent GET request.");
|
||||||
|
|
||||||
if request.location.segments.len() != 0 {
|
if request.location.segments.len() != 0 {
|
||||||
|
let segclone = request.location.segments.clone();
|
||||||
path = unwrap_url_into_segments(request.location);
|
path = unwrap_url_into_segments(request.location);
|
||||||
|
if path.contains(".cgi/") {
|
||||||
|
let mut cgiscript = 0;
|
||||||
|
let mut i = 0;
|
||||||
|
let mut cgipath: Vec<String> = vec![];
|
||||||
|
for segment in &segclone {
|
||||||
|
if segment.contains(".cgi") {
|
||||||
|
cgipath.push(segment.to_string());
|
||||||
|
cgiscript = i;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
cgipath.push(segment.to_string());
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut cgipathraw = "".to_string();
|
||||||
|
for seg in cgipath {
|
||||||
|
if cgipathraw == "".to_string() {
|
||||||
|
cgipathraw = seg;
|
||||||
|
} else {
|
||||||
|
cgipathraw = format!("{}/{}", cgipathraw, seg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let contents = process_cgi_with_path(cgipathraw, segclone, cgiscript);
|
||||||
|
if contents.is_some() {
|
||||||
|
let mut resource = Resource { contents: contents.unwrap(), status_code: 200, mime: "text/html".to_string(), iscgi: true };
|
||||||
|
return resource;
|
||||||
|
} else {
|
||||||
|
let newcontents = "<!DOCTYPE HTML><html><body><h1>502 Bad Gateway</h1><p>The server is unable to complete your request due to an error.</p></body></html>".to_string().into_bytes();
|
||||||
|
let mut resource = Resource { contents: newcontents, status_code: 502, mime: "text/html".to_string(), iscgi: false };
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
path.remove(0);
|
path.remove(0);
|
||||||
let exists = check_if_path_exists(path.clone());
|
let exists = check_if_path_exists(path.clone());
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue