Added cgi and util mod
This commit is contained in:
43
src/cgi.rs
Normal file
43
src/cgi.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
use std::io::{self, BufReader};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process::Command;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio_rustls::server::TlsStream;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::config;
|
||||||
|
use crate::status;
|
||||||
|
use crate::util;
|
||||||
|
|
||||||
|
pub async fn cgi(
|
||||||
|
stream: TlsStream<TcpStream>,
|
||||||
|
path: PathBuf,
|
||||||
|
url: Url,
|
||||||
|
cfg: config::Config,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
|
||||||
|
let mut envs = HashMap::new();
|
||||||
|
envs.insert("GEMINI_URL", url.as_str());
|
||||||
|
envs.insert("SERVER_NAME", url.host_str().unwrap());
|
||||||
|
envs.insert("SCRIPT_NAME", path.file_name().unwrap().to_str().unwrap());
|
||||||
|
envs.insert("SERVER_PROTOCOL", "GEMINI");
|
||||||
|
// envs.insert("SERVER_PORT", &(cfg.port as str));
|
||||||
|
|
||||||
|
if let Some(q) = url.query() {
|
||||||
|
envs.insert("QUERY_STRING", q);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmd = Command::new(path.to_str().unwrap())
|
||||||
|
.env_clear()
|
||||||
|
.envs(&envs)
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
if !cmd.status.success() {
|
||||||
|
util::send(stream, status::Status::CGIError, "CGI Error!", None).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let cmd = String::from_utf8(cmd.stdout).unwrap();
|
||||||
|
util::send(stream, status::Status::Success, "text/gemini", Some(cmd)).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
72
src/main.rs
72
src/main.rs
@@ -25,26 +25,11 @@ use tokio_rustls::server::TlsStream;
|
|||||||
use tokio_rustls::TlsAcceptor;
|
use tokio_rustls::TlsAcceptor;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
mod cgi;
|
||||||
mod config;
|
mod config;
|
||||||
mod status;
|
mod status;
|
||||||
mod tls;
|
mod tls;
|
||||||
|
mod util;
|
||||||
async fn send(
|
|
||||||
mut stream: TlsStream<TcpStream>,
|
|
||||||
stat: status::Status,
|
|
||||||
meta: String,
|
|
||||||
body: Option<String>,
|
|
||||||
) -> Result<(), io::Error> {
|
|
||||||
let mut s = format!("{}\t{}\r\n", stat as u8, meta);
|
|
||||||
stream.write_all(s.as_bytes()).await?;
|
|
||||||
stream.flush().await?;
|
|
||||||
if let Some(b) = body {
|
|
||||||
s = format!("{}", b);
|
|
||||||
}
|
|
||||||
stream.write_all(s.as_bytes()).await?;
|
|
||||||
stream.flush().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_content(path: PathBuf, u: url::Url) -> Result<String, io::Error> {
|
fn get_content(path: PathBuf, u: url::Url) -> Result<String, io::Error> {
|
||||||
let meta = fs::metadata(&path).expect("Unable to read metadata");
|
let meta = fs::metadata(&path).expect("Unable to read metadata");
|
||||||
@@ -77,10 +62,10 @@ async fn handle_connection(
|
|||||||
let url = Url::parse(&request).unwrap();
|
let url = Url::parse(&request).unwrap();
|
||||||
|
|
||||||
if url.scheme() != "gemini" {
|
if url.scheme() != "gemini" {
|
||||||
send(
|
util::send(
|
||||||
stream,
|
stream,
|
||||||
status::Status::ProxyRequestRefused,
|
status::Status::ProxyRequestRefused,
|
||||||
"Not a gemini scheme!\r\n".to_string(),
|
"Not a gemini scheme!\r\n",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -88,10 +73,10 @@ async fn handle_connection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if url.path().to_string().contains("..") {
|
if url.path().to_string().contains("..") {
|
||||||
send(
|
util::send(
|
||||||
stream,
|
stream,
|
||||||
status::Status::PermanentFailure,
|
status::Status::PermanentFailure,
|
||||||
"Not in path!".to_string(),
|
"Not in path!",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -100,11 +85,11 @@ async fn handle_connection(
|
|||||||
|
|
||||||
let mut dir = String::new();
|
let mut dir = String::new();
|
||||||
let mut cgi = String::new();
|
let mut cgi = String::new();
|
||||||
for server in cfg.server {
|
for server in &cfg.server {
|
||||||
if Some(server.hostname.as_str()) == url.host_str() {
|
if Some(server.hostname.as_str()) == url.host_str() {
|
||||||
dir = server.dir;
|
dir = server.dir.to_string();
|
||||||
if server.cgi.is_some() {
|
if server.cgi.is_some() {
|
||||||
cgi = server.cgi.unwrap();
|
cgi = server.cgi.as_ref().unwrap().to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,13 +100,7 @@ async fn handle_connection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
send(
|
util::send(stream, status::Status::NotFound, "Not found!\r\n", None).await?;
|
||||||
stream,
|
|
||||||
status::Status::NotFound,
|
|
||||||
"Not found!\r\n".to_string(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,10 +109,10 @@ async fn handle_connection(
|
|||||||
|
|
||||||
if meta.is_dir() {
|
if meta.is_dir() {
|
||||||
if !url.path().ends_with("/") {
|
if !url.path().ends_with("/") {
|
||||||
send(
|
util::send(
|
||||||
stream,
|
stream,
|
||||||
status::Status::RedirectPermanent,
|
status::Status::RedirectPermanent,
|
||||||
format!("{}/\r\n", url),
|
format!("{}/\r\n", url).as_str(),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -146,36 +125,15 @@ async fn handle_connection(
|
|||||||
|
|
||||||
// add timeout
|
// add timeout
|
||||||
if cgi.trim_end_matches("/") == path.parent().unwrap().to_str().unwrap() {
|
if cgi.trim_end_matches("/") == path.parent().unwrap().to_str().unwrap() {
|
||||||
let cmd = Command::new(path.to_str().unwrap())
|
cgi::cgi(stream, path, url, cfg).await?;
|
||||||
.env_clear()
|
|
||||||
.wait_timeout(time)
|
|
||||||
.output()?;
|
|
||||||
if !cmd.status.success() {
|
|
||||||
send(
|
|
||||||
stream,
|
|
||||||
status::Status::CGIError,
|
|
||||||
"CGI Error!".to_string(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let cmd = String::from_utf8(cmd.stdout).unwrap();
|
|
||||||
send(
|
|
||||||
stream,
|
|
||||||
status::Status::Success,
|
|
||||||
"text/gemini".to_string(),
|
|
||||||
Some(cmd),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = get_content(path, url)?;
|
let content = get_content(path, url)?;
|
||||||
send(
|
util::send(
|
||||||
stream,
|
stream,
|
||||||
status::Status::Success,
|
status::Status::Success,
|
||||||
"text/gemini".to_string(),
|
"text/gemini",
|
||||||
Some(content),
|
Some(content),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
23
src/util.rs
Normal file
23
src/util.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use std::io;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio::prelude::*;
|
||||||
|
use tokio_rustls::server::TlsStream;
|
||||||
|
|
||||||
|
use crate::status;
|
||||||
|
|
||||||
|
pub async fn send(
|
||||||
|
mut stream: TlsStream<TcpStream>,
|
||||||
|
stat: status::Status,
|
||||||
|
meta: &str,
|
||||||
|
body: Option<String>,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
let mut s = format!("{}\t{}\r\n", stat as u8, meta);
|
||||||
|
stream.write_all(s.as_bytes()).await?;
|
||||||
|
stream.flush().await?;
|
||||||
|
if let Some(b) = body {
|
||||||
|
s = format!("{}", b);
|
||||||
|
}
|
||||||
|
stream.write_all(s.as_bytes()).await?;
|
||||||
|
stream.flush().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user