diff --git a/src/server/endpoint.rs b/src/server/endpoint.rs index 421b1d9..7ea4487 100644 --- a/src/server/endpoint.rs +++ b/src/server/endpoint.rs @@ -188,10 +188,21 @@ impl EndpointParam { } fn get_base(req: &Parts) -> Option { + if let Some(url) = Self::base_from_env().as_ref() { + return Some(url.clone()); + } + + if let Some(url) = Self::base_from_reverse_proxy(req) { + return Some(url); + } + + Self::base_from_host(req) + } + + fn base_from_reverse_proxy(req: &Parts) -> Option { let host = req .headers .get("X-Forwarded-Host") - .or_else(|| req.headers.get(HOST)) .and_then(|x| x.to_str().ok())?; let proto = req @@ -204,6 +215,27 @@ impl EndpointParam { let base = base.parse().ok()?; Some(base) } + + fn base_from_host(req: &Parts) -> Option { + let host = req.headers.get(HOST)?.to_str().ok()?; + let base = format!("http://{}/", host); + let base = base.parse().ok()?; + Some(base) + } + + fn base_from_env() -> &'static Option { + use std::env; + use std::sync::OnceLock; + + static APP_BASE_URL: OnceLock> = OnceLock::new(); + APP_BASE_URL.get_or_init(|| { + let var = env::var("RSS_FUNNEL_APP_BASE").ok(); + var.map(|v| { + v.parse() + .expect("Invalid base url specified in RSS_FUNNEL_APP_BASE") + }) + }) + } } impl Service for EndpointService { diff --git a/src/server/web.rs b/src/server/web.rs index 62d2d97..29bbc9b 100644 --- a/src/server/web.rs +++ b/src/server/web.rs @@ -5,7 +5,7 @@ mod login; use std::borrow::Cow; use axum::{ - extract::{rejection::QueryRejection, Path, Query}, + extract::Path, response::{IntoResponse, Redirect, Response}, routing, Extension, Router, }; @@ -70,14 +70,13 @@ async fn handle_endpoint( _: Auth, Path(path): Path, Extension(service): Extension, - param: Result, QueryRejection>, + param: EndpointParam, ) -> Result { let endpoint = service.get_endpoint(&path).await.ok_or_else(|| { (StatusCode::NOT_FOUND, format!("Endpoint {path} not found")) .into_response() })?; - let param = param.map(|q| q.0).map_err(|e| e.body_text()); Ok(endpoint::render_endpoint_page(endpoint, path, param).await) } diff --git a/src/server/web/endpoint.rs b/src/server/web/endpoint.rs index c9ec9d1..b3d47f1 100644 --- a/src/server/web/endpoint.rs +++ b/src/server/web/endpoint.rs @@ -13,25 +13,17 @@ use crate::{ pub async fn render_endpoint_page( endpoint: EndpointService, path: String, - param: Result, + param: EndpointParam, ) -> Markup { // render source control let source = source_control_fragment(&path, endpoint.source(), ¶m); // render config - let config = render_config_fragment(&path, param.as_ref().ok(), &endpoint); + let config = render_config_fragment(&path, ¶m, &endpoint); let config_tags = render_config_header_tags(&endpoint); // render normalized feed - let feed = match param { - Ok(param) => fetch_and_render_feed(endpoint, param).await, - Err(e) => html! { - div .flash.error { - header { b { "Invalid request params" } } - p { (e) } - } - }, - }; + let feed = fetch_and_render_feed(endpoint, param).await; html! { (DOCTYPE) @@ -91,7 +83,7 @@ pub async fn render_endpoint_page( fn source_control_fragment( path: &str, source: &Source, - param: &Result, + param: &EndpointParam, ) -> Markup { match source { Source::Dynamic => html! { @@ -100,7 +92,7 @@ fn source_control_fragment( type="text" name="source" placeholder="Source URL" - value=[param.as_ref().ok().and_then(|p| p.source()).map(|url| url.as_str())] + value=[param.source().map(|url| url.as_str())] hx-get=(format!("/_/endpoint/{path}")) hx-trigger="keyup changed delay:500ms" hx-push-url="true" @@ -114,7 +106,7 @@ fn source_control_fragment( Source::RelativeUrl(url) => html! {div title="Source" .source { (url) }}, Source::Templated(templated) => html! { div .source-template-container { - @let queries = param.as_ref().ok().map(|p| p.extra_queries()); + @let queries = param.extra_queries(); (source_template_fragment(templated, path, queries)); } }, @@ -154,14 +146,14 @@ fn from_scratch_fragment(scratch: &FromScratch) -> Markup { fn source_template_fragment( templated: &crate::source::Templated, path: &str, - queries: Option<&HashMap>, + queries: &HashMap, ) -> Markup { html! { @for fragment in templated.fragments() { @match fragment { Either::Left(plain) => span style="white-space: nowrap" { (plain) }, Either::Right((name, Some(placeholder))) => { - @let value=queries.and_then(|q| q.get(name)); + @let value=queries.get(name); @let default_value=placeholder.default.as_ref(); @let value=value.or(default_value); @let validation=placeholder.validation.as_ref(); @@ -203,12 +195,12 @@ fn render_config_header_tags(endpoint: &EndpointService) -> Markup { fn render_config_fragment( path: &str, - param: Option<&EndpointParam>, + param: &EndpointParam, endpoint: &EndpointService, ) -> Markup { let config = endpoint.config(); let filter_enabled = |i| { - if let Some(f) = param.and_then(|p| p.filter_skip()) { + if let Some(f) = param.filter_skip() { f.allows_filter(i) as u8 } else { true as u8