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