diff --git a/src/lib.rs b/src/lib.rs index 02ba151..1280bba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,6 +77,7 @@ struct ServerInner { routes: Arc>, timeout: Duration, complex_timeout: Option, + autorewrite: bool, #[cfg(feature="ratelimiting")] rate_limits: Arc>>, #[cfg(feature="user_management")] @@ -206,13 +207,22 @@ impl ServerInner { request.set_cert(client_cert); } - let response = if let Some((trailing, handler)) = self.routes.match_request(&request) { + let mut response = if let Some((trailing, handler)) = self.routes.match_request(&request) { request.set_trailing(trailing); - handler.handle(request).await + handler.handle(request.clone()).await } else { Response::not_found() }; + match response.rewrite_all(&request).await { + Ok(true) => { /* all is well */ } + Ok(false) => panic!("Upstream did not include SCRIPT_PATH or SCRIPT_NAME"), + Err(e) => { + error!("Error reading text/gemini file from Response reader: {}", e); + response = Response::not_found(); + } + } + self.send_response(response, &mut stream).await .context("Failed to send response")?; @@ -417,6 +427,7 @@ pub struct Server { timeout: Duration, complex_body_timeout_override: Option, routes: RoutingNode, + autorewrite: bool, #[cfg(feature = "gemini_srv")] cert_path: PathBuf, #[cfg(feature = "gemini_srv")] @@ -437,6 +448,7 @@ impl Server { timeout: Duration::from_secs(1), complex_body_timeout_override: Some(Duration::from_secs(30)), routes: RoutingNode::default(), + autorewrite: false, #[cfg(feature = "gemini_srv")] cert_path: PathBuf::from("cert/cert.pem"), #[cfg(feature = "gemini_srv")] @@ -621,6 +633,24 @@ impl Server { self } + /// Enable or disable autorewrite + /// + /// Autorewrite automatically detects links in responses being sent out through kochab + /// and rewrites them to match the base of the script. For example, if the script is + /// mounted on "/app", any links to "/page" would be rewritten as "/app/page". This + /// does nothing when in `gemini_srv` mode. + /// + /// **Note:** If you are serving *very long* `text/gemini` files using `serve_dir`, + /// then you should avoid setting this to true. Additionally, if using this option, + /// do not try to rewrite your links using [`Request::rewrite_path`] or + /// [`Response::rewrite_all`], as this will apply the rewrite twice. + /// + /// For more information about rewriting, see [`Request::rewrite_path`]. + pub fn set_autorewrite(mut self, autorewrite: bool) -> Self { + self.autorewrite = autorewrite; + self + } + fn build(mut self) -> Result { #[cfg(feature = "gemini_srv")] let config = tls_config( @@ -639,6 +669,7 @@ impl Server { routes: Arc::new(self.routes), timeout: self.timeout, complex_timeout: self.complex_body_timeout_override, + autorewrite: self.autorewrite, #[cfg(feature = "gemini_srv")] tls_acceptor: TlsAcceptor::from(config), #[cfg(feature="ratelimiting")] diff --git a/src/types/request.rs b/src/types/request.rs index f12367b..ba7ec49 100644 --- a/src/types/request.rs +++ b/src/types/request.rs @@ -17,6 +17,7 @@ use ring::digest; #[cfg(feature="user_management")] use crate::user_management::{UserManager, User}; +#[derive(Clone)] pub struct Request { uri: URIReference<'static>, input: Option,