query: Add a stub implementation for LocateCatalogs.
[wine] / dlls / urlmon / tests / protocol.c
1 /*
2  * Copyright 2005 Jacek Caban
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20
21 #include <wine/test.h>
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "ole2.h"
27 #include "urlmon.h"
28
29 #include "initguid.h"
30
31 #define DEFINE_EXPECT(func) \
32     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
33
34 #define SET_EXPECT(func) \
35     expect_ ## func = TRUE
36
37 #define CHECK_EXPECT(func) \
38     do { \
39         ok(expect_ ##func, "unexpected call " #func "\n"); \
40         expect_ ## func = FALSE; \
41         called_ ## func = TRUE; \
42     }while(0)
43
44 #define CHECK_EXPECT2(func) \
45     do { \
46         ok(expect_ ##func, "unexpected call " #func  "\n"); \
47         called_ ## func = TRUE; \
48     }while(0)
49
50 #define CHECK_CALLED(func) \
51     do { \
52         ok(called_ ## func, "expected " #func "\n"); \
53         expect_ ## func = called_ ## func = FALSE; \
54     }while(0)
55
56 DEFINE_EXPECT(GetBindInfo);
57 DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
58 DEFINE_EXPECT(ReportProgress_DIRECTBIND);
59 DEFINE_EXPECT(ReportProgress_FINDINGRESOURCE);
60 DEFINE_EXPECT(ReportProgress_CONNECTING);
61 DEFINE_EXPECT(ReportProgress_SENDINGREQUEST);
62 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
63 DEFINE_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
64 DEFINE_EXPECT(ReportData);
65 DEFINE_EXPECT(ReportResult);
66 DEFINE_EXPECT(GetBindString_ACCEPT_MIMES);
67 DEFINE_EXPECT(GetBindString_USER_AGENT);
68 DEFINE_EXPECT(QueryService_HttpNegotiate);
69 DEFINE_EXPECT(BeginningTransaction);
70 DEFINE_EXPECT(GetRootSecurityId);
71 DEFINE_EXPECT(OnResponse);
72 DEFINE_EXPECT(Switch);
73
74 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
75 static const WCHAR index_url[] =
76     {'f','i','l','e',':','i','n','d','e','x','.','h','t','m','l',0};
77
78 static HRESULT expect_hrResult;
79 static LPCWSTR file_name, http_url;
80 static IInternetProtocol *http_protocol = NULL;
81 static BOOL first_data_notif = FALSE;
82 static HWND protocol_hwnd;
83 static int state = 0;
84 static DWORD bindf = 0;
85
86 static enum {
87     FILE_TEST,
88     HTTP_TEST
89 } tested_protocol;
90
91 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv)
92 {
93     if(IsEqualGUID(&IID_IUnknown, riid)
94             || IsEqualGUID(&IID_IHttpNegotiate, riid)
95             || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
96         *ppv = iface;
97         return S_OK;
98     }
99
100     ok(0, "unexpected call\n");
101     return E_NOINTERFACE;
102 }
103
104 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
105 {
106     return 2;
107 }
108
109 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
110 {
111     return 1;
112 }
113
114 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL,
115         LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
116 {
117     CHECK_EXPECT(BeginningTransaction);
118
119     ok(!lstrcmpW(szURL, http_url), "szURL != http_url\n");
120
121     ok(szHeaders != NULL, "szHeaders == NULL\n");
122     if(szHeaders) {
123         static const WCHAR header[] =
124             {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',':',
125              ' ','g','z','i','p',',',' ','d','e','f','l','a','t','e',0};
126         ok(!lstrcmpW(header, szHeaders), "Unexpected szHeaders\n");
127     }
128
129     ok(!dwReserved, "dwReserved=%ld, expected 0\n", dwReserved);
130     ok(pszAdditionalHeaders != NULL, "pszAdditionalHeaders == NULL\n");
131     if(pszAdditionalHeaders)
132         ok(*pszAdditionalHeaders == NULL, "*pszAdditionalHeaders != NULL\n");
133
134     return S_OK;
135 }
136
137 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
138         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
139 {
140     CHECK_EXPECT(OnResponse);
141
142     ok(dwResponseCode == 200, "dwResponseCode=%ld, expected 200\n", dwResponseCode);
143     ok(szResponseHeaders != NULL, "szResponseHeaders == NULL\n");
144     ok(szRequestHeaders == NULL, "szRequestHeaders != NULL\n");
145     ok(pszAdditionalRequestHeaders == NULL, "pszAdditionalHeaders != NULL\n");
146
147     return S_OK;
148 }
149
150 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
151         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
152 {
153     static const BYTE sec_id[] = {'h','t','t','p',':','t','e','s','t',1,0,0,0};
154     
155     CHECK_EXPECT(GetRootSecurityId);
156
157     ok(!dwReserved, "dwReserved=%ld, expected 0\n", dwReserved);
158     ok(pbSecurityId != NULL, "pbSecurityId == NULL\n");
159     ok(pcbSecurityId != NULL, "pcbSecurityId == NULL\n");
160
161     if(pcbSecurityId) {
162         ok(*pcbSecurityId == 512, "*pcbSecurityId=%ld, expected 512\n", *pcbSecurityId);
163         *pcbSecurityId = sizeof(sec_id);
164     }
165
166     if(pbSecurityId)
167         memcpy(pbSecurityId, sec_id, sizeof(sec_id));
168
169     return E_FAIL;
170 }
171
172 static IHttpNegotiate2Vtbl HttpNegotiateVtbl = {
173     HttpNegotiate_QueryInterface,
174     HttpNegotiate_AddRef,
175     HttpNegotiate_Release,
176     HttpNegotiate_BeginningTransaction,
177     HttpNegotiate_OnResponse,
178     HttpNegotiate_GetRootSecurityId
179 };
180
181 static IHttpNegotiate2 http_negotiate = { &HttpNegotiateVtbl };
182
183 static HRESULT QueryInterface(REFIID,void**);
184
185 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
186 {
187     return QueryInterface(riid, ppv);
188 }
189
190 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
191 {
192     return 2;
193 }
194
195 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
196 {
197     return 1;
198 }
199
200 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
201         REFIID riid, void **ppv)
202 {
203     if(IsEqualGUID(&IID_IHttpNegotiate, guidService) || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
204         CHECK_EXPECT2(QueryService_HttpNegotiate);
205         return IHttpNegotiate2_QueryInterface(&http_negotiate, riid, ppv);
206     }
207
208     ok(0, "unexpected call\n");
209     return E_FAIL;
210 }
211
212 static const IServiceProviderVtbl ServiceProviderVtbl = {
213     ServiceProvider_QueryInterface,
214     ServiceProvider_AddRef,
215     ServiceProvider_Release,
216     ServiceProvider_QueryService
217 };
218
219 static IServiceProvider service_provider = { &ServiceProviderVtbl };
220
221 static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv)
222 {
223     return QueryInterface(riid, ppv);
224 }
225
226 static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface)
227 {
228     return 2;
229 }
230
231 static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface)
232 {
233     return 1;
234 }
235
236 static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData)
237 {
238     CHECK_EXPECT2(Switch);
239     ok(pProtocolData != NULL, "pProtocolData == NULL\n");
240     SendMessageW(protocol_hwnd, WM_USER, 0, (LPARAM)pProtocolData);
241     return S_OK;
242 }
243
244 static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode,
245         LPCWSTR szStatusText)
246 {
247     static const WCHAR text_html[] = {'t','e','x','t','/','h','t','m','l',0};
248     static const WCHAR host[] =
249         {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
250     static const WCHAR wszWineHQIP[] =
251         {'2','0','9','.','3','2','.','1','4','1','.','3',0};
252     /* I'm not sure if it's a good idea to hardcode here the IP address... */
253
254     switch(ulStatusCode) {
255     case BINDSTATUS_MIMETYPEAVAILABLE:
256         CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
257         ok(szStatusText != NULL, "szStatusText == NULL\n");
258         if(szStatusText)
259             ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n");
260         break;
261     case BINDSTATUS_DIRECTBIND:
262         CHECK_EXPECT2(ReportProgress_DIRECTBIND);
263         ok(szStatusText == NULL, "szStatusText != NULL\n");
264         break;
265     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
266         CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
267         ok(szStatusText != NULL, "szStatusText == NULL\n");
268         if(szStatusText)
269             ok(!lstrcmpW(szStatusText, file_name), "szStatusText != file_name\n");
270         break;
271     case BINDSTATUS_FINDINGRESOURCE:
272         CHECK_EXPECT(ReportProgress_FINDINGRESOURCE);
273         ok(szStatusText != NULL, "szStatusText == NULL\n");
274         if(szStatusText)
275             ok(!lstrcmpW(szStatusText, host), "szStatustext != \"www.winehq.org\"\n");
276         break;
277     case BINDSTATUS_CONNECTING:
278         CHECK_EXPECT(ReportProgress_CONNECTING);
279         ok(szStatusText != NULL, "szStatusText == NULL\n");
280         if(szStatusText)
281             ok(!lstrcmpW(szStatusText, wszWineHQIP), "Unexpected szStatusText\n");
282         break;
283     case BINDSTATUS_SENDINGREQUEST:
284         CHECK_EXPECT(ReportProgress_SENDINGREQUEST);
285         if(tested_protocol == FILE_TEST) {
286             ok(szStatusText != NULL, "szStatusText == NULL\n");
287             if(szStatusText)
288                 ok(!*szStatusText, "wrong szStatusText\n");
289         }else {
290             ok(szStatusText == NULL, "szStatusText != NULL\n");
291         }
292         break;
293     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
294         CHECK_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
295         ok(szStatusText != NULL, "szStatusText == NULL\n");
296         if(szStatusText)
297             ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n");
298         break;
299     default:
300         ok(0, "Unexpected call %ld\n", ulStatusCode);
301     };
302
303     return S_OK;
304 }
305
306 static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF,
307         ULONG ulProgress, ULONG ulProgressMax)
308 {
309     if(tested_protocol == FILE_TEST) {
310         CHECK_EXPECT2(ReportData);
311
312         ok(ulProgress == ulProgressMax, "ulProgress (%ld) != ulProgressMax (%ld)\n",
313            ulProgress, ulProgressMax);
314         ok(ulProgressMax == 13, "ulProgressMax=%ld, expected 13\n", ulProgressMax);
315         ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION),
316                 "grcfBSCF = %08lx\n", grfBSCF);
317     }else if(tested_protocol == HTTP_TEST) {
318         if(!(grfBSCF & BSCF_LASTDATANOTIFICATION))
319             CHECK_EXPECT(ReportData);
320
321         ok(ulProgress, "ulProgress == 0\n");
322
323         if(first_data_notif) {
324             ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION, "grcfBSCF = %08lx\n", grfBSCF);
325             first_data_notif = FALSE;
326         } else {
327             ok(grfBSCF == BSCF_INTERMEDIATEDATANOTIFICATION
328                || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION),
329                "grcfBSCF = %08lx\n", grfBSCF);
330         }
331     }
332     return S_OK;
333 }
334
335 static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult,
336         DWORD dwError, LPCWSTR szResult)
337 {
338     CHECK_EXPECT(ReportResult);
339
340     ok(hrResult == expect_hrResult, "hrResult = %08lx, expected: %08lx\n",
341             hrResult, expect_hrResult);
342     if(SUCCEEDED(hrResult))
343         ok(dwError == ERROR_SUCCESS, "dwError = %ld, expected ERROR_SUCCESS\n", dwError);
344     else
345         ok(dwError != ERROR_SUCCESS, "dwError == ERROR_SUCCESS\n");
346     ok(!szResult, "szResult != NULL\n");
347
348     return S_OK;
349 }
350
351 static IInternetProtocolSinkVtbl protocol_sink_vtbl = {
352     ProtocolSink_QueryInterface,
353     ProtocolSink_AddRef,
354     ProtocolSink_Release,
355     ProtocolSink_Switch,
356     ProtocolSink_ReportProgress,
357     ProtocolSink_ReportData,
358     ProtocolSink_ReportResult
359 };
360
361 static IInternetProtocolSink protocol_sink = { &protocol_sink_vtbl };
362
363 static HRESULT QueryInterface(REFIID riid, void **ppv)
364 {
365     *ppv = NULL;
366
367     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid))
368         *ppv = &protocol_sink;
369     if(IsEqualGUID(&IID_IServiceProvider, riid))
370         *ppv = &service_provider;
371
372     if(*ppv)
373         return S_OK;
374
375     return E_NOINTERFACE;
376 }
377
378 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
379 {
380     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo, riid)) {
381         *ppv = iface;
382         return S_OK;
383     }
384     return E_NOINTERFACE;
385 }
386
387 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
388 {
389     return 2;
390 }
391
392 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
393 {
394     return 1;
395 }
396
397 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
398 {
399     DWORD cbSize;
400
401     CHECK_EXPECT(GetBindInfo);
402
403     ok(grfBINDF != NULL, "grfBINDF == NULL\n");
404     ok(pbindinfo != NULL, "pbindinfo == NULL\n");
405     ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %ld\n", pbindinfo->cbSize);
406
407     *grfBINDF = bindf;
408     cbSize = pbindinfo->cbSize;
409     memset(pbindinfo, 0, cbSize);
410     pbindinfo->cbSize = cbSize;
411
412     return S_OK;
413 }
414
415 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType,
416         LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
417 {
418     static const WCHAR acc_mime[] = {'*','/','*',0};
419     static const WCHAR user_agent[] = {'W','i','n','e',0};
420
421     ok(ppwzStr != NULL, "ppwzStr == NULL\n");
422     ok(pcElFetched != NULL, "pcElFetched == NULL\n");
423
424     switch(ulStringType) {
425     case BINDSTRING_ACCEPT_MIMES:
426         CHECK_EXPECT(GetBindString_ACCEPT_MIMES);
427         ok(cEl == 256, "cEl=%ld, expected 256\n", cEl);
428         if(pcElFetched) {
429             ok(*pcElFetched == 256, "*pcElFetched=%ld, expected 256\n", *pcElFetched);
430             *pcElFetched = 1;
431         }
432         if(ppwzStr) {
433             *ppwzStr = CoTaskMemAlloc(sizeof(acc_mime));
434             memcpy(*ppwzStr, acc_mime, sizeof(acc_mime));
435         }
436         return S_OK;
437     case BINDSTRING_USER_AGENT:
438         CHECK_EXPECT(GetBindString_USER_AGENT);
439         ok(cEl == 1, "cEl=%ld, expected 1\n", cEl);
440         if(pcElFetched) {
441             ok(*pcElFetched == 0, "*pcElFetch=%ld, expectd 0\n", *pcElFetched);
442             *pcElFetched = 1;
443         }
444         if(ppwzStr) {
445             *ppwzStr = CoTaskMemAlloc(sizeof(user_agent));
446             memcpy(*ppwzStr, user_agent, sizeof(user_agent));
447         }
448         return S_OK;
449     default:
450         ok(0, "unexpected call\n");
451     }
452
453     return E_NOTIMPL;
454 }
455
456 static IInternetBindInfoVtbl bind_info_vtbl = {
457     BindInfo_QueryInterface,
458     BindInfo_AddRef,
459     BindInfo_Release,
460     BindInfo_GetBindInfo,
461     BindInfo_GetBindString
462 };
463
464 static IInternetBindInfo bind_info = { &bind_info_vtbl };
465
466 static void test_priority(IInternetProtocol *protocol)
467 {
468     IInternetPriority *priority;
469     LONG pr;
470     HRESULT hres;
471
472     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority,
473                                             (void**)&priority);
474     ok(hres == S_OK, "QueryInterface(IID_IInternetPriority) failed: %08lx\n", hres);
475     if(FAILED(hres))
476         return;
477
478     hres = IInternetPriority_GetPriority(priority, &pr);
479     ok(hres == S_OK, "GetPriority failed: %08lx\n", hres);
480     ok(pr == 0, "pr=%ld, expected 0\n", pr);
481
482     hres = IInternetPriority_SetPriority(priority, 1);
483     ok(hres == S_OK, "SetPriority failed: %08lx\n", hres);
484
485     hres = IInternetPriority_GetPriority(priority, &pr);
486     ok(hres == S_OK, "GetPriority failed: %08lx\n", hres);
487     ok(pr == 1, "pr=%ld, expected 1\n", pr);
488
489     IInternetPriority_Release(priority);
490 }
491
492 static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL is_first)
493 {
494     HRESULT hres;
495
496     SET_EXPECT(GetBindInfo);
497     if(!(bindf & BINDF_FROMURLMON))
498        SET_EXPECT(ReportProgress_DIRECTBIND);
499     if(is_first) {
500         SET_EXPECT(ReportProgress_SENDINGREQUEST);
501         SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
502         if(bindf & BINDF_FROMURLMON)
503             SET_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
504         else
505             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
506     }
507     SET_EXPECT(ReportData);
508     if(is_first)
509         SET_EXPECT(ReportResult);
510
511     expect_hrResult = S_OK;
512
513     hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0);
514     ok(hres == S_OK, "Start failed: %08lx\n", hres);
515
516     CHECK_CALLED(GetBindInfo);
517     if(!(bindf & BINDF_FROMURLMON))
518        CHECK_CALLED(ReportProgress_DIRECTBIND);
519     if(is_first) {
520         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
521         CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
522         if(bindf & BINDF_FROMURLMON)
523             CHECK_CALLED(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
524         else
525             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
526     }
527     CHECK_CALLED(ReportData);
528     if(is_first)
529         CHECK_CALLED(ReportResult);
530 }
531
532 static void test_file_protocol_url(LPCWSTR url)
533 {
534     IInternetProtocolInfo *protocol_info;
535     IUnknown *unk;
536     IClassFactory *factory;
537     HRESULT hres;
538
539     hres = CoGetClassObject(&CLSID_FileProtocol, CLSCTX_INPROC_SERVER, NULL,
540             &IID_IUnknown, (void**)&unk);
541     ok(hres == S_OK, "CoGetClassObject failed: %08lx\n", hres);
542     if(!SUCCEEDED(hres))
543         return;
544
545     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
546     ok(hres == E_NOINTERFACE,
547             "Could not get IInternetProtocolInfo interface: %08lx, expected E_NOINTERFACE\n", hres);
548
549     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
550     ok(hres == S_OK, "Could not get IClassFactory interface\n");
551     if(SUCCEEDED(hres)) {
552         IInternetProtocol *protocol;
553         BYTE buf[512];
554         ULONG cb;
555         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
556         ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres);
557
558         if(SUCCEEDED(hres)) {
559             file_protocol_start(protocol, url, TRUE);
560             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
561             ok(hres == S_OK, "Read failed: %08lx\n", hres);
562             ok(cb == 2, "cb=%lu expected 2\n", cb);
563             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
564             ok(hres == S_FALSE, "Read failed: %08lx\n", hres);
565             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
566             ok(hres == S_FALSE, "Read failed: %08lx expected S_FALSE\n", hres);
567             ok(cb == 0, "cb=%lu expected 0\n", cb);
568             hres = IInternetProtocol_UnlockRequest(protocol);
569             ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres);
570
571             file_protocol_start(protocol, url, FALSE);
572             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
573             ok(hres == S_FALSE, "Read failed: %08lx\n", hres);
574             hres = IInternetProtocol_LockRequest(protocol, 0);
575             ok(hres == S_OK, "LockRequest failed: %08lx\n", hres);
576             hres = IInternetProtocol_UnlockRequest(protocol);
577             ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres);
578
579             IInternetProtocol_Release(protocol);
580         }
581
582         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
583         ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres);
584
585         if(SUCCEEDED(hres)) {
586             file_protocol_start(protocol, url, TRUE);
587             hres = IInternetProtocol_LockRequest(protocol, 0);
588             ok(hres == S_OK, "LockRequest failed: %08lx\n", hres);
589             hres = IInternetProtocol_Terminate(protocol, 0);
590             ok(hres == S_OK, "Terminate failed: %08lx\n", hres);
591             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
592             ok(hres == S_OK, "Read failed: %08lx\n\n", hres);
593             hres = IInternetProtocol_UnlockRequest(protocol);
594             ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres);
595             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
596             ok(hres == S_OK, "Read failed: %08lx\n", hres);
597             hres = IInternetProtocol_Terminate(protocol, 0);
598             ok(hres == S_OK, "Terminate failed: %08lx\n", hres);
599
600             IInternetProtocol_Release(protocol);
601         }
602
603         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
604         ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres);
605
606         if(SUCCEEDED(hres)) {
607             file_protocol_start(protocol, url, TRUE);
608             hres = IInternetProtocol_Terminate(protocol, 0);
609             ok(hres == S_OK, "Terminate failed: %08lx\n", hres);
610             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
611             ok(hres == S_OK, "Read failed: %08lx\n", hres);
612             ok(cb == 2, "cb=%lu expected 2\n", cb);
613
614             IInternetProtocol_Release(protocol);
615         }
616
617         IClassFactory_Release(factory);
618     }
619
620     IUnknown_Release(unk);
621 }
622
623 static void test_file_protocol_fail(void)
624 {
625     IInternetProtocol *protocol;
626     HRESULT hres;
627
628     static const WCHAR index_url2[] =
629         {'f','i','l','e',':','/','/','i','n','d','e','x','.','h','t','m','l',0};
630
631     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
632             &IID_IInternetProtocol, (void**)&protocol);
633     ok(hres == S_OK, "CoCreateInstance failed: %08lx\n", hres);
634     if(FAILED(hres))
635         return;
636
637     SET_EXPECT(GetBindInfo);
638     expect_hrResult = MK_E_SYNTAX;
639     hres = IInternetProtocol_Start(protocol, wszIndexHtml, &protocol_sink, &bind_info, 0, 0);
640     ok(hres == MK_E_SYNTAX, "Start failed: %08lx, expected MK_E_SYNTAX\n", hres);
641     CHECK_CALLED(GetBindInfo);
642
643     SET_EXPECT(GetBindInfo);
644     if(!(bindf & BINDF_FROMURLMON))
645         SET_EXPECT(ReportProgress_DIRECTBIND);
646     SET_EXPECT(ReportProgress_SENDINGREQUEST);
647     SET_EXPECT(ReportResult);
648     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
649     hres = IInternetProtocol_Start(protocol, index_url, &protocol_sink, &bind_info, 0, 0);
650     ok(hres == INET_E_RESOURCE_NOT_FOUND,
651             "Start failed: %08lx expected INET_E_RESOURCE_NOT_FOUND\n", hres);
652     CHECK_CALLED(GetBindInfo);
653     if(!(bindf & BINDF_FROMURLMON))
654         CHECK_CALLED(ReportProgress_DIRECTBIND);
655     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
656     CHECK_CALLED(ReportResult);
657
658     IInternetProtocol_Release(protocol);
659
660     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
661             &IID_IInternetProtocol, (void**)&protocol);
662     ok(hres == S_OK, "CoCreateInstance failed: %08lx\n", hres);
663     if(FAILED(hres))
664         return;
665
666     SET_EXPECT(GetBindInfo);
667     if(!(bindf & BINDF_FROMURLMON))
668         SET_EXPECT(ReportProgress_DIRECTBIND);
669     SET_EXPECT(ReportProgress_SENDINGREQUEST);
670     SET_EXPECT(ReportResult);
671     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
672
673     hres = IInternetProtocol_Start(protocol, index_url2, &protocol_sink, &bind_info, 0, 0);
674     ok(hres == INET_E_RESOURCE_NOT_FOUND,
675             "Start failed: %08lx, expected INET_E_RESOURCE_NOT_FOUND\n", hres);
676     CHECK_CALLED(GetBindInfo);
677     if(!(bindf & BINDF_FROMURLMON))
678         CHECK_CALLED(ReportProgress_DIRECTBIND);
679     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
680     CHECK_CALLED(ReportResult);
681
682     IInternetProtocol_Release(protocol);
683 }
684
685 static void test_file_protocol(void) {
686     WCHAR buf[MAX_PATH];
687     DWORD size;
688     ULONG len;
689     HANDLE file;
690
691     static const WCHAR wszFile[] = {'f','i','l','e',':',0};
692     static const WCHAR wszFile2[] = {'f','i','l','e',':','/','/',0};
693     static const WCHAR wszFile3[] = {'f','i','l','e',':','/','/','/',0};
694     static const char html_doc[] = "<HTML></HTML>";
695
696     tested_protocol = FILE_TEST;
697
698     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
699             FILE_ATTRIBUTE_NORMAL, NULL);
700     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
701     if(file == INVALID_HANDLE_VALUE)
702         return;
703     WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL);
704     CloseHandle(file);
705
706     file_name = wszIndexHtml;
707     bindf = 0;
708     test_file_protocol_url(index_url);
709     bindf = BINDF_FROMURLMON;
710     test_file_protocol_url(index_url);
711
712     memcpy(buf, wszFile, sizeof(wszFile));
713     len = sizeof(wszFile)/sizeof(WCHAR)-1;
714     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
715     buf[len++] = '\\';
716     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
717
718     file_name = buf + sizeof(wszFile)/sizeof(WCHAR)-1;
719     bindf = 0;
720     test_file_protocol_url(buf);
721     bindf = BINDF_FROMURLMON;
722     test_file_protocol_url(buf);
723
724     memcpy(buf, wszFile2, sizeof(wszFile2));
725     len = sizeof(wszFile2)/sizeof(WCHAR)-1;
726     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
727     buf[len++] = '\\';
728     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
729
730     file_name = buf + sizeof(wszFile2)/sizeof(WCHAR)-1;
731     bindf = 0;
732     test_file_protocol_url(buf);
733     bindf = BINDF_FROMURLMON;
734     test_file_protocol_url(buf);
735
736     memcpy(buf, wszFile3, sizeof(wszFile3));
737     len = sizeof(wszFile3)/sizeof(WCHAR)-1;
738     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
739     buf[len++] = '\\';
740     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
741
742     file_name = buf + sizeof(wszFile3)/sizeof(WCHAR)-1;
743     bindf = 0;
744     test_file_protocol_url(buf);
745     bindf = BINDF_FROMURLMON;
746     test_file_protocol_url(buf);
747
748     DeleteFileW(wszIndexHtml);
749
750     bindf = 0;
751     test_file_protocol_fail();
752     bindf = BINDF_FROMURLMON;
753     test_file_protocol_fail();
754 }
755
756 static BOOL http_protocol_start(LPCWSTR url, BOOL is_first)
757 {
758     HRESULT hres;
759
760     first_data_notif = TRUE;
761
762     SET_EXPECT(GetBindInfo);
763     SET_EXPECT(GetBindString_USER_AGENT);
764     SET_EXPECT(GetBindString_ACCEPT_MIMES);
765     SET_EXPECT(QueryService_HttpNegotiate);
766     SET_EXPECT(BeginningTransaction);
767     SET_EXPECT(GetRootSecurityId);
768
769     hres = IInternetProtocol_Start(http_protocol, url, &protocol_sink, &bind_info, 0, 0);
770     todo_wine {
771         ok(hres == S_OK, "Start failed: %08lx\n", hres);
772     }
773     if(FAILED(hres))
774         return FALSE;
775
776     CHECK_CALLED(GetBindInfo);
777     CHECK_CALLED(GetBindString_USER_AGENT);
778     CHECK_CALLED(GetBindString_ACCEPT_MIMES);
779     CHECK_CALLED(QueryService_HttpNegotiate);
780     CHECK_CALLED(BeginningTransaction);
781     CHECK_CALLED(GetRootSecurityId);
782
783     return TRUE;
784 }
785
786 static void test_http_protocol_url(LPCWSTR url)
787 {
788     IInternetProtocolInfo *protocol_info;
789     IClassFactory *factory;
790     IUnknown *unk;
791     HRESULT hres;
792
793     http_url = url;
794
795     hres = CoGetClassObject(&CLSID_HttpProtocol, CLSCTX_INPROC_SERVER, NULL,
796             &IID_IUnknown, (void**)&unk);
797     ok(hres == S_OK, "CoGetClassObject failed: %08lx\n", hres);
798     if(!SUCCEEDED(hres))
799         return;
800
801     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
802     ok(hres == E_NOINTERFACE,
803         "Could not get IInternetProtocolInfo interface: %08lx, expected E_NOINTERFACE\n",
804         hres);
805
806     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
807     ok(hres == S_OK, "Could not get IClassFactory interface\n");
808     IUnknown_Release(unk);
809     if(FAILED(hres))
810         return;
811
812     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
813                                         (void**)&http_protocol);
814     ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres);
815     if(SUCCEEDED(hres)) {
816         BYTE buf[512];
817         DWORD cb;
818         MSG msg;
819
820         bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
821
822         test_priority(http_protocol);
823
824         SET_EXPECT(ReportProgress_FINDINGRESOURCE);
825         SET_EXPECT(ReportProgress_CONNECTING);
826         SET_EXPECT(ReportProgress_SENDINGREQUEST);
827
828         if(!http_protocol_start(url, TRUE))
829             return;
830
831         hres = IInternetProtocol_Read(http_protocol, buf, 2, &cb);
832         ok(hres == E_PENDING, "Read failed: %08lx, expected E_PENDING\n", hres);
833         ok(!cb, "cb=%ld, expected 0\n", cb);
834
835         SET_EXPECT(Switch);
836         SET_EXPECT(ReportResult);
837         expect_hrResult = S_OK;
838
839         GetMessageW(&msg, NULL, 0, 0);
840
841         CHECK_CALLED(Switch);
842         CHECK_CALLED(ReportResult);
843
844         IInternetProtocol_Release(http_protocol);
845     }
846
847     IClassFactory_Release(factory);
848 }
849
850 static void test_http_protocol(void)
851 {
852     static const WCHAR winehq_url[] =
853         {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
854             'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
855
856     tested_protocol = HTTP_TEST;
857     test_http_protocol_url(winehq_url);
858
859 }
860
861 static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
862 {
863     if(msg == WM_USER) {
864         HRESULT hres;
865         DWORD cb;
866         BYTE buf[3600];
867
868         SET_EXPECT(ReportData);
869         if(!state) {
870             CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
871             CHECK_CALLED(ReportProgress_CONNECTING);
872             CHECK_CALLED(ReportProgress_SENDINGREQUEST);
873
874             SET_EXPECT(OnResponse);
875             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
876         }
877
878         hres = IInternetProtocol_Continue(http_protocol, (PROTOCOLDATA*)lParam);
879         ok(hres == S_OK, "Continue failed: %08lx\n", hres);
880
881         CHECK_CALLED(ReportData);
882         if(!state) {
883             CHECK_CALLED(OnResponse);
884             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
885         }
886
887         do hres = IInternetProtocol_Read(http_protocol, buf, sizeof(buf), &cb);
888         while(cb);
889
890         ok(hres == S_FALSE || hres == E_PENDING, "Read failed: %08lx\n", hres);
891
892         if(hres == S_FALSE)
893             PostMessageW(protocol_hwnd, WM_USER+1, 0, 0);
894
895         if(!state) {
896             state = 1;
897
898             hres = IInternetProtocol_LockRequest(http_protocol, 0);
899             ok(hres == S_OK, "LockRequest failed: %08lx\n", hres);
900
901             do hres = IInternetProtocol_Read(http_protocol, buf, sizeof(buf), &cb);
902             while(cb);
903             ok(hres == S_FALSE || hres == E_PENDING, "Read failed: %08lx\n", hres);
904         }
905     }
906
907     return DefWindowProc(hwnd, msg, wParam, lParam);
908 }
909
910 static HWND create_protocol_window(void)
911 {
912     static const WCHAR wszProtocolWindow[] =
913         {'P','r','o','t','o','c','o','l','W','i','n','d','o','w',0};
914     static WNDCLASSEXW wndclass = {
915         sizeof(WNDCLASSEXW),
916         0,
917         wnd_proc,
918         0, 0, NULL, NULL, NULL, NULL, NULL,
919         wszProtocolWindow,
920         NULL
921     };
922
923     RegisterClassExW(&wndclass);
924     return CreateWindowW(wszProtocolWindow, wszProtocolWindow,
925                          WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
926                          CW_USEDEFAULT, NULL, NULL, NULL, NULL);
927 }
928
929 START_TEST(protocol)
930 {
931     OleInitialize(NULL);
932
933     protocol_hwnd = create_protocol_window();
934
935     test_file_protocol();
936     test_http_protocol();
937
938     DestroyWindow(protocol_hwnd);
939
940     OleUninitialize();
941 }