1 /* 2 * URL Cache Tests 3 * 4 * Copyright 2008 Robert Shearman for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winnls.h" 28 #include "wininet.h" 29 #include "winineti.h" 30 31 #include "wine/test.h" 32 33 static const char test_url[] = "http://urlcachetest.winehq.org/index.html"; 34 static const WCHAR test_urlW[] = {'h','t','t','p',':','/','/','u','r','l','c','a','c','h','e','t','e','s','t','.', 35 'w','i','n','e','h','q','.','o','r','g','/','i','n','d','e','x','.','h','t','m','l',0}; 36 static const char test_url1[] = "Visited: user@http://urlcachetest.winehq.org/index.html"; 37 static const char test_hash_collisions1[] = "Visited: http://winehq.org/doc0.html"; 38 static const char test_hash_collisions2[] = "Visited: http://winehq.org/doc75651909.html"; 39 40 static BOOL (WINAPI *pDeleteUrlCacheEntryA)(LPCSTR); 41 static BOOL (WINAPI *pUnlockUrlCacheEntryFileA)(LPCSTR,DWORD); 42 43 static char filenameA[MAX_PATH + 1]; 44 static char filenameA1[MAX_PATH + 1]; 45 static BOOL old_ie = FALSE; 46 static BOOL ie10_cache = FALSE; 47 48 static void check_cache_entry_infoA(const char *returnedfrom, INTERNET_CACHE_ENTRY_INFOA *lpCacheEntryInfo) 49 { 50 ok(lpCacheEntryInfo->dwStructSize == sizeof(*lpCacheEntryInfo), "%s: dwStructSize was %d\n", returnedfrom, lpCacheEntryInfo->dwStructSize); 51 ok(!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_url), "%s: lpszSourceUrlName should be %s instead of %s\n", returnedfrom, test_url, lpCacheEntryInfo->lpszSourceUrlName); 52 ok(!strcmp(lpCacheEntryInfo->lpszLocalFileName, filenameA), "%s: lpszLocalFileName should be %s instead of %s\n", returnedfrom, filenameA, lpCacheEntryInfo->lpszLocalFileName); 53 ok(!strcmp(lpCacheEntryInfo->lpszFileExtension, "html"), "%s: lpszFileExtension should be html instead of %s\n", returnedfrom, lpCacheEntryInfo->lpszFileExtension); 54 } 55 56 static void test_find_url_cache_entriesA(void) 57 { 58 BOOL ret; 59 HANDLE hEnumHandle; 60 BOOL found = FALSE; 61 DWORD cbCacheEntryInfo; 62 DWORD cbCacheEntryInfoSaved; 63 INTERNET_CACHE_ENTRY_INFOA *lpCacheEntryInfo; 64 65 cbCacheEntryInfo = 0; 66 SetLastError(0xdeadbeef); 67 hEnumHandle = FindFirstUrlCacheEntryA(NULL, NULL, &cbCacheEntryInfo); 68 ok(!hEnumHandle, "FindFirstUrlCacheEntry should have failed\n"); 69 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "FindFirstUrlCacheEntry should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); 70 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo * sizeof(char)); 71 cbCacheEntryInfoSaved = cbCacheEntryInfo; 72 hEnumHandle = FindFirstUrlCacheEntryA(NULL, lpCacheEntryInfo, &cbCacheEntryInfo); 73 ok(hEnumHandle != NULL, "FindFirstUrlCacheEntry failed with error %d\n", GetLastError()); 74 while (TRUE) 75 { 76 if (!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_url)) 77 { 78 found = TRUE; 79 ret = TRUE; 80 break; 81 } 82 SetLastError(0xdeadbeef); 83 cbCacheEntryInfo = cbCacheEntryInfoSaved; 84 ret = FindNextUrlCacheEntryA(hEnumHandle, lpCacheEntryInfo, &cbCacheEntryInfo); 85 if (!ret) 86 { 87 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 88 { 89 lpCacheEntryInfo = HeapReAlloc(GetProcessHeap(), 0, lpCacheEntryInfo, cbCacheEntryInfo); 90 cbCacheEntryInfoSaved = cbCacheEntryInfo; 91 ret = FindNextUrlCacheEntryA(hEnumHandle, lpCacheEntryInfo, &cbCacheEntryInfo); 92 } 93 } 94 if (!ret) 95 break; 96 } 97 ok(ret, "FindNextUrlCacheEntry failed with error %d\n", GetLastError()); 98 ok(found, "Committed url cache entry not found during enumeration\n"); 99 100 ret = FindCloseUrlCache(hEnumHandle); 101 ok(ret, "FindCloseUrlCache failed with error %d\n", GetLastError()); 102 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 103 } 104 105 static void test_GetUrlCacheEntryInfoExA(void) 106 { 107 BOOL ret; 108 DWORD cbCacheEntryInfo, cbRedirectUrl; 109 INTERNET_CACHE_ENTRY_INFOA *lpCacheEntryInfo; 110 111 SetLastError(0xdeadbeef); 112 ret = GetUrlCacheEntryInfoExA(NULL, NULL, NULL, NULL, NULL, NULL, 0); 113 ok(!ret, "GetUrlCacheEntryInfoEx with NULL URL and NULL args should have failed\n"); 114 ok(GetLastError() == ERROR_INVALID_PARAMETER, 115 "GetUrlCacheEntryInfoEx with NULL URL and NULL args should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); 116 117 cbCacheEntryInfo = sizeof(INTERNET_CACHE_ENTRY_INFOA); 118 SetLastError(0xdeadbeef); 119 ret = GetUrlCacheEntryInfoExA("", NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0); 120 ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n"); 121 ok(GetLastError() == ERROR_FILE_NOT_FOUND, 122 "GetUrlCacheEntryInfoEx should have set last error to ERROR_FILE_NOT_FOUND instead of %d\n", GetLastError()); 123 124 ret = GetUrlCacheEntryInfoExA(test_url, NULL, NULL, NULL, NULL, NULL, 0); 125 ok(ret, "GetUrlCacheEntryInfoEx with NULL args failed with error %d\n", GetLastError()); 126 127 cbCacheEntryInfo = 0; 128 SetLastError(0xdeadbeef); 129 ret = GetUrlCacheEntryInfoExA(test_url, NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0); 130 ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n"); 131 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 132 "GetUrlCacheEntryInfoEx should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); 133 134 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 135 136 SetLastError(0xdeadbeef); 137 ret = GetUrlCacheEntryInfoExA(test_url, NULL, NULL, NULL, NULL, NULL, 0x200 /*GET_INSTALLED_ENTRY*/); 138 ok(ret == ie10_cache, "GetUrlCacheEntryInfoEx returned %x\n", ret); 139 if (!ret) ok(GetLastError() == ERROR_FILE_NOT_FOUND, 140 "GetUrlCacheEntryInfoEx should have set last error to ERROR_FILE_NOT_FOUND instead of %d\n", GetLastError()); 141 142 /* Unicode version of function seems to ignore 0x200 flag */ 143 ret = GetUrlCacheEntryInfoExW(test_urlW, NULL, NULL, NULL, NULL, NULL, 0x200 /*GET_INSTALLED_ENTRY*/); 144 ok(ret || broken(old_ie && !ret), "GetUrlCacheEntryInfoExW failed with error %d\n", GetLastError()); 145 146 ret = GetUrlCacheEntryInfoExA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo, NULL, NULL, NULL, 0); 147 ok(ret, "GetUrlCacheEntryInfoEx failed with error %d\n", GetLastError()); 148 149 if (ret) check_cache_entry_infoA("GetUrlCacheEntryInfoEx", lpCacheEntryInfo); 150 151 lpCacheEntryInfo->CacheEntryType |= 0x10000000; /* INSTALLED_CACHE_ENTRY */ 152 ret = SetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, CACHE_ENTRY_ATTRIBUTE_FC); 153 ok(ret, "SetUrlCacheEntryInfoA failed with error %d\n", GetLastError()); 154 155 SetLastError(0xdeadbeef); 156 ret = GetUrlCacheEntryInfoExA(test_url, NULL, NULL, NULL, NULL, NULL, 0x200 /*GET_INSTALLED_ENTRY*/); 157 ok(ret, "GetUrlCacheEntryInfoEx failed with error %d\n", GetLastError()); 158 159 cbCacheEntryInfo = 100000; 160 SetLastError(0xdeadbeef); 161 ret = GetUrlCacheEntryInfoExA(test_url, NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0); 162 ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n"); 163 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetUrlCacheEntryInfoEx should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); 164 165 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 166 167 /* Querying the redirect URL fails with ERROR_INVALID_PARAMETER */ 168 SetLastError(0xdeadbeef); 169 ret = GetUrlCacheEntryInfoExA(test_url, NULL, NULL, NULL, &cbRedirectUrl, NULL, 0); 170 ok(!ret, "GetUrlCacheEntryInfoEx should have failed\n"); 171 ok(GetLastError() == ERROR_INVALID_PARAMETER, 172 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 173 SetLastError(0xdeadbeef); 174 ret = GetUrlCacheEntryInfoExA(test_url, NULL, &cbCacheEntryInfo, NULL, &cbRedirectUrl, NULL, 0); 175 ok(!ret, "GetUrlCacheEntryInfoEx should have failed\n"); 176 ok(GetLastError() == ERROR_INVALID_PARAMETER, 177 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 178 } 179 180 static void test_RetrieveUrlCacheEntryA(void) 181 { 182 BOOL ret; 183 DWORD cbCacheEntryInfo; 184 185 cbCacheEntryInfo = 0; 186 SetLastError(0xdeadbeef); 187 ret = RetrieveUrlCacheEntryFileA(NULL, NULL, &cbCacheEntryInfo, 0); 188 ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); 189 ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); 190 191 if (0) 192 { 193 /* Crashes on Win9x, NT4 and W2K */ 194 SetLastError(0xdeadbeef); 195 ret = RetrieveUrlCacheEntryFileA(test_url, NULL, NULL, 0); 196 ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); 197 ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); 198 } 199 200 SetLastError(0xdeadbeef); 201 cbCacheEntryInfo = 100000; 202 ret = RetrieveUrlCacheEntryFileA(NULL, NULL, &cbCacheEntryInfo, 0); 203 ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); 204 ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); 205 } 206 207 static void test_IsUrlCacheEntryExpiredA(void) 208 { 209 static const char uncached_url[] = 210 "What's the airspeed velocity of an unladen swallow?"; 211 BOOL ret; 212 FILETIME ft; 213 DWORD size; 214 INTERNET_CACHE_ENTRY_INFOA *info; 215 ULARGE_INTEGER exp_time; 216 217 /* The function returns TRUE when the output time is NULL or the tested URL 218 * is NULL. 219 */ 220 ret = IsUrlCacheEntryExpiredA(NULL, 0, NULL); 221 ok(ret != ie10_cache, "IsUrlCacheEntryExpiredA returned %x\n", ret); 222 ft.dwLowDateTime = 0xdeadbeef; 223 ft.dwHighDateTime = 0xbaadf00d; 224 ret = IsUrlCacheEntryExpiredA(NULL, 0, &ft); 225 ok(ret != ie10_cache, "IsUrlCacheEntryExpiredA returned %x\n", ret); 226 ok(ft.dwLowDateTime == 0xdeadbeef && ft.dwHighDateTime == 0xbaadf00d, 227 "expected time to be unchanged, got (%u,%u)\n", 228 ft.dwLowDateTime, ft.dwHighDateTime); 229 ret = IsUrlCacheEntryExpiredA(test_url, 0, NULL); 230 ok(ret != ie10_cache, "IsUrlCacheEntryExpiredA returned %x\n", ret); 231 232 /* The return value should indicate whether the URL is expired, 233 * and the filetime indicates the last modified time, but a cache entry 234 * with a zero expire time is "not expired". 235 */ 236 ft.dwLowDateTime = 0xdeadbeef; 237 ft.dwHighDateTime = 0xbaadf00d; 238 ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft); 239 ok(!ret, "expected FALSE\n"); 240 ok(!ft.dwLowDateTime && !ft.dwHighDateTime, 241 "expected time (0,0), got (%u,%u)\n", 242 ft.dwLowDateTime, ft.dwHighDateTime); 243 244 /* Same behavior with bogus flags. */ 245 ft.dwLowDateTime = 0xdeadbeef; 246 ft.dwHighDateTime = 0xbaadf00d; 247 ret = IsUrlCacheEntryExpiredA(test_url, 0xffffffff, &ft); 248 ok(!ret, "expected FALSE\n"); 249 ok(!ft.dwLowDateTime && !ft.dwHighDateTime, 250 "expected time (0,0), got (%u,%u)\n", 251 ft.dwLowDateTime, ft.dwHighDateTime); 252 253 /* Set the expire time to a point in the past.. */ 254 ret = GetUrlCacheEntryInfoA(test_url, NULL, &size); 255 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 256 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 257 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 258 info = HeapAlloc(GetProcessHeap(), 0, size); 259 ret = GetUrlCacheEntryInfoA(test_url, info, &size); 260 ok(ret, "GetUrlCacheEntryInfo failed: %d\n", GetLastError()); 261 GetSystemTimeAsFileTime(&info->ExpireTime); 262 exp_time.u.LowPart = info->ExpireTime.dwLowDateTime; 263 exp_time.u.HighPart = info->ExpireTime.dwHighDateTime; 264 exp_time.QuadPart -= 10 * 60 * (ULONGLONG)10000000; 265 info->ExpireTime.dwLowDateTime = exp_time.u.LowPart; 266 info->ExpireTime.dwHighDateTime = exp_time.u.HighPart; 267 ret = SetUrlCacheEntryInfoA(test_url, info, CACHE_ENTRY_EXPTIME_FC); 268 ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError()); 269 ft.dwLowDateTime = 0xdeadbeef; 270 ft.dwHighDateTime = 0xbaadf00d; 271 /* and the entry should be expired. */ 272 ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft); 273 ok(ret, "expected TRUE\n"); 274 /* The modified time returned is 0. */ 275 ok(!ft.dwLowDateTime && !ft.dwHighDateTime, 276 "expected time (0,0), got (%u,%u)\n", 277 ft.dwLowDateTime, ft.dwHighDateTime); 278 /* Set the expire time to a point in the future.. */ 279 exp_time.QuadPart += 20 * 60 * (ULONGLONG)10000000; 280 info->ExpireTime.dwLowDateTime = exp_time.u.LowPart; 281 info->ExpireTime.dwHighDateTime = exp_time.u.HighPart; 282 ret = SetUrlCacheEntryInfoA(test_url, info, CACHE_ENTRY_EXPTIME_FC); 283 ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError()); 284 ft.dwLowDateTime = 0xdeadbeef; 285 ft.dwHighDateTime = 0xbaadf00d; 286 /* and the entry should no longer be expired. */ 287 ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft); 288 ok(!ret, "expected FALSE\n"); 289 /* The modified time returned is still 0. */ 290 ok(!ft.dwLowDateTime && !ft.dwHighDateTime, 291 "expected time (0,0), got (%u,%u)\n", 292 ft.dwLowDateTime, ft.dwHighDateTime); 293 /* Set the modified time... */ 294 GetSystemTimeAsFileTime(&info->LastModifiedTime); 295 ret = SetUrlCacheEntryInfoA(test_url, info, CACHE_ENTRY_MODTIME_FC); 296 ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError()); 297 /* and the entry should still be unexpired.. */ 298 ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft); 299 ok(!ret, "expected FALSE\n"); 300 /* but the modified time returned is the last modified time just set. */ 301 ok(ft.dwLowDateTime == info->LastModifiedTime.dwLowDateTime && 302 ft.dwHighDateTime == info->LastModifiedTime.dwHighDateTime, 303 "expected time (%u,%u), got (%u,%u)\n", 304 info->LastModifiedTime.dwLowDateTime, 305 info->LastModifiedTime.dwHighDateTime, 306 ft.dwLowDateTime, ft.dwHighDateTime); 307 HeapFree(GetProcessHeap(), 0, info); 308 309 /* An uncached URL is implicitly expired, but with unknown time. */ 310 ft.dwLowDateTime = 0xdeadbeef; 311 ft.dwHighDateTime = 0xbaadf00d; 312 ret = IsUrlCacheEntryExpiredA(uncached_url, 0, &ft); 313 ok(ret != ie10_cache, "IsUrlCacheEntryExpiredA returned %x\n", ret); 314 ok(!ft.dwLowDateTime && !ft.dwHighDateTime, 315 "expected time (0,0), got (%u,%u)\n", 316 ft.dwLowDateTime, ft.dwHighDateTime); 317 } 318 319 static void _check_file_exists(LONG l, LPCSTR filename) 320 { 321 HANDLE file; 322 323 file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 324 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 325 ok_(__FILE__,l)(file != INVALID_HANDLE_VALUE, 326 "expected file to exist, CreateFile failed with error %d\n", 327 GetLastError()); 328 CloseHandle(file); 329 } 330 331 #define check_file_exists(f) _check_file_exists(__LINE__, f) 332 333 static void _check_file_not_exists(LONG l, LPCSTR filename) 334 { 335 HANDLE file; 336 337 file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 338 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 339 ok_(__FILE__,l)(file == INVALID_HANDLE_VALUE, 340 "expected file not to exist\n"); 341 if (file != INVALID_HANDLE_VALUE) 342 CloseHandle(file); 343 } 344 345 #define check_file_not_exists(f) _check_file_not_exists(__LINE__, f) 346 347 static void create_and_write_file(LPCSTR filename, void *data, DWORD len) 348 { 349 HANDLE file; 350 DWORD written; 351 BOOL ret; 352 353 file = CreateFileA(filename, GENERIC_WRITE, 354 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 355 FILE_ATTRIBUTE_NORMAL, NULL); 356 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed with error %d\n", GetLastError()); 357 358 ret = WriteFile(file, data, len, &written, NULL); 359 ok(ret, "WriteFile failed with error %d\n", GetLastError()); 360 361 CloseHandle(file); 362 } 363 364 static void test_urlcacheA(void) 365 { 366 static char long_url[300] = "http://www.winehq.org/"; 367 static char ok_header[] = "HTTP/1.0 200 OK\r\n\r\n"; 368 BOOL ret; 369 HANDLE hFile; 370 BYTE zero_byte = 0; 371 INTERNET_CACHE_ENTRY_INFOA *lpCacheEntryInfo; 372 INTERNET_CACHE_ENTRY_INFOA *lpCacheEntryInfo2; 373 DWORD cbCacheEntryInfo; 374 static const FILETIME filetime_zero; 375 FILETIME now; 376 int len; 377 378 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA, 0); 379 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 380 381 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA1, 0); 382 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 383 check_file_exists(filenameA1); 384 DeleteFileA(filenameA1); 385 386 ok(lstrcmpiA(filenameA, filenameA1), "expected a different file name\n"); 387 388 create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte)); 389 390 ret = CommitUrlCacheEntryA(test_url1, NULL, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL); 391 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 392 cbCacheEntryInfo = 0; 393 ret = GetUrlCacheEntryInfoA(test_url1, NULL, &cbCacheEntryInfo); 394 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 395 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 396 "GetUrlCacheEntryInfo should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); 397 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 398 ret = GetUrlCacheEntryInfoA(test_url1, lpCacheEntryInfo, &cbCacheEntryInfo); 399 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 400 ok(!memcmp(&lpCacheEntryInfo->ExpireTime, &filetime_zero, sizeof(FILETIME)), 401 "expected zero ExpireTime\n"); 402 ok(!memcmp(&lpCacheEntryInfo->LastModifiedTime, &filetime_zero, sizeof(FILETIME)), 403 "expected zero LastModifiedTime\n"); 404 ok(lpCacheEntryInfo->CacheEntryType == (NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY) || 405 broken(lpCacheEntryInfo->CacheEntryType == NORMAL_CACHE_ENTRY /* NT4/W2k */), 406 "expected type NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY, got %08x\n", 407 lpCacheEntryInfo->CacheEntryType); 408 ok(!U(*lpCacheEntryInfo).dwExemptDelta, "expected dwExemptDelta 0, got %d\n", 409 U(*lpCacheEntryInfo).dwExemptDelta); 410 411 /* Make sure there is a notable change in timestamps */ 412 Sleep(1000); 413 414 /* A subsequent commit with a different time/type doesn't change most of the entry */ 415 GetSystemTimeAsFileTime(&now); 416 ret = CommitUrlCacheEntryA(test_url1, NULL, now, now, NORMAL_CACHE_ENTRY, 417 (LPBYTE)ok_header, strlen(ok_header), NULL, NULL); 418 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 419 cbCacheEntryInfo = 0; 420 ret = GetUrlCacheEntryInfoA(test_url1, NULL, &cbCacheEntryInfo); 421 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 422 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 423 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 424 lpCacheEntryInfo2 = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 425 ret = GetUrlCacheEntryInfoA(test_url1, lpCacheEntryInfo2, &cbCacheEntryInfo); 426 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 427 /* but it does change the time.. */ 428 ok(memcmp(&lpCacheEntryInfo2->ExpireTime, &filetime_zero, sizeof(FILETIME)), 429 "expected positive ExpireTime\n"); 430 ok(memcmp(&lpCacheEntryInfo2->LastModifiedTime, &filetime_zero, sizeof(FILETIME)), 431 "expected positive LastModifiedTime\n"); 432 ok(lpCacheEntryInfo2->CacheEntryType == (NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY) || 433 broken(lpCacheEntryInfo2->CacheEntryType == NORMAL_CACHE_ENTRY /* NT4/W2k */), 434 "expected type NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY, got %08x\n", 435 lpCacheEntryInfo2->CacheEntryType); 436 /* and set the headers. */ 437 ok(lpCacheEntryInfo2->dwHeaderInfoSize == 19, 438 "expected headers size 19, got %d\n", 439 lpCacheEntryInfo2->dwHeaderInfoSize); 440 /* Hit rate gets incremented by 1 */ 441 ok((lpCacheEntryInfo->dwHitRate + 1) == lpCacheEntryInfo2->dwHitRate, 442 "HitRate not incremented by one on commit\n"); 443 /* Last access time should be updated */ 444 ok(!(lpCacheEntryInfo->LastAccessTime.dwHighDateTime == lpCacheEntryInfo2->LastAccessTime.dwHighDateTime && 445 lpCacheEntryInfo->LastAccessTime.dwLowDateTime == lpCacheEntryInfo2->LastAccessTime.dwLowDateTime), 446 "Last accessed time was not updated by commit\n"); 447 /* File extension should be unset */ 448 ok(lpCacheEntryInfo2->lpszFileExtension == NULL, 449 "Fileextension isn't unset: %s\n", 450 lpCacheEntryInfo2->lpszFileExtension); 451 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 452 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo2); 453 454 ret = CommitUrlCacheEntryA(test_url, filenameA, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL); 455 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 456 457 cbCacheEntryInfo = 0; 458 SetLastError(0xdeadbeef); 459 ret = RetrieveUrlCacheEntryFileA(test_url, NULL, &cbCacheEntryInfo, 0); 460 ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); 461 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 462 "RetrieveUrlCacheEntryFile should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); 463 464 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 465 ret = RetrieveUrlCacheEntryFileA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo, 0); 466 ok(ret, "RetrieveUrlCacheEntryFile failed with error %d\n", GetLastError()); 467 468 if (ret) check_cache_entry_infoA("RetrieveUrlCacheEntryFile", lpCacheEntryInfo); 469 470 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 471 472 cbCacheEntryInfo = 0; 473 SetLastError(0xdeadbeef); 474 ret = RetrieveUrlCacheEntryFileA(test_url1, NULL, &cbCacheEntryInfo, 0); 475 ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); 476 ok(GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_INSUFFICIENT_BUFFER, 477 "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_DATA instead of %d\n", GetLastError()); 478 479 if (pUnlockUrlCacheEntryFileA) 480 { 481 ret = pUnlockUrlCacheEntryFileA(test_url, 0); 482 ok(ret, "UnlockUrlCacheEntryFileA failed with error %d\n", GetLastError()); 483 } 484 485 /* test Find*UrlCacheEntry functions */ 486 test_find_url_cache_entriesA(); 487 488 test_GetUrlCacheEntryInfoExA(); 489 test_RetrieveUrlCacheEntryA(); 490 test_IsUrlCacheEntryExpiredA(); 491 492 if (pDeleteUrlCacheEntryA) 493 { 494 ret = pDeleteUrlCacheEntryA(test_url); 495 ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError()); 496 ret = pDeleteUrlCacheEntryA(test_url1); 497 ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError()); 498 } 499 500 SetLastError(0xdeadbeef); 501 ret = DeleteFileA(filenameA); 502 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "local file should no longer exist\n"); 503 504 /* Creating two entries with the same URL */ 505 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA, 0); 506 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 507 508 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA1, 0); 509 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 510 511 ok(lstrcmpiA(filenameA, filenameA1), "expected a different file name\n"); 512 513 create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte)); 514 create_and_write_file(filenameA1, &zero_byte, sizeof(zero_byte)); 515 check_file_exists(filenameA); 516 check_file_exists(filenameA1); 517 518 ret = CommitUrlCacheEntryA(test_url, filenameA, filetime_zero, 519 filetime_zero, NORMAL_CACHE_ENTRY, (LPBYTE)ok_header, 520 strlen(ok_header), "html", NULL); 521 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 522 check_file_exists(filenameA); 523 check_file_exists(filenameA1); 524 ret = CommitUrlCacheEntryA(test_url, filenameA1, filetime_zero, 525 filetime_zero, COOKIE_CACHE_ENTRY, NULL, 0, "html", NULL); 526 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 527 /* By committing the same URL a second time, the prior entry is 528 * overwritten... 529 */ 530 cbCacheEntryInfo = 0; 531 SetLastError(0xdeadbeef); 532 ret = GetUrlCacheEntryInfoA(test_url, NULL, &cbCacheEntryInfo); 533 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 534 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 535 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 536 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 537 ret = GetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo); 538 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 539 /* with the previous entry type retained.. */ 540 ok(lpCacheEntryInfo->CacheEntryType & NORMAL_CACHE_ENTRY, 541 "expected cache entry type NORMAL_CACHE_ENTRY, got %d (0x%08x)\n", 542 lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType); 543 /* and the headers overwritten.. */ 544 ok(!lpCacheEntryInfo->dwHeaderInfoSize, "expected headers size 0, got %d\n", 545 lpCacheEntryInfo->dwHeaderInfoSize); 546 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 547 /* and the previous filename shouldn't exist. */ 548 check_file_not_exists(filenameA); 549 check_file_exists(filenameA1); 550 551 if (pDeleteUrlCacheEntryA) 552 { 553 ret = pDeleteUrlCacheEntryA(test_url); 554 ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError()); 555 check_file_not_exists(filenameA); 556 check_file_not_exists(filenameA1); 557 /* Just in case, clean up files */ 558 DeleteFileA(filenameA1); 559 DeleteFileA(filenameA); 560 } 561 562 /* Check whether a retrieved cache entry can be deleted before it's 563 * unlocked: 564 */ 565 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA, 0); 566 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 567 ret = CommitUrlCacheEntryA(test_url, filenameA, filetime_zero, filetime_zero, 568 NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL); 569 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 570 571 cbCacheEntryInfo = 0; 572 SetLastError(0xdeadbeef); 573 ret = RetrieveUrlCacheEntryFileA(test_url, NULL, &cbCacheEntryInfo, 0); 574 ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); 575 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 576 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 577 578 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 579 ret = RetrieveUrlCacheEntryFileA(test_url, lpCacheEntryInfo, 580 &cbCacheEntryInfo, 0); 581 ok(ret, "RetrieveUrlCacheEntryFile failed with error %d\n", GetLastError()); 582 583 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 584 585 if (pDeleteUrlCacheEntryA) 586 { 587 ret = pDeleteUrlCacheEntryA(test_url); 588 ok(!ret, "Expected failure\n"); 589 ok(GetLastError() == ERROR_SHARING_VIOLATION, 590 "Expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); 591 check_file_exists(filenameA); 592 } 593 594 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 595 memset(lpCacheEntryInfo, 0, cbCacheEntryInfo); 596 ret = GetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo); 597 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 598 ok(lpCacheEntryInfo->CacheEntryType & 0x400000, 599 "CacheEntryType hasn't PENDING_DELETE_CACHE_ENTRY set, (flags %08x)\n", 600 lpCacheEntryInfo->CacheEntryType); 601 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 602 603 if (pUnlockUrlCacheEntryFileA) 604 { 605 check_file_exists(filenameA); 606 ret = pUnlockUrlCacheEntryFileA(test_url, 0); 607 ok(ret, "UnlockUrlCacheEntryFileA failed: %d\n", GetLastError()); 608 /* By unlocking the already-deleted cache entry, the file associated 609 * with it is deleted.. 610 */ 611 check_file_not_exists(filenameA); 612 /* (just in case, delete file) */ 613 DeleteFileA(filenameA); 614 } 615 if (pDeleteUrlCacheEntryA) 616 { 617 /* and a subsequent deletion should fail. */ 618 ret = pDeleteUrlCacheEntryA(test_url); 619 ok(!ret, "Expected failure\n"); 620 ok(GetLastError() == ERROR_FILE_NOT_FOUND, 621 "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 622 } 623 624 /* Test whether preventing a file from being deleted causes 625 * DeleteUrlCacheEntryA to fail. 626 */ 627 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA, 0); 628 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 629 630 create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte)); 631 check_file_exists(filenameA); 632 633 ret = CommitUrlCacheEntryA(test_url, filenameA, filetime_zero, 634 filetime_zero, NORMAL_CACHE_ENTRY, (LPBYTE)ok_header, 635 strlen(ok_header), "html", NULL); 636 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 637 check_file_exists(filenameA); 638 hFile = CreateFileA(filenameA, GENERIC_READ, 0, NULL, OPEN_EXISTING, 639 FILE_ATTRIBUTE_NORMAL, NULL); 640 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA failed: %d\n", 641 GetLastError()); 642 if (pDeleteUrlCacheEntryA) 643 { 644 /* DeleteUrlCacheEntryA should succeed.. */ 645 ret = pDeleteUrlCacheEntryA(test_url); 646 ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError()); 647 } 648 CloseHandle(hFile); 649 if (pDeleteUrlCacheEntryA) 650 { 651 /* and a subsequent deletion should fail.. */ 652 ret = pDeleteUrlCacheEntryA(test_url); 653 ok(!ret, "Expected failure\n"); 654 ok(GetLastError() == ERROR_FILE_NOT_FOUND, 655 "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 656 } 657 /* and the file should be untouched. */ 658 check_file_exists(filenameA); 659 DeleteFileA(filenameA); 660 661 /* Try creating a sticky entry. Unlike non-sticky entries, the filename 662 * must have been set already. 663 */ 664 SetLastError(0xdeadbeef); 665 ret = CommitUrlCacheEntryA(test_url, NULL, filetime_zero, filetime_zero, 666 STICKY_CACHE_ENTRY, (LPBYTE)ok_header, strlen(ok_header), "html", 667 NULL); 668 ok(ret == ie10_cache, "CommitUrlCacheEntryA returned %x\n", ret); 669 if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, 670 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 671 SetLastError(0xdeadbeef); 672 ret = CommitUrlCacheEntryA(test_url, NULL, filetime_zero, filetime_zero, 673 NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY, 674 (LPBYTE)ok_header, strlen(ok_header), "html", NULL); 675 ok(ret == ie10_cache, "CommitUrlCacheEntryA returned %x\n", ret); 676 if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, 677 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 678 679 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA, 0); 680 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 681 create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte)); 682 ret = CommitUrlCacheEntryA(test_url, filenameA, filetime_zero, filetime_zero, 683 NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY, 684 (LPBYTE)ok_header, strlen(ok_header), "html", NULL); 685 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 686 cbCacheEntryInfo = 0; 687 SetLastError(0xdeadbeef); 688 ret = GetUrlCacheEntryInfoA(test_url, NULL, &cbCacheEntryInfo); 689 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 690 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 691 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 692 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 693 ret = GetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo); 694 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 695 ok(lpCacheEntryInfo->CacheEntryType & (NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY), 696 "expected cache entry type NORMAL_CACHE_ENTRY | STICKY_CACHE_ENTRY, got %d (0x%08x)\n", 697 lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType); 698 ok(U(*lpCacheEntryInfo).dwExemptDelta == 86400, 699 "expected dwExemptDelta 86400, got %d\n", 700 U(*lpCacheEntryInfo).dwExemptDelta); 701 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 702 if (pDeleteUrlCacheEntryA) 703 { 704 ret = pDeleteUrlCacheEntryA(test_url); 705 ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError()); 706 /* When explicitly deleting the cache entry, the file is also deleted */ 707 check_file_not_exists(filenameA); 708 } 709 /* Test once again, setting the exempt delta via SetUrlCacheEntryInfo */ 710 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA, 0); 711 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 712 create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte)); 713 ret = CommitUrlCacheEntryA(test_url, filenameA, filetime_zero, filetime_zero, 714 NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY, 715 (LPBYTE)ok_header, strlen(ok_header), "html", NULL); 716 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 717 cbCacheEntryInfo = 0; 718 SetLastError(0xdeadbeef); 719 ret = GetUrlCacheEntryInfoA(test_url, NULL, &cbCacheEntryInfo); 720 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 721 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 722 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 723 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 724 ret = GetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo); 725 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 726 ok(lpCacheEntryInfo->CacheEntryType & (NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY), 727 "expected cache entry type NORMAL_CACHE_ENTRY | STICKY_CACHE_ENTRY, got %d (0x%08x)\n", 728 lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType); 729 ok(U(*lpCacheEntryInfo).dwExemptDelta == 86400, 730 "expected dwExemptDelta 86400, got %d\n", 731 U(*lpCacheEntryInfo).dwExemptDelta); 732 U(*lpCacheEntryInfo).dwExemptDelta = 0; 733 ret = SetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, 734 CACHE_ENTRY_EXEMPT_DELTA_FC); 735 ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError()); 736 ret = GetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo); 737 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 738 ok(!U(*lpCacheEntryInfo).dwExemptDelta, "expected dwExemptDelta 0, got %d\n", 739 U(*lpCacheEntryInfo).dwExemptDelta); 740 /* See whether a sticky cache entry has the flag cleared once the exempt 741 * delta is meaningless. 742 */ 743 ok(lpCacheEntryInfo->CacheEntryType & (NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY), 744 "expected cache entry type NORMAL_CACHE_ENTRY | STICKY_CACHE_ENTRY, got %d (0x%08x)\n", 745 lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType); 746 747 /* Recommit of Url entry keeps dwExemptDelta */ 748 U(*lpCacheEntryInfo).dwExemptDelta = 8600; 749 ret = SetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, 750 CACHE_ENTRY_EXEMPT_DELTA_FC); 751 ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError()); 752 753 ret = CreateUrlCacheEntryA(test_url, 0, "html", filenameA1, 0); 754 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 755 create_and_write_file(filenameA1, &zero_byte, sizeof(zero_byte)); 756 757 ret = CommitUrlCacheEntryA(test_url, filenameA1, filetime_zero, filetime_zero, 758 NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY, 759 (LPBYTE)ok_header, strlen(ok_header), "html", NULL); 760 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 761 762 ret = GetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, &cbCacheEntryInfo); 763 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 764 ok(U(*lpCacheEntryInfo).dwExemptDelta == 8600 || (ie10_cache && U(*lpCacheEntryInfo).dwExemptDelta == 86400), 765 "expected dwExemptDelta 8600, got %d\n", U(*lpCacheEntryInfo).dwExemptDelta); 766 767 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 768 769 if (pDeleteUrlCacheEntryA) 770 { 771 ret = pDeleteUrlCacheEntryA(test_url); 772 ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError()); 773 check_file_not_exists(filenameA); 774 } 775 776 /* Test if files with identical hash keys are handled correctly */ 777 ret = CommitUrlCacheEntryA(test_hash_collisions1, NULL, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL); 778 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 779 ret = CommitUrlCacheEntryA(test_hash_collisions2, NULL, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL); 780 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 781 782 cbCacheEntryInfo = 0; 783 ret = GetUrlCacheEntryInfoA(test_hash_collisions1, NULL, &cbCacheEntryInfo); 784 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 785 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 786 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 787 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 788 ret = GetUrlCacheEntryInfoA(test_hash_collisions1, lpCacheEntryInfo, &cbCacheEntryInfo); 789 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 790 ok(!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_hash_collisions1), 791 "got incorrect entry: %s\n", lpCacheEntryInfo->lpszSourceUrlName); 792 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 793 794 cbCacheEntryInfo = 0; 795 ret = GetUrlCacheEntryInfoA(test_hash_collisions2, NULL, &cbCacheEntryInfo); 796 ok(!ret, "GetUrlCacheEntryInfo should have failed\n"); 797 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, 798 "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); 799 lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); 800 ret = GetUrlCacheEntryInfoA(test_hash_collisions2, lpCacheEntryInfo, &cbCacheEntryInfo); 801 ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError()); 802 ok(!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_hash_collisions2), 803 "got incorrect entry: %s\n", lpCacheEntryInfo->lpszSourceUrlName); 804 HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); 805 806 if (pDeleteUrlCacheEntryA) { 807 ret = pDeleteUrlCacheEntryA(test_hash_collisions1); 808 ok(ret, "DeleteUrlCacheEntry failed: %d\n", GetLastError()); 809 ret = pDeleteUrlCacheEntryA(test_hash_collisions2); 810 ok(ret, "DeleteUrlCacheEntry failed: %d\n", GetLastError()); 811 } 812 813 len = strlen(long_url); 814 memset(long_url+len, 'a', sizeof(long_url)-len); 815 long_url[sizeof(long_url)-1] = 0; 816 ret = CreateUrlCacheEntryA(long_url, 0, NULL, filenameA, 0); 817 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 818 check_file_exists(filenameA); 819 DeleteFileA(filenameA); 820 821 ret = CreateUrlCacheEntryA(long_url, 0, "extension", filenameA, 0); 822 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 823 check_file_exists(filenameA); 824 DeleteFileA(filenameA); 825 826 long_url[250] = 0; 827 ret = CreateUrlCacheEntryA(long_url, 0, NULL, filenameA, 0); 828 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 829 check_file_exists(filenameA); 830 DeleteFileA(filenameA); 831 832 ret = CreateUrlCacheEntryA(long_url, 0, "extension", filenameA, 0); 833 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 834 check_file_exists(filenameA); 835 DeleteFileA(filenameA); 836 } 837 838 static void test_urlcacheW(void) 839 { 840 static struct test_data 841 { 842 DWORD err; 843 WCHAR url[128]; 844 char encoded_url[128]; 845 WCHAR extension[32]; 846 WCHAR header_info[128]; 847 }urls[] = { 848 { 849 0, {'h','t','t','p',':','/','/','T','.','p','l','/','t',0}, 850 "http://T.pl/t", {0}, {0} 851 }, 852 { 853 0, {'w','w','w','.','T','.','p','l','/','t',0}, 854 "www.T.pl/t", {0}, {0} 855 }, 856 { 857 0, {'h','t','t','p',':','/','/','w','w','w','.','t','e','s','t',0x15b,0x107, 858 '.','o','r','g','/','t','e','s','t','.','h','t','m','l',0}, 859 "http://www.xn--test-ota71c.org/test.html", {'t','x','t',0}, {0} 860 }, 861 { 862 0, {'w','w','w','.','T','e','s','t',0x15b,0x107,'.','o','r','g', 863 '/','t','e','s','t','.','h','t','m','l',0}, 864 "www.Test\xc5\x9b\xc4\x87.org/test.html", {'a',0x106,'a',0}, {'b',0x106,'b',0} 865 }, 866 { 867 0, {'H','t','t','p','s',':','/','/',0x15b,0x15b,0x107,'/','t',0x107,'/', 868 't','e','s','t','?','a','=','%','2','0',0x106,0}, 869 "Https://xn--4da1oa/t\xc4\x87/test?a=%20\xc4\x86", {'a',0x15b,'a',0}, {'b',0x15b,'b',0} 870 }, 871 { 872 12005, {'h','t','t','p','s',':','/','/','/','/',0x107,'.','o','r','g','/','t','e','s','t',0}, 873 "", {0}, {0} 874 }, 875 { 876 0, {'C','o','o','k','i','e',':',' ','u','s','e','r','@','h','t','t','p', 877 ':','/','/','t',0x15b,0x107,'.','o','r','g','/',0}, 878 "Cookie: user@http://t\xc5\x9b\xc4\x87.org/", {0}, {0} 879 } 880 }; 881 static const FILETIME filetime_zero; 882 883 WCHAR bufW[MAX_PATH]; 884 DWORD i; 885 BOOL ret; 886 887 if(old_ie) { 888 win_skip("urlcache unicode functions\n"); 889 return; 890 } 891 892 if(ie10_cache) { 893 if(!MultiByteToWideChar(CP_ACP, 0, urls[6].encoded_url, -1, 894 urls[6].url, sizeof(urls[6].url)/sizeof(WCHAR))) 895 urls[6].url[0] = 0; 896 897 trace("converted url in test 6: %s\n", wine_dbgstr_w(urls[6].url)); 898 } 899 900 for(i=0; i<sizeof(urls)/sizeof(*urls); i++) { 901 INTERNET_CACHE_ENTRY_INFOA *entry_infoA; 902 INTERNET_CACHE_ENTRY_INFOW *entry_infoW; 903 DWORD size; 904 905 if(!urls[i].url[0]) { 906 win_skip("No UTF16 version of url (%d)\n", i); 907 continue; 908 } 909 910 SetLastError(0xdeadbeef); 911 ret = CreateUrlCacheEntryW(urls[i].url, 0, NULL, bufW, 0); 912 if(urls[i].err != 0) { 913 ok(!ret, "%d) CreateUrlCacheEntryW succeeded\n", i); 914 ok(urls[i].err == GetLastError(), "%d) GetLastError() = %d\n", i, GetLastError()); 915 continue; 916 } 917 ok(ret, "%d) CreateUrlCacheEntryW failed: %d\n", i, GetLastError()); 918 919 /* dwHeaderSize is ignored, pass 0 to prove it */ 920 ret = CommitUrlCacheEntryW(urls[i].url, bufW, filetime_zero, filetime_zero, 921 NORMAL_CACHE_ENTRY, urls[i].header_info, 0, urls[i].extension, NULL); 922 ok(ret, "%d) CommitUrlCacheEntryW failed: %d\n", i, GetLastError()); 923 924 SetLastError(0xdeadbeef); 925 size = 0; 926 ret = GetUrlCacheEntryInfoW(urls[i].url, NULL, &size); 927 ok(!ret && GetLastError()==ERROR_INSUFFICIENT_BUFFER, 928 "%d) GetLastError() = %d\n", i, GetLastError()); 929 entry_infoW = HeapAlloc(GetProcessHeap(), 0, size); 930 ret = GetUrlCacheEntryInfoW(urls[i].url, entry_infoW, &size); 931 ok(ret, "%d) GetUrlCacheEntryInfoW failed: %d\n", i, GetLastError()); 932 933 ret = GetUrlCacheEntryInfoA(urls[i].encoded_url, NULL, &size); 934 ok(!ret && GetLastError()==ERROR_INSUFFICIENT_BUFFER, 935 "%d) GetLastError() = %d\n", i, GetLastError()); 936 if(!ret && GetLastError()!=ERROR_INSUFFICIENT_BUFFER) { 937 win_skip("ANSI version of url is incorrect\n"); 938 continue; 939 } 940 entry_infoA = HeapAlloc(GetProcessHeap(), 0, size); 941 ret = GetUrlCacheEntryInfoA(urls[i].encoded_url, entry_infoA, &size); 942 ok(ret, "%d) GetUrlCacheEntryInfoA failed: %d\n", i, GetLastError()); 943 944 ok(entry_infoW->dwStructSize == entry_infoA->dwStructSize, 945 "%d) entry_infoW->dwStructSize = %d, expected %d\n", 946 i, entry_infoW->dwStructSize, entry_infoA->dwStructSize); 947 ok(!lstrcmpW(urls[i].url, entry_infoW->lpszSourceUrlName), 948 "%d) entry_infoW->lpszSourceUrlName = %s\n", 949 i, wine_dbgstr_w(entry_infoW->lpszSourceUrlName)); 950 ok(!lstrcmpA(urls[i].encoded_url, entry_infoA->lpszSourceUrlName), 951 "%d) entry_infoA->lpszSourceUrlName = %s\n", 952 i, entry_infoA->lpszSourceUrlName); 953 ok(entry_infoW->CacheEntryType == entry_infoA->CacheEntryType, 954 "%d) entry_infoW->CacheEntryType = %x, expected %x\n", 955 i, entry_infoW->CacheEntryType, entry_infoA->CacheEntryType); 956 ok(entry_infoW->dwUseCount == entry_infoA->dwUseCount, 957 "%d) entry_infoW->dwUseCount = %d, expected %d\n", 958 i, entry_infoW->dwUseCount, entry_infoA->dwUseCount); 959 ok(entry_infoW->dwHitRate == entry_infoA->dwHitRate, 960 "%d) entry_infoW->dwHitRate = %d, expected %d\n", 961 i, entry_infoW->dwHitRate, entry_infoA->dwHitRate); 962 ok(entry_infoW->dwSizeLow == entry_infoA->dwSizeLow, 963 "%d) entry_infoW->dwSizeLow = %d, expected %d\n", 964 i, entry_infoW->dwSizeLow, entry_infoA->dwSizeLow); 965 ok(entry_infoW->dwSizeHigh == entry_infoA->dwSizeHigh, 966 "%d) entry_infoW->dwSizeHigh = %d, expected %d\n", 967 i, entry_infoW->dwSizeHigh, entry_infoA->dwSizeHigh); 968 ok(!memcmp(&entry_infoW->LastModifiedTime, &entry_infoA->LastModifiedTime, sizeof(FILETIME)), 969 "%d) entry_infoW->LastModifiedTime is incorrect\n", i); 970 ok(!memcmp(&entry_infoW->ExpireTime, &entry_infoA->ExpireTime, sizeof(FILETIME)), 971 "%d) entry_infoW->ExpireTime is incorrect\n", i); 972 ok(!memcmp(&entry_infoW->LastAccessTime, &entry_infoA->LastAccessTime, sizeof(FILETIME)), 973 "%d) entry_infoW->LastAccessTime is incorrect\n", i); 974 ok(!memcmp(&entry_infoW->LastSyncTime, &entry_infoA->LastSyncTime, sizeof(FILETIME)), 975 "%d) entry_infoW->LastSyncTime is incorrect\n", i); 976 977 MultiByteToWideChar(CP_ACP, 0, entry_infoA->lpszLocalFileName, -1, bufW, MAX_PATH); 978 ok(!lstrcmpW(entry_infoW->lpszLocalFileName, bufW), 979 "%d) entry_infoW->lpszLocalFileName = %s, expected %s\n", 980 i, wine_dbgstr_w(entry_infoW->lpszLocalFileName), wine_dbgstr_w(bufW)); 981 982 if(!urls[i].header_info[0]) { 983 ok(!entry_infoW->lpHeaderInfo, "entry_infoW->lpHeaderInfo != NULL\n"); 984 }else { 985 ok(!lstrcmpW((WCHAR*)entry_infoW->lpHeaderInfo, urls[i].header_info), 986 "%d) entry_infoW->lpHeaderInfo = %s\n", 987 i, wine_dbgstr_w((WCHAR*)entry_infoW->lpHeaderInfo)); 988 } 989 990 if(!urls[i].extension[0]) { 991 ok(!entry_infoW->lpszFileExtension || (ie10_cache && !entry_infoW->lpszFileExtension[0]), 992 "%d) entry_infoW->lpszFileExtension = %s\n", 993 i, wine_dbgstr_w(entry_infoW->lpszFileExtension)); 994 }else { 995 MultiByteToWideChar(CP_ACP, 0, entry_infoA->lpszFileExtension, -1, bufW, MAX_PATH); 996 ok(!lstrcmpW(entry_infoW->lpszFileExtension, bufW) || 997 (ie10_cache && !lstrcmpW(entry_infoW->lpszFileExtension, urls[i].extension)), 998 "%d) entry_infoW->lpszFileExtension = %s, expected %s\n", 999 i, wine_dbgstr_w(entry_infoW->lpszFileExtension), wine_dbgstr_w(bufW)); 1000 } 1001 1002 HeapFree(GetProcessHeap(), 0, entry_infoW); 1003 HeapFree(GetProcessHeap(), 0, entry_infoA); 1004 1005 if(pDeleteUrlCacheEntryA) { 1006 ret = pDeleteUrlCacheEntryA(urls[i].encoded_url); 1007 ok(ret, "%d) DeleteUrlCacheEntryW failed: %d\n", i, GetLastError()); 1008 } 1009 } 1010 } 1011 1012 static void test_FindCloseUrlCache(void) 1013 { 1014 BOOL r; 1015 DWORD err; 1016 1017 SetLastError(0xdeadbeef); 1018 r = FindCloseUrlCache(NULL); 1019 err = GetLastError(); 1020 ok(0 == r, "expected 0, got %d\n", r); 1021 ok(ERROR_INVALID_HANDLE == err, "expected %d, got %d\n", ERROR_INVALID_HANDLE, err); 1022 } 1023 1024 static void test_GetDiskInfoA(void) 1025 { 1026 BOOL ret; 1027 DWORD error, cluster_size; 1028 DWORDLONG free, total; 1029 char path[MAX_PATH], *p; 1030 1031 GetSystemDirectoryA(path, MAX_PATH); 1032 if ((p = strchr(path, '\\'))) *++p = 0; 1033 1034 ret = GetDiskInfoA(path, &cluster_size, &free, &total); 1035 ok(ret, "GetDiskInfoA failed %u\n", GetLastError()); 1036 1037 ret = GetDiskInfoA(path, &cluster_size, &free, NULL); 1038 ok(ret, "GetDiskInfoA failed %u\n", GetLastError()); 1039 1040 ret = GetDiskInfoA(path, &cluster_size, NULL, NULL); 1041 ok(ret, "GetDiskInfoA failed %u\n", GetLastError()); 1042 1043 ret = GetDiskInfoA(path, NULL, NULL, NULL); 1044 ok(ret, "GetDiskInfoA failed %u\n", GetLastError()); 1045 1046 SetLastError(0xdeadbeef); 1047 strcpy(p, "\\non\\existing\\path"); 1048 ret = GetDiskInfoA(path, NULL, NULL, NULL); 1049 error = GetLastError(); 1050 ok(!ret || 1051 broken(old_ie && ret), /* < IE7 */ 1052 "GetDiskInfoA succeeded\n"); 1053 ok(error == ERROR_PATH_NOT_FOUND || 1054 broken(old_ie && error == 0xdeadbeef), /* < IE7 */ 1055 "got %u expected ERROR_PATH_NOT_FOUND\n", error); 1056 1057 SetLastError(0xdeadbeef); 1058 ret = GetDiskInfoA(NULL, NULL, NULL, NULL); 1059 error = GetLastError(); 1060 ok(!ret, "GetDiskInfoA succeeded\n"); 1061 ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error); 1062 } 1063 1064 static BOOL cache_entry_exists(const char *url) 1065 { 1066 static char buf[10000]; 1067 DWORD size = sizeof(buf); 1068 BOOL ret; 1069 1070 ret = GetUrlCacheEntryInfoA(url, (void*)buf, &size); 1071 ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "GetUrlCacheEntryInfoA returned %x (%u)\n", ret, GetLastError()); 1072 1073 return ret; 1074 } 1075 1076 static void test_trailing_slash(void) 1077 { 1078 char filename[MAX_PATH]; 1079 BYTE zero_byte = 0; 1080 BOOL ret; 1081 1082 static const FILETIME filetime_zero; 1083 static char url_with_slash[] = "http://testing.cache.com/"; 1084 1085 1086 ret = CreateUrlCacheEntryA(url_with_slash, 0, "html", filename, 0); 1087 ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); 1088 1089 create_and_write_file(filename, &zero_byte, sizeof(zero_byte)); 1090 1091 ret = CommitUrlCacheEntryA("Visited: http://testing.cache.com/", NULL, filetime_zero, filetime_zero, 1092 NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL); 1093 ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); 1094 1095 ok(cache_entry_exists("Visited: http://testing.cache.com/"), "cache entry does not exist\n"); 1096 ok(!cache_entry_exists("Visited: http://testing.cache.com"), "cache entry exists\n"); 1097 1098 ret = DeleteUrlCacheEntryA("Visited: http://testing.cache.com/"); 1099 ok(ret, "DeleteCacheEntryA failed\n"); 1100 DeleteFileA(filename); 1101 } 1102 1103 START_TEST(urlcache) 1104 { 1105 HMODULE hdll; 1106 hdll = GetModuleHandleA("wininet.dll"); 1107 1108 if(!GetProcAddress(hdll, "InternetGetCookieExW")) { 1109 win_skip("Too old IE (older than 6.0)\n"); 1110 return; 1111 } 1112 if(!GetProcAddress(hdll, "InternetGetSecurityInfoByURL")) /* < IE7 */ 1113 old_ie = TRUE; 1114 1115 if(GetProcAddress(hdll, "CreateUrlCacheEntryExW")) { 1116 trace("Running tests on IE10 or newer\n"); 1117 ie10_cache = TRUE; 1118 } 1119 1120 pDeleteUrlCacheEntryA = (void*)GetProcAddress(hdll, "DeleteUrlCacheEntryA"); 1121 pUnlockUrlCacheEntryFileA = (void*)GetProcAddress(hdll, "UnlockUrlCacheEntryFileA"); 1122 test_urlcacheA(); 1123 test_urlcacheW(); 1124 test_FindCloseUrlCache(); 1125 test_GetDiskInfoA(); 1126 test_trailing_slash(); 1127 } 1128