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