forked from cadey/maj
input test and static file serving with majsite
This commit is contained in:
parent
d2af2c5f08
commit
28ae14ffa7
|
@ -11,7 +11,8 @@ anyhow = "1"
|
|||
async-std = "1.5"
|
||||
async-trait = "0"
|
||||
log = "0"
|
||||
pretty_env_logger = "0.4"
|
||||
env_logger = "0"
|
||||
percent-encoding = "2"
|
||||
rustls = { version = "0.18", features = ["dangerous_configuration"] }
|
||||
structopt = "0.3"
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use maj::{
|
|||
server::{Error, Handler as MajHandler, Request},
|
||||
split, Response,
|
||||
};
|
||||
use percent_encoding::percent_decode_str;
|
||||
use rustls::internal::pemfile::{certs, rsa_private_keys};
|
||||
use rustls::{
|
||||
AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey, RootCertStore, ServerConfig,
|
||||
|
@ -33,6 +34,10 @@ struct Options {
|
|||
#[structopt(short = "k", long = "key", env = "KEY_FILE")]
|
||||
key: PathBuf,
|
||||
|
||||
/// static path
|
||||
#[structopt(short = "s", long, env = "STATIC_PATH")]
|
||||
static_path: PathBuf,
|
||||
|
||||
/// server hostname
|
||||
#[structopt(
|
||||
long = "hostname",
|
||||
|
@ -53,7 +58,7 @@ fn load_keys(path: &Path) -> io::Result<Vec<PrivateKey>> {
|
|||
}
|
||||
|
||||
fn main() -> Result<(), maj::server::Error> {
|
||||
pretty_env_logger::init();
|
||||
env_logger::init();
|
||||
let opts = Options::from_args();
|
||||
let certs = load_certs(&opts.cert)?;
|
||||
let mut keys = load_keys(&opts.key)?;
|
||||
|
@ -75,6 +80,7 @@ fn main() -> Result<(), maj::server::Error> {
|
|||
task::block_on(maj::server::serve(
|
||||
Arc::new(Handler {
|
||||
hostname: opts.hostname,
|
||||
files: maj::server::files::Handler::new(opts.static_path),
|
||||
}),
|
||||
config,
|
||||
opts.host,
|
||||
|
@ -86,6 +92,7 @@ fn main() -> Result<(), maj::server::Error> {
|
|||
|
||||
struct Handler {
|
||||
hostname: String,
|
||||
files: maj::server::files::Handler,
|
||||
}
|
||||
|
||||
async fn index() -> Result<maj::Response, maj::server::Error> {
|
||||
|
@ -110,6 +117,26 @@ async fn need_cert(req: Request) -> Result<Response, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
async fn input(req: Request) -> Result<Response, Error> {
|
||||
match req.url.query() {
|
||||
None => Ok(Response::input("test")),
|
||||
Some(q) => Ok({
|
||||
use maj::gemini::Node::*;
|
||||
let result = vec![
|
||||
Heading {
|
||||
level: 1,
|
||||
body: "Input test".to_string(),
|
||||
},
|
||||
Text("".to_string()),
|
||||
Text("You gave me:".to_string()),
|
||||
Preformatted(format!("{}", percent_decode_str(q).decode_utf8()?)),
|
||||
];
|
||||
|
||||
Response::render(result)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MajHandler for Handler {
|
||||
async fn handle(&self, req: Request) -> Result<Response, Error> {
|
||||
|
@ -127,7 +154,9 @@ impl MajHandler for Handler {
|
|||
route!(req.url.path(), {
|
||||
(/) => index().await;
|
||||
(/"cert") => need_cert(req).await;
|
||||
(/"input") => input(req).await;
|
||||
(/"majc") => majc().await;
|
||||
(/"static"[/rest..]) => self.files.handle(req).await;
|
||||
});
|
||||
|
||||
Ok(Response::not_found())
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# test
|
||||
|
||||
Hi there
|
|
@ -3,46 +3,45 @@ use super::{Handler as MajHandler, Request, Result};
|
|||
use crate::Response;
|
||||
use async_trait::async_trait;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Handler {
|
||||
chop_off: String,
|
||||
base_dir: String,
|
||||
base_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
/// Serves static files from an OS directory with a given prefix chopped off.
|
||||
pub fn new(chop_off: String, base_dir: String) -> Self {
|
||||
pub fn new(base_dir: PathBuf) -> Self {
|
||||
Handler {
|
||||
chop_off: chop_off,
|
||||
base_dir: base_dir,
|
||||
}
|
||||
}
|
||||
|
||||
fn chop(&self, path: String) -> Option<String> {
|
||||
if path.starts_with(&self.chop_off) {
|
||||
path.strip_prefix(&self.chop_off).map(|val| val.to_string())
|
||||
} else {
|
||||
Some(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl MajHandler for Handler {
|
||||
async fn handle(&self, r: Request) -> Result<Response> {
|
||||
let mut path = std::path::PathBuf::from(&self.base_dir);
|
||||
let mut url = r.url.clone();
|
||||
url.set_path(&self.chop(r.url.path().to_string()).unwrap());
|
||||
if let Some(segments) = r.url.path_segments() {
|
||||
path.extend(segments);
|
||||
}
|
||||
|
||||
if async_std::fs::metadata(&path).await?.is_dir() {
|
||||
if url.as_str().ends_with('/') {
|
||||
log::debug!("opening file {:?}", path);
|
||||
|
||||
match async_std::fs::metadata(&path).await {
|
||||
Ok(stat) => {
|
||||
if stat.is_dir() {
|
||||
if r.url.as_str().ends_with('/') {
|
||||
path.push("index.gmi");
|
||||
} else {
|
||||
// Send a redirect when the URL for a directory has no trailing slash.
|
||||
return Ok(Response::perm_redirect(format!("{}/", url)));
|
||||
return Ok(Response::perm_redirect(format!("{}/", r.url)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(why) => {
|
||||
log::error!("file {} not found: {}", path.to_str().unwrap(), why);
|
||||
return Ok(Response::not_found());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +50,9 @@ impl MajHandler for Handler {
|
|||
async_std::io::copy(&mut file, &mut buf).await?;
|
||||
|
||||
// Send header.
|
||||
if path.extension() == Some(OsStr::new("gmi")) {
|
||||
if path.extension() == Some(OsStr::new("gmi"))
|
||||
|| path.extension() == Some(OsStr::new("gemini"))
|
||||
{
|
||||
return Ok(Response::gemini(buf));
|
||||
}
|
||||
|
||||
|
|
|
@ -107,8 +107,8 @@ async fn handle_request(
|
|||
handle(h, req, &mut stream, addr).await;
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = write_header(&mut stream, StatusCode::BadRequest, "Invalid request.").await;
|
||||
log::error!("error from {}: {:?}", addr, e);
|
||||
let _ = write_header(&mut stream, StatusCode::BadRequest, "Invalid request").await;
|
||||
log::error!("error from {}: {}", addr, e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -171,11 +171,11 @@ async fn handle<T>(
|
|||
.write(format!("{} {}\r\n", resp.status as u8, resp.meta).as_bytes())
|
||||
.await;
|
||||
let _ = stream.write(&resp.body).await;
|
||||
log::info!("{}: {} {} {:?}", addr, u, resp.meta, resp.status);
|
||||
log::info!("{}: {} {:?} {}", addr, u, resp.status, resp.meta);
|
||||
}
|
||||
Err(why) => {
|
||||
let _ = stream
|
||||
.write(format!("{} {:?}\r\n", StatusCode::PermanentFailure as u8, why).as_bytes())
|
||||
.write(format!("{} {}\r\n", StatusCode::PermanentFailure as u8, why.to_string()).as_bytes())
|
||||
.await;
|
||||
log::error!("{}: {}: {:?}", addr, u, why);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue