diff options
author | Sergey Markelov <sergey@solidstatenetworks.com> | 2021-09-27 08:31:52 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2021-09-27 08:32:41 +0200 |
commit | 4b997626b1182a8a7d974f2957b3ad8eaebd8817 (patch) | |
tree | 0e890625cd24507956daa73feed58eb1ed40e230 | |
parent | 3363eeb26298b9d30fc5ec29101e5dd205d04db9 (diff) | |
download | curl-4b997626b1182a8a7d974f2957b3ad8eaebd8817.tar.gz |
urlapi: support UNC paths in file: URLs on Windows
- file://host.name/path/file.txt is a valid UNC path
\\host.name\path\files.txt to a non-local file transformed into URI
(RFC 8089 Appendix E.3)
- UNC paths on other OSs must be smb: URLs
Closes #7366
-rw-r--r-- | lib/urlapi.c | 40 | ||||
-rw-r--r-- | tests/data/test2080 | bin | 20673 -> 20675 bytes | |||
-rw-r--r-- | tests/libtest/lib1560.c | 4 |
3 files changed, 38 insertions, 6 deletions
diff --git a/lib/urlapi.c b/lib/urlapi.c index 7f03862cf..59123ed57 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -760,6 +760,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) { char *path; bool path_alloced = FALSE; + bool uncpath = FALSE; char *hostname; char *query = NULL; char *fragment = NULL; @@ -798,7 +799,6 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) /* path has been allocated large enough to hold this */ strcpy(path, &url[5]); - hostname = NULL; /* no host for file: URLs */ u->scheme = strdup("file"); if(!u->scheme) return CURLUE_OUT_OF_MEMORY; @@ -820,10 +820,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) * * o the hostname matches "localhost" (case-insensitively), or * - * o the hostname is a FQDN that resolves to this machine. + * o the hostname is a FQDN that resolves to this machine, or + * + * o it is an UNC String transformed to an URI (Windows only, RFC 8089 + * Appendix E.3). * * For brevity, we only consider URLs with empty, "localhost", or - * "127.0.0.1" hostnames as local. + * "127.0.0.1" hostnames as local, otherwise as an UNC String. * * Additionally, there is an exception for URLs with a Windows drive * letter in the authority (which was accidentally omitted from RFC 8089 @@ -832,18 +835,43 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) { /* the URL includes a host name, it must match "localhost" or "127.0.0.1" to be valid */ - if(!checkprefix("localhost/", ptr) && - !checkprefix("127.0.0.1/", ptr)) { + if(checkprefix("localhost/", ptr) || + checkprefix("127.0.0.1/", ptr)) { + ptr += 9; /* now points to the slash after the host */ + } + else { +#if defined(WIN32) + size_t len; + + /* the host name, NetBIOS computer name, can not contain disallowed + chars, and the delimiting slash character must be appended to the + host name */ + path = strpbrk(ptr, "/\\:*?\"<>|"); + if(!path || *path != '/') + return CURLUE_MALFORMED_INPUT; + + len = path - ptr; + if(len) { + memcpy(hostname, ptr, len); + hostname[len] = 0; + uncpath = TRUE; + } + + ptr -= 2; /* now points to the // before the host in UNC */ +#else /* Invalid file://hostname/, expected localhost or 127.0.0.1 or none */ return CURLUE_MALFORMED_INPUT; +#endif } - ptr += 9; /* now points to the slash after the host */ } path = ptr; } + if(!uncpath) + hostname = NULL; /* no host for file: URLs by default */ + #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) /* Don't allow Windows drive letters when not in Windows. * This catches both "file:/c:" and "file:c:" */ diff --git a/tests/data/test2080 b/tests/data/test2080 Binary files differindex 9a337031d..9c8d538fc 100644 --- a/tests/data/test2080 +++ b/tests/data/test2080 diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index 3d341ddb4..f7529592c 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -187,6 +187,10 @@ static const struct testcase get_parts_list[] ={ {"file:///C:\\programs\\foo", "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]", CURLU_DEFAULT_SCHEME, 0, CURLUE_OK}, + {"file://host.example.com/Share/path/to/file.txt", + "file | [11] | [12] | [13] | host.example.com | [15] | " + "//host.example.com/Share/path/to/file.txt | [16] | [17]", + CURLU_DEFAULT_SCHEME, 0, CURLUE_OK}, #endif {"https://example.com/color/#green?no-red", "https | [11] | [12] | [13] | example.com | [15] | /color/ | [16] | " |