servo / rust-url

URL parser for Rust
https://docs.rs/url/
Apache License 2.0
1.27k stars 317 forks source link

`Url::from_file_path()` incorrect handling of backslash on linux #901

Closed nayeemrmn closed 5 months ago

nayeemrmn commented 5 months ago

Also affects Url::from_directory_path().

Backslashes in paths get left as-is. They should be percent-encoded to %5C. Currently that backslash would change to a forward-slash if the output were to be stringified and re-parsed with Url::parse(). See the following roundtrip:

fn main() {
  let path = std::path::PathBuf::from("/a/b/c\\d");
  let url = url::Url::from_file_path(&path).unwrap();
  println!("{}", url.as_str()); // file:///a/b/c\d
  let url2 = url::Url::parse(url.as_str()).unwrap();
  println!("{}", url2.as_str()); // file:///a/b/c/d
  let path2 = url2.to_file_path().unwrap();
  println!("{}", path2.display()); // /a/b/c/d
  //                         Expected /a/b/c\d
}

Expected:

fn main() {
  let path = std::path::PathBuf::from("/a/b/c\\d");
  let url = url::Url::from_file_path(&path).unwrap();
  println!("{}", url.as_str()); // file:///a/b/c%5Cd
  let url2 = url::Url::parse(url.as_str()).unwrap();
  println!("{}", url2.as_str()); // file:///a/b/c%5Cd
  let path2 = url2.to_file_path().unwrap();
  println!("{}", path2.display()); // /a/b/c\d
}

On Windows they get swapped to forward-slashes, which is correct for Windows.