Allow instance_uri configuration value to contain URI scheme

This commit is contained in:
silverpill 2023-02-09 15:37:50 +00:00
parent 4ab95055d6
commit 0b8553d0c2
5 changed files with 69 additions and 18 deletions

View file

@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Changed
- Allow `instance_uri` configuration value to contain URI scheme.
## [1.13.1] - 2023-02-09 ## [1.13.1] - 2023-02-09
### Fixed ### Fixed

View file

@ -5,7 +5,8 @@ web_client_dir: null
http_host: '127.0.0.1' http_host: '127.0.0.1'
http_port: 8380 http_port: 8380
instance_uri: 127.0.0.1:8380 instance_uri: http://127.0.0.1:8380
instance_title: Mitra instance_title: Mitra
instance_short_description: My instance instance_short_description: My instance
instance_description: My instance instance_description: My instance

View file

@ -12,7 +12,8 @@ http_port: 8383
#log_level: info #log_level: info
# Domain name # Domain name
instance_uri: example.tld instance_uri: https://example.tld
instance_title: example instance_title: example
instance_short_description: my instance instance_short_description: my instance
# Long description can contain markdown syntax # Long description can contain markdown syntax

View file

@ -9,7 +9,7 @@ use serde::{
}; };
use url::Url; use url::Url;
use crate::utils::urls::guess_protocol; use crate::utils::urls::normalize_url;
use super::blockchain::BlockchainConfig; use super::blockchain::BlockchainConfig;
use super::environment::Environment; use super::environment::Environment;
@ -78,7 +78,9 @@ pub struct Config {
pub log_level: LogLevel, pub log_level: LogLevel,
// Domain name or <IP address>:<port> // Domain name or <IP address>:<port>
// URI scheme is optional
instance_uri: String, instance_uri: String,
pub instance_title: String, pub instance_title: String,
pub instance_short_description: String, pub instance_short_description: String,
pub instance_description: String, pub instance_description: String,
@ -121,14 +123,7 @@ pub struct Config {
impl Config { impl Config {
pub(super) fn try_instance_url(&self) -> Result<Url, url::ParseError> { pub(super) fn try_instance_url(&self) -> Result<Url, url::ParseError> {
let scheme = match self.environment { normalize_url(&self.instance_uri)
Environment::Development => "http",
Environment::Production => guess_protocol(&self.instance_uri),
};
let url_str = format!("{}://{}", scheme, self.instance_uri);
let url = Url::parse(&url_str)?;
url.host().ok_or(url::ParseError::EmptyHost)?; // validates URL
Ok(url)
} }
pub fn instance(&self) -> Instance { pub fn instance(&self) -> Instance {

View file

@ -1,4 +1,4 @@
use std::net::Ipv6Addr; use std::net::{Ipv4Addr, Ipv6Addr};
use url::{Host, ParseError, Url}; use url::{Host, ParseError, Url};
pub fn get_hostname(url: &str) -> Result<String, ParseError> { pub fn get_hostname(url: &str) -> Result<String, ParseError> {
@ -14,13 +14,13 @@ pub fn get_hostname(url: &str) -> Result<String, ParseError> {
} }
pub fn guess_protocol(hostname: &str) -> &'static str { pub fn guess_protocol(hostname: &str) -> &'static str {
let maybe_ipv6_address = hostname.parse::<Ipv6Addr>(); let maybe_ipv4_address = hostname.parse::<Ipv4Addr>();
if let Ok(ipv6_address) = maybe_ipv6_address { if let Ok(_ipv4_address) = maybe_ipv4_address {
let prefix = ipv6_address.segments()[0];
if (0x0200..=0x03ff).contains(&prefix) {
// Yggdrasil
return "http"; return "http";
}; };
let maybe_ipv6_address = hostname.parse::<Ipv6Addr>();
if let Ok(_ipv6_address) = maybe_ipv6_address {
return "http";
}; };
if hostname.ends_with(".onion") || hostname.ends_with(".i2p") { if hostname.ends_with(".onion") || hostname.ends_with(".i2p") {
// Tor / I2P // Tor / I2P
@ -31,9 +31,36 @@ pub fn guess_protocol(hostname: &str) -> &'static str {
} }
} }
pub fn normalize_url(url: &str) -> Result<Url, url::ParseError> {
let normalized_url = if
url.starts_with("http://") ||
url.starts_with("https://")
{
url.to_string()
} else {
// Add scheme
// Doesn't work for IPv6
let hostname = if let Some((hostname, _port)) = url.split_once(':') {
hostname
} else {
url
};
let url_scheme = guess_protocol(hostname);
format!(
"{}://{}",
url_scheme,
url,
)
};
let url = Url::parse(&normalized_url)?;
url.host().ok_or(ParseError::EmptyHost)?; // validates URL
Ok(url)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_get_hostname() { fn test_get_hostname() {
let url = "https://example.org/objects/1"; let url = "https://example.org/objects/1";
@ -41,6 +68,13 @@ mod tests {
assert_eq!(hostname, "example.org"); assert_eq!(hostname, "example.org");
} }
#[test]
fn test_get_hostname_if_port_number() {
let url = "http://127.0.0.1:8380/objects/1";
let hostname = get_hostname(url).unwrap();
assert_eq!(hostname, "127.0.0.1");
}
#[test] #[test]
fn test_get_hostname_tor() { fn test_get_hostname_tor() {
let url = "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/objects/1"; let url = "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/objects/1";
@ -76,9 +110,25 @@ mod tests {
guess_protocol("zzz.i2p"), guess_protocol("zzz.i2p"),
"http", "http",
); );
// Yggdrasil
assert_eq!( assert_eq!(
guess_protocol("319:3cf0:dd1d:47b9:20c:29ff:fe2c:39be"), guess_protocol("319:3cf0:dd1d:47b9:20c:29ff:fe2c:39be"),
"http", "http",
); );
// localhost
assert_eq!(
guess_protocol("127.0.0.1"),
"http",
);
}
#[test]
fn test_normalize_url() {
let result = normalize_url("https://test.net").unwrap();
assert_eq!(result.to_string(), "https://test.net/");
let result = normalize_url("example.com").unwrap();
assert_eq!(result.to_string(), "https://example.com/");
let result = normalize_url("127.0.0.1:8380").unwrap();
assert_eq!(result.to_string(), "http://127.0.0.1:8380/");
} }
} }