From d6c0e8159b7aab54696dde71c07c077c0da75ea0 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 31 Dec 2012 14:33:20 -0600 Subject: [PATCH] wininet: Fail on URLs without a scheme. --- dlls/wininet/internet.c | 228 +++++++++++++++++----------------- dlls/wininet/tests/internet.c | 2 - dlls/wininet/tests/url.c | 23 +++- 3 files changed, 132 insertions(+), 121 deletions(-) diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 88fe03740b8..e95070f4ac9 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -1647,9 +1647,9 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR * */ LPCWSTR lpszParam = NULL; - BOOL bIsAbsolute = FALSE; + BOOL found_colon = FALSE; LPCWSTR lpszap, lpszUrl = lpszUrl_orig; - LPCWSTR lpszcp = NULL; + LPCWSTR lpszcp = NULL, lpszNetLoc; LPWSTR lpszUrl_decode = NULL; DWORD dwUrlLength = dwUrlLength_orig; @@ -1699,9 +1699,9 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR lpszap++; continue; } - if ((*lpszap == ':') && (lpszap - lpszUrl >= 2)) + if (*lpszap == ':') { - bIsAbsolute = TRUE; + found_colon = TRUE; lpszcp = lpszap; } else @@ -1712,6 +1712,11 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR break; } + if(!found_colon){ + SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); + return 0; + } + lpUC->nScheme = INTERNET_SCHEME_UNKNOWN; lpUC->nPort = INTERNET_INVALID_PORT_NUMBER; @@ -1723,142 +1728,131 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength, lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0); - if (bIsAbsolute) /* Parse :[//] */ + + /* Get scheme first. */ + lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl); + SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, + lpszUrl, lpszcp - lpszUrl); + + /* Eat ':' in protocol. */ + lpszcp++; + + /* double slash indicates the net_loc portion is present */ + if ((lpszcp[0] == '/') && (lpszcp[1] == '/')) { - LPCWSTR lpszNetLoc; + lpszcp += 2; - /* Get scheme first. */ - lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl); - SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, - lpszUrl, lpszcp - lpszUrl); - - /* Eat ':' in protocol. */ - lpszcp++; - - /* double slash indicates the net_loc portion is present */ - if ((lpszcp[0] == '/') && (lpszcp[1] == '/')) + lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl)); + if (lpszParam) { - lpszcp += 2; - - lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl)); - if (lpszParam) - { - if (lpszNetLoc) - lpszNetLoc = min(lpszNetLoc, lpszParam); - else - lpszNetLoc = lpszParam; - } - else if (!lpszNetLoc) - lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl); - - /* Parse net-loc */ if (lpszNetLoc) + lpszNetLoc = min(lpszNetLoc, lpszParam); + else + lpszNetLoc = lpszParam; + } + else if (!lpszNetLoc) + lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl); + + /* Parse net-loc */ + if (lpszNetLoc) + { + LPCWSTR lpszHost; + LPCWSTR lpszPort; + + /* [[<:password>]@][:] */ + /* First find the user and password if they exist */ + + lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl)); + if (lpszHost == NULL || lpszHost > lpszNetLoc) { - LPCWSTR lpszHost; - LPCWSTR lpszPort; + /* username and password not specified. */ + SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0); + SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0); + } + else /* Parse out username and password */ + { + LPCWSTR lpszUser = lpszcp; + LPCWSTR lpszPasswd = lpszHost; - /* [[<:password>]@][:] */ - /* First find the user and password if they exist */ - - lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl)); - if (lpszHost == NULL || lpszHost > lpszNetLoc) + while (lpszcp < lpszHost) { - /* username and password not specified. */ - SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0); - SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0); - } - else /* Parse out username and password */ - { - LPCWSTR lpszUser = lpszcp; - LPCWSTR lpszPasswd = lpszHost; + if (*lpszcp == ':') + lpszPasswd = lpszcp; - while (lpszcp < lpszHost) - { - if (*lpszcp == ':') - lpszPasswd = lpszcp; - - lpszcp++; - } - - SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, - lpszUser, lpszPasswd - lpszUser); - - if (lpszPasswd != lpszHost) - lpszPasswd++; - SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, - lpszPasswd == lpszHost ? NULL : lpszPasswd, - lpszHost - lpszPasswd); - - lpszcp++; /* Advance to beginning of host */ + lpszcp++; } - /* Parse <:port> */ + SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, + lpszUser, lpszPasswd - lpszUser); - lpszHost = lpszcp; - lpszPort = lpszNetLoc; + if (lpszPasswd != lpszHost) + lpszPasswd++; + SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, + lpszPasswd == lpszHost ? NULL : lpszPasswd, + lpszHost - lpszPasswd); - /* special case for res:// URLs: there is no port here, so the host is the - entire string up to the first '/' */ - if(lpUC->nScheme==INTERNET_SCHEME_RES) + lpszcp++; /* Advance to beginning of host */ + } + + /* Parse <:port> */ + + lpszHost = lpszcp; + lpszPort = lpszNetLoc; + + /* special case for res:// URLs: there is no port here, so the host is the + entire string up to the first '/' */ + if(lpUC->nScheme==INTERNET_SCHEME_RES) + { + SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, + lpszHost, lpszPort - lpszHost); + lpszcp=lpszNetLoc; + } + else + { + while (lpszcp < lpszNetLoc) + { + if (*lpszcp == ':') + lpszPort = lpszcp; + + lpszcp++; + } + + /* If the scheme is "file" and the host is just one letter, it's not a host */ + if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1) + { + lpszcp=lpszHost; + SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, + NULL, 0); + } + else { SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost); - lpszcp=lpszNetLoc; - } - else - { - while (lpszcp < lpszNetLoc) + if (lpszPort != lpszNetLoc) + lpUC->nPort = atoiW(++lpszPort); + else switch (lpUC->nScheme) { - if (*lpszcp == ':') - lpszPort = lpszcp; - - lpszcp++; - } - - /* If the scheme is "file" and the host is just one letter, it's not a host */ - if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1) - { - lpszcp=lpszHost; - SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, - NULL, 0); - } - else - { - SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, - lpszHost, lpszPort - lpszHost); - if (lpszPort != lpszNetLoc) - lpUC->nPort = atoiW(++lpszPort); - else switch (lpUC->nScheme) - { - case INTERNET_SCHEME_HTTP: - lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT; - break; - case INTERNET_SCHEME_HTTPS: - lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT; - break; - case INTERNET_SCHEME_FTP: - lpUC->nPort = INTERNET_DEFAULT_FTP_PORT; - break; - case INTERNET_SCHEME_GOPHER: - lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT; - break; - default: - break; - } + case INTERNET_SCHEME_HTTP: + lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT; + break; + case INTERNET_SCHEME_HTTPS: + lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT; + break; + case INTERNET_SCHEME_FTP: + lpUC->nPort = INTERNET_DEFAULT_FTP_PORT; + break; + case INTERNET_SCHEME_GOPHER: + lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT; + break; + default: + break; } } } } - else - { - SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0); - SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0); - SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0); - } } else { - SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0); SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0); SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0); SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0); diff --git a/dlls/wininet/tests/internet.c b/dlls/wininet/tests/internet.c index c93c37ac911..4fb9e23e7ed 100644 --- a/dlls/wininet/tests/internet.c +++ b/dlls/wininet/tests/internet.c @@ -655,9 +655,7 @@ static void test_null(void) ok(r == FALSE, "return wrong\n"); r = InternetSetCookieW(szServer, NULL, szServer); - todo_wine { ok(GetLastError() == ERROR_INTERNET_UNRECOGNIZED_SCHEME, "wrong error\n"); - } ok(r == FALSE, "return wrong\n"); sz = 0; diff --git a/dlls/wininet/tests/url.c b/dlls/wininet/tests/url.c index 96c380993ea..7817e8f4fee 100644 --- a/dlls/wininet/tests/url.c +++ b/dlls/wininet/tests/url.c @@ -160,6 +160,9 @@ static const crack_url_test_t crack_url_tests[] = { {"file:///C:/Program%20Files/Atmel/./Asdf.xml", 0, 4, INTERNET_SCHEME_FILE, -1, 0, -1, 0, -1, 0, -1, 0, 7, 36, -1, 0, "file", "", "", "", "C:\\Program Files\\Atmel\\.\\Asdf.xml", ""}, + {"C:\\file.txt", + 0, 1, INTERNET_SCHEME_UNKNOWN, -1, 0, -1, 0, -1, 0, -1, 0, 2, 9, -1, 0, + "C", "", "", "", "\\file.txt", ""} }; static const WCHAR *w_str_of(const char *str) @@ -541,6 +544,7 @@ static void InternetCrackUrl_test(void) SetLastError(0xdeadbeef); urlComponents.dwStructSize = 0; ret = InternetCrackUrlA(TEST_URL, 0, 0, &urlComponents); + GLE = GetLastError(); ok(ret == FALSE, "Expected InternetCrackUrl to fail\n"); ok(GLE != 0xdeadbeef && GLE != ERROR_SUCCESS, "Expected GLE to represent a failure\n"); @@ -551,8 +555,25 @@ static void InternetCrackUrl_test(void) SetLastError(0xdeadbeef); urlComponents.dwStructSize = sizeof(urlComponents) + 1; ret = InternetCrackUrlA(TEST_URL, 0, 0, &urlComponents); + GLE = GetLastError(); ok(ret == FALSE, "Expected InternetCrackUrl to fail\n"); ok(GLE != 0xdeadbeef && GLE != ERROR_SUCCESS, "Expected GLE to represent a failure\n"); + + SetLastError(0xdeadbeef); + memset(&urlComponents, 0, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + ret = InternetCrackUrlA("file.txt", 0, 0, &urlComponents); + GLE = GetLastError(); + ok(ret == FALSE, "Expected InternetCrackUrl to fail\n"); + ok(GLE == ERROR_INTERNET_UNRECOGNIZED_SCHEME, "Expected GLE to represent a failure\n"); + + SetLastError(0xdeadbeef); + memset(&urlComponents, 0, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + ret = InternetCrackUrlA("www.winehq.org", 0, 0, &urlComponents); + GLE = GetLastError(); + ok(ret == FALSE, "Expected InternetCrackUrl to fail\n"); + ok(GLE == ERROR_INTERNET_UNRECOGNIZED_SCHEME, "Expected GLE to represent a failure\n"); } static void InternetCrackUrlW_test(void) @@ -690,12 +711,10 @@ static void InternetCrackUrlW_test(void) comp.dwExtraInfoLength = sizeof(extra)/sizeof(extra[0]); r = InternetCrackUrlW(url2, 0, 0, &comp); - todo_wine { ok(!r, "InternetCrackUrl should have failed\n"); ok(GetLastError() == ERROR_INTERNET_UNRECOGNIZED_SCHEME, "InternetCrackUrl should have failed with error ERROR_INTERNET_UNRECOGNIZED_SCHEME instead of error %d\n", GetLastError()); - } /* Test to see whether cracking a URL without a filename initializes urlpart */ urlpart[0]=0xba;