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