Merge pull request #17 from ben1009/feat/support-file-urls

feat: support file:// URL scheme for local HTML testing
This commit is contained in:
h4ckf0r0day authored and GitHub committed 2026-04-25 12:36:57 +02:00
commit 00ee2db9cb
2 files changed
+51 -4

No files matched your search

+6 -2
View File
@@ -551,13 +551,17 @@ fn glob_match(pattern: &str, url: &str) -> bool {
fn validate_fetch_url(url: &url::Url) -> Result<(), String> {
let scheme = url.scheme();
if scheme != "http" && scheme != "https" {
if scheme != "http" && scheme != "https" && scheme != "file" {
return Err(format!(
"Forbidden URL scheme '{}' - only http and https are allowed",
"Forbidden URL scheme '{}' - only http, https, and file are allowed",
scheme
));
}
if scheme == "file" {
return Ok(());
}
if let Some(host) = url.host() {
match host {
url::Host::Ipv4(ip) => {
+45 -2
View File
@@ -66,13 +66,17 @@ pub type ResponseCallback = Arc<dyn Fn(&RequestInfo, &Response) + Send + Sync>;
fn validate_url(url: &Url) -> Result<(), ObscuraNetError> {
let scheme = url.scheme();
if scheme != "http" && scheme != "https" {
if scheme != "http" && scheme != "https" && scheme != "file" {
return Err(ObscuraNetError::Network(format!(
"Forbidden URL scheme '{}' - only http and https are allowed",
"Forbidden URL scheme '{}' - only http, https, and file are allowed",
scheme
)));
}
if scheme == "file" {
return Ok(());
}
if let Some(host) = url.host() {
match host {
url::Host::Ipv4(ip) => {
@@ -115,6 +119,41 @@ fn validate_url(url: &Url) -> Result<(), ObscuraNetError> {
Ok(())
}
async fn fetch_file_url(url: &Url) -> Result<Response, ObscuraNetError> {
let path = url
.to_file_path()
.map_err(|_| ObscuraNetError::Network("Invalid file URL".to_string()))?;
let body = tokio::fs::read(&path)
.await
.map_err(|e| ObscuraNetError::Network(format!("Failed to read file: {}", e)))?;
let mut headers = HashMap::new();
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
let ct = match ext.to_lowercase().as_str() {
"html" | "htm" => "text/html",
"css" => "text/css",
"js" | "mjs" => "application/javascript",
"json" => "application/json",
"png" => "image/png",
"jpg" | "jpeg" => "image/jpeg",
"gif" => "image/gif",
"svg" => "image/svg+xml",
"webp" => "image/webp",
"ico" => "image/x-icon",
_ => "application/octet-stream",
};
headers.insert("content-type".to_string(), ct.to_string());
}
Ok(Response {
url: url.clone(),
status: 200,
headers,
body,
redirected_from: Vec::new(),
})
}
pub struct ObscuraHttpClient {
client: tokio::sync::OnceCell<Client>,
proxy_url: Option<String>,
@@ -190,6 +229,10 @@ impl ObscuraHttpClient {
) -> Result<Response, ObscuraNetError> {
validate_url(url)?;
if url.scheme() == "file" {
return fetch_file_url(url).await;
}
let mut method = initial_method;
let mut body = initial_body;
if self.block_trackers {