[PATCH 3/4] kernelbase: Do not parse username, password, and port separately for file URLs in UrlGetPart().

Zebediah Figura zfigura at codeweavers.com
Tue Mar 22 23:28:02 CDT 2022


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/kernelbase/path.c   | 109 +++++++++++++++++++++------------------
 dlls/shlwapi/tests/url.c |  16 +++---
 2 files changed, 68 insertions(+), 57 deletions(-)

diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index 917fd644770..fbe4728efda 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -72,6 +72,7 @@ struct parsed_url
     DWORD port_len;        /* [out] size of Port (until "/" or eos)     */
     const WCHAR *query;    /* [out] start of Query                      */
     DWORD query_len;       /* [out] size of Query (until eos)           */
+    DWORD scheme_number;
 };
 
 static WCHAR *heap_strdupAtoW(const char *str)
@@ -4201,49 +4202,69 @@ static void parse_url( const WCHAR *url, struct parsed_url *pl )
     if (work < url + 2 || *work != ':') return;
     pl->scheme_len = work - pl->scheme;
     work++;
+    pl->scheme_number = get_scheme_code(pl->scheme, pl->scheme_len);
     if (!is_slash( work[0] ) || !is_slash( work[1] ))
         return;
+    work += 2;
 
-    pl->username = work + 2;
-    work = parse_url_element( pl->username, L":@/\\?#" );
-    pl->username_len = work - pl->username;
-    if (*work == ':')
+    if (pl->scheme_number != URL_SCHEME_FILE)
     {
-        pl->password = work + 1;
-        work = parse_url_element( pl->password, L"@/\\?#" );
-        pl->password_len = work - pl->password;
-        if (*work != '@')
+        pl->username = work;
+        work = parse_url_element( pl->username, L":@/\\?#" );
+        pl->username_len = work - pl->username;
+        if (*work == ':')
         {
-            /* what we just parsed must be the hostname and port
-             * so reset pointers and clear then let it parse */
+            pl->password = work + 1;
+            work = parse_url_element( pl->password, L"@/\\?#" );
+            pl->password_len = work - pl->password;
+            if (*work == '@')
+            {
+                work++;
+            }
+            else
+            {
+                /* what we just parsed must be the hostname and port
+                 * so reset pointers and clear then let it parse */
+                pl->username_len = pl->password_len = 0;
+                work = pl->username;
+                pl->username = pl->password = 0;
+            }
+        }
+        else if (*work == '@')
+        {
+            /* no password */
+            pl->password_len = 0;
+            pl->password = 0;
+            work++;
+        }
+        else
+        {
+            /* what was parsed was hostname, so reset pointers and let it parse */
             pl->username_len = pl->password_len = 0;
-            work = pl->username - 1;
+            work = pl->username;
             pl->username = pl->password = 0;
         }
     }
-    else if (*work == '@')
+
+    pl->hostname = work;
+    if (pl->scheme_number == URL_SCHEME_FILE)
     {
-        /* no password */
-        pl->password_len = 0;
-        pl->password = 0;
+        work = parse_url_element( pl->hostname, L"/\\?#" );
+        pl->hostname_len = work - pl->hostname;
+        if (pl->hostname_len >= 2 && pl->hostname[1] == ':')
+            pl->hostname_len = 0;
     }
     else
     {
-        /* what was parsed was hostname, so reset pointers and let it parse */
-        pl->username_len = pl->password_len = 0;
-        work = pl->username - 1;
-        pl->username = pl->password = 0;
-    }
+        work = parse_url_element( pl->hostname, L":/\\?#" );
+        pl->hostname_len = work - pl->hostname;
 
-    pl->hostname = work + 1;
-    work = parse_url_element( pl->hostname, L":/\\?#" );
-    pl->hostname_len = work - pl->hostname;
-
-    if (*work == ':')
-    {
-        pl->port = work + 1;
-        work = parse_url_element( pl->port, L"/\\?#" );
-        pl->port_len = work - pl->port;
+        if (*work == ':')
+        {
+            pl->port = work + 1;
+            work = parse_url_element( pl->port, L"/\\?#" );
+            pl->port_len = work - pl->port;
+        }
     }
 
     if ((pl->query = wcschr( work, '?' )))
@@ -4255,26 +4276,19 @@ static void parse_url( const WCHAR *url, struct parsed_url *pl )
 
 HRESULT WINAPI UrlGetPartW(const WCHAR *url, WCHAR *out, DWORD *out_len, DWORD part, DWORD flags)
 {
-    DWORD scheme, size, schsize;
     LPCWSTR addr, schaddr;
     struct parsed_url pl;
+    DWORD size, schsize;
 
     TRACE("%s, %p, %p(%ld), %#lx, %#lx\n", wine_dbgstr_w(url), out, out_len, *out_len, part, flags);
 
     if (!url || !out || !out_len || !*out_len)
         return E_INVALIDARG;
 
-    addr = wcschr(url, ':');
-    if (!addr)
-        scheme = URL_SCHEME_UNKNOWN;
-    else
-        scheme = get_scheme_code(url, addr - url);
-
     parse_url(url, &pl);
 
-    switch (scheme)
+    switch (pl.scheme_number)
     {
-        case URL_SCHEME_FILE:
         case URL_SCHEME_FTP:
         case URL_SCHEME_GOPHER:
         case URL_SCHEME_HTTP:
@@ -4285,6 +4299,11 @@ HRESULT WINAPI UrlGetPartW(const WCHAR *url, WCHAR *out, DWORD *out_len, DWORD p
         case URL_SCHEME_SNEWS:
             break;
 
+        case URL_SCHEME_FILE:
+            if (part != URL_PART_SCHEME && part != URL_PART_QUERY && part != URL_PART_HOSTNAME)
+                return E_FAIL;
+            break;
+
         default:
             if (part != URL_PART_SCHEME && part != URL_PART_QUERY)
                 return E_FAIL;
@@ -4299,16 +4318,8 @@ HRESULT WINAPI UrlGetPartW(const WCHAR *url, WCHAR *out, DWORD *out_len, DWORD p
         break;
 
     case URL_PART_HOSTNAME:
-        if (scheme == URL_SCHEME_FILE && (!pl.hostname_len || (pl.hostname_len == 1 && *(pl.hostname + 1) == ':')))
-        {
-            addr = NULL;
-            size = 0;
-        }
-        else
-        {
-            addr = pl.hostname;
-            size = pl.hostname_len;
-        }
+        addr = pl.hostname;
+        size = pl.hostname_len;
         break;
 
     case URL_PART_USERNAME:
@@ -4342,7 +4353,7 @@ HRESULT WINAPI UrlGetPartW(const WCHAR *url, WCHAR *out, DWORD *out_len, DWORD p
         return E_INVALIDARG;
     }
 
-    if (flags == URL_PARTFLAG_KEEPSCHEME && scheme != URL_SCHEME_FILE)
+    if (flags == URL_PARTFLAG_KEEPSCHEME && pl.scheme_number != URL_SCHEME_FILE)
     {
         if (!pl.scheme || !pl.scheme_len)
             return E_FAIL;
diff --git a/dlls/shlwapi/tests/url.c b/dlls/shlwapi/tests/url.c
index fb3df96e13d..7cf7097a9ba 100644
--- a/dlls/shlwapi/tests/url.c
+++ b/dlls/shlwapi/tests/url.c
@@ -596,7 +596,7 @@ static void test_UrlGetPart(void)
         DWORD flags;
         HRESULT hr;
         const char *expect;
-        BOOL todo_hr, todo_result;
+        BOOL todo_hr;
     }
     tests[] =
     {
@@ -684,10 +684,10 @@ static void test_UrlGetPart(void)
         {"http:///index.html", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:"},
         {"file://h o s t/c:/windows/file", URL_PART_HOSTNAME, 0, S_OK, "h o s t"},
         {"file://h o s t/c:/windows/file", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "h o s t"},
-        {"file://foo:bar@localhost:21/file?query=x", URL_PART_USERNAME, 0, E_FAIL, .todo_hr = TRUE},
-        {"file://foo:bar@localhost:21/file?query=x", URL_PART_PASSWORD, 0, E_FAIL, .todo_hr = TRUE},
-        {"file://foo:bar@localhost:21/file?query=x", URL_PART_HOSTNAME, 0, S_OK, "foo:bar at localhost:21", .todo_result = TRUE},
-        {"file://foo:bar@localhost:21/file?query=x", URL_PART_PORT, 0, E_FAIL, .todo_hr = TRUE},
+        {"file://foo:bar@localhost:21/file?query=x", URL_PART_USERNAME, 0, E_FAIL},
+        {"file://foo:bar@localhost:21/file?query=x", URL_PART_PASSWORD, 0, E_FAIL},
+        {"file://foo:bar@localhost:21/file?query=x", URL_PART_HOSTNAME, 0, S_OK, "foo:bar at localhost:21"},
+        {"file://foo:bar@localhost:21/file?query=x", URL_PART_PORT, 0, E_FAIL},
         {"file://foo:bar@localhost:21/file?query=x", URL_PART_QUERY, 0, S_OK, "query=x"},
         {"http://user:pass 123 at www.wine hq.org", URL_PART_HOSTNAME, 0, S_OK, "www.wine hq.org"},
         {"http://user:pass 123 at www.wine hq.org", URL_PART_PASSWORD, 0, S_OK, "pass 123"},
@@ -799,7 +799,7 @@ static void test_UrlGetPart(void)
             {
                 if (expect)
                 {
-                    todo_wine_if (tests[i].todo_hr || tests[i].todo_result)
+                    todo_wine_if (tests[i].todo_hr)
                         ok(size == strlen(expect) + 1, "Got size %lu.\n", size);
                 }
             }
@@ -820,7 +820,7 @@ static void test_UrlGetPart(void)
             ok(size == strlen(buffer), "Got size %lu.\n", size);
             if (expect)
             {
-                todo_wine_if (tests[i].todo_hr || tests[i].todo_result)
+                todo_wine_if (tests[i].todo_hr)
                     ok(!strcmp(buffer, expect), "Got result %s.\n", debugstr_a(buffer));
             }
         }
@@ -854,7 +854,7 @@ static void test_UrlGetPart(void)
             {
                 if (expect)
                 {
-                    todo_wine_if (tests[i].todo_hr || tests[i].todo_result)
+                    todo_wine_if (tests[i].todo_hr)
                         ok(size == strlen(expect) + 1, "Got size %lu.\n", size);
                 }
             }
-- 
2.34.1




More information about the wine-devel mailing list