Commit 1928ee88 authored by James Hawkins's avatar James Hawkins Committed by Alexandre Julliard

Implement InternetCreateUrlW and test cases.

parent 0d23ac47
......@@ -3422,6 +3422,142 @@ BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
return (hr==S_OK);
}
/* max port num is 65535 => 5 digits */
#define MAX_WORD_DIGITS 5
/* we can calculate using ansi strings because we're just
* calculating string length, not size
*/
static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
LPDWORD lpdwUrlLength, LPDWORD lpdwSchemeLength)
{
static const WCHAR httpW[] = {'h','t','t','p',0};
*lpdwUrlLength = 0;
switch (lpUrlComponents->nScheme)
{
case INTERNET_SCHEME_FTP:
case INTERNET_SCHEME_RES:
*lpdwSchemeLength = 3;
break;
case INTERNET_SCHEME_HTTP:
case INTERNET_SCHEME_FILE:
case INTERNET_SCHEME_NEWS:
*lpdwSchemeLength = 4;
break;
default:
*lpdwSchemeLength = 4;
break;
}
*lpdwUrlLength += *lpdwSchemeLength;
*lpdwUrlLength += strlen("://");
if (lpUrlComponents->lpszUserName)
{
*lpdwUrlLength += lpUrlComponents->dwUserNameLength;
*lpdwUrlLength += strlen("@");
}
else
{
if (lpUrlComponents->lpszPassword)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
else
SetLastError(ERROR_ALREADY_EXISTS);
}
if (lpUrlComponents->lpszPassword)
{
*lpdwUrlLength += strlen(":");
*lpdwUrlLength += lpUrlComponents->dwPasswordLength;
}
*lpdwUrlLength += lpUrlComponents->dwHostNameLength;
if (lpUrlComponents->nPort != 80 ||
(lpUrlComponents->lpszScheme && strncmpW(lpUrlComponents->lpszScheme, httpW, lpUrlComponents->dwSchemeLength)))
{
char szPort[MAX_WORD_DIGITS];
sprintf(szPort, "%d", lpUrlComponents->nPort);
*lpdwUrlLength += strlen(szPort);
*lpdwUrlLength += strlen(":");
}
*lpdwUrlLength += lpUrlComponents->dwUrlPathLength;
return TRUE;
}
static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
{
INT len;
ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
urlCompW->nScheme = lpUrlComponents->nScheme;
urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
urlCompW->nPort = lpUrlComponents->nPort;
urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
if (lpUrlComponents->lpszScheme)
{
len = lpUrlComponents->dwSchemeLength + 1;
urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
-1, urlCompW->lpszScheme, len);
}
if (lpUrlComponents->lpszHostName)
{
len = lpUrlComponents->dwHostNameLength + 1;
urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
-1, urlCompW->lpszHostName, len);
}
if (lpUrlComponents->lpszUserName)
{
len = lpUrlComponents->dwUserNameLength + 1;
urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
-1, urlCompW->lpszUserName, len);
}
if (lpUrlComponents->lpszPassword)
{
len = lpUrlComponents->dwPasswordLength + 1;
urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
-1, urlCompW->lpszPassword, len);
}
if (lpUrlComponents->lpszUrlPath)
{
len = lpUrlComponents->dwUrlPathLength + 1;
urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
-1, urlCompW->lpszUrlPath, len);
}
if (lpUrlComponents->lpszExtraInfo)
{
len = lpUrlComponents->dwExtraInfoLength + 1;
urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
-1, urlCompW->lpszExtraInfo, len);
}
}
/***********************************************************************
*
* InternetCreateUrlA
......@@ -3434,8 +3570,130 @@ BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
LPSTR lpszUrl, LPDWORD lpdwUrlLength)
{
FIXME("\n");
return FALSE;
BOOL ret;
LPWSTR urlW = NULL;
URL_COMPONENTSW urlCompW;
TRACE("(%p,%ld,%s,%p)\n", lpUrlComponents, dwFlags, debugstr_a(lpszUrl), lpdwUrlLength);
if (!lpUrlComponents)
return FALSE;
if (lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
convert_urlcomp_atow(lpUrlComponents, &urlCompW);
if (lpszUrl)
urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
/* on success, lpdwUrlLength points to the size of urlW in WCHARS
* minus one, so add one to leave room for NULL terminator
*/
if (ret)
WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
HeapFree(GetProcessHeap(), 0, urlW);
return ret;
}
/***********************************************************************
*
* InternetCreateUrlW
*
* RETURNS
* TRUE on success
* FALSE on failure
*
*/
BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
{
DWORD dwLen, dwSchemeLen;
static const WCHAR colonSlashW[] = {':','/','/',0};
static const WCHAR httpW[] = {'h','t','t','p',0};
static const WCHAR colonW[] = {':',0};
static const WCHAR atW[] = {'@',0};
static const WCHAR percentD[] = {'%','d',0};
TRACE("(%p,%ld,%s,%p)\n", lpUrlComponents, dwFlags, debugstr_w(lpszUrl), lpdwUrlLength);
if (!lpUrlComponents)
return FALSE;
if (lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!calc_url_length(lpUrlComponents, &dwLen, &dwSchemeLen))
return FALSE;
if (!lpszUrl || *lpdwUrlLength < dwLen)
{
*lpdwUrlLength = dwLen + 1; /* terminating null */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
*lpdwUrlLength = dwLen;
lpszUrl[0] = 0x00;
if (lpUrlComponents->lpszScheme)
lstrcpynW(lpszUrl, lpUrlComponents->lpszScheme,
min(lpUrlComponents->dwSchemeLength, dwSchemeLen) + 1);
lstrcatW(lpszUrl, colonSlashW);
if (lpUrlComponents->lpszUserName)
{
if (!*lpUrlComponents->lpszUserName)
return TRUE;
lstrcatW(lpszUrl, lpUrlComponents->lpszUserName);
if (lpUrlComponents->lpszPassword)
{
lstrcatW(lpszUrl, colonW);
if (!*lpUrlComponents->lpszPassword)
return TRUE;
else
lstrcatW(lpszUrl, lpUrlComponents->lpszPassword);
}
lstrcatW(lpszUrl, atW);
}
lstrcatW(lpszUrl, lpUrlComponents->lpszHostName);
if (lpUrlComponents->nPort != 80 || (lpUrlComponents->lpszScheme &&
strncmpW(lpUrlComponents->lpszScheme, httpW, lpUrlComponents->dwSchemeLength)))
{
WCHAR szPort[MAX_WORD_DIGITS];
sprintfW(szPort, percentD, lpUrlComponents->nPort);
lstrcatW(lpszUrl, colonW);
lstrcatW(lpszUrl, szPort);
}
lstrcatW(lpszUrl, lpUrlComponents->lpszUrlPath);
return TRUE;
}
DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
......@@ -3579,22 +3837,6 @@ BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
FIXME("(%p, 0x%08lx) stub\n", hInternet, dwError);
return FALSE;
}
/***********************************************************************
*
* InternetCreateUrlW
*
* RETURNS
* TRUE on success
* FALSE on failure
*
*/
BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* dump_INTERNET_FLAGS
......
......@@ -39,6 +39,14 @@
#define TEST_URL2_EXTRA "?arg=1"
#define TEST_URL3 "file:///C:/Program%20Files/Atmel/AVR%20Tools/STK500/STK500.xml"
#define CREATE_URL1 "http://username:password@www.winehq.org/site/about"
#define CREATE_URL2 "http://username@www.winehq.org/site/about"
#define CREATE_URL3 "http://username:"
#define CREATE_URL4 "http://www.winehq.org/site/about"
#define CREATE_URL5 "http://"
#define CREATE_URL6 "nhtt://username:password@www.winehq.org:80/site/about"
#define CREATE_URL7 "http://username:password@www.winehq.org:42/site/about"
int goon = 0;
static VOID WINAPI callback(
......@@ -590,6 +598,242 @@ static void InternetTimeToSystemTimeW_test(void)
ok( ret, "InternetTimeToSystemTimeW failed (%ld)\n", GetLastError() );
}
static void fill_url_components(LPURL_COMPONENTS lpUrlComponents)
{
lpUrlComponents->dwStructSize = sizeof(URL_COMPONENTS);
lpUrlComponents->lpszScheme = "http";
lpUrlComponents->dwSchemeLength = strlen(lpUrlComponents->lpszScheme);
lpUrlComponents->nScheme = INTERNET_SCHEME_HTTP;
lpUrlComponents->lpszHostName = "www.winehq.org";
lpUrlComponents->dwHostNameLength = strlen(lpUrlComponents->lpszHostName);
lpUrlComponents->nPort = 80;
lpUrlComponents->lpszUserName = "username";
lpUrlComponents->dwUserNameLength = strlen(lpUrlComponents->lpszUserName);
lpUrlComponents->lpszPassword = "password";
lpUrlComponents->dwPasswordLength = strlen(lpUrlComponents->lpszPassword);
lpUrlComponents->lpszUrlPath = "/site/about";
lpUrlComponents->dwUrlPathLength = strlen(lpUrlComponents->lpszUrlPath);
lpUrlComponents->lpszExtraInfo = "";
lpUrlComponents->dwExtraInfoLength = strlen(lpUrlComponents->lpszExtraInfo);
}
static void InternetCreateUrlA_test()
{
URL_COMPONENTS urlComp;
LPSTR szUrl;
DWORD len = -1;
BOOL ret;
/* test NULL lpUrlComponents */
ret = InternetCreateUrlA(NULL, 0, NULL, &len);
SetLastError(0xdeadbeef);
ok(!ret, "Expected failure\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == -1, "Expected len -1, got %ld\n", len);
/* test garbage lpUrlComponets */
ret = InternetCreateUrlA(&urlComp, 0, NULL, &len);
SetLastError(0xdeadbeef);
ok(!ret, "Expected failure\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == -1, "Expected len -1, got %ld\n", len);
/* test zero'ed lpUrlComponents */
ZeroMemory(&urlComp, sizeof(URL_COMPONENTS));
SetLastError(0xdeadbeef);
ret = InternetCreateUrlA(&urlComp, 0, NULL, &len);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
ok(len == -1, "Expected len -1, got %ld\n", len);
/* test valid lpUrlComponets, NULL lpdwUrlLength */
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
ret = InternetCreateUrlA(&urlComp, 0, NULL, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
ok(len == -1, "Expected len -1, got %ld\n", len);
/* test valid lpUrlComponets, emptry szUrl
* lpdwUrlLength is size of buffer required on exit, including
* the terminating null when GLE == ERROR_INSUFFICIENT_BUFFER
*/
SetLastError(0xdeadbeef);
ret = InternetCreateUrlA(&urlComp, 0, NULL, &len);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
ok(len == 51, "Expected len 51, got %ld\n", len);
/* test correct size, NULL szUrl */
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
ret = InternetCreateUrlA(&urlComp, 0, NULL, &len);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
ok(len == 51, "Expected len 51, got %ld\n", len);
/* test valid lpUrlComponets, alloced szUrl, small size */
SetLastError(0xdeadbeef);
szUrl = HeapAlloc(GetProcessHeap(), 0, len);
len -= 2;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
ok(len == 51, "Expected len 51, got %ld\n", len);
/* alloced szUrl, NULL lpszScheme
* shows that it uses dwXLength instead of strlen(lpszX)
*/
SetLastError(0xdeadbeef);
urlComp.lpszScheme = NULL;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == 50, "Expected len 50, got %ld\n", len);
/* alloced szUrl, invalid nScheme
* any nScheme out of range seems ignored
*/
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
urlComp.nScheme = -3;
len++;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == 50, "Expected len 50, got %ld\n", len);
/* test valid lpUrlComponets, alloced szUrl */
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
len = 51;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == 50, "Expected len 50, got %ld\n", len);
ok(strstr(szUrl, "80") == NULL, "Didn't expect to find 80 in szUrl\n");
ok(!strcmp(szUrl, CREATE_URL1), "Expected %s, got %s\n", CREATE_URL1, szUrl);
/* valid username, NULL password */
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
urlComp.lpszPassword = NULL;
len = 42;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == 41, "Expected len 41, got %ld\n", len);
ok(!strcmp(szUrl, CREATE_URL2), "Expected %s, got %s\n", CREATE_URL2, szUrl);
/* valid username, empty password */
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
urlComp.lpszPassword = "";
len = 51;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == 50, "Expected len 50, got %ld\n", len);
ok(!strcmp(szUrl, CREATE_URL3), "Expected %s, got %s\n", CREATE_URL2, szUrl);
/* valid password, NULL username
* if password is provided, username has to exist
*/
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
urlComp.lpszUserName = NULL;
len = 42;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
ok(len == 42, "Expected len 42, got %ld\n", len);
ok(!strcmp(szUrl, CREATE_URL3), "Expected %s, got %s\n", CREATE_URL2, szUrl);
/* valid password, empty username
* if password is provided, username has to exist
*/
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
urlComp.lpszUserName = "";
len = 51;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == 50, "Expected len 50, got %ld\n", len);
ok(!strcmp(szUrl, CREATE_URL5), "Expected %s, got %s\n", CREATE_URL4, szUrl);
/* NULL username, NULL password */
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
urlComp.lpszUserName = NULL;
urlComp.lpszPassword = NULL;
len = 42;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == ERROR_ALREADY_EXISTS,
"Expected ERROR_ALREADYEXISTS, got %ld\n", GetLastError());
ok(len == 32, "Expected len 32, got %ld\n", len);
ok(!strcmp(szUrl, CREATE_URL4), "Expected %s, got %s\n", CREATE_URL3, szUrl);
/* empty username, empty password */
fill_url_components(&urlComp);
SetLastError(0xdeadbeef);
urlComp.lpszUserName = "";
urlComp.lpszPassword = "";
len = 51;
ret = InternetCreateUrlA(&urlComp, 0, szUrl, &len);
ok(ret, "Expected success\n");
ok(GetLastError() == 0xdeadbeef,
"Expected 0xdeadbeef, got %ld\n", GetLastError());
ok(len == 50, "Expected len 50, got %ld\n", len);
ok(!strcmp(szUrl, CREATE_URL5), "Expected %s, got %s\n", CREATE_URL4, szUrl);
/* if lpszScheme != "http" or nPort != 80, display nPort.
* depending on nScheme, displays only first x characters
* of lpszScheme:
* HTTP: x=4
* FTP: x=3 etc
*/
fill_url_components(&urlComp);
HeapFree(GetProcessHeap(), 0, szUrl);
urlComp.lpszScheme = "nhttp";
len = 54;
szUrl = HeapAlloc(GetProcessHeap(), 0, len);
ret = InternetCreateUrlA(&urlComp, ICU_ESCAPE, szUrl, &len);
ok(ret, "Expected success\n");
ok(len == 53, "Expected len 51, got %ld\n", len);
ok(strstr(szUrl, "80") != NULL, "Expected to find 80 in szUrl\n");
ok(!strncmp(szUrl, "nhtt://", 7), "Expected 'nhtt://'\n");
ok(!strcmp(szUrl, CREATE_URL6), "Expected %s, got %s\n", CREATE_URL5, szUrl);
/* if lpszScheme != "http" or nPort != 80, display nPort */
HeapFree(GetProcessHeap(), 0, szUrl);
urlComp.lpszScheme = "http";
urlComp.nPort = 42;
szUrl = HeapAlloc(GetProcessHeap(), 0, ++len);
ret = InternetCreateUrlA(&urlComp, ICU_ESCAPE, szUrl, &len);
ok(ret, "Expected success\n");
ok(len == 53, "Expected len 53, got %ld\n", len);
ok(strstr(szUrl, "42") != NULL, "Expected to find 42 in szUrl\n");
ok(!strcmp(szUrl, CREATE_URL7), "Expected %s, got %s\n", CREATE_URL6, szUrl);
HeapFree(GetProcessHeap(), 0, szUrl);
}
START_TEST(http)
{
winapi_test(0x10000000);
......@@ -601,4 +845,5 @@ START_TEST(http)
InternetTimeFromSystemTimeW_test();
InternetTimeToSystemTimeA_test();
InternetTimeToSystemTimeW_test();
InternetCreateUrlA_test();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment