Skip to content

Commit

Permalink
urlapi: UNC paths in file: URLs on Windows
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
sergio-nsk committed Aug 22, 2021
1 parent 26c002b commit 8d52e2b
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 6 deletions.
40 changes: 34 additions & 6 deletions lib/urlapi.c
Expand Up @@ -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;
Expand Down Expand Up @@ -799,7 +800,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;
Expand All @@ -821,10 +821,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
Expand All @@ -833,18 +836,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:" */
Expand Down
Binary file modified tests/data/test2080
Binary file not shown.
4 changes: 4 additions & 0 deletions tests/libtest/lib1560.c
Expand Up @@ -187,6 +187,10 @@ static 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] | "
Expand Down

0 comments on commit 8d52e2b

Please sign in to comment.