1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
use std::fs::{self, DirEntry};
use std::io::Write;
use std::net::TcpStream;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::{io::Read, net::TcpListener};
use rustls::ServerConnection;
use rustls::{
ServerConfig, Stream,
pki_types::{CertificateDer, PrivateKeyDer, pem::PemObject},
};
fn main() {
println!("Starting MorGemTS Server...");
let root: PathBuf = fs::canonicalize("content").unwrap();
let certs = CertificateDer::pem_file_iter("cert/morgemrs.crt")
.unwrap()
.map(|cert| cert.unwrap())
.collect();
let private_key = PrivateKeyDer::from_pem_file("cert/morgemrs.key").unwrap();
let config = Arc::new(
ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, private_key)
.unwrap(),
);
let listener = TcpListener::bind("127.0.0.1:1965").unwrap();
for mut tcp_stream in listener.incoming().flatten() {
let mut conn = ServerConnection::new(config.clone()).unwrap();
let mut tls_stream = Stream::new(&mut conn, &mut tcp_stream);
let mut buffer = [0; 1027]; // 1024 URI bytes + 2 CRLF bytes + 1 overflow byte
let Ok(n) = tls_stream.read(&mut buffer[..]) else {
let _ = writeln!(tls_stream, "59\r\n");
continue;
};
if n == 1027 {
let _ = writeln!(tls_stream, "59\r\n");
continue;
}
let Ok(raw_uri) = String::from_utf8(buffer.to_vec()) else {
let _ = writeln!(tls_stream, "59\r\n");
continue;
};
let Some(mut uri) = raw_uri
.trim_end_matches(|c: char| c == char::from(0) || c.is_whitespace())
.strip_prefix("gemini://localhost")
else {
let _ = writeln!(tls_stream, "53 Proxy Not Supported\r\n");
continue;
};
uri = uri.trim_matches('/');
let Ok(path) = root.join(uri).canonicalize() else {
let _ = writeln!(tls_stream, "51 Not Found\r\n");
continue;
};
if !path.starts_with(&root) {
let _ = writeln!(tls_stream, "51 Not Found\rpath\n");
continue;
}
if path.is_dir() {
serve_dir(&path, uri, &mut tls_stream);
} else if path.is_file() {
serve_file(&path, &mut tls_stream);
} else {
let _ = writeln!(tls_stream, "51 Not Found\r\n");
}
}
}
fn serve_dir(dir: &Path, uri: &str, tls_stream: &mut Stream<'_, ServerConnection, TcpStream>) {
let index_path = dir.join("index.gem");
if index_path.is_file() {
serve_file(&index_path, tls_stream);
return;
}
let Ok(read_dir) = dir.read_dir() else {
let _ = writeln!(tls_stream, "50 Server Error\r\n");
return;
};
let contents: Vec<DirEntry> = read_dir.flatten().collect();
let content_string = contents
.iter()
.flat_map(|f| f.file_name().into_string())
.map(|s| {
if uri.is_empty() {
format!("=> /{}", s)
} else {
format!("=> /{}/{} ", uri, s)
}
})
.collect::<Vec<String>>()
.join("\r\n");
let _ = writeln!(tls_stream, "20 text/gemini\r\n{}", content_string);
}
fn serve_file(file: &Path, tls_stream: &mut Stream<'_, ServerConnection, TcpStream>) {
let Ok(contents) = fs::read_to_string(file) else {
let _ = writeln!(tls_stream, "50 Server Error\r\n");
return;
};
let _ = writeln!(tls_stream, "20 text/gemini\r\n{}", contents);
}
|