Skip to content

Commit 3c09b62

Browse files
committed
fix: base url validation
Signed-off-by: Rahul Baradol <[email protected]>
1 parent db2e2ba commit 3c09b62

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

crates/ofrep/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ thiserror = "2.0"
2222
anyhow = "1.0.98"
2323
chrono = "0.4"
2424
once_cell = "1.18"
25-
tokio = { version = "1.45", features = ["full"] }
25+
tokio = { version = "1.45", features = ["full"] }
26+
url = "2.5.4"

crates/ofrep/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use thiserror::Error;
22

3-
#[derive(Error, Debug)]
3+
#[derive(Error, Debug, PartialEq)]
44
pub enum OfrepError {
55
#[error("Provider error: {0}")]
66
Provider(String),

crates/ofrep/src/lib.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ use open_feature::provider::{FeatureProvider, ProviderMetadata, ResolutionDetail
66
use open_feature::{EvaluationContext, EvaluationError, StructValue};
77
use reqwest::header::HeaderMap;
88
use resolver::Resolver;
9+
use std::fmt;
910
use std::sync::Arc;
1011
use std::time::Duration;
1112
use tracing::debug;
1213
use tracing::instrument;
14+
use url::Url;
1315

1416
use async_trait::async_trait;
1517

@@ -37,10 +39,30 @@ pub struct OfrepProvider {
3739
provider: Arc<dyn FeatureProvider + Send + Sync>,
3840
}
3941

42+
impl fmt::Debug for OfrepProvider {
43+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44+
f.debug_struct("OfrepProvider")
45+
.field("provider", &"<FeatureProvider>")
46+
.finish()
47+
}
48+
}
49+
4050
impl OfrepProvider {
4151
#[instrument(skip(options))]
4252
pub async fn new(options: OfrepOptions) -> Result<Self, OfrepError> {
4353
debug!("Initializing OfrepProvider with options: {:?}", options);
54+
55+
let url = Url::parse(&options.base_url).map_err(|e| {
56+
OfrepError::Config(format!("Invalid base url: '{}' ({})", options.base_url, e))
57+
})?;
58+
59+
if !matches!(url.scheme(), "http" | "https") {
60+
return Err(OfrepError::Config(format!(
61+
"Invalid base url: '{}' (unsupported scheme)",
62+
url.scheme()
63+
)));
64+
}
65+
4466
Ok(Self {
4567
provider: Arc::new(Resolver::new(&options)),
4668
})
@@ -93,3 +115,36 @@ impl FeatureProvider for OfrepProvider {
93115
self.provider.resolve_struct_value(flag_key, context).await
94116
}
95117
}
118+
119+
#[cfg(test)]
120+
mod tests {
121+
use super::*;
122+
use test_log::test;
123+
124+
#[test(tokio::test)]
125+
async fn test_ofrep_options_validation() {
126+
let provider_with_empty_host = OfrepProvider::new(OfrepOptions {
127+
base_url: "http://".to_string(),
128+
..Default::default()
129+
})
130+
.await;
131+
132+
let provider_with_invalid_scheme = OfrepProvider::new(OfrepOptions {
133+
base_url: "invalid://".to_string(),
134+
..Default::default()
135+
})
136+
.await;
137+
138+
assert!(provider_with_empty_host.is_err());
139+
assert!(provider_with_invalid_scheme.is_err());
140+
141+
assert_eq!(
142+
provider_with_empty_host.unwrap_err(),
143+
OfrepError::Config("Invalid base url: 'http://' (empty host)".to_string())
144+
);
145+
assert_eq!(
146+
provider_with_invalid_scheme.unwrap_err(),
147+
OfrepError::Config("Invalid base url: 'invalid' (unsupported scheme)".to_string())
148+
);
149+
}
150+
}

0 commit comments

Comments
 (0)