diff options
| author | Jan Wolff <janw@mailbox.org> | 2020-05-17 00:16:57 +0200 |
|---|---|---|
| committer | Jan Wolff <janw@mailbox.org> | 2020-05-17 00:16:57 +0200 |
| commit | 87d61457bdc33676475803937ccd39e1a6c661de (patch) | |
| tree | 07291e8b185b1b4cab8940534b5e29f5a1013f55 /src/server | |
| parent | 177d12b5b89f97039a5849d131b3524eecb3bf57 (diff) | |
working file serving
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/handler.rs | 29 | ||||
| -rw-r--r-- | src/server/mod.rs | 44 | ||||
| -rw-r--r-- | src/server/response.rs | 50 |
3 files changed, 58 insertions, 65 deletions
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") } |
