Windows will stop processing at the first null, even when given an explicit length.
Signed-off-by: Tim Clem tclem@codeweavers.com --- Added some more thorough tests. In the case that amounts to InternetCrackUrlA("http://", ...), Wine does the wrong thing, even with these patches. Windows rejects that, but we seemingly have no check for an empty hostname. I left that test as todo_wine.
dlls/wininet/tests/url.c | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/dlls/wininet/tests/url.c b/dlls/wininet/tests/url.c index bce7dc76c59..6927ca5e6e8 100644 --- a/dlls/wininet/tests/url.c +++ b/dlls/wininet/tests/url.c @@ -653,6 +653,26 @@ static void InternetCrackUrl_test(void) GLE = GetLastError(); ok(ret == FALSE, "Expected InternetCrackUrl to fail\n"); ok(GLE == ERROR_INTERNET_UNRECOGNIZED_SCHEME, "Expected GLE to represent a failure\n"); + + /* Windows treats dwUrlLength as a maximum - if there is a null before + * that length, it stops there. */ + copy_compsA(&urlSrc, &urlComponents, 32, 1024, 1024, 1024, 1024, 1024); + ret = InternetCrackUrlA("http://x.org", 13 /* includes the nul */, 0, &urlComponents); + ok(ret, "InternetCrackUrlA failed with error %d\n", GetLastError()); + todo_wine + ok(urlComponents.dwHostNameLength == 5, + "Expected dwHostNameLength of 5, got %d\n", urlComponents.dwHostNameLength); + + copy_compsA(&urlSrc, &urlComponents, 32, 1024, 1024, 1024, 1024, 1024); + ret = InternetCrackUrlA("http://%5C0x.org", 13, 0, &urlComponents); + todo_wine ok(ret == FALSE, "Expected InternetCrackUrlA to fail\n"); + + copy_compsA(&urlSrc, &urlComponents, 32, 1024, 1024, 1024, 1024, 1024); + ret = InternetCrackUrlA("http://x.org%5C0/x", 15, 0, &urlComponents); + ok(ret, "InternetCrackUrlA failed with error %d\n", GetLastError()); + todo_wine + ok(urlComponents.dwUrlPathLength == 0, + "Expected dwUrlPathLength of 0, got %d\n", urlComponents.dwUrlPathLength); }
static void InternetCrackUrlW_test(void) @@ -664,6 +684,8 @@ static void InternetCrackUrlW_test(void) 'U','L','T', 0 }; static const WCHAR url2[] = { '.','.','/','R','i','t','z','.','x','m','l',0 }; static const WCHAR url3[] = { 'h','t','t','p',':','/','/','x','.','o','r','g',0 }; + static const WCHAR url4[] = { 'h','t','t','p',':','/','/',0,'x','.','o','r','g',0 }; + static const WCHAR url5[] = { 'h','t','t','p',':','/','/','x','.','o','r','g',0,'/','x',0 }; URL_COMPONENTSW comp; WCHAR scheme[20], host[20], user[20], pwd[20], urlpart[50], extra[50]; DWORD error; @@ -825,6 +847,41 @@ static void InternetCrackUrlW_test(void) ok(r, "InternetCrackUrlW failed unexpectedly\n"); ok(!strcmp_wa(host, "x.org"), "host is %s, should be x.org\n", wine_dbgstr_w(host)); todo_wine ok(urlpart[0] == 0, "urlpart should be empty\n"); + + /* Windows treats dwUrlLength as a maximum - if there is a null before + * that length, it stops there. */ + host[0] = 0; + memset(&comp, 0, sizeof(comp)); + comp.dwStructSize = sizeof(comp); + comp.lpszHostName = host; + comp.dwHostNameLength = ARRAY_SIZE(host); + r = InternetCrackUrlW(url3, 13 /* includes the nul */, 0, &comp); + ok(r, "InternetCrackUrlW failed with error %d\n", GetLastError()); + todo_wine + ok(comp.dwHostNameLength == 5, + "Expected dwHostNameLength of 5, got %d\n", comp.dwHostNameLength); + + host[0] = 0; + memset(&comp, 0, sizeof(comp)); + comp.dwStructSize = sizeof(comp); + comp.lpszHostName = host; + comp.dwHostNameLength = ARRAY_SIZE(host); + r = InternetCrackUrlW(url4, 13, 0, &comp); + todo_wine ok(r == FALSE, "Expected InternetCrackUrlW to fail\n"); + + host[0] = 0; + urlpart[0] = 0; + memset(&comp, 0, sizeof(comp)); + comp.dwStructSize = sizeof(comp); + comp.lpszHostName = host; + comp.dwHostNameLength = ARRAY_SIZE(host); + comp.lpszUrlPath = urlpart; + comp.dwUrlPathLength = ARRAY_SIZE(urlpart); + r = InternetCrackUrlW(url5, 15, 0, &comp); + ok(r, "InternetCrackUrlW failed with error %d\n", GetLastError()); + todo_wine + ok(comp.dwUrlPathLength == 0, + "Expected dwUrlPathLength of 0, got %d\n", comp.dwUrlPathLength); }
static void fill_url_components(URL_COMPONENTSA *lpUrlComponents)
The analogous heap_strndupW already does this. Fixes InternetCrackUrlA behavior when passed a dwUrlLength that's past the end of the string.
Signed-off-by: Tim Clem tclem@codeweavers.com --- dlls/wininet/internet.h | 5 ++++- dlls/wininet/tests/url.c | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 0efea473255..e9d68e2c2d9 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -152,7 +152,10 @@ static inline WCHAR *heap_strndupAtoW(const char *str, int len_a, DWORD *len_w)
if(str) { size_t len; - if(len_a < 0) len_a = strlen(str); + if(len_a < 0) + len_a = strlen(str); + else if(len_a > 0) + len_a = strnlen(str, len_a); len = MultiByteToWideChar(CP_ACP, 0, str, len_a, NULL, 0); ret = heap_alloc((len+1)*sizeof(WCHAR)); if(ret) { diff --git a/dlls/wininet/tests/url.c b/dlls/wininet/tests/url.c index 6927ca5e6e8..9476d4309c3 100644 --- a/dlls/wininet/tests/url.c +++ b/dlls/wininet/tests/url.c @@ -659,7 +659,6 @@ static void InternetCrackUrl_test(void) copy_compsA(&urlSrc, &urlComponents, 32, 1024, 1024, 1024, 1024, 1024); ret = InternetCrackUrlA("http://x.org", 13 /* includes the nul */, 0, &urlComponents); ok(ret, "InternetCrackUrlA failed with error %d\n", GetLastError()); - todo_wine ok(urlComponents.dwHostNameLength == 5, "Expected dwHostNameLength of 5, got %d\n", urlComponents.dwHostNameLength);
@@ -670,7 +669,6 @@ static void InternetCrackUrl_test(void) copy_compsA(&urlSrc, &urlComponents, 32, 1024, 1024, 1024, 1024, 1024); ret = InternetCrackUrlA("http://x.org%5C0/x", 15, 0, &urlComponents); ok(ret, "InternetCrackUrlA failed with error %d\n", GetLastError()); - todo_wine ok(urlComponents.dwUrlPathLength == 0, "Expected dwUrlPathLength of 0, got %d\n", urlComponents.dwUrlPathLength); }
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Tim Clem tclem@codeweavers.com --- dlls/wininet/internet.c | 13 ++++++++++++- dlls/wininet/tests/url.c | 2 -- 2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 1b6f060d607..c5b70e60d0c 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -1636,7 +1636,18 @@ BOOL WINAPI InternetCrackUrlW(const WCHAR *lpszUrl, DWORD dwUrlLength, DWORD dwF SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (!dwUrlLength) dwUrlLength = lstrlenW(lpszUrl); + + if (!dwUrlLength) + dwUrlLength = lstrlenW(lpszUrl); + else { + /* Windows stops at a null, regardless of what dwUrlLength says. */ + DWORD len = wcsnlen(lpszUrl, dwUrlLength); + if (dwUrlLength != len) { + TRACE("dwUrlLength %u is past a null terminator. Treating length as %u.\n", + dwUrlLength, len); + dwUrlLength = len; + } + }
if (dwFlags & ICU_DECODE) { diff --git a/dlls/wininet/tests/url.c b/dlls/wininet/tests/url.c index 9476d4309c3..59b66a5404c 100644 --- a/dlls/wininet/tests/url.c +++ b/dlls/wininet/tests/url.c @@ -855,7 +855,6 @@ static void InternetCrackUrlW_test(void) comp.dwHostNameLength = ARRAY_SIZE(host); r = InternetCrackUrlW(url3, 13 /* includes the nul */, 0, &comp); ok(r, "InternetCrackUrlW failed with error %d\n", GetLastError()); - todo_wine ok(comp.dwHostNameLength == 5, "Expected dwHostNameLength of 5, got %d\n", comp.dwHostNameLength);
@@ -877,7 +876,6 @@ static void InternetCrackUrlW_test(void) comp.dwUrlPathLength = ARRAY_SIZE(urlpart); r = InternetCrackUrlW(url5, 15, 0, &comp); ok(r, "InternetCrackUrlW failed with error %d\n", GetLastError()); - todo_wine ok(comp.dwUrlPathLength == 0, "Expected dwUrlPathLength of 0, got %d\n", comp.dwUrlPathLength); }