summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs14
-rw-r--r--src/server/handler.rs29
-rw-r--r--src/server/mod.rs44
-rw-r--r--src/server/response.rs50
4 files changed, 70 insertions, 67 deletions
diff --git a/src/main.rs b/src/main.rs
index 59b6d00..9d1fdcf 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,18 @@
mod server;
+use std::env;
use std::path::Path;
+fn read_config() -> server::ServerConfig {
+ let mut config = server::ServerConfig::new(
+ "klockenschooster.de".to_string(),
+ "/home/jw/code/projects/sheldond/doc".to_string(),
+ );
+ config.add_addr("127.0.0.1:1965".to_string());
+ config.add_addr("[::1]:1965".to_string());
+ return config;
+}
+
fn main() {
- let wwwRoot = Path::new("/var/www/gemini/");
- let server = server::Server::new("gemini://localhost", &wwwRoot);
+ let server = server::Server::new(&read_config());
server.serve();
}
diff --git a/src/server/handler.rs b/src/server/handler.rs
index ceb6551..4a593e8 100644
--- a/src/server/handler.rs
+++ b/src/server/handler.rs
@@ -1,17 +1,32 @@
use crate::server::response;
use crate::server::ServerConfig;
+use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslStream};
+use std::fs::File;
+use std::io::{copy, BufReader, BufWriter};
+use std::net::TcpStream;
use std::path::Path;
use url::Url;
-pub fn handle(config: &ServerConfig, url: Url) -> Option<response::Response> {
+pub fn handle(config: &ServerConfig, url: Url, stream: &mut SslStream<TcpStream>) {
if url.scheme() != "gemini" {
- return Some(response::invalid_protocol());
+ stream.ssl_write(&response::invalid_protocol().to_vec());
+ return;
}
- let path = Path::new(url.path());
- if !path.has_root() {
- return Some(response::not_understood());
- }
+ let rel_path = Path::new(url.path()).strip_prefix("/").unwrap();
+ let path = config.www_root.join(rel_path);
+
+ let file = match File::open(&path) {
+ Ok(file) => file,
+ Err(_) => {
+ stream.ssl_write(&response::not_found().to_vec());
+ return;
+ }
+ };
+
+ stream.ssl_write(&response::Header::new(response::Status::Success, "text/gemini").to_vec());
- None
+ let mut buf_file = BufReader::new(file);
+ let mut buf_stream = BufWriter::new(stream);
+ copy(&mut buf_file, &mut buf_stream);
}
diff --git a/src/server/mod.rs b/src/server/mod.rs
index d7826f6..545fbeb 100644
--- a/src/server/mod.rs
+++ b/src/server/mod.rs
@@ -1,4 +1,3 @@
-use crate::server::response::Response;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslStream};
use std::collections::HashMap;
use std::net::{SocketAddr, TcpListener, TcpStream};
@@ -13,8 +12,26 @@ pub mod response;
#[derive(Clone)]
pub struct ServerConfig {
- defaultHost: Url,
- wwwRoot: PathBuf,
+ default_host: Url,
+ www_root: PathBuf,
+ addrs: Vec<SocketAddr>,
+}
+
+impl ServerConfig {
+ pub fn new(default_host: String, www_root: String) -> ServerConfig {
+ let mut url = Url::parse("gemini://default").unwrap();
+ url.set_host(Some(default_host.as_str()));
+
+ ServerConfig {
+ default_host: url,
+ www_root: PathBuf::from(www_root),
+ addrs: Vec::new(),
+ }
+ }
+
+ pub fn add_addr(&mut self, addr: String) {
+ self.addrs.push(addr.parse().unwrap());
+ }
}
pub struct Server {
@@ -23,21 +40,15 @@ pub struct Server {
}
impl Server {
- pub fn new(host: &str, wwwRoot: &Path) -> Server {
- let config = ServerConfig {
- defaultHost: Url::parse(host).unwrap(),
- wwwRoot: PathBuf::from(wwwRoot),
- };
-
+ pub fn new(config: &ServerConfig) -> Server {
Server {
acceptor: build_acceptor(),
- config: config,
+ config: config.clone(),
}
}
pub fn serve(&self) {
- let addrs = [SocketAddr::from(([127, 0, 0, 1], 1965))];
- let listener = TcpListener::bind(&addrs[..]).unwrap();
+ let listener = TcpListener::bind(&self.config.addrs[..]).unwrap();
for stream in listener.incoming() {
match stream {
@@ -62,15 +73,10 @@ fn handle_client(config: &ServerConfig, mut stream: SslStream<TcpStream>) {
let location = match Url::parse(&request) {
Ok(url) => url,
- Err(e) => config.defaultHost.join(&request).unwrap(),
- };
-
- let response = match handler::handle(config, location) {
- Some(response) => response,
- None => response::internal_error(),
+ Err(e) => config.default_host.join(&request).unwrap(),
};
- stream.ssl_write(&response.format());
+ handler::handle(config, location, &mut stream);
}
fn build_acceptor() -> std::sync::Arc<SslAcceptor> {
diff --git a/src/server/response.rs b/src/server/response.rs
index 36d5d15..8b087ba 100644
--- a/src/server/response.rs
+++ b/src/server/response.rs
@@ -15,11 +15,6 @@ pub struct Header {
meta: String,
}
-pub struct Response {
- header: Header,
- data: Vec<u8>,
-}
-
impl Header {
pub fn new(status: Status, meta: &str) -> Header {
Header {
@@ -31,47 +26,24 @@ impl Header {
pub fn format(&self) -> String {
format!("{} {}\r\n", self.status as u8, self.meta)
}
-}
-impl Response {
- pub fn new(header: Header, data: Vec<u8>) -> Response {
- Response {
- header: header,
- data: data,
- }
- }
-
- pub fn new_empty(header: Header) -> Response {
- Response {
- header: header,
- data: Vec::new(),
- }
+ pub fn to_vec(&self) -> Vec<u8> {
+ self.format().as_bytes().to_vec()
}
+}
- pub fn format(&self) -> Vec<u8> {
- let mut resp: Vec<u8> = self.header.format().as_bytes().to_vec();
- resp.extend(&self.data);
- return resp;
- }
+pub fn invalid_protocol() -> Header {
+ Header::new(Status::PermanentFailure, "this protocol is not supported")
}
-pub fn invalid_protocol() -> Response {
- Response::new_empty(Header::new(
- Status::PermanentFailure,
- "this protocol is not supported",
- ))
+pub fn not_understood() -> Header {
+ Header::new(Status::PermanentFailure, "request not understood")
}
-pub fn not_understood() -> Response {
- Response::new_empty(Header::new(
- Status::PermanentFailure,
- "request not understood",
- ))
+pub fn not_found() -> Header {
+ Header::new(Status::PermanentFailure, "resource not found")
}
-pub fn internal_error() -> Response {
- Response::new_empty(Header::new(
- Status::PermanentFailure,
- "internal server error",
- ))
+pub fn internal_error() -> Header {
+ Header::new(Status::PermanentFailure, "internal server error")
}