Browse Source

gempress: return result from function handlers

main
Garrit Franke 3 years ago
parent
commit
4ce5ebabf2
Signed by: garrit
GPG Key ID: 65586C4DDA55EA2C
  1. 4
      lib/gempress/examples/simple_server.rs
  2. 27
      lib/gempress/src/gemini.rs
  3. 41
      lib/gempress/src/lib.rs
  4. 14
      src/main.rs

4
lib/gempress/examples/simple_server.rs

@ -2,10 +2,12 @@ extern crate gempress;
use gempress::gemini;
use gempress::Gempress;
use gempress::GempressResult;
use std::path::PathBuf;
fn index_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) {
fn index_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) -> GempressResult<()> {
res.send("Hello from index route!".as_bytes());
Ok(())
}
fn main() {

27
lib/gempress/src/gemini.rs

@ -1,8 +1,23 @@
use std::fmt;
use crate::error::{GempressError, GempressResult};
use native_tls::TlsStream;
use std::{io::Write, net::TcpStream, str::FromStr};
use url::Url;
/// Gemini status codes as defined in Appendix 1
/// TODO: fill out remaining codes
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum StatusCode {
Success = 20,
NotFound = 51,
}
impl fmt::Display for StatusCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", *self as u8)
}
}
/// A gemini request
#[derive(Debug, PartialEq, Eq)]
pub struct Request {
@ -65,7 +80,7 @@ impl FromStr for Request {
/// A gemini response
pub struct Response {
pub status: [u8; 2],
pub status_code: StatusCode,
pub meta: Vec<u8>,
pub body: Vec<u8>,
stream: TlsStream<TcpStream>,
@ -74,19 +89,25 @@ pub struct Response {
impl Response {
pub(crate) fn new(stream: TlsStream<TcpStream>) -> Self {
Self {
status: [b'2', b'0'],
status_code: StatusCode::Success,
meta: "text/gemini".into(),
body: Vec::new(),
stream,
}
}
/// Set the status code of a response
pub fn status(&mut self, code: StatusCode) -> GempressResult<&mut Self> {
self.status_code = code;
return Ok(self);
}
/// "Finish" the response and write it to the steeam
pub fn send(&mut self, text: &[u8]) -> GempressResult<usize> {
let mut buf: Vec<u8> = Vec::new();
// <Status>
buf.extend(&self.status);
buf.extend(self.status_code.to_string().as_bytes());
// <Space>
buf.push(0x20);

41
lib/gempress/src/lib.rs

@ -2,8 +2,8 @@ extern crate native_tls;
/// Types representing the gemini specification
pub mod gemini;
pub mod error;
mod error;
mod io;
mod logger;
@ -13,7 +13,7 @@ use std::net::{TcpListener, TcpStream};
use std::path::PathBuf;
use std::sync::Arc;
use error::{GempressError, GempressResult};
pub use error::{GempressError, GempressResult};
use native_tls::{TlsAcceptor, TlsStream};
/// Configuration for a Gempress server.
@ -30,7 +30,7 @@ impl Config {
/// To generate a self-signed certificate, you can execute the following commands (substitute
/// `localhost` with your hostname, if applicable):
///
/// ```
/// ```sh
/// openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=localhost'
/// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem
///
@ -57,7 +57,7 @@ impl Config {
/// # Examples
///
/// ```
/// use gempress::Gempress;
/// use gempress::*;
/// use gempress::gemini;
/// use std::path::PathBuf;
///
@ -65,8 +65,10 @@ impl Config {
/// let mut app = Gempress::new(config);
///
/// // Define a function handler
/// fn index_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) {
/// res.send("Hello from index route!".as_bytes());
/// fn index_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) ->
/// GempressResult<()> {
/// res.send("Hello from index route!".as_bytes())?;
/// Ok(())
/// }
///
/// // Apply function handler to path
@ -77,7 +79,7 @@ impl Config {
/// })
/// .unwrap();
/// ```
pub type Handler = dyn Fn(Box<gemini::Request>, Box<gemini::Response>);
pub type Handler = dyn Fn(Box<gemini::Request>, Box<gemini::Response>) -> error::GempressResult<()>;
struct Layer {
handler: Box<Handler>,
@ -119,16 +121,21 @@ impl Gempress {
///
/// ```
/// use gempress::gemini;
/// use gempress::*;
///
/// let config = gempress::Config::from_identity(PathBuf::from("identity.pfx"), "password".into());
/// let mut app = Gempress::new(config);
///
/// fn index_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) {
/// res.send("Hello from index route!".as_bytes());
/// fn index_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) ->
/// GempressResult<()> {
/// res.send("Hello from index route!".as_bytes())?;
/// Ok(())
/// }
///
/// fn foo_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) {
/// fn foo_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) ->
/// GempressResult<()> {
/// res.send("This is the /foo route".as_bytes());
/// Ok(())
/// }
///
/// app.on("/", &index_handler);
@ -198,15 +205,19 @@ impl Gempress {
let raw_request = String::from_utf8(buffer.to_vec())?;
let request = gemini::Request::parse(&raw_request)?;
let response = gemini::Response::new(stream);
let mut response = gemini::Response::new(stream);
let layer = self
let maybe_layer = self
.stack
.iter()
.find(|&l| l.path == request.url.path())
.unwrap();
.find(|&l| l.path == request.url.path());
response.status(gemini::StatusCode::Success)?;
(layer.handler)(Box::new(request), Box::new(response));
match maybe_layer {
Some(layer) => { (layer.handler)(Box::new(request), Box::new(response)); },
None => { response.status(gemini::StatusCode::NotFound)?.send("Not found".as_bytes()); },
};
Ok(())
}

14
src/main.rs

@ -1,13 +1,23 @@
extern crate gempress;
use gempress::Gempress;
use gempress::error::GempressResult;
use gempress::gemini;
use gempress::gemini::StatusCode;
use std::path::PathBuf;
fn index_handler(req: Box<gemini::Request>, mut res: Box<gemini::Response>) -> GempressResult<()>{
res.status(StatusCode::Success)?.send("Hello from index route!".as_bytes())?;
Ok(())
}
fn main() {
// Run make_cert.sh to generate a certificate
let config = gempress::Config::from_identity(PathBuf::from("identity.pfx"), "qqqq".into());
let config = gempress::Config::from_identity(PathBuf::from("identity.pfx"), "password".into());
let mut app = Gempress::new(config);
let app = Gempress::new(config);
app.on("/", &index_handler);
app.listen(1965, || {
println!("Listening on port 1965");

Loading…
Cancel
Save