urlmon/tests: Keep track of download state in tests.
[wine] / dlls / urlmon / tests / url.c
1 /*
2  * UrlMon URL tests
3  *
4  * Copyright 2004 Kevin Koltzau
5  * Copyright 2004 Jacek Caban
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25 #define CONST_VTABLE
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "urlmon.h"
30 #include "wininet.h"
31
32 #include "wine/test.h"
33
34 #define DEFINE_EXPECT(func) \
35     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
36
37 #define SET_EXPECT(func) \
38     expect_ ## func = TRUE
39
40 #define CHECK_EXPECT(func) \
41     do { \
42         ok(expect_ ##func, "unexpected call " #func "\n"); \
43         expect_ ## func = FALSE; \
44         called_ ## func = TRUE; \
45     }while(0)
46
47 #define CHECK_EXPECT2(func) \
48     do { \
49         ok(expect_ ##func, "unexpected call " #func "\n"); \
50         called_ ## func = TRUE; \
51     }while(0)
52
53 #define CHECK_CALLED(func) \
54     do { \
55         ok(called_ ## func, "expected " #func "\n"); \
56         expect_ ## func = called_ ## func = FALSE; \
57     }while(0)
58
59 #define CHECK_NOT_CALLED(func) \
60     do { \
61         ok(!called_ ## func, "unexpected " #func "\n"); \
62         expect_ ## func = called_ ## func = FALSE; \
63     }while(0)
64
65 #define CLEAR_CALLED(func) \
66     expect_ ## func = called_ ## func = FALSE
67
68 DEFINE_EXPECT(QueryInterface_IServiceProvider);
69 DEFINE_EXPECT(QueryInterface_IHttpNegotiate);
70 DEFINE_EXPECT(BeginningTransaction);
71 DEFINE_EXPECT(OnResponse);
72 DEFINE_EXPECT(QueryInterface_IHttpNegotiate2);
73 DEFINE_EXPECT(GetRootSecurityId);
74 DEFINE_EXPECT(GetBindInfo);
75 DEFINE_EXPECT(OnStartBinding);
76 DEFINE_EXPECT(OnProgress_FINDINGRESOURCE);
77 DEFINE_EXPECT(OnProgress_CONNECTING);
78 DEFINE_EXPECT(OnProgress_SENDINGREQUEST);
79 DEFINE_EXPECT(OnProgress_MIMETYPEAVAILABLE);
80 DEFINE_EXPECT(OnProgress_BEGINDOWNLOADDATA);
81 DEFINE_EXPECT(OnProgress_DOWNLOADINGDATA);
82 DEFINE_EXPECT(OnProgress_ENDDOWNLOADDATA);
83 DEFINE_EXPECT(OnStopBinding);
84 DEFINE_EXPECT(OnDataAvailable);
85 DEFINE_EXPECT(Start);
86 DEFINE_EXPECT(Read);
87 DEFINE_EXPECT(LockRequest);
88 DEFINE_EXPECT(Terminate);
89 DEFINE_EXPECT(UnlockRequest);
90
91 static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'};
92 static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'};
93
94 static const WCHAR WINE_ABOUT_URL[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
95                                        'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
96 static const WCHAR ABOUT_BLANK[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
97 static WCHAR INDEX_HTML[MAX_PATH];
98 static const WCHAR ITS_URL[] =
99     {'i','t','s',':','t','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0};
100 static const WCHAR MK_URL[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':',
101     't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0};
102
103
104
105 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
106
107 static BOOL stopped_binding = FALSE, emulate_protocol = FALSE,
108     data_available = FALSE, http_is_first = TRUE;
109 static DWORD read = 0, bindf = 0;
110
111 static const LPCWSTR urls[] = {
112     WINE_ABOUT_URL,
113     ABOUT_BLANK,
114     INDEX_HTML,
115     ITS_URL,
116     MK_URL
117 };
118
119 static enum {
120     HTTP_TEST,
121     ABOUT_TEST,
122     FILE_TEST,
123     ITS_TEST,
124     MK_TEST
125 } test_protocol;
126
127 static enum {
128     BEFORE_DOWNLOAD,
129     DOWNLOADING,
130     END_DOWNLOAD
131 } download_state;
132
133 static void test_CreateURLMoniker(LPCWSTR url1, LPCWSTR url2)
134 {
135     HRESULT hr;
136     IMoniker *mon1 = NULL;
137     IMoniker *mon2 = NULL;
138
139     hr = CreateURLMoniker(NULL, url1, &mon1);
140     ok(SUCCEEDED(hr), "failed to create moniker: 0x%08x\n", hr);
141     if(SUCCEEDED(hr)) {
142         hr = CreateURLMoniker(mon1, url2, &mon2);
143         ok(SUCCEEDED(hr), "failed to create moniker: 0x%08x\n", hr);
144     }
145     if(mon1) IMoniker_Release(mon1);
146     if(mon2) IMoniker_Release(mon2);
147 }
148
149 static void test_create(void)
150 {
151     test_CreateURLMoniker(TEST_URL_1, TEST_PART_URL_1);
152 }
153
154 static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
155 {
156     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) {
157         *ppv = iface;
158         return S_OK;
159     }
160
161     *ppv = NULL;
162     return E_NOINTERFACE;
163 }
164
165 static ULONG WINAPI Protocol_AddRef(IInternetProtocol *iface)
166 {
167     return 2;
168 }
169
170 static ULONG WINAPI Protocol_Release(IInternetProtocol *iface)
171 {
172     return 1;
173 }
174
175 static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
176         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
177         DWORD grfPI, DWORD dwReserved)
178 {
179     BINDINFO bindinfo, bi = {sizeof(bi), 0};
180     DWORD bindf, bscf = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
181     WCHAR null_char = 0;
182     HRESULT hres;
183
184     static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
185
186     CHECK_EXPECT(Start);
187
188     read = 0;
189
190     ok(szUrl && !lstrcmpW(szUrl, urls[test_protocol]), "wrong url\n");
191     ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
192     ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
193     ok(grfPI == 0, "grfPI=%d, expected 0\n", grfPI);
194     ok(dwReserved == 0, "dwReserved=%d, expected 0\n", dwReserved);
195
196     memset(&bindinfo, 0, sizeof(bindinfo));
197     bindinfo.cbSize = sizeof(bindinfo);
198     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
199     ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres);
200
201     if(test_protocol == FILE_TEST || test_protocol == MK_TEST) {
202         ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA
203                      |BINDF_FROMURLMON),
204            "bindf=%08x\n", bindf);
205     }else {
206         ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA|
207                      BINDF_FROMURLMON|BINDF_NEEDFILE),
208            "bindf=%08x\n", bindf);
209     }
210
211     ok(!memcmp(&bindinfo, &bi, sizeof(bindinfo)), "wrong bindinfo\n");
212
213     switch(test_protocol) {
214     case MK_TEST:
215         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
216                 BINDSTATUS_DIRECTBIND, NULL);
217         ok(hres == S_OK,
218            "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
219
220     case FILE_TEST:
221     case ITS_TEST:
222         SET_EXPECT(OnProgress_SENDINGREQUEST);
223         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
224                 BINDSTATUS_SENDINGREQUEST, &null_char);
225         ok(hres == S_OK,
226            "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
227         CHECK_CALLED(OnProgress_SENDINGREQUEST);
228     default:
229         break;
230     }
231
232     if(test_protocol == FILE_TEST) {
233         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
234                 BINDSTATUS_CACHEFILENAMEAVAILABLE, &null_char);
235         ok(hres == S_OK,
236            "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
237
238         SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
239         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
240                 BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, wszTextHtml);
241         ok(hres == S_OK,
242            "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres);
243         CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
244     }else {
245         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
246                 BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);
247         ok(hres == S_OK,
248            "ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) failed: %08x\n", hres);
249     }
250
251     if(test_protocol == ABOUT_TEST)
252         bscf |= BSCF_DATAFULLYAVAILABLE;
253     if(test_protocol == ITS_TEST)
254         bscf = BSCF_FIRSTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
255
256     SET_EXPECT(Read);
257     if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
258         SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
259     SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
260     SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
261     SET_EXPECT(LockRequest);
262     SET_EXPECT(OnDataAvailable);
263     SET_EXPECT(OnStopBinding);
264
265     hres = IInternetProtocolSink_ReportData(pOIProtSink, bscf, 13, 13);
266     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
267
268     CHECK_CALLED(Read);
269     if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
270         CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
271     CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
272     CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
273     CHECK_CALLED(LockRequest);
274     CHECK_CALLED(OnDataAvailable);
275     CHECK_CALLED(OnStopBinding);
276
277     if(test_protocol == ITS_TEST) {
278         SET_EXPECT(Read);
279         hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_BEGINDOWNLOADDATA, NULL);
280         ok(hres == S_OK, "ReportProgress(BINDSTATUS_BEGINDOWNLOADDATA) failed: %08x\n", hres);
281         CHECK_CALLED(Read);
282     }
283
284     SET_EXPECT(Terminate);
285     hres = IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
286     ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
287     CHECK_CALLED(Terminate);
288
289     return S_OK;
290 }
291
292 static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
293         PROTOCOLDATA *pProtocolData)
294 {
295     ok(0, "unexpected call\n");
296     return E_NOTIMPL;
297 }
298
299 static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
300         DWORD dwOptions)
301 {
302     ok(0, "unexpected call\n");
303     return E_NOTIMPL;
304 }
305
306 static HRESULT WINAPI Protocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
307 {
308     CHECK_EXPECT(Terminate);
309     ok(dwOptions == 0, "dwOptions=%d, expected 0\n", dwOptions);
310     return S_OK;
311 }
312
313 static HRESULT WINAPI Protocol_Suspend(IInternetProtocol *iface)
314 {
315     ok(0, "unexpected call\n");
316     return E_NOTIMPL;
317 }
318
319 static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface)
320 {
321     ok(0, "unexpected call\n");
322     return E_NOTIMPL;
323 }
324
325 static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv,
326         ULONG cb, ULONG *pcbRead)
327 {
328     static const char data[] = "<HTML></HTML>";
329
330     CHECK_EXPECT2(Read);
331
332     if(read) {
333         *pcbRead = 0;
334         return S_FALSE;
335     }
336
337     ok(pv != NULL, "pv == NULL\n");
338     ok(cb != 0, "cb == 0\n");
339     ok(pcbRead != NULL, "pcbRead == NULL\n");
340     if(pcbRead) {
341         ok(*pcbRead == 0, "*pcbRead=%d, expected 0\n", *pcbRead);
342         read += *pcbRead = sizeof(data)-1;
343     }
344     if(pv)
345         memcpy(pv, data, sizeof(data));
346
347     return S_OK;
348 }
349
350 static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface,
351         LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
352 {
353     ok(0, "unexpected call\n");
354     return E_NOTIMPL;
355 }
356
357 static HRESULT WINAPI Protocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
358 {
359     CHECK_EXPECT(LockRequest);
360     return S_OK;
361 }
362
363 static HRESULT WINAPI Protocol_UnlockRequest(IInternetProtocol *iface)
364 {
365     CHECK_EXPECT(UnlockRequest);
366     return S_OK;
367 }
368
369 static const IInternetProtocolVtbl ProtocolVtbl = {
370     Protocol_QueryInterface,
371     Protocol_AddRef,
372     Protocol_Release,
373     Protocol_Start,
374     Protocol_Continue,
375     Protocol_Abort,
376     Protocol_Terminate,
377     Protocol_Suspend,
378     Protocol_Resume,
379     Protocol_Read,
380     Protocol_Seek,
381     Protocol_LockRequest,
382     Protocol_UnlockRequest
383 };
384
385 static IInternetProtocol Protocol = { &ProtocolVtbl };
386
387 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv)
388 {
389     if(IsEqualGUID(&IID_IUnknown, riid)
390             || IsEqualGUID(&IID_IHttpNegotiate, riid)
391             || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
392         *ppv = iface;
393         return S_OK;
394     }
395
396     ok(0, "unexpected call\n");
397     return E_NOINTERFACE;
398 }
399
400 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
401 {
402     return 2;
403 }
404
405 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
406 {
407     return 1;
408 }
409
410 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL,
411         LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
412 {
413     CHECK_EXPECT(BeginningTransaction);
414
415     ok(!lstrcmpW(szURL, urls[test_protocol]), "szURL != urls[test_protocol]\n");
416     ok(!dwReserved, "dwReserved=%d, expected 0\n", dwReserved);
417     ok(pszAdditionalHeaders != NULL, "pszAdditionalHeaders == NULL\n");
418     if(pszAdditionalHeaders)
419         ok(*pszAdditionalHeaders == NULL, "*pszAdditionalHeaders != NULL\n");
420
421     return S_OK;
422 }
423
424 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
425         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
426 {
427     CHECK_EXPECT(OnResponse);
428
429     ok(dwResponseCode == 200, "dwResponseCode=%d, expected 200\n", dwResponseCode);
430     ok(szResponseHeaders != NULL, "szResponseHeaders == NULL\n");
431     ok(szRequestHeaders == NULL, "szRequestHeaders != NULL\n");
432     /* Note: in protocol.c tests, OnResponse pszAdditionalRequestHeaders _is_ NULL */
433     ok(pszAdditionalRequestHeaders != NULL, "pszAdditionalHeaders == NULL\n");
434     if(pszAdditionalRequestHeaders)
435         ok(*pszAdditionalRequestHeaders == NULL, "*pszAdditionalHeaders != NULL\n");
436
437     return S_OK;
438 }
439
440 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
441         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
442 {
443     static const BYTE sec_id[] = {'h','t','t','p',':','t','e','s','t',1,0,0,0};
444
445     CHECK_EXPECT(GetRootSecurityId);
446
447     ok(!dwReserved, "dwReserved=%ld, expected 0\n", dwReserved);
448     ok(pbSecurityId != NULL, "pbSecurityId == NULL\n");
449     ok(pcbSecurityId != NULL, "pcbSecurityId == NULL\n");
450
451     if(pcbSecurityId) {
452         ok(*pcbSecurityId == 512, "*pcbSecurityId=%d, expected 512\n", *pcbSecurityId);
453         *pcbSecurityId = sizeof(sec_id);
454     }
455
456     if(pbSecurityId)
457         memcpy(pbSecurityId, sec_id, sizeof(sec_id));
458
459     return E_FAIL;
460 }
461
462 static IHttpNegotiate2Vtbl HttpNegotiateVtbl = {
463     HttpNegotiate_QueryInterface,
464     HttpNegotiate_AddRef,
465     HttpNegotiate_Release,
466     HttpNegotiate_BeginningTransaction,
467     HttpNegotiate_OnResponse,
468     HttpNegotiate_GetRootSecurityId
469 };
470
471 static IHttpNegotiate2 HttpNegotiate = { &HttpNegotiateVtbl };
472
473 static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
474 {
475     if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
476         if(emulate_protocol) {
477             *ppv = &Protocol;
478             return S_OK;
479         }else {
480             return E_NOINTERFACE;
481         }
482     }
483     else if (IsEqualGUID(&IID_IServiceProvider, riid))
484     {
485         CHECK_EXPECT(QueryInterface_IServiceProvider);
486     }
487     else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
488     {
489         CHECK_EXPECT(QueryInterface_IHttpNegotiate);
490         *ppv = &HttpNegotiate;
491         return S_OK;
492     }
493     else if (IsEqualGUID(&IID_IHttpNegotiate2, riid))
494     {
495         CHECK_EXPECT(QueryInterface_IHttpNegotiate2);
496         *ppv = &HttpNegotiate;
497         return S_OK;
498     }
499
500     return E_NOINTERFACE;
501 }
502
503 static ULONG WINAPI statusclb_AddRef(IBindStatusCallback *iface)
504 {
505     return 2;
506 }
507
508 static ULONG WINAPI statusclb_Release(IBindStatusCallback *iface)
509 {
510     return 1;
511 }
512
513 static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
514         IBinding *pib)
515 {
516     HRESULT hres;
517     IMoniker *mon;
518
519     CHECK_EXPECT(OnStartBinding);
520
521     ok(pib != NULL, "pib should not be NULL\n");
522
523     hres = IBinding_QueryInterface(pib, &IID_IMoniker, (void**)&mon);
524     ok(hres == E_NOINTERFACE, "IBinding should not have IMoniker interface\n");
525     if(SUCCEEDED(hres))
526         IMoniker_Release(mon);
527
528     return S_OK;
529 }
530
531 static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
532 {
533     ok(0, "unexpected call\n");
534     return E_NOTIMPL;
535 }
536
537 static HRESULT WINAPI statusclb_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
538 {
539     ok(0, "unexpected call\n");
540     return E_NOTIMPL;
541 }
542
543 static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
544         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
545 {
546     switch(ulStatusCode) {
547     case BINDSTATUS_FINDINGRESOURCE:
548         CHECK_EXPECT(OnProgress_FINDINGRESOURCE);
549         break;
550     case BINDSTATUS_CONNECTING:
551         CHECK_EXPECT(OnProgress_CONNECTING);
552         break;
553     case BINDSTATUS_SENDINGREQUEST:
554         CHECK_EXPECT(OnProgress_SENDINGREQUEST);
555         break;
556     case BINDSTATUS_MIMETYPEAVAILABLE:
557         CHECK_EXPECT(OnProgress_MIMETYPEAVAILABLE);
558         ok(download_state == BEFORE_DOWNLOAD, "Download state was %d, expected BEFORE_DOWNLOAD\n",
559            download_state);
560         break;
561     case BINDSTATUS_BEGINDOWNLOADDATA:
562         CHECK_EXPECT(OnProgress_BEGINDOWNLOADDATA);
563         ok(szStatusText != NULL, "szStatusText == NULL\n");
564         if(szStatusText)
565             ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
566         ok(download_state == BEFORE_DOWNLOAD, "Download state was %d, expected BEFORE_DOWNLOAD\n",
567            download_state);
568         download_state = DOWNLOADING;
569         break;
570     case BINDSTATUS_DOWNLOADINGDATA:
571         CHECK_EXPECT2(OnProgress_DOWNLOADINGDATA);
572         ok(download_state == DOWNLOADING, "Download state was %d, expected DOWNLOADING\n",
573            download_state);
574         break;
575     case BINDSTATUS_ENDDOWNLOADDATA:
576         CHECK_EXPECT(OnProgress_ENDDOWNLOADDATA);
577         ok(szStatusText != NULL, "szStatusText == NULL\n");
578         if(szStatusText)
579             ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
580         ok(download_state == DOWNLOADING, "Download state was %d, expected DOWNLOADING\n",
581            download_state);
582         download_state = END_DOWNLOAD;
583         break;
584     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
585         ok(szStatusText != NULL, "szStatusText == NULL\n");
586         if(szStatusText && test_protocol == FILE_TEST)
587             ok(!lstrcmpW(INDEX_HTML+7, szStatusText), "wrong szStatusText\n");
588         break;
589     default:
590         todo_wine { ok(0, "unexpexted code %d\n", ulStatusCode); }
591     };
592     return S_OK;
593 }
594
595 static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
596 {
597     CHECK_EXPECT(OnStopBinding);
598
599     /* ignore DNS failure */
600     if (hresult != HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED))
601     {
602         ok(SUCCEEDED(hresult), "Download failed: %08x\n", hresult);
603         ok(szError == NULL, "szError should be NULL\n");
604     }
605     stopped_binding = TRUE;
606
607     return S_OK;
608 }
609
610 static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
611 {
612     DWORD cbSize;
613
614     CHECK_EXPECT(GetBindInfo);
615
616     *grfBINDF = bindf;
617     cbSize = pbindinfo->cbSize;
618     memset(pbindinfo, 0, cbSize);
619     pbindinfo->cbSize = cbSize;
620
621     return S_OK;
622 }
623
624 static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
625         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
626 {
627     HRESULT hres;
628     DWORD readed;
629     BYTE buf[512];
630
631     CHECK_EXPECT2(OnDataAvailable);
632     ok(download_state == DOWNLOADING || download_state == END_DOWNLOAD,
633        "Download state was %d, expected DOWNLOADING or END_DOWNLOAD\n",
634        download_state);
635     data_available = TRUE;
636
637     if (0)
638     {
639     /* FIXME: Uncomment after removing BindToStorage hack. */
640     ok(pformatetc != NULL, "pformatetx == NULL\n");
641     if(pformatetc) {
642         ok(pformatetc->cfFormat == 0xc02d, "clipformat=%x\n", pformatetc->cfFormat); 
643         ok(pformatetc->ptd == NULL, "ptd = %p\n", pformatetc->ptd);
644         ok(pformatetc->dwAspect == 1, "dwAspect=%u\n", pformatetc->dwAspect);
645         ok(pformatetc->lindex == -1, "lindex=%d\n", pformatetc->lindex);
646         ok(pformatetc->tymed == TYMED_ISTREAM, "tymed=%u\n", pformatetc->tymed);
647     }
648
649     ok(pstgmed != NULL, "stgmeg == NULL\n");
650     if(pstgmed) {
651         ok(pstgmed->tymed == TYMED_ISTREAM, "tymed=%u\n", pstgmed->tymed);
652         ok(U(*pstgmed).pstm != NULL, "pstm == NULL\n");
653         ok(pstgmed->pUnkForRelease != NULL, "pUnkForRelease == NULL\n");
654     }
655     }
656
657     if(U(*pstgmed).pstm) {
658         do hres = IStream_Read(U(*pstgmed).pstm, buf, 512, &readed);
659         while(hres == S_OK);
660         ok(hres == S_FALSE || hres == E_PENDING, "IStream_Read returned %08x\n", hres);
661     }
662
663     return S_OK;
664 }
665
666 static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
667 {
668     ok(0, "unexpected call\n");
669     return E_NOTIMPL;
670 }
671
672 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
673     statusclb_QueryInterface,
674     statusclb_AddRef,
675     statusclb_Release,
676     statusclb_OnStartBinding,
677     statusclb_GetPriority,
678     statusclb_OnLowResource,
679     statusclb_OnProgress,
680     statusclb_OnStopBinding,
681     statusclb_GetBindInfo,
682     statusclb_OnDataAvailable,
683     statusclb_OnObjectAvailable
684 };
685
686 static IBindStatusCallback bsc = { &BindStatusCallbackVtbl };
687
688 static void test_CreateAsyncBindCtx(void)
689 {
690     IBindCtx *bctx = (IBindCtx*)0x0ff00ff0;
691     HRESULT hres;
692     ULONG ref;
693     BIND_OPTS bindopts;
694
695     hres = CreateAsyncBindCtx(0, NULL, NULL, &bctx);
696     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08x\n", hres);
697     ok(bctx == (IBindCtx*)0x0ff00ff0, "bctx should not be changed\n");
698
699     hres = CreateAsyncBindCtx(0, NULL, NULL, NULL);
700     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08x\n", hres);
701
702     SET_EXPECT(QueryInterface_IServiceProvider);
703     hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
704     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08x\n", hres);
705     todo_wine CHECK_CALLED(QueryInterface_IServiceProvider);
706
707     bindopts.cbStruct = sizeof(bindopts);
708     hres = IBindCtx_GetBindOptions(bctx, &bindopts);
709     ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08x\n", hres);
710     ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
711                 "bindopts.grfFlags = %08x, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
712     ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
713                 "bindopts.grfMode = %08x, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
714                 bindopts.grfMode);
715     ok(bindopts.dwTickCountDeadline == 0,
716                 "bindopts.dwTickCountDeadline = %08x, expected: 0\n", bindopts.dwTickCountDeadline);
717
718     ref = IBindCtx_Release(bctx);
719     ok(ref == 0, "bctx should be destroyed here\n");
720 }
721
722 static void test_CreateAsyncBindCtxEx(void)
723 {
724     IBindCtx *bctx = NULL, *bctx_arg = NULL;
725     BIND_OPTS bindopts;
726     HRESULT hres;
727
728     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, NULL, 0);
729     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed: %08x, expected E_INVALIDARG\n", hres);
730
731     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
732     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
733
734     if(SUCCEEDED(hres)) {
735         bindopts.cbStruct = sizeof(bindopts);
736         hres = IBindCtx_GetBindOptions(bctx, &bindopts);
737         ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08x\n", hres);
738         ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
739                 "bindopts.grfFlags = %08x, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
740         ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
741                 "bindopts.grfMode = %08x, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
742                 bindopts.grfMode);
743         ok(bindopts.dwTickCountDeadline == 0,
744                 "bindopts.dwTickCountDeadline = %08x, expected: 0\n", bindopts.dwTickCountDeadline);
745
746         IBindCtx_Release(bctx);
747     }
748
749     CreateBindCtx(0, &bctx_arg);
750     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
751     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
752
753     if(SUCCEEDED(hres)) {
754         bindopts.cbStruct = sizeof(bindopts);
755         hres = IBindCtx_GetBindOptions(bctx, &bindopts);
756         ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08x\n", hres);
757         ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
758                 "bindopts.grfFlags = %08x, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
759         ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
760                 "bindopts.grfMode = %08x, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
761                 bindopts.grfMode);
762         ok(bindopts.dwTickCountDeadline == 0,
763                 "bindopts.dwTickCountDeadline = %08x, expected: 0\n", bindopts.dwTickCountDeadline);
764
765         IBindCtx_Release(bctx);
766     }
767
768     IBindCtx_Release(bctx_arg);
769
770     SET_EXPECT(QueryInterface_IServiceProvider);
771     hres = CreateAsyncBindCtxEx(NULL, 0, &bsc, NULL, &bctx, 0);
772     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
773     todo_wine CHECK_CALLED(QueryInterface_IServiceProvider);
774
775     if(SUCCEEDED(hres))
776         IBindCtx_Release(bctx);
777 }
778
779 static void test_BindToStorage(int protocol, BOOL emul)
780 {
781     IMoniker *mon;
782     HRESULT hres;
783     LPOLESTR display_name;
784     IBindCtx *bctx;
785     MSG msg;
786     IBindStatusCallback *previousclb;
787     IUnknown *unk = (IUnknown*)0x00ff00ff;
788     IBinding *bind;
789
790     test_protocol = protocol;
791     emulate_protocol = emul;
792     download_state = BEFORE_DOWNLOAD;
793     stopped_binding = FALSE;
794     data_available = FALSE;
795
796     SET_EXPECT(QueryInterface_IServiceProvider);
797     hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
798     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08x\n\n", hres);
799     if(FAILED(hres))
800         return;
801     todo_wine CHECK_CALLED(QueryInterface_IServiceProvider);
802
803     SET_EXPECT(QueryInterface_IServiceProvider);
804     hres = RegisterBindStatusCallback(bctx, &bsc, &previousclb, 0);
805     ok(SUCCEEDED(hres), "RegisterBindStatusCallback failed: %08x\n", hres);
806     ok(previousclb == &bsc, "previousclb(%p) != sclb(%p)\n", previousclb, &bsc);
807     todo_wine CHECK_CALLED(QueryInterface_IServiceProvider);
808     if(previousclb)
809         IBindStatusCallback_Release(previousclb);
810
811     hres = CreateURLMoniker(NULL, urls[test_protocol], &mon);
812     ok(SUCCEEDED(hres), "failed to create moniker: %08x\n", hres);
813     if(FAILED(hres)) {
814         IBindCtx_Release(bctx);
815         return;
816     }
817
818     if(test_protocol == FILE_TEST && INDEX_HTML[7] == '/')
819         memmove(INDEX_HTML+7, INDEX_HTML+8, lstrlenW(INDEX_HTML+7)*sizeof(WCHAR));
820
821     hres = IMoniker_QueryInterface(mon, &IID_IBinding, (void**)&bind);
822     ok(hres == E_NOINTERFACE, "IMoniker should not have IBinding interface\n");
823     if(SUCCEEDED(hres))
824         IBinding_Release(bind);
825
826     hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name);
827     ok(hres == S_OK, "GetDisplayName failed %08x\n", hres);
828     ok(!lstrcmpW(display_name, urls[test_protocol]), "GetDisplayName got wrong name\n");
829
830     SET_EXPECT(QueryInterface_IServiceProvider);
831     SET_EXPECT(GetBindInfo);
832     SET_EXPECT(OnStartBinding);
833     if(emulate_protocol) {
834         SET_EXPECT(Start);
835         SET_EXPECT(UnlockRequest);
836     }else {
837         if(test_protocol == HTTP_TEST) {
838             SET_EXPECT(QueryInterface_IHttpNegotiate);
839             SET_EXPECT(BeginningTransaction);
840             SET_EXPECT(QueryInterface_IHttpNegotiate2);
841             SET_EXPECT(GetRootSecurityId);
842             SET_EXPECT(OnProgress_FINDINGRESOURCE);
843             SET_EXPECT(OnProgress_CONNECTING);
844         }
845         if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST)
846             SET_EXPECT(OnProgress_SENDINGREQUEST);
847         if(test_protocol == HTTP_TEST)
848             SET_EXPECT(OnResponse);
849         SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
850         SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
851         if(test_protocol == HTTP_TEST)
852             SET_EXPECT(OnProgress_DOWNLOADINGDATA);
853         SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
854         SET_EXPECT(OnDataAvailable);
855         SET_EXPECT(OnStopBinding);
856     }
857
858     hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
859     if (test_protocol == HTTP_TEST && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED))
860     {
861         trace( "Network unreachable, skipping tests\n" );
862         return;
863     }
864     if (!SUCCEEDED(hres)) return;
865
866     if((bindf & BINDF_ASYNCHRONOUS) && !data_available) {
867         ok(hres == MK_S_ASYNCHRONOUS, "IMoniker_BindToStorage failed: %08x\n", hres);
868         ok(unk == NULL, "istr should be NULL\n");
869     }else {
870         ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres);
871         ok(unk != NULL, "unk == NULL\n");
872     }
873     if(unk)
874         IUnknown_Release(unk);
875
876     while((bindf & BINDF_ASYNCHRONOUS) &&
877           !stopped_binding && GetMessage(&msg,NULL,0,0)) {
878         TranslateMessage(&msg);
879         DispatchMessage(&msg);
880     }
881
882     CHECK_CALLED(GetBindInfo);
883     CHECK_CALLED(OnStartBinding);
884     if(emulate_protocol) {
885         todo_wine CHECK_NOT_CALLED(QueryInterface_IServiceProvider);
886         CHECK_CALLED(Start);
887         CHECK_CALLED(UnlockRequest);
888     }else {
889         if(test_protocol == HTTP_TEST) {
890             CHECK_NOT_CALLED(QueryInterface_IServiceProvider);
891             todo_wine CHECK_CALLED(QueryInterface_IHttpNegotiate);
892             todo_wine CHECK_CALLED(BeginningTransaction);
893             /* QueryInterface_IHttpNegotiate2 and GetRootSecurityId
894              * called on WinXP but not on Win98 */
895             CLEAR_CALLED(QueryInterface_IHttpNegotiate2);
896             CLEAR_CALLED(GetRootSecurityId);
897             if(http_is_first) {
898                 CHECK_CALLED(OnProgress_FINDINGRESOURCE);
899                 CHECK_CALLED(OnProgress_CONNECTING);
900             }else todo_wine {
901                 CHECK_NOT_CALLED(OnProgress_FINDINGRESOURCE);
902                 CHECK_NOT_CALLED(OnProgress_CONNECTING);
903             }
904             CHECK_CALLED(OnProgress_SENDINGREQUEST);
905             todo_wine CHECK_CALLED(OnResponse);
906             todo_wine { CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); }
907         }else {
908             todo_wine CHECK_NOT_CALLED(QueryInterface_IServiceProvider);
909             CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
910         }
911         CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
912         if(test_protocol == HTTP_TEST)
913             CHECK_CALLED(OnProgress_DOWNLOADINGDATA);
914         CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
915         CHECK_CALLED(OnDataAvailable);
916         CHECK_CALLED(OnStopBinding);
917     }
918
919     ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
920     ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
921
922     if(test_protocol == HTTP_TEST)
923         http_is_first = FALSE;
924 }
925
926 static void set_file_url(void)
927 {
928     int len;
929
930     static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'};
931
932     memcpy(INDEX_HTML, wszFile, sizeof(wszFile));
933     len = sizeof(wszFile)/sizeof(WCHAR);
934     INDEX_HTML[len++] = '/';
935     len += GetCurrentDirectoryW(sizeof(INDEX_HTML)/sizeof(WCHAR)-len, INDEX_HTML+len);
936     INDEX_HTML[len++] = '\\';
937     memcpy(INDEX_HTML+len, wszIndexHtml, sizeof(wszIndexHtml));
938 }
939
940 static void create_file(void)
941 {
942     HANDLE file;
943     DWORD size;
944
945     static const char html_doc[] = "<HTML></HTML>";
946
947     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
948             FILE_ATTRIBUTE_NORMAL, NULL);
949     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
950     if(file == INVALID_HANDLE_VALUE)
951         return;
952
953     WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL);
954     CloseHandle(file);
955
956     set_file_url();
957 }
958
959 static void test_BindToStorage_fail(void)
960 {
961     IMoniker *mon = NULL;
962     IBindCtx *bctx = NULL;
963     IUnknown *unk;
964     HRESULT hres;
965
966     hres = CreateURLMoniker(NULL, ABOUT_BLANK, &mon);
967     ok(hres == S_OK, "CreateURLMoniker failed: %08x\n", hres);
968     if(FAILED(hres))
969         return;
970
971     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
972     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
973
974     hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
975     ok(hres == MK_E_SYNTAX, "hres=%08x, expected INET_E_SYNTAX\n", hres);
976
977     IBindCtx_Release(bctx);
978
979     IMoniker_Release(mon);
980 }
981
982 START_TEST(url)
983 {
984     test_create();
985     test_CreateAsyncBindCtx();
986     test_CreateAsyncBindCtxEx();
987
988     trace("synchronous http test...\n");
989     test_BindToStorage(HTTP_TEST, FALSE);
990
991     trace("synchronous file test...\n");
992     create_file();
993     test_BindToStorage(FILE_TEST, FALSE);
994     DeleteFileW(wszIndexHtml);
995
996     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
997
998     trace("http test...\n");
999     test_BindToStorage(HTTP_TEST, FALSE);
1000
1001     trace("about test...\n");
1002     CoInitialize(NULL);
1003     test_BindToStorage(ABOUT_TEST, FALSE);
1004     CoUninitialize();
1005
1006     trace("emulated about test...\n");
1007     test_BindToStorage(ABOUT_TEST, TRUE);
1008
1009     trace("file test...\n");
1010     create_file();
1011     test_BindToStorage(FILE_TEST, FALSE);
1012     DeleteFileW(wszIndexHtml);
1013
1014     trace("emulated file test...\n");
1015     set_file_url();
1016     test_BindToStorage(FILE_TEST, TRUE);
1017
1018     trace("emulated its test...\n");
1019     test_BindToStorage(ITS_TEST, TRUE);
1020
1021     trace("emulated mk test...\n");
1022     test_BindToStorage(MK_TEST, TRUE);
1023
1024     test_BindToStorage_fail();
1025 }