Browse Source

Extract I/O related functions to "io" module

Signed-off-by: Alexey Yerin <yerinalexey98fd@gmail.com>
master
Alexey Yerin 3 years ago committed by Garrit Franke
parent
commit
9c83ef849b
  1. 25
      src/gemini.rs
  2. 54
      src/io.rs
  3. 50
      src/main.rs

25
src/gemini.rs

@ -1,5 +1,7 @@
use crate::error::{TaurusError, TaurusResult};
use crate::logger;
use native_tls::TlsStream;
use std::path;
use std::{io::Write, net::TcpStream, str::FromStr};
use url::Url;
@ -83,6 +85,29 @@ impl GeminiResponse {
}
}
pub fn from_file(path: &str) -> TaurusResult<GeminiResponse> {
let extension = path::Path::new(path)
.extension()
.unwrap_or_else(|| std::ffi::OsStr::new(""));
let mime_type = match &*extension.to_string_lossy() {
"gmi" => "text/gemini; charset=utf-8",
ext => mime_guess::from_ext(ext)
.first_raw()
.unwrap_or("text/plain"),
};
match crate::io::read_file(path) {
Ok(buf) => Ok(GeminiResponse::success(buf, mime_type)),
Err(err) => {
// Cannot read file or it doesn't exist
logger::error(format!("{}: {}", path, err));
Ok(GeminiResponse::not_found())
}
}
}
pub fn send(&self, mut stream: TlsStream<TcpStream>) -> TaurusResult<usize> {
let mut buf: Vec<u8> = Vec::new();

54
src/io.rs

@ -0,0 +1,54 @@
use crate::error::{TaurusError, TaurusResult};
use native_tls::Identity;
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;
/// Read a file into Vec
pub fn read_file(file_path: &str) -> Result<Vec<u8>, io::Error> {
let mut file = File::open(file_path)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
Ok(buf)
}
/// Read certificate file
pub fn load_cert(cert_file: &str, password: &str) -> TaurusResult<Identity> {
let identity = read_file(&cert_file).map_err(TaurusError::NoIdentity)?;
let identity = Identity::from_pkcs12(&identity, &password)?;
Ok(identity)
}
/// Resolve path to a file, returning index.gmi if a subdirectory is encountered
///
/// If path points to a file, it is returned.
/// If path points to a directory, `./index.gmi` is returned
pub fn resolve_path(path: &Path) -> String {
if path.is_dir() {
path.join("index.gmi").to_string_lossy().into_owned()
} else {
path.to_string_lossy().into_owned()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolve_path_file() {
let path = Path::new("./file.gmi");
assert_eq!(resolve_path(&path), String::from("./file.gmi"));
}
#[test]
fn resolve_path_dir() {
let path = Path::new("./");
assert_eq!(resolve_path(&path), String::from("./index.gmi"));
}
}

50
src/main.rs

@ -4,14 +4,14 @@ extern crate url;
mod config;
mod error;
mod gemini;
mod io;
mod logger;
use error::{TaurusError, TaurusResult};
use gemini::{GeminiRequest, GeminiResponse};
use native_tls::{Identity, TlsAcceptor, TlsStream};
use native_tls::{TlsAcceptor, TlsStream};
use std::{
fs::File,
io::{self, Read},
io::Read,
net::{TcpListener, TcpStream},
path,
sync::Arc,
@ -58,9 +58,7 @@ fn run() -> TaurusResult<()> {
.unwrap_or_else(|| "/var/www/gemini".to_owned());
// Read certificate
let identity = read_file(&cert_file).map_err(TaurusError::NoIdentity)?;
let identity = Identity::from_pkcs12(&identity, &config.certificate_password)?;
let identity = crate::io::load_cert(&cert_file, &config.certificate_password)?;
let address = format!("0.0.0.0:{}", port);
let listener = TcpListener::bind(address).map_err(TaurusError::BindFailed)?;
@ -93,40 +91,7 @@ fn run() -> TaurusResult<()> {
Ok(())
}
/// Helper function to read a file into Vec
fn read_file(file_path: &str) -> Result<Vec<u8>, io::Error> {
let mut file = File::open(file_path)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
Ok(buf)
}
/// Send file as a response
fn write_file(path: &str) -> TaurusResult<GeminiResponse> {
let extension = path::Path::new(path)
.extension()
.unwrap_or_else(|| std::ffi::OsStr::new(""));
let mime_type = match &*extension.to_string_lossy() {
"gmi" => "text/gemini; charset=utf-8",
ext => mime_guess::from_ext(ext)
.first_raw()
.unwrap_or("text/plain"),
};
match read_file(path) {
Ok(buf) => Ok(GeminiResponse::success(buf, mime_type)),
Err(err) => {
// Cannot read file or it doesn't exist
logger::error(format!("{}: {}", path, err));
Ok(GeminiResponse::not_found())
}
}
}
fn handle_client(mut stream: TlsStream<TcpStream>, static_root: &str) -> TaurusResult<usize> {
let mut buffer = [0; 1024];
@ -151,12 +116,7 @@ fn handle_client(mut stream: TlsStream<TcpStream>, static_root: &str) -> TaurusR
// Check if file/dir exists
if path.exists() {
// If it's a directory, try to find index.gmi
if path.is_dir() {
write_file(&path.join("index.gmi").to_string_lossy())?.send(stream)
} else {
write_file(&path.to_string_lossy())?.send(stream)
}
GeminiResponse::from_file(&crate::io::resolve_path(&path))?.send(stream)
} else {
GeminiResponse::not_found().send(stream)
}

Loading…
Cancel
Save