Просмотр исходного кода

Windows UNC paths: parse host and percent-encode share name

Simon Sapin 9 лет назад
Родитель
Сommit
1ec057f79f
2 измененных файлов с 20 добавлено и 9 удалено
  1. 8 6
      src/lib.rs
  2. 12 3
      tests/unit.rs

+ 8 - 6
src/lib.rs

@@ -1785,22 +1785,24 @@ fn path_to_file_url_segments_windows(path: &Path, serialization: &mut String)
     let mut components = path.components();
     let mut components = path.components();
 
 
     let host_end;
     let host_end;
-    let host;
+    let host_internal;
     match components.next() {
     match components.next() {
         Some(Component::Prefix(ref p)) => match p.kind() {
         Some(Component::Prefix(ref p)) => match p.kind() {
             Prefix::Disk(letter) | Prefix::VerbatimDisk(letter) => {
             Prefix::Disk(letter) | Prefix::VerbatimDisk(letter) => {
                 host_end = to_u32(serialization.len()).unwrap();
                 host_end = to_u32(serialization.len()).unwrap();
-                host = HostInternal::None;
+                host_internal = HostInternal::None;
                 serialization.push('/');
                 serialization.push('/');
                 serialization.push(letter as char);
                 serialization.push(letter as char);
                 serialization.push(':');
                 serialization.push(':');
             },
             },
             Prefix::UNC(server, share) | Prefix::VerbatimUNC(server, share) => {
             Prefix::UNC(server, share) | Prefix::VerbatimUNC(server, share) => {
-                serialization.push_str(server.to_str().ok_or(())?);
+                let host = Host::parse(server.to_str().ok_or(())?).map_err(|_| ())?;
+                write!(serialization, "{}", host).unwrap();
                 host_end = to_u32(serialization.len()).unwrap();
                 host_end = to_u32(serialization.len()).unwrap();
-                host = HostInternal::Domain;  // FIXME: Can this be an IP address?
+                host_internal = host.into();
                 serialization.push('/');
                 serialization.push('/');
-                serialization.push_str(share.to_str().ok_or(())?);
+                let share = share.to_str().ok_or(())?;
+                serialization.extend(percent_encode(share.as_bytes(), PATH_SEGMENT_ENCODE_SET));
             },
             },
             _ => return Err(())
             _ => return Err(())
         },
         },
@@ -1815,7 +1817,7 @@ fn path_to_file_url_segments_windows(path: &Path, serialization: &mut String)
         serialization.push('/');
         serialization.push('/');
         serialization.extend(percent_encode(component.as_bytes(), PATH_SEGMENT_ENCODE_SET));
         serialization.extend(percent_encode(component.as_bytes(), PATH_SEGMENT_ENCODE_SET));
     }
     }
-    Ok((host_end, host))
+    Ok((host_end, host_internal))
 }
 }
 
 
 #[cfg(any(unix, target_os = "redox"))]
 #[cfg(any(unix, target_os = "redox"))]

+ 12 - 3
tests/unit.rs

@@ -415,14 +415,23 @@ fn test_origin_hash() {
     assert_ne!(hash(&opaque_origin), hash(&other_opaque_origin));
     assert_ne!(hash(&opaque_origin), hash(&other_opaque_origin));
 }
 }
 
 
-#[cfg(windows)]
 #[test]
 #[test]
 fn test_windows_unc_path() {
 fn test_windows_unc_path() {
+    if !cfg!(windows) {
+        return
+    }
+
     let url = Url::from_file_path(Path::new(r"\\host\share\path\file.txt")).unwrap();
     let url = Url::from_file_path(Path::new(r"\\host\share\path\file.txt")).unwrap();
     assert_eq!(url.as_str(), "file://host/share/path/file.txt");
     assert_eq!(url.as_str(), "file://host/share/path/file.txt");
 
 
+    let url = Url::from_file_path(Path::new(r"\\höst\share\path\file.txt")).unwrap();
+    assert_eq!(url.as_str(), "file://xn--hst-sna/share/path/file.txt");
+
+    let url = Url::from_file_path(Path::new(r"\\192.168.0.1\share\path\file.txt")).unwrap();
+    assert_eq!(url.host(), Some(Host::Ipv4(Ipv4Addr::new(192, 168, 0, 1))));
+
     let path = url.to_file_path().unwrap();
     let path = url.to_file_path().unwrap();
-    assert_eq!(path.to_str(), Some(r"\\host\share\path\file.txt"));
+    assert_eq!(path.to_str(), Some(r"\\192.168.0.1\share\path\file.txt"));
 
 
     // Another way to write these:
     // Another way to write these:
     let url = Url::from_file_path(Path::new(r"\\?\UNC\host\share\path\file.txt")).unwrap();
     let url = Url::from_file_path(Path::new(r"\\?\UNC\host\share\path\file.txt")).unwrap();
@@ -431,4 +440,4 @@ fn test_windows_unc_path() {
     // Paths starting with "\\.\" (Local Device Paths) are intentionally not supported.
     // Paths starting with "\\.\" (Local Device Paths) are intentionally not supported.
     let url = Url::from_file_path(Path::new(r"\\.\some\path\file.txt"));
     let url = Url::from_file_path(Path::new(r"\\.\some\path\file.txt"));
     assert!(url.is_err());
     assert!(url.is_err());
-}
+}