Bug fix: If text file wasn't utf8 it would fail and not send any

response to clients.
This commit is contained in:
int 80h
2021-12-12 14:56:52 -05:00
parent f23fa8668b
commit 6d11676da4
7 changed files with 93 additions and 99 deletions

View File

@@ -41,7 +41,6 @@ async fn get_binary(mut con: conn::Connection, path: PathBuf, meta: String) -> i
let len = {
let buf = reader.fill_buf().await?;
con.send_raw(buf).await?;
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
buf.len()
};
if len == 0 {
@@ -57,12 +56,7 @@ async fn get_binary(mut con: conn::Connection, path: PathBuf, meta: String) -> i
Ok(())
}
async fn get_content(path: PathBuf, u: &url::Url) -> Result<String> {
let meta = tokio::fs::metadata(&path).await?;
if meta.is_file() {
return Ok(tokio::fs::read_to_string(path).await?);
}
async fn gen_dir_list(path: PathBuf, u: &url::Url) -> Result<String> {
let mut dirs: Vec<String> = Vec::new();
let mut files: Vec<String> = Vec::new();
@@ -201,12 +195,13 @@ pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Resu
#[cfg(feature = "proxy")]
match &con.srv.server.proxy {
Some(pr) => match url.path_segments().map(|c| c.collect::<Vec<_>>()) {
Some(s) => if let Some(p) = pr.get(s[0]) {
Some(pr) => {
if let Some(s) = url.path_segments().map(|c| c.collect::<Vec<_>>()) {
if let Some(p) = pr.get(s[0]) {
revproxy::proxy(p.to_string(), url, con).await?;
return Ok(());
},
None => {}
}
}
},
None => {}
}
@@ -313,18 +308,35 @@ pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Resu
}
let mut mime = get_mime(&path);
if mime == "text/gemini" && con.srv.server.lang.is_some() {
mime += &("; lang=".to_string() + &con.srv.server.lang.to_owned().unwrap());
}
if !mime.starts_with("text/") {
logger::logger(con.peer_addr, Status::Success, url.as_str());
get_binary(con, path, mime).await?;
return Ok(());
}
let content = get_content(path, &url).await?;
con.send_body(Status::Success, Some(&mime), Some(content))
if meta.is_file() {
if mime == "text/gemini" && con.srv.server.lang.is_some() {
mime += &("; lang=".to_string() + &con.srv.server.lang.to_owned().unwrap());
}
if !mime.starts_with("text/") {
logger::logger(con.peer_addr, Status::Success, url.as_str());
get_binary(con, path, mime).await?;
return Ok(());
}
match fs::read_to_string(path).await {
Ok(c) => {
con.send_body(Status::Success, Some(&mime), Some(c))
.await?;
logger::logger(con.peer_addr, Status::Success, url.as_str());
}
Err(e) => {
println!("{}", e);
con.send_status(Status::NotFound, None)
.await?;
logger::logger(con.peer_addr, Status::NotFound, url.as_str());
}
}
} else {
let dir = gen_dir_list(path, &url).await?;
con.send_body(Status::Success, Some(&mime), Some(dir))
.await?;
logger::logger(con.peer_addr, Status::Success, url.as_str());
logger::logger(con.peer_addr, Status::Success, url.as_str());
}
Ok(())
}

View File

@@ -4,7 +4,10 @@ use crate::lib::errors;
use std::collections::HashMap;
use std::env;
use std::path;
use std::net;
use std::net::ToSocketAddrs;
use tokio::fs;
use tokio::io;
type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
@@ -12,7 +15,7 @@ type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send +
pub struct Config {
pub port: Option<u16>,
pub host: Option<String>,
pub interface: Option<Vec<String>>,
pub interface: Option<Vec<net::SocketAddr>>,
pub log: Option<String>,
pub server: Vec<Server>,
}
@@ -65,7 +68,7 @@ impl Config {
}
let fd = fs::read_to_string(p).await.unwrap();
let config: Config = match toml::from_str(&fd) {
let mut config: Config = match toml::from_str(&fd) {
Ok(c) => c,
Err(e) => return Err(Box::new(e)),
};
@@ -86,8 +89,18 @@ impl Config {
"You need to specify either host/port or interface".into(),
)));
} else if config.host.is_some() && config.port.is_some() {
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
addr.push(
format!("{}:{}", &config.host.to_owned().unwrap(), &config.port.unwrap())
.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
);
config.interface = Some(addr);
return Ok(config);
} else if config.interface.is_some() {
} else if let Some(ref mut i) = config.interface {
i.sort_by(|a, b| a.port().cmp(&b.port()));
i.dedup();
return Ok(config);
}
Err(Box::new(errors::GemError(

View File

@@ -4,7 +4,6 @@ use tokio::net::TcpListener;
use tokio_rustls::server::TlsStream;
use tokio_rustls::TlsAcceptor;
//use futures_util::future::TryFutureExt;
use std::collections::HashMap;
use std::future::Future;
use std::io;
@@ -71,12 +70,10 @@ impl Server {
pub async fn serve(
self,
cmap: HashMap<String, config::ServerCfg>,
default: String,
handler: impl Handler + 'static + Copy,
) -> Result {
for listen in self.listener {
let cmap = cmap.clone();
let default = default.clone();
let listen = Arc::new(listen);
let acceptor = Arc::new(self.acceptor.clone());
@@ -86,8 +83,7 @@ impl Server {
let local_addr = stream.local_addr().unwrap();
let acceptor = acceptor.clone();
let cmap = cmap.clone();
let default = default.clone();
let mut handler = handler.clone();
let mut handler = handler;
tokio::spawn(async move {
let mut stream = match acceptor.accept(stream).await {
@@ -105,7 +101,7 @@ impl Server {
let srv = match cmap.get(sni) {
Some(h) => h,
None => cmap.get(&default).unwrap(),
None => return Ok(()) as io::Result<()>,
}
.to_owned();
@@ -138,7 +134,7 @@ impl Server {
}
}
pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection, url::Url)> {
async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection, url::Url)> {
let mut buffer = [0; 1024];
let len = match tokio::time::timeout(
tokio::time::Duration::from_secs(5),

View File

@@ -28,7 +28,7 @@ pub enum Status {
}
impl Status {
pub fn to_str(&self) -> &str {
pub fn to_str(self) -> &'static str {
match self {
Status::Input => "Input",
Status::Success => "Success",

View File

@@ -1,9 +1,6 @@
#[macro_use]
extern crate serde_derive;
use std::io;
use std::net::ToSocketAddrs;
#[cfg(any(feature = "cgi", feature = "scgi"))]
mod cgi;
mod con_handler;
@@ -33,40 +30,17 @@ async fn main() -> errors::Result {
logger::init(&cfg.log)?;
let cmap = cfg.to_map();
let default = &cfg.server[0].hostname;
println!("Serving {} vhosts", cfg.server.len());
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
if cfg.host.is_some() && cfg.port.is_some() {
addr.push(
format!("{}:{}", &cfg.host.to_owned().unwrap(), &cfg.port.unwrap())
.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
);
} else {
match &cfg.interface {
Some(i) => {
for iface in i {
addr.push(
iface
.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
);
}
}
None => {}
}
if let Some(i) = &cfg.interface {
addr.append(&mut i.to_owned());
}
addr.sort_by(|a, b| a.port().cmp(&b.port()));
addr.dedup();
let server = server::Server::bind(addr, tls_acceptor_conf, cfg.clone()).await?;
let server = server::Server::bind(addr, tls_acceptor_conf, cfg).await?;
if let Err(e) = server
.serve(
cmap,
default.to_string(),
server::force_boxed(con_handler::handle_connection),
)
.await