|
1 | 1 | //! Utilities and structures for working with hrefs. |
2 | 2 |
|
3 | | -use crate::Result; |
| 3 | +use crate::{Error, Result}; |
4 | 4 | use std::borrow::Cow; |
5 | 5 | use url::Url; |
6 | 6 |
|
@@ -57,11 +57,21 @@ pub trait SelfHref { |
57 | 57 | } |
58 | 58 | } |
59 | 59 |
|
| 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 | + |
60 | 69 | /// Returns `true` if the href is absolute. |
61 | 70 | /// |
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. |
63 | 73 | 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('/') |
65 | 75 | } |
66 | 76 |
|
67 | 77 | /// Makes an href absolute relative to a base. |
@@ -157,17 +167,15 @@ pub fn make_relative(href: &str, base: &str) -> String { |
157 | 167 | /// |
158 | 168 | /// Handles adding a `file://` prefix and making it absolute, if needed. |
159 | 169 | 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) { |
161 | 173 | Ok(url) |
162 | 174 | } 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(¤t_dir) |
| 177 | + .map_err(|_| Error::InvalidFilePath(current_dir.to_string_lossy().into_owned()))?; |
| 178 | + Ok(url.join(href)?) |
171 | 179 | } |
172 | 180 | } |
173 | 181 |
|
|
0 commit comments