123 lines
3.7 KiB
Rust
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(())
|
|
}
|