From 2cfe9fcb5fc63a31cceed807af573f511d33c374 Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Tue, 2 Nov 2021 14:17:47 -0400 Subject: [PATCH] [web] [WIP] Fix sending OGP tags --- web/assets/default_config.yml | 7 ++++++ web/src/configuration.rs | 10 ++++++++ web/src/main.rs | 47 ++++++++++++++++++++--------------- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/web/assets/default_config.yml b/web/assets/default_config.yml index 7a01e9a..12e6136 100644 --- a/web/assets/default_config.yml +++ b/web/assets/default_config.yml @@ -6,6 +6,13 @@ port: 1312 # The address the server should bind to address: 0.0.0.0 +# The base URL the server will be running under, with no trailing slash +# +# This is also your opportunity to serve requests under a subpath. For example, if you +# want pronouns.today to only run on the /pronouns route of your webserver, you can set +# this to https://example.com/pronouns +base_url: https://pronouns.today + # A list of pronouns recognized by the server # # WARNING: When adding pronouns, only add pronouns to the bottom of the list, and do not diff --git a/web/src/configuration.rs b/web/src/configuration.rs index 558c68e..721e4fe 100644 --- a/web/src/configuration.rs +++ b/web/src/configuration.rs @@ -82,6 +82,11 @@ pub struct Run { /// for warnings when changing this value. formatted as a list of comma seperated /// five-form pronouns, e.g. she/her/her/hers/herself,he/him/his/his/himself pub pronouns: Option, + + #[argh(option, long="base")] + /// the base url content is served under, starting with the protocol (https://) and without a + /// trailing slash + pub base_url: Option, } impl Run { @@ -131,6 +136,9 @@ pub struct Conf { /// The address to bind to. Defaults to 0.0.0.0 pub address: IpAddr, + + /// The base url the server will be running under, with no trailing slash + pub base_url: String, } impl Conf { @@ -138,6 +146,7 @@ impl Conf { self.port = args.port.unwrap_or(self.port); self.address = args.address.unwrap_or(self.address); self.instance_settings.pronoun_list = args.pronouns.map(Into::into).unwrap_or(self.instance_settings.pronoun_list); + self.base_url = args.base_url.unwrap_or(self.base_url); self } } @@ -148,6 +157,7 @@ impl Default for Conf { instance_settings: InstanceSettings::default(), port: 1312, address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), + base_url: "https://pronouns.today".into(), } } } diff --git a/web/src/main.rs b/web/src/main.rs index d1dafa1..7e46dba 100644 --- a/web/src/main.rs +++ b/web/src/main.rs @@ -3,6 +3,7 @@ pub mod contrast; pub mod statics; pub mod configuration; +use crate::configuration::Conf; use std::io::IoSlice; use crate::statics::StaticAsset; use smol::io::AsyncWriteExt; @@ -105,13 +106,13 @@ async fn start_server(config: configuration::Conf, executor: &smol::LocalExecuto let connection = smol::net::TcpListener::bind(socket_addr).await?; let mut incoming = connection.incoming(); - // Make the instance settings immortal - let instance_settings = Box::leak(Box::new(config.instance_settings)); + // Make the configuration immortal + let config = Box::leak(Box::new(config)); while let Some(stream) = incoming.next().await { match stream { Ok(stream) => { - executor.spawn(handle_request(stream, instance_settings)).detach(); + executor.spawn(handle_request(stream, config)).detach(); }, Err(e) => { log::error!("IO Error with client/server connection: {}", e); @@ -135,7 +136,7 @@ async fn start_server(config: configuration::Conf, executor: &smol::LocalExecuto /// - Serialization of the response is done using [`Response::into_bytes()`] async fn handle_request( raw_stream: impl smol::io::AsyncRead + smol::io::AsyncWrite + Unpin, - settings: &InstanceSettings + conf: &Conf, ) { let mut stream = smol::io::BufReader::new(raw_stream); @@ -153,7 +154,7 @@ async fn handle_request( }; let response = route_request(&req) - .generate_response(settings); + .generate_response(conf); let io_slices = response.into_io_slices(); for slice in io_slices { @@ -194,9 +195,10 @@ fn route_request(req: &ScgiRequest) -> Route { _ => return Route::BadRequest(BadRequest::MethodNotAllowed), } - let mut segments: Vec<_> = req.headers + let request_uri = req.headers .get("REQUEST_URI") - .expect("Misconfigured server didn't send a REQUEST_URI header") + .expect("Misconfigured server didn't send a REQUEST_URI header"); + let mut segments: Vec<_> = request_uri .split("/") .filter(|s| s.len() > 0) .collect(); @@ -241,13 +243,14 @@ fn route_request(req: &ScgiRequest) -> Route { (None, Some(_)) => unreachable!(), }; - let response_type = if is_thumb { - Route::SendThumbnail - } else { - Route::SendPronounPage - }; + let name = name.map(|n| (*n).to_owned()); - response_type(name.map(|n| (*n).to_owned()), prefs) + if is_thumb { + Route::SendThumbnail(name, prefs) + } else { + let uri = request_uri.trim_end_matches('/').to_owned(); + Route::SendPronounPage(name, prefs, uri) + } } /// Determines the type of route that the request should be met with, and necessary data @@ -276,8 +279,9 @@ enum Route { /// Respond with an HTML pronoun page. /// /// Takes the user's name (if specified), and the preferences of that user, or - /// [`None`] for defults - SendPronounPage(Option, Option), + /// [`None`] for defults. The third string is the URI of the current page, + /// ending without a / + SendPronounPage(Option, Option, String), /// Respond with an image containing the user's pronouns /// @@ -312,11 +316,12 @@ enum BadRequest { impl Route { /// Actually perform the action that each route entails - fn generate_response(self, settings: &InstanceSettings) -> Response { + fn generate_response(self, conf: &Conf) -> Response { + let settings = &conf.instance_settings; let result = match self { Route::SendStatic(data) => Ok(data.generate_response()), - Route::SendPronounPage(name, prefs) => - Route::send_pronoun_page(name, prefs, settings), + Route::SendPronounPage(name, prefs, url) => + Route::send_pronoun_page(name, prefs, url, conf), Route::SendThumbnail(name, prefs) => Route::send_thumbnail(name, prefs, settings), Route::GenerateLink => @@ -332,15 +337,17 @@ impl Route { fn send_pronoun_page( name: Option, prefs: Option, - settings: &InstanceSettings, + uri: String, + conf: &Conf, ) -> Result { + let settings = &conf.instance_settings; let pronoun = Route::get_pronoun(name.as_ref(), prefs, settings)?; let body = IndexTemplate { name, pronoun, pronouns: settings.pronoun_list.iter().enumerate().collect(), - url: String::new(), //TODO + url: format!("{}{}", &conf.base_url, uri), //TODO } .render() .unwrap();