summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorJan Wolff <janw@mailbox.org>2020-05-26 06:49:20 +0200
committerJan Wolff <janw@mailbox.org>2020-05-26 06:49:20 +0200
commit2ffc8ff0ccb0bfad7d69104cbc00b167589c780b (patch)
treeff344bee57957c237bba560d59713a09ce3f3189 /src/server
parentaa041cc4a6d2ed4c817eadfdd36d3bd73d0f0cf1 (diff)
correctly adhere to spec in most request cases
Diffstat (limited to 'src/server')
-rw-r--r--src/server/handler.rs31
-rw-r--r--src/server/mod.rs4
-rw-r--r--src/server/response.rs6
3 files changed, 32 insertions, 9 deletions
diff --git a/src/server/handler.rs b/src/server/handler.rs
index f32a015..db45073 100644
--- a/src/server/handler.rs
+++ b/src/server/handler.rs
@@ -20,11 +20,10 @@ fn send_header(stream: &mut SslStream<TcpStream>, header: &response::Header) {
}
pub fn handle_request(config: &ServerConfig, mut stream: SslStream<TcpStream>) {
- let mut buffer = [0; 1026];
+ let mut buffer = [0; 1024];
match stream.ssl_read(&mut buffer) {
Ok(s) => {
- if s == 0 {
- println!("received empty request buffer");
+ if s == 0 || s > 1025 {
send_header(&mut stream, &response::bad_request());
return;
}
@@ -47,7 +46,11 @@ pub fn handle_request(config: &ServerConfig, mut stream: SslStream<TcpStream>) {
let location = match Url::parse(&request) {
Ok(url) => url,
- Err(_) => config.default_host.join(&request).unwrap(),
+ Err(_) => {
+ println!("received invalid request url");
+ send_header(&mut stream, &response::bad_request());
+ return;
+ },
};
handle_response(config, location, &mut stream);
@@ -69,25 +72,39 @@ fn write_line<T: Write>(line: &[u8], stream: &mut BufWriter<T>) -> Result<(), Er
fn handle_response(config: &ServerConfig, url: Url, mut stream: &mut SslStream<TcpStream>) {
println!("responding for: {}", url);
- if url.scheme() != "gemini" {
- send_header(&mut stream, &response::permanent_failure());
+ // url scheme must be either "gemini://" or "//" (empty)
+ if url.scheme() != "gemini" && url.scheme() != "" {
+ send_header(&mut stream, &response::proxy_request_refused());
return;
}
+ // url request host must match
if url.host() != config.default_host.host() {
send_header(&mut stream, &response::proxy_request_refused());
return;
}
+ // TODO: also drop on incorrect port in request
+
let rel_path = match Path::new(url.path()).strip_prefix("/") {
Ok(path) => path,
Err(_) => {
- Path::new("")
+ // empty path, gemini spec says to redirect client to root
+ send_header(&mut stream, &response::redirect_permanent(
+ config.default_host.as_str(),
+ ));
+ return;
}
};
let path = gen_path_index(&config.gem_root.join(rel_path));
+ // make sure we can't escape gem_root
+ if !path.starts_with(&config.gem_root) {
+ send_header(&mut stream, &response::bad_request());
+ return;
+ }
+
let file = match File::open(&path) {
Ok(file) => file,
Err(_) => {
diff --git a/src/server/mod.rs b/src/server/mod.rs
index 9909fd2..a38e194 100644
--- a/src/server/mod.rs
+++ b/src/server/mod.rs
@@ -24,7 +24,7 @@ pub struct ServerConfig {
impl ServerConfig {
pub fn new() -> ServerConfig {
ServerConfig {
- default_host: Url::parse("gemini://localhost").unwrap(),
+ default_host: Url::parse("gemini://localhost/").unwrap(),
gem_root: PathBuf::from(""),
addrs: Vec::new(),
user: unistd::getuid(),
@@ -35,7 +35,7 @@ impl ServerConfig {
}
pub fn set_default_host(&mut self, default_host: String) {
- let mut url = Url::parse("gemini://default").unwrap();
+ let mut url = Url::parse("gemini://default/").unwrap();
match url.set_host(Some(default_host.as_str())) {
Ok(_) => {}
diff --git a/src/server/response.rs b/src/server/response.rs
index 913d881..263b2e3 100644
--- a/src/server/response.rs
+++ b/src/server/response.rs
@@ -3,6 +3,7 @@ use std::vec::Vec;
#[derive(Copy, Clone)]
pub enum Status {
Success = 20,
+ RedirectPermanent = 31,
PermanentFailure = 50,
NotFound = 51,
ProxyRequestRefused = 53,
@@ -31,6 +32,10 @@ impl Header {
}
}
+pub fn redirect_permanent(meta: &str) -> Header {
+ Header::new(Status::RedirectPermanent, meta)
+}
+
pub fn permanent_failure() -> Header {
Header::new(Status::PermanentFailure, "permanent failure")
}
@@ -46,3 +51,4 @@ pub fn proxy_request_refused() -> Header {
pub fn bad_request() -> Header {
Header::new(Status::BadRequest, "bad request")
}
+