One more addition: I think it would make sense to check for
index.gemini as well, as discussed on the gemini mailing list some
time ago. index.gmi has priority though.
I also think that's better. When I was wrinting this, I tried to mimic
HTTP servers whose return `index.html` on `/` without actually
redirecting anywhere.
I was just working on this yesterday, but I was really unhappy with my
approach. This seems cleaner, but it unfortunately does not work (for
me). I think the more "gemini-like" approach would be to return a 31
(permanent redirect) with the location of <Requested
Directory>/index.gmi.
It's up to the client to redirect to the corresponding page then.
Also, some repeated parts are now their own funtions which makes code
much simpler.
---
src/main.rs | 59 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 33 insertions(+), 26 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index d3557b1..0d1c9b0 100644
--- a/src/main.rs+++ b/src/main.rs
@@ -5,6 +5,7 @@ mod gemini;
use native_tls::{Identity, TlsAcceptor, TlsStream};
use std::fs::File;
+use std::io;use std::io::Read;
use std::io::Write;
use std::net::TcpListener;
@@ -39,7 +40,34 @@ fn main() {
Err(e) => println!("Can't handle stream: {}", e),
});
}
- Err(_e) => println!("Error: {}", _e),+ Err(err) => println!("Error: {}", err),+ }+ }+}++/// 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 send_file(path: &str, response: &mut gemini::GeminiResonse) {+ match read_file(path) {+ Ok(buf) => {+ response.body = Some(buf);+ }+ Err(err) => {+ // Cannot read file or it doesn't exist++ println!("Error ({}): {}", path, err);++ response.status = [b'5', b'1'];+ response.meta = format!("Resource not found: {}", path).into(); }
}
}
@@ -60,31 +88,10 @@ fn handle_client(mut stream: TlsStream<TcpStream>) {
let request = gemini::GeminiRequest::from_string(&raw_request).unwrap();
let mut response = gemini::GeminiResonse::new();
- match request.file_path() {- Some(file_path) => {- println!("Reading {}", file_path);-- match File::open(file_path) {- Ok(mut file) => {- let mut body_buf = Vec::new();- if let Err(e) = file.read_to_end(&mut body_buf) {- println!("Could not read file {}", e);- }-- response.body = Some(body_buf);- }- Err(e) => {- let file_path = request.file_path().unwrap_or("");- println!("Error ({}): {}", file_path, e);- response.status = [b'5', b'1'];- response.meta = format!("Resource not found: {}", file_path).into();- }- }- }- None => {- println!("No file found in request");- response.status = [b'5', b'1']- }+ if let Some(path) = request.file_path() {+ send_file(path, &mut response);+ } else {+ send_file("index.gmi", &mut response); }
if let Err(e) = stream.write(&response.build()) {
--
2.29.2