Skip to content

Commit 88be29b

Browse files
committed
fix: windows paths
1 parent 3087a34 commit 88be29b

File tree

4 files changed

+32
-14
lines changed

4 files changed

+32
-14
lines changed

crates/core/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ pub enum Error {
5858
#[error("invalid datetime: {0}")]
5959
InvalidDatetime(String),
6060

61+
/// A file path could not be converted to a URL.
62+
#[error("invalid file path: {0}")]
63+
InvalidFilePath(String),
64+
6165
/// [std::io::Error]
6266
#[error(transparent)]
6367
Io(#[from] std::io::Error),

crates/core/src/href.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Utilities and structures for working with hrefs.
22
3-
use crate::Result;
3+
use crate::{Error, Result};
44
use std::borrow::Cow;
55
use url::Url;
66

@@ -57,11 +57,21 @@ pub trait SelfHref {
5757
}
5858
}
5959

60+
/// Returns `true` if the href looks like a Windows absolute path (e.g. `C:\foo` or `D:/bar`).
61+
pub fn is_windows_absolute_path(s: &str) -> bool {
62+
let bytes = s.as_bytes();
63+
bytes.len() >= 3
64+
&& bytes[0].is_ascii_alphabetic()
65+
&& bytes[1] == b':'
66+
&& (bytes[2] == b'\\' || bytes[2] == b'/')
67+
}
68+
6069
/// Returns `true` if the href is absolute.
6170
///
62-
/// An href is absolute if it can be parsed to a url or starts with a `/`.
71+
/// An href is absolute if it can be parsed to a url, starts with a `/`, or is
72+
/// a Windows absolute path.
6373
pub fn is_absolute(href: &str) -> bool {
64-
Url::parse(href).is_ok() || href.starts_with('/')
74+
is_windows_absolute_path(href) || Url::parse(href).is_ok() || href.starts_with('/')
6575
}
6676

6777
/// Makes an href absolute relative to a base.
@@ -157,17 +167,15 @@ pub fn make_relative(href: &str, base: &str) -> String {
157167
///
158168
/// Handles adding a `file://` prefix and making it absolute, if needed.
159169
pub fn make_url(href: &str) -> Result<Url> {
160-
if let Ok(url) = Url::parse(href) {
170+
if is_windows_absolute_path(href) || href.starts_with('/') {
171+
Url::from_file_path(href).map_err(|_| Error::InvalidFilePath(href.to_string()))
172+
} else if let Ok(url) = Url::parse(href) {
161173
Ok(url)
162174
} else {
163-
let url = if href.starts_with("/") {
164-
Url::parse(&format!("file://{href}"))
165-
} else {
166-
let current_dir = std::env::current_dir()?;
167-
let url = make_url(&format!("{}/", current_dir.to_string_lossy()))?;
168-
url.join(href)
169-
}?;
170-
Ok(url)
175+
let current_dir = std::env::current_dir()?;
176+
let url = Url::from_directory_path(&current_dir)
177+
.map_err(|_| Error::InvalidFilePath(current_dir.to_string_lossy().into_owned()))?;
178+
Ok(url.join(href)?)
171179
}
172180
}
173181

crates/core/src/migrate.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{Error, Result, Version};
22
use serde::{Serialize, de::DeserializeOwned};
33
use serde_json::{Map, Value};
44
use std::collections::HashMap;
5+
use url::Url;
56

67
/// Migrates a STAC object from one version to another.
78
pub trait Migrate: Sized + Serialize + DeserializeOwned + std::fmt::Debug {
@@ -200,9 +201,11 @@ fn migrate_links(object: &mut Map<String, Value>) {
200201
.map(|s| s == "self")
201202
.unwrap_or_default()
202203
&& let Some(href) = link.get("href").and_then(|v| v.as_str())
203-
&& href.starts_with('/')
204+
&& (href.starts_with('/') || crate::href::is_windows_absolute_path(href))
204205
{
205-
let _ = link.insert("href".to_string(), format!("file://{href}").into());
206+
if let Ok(url) = Url::from_file_path(href) {
207+
let _ = link.insert("href".to_string(), url.to_string().into());
208+
}
206209
}
207210
}
208211
}

crates/io/src/realized_href.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ pub enum RealizedHref {
1313

1414
impl From<&str> for RealizedHref {
1515
fn from(s: &str) -> RealizedHref {
16+
if stac::href::is_windows_absolute_path(s) {
17+
return RealizedHref::PathBuf(PathBuf::from(s));
18+
}
1619
if let Ok(url) = Url::parse(s) {
1720
if url.scheme() == "file" {
1821
url.to_file_path()

0 commit comments

Comments
 (0)