maj/src/server/mod.rs

123 lines
3.7 KiB
Rust

use crate::{Response, StatusCode};
use async_trait::async_trait;
use rustls::{Certificate, Session};
use std::{error::Error as StdError, sync::Arc};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::{net::TcpListener, stream::StreamExt};
use tokio_rustls::TlsAcceptor;
use url::Url;
/// A Gemini request and its associated metadata.
#[allow(dead_code)]
pub struct Request {
pub url: Url,
pub certs: Option<Vec<Certificate>>,
}
pub type Error = Box<dyn StdError + Sync + Send>;
#[allow(dead_code, unused_assignments, unused_mut, unused_variables)]
mod routes;
pub use routes::*;
#[async_trait]
pub trait Handler {
async fn handle(&self, r: Request) -> Result<Response, Error>;
}
pub async fn serve<T>(h: T, cfg: rustls::ServerConfig, host: String, port: u16) -> Result<(), Error>
where
T: Handler,
{
let cfg = Arc::new(cfg);
let mut listener = TcpListener::bind(&format!("{}:{}", host, port)).await?;
let mut incoming = listener.incoming();
let acceptor = TlsAcceptor::from(cfg.clone());
while let Some(stream) = incoming.next().await {
let stream = stream?;
let addr = stream.peer_addr().unwrap();
let acceptor = acceptor.clone();
let mut stream = acceptor.accept(stream).await?;
let mut rd = BufReader::new(&mut stream);
let mut u = String::new();
rd.read_line(&mut u).await?;
if u.len() > 1025 {
stream
.write(format!("{} URL too long", StatusCode::BadRequest as u8).as_bytes())
.await?;
continue;
}
let u = Url::parse(&u)?;
match h
.handle(Request {
url: u.clone(),
certs: stream.get_ref().1.get_peer_certificates(),
})
.await
{
Ok(resp) => {
stream
.write(format!("{} {}\r\n", resp.status as u8, resp.meta).as_bytes())
.await?;
stream.write(&resp.body).await?;
log::info!("{}: {} {:?}", addr, u, resp.status);
}
Err(why) => {
stream
.write(format!("{} {:?}\r\n", StatusCode::PermanentFailure as u8, why).as_bytes())
.await?;
log::error!("{}: {}: {:?}", addr, u, why);
}
};
}
Ok(())
}
pub async fn serve_plain<T>(h: T, host: String, port: u16) -> Result<(), Error>
where
T: Handler,
{
let mut listener = TcpListener::bind(&format!("{}:{}", host, port)).await?;
let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
let mut stream = stream?;
let mut rd = BufReader::new(&mut stream);
let mut u = String::new();
rd.read_line(&mut u).await?;
if u.len() > 1025 {
stream
.write(format!("{} URL too long", StatusCode::BadRequest as u8).as_bytes())
.await?;
continue;
}
let u = Url::parse(&u)?;
match h
.handle(Request {
url: u.clone(),
certs: None,
})
.await
{
Ok(resp) => {
stream
.write(format!("{} {}", resp.status as u8, resp.meta).as_bytes())
.await?;
stream.write(&resp.body).await?;
log::info!("{}: {} {:?}", stream.peer_addr().unwrap(), u, resp.status);
}
Err(why) => {
stream
.write(format!("{} {:?}", StatusCode::PermanentFailure as u8, why).as_bytes())
.await?;
log::error!("{}: {}: {:?}", stream.peer_addr().unwrap(), u, why);
}
};
}
Ok(())
}