maj-async-std #4
|
@ -1,4 +1,9 @@
|
|||
use async_std::task;
|
||||
use maj::{
|
||||
route, seg,
|
||||
server::{Error, Handler as MajHandler, Request},
|
||||
split, Response,
|
||||
};
|
||||
use rustls::internal::pemfile::{certs, rsa_private_keys};
|
||||
use rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
|
||||
use std::fs::File;
|
||||
|
@ -50,7 +55,12 @@ fn main() -> Result<(), maj::server::Error> {
|
|||
let certs = load_certs(&opts.cert)?;
|
||||
let mut keys = load_keys(&opts.key)?;
|
||||
|
||||
log::info!("{:?}", opts);
|
||||
log::info!(
|
||||
"serving gemini://{} on {}:{}",
|
||||
opts.hostname,
|
||||
opts.host,
|
||||
opts.port
|
||||
);
|
||||
|
||||
let mut config = ServerConfig::new(NoClientAuth::new());
|
||||
config
|
||||
|
@ -73,50 +83,35 @@ struct Handler {
|
|||
hostname: String,
|
||||
}
|
||||
|
||||
fn index() -> Result<maj::Response, maj::server::Error> {
|
||||
fn index(_req: Request) -> Result<maj::Response, maj::server::Error> {
|
||||
let msg = include_bytes!("index.gmi");
|
||||
|
||||
Ok(maj::Response {
|
||||
status: maj::StatusCode::Success,
|
||||
meta: "text/gemini".to_string(),
|
||||
body: msg.to_vec(),
|
||||
})
|
||||
Ok(Response::gemini(msg.to_vec()))
|
||||
}
|
||||
|
||||
fn majc() -> Result<maj::Response, maj::server::Error> {
|
||||
fn majc(_req: Request) -> Result<maj::Response, maj::server::Error> {
|
||||
let msg = include_bytes!("majc.gmi");
|
||||
|
||||
Ok(maj::Response {
|
||||
status: maj::StatusCode::Success,
|
||||
meta: "text/gemini".to_string(),
|
||||
body: msg.to_vec(),
|
||||
})
|
||||
Ok(Response::gemini(msg.to_vec()))
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl maj::server::Handler for Handler {
|
||||
async fn handle(&self, r: maj::server::Request) -> Result<maj::Response, maj::server::Error> {
|
||||
if r.url.has_host() && r.url.host_str().unwrap().to_string() != self.hostname {
|
||||
return Ok(maj::Response {
|
||||
status: maj::StatusCode::ProxyRequestRefused,
|
||||
meta: "Wrong host".to_string(),
|
||||
body: vec![],
|
||||
});
|
||||
impl MajHandler for Handler {
|
||||
async fn handle(&self, req: Request) -> Result<Response, Error> {
|
||||
if req.url.has_host() && req.url.host_str().unwrap().to_string() != self.hostname {
|
||||
return Ok(Response::no_proxy());
|
||||
}
|
||||
|
||||
match r.url.path() {
|
||||
"" => Ok(maj::Response {
|
||||
status: maj::StatusCode::PermanentRedirect,
|
||||
meta: format!("gemini://{}/", self.hostname),
|
||||
body: vec![],
|
||||
}),
|
||||
"/" => index(),
|
||||
"/majc" => majc(),
|
||||
_ => Ok(maj::Response {
|
||||
status: maj::StatusCode::NotFound,
|
||||
meta: "Not found".to_string(),
|
||||
body: vec![],
|
||||
}),
|
||||
if req.url.path() == "" {
|
||||
return Ok(Response::perm_redirect(format!(
|
||||
"gemini://{}/",
|
||||
self.hostname
|
||||
)));
|
||||
}
|
||||
|
||||
route!(req.url.path(), {
|
||||
(/) => index(req);
|
||||
(/"majc") => majc(req);
|
||||
});
|
||||
|
||||
Ok(Response::not_found())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::StatusCode;
|
||||
use crate::{gemini, StatusCode};
|
||||
use num::FromPrimitive;
|
||||
use std::io::{prelude::*, ErrorKind, self};
|
||||
use std::io::{self, prelude::*, ErrorKind};
|
||||
|
||||
/// A Gemini response as specified in [the spec](https://gemini.circumlunar.space/docs/specification.html).
|
||||
#[derive(Default)]
|
||||
|
@ -10,6 +10,51 @@ pub struct Response {
|
|||
pub body: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub fn gemini(body: Vec<u8>) -> Response {
|
||||
Response {
|
||||
status: StatusCode::Success,
|
||||
meta: "text/gemini".to_string(),
|
||||
body: body,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(body: Vec<gemini::Node>) -> Response {
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
gemini::render(body, &mut buf).unwrap();
|
||||
|
||||
Response {
|
||||
status: StatusCode::Success,
|
||||
meta: "text/gemini".to_string(),
|
||||
body: buf,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn perm_redirect(to: String) -> Response {
|
||||
Response {
|
||||
status: StatusCode::PermanentRedirect,
|
||||
meta: to,
|
||||
body: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no_proxy() -> Response {
|
||||
Response {
|
||||
status: StatusCode::ProxyRequestRefused,
|
||||
meta: "Wrong host".to_string(),
|
||||
body: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_found() -> Response {
|
||||
Response {
|
||||
status: StatusCode::NotFound,
|
||||
meta: "Not found".to_string(),
|
||||
body: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The parser state.
|
||||
#[derive(Debug)]
|
||||
enum State {
|
||||
|
@ -103,7 +148,7 @@ impl Response {
|
|||
}
|
||||
_ => {
|
||||
if data.len() == 1024 {
|
||||
return Err(Error::ResponseMetaTooLong)
|
||||
return Err(Error::ResponseMetaTooLong);
|
||||
}
|
||||
data.push(buf[0]);
|
||||
}
|
||||
|
@ -168,11 +213,13 @@ mod tests {
|
|||
|
||||
match Response::parse(&mut fin) {
|
||||
Ok(_) => panic!("wanted error but didn't get one"),
|
||||
Err(why) => if let ResponseError::ResponseMetaTooLong = why {
|
||||
println!("ok");
|
||||
} else {
|
||||
panic!("wanted ResponseError::ResponseMetaTooLong")
|
||||
},
|
||||
Err(why) => {
|
||||
if let ResponseError::ResponseMetaTooLong = why {
|
||||
println!("ok");
|
||||
} else {
|
||||
panic!("wanted ResponseError::ResponseMetaTooLong")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue