Changed main to only look at the config once instead of per connection

This commit is contained in:
int 80h
2020-05-06 23:19:34 -04:00
parent 83163f9a95
commit a066e54acc
3 changed files with 58 additions and 40 deletions

View File

@@ -22,22 +22,42 @@ pub struct Server {
pub usrdir: Option<bool>, pub usrdir: Option<bool>,
} }
#[derive(Debug, Clone)]
pub struct ServerCfg {
pub hostname: String,
pub dir: String,
pub key: String,
pub cert: String,
pub cgi: String,
pub usrdir: bool,
pub port: i32,
}
impl Config { impl Config {
pub fn new(file: &Path) -> Result<Config, Error> { pub fn new(file: &Path) -> Result<Config, Error> {
let fd = std::fs::read_to_string(file).unwrap(); let fd = std::fs::read_to_string(file).unwrap();
let config: Config = toml::from_str(&fd).unwrap(); let config: Config = toml::from_str(&fd).unwrap();
return Ok(config); return Ok(config);
} }
pub fn to_map(&self) -> HashMap<String, Server> { pub fn to_map(&self) -> HashMap<String, ServerCfg> {
let mut map = HashMap::new(); let mut map = HashMap::new();
for srv in &self.server { for srv in &self.server {
map.insert(srv.hostname.clone(), Server { let cgi = match srv.cgi.to_owned() {
Some(c) => c,
None => "".to_string(),
};
let usrdir = match srv.usrdir {
Some(u) => u,
None => false,
};
map.insert(srv.hostname.clone(), ServerCfg {
hostname: srv.hostname.clone(), hostname: srv.hostname.clone(),
dir: srv.dir.clone(), dir: srv.dir.clone(),
key: srv.key.clone(), key: srv.key.clone(),
cert: srv.cert.clone(), cert: srv.cert.clone(),
cgi: srv.cgi.clone(), cgi: cgi,
usrdir: srv.usrdir.clone(), usrdir: usrdir,
port: self.port.clone(),
}); });
} }
map map

View File

@@ -9,10 +9,6 @@ use crate::status;
pub struct Connection { pub struct Connection {
pub stream: TlsStream<TcpStream>, pub stream: TlsStream<TcpStream>,
pub peer_addr: SocketAddr, pub peer_addr: SocketAddr,
pub hostname: String,
pub dir: String,
pub cgi: String,
pub usrdir: bool,
} }
impl Connection { impl Connection {

View File

@@ -98,7 +98,8 @@ fn get_content(path: PathBuf, u: url::Url) -> Result<String, io::Error> {
return Ok(list); return Ok(list);
} }
async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> { // TODO Rewrite this monster.
async fn handle_connection(mut con: conn::Connection, srv: &config::ServerCfg) -> Result<(), io::Error> {
let now: DateTime<Utc> = Utc::now(); let now: DateTime<Utc> = Utc::now();
println!("{} New Connection: {}", now, con.peer_addr); println!("{} New Connection: {}", now, con.peer_addr);
let mut buffer = [0; 1024]; let mut buffer = [0; 1024];
@@ -123,7 +124,7 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
} }
}; };
if Some(con.hostname.as_str()) != url.host_str() { if Some(srv.hostname.as_str()) != url.host_str() {
con.send_status(status::Status::ProxyRequestRefused, "Url doesn't match certificate!").await?; con.send_status(status::Status::ProxyRequestRefused, "Url doesn't match certificate!").await?;
return Ok(()); return Ok(());
} }
@@ -146,7 +147,7 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
let mut path = PathBuf::new(); let mut path = PathBuf::new();
if url.path().starts_with("/~") && con.usrdir == true{ if url.path().starts_with("/~") && srv.usrdir == true{
let usr = url.path().trim_start_matches("/~"); let usr = url.path().trim_start_matches("/~");
let usr: Vec<&str> = usr.splitn(2, "/").collect(); let usr: Vec<&str> = usr.splitn(2, "/").collect();
path.push("/home/"); path.push("/home/");
@@ -156,7 +157,7 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
path.push(format!("{}/{}/",usr[0], "public_gemini")); path.push(format!("{}/{}/",usr[0], "public_gemini"));
} }
} else { } else {
path.push(&con.dir); path.push(&srv.dir);
if url.path() != "" || url.path() != "/" { if url.path() != "" || url.path() != "/" {
path.push(url.path().trim_start_matches("/")); path.push(url.path().trim_start_matches("/"));
} }
@@ -171,6 +172,8 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
let mut meta = fs::metadata(&path).expect("Unable to read metadata"); let mut meta = fs::metadata(&path).expect("Unable to read metadata");
let mut perm = meta.permissions(); let mut perm = meta.permissions();
// TODO fix me
// This block is terrible
if meta.is_dir() { if meta.is_dir() {
if !url.path().ends_with("/") { if !url.path().ends_with("/") {
con.send_status( con.send_status(
@@ -184,11 +187,18 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
path.push("index.gemini"); path.push("index.gemini");
meta = fs::metadata(&path).expect("Unable to read metadata"); meta = fs::metadata(&path).expect("Unable to read metadata");
perm = meta.permissions(); perm = meta.permissions();
if perm.mode() & 0o0444 != 0o444 {
let mut p = path.clone();
p.pop();
path.push(format!("{}/",p.display()));
meta = fs::metadata(&path).expect("Unable to read metadata");
perm = meta.permissions();
}
} }
} }
// add timeout // TODO add timeout
if con.cgi.trim_end_matches("/") == path.parent().unwrap().to_str().unwrap() { if srv.cgi.trim_end_matches("/") == path.parent().unwrap().to_str().unwrap() {
if perm.mode() & 0o0111 == 0o0111 { if perm.mode() & 0o0111 == 0o0111 {
cgi::cgi(con, path, url).await?; cgi::cgi(con, path, url).await?;
return Ok(()); return Ok(());
@@ -233,6 +243,7 @@ fn main() -> io::Result<()> {
return Ok(()); return Ok(());
} }
let cfg = config::Config::new(&p)?; let cfg = config::Config::new(&p)?;
let cmap = cfg.to_map();
println!("Serving {} vhosts", cfg.server.len()); println!("Serving {} vhosts", cfg.server.len());
let addr = format!("{}:{}", cfg.host, cfg.port); let addr = format!("{}:{}", cfg.host, cfg.port);
@@ -255,40 +266,31 @@ fn main() -> io::Result<()> {
loop { loop {
let (stream, peer_addr) = listener.accept().await?; let (stream, peer_addr) = listener.accept().await?;
let acceptor = acceptor.clone(); let acceptor = acceptor.clone();
let cfg = cfg.clone(); let cmap = cmap.clone();
let fut = async move { let fut = async move {
let mut stream = acceptor.accept(stream).await?; let mut stream = acceptor.accept(stream).await?;
let (_, sni) = TlsStream::get_mut(&mut stream); let (_, sni) = TlsStream::get_mut(&mut stream);
let sni = sni.get_sni_hostname(); let sni = match sni.get_sni_hostname() {
let mut dir = String::new(); Some(s) => s,
let mut cgi = String::new(); None => return Ok(()),
let mut hostname = String::new(); };
let mut usrdir: bool = false;
let srv = match cmap.get(sni) {
for server in &cfg.server { Some(h) => h,
if Some(server.hostname.as_str()) == sni { None => {
hostname = sni.unwrap().to_string(); // I'm not sure this will actually get called?
dir = server.dir.to_string(); stream.write_all(b"59\tNotFound!\r\n").await?;
if server.cgi.is_some() { stream.flush().await?;
cgi = server.cgi.as_ref().unwrap().to_string(); return Ok(());
} },
if server.usrdir.is_some() { };
usrdir = server.usrdir.unwrap();
}
break;
}
}
let con = conn::Connection { let con = conn::Connection {
stream, stream,
peer_addr, peer_addr,
hostname,
dir,
cgi,
usrdir,
}; };
handle_connection(con).await?; handle_connection(con, srv).await?;
Ok(()) as io::Result<()> Ok(()) as io::Result<()>
}; };