diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 5844a7c7d69..60dab624419 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -1019,6 +1019,37 @@ static void cache_authorization(LPWSTR host, LPWSTR scheme, LeaveCriticalSection(&authcache_cs); } +void free_authorization_cache(void) +{ + authorizationData *ad, *sa_safe; + basicAuthorizationData *basic, *basic_safe; + + EnterCriticalSection(&authcache_cs); + + LIST_FOR_EACH_ENTRY_SAFE(basic, basic_safe, &basicAuthorizationCache, basicAuthorizationData, entry) + { + heap_free(basic->host); + heap_free(basic->realm); + heap_free(basic->authorization); + + list_remove(&basic->entry); + heap_free(basic); + } + + LIST_FOR_EACH_ENTRY_SAFE(ad, sa_safe, &authorizationCache, authorizationData, entry) + { + heap_free(ad->host); + heap_free(ad->scheme); + heap_free(ad->user); + heap_free(ad->password); + heap_free(ad->domain); + list_remove(&ad->entry); + heap_free(ad); + } + + LeaveCriticalSection(&authcache_cs); +} + static BOOL HTTP_DoAuthorization( http_request_t *request, LPCWSTR pszAuthValue, struct HttpAuthInfo **ppAuthInfo, LPWSTR domain_and_username, LPWSTR password, diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index b7aa5fe330b..266100861d3 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -2821,6 +2821,7 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, case INTERNET_OPTION_END_BROWSER_SESSION: FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: semi-stub\n"); free_cookie(); + free_authorization_cache(); break; case INTERNET_OPTION_CONNECTED_STATE: FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n"); diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 40e51bec328..8954d071f9b 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -456,6 +456,7 @@ static inline req_file_t *req_file_addref(req_file_t *req_file) BOOL init_urlcache(void) DECLSPEC_HIDDEN; void free_urlcache(void) DECLSPEC_HIDDEN; void free_cookie(void) DECLSPEC_HIDDEN; +void free_authorization_cache(void) DECLSPEC_HIDDEN; void init_winsock(void) DECLSPEC_HIDDEN; diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index b61d5c7030d..f1a647346ef 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -4502,6 +4502,92 @@ static void test_basic_auth_credentials_reuse(int port) InternetCloseHandle( ses ); } +static void test_basic_auth_credentials_end_session(int port) +{ + HINTERNET ses, con, req; + DWORD status, size; + BOOL ret; + char buffer[0x40]; + + ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 ); + ok( ses != NULL, "InternetOpenA failed\n" ); + + con = InternetConnectA( ses, "localhost", port, "user", "pwd", + INTERNET_SERVICE_HTTP, 0, 0 ); + ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() ); + + req = HttpOpenRequestA( con, "HEAD", "/upload.txt", NULL, NULL, NULL, 0, 0 ); + ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() ); + + ret = HttpSendRequestA( req, NULL, 0, NULL, 0 ); + ok( ret, "HttpSendRequestA failed %u\n", GetLastError() ); + + size = sizeof(buffer); + SetLastError(0xdeadbeef); + ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size); + ok(ret, "unexpected failure %u\n", GetLastError()); + ok(!strcmp(buffer, "user"), "got %s\n", buffer); + ok(size == 4, "got %u\n", size); + + size = sizeof(buffer); + SetLastError(0xdeadbeef); + ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size); + ok(ret, "unexpected failure %u\n", GetLastError()); + ok(!strcmp(buffer, "pwd"), "got %s\n", buffer); + ok(size == 3, "got %u\n", size); + + status = 0xdeadbeef; + size = sizeof(status); + ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL ); + ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() ); + ok( status == HTTP_STATUS_OK, "got %u\n", status ); + + InternetCloseHandle( req ); + InternetCloseHandle( con ); + InternetCloseHandle( ses ); + + ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 ); + ok( ses != NULL, "InternetOpenA failed\n" ); + + /* Clear the cached credentials */ + ret = InternetSetOptionA(ses, INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0); + ok(ret, "unexpected failure %u\n", GetLastError()); + + con = InternetConnectA( ses, "localhost", port, NULL, NULL, + INTERNET_SERVICE_HTTP, 0, 0 ); + ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() ); + + req = HttpOpenRequestA( con, "PUT", "/upload2.txt", NULL, NULL, NULL, 0, 0 ); + ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() ); + + ret = HttpSendRequestA( req, NULL, 0, NULL, 0 ); + ok( ret, "HttpSendRequestA failed %u\n", GetLastError() ); + + size = sizeof(buffer); + SetLastError(0xdeadbeef); + ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size); + ok(ret, "unexpected failure %u\n", GetLastError()); + ok(!strcmp(buffer, ""), "got %s\n", buffer); + ok(size == 0, "got %u\n", size); + + size = sizeof(buffer); + SetLastError(0xdeadbeef); + ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size); + ok(ret, "unexpected failure %u\n", GetLastError()); + ok(!strcmp(buffer, ""), "got %s\n", buffer); + ok(size == 0, "got %u\n", size); + + status = 0xdeadbeef; + size = sizeof(status); + ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL ); + ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() ); + ok( status == HTTP_STATUS_BAD_REQUEST, "got %u\n", status ); + + InternetCloseHandle( req ); + InternetCloseHandle( con ); + InternetCloseHandle( ses ); +} + static void test_async_read(int port) { HINTERNET ses, con, req; @@ -5696,6 +5782,7 @@ static void test_http_connection(void) test_request_content_length(si.port); test_accept_encoding(si.port); test_basic_auth_credentials_reuse(si.port); + test_basic_auth_credentials_end_session(si.port); test_async_read(si.port); test_http_read(si.port); test_connection_break(si.port);