urlmon: Added more protocol tests.
[wine] / dlls / urlmon / tests / protocol.c
1 /*
2  * Copyright 2005-2007 Jacek Caban for CodeWeavers
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 #include <stdio.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "urlmon.h"
30
31 #include "initguid.h"
32
33 #define DEFINE_EXPECT(func) \
34     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
35
36 #define SET_EXPECT(func) \
37     expect_ ## func = TRUE
38
39 #define CHECK_EXPECT2(func) \
40     do { \
41         ok(expect_ ##func, "unexpected call " #func  "\n"); \
42         called_ ## func = TRUE; \
43     }while(0)
44
45 #define CHECK_EXPECT(func) \
46     do { \
47         CHECK_EXPECT2(func);     \
48         expect_ ## func = FALSE; \
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 CHECK_NOT_CALLED(func) \
58     do { \
59         ok(!called_ ## func, "unexpected " #func "\n"); \
60         expect_ ## func = called_ ## func = FALSE; \
61     }while(0)
62
63 #define CLEAR_CALLED(func) \
64     expect_ ## func = called_ ## func = FALSE
65
66 DEFINE_EXPECT(GetBindInfo);
67 DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
68 DEFINE_EXPECT(ReportProgress_DIRECTBIND);
69 DEFINE_EXPECT(ReportProgress_RAWMIMETYPE);
70 DEFINE_EXPECT(ReportProgress_FINDINGRESOURCE);
71 DEFINE_EXPECT(ReportProgress_CONNECTING);
72 DEFINE_EXPECT(ReportProgress_SENDINGREQUEST);
73 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
74 DEFINE_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
75 DEFINE_EXPECT(ReportProgress_PROTOCOLCLASSID);
76 DEFINE_EXPECT(ReportProgress_COOKIE_SENT);
77 DEFINE_EXPECT(ReportProgress_REDIRECTING);
78 DEFINE_EXPECT(ReportData);
79 DEFINE_EXPECT(ReportResult);
80 DEFINE_EXPECT(GetBindString_ACCEPT_MIMES);
81 DEFINE_EXPECT(GetBindString_USER_AGENT);
82 DEFINE_EXPECT(GetBindString_POST_COOKIE);
83 DEFINE_EXPECT(QueryService_HttpNegotiate);
84 DEFINE_EXPECT(QueryService_InternetProtocol);
85 DEFINE_EXPECT(BeginningTransaction);
86 DEFINE_EXPECT(GetRootSecurityId);
87 DEFINE_EXPECT(OnResponse);
88 DEFINE_EXPECT(Switch);
89 DEFINE_EXPECT(Continue);
90 DEFINE_EXPECT(CreateInstance);
91 DEFINE_EXPECT(Start);
92 DEFINE_EXPECT(Terminate);
93 DEFINE_EXPECT(Read);
94 DEFINE_EXPECT(SetPriority);
95 DEFINE_EXPECT(LockRequest);
96 DEFINE_EXPECT(UnlockRequest);
97
98 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
99 static const WCHAR index_url[] =
100     {'f','i','l','e',':','i','n','d','e','x','.','h','t','m','l',0};
101
102 static const WCHAR acc_mimeW[] = {'*','/','*',0};
103 static const WCHAR user_agentW[] = {'W','i','n','e',0};
104 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
105 static const WCHAR hostW[] = {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
106 static const WCHAR winehq_ipW[] = {'2','0','9','.','4','6','.','2','5','.','1','3','4',0};
107 static const WCHAR emptyW[] = {0};
108
109 static HRESULT expect_hrResult;
110 static LPCWSTR file_name, http_url, expect_wsz;
111 static IInternetProtocol *http_protocol = NULL;
112 static BOOL first_data_notif = FALSE, http_is_first = FALSE,
113     http_post_test = FALSE;
114 static int state = 0, prot_state;
115 static DWORD bindf = 0, ex_priority = 0;
116 static IInternetProtocol *binding_protocol;
117 static IInternetBindInfo *prot_bind_info;
118 static IInternetProtocolSink *binding_sink;
119 static void *expect_pv;
120 static HANDLE event_complete, event_complete2;
121 static BOOL binding_test;
122 static PROTOCOLDATA protocoldata, *pdata;
123 static DWORD prot_read;
124
125 static enum {
126     FILE_TEST,
127     HTTP_TEST,
128     MK_TEST,
129     BIND_TEST
130 } tested_protocol;
131
132 static const WCHAR protocol_names[][10] = {
133     {'f','i','l','e',0},
134     {'h','t','t','p',0},
135     {'m','k',0},
136     {'t','e','s','t',0}
137 };
138
139 static const WCHAR binding_urls[][30] = {
140     {'f','i','l','e',':','t','e','s','t','.','h','t','m','l',0},
141     {'h','t','t','p',':','/','/','t','e','s','t','/','t','e','s','t','.','h','t','m','l',0},
142     {'m','k',':','t','e','s','t',0},
143     {'t','e','s','t',':','/','/','f','i','l','e','.','h','t','m','l',0}
144 };
145
146 static const char *debugstr_w(LPCWSTR str)
147 {
148     static char buf[512];
149     if(!str)
150         return "(null)";
151     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
152     return buf;
153 }
154
155 static const char *debugstr_guid(REFIID riid)
156 {
157     static char buf[50];
158
159     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
160             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
161             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
162             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
163
164     return buf;
165 }
166
167 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv)
168 {
169     if(IsEqualGUID(&IID_IUnknown, riid)
170             || IsEqualGUID(&IID_IHttpNegotiate, riid)
171             || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
172         *ppv = iface;
173         return S_OK;
174     }
175
176     ok(0, "unexpected call\n");
177     return E_NOINTERFACE;
178 }
179
180 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
181 {
182     return 2;
183 }
184
185 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
186 {
187     return 1;
188 }
189
190 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL,
191         LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
192 {
193     LPWSTR addl_headers;
194
195     static const WCHAR wszHeaders[] =
196         {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ','a','p','p','l','i','c','a','t',
197          'i','o','n','/','x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o',
198          'd','e','d','\r','\n',0};
199
200     CHECK_EXPECT(BeginningTransaction);
201
202     if(binding_test)
203         ok(!lstrcmpW(szURL, binding_urls[tested_protocol]), "szURL != http_url\n");
204     else
205         ok(!lstrcmpW(szURL, http_url), "szURL != http_url\n");
206     ok(!dwReserved, "dwReserved=%d, expected 0\n", dwReserved);
207     ok(pszAdditionalHeaders != NULL, "pszAdditionalHeaders == NULL\n");
208     if(pszAdditionalHeaders)
209     {
210         ok(*pszAdditionalHeaders == NULL, "*pszAdditionalHeaders != NULL\n");
211         if (http_post_test)
212         {
213             addl_headers = CoTaskMemAlloc(sizeof(wszHeaders));
214             if (!addl_headers)
215             {
216                 http_post_test = FALSE;
217                 skip("Out of memory\n");
218                 return E_OUTOFMEMORY;
219             }
220             lstrcpyW(addl_headers, wszHeaders);
221             *pszAdditionalHeaders = addl_headers;
222         }
223     }
224
225     return S_OK;
226 }
227
228 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
229         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
230 {
231     CHECK_EXPECT(OnResponse);
232
233     ok(dwResponseCode == 200, "dwResponseCode=%d, expected 200\n", dwResponseCode);
234     ok(szResponseHeaders != NULL, "szResponseHeaders == NULL\n");
235     ok(szRequestHeaders == NULL, "szRequestHeaders != NULL\n");
236     ok(pszAdditionalRequestHeaders == NULL, "pszAdditionalHeaders != NULL\n");
237
238     return S_OK;
239 }
240
241 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
242         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
243 {
244     static const BYTE sec_id[] = {'h','t','t','p',':','t','e','s','t',1,0,0,0};
245     
246     CHECK_EXPECT(GetRootSecurityId);
247
248     ok(!dwReserved, "dwReserved=%ld, expected 0\n", dwReserved);
249     ok(pbSecurityId != NULL, "pbSecurityId == NULL\n");
250     ok(pcbSecurityId != NULL, "pcbSecurityId == NULL\n");
251
252     if(pcbSecurityId) {
253         ok(*pcbSecurityId == 512, "*pcbSecurityId=%d, expected 512\n", *pcbSecurityId);
254         *pcbSecurityId = sizeof(sec_id);
255     }
256
257     if(pbSecurityId)
258         memcpy(pbSecurityId, sec_id, sizeof(sec_id));
259
260     return E_FAIL;
261 }
262
263 static IHttpNegotiate2Vtbl HttpNegotiateVtbl = {
264     HttpNegotiate_QueryInterface,
265     HttpNegotiate_AddRef,
266     HttpNegotiate_Release,
267     HttpNegotiate_BeginningTransaction,
268     HttpNegotiate_OnResponse,
269     HttpNegotiate_GetRootSecurityId
270 };
271
272 static IHttpNegotiate2 http_negotiate = { &HttpNegotiateVtbl };
273
274 static HRESULT QueryInterface(REFIID,void**);
275
276 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
277 {
278     return QueryInterface(riid, ppv);
279 }
280
281 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
282 {
283     return 2;
284 }
285
286 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
287 {
288     return 1;
289 }
290
291 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
292         REFIID riid, void **ppv)
293 {
294     if(IsEqualGUID(&IID_IHttpNegotiate, guidService) || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
295         CHECK_EXPECT2(QueryService_HttpNegotiate);
296         return IHttpNegotiate2_QueryInterface(&http_negotiate, riid, ppv);
297     }
298
299     if(IsEqualGUID(&IID_IInternetProtocol, guidService)) {
300         ok(IsEqualGUID(&IID_IInternetProtocol, riid), "unexpected riid\n");
301         CHECK_EXPECT(QueryService_InternetProtocol);
302         return E_NOINTERFACE;
303     }
304
305     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
306     return E_FAIL;
307 }
308
309 static const IServiceProviderVtbl ServiceProviderVtbl = {
310     ServiceProvider_QueryInterface,
311     ServiceProvider_AddRef,
312     ServiceProvider_Release,
313     ServiceProvider_QueryService
314 };
315
316 static IServiceProvider service_provider = { &ServiceProviderVtbl };
317
318 static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv)
319 {
320     return QueryInterface(riid, ppv);
321 }
322
323 static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface)
324 {
325     return 2;
326 }
327
328 static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface)
329 {
330     return 1;
331 }
332
333 static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData)
334 {
335     HRESULT hres;
336
337     CHECK_EXPECT(Switch);
338     ok(pProtocolData != NULL, "pProtocolData == NULL\n");
339
340     pdata = pProtocolData;
341
342     if(binding_test) {
343         SetEvent(event_complete);
344         WaitForSingleObject(event_complete2, INFINITE);
345         return S_OK;
346     }
347
348     if (!state) {
349         if (http_is_first) {
350             CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
351             CHECK_CALLED(ReportProgress_CONNECTING);
352         } else todo_wine {
353             CHECK_NOT_CALLED(ReportProgress_FINDINGRESOURCE);
354             CHECK_NOT_CALLED(ReportProgress_CONNECTING);
355         }
356         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
357         SET_EXPECT(OnResponse);
358         SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
359         if(bindf & BINDF_NEEDFILE)
360             SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
361     }
362
363     SET_EXPECT(ReportData);
364     hres = IInternetProtocol_Continue(http_protocol, pProtocolData);
365     ok(hres == S_OK, "Continue failed: %08x\n", hres);
366     CHECK_CALLED(ReportData);
367
368     if (!state) {
369         state = 1;
370         CHECK_CALLED(OnResponse);
371         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
372         if(bindf & BINDF_NEEDFILE)
373             CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
374     }
375
376     SetEvent(event_complete);
377
378     return S_OK;
379 }
380
381 static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode,
382         LPCWSTR szStatusText)
383 {
384     static const WCHAR null_guid[] = {'{','0','0','0','0','0','0','0','0','-','0','0','0','0','-',
385         '0','0','0','0','-','0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0','}',0};
386     static const WCHAR text_plain[] = {'t','e','x','t','/','p','l','a','i','n',0};
387     static const WCHAR post_host[] =
388         {'c','r','o','s','s','o','v','e','r','.','c','o','d','e',
389          'w','e','a','v','e','r','s','.','c','o','m',0};
390     static const WCHAR wszCrossoverIP[] =
391         {'2','0','9','.','4','6','.','2','5','.','1','3','2',0};
392     /* I'm not sure if it's a good idea to hardcode here the IP address... */
393
394     switch(ulStatusCode) {
395     case BINDSTATUS_MIMETYPEAVAILABLE:
396         CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
397         ok(szStatusText != NULL, "szStatusText == NULL\n");
398         if(szStatusText) {
399             if(tested_protocol == BIND_TEST)
400                 ok(szStatusText == expect_wsz, "unexpected szStatusText\n");
401             else if (http_post_test)
402                 ok(lstrlenW(text_plain) <= lstrlenW(szStatusText) &&
403                    !memcmp(szStatusText, text_plain, lstrlenW(text_plain)*sizeof(WCHAR)),
404                    "szStatusText != text/plain\n");
405             else
406                 ok(lstrlenW(text_htmlW) <= lstrlenW(szStatusText) &&
407                    !memcmp(szStatusText, text_htmlW, lstrlenW(text_htmlW)*sizeof(WCHAR)),
408                    "szStatusText != text/html\n");
409         }
410         break;
411     case BINDSTATUS_DIRECTBIND:
412         CHECK_EXPECT2(ReportProgress_DIRECTBIND);
413         ok(szStatusText == NULL, "szStatusText != NULL\n");
414         break;
415     case BINDSTATUS_RAWMIMETYPE:
416         CHECK_EXPECT2(ReportProgress_RAWMIMETYPE);
417         ok(szStatusText != NULL, "szStatusText == NULL\n");
418         if(szStatusText)
419             ok(lstrlenW(szStatusText) < lstrlenW(text_htmlW) ||
420                !memcmp(szStatusText, text_htmlW, lstrlenW(text_htmlW)*sizeof(WCHAR)),
421                "szStatusText != text/html\n");
422         break;
423     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
424         CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
425         ok(szStatusText != NULL, "szStatusText == NULL\n");
426         if(szStatusText) {
427             if(binding_test)
428                 ok(szStatusText == expect_wsz, "unexpected szStatusText\n");
429             else if(tested_protocol == FILE_TEST)
430                 ok(!lstrcmpW(szStatusText, file_name), "szStatusText = \"%s\"\n", debugstr_w(szStatusText));
431             else
432                 ok(szStatusText != NULL, "szStatusText == NULL\n");
433         }
434         break;
435     case BINDSTATUS_FINDINGRESOURCE:
436         CHECK_EXPECT(ReportProgress_FINDINGRESOURCE);
437         ok(szStatusText != NULL, "szStatusText == NULL\n");
438         if(szStatusText)
439         {
440             if (!http_post_test)
441                 ok(!lstrcmpW(szStatusText, hostW),
442                    "szStatustext != \"www.winehq.org\"\n");
443             else
444                 ok(!lstrcmpW(szStatusText, post_host),
445                    "szStatustext != \"crossover.codeweavers.com\"\n");
446         }
447         break;
448     case BINDSTATUS_CONNECTING:
449         CHECK_EXPECT(ReportProgress_CONNECTING);
450         ok(szStatusText != NULL, "szStatusText == NULL\n");
451         if(szStatusText)
452             ok(!lstrcmpW(szStatusText, http_post_test ?
453                          wszCrossoverIP : winehq_ipW),
454                "Unexpected szStatusText\n");
455         break;
456     case BINDSTATUS_SENDINGREQUEST:
457         CHECK_EXPECT(ReportProgress_SENDINGREQUEST);
458         if(tested_protocol == FILE_TEST) {
459             ok(szStatusText != NULL, "szStatusText == NULL\n");
460             if(szStatusText)
461                 ok(!*szStatusText, "wrong szStatusText\n");
462         }
463         break;
464     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
465         CHECK_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
466         ok(szStatusText != NULL, "szStatusText == NULL\n");
467         if(szStatusText)
468             ok(!lstrcmpW(szStatusText, text_htmlW), "szStatusText != text/html\n");
469         break;
470     case BINDSTATUS_PROTOCOLCLASSID:
471         CHECK_EXPECT(ReportProgress_PROTOCOLCLASSID);
472         ok(szStatusText != NULL, "szStatusText == NULL\n");
473         ok(!lstrcmpW(szStatusText, null_guid), "unexpected szStatusText\n");
474         break;
475     case BINDSTATUS_COOKIE_SENT:
476         CHECK_EXPECT(ReportProgress_COOKIE_SENT);
477         ok(szStatusText == NULL, "szStatusText != NULL\n");
478         break;
479     case BINDSTATUS_REDIRECTING:
480         CHECK_EXPECT(ReportProgress_REDIRECTING);
481         ok(szStatusText == NULL, "szStatusText != NULL\n");
482         break;
483     default:
484         ok(0, "Unexpected status %d\n", ulStatusCode);
485     };
486
487     return S_OK;
488 }
489
490 static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF,
491         ULONG ulProgress, ULONG ulProgressMax)
492 {
493     if(tested_protocol == FILE_TEST) {
494         CHECK_EXPECT2(ReportData);
495
496         ok(ulProgress == ulProgressMax, "ulProgress (%d) != ulProgressMax (%d)\n",
497            ulProgress, ulProgressMax);
498         ok(ulProgressMax == 13, "ulProgressMax=%d, expected 13\n", ulProgressMax);
499         ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION),
500                 "grcfBSCF = %08x\n", grfBSCF);
501     }else if(!binding_test && tested_protocol == HTTP_TEST) {
502         if(!(grfBSCF & BSCF_LASTDATANOTIFICATION))
503             CHECK_EXPECT(ReportData);
504         else if (http_post_test)
505             ok(ulProgress == 13, "Read %u bytes instead of 13\n", ulProgress);
506
507         ok(ulProgress, "ulProgress == 0\n");
508
509         if(first_data_notif) {
510             ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION, "grcfBSCF = %08x\n", grfBSCF);
511             first_data_notif = FALSE;
512         } else {
513             ok(grfBSCF == BSCF_INTERMEDIATEDATANOTIFICATION
514                || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION),
515                "grcfBSCF = %08x\n", grfBSCF);
516         }
517
518         if(!(bindf & BINDF_FROMURLMON) &&
519            !(grfBSCF & BSCF_LASTDATANOTIFICATION)) {
520             if(!state) {
521                 state = 1;
522                 if(http_is_first) {
523                     CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
524                     CHECK_CALLED(ReportProgress_CONNECTING);
525                 } else todo_wine {
526                     CHECK_NOT_CALLED(ReportProgress_FINDINGRESOURCE);
527                     CHECK_NOT_CALLED(ReportProgress_CONNECTING);
528                 }
529                 CHECK_CALLED(ReportProgress_SENDINGREQUEST);
530                 CHECK_CALLED(OnResponse);
531                 CHECK_CALLED(ReportProgress_RAWMIMETYPE);
532             }
533             SetEvent(event_complete);
534         }
535     }else {
536         BYTE buf[1000];
537         ULONG read;
538         HRESULT hres;
539
540         CHECK_EXPECT(ReportData);
541
542         if(tested_protocol == BIND_TEST)
543             return S_OK;
544
545         do {
546             SET_EXPECT(Read);
547             hres = IInternetProtocol_Read(binding_protocol, expect_pv=buf, sizeof(buf), &read);
548             CHECK_CALLED(Read);
549         }while(hres == S_OK);
550     }
551
552     return S_OK;
553 }
554
555 static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult,
556         DWORD dwError, LPCWSTR szResult)
557 {
558     CHECK_EXPECT(ReportResult);
559
560     ok(hrResult == expect_hrResult, "hrResult = %08x, expected: %08x\n",
561             hrResult, expect_hrResult);
562     if(SUCCEEDED(hrResult))
563         ok(dwError == ERROR_SUCCESS, "dwError = %d, expected ERROR_SUCCESS\n", dwError);
564     else
565         ok(dwError != ERROR_SUCCESS, "dwError == ERROR_SUCCESS\n");
566     ok(!szResult, "szResult != NULL\n");
567
568     return S_OK;
569 }
570
571 static IInternetProtocolSinkVtbl protocol_sink_vtbl = {
572     ProtocolSink_QueryInterface,
573     ProtocolSink_AddRef,
574     ProtocolSink_Release,
575     ProtocolSink_Switch,
576     ProtocolSink_ReportProgress,
577     ProtocolSink_ReportData,
578     ProtocolSink_ReportResult
579 };
580
581 static IInternetProtocolSink protocol_sink = { &protocol_sink_vtbl };
582
583 static HRESULT QueryInterface(REFIID riid, void **ppv)
584 {
585     *ppv = NULL;
586
587     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid))
588         *ppv = &protocol_sink;
589     if(IsEqualGUID(&IID_IServiceProvider, riid))
590         *ppv = &service_provider;
591
592     if(*ppv)
593         return S_OK;
594
595     return E_NOINTERFACE;
596 }
597
598 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
599 {
600     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo, riid)) {
601         *ppv = iface;
602         return S_OK;
603     }
604     return E_NOINTERFACE;
605 }
606
607 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
608 {
609     return 2;
610 }
611
612 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
613 {
614     return 1;
615 }
616
617 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
618 {
619     DWORD cbSize;
620
621     static const CHAR szPostData[] = "mode=Test";
622
623     CHECK_EXPECT(GetBindInfo);
624
625     ok(grfBINDF != NULL, "grfBINDF == NULL\n");
626     ok(pbindinfo != NULL, "pbindinfo == NULL\n");
627     ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %d\n", pbindinfo->cbSize);
628
629     *grfBINDF = bindf;
630     if(binding_test)
631         *grfBINDF |= BINDF_FROMURLMON;
632     cbSize = pbindinfo->cbSize;
633     memset(pbindinfo, 0, cbSize);
634     pbindinfo->cbSize = cbSize;
635
636     if (http_post_test)
637     {
638         /* Must be GMEM_FIXED, GMEM_MOVABLE does not work properly
639          * with urlmon on native (Win98 and WinXP) */
640         U(pbindinfo->stgmedData).hGlobal = GlobalAlloc(GPTR, sizeof(szPostData));
641         if (!U(pbindinfo->stgmedData).hGlobal)
642         {
643             http_post_test = FALSE;
644             skip("Out of memory\n");
645             return E_OUTOFMEMORY;
646         }
647         lstrcpy((LPSTR)U(pbindinfo->stgmedData).hGlobal, szPostData);
648         pbindinfo->cbstgmedData = sizeof(szPostData)-1;
649         pbindinfo->dwBindVerb = BINDVERB_POST;
650         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
651     }
652
653     return S_OK;
654 }
655
656 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType,
657         LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
658 {
659     ok(ppwzStr != NULL, "ppwzStr == NULL\n");
660     ok(pcElFetched != NULL, "pcElFetched == NULL\n");
661
662     switch(ulStringType) {
663     case BINDSTRING_ACCEPT_MIMES:
664         CHECK_EXPECT(GetBindString_ACCEPT_MIMES);
665         ok(cEl == 256, "cEl=%d, expected 256\n", cEl);
666         if(pcElFetched) {
667             ok(*pcElFetched == 256, "*pcElFetched=%d, expected 256\n", *pcElFetched);
668             *pcElFetched = 1;
669         }
670         if(ppwzStr) {
671             *ppwzStr = CoTaskMemAlloc(sizeof(acc_mimeW));
672             memcpy(*ppwzStr, acc_mimeW, sizeof(acc_mimeW));
673         }
674         return S_OK;
675     case BINDSTRING_USER_AGENT:
676         CHECK_EXPECT(GetBindString_USER_AGENT);
677         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
678         if(pcElFetched) {
679             ok(*pcElFetched == 0, "*pcElFetch=%d, expectd 0\n", *pcElFetched);
680             *pcElFetched = 1;
681         }
682         if(ppwzStr) {
683             *ppwzStr = CoTaskMemAlloc(sizeof(user_agentW));
684             memcpy(*ppwzStr, user_agentW, sizeof(user_agentW));
685         }
686         return S_OK;
687     case BINDSTRING_POST_COOKIE:
688         CHECK_EXPECT(GetBindString_POST_COOKIE);
689         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
690         if(pcElFetched)
691             ok(*pcElFetched == 0, "*pcElFetch=%d, expectd 0\n", *pcElFetched);
692         return S_OK;
693     default:
694         ok(0, "unexpected call\n");
695     }
696
697     return E_NOTIMPL;
698 }
699
700 static IInternetBindInfoVtbl bind_info_vtbl = {
701     BindInfo_QueryInterface,
702     BindInfo_AddRef,
703     BindInfo_Release,
704     BindInfo_GetBindInfo,
705     BindInfo_GetBindString
706 };
707
708 static IInternetBindInfo bind_info = { &bind_info_vtbl };
709
710 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
711                                                   REFIID riid, void **ppv)
712 {
713     ok(0, "unexpected call\n");
714     return E_NOINTERFACE;
715 }
716
717 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
718 {
719     return 2;
720 }
721
722 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
723 {
724     return 1;
725 }
726
727 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
728 {
729     CHECK_EXPECT(SetPriority);
730     ok(nPriority == ex_priority, "nPriority=%d\n", nPriority);
731     return S_OK;
732 }
733
734 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
735 {
736     ok(0, "unexpected call\n");
737     return E_NOTIMPL;
738 }
739
740
741 static const IInternetPriorityVtbl InternetPriorityVtbl = {
742     InternetPriority_QueryInterface,
743     InternetPriority_AddRef,
744     InternetPriority_Release,
745     InternetPriority_SetPriority,
746     InternetPriority_GetPriority
747 };
748
749 static IInternetPriority InternetPriority = { &InternetPriorityVtbl };
750
751 static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
752 {
753     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) {
754         *ppv = iface;
755         return S_OK;
756     }
757
758     if(IsEqualGUID(&IID_IInternetPriority, riid)) {
759         *ppv = &InternetPriority;
760         return S_OK;
761     }
762
763     ok(0, "unexpected riid %s\n", debugstr_guid(riid));
764     *ppv = NULL;
765     return E_NOINTERFACE;
766 }
767
768 static ULONG WINAPI Protocol_AddRef(IInternetProtocol *iface)
769 {
770     return 2;
771 }
772
773 static ULONG WINAPI Protocol_Release(IInternetProtocol *iface)
774 {
775     return 1;
776 }
777
778 static DWORD WINAPI thread_proc(PVOID arg)
779 {
780     HRESULT hres;
781
782     memset(&protocoldata, -1, sizeof(protocoldata));
783
784     prot_state = 0;
785
786     SET_EXPECT(ReportProgress_FINDINGRESOURCE);
787     hres = IInternetProtocolSink_ReportProgress(binding_sink,
788             BINDSTATUS_FINDINGRESOURCE, hostW);
789     CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
790     ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
791
792     SET_EXPECT(ReportProgress_CONNECTING);
793     hres = IInternetProtocolSink_ReportProgress(binding_sink,
794             BINDSTATUS_CONNECTING, winehq_ipW);
795     CHECK_CALLED(ReportProgress_CONNECTING);
796     ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
797
798     SET_EXPECT(ReportProgress_SENDINGREQUEST);
799     hres = IInternetProtocolSink_ReportProgress(binding_sink,
800             BINDSTATUS_SENDINGREQUEST, NULL);
801     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
802     ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
803
804     prot_state = 1;
805     SET_EXPECT(Switch);
806     hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
807     CHECK_CALLED(Switch);
808     ok(hres == S_OK, "Switch failed: %08x\n", hres);
809
810     prot_state = 2;
811     SET_EXPECT(Switch);
812     hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
813     CHECK_CALLED(Switch);
814     ok(hres == S_OK, "Switch failed: %08x\n", hres);
815
816     prot_state = 2;
817     SET_EXPECT(Switch);
818     hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
819     CHECK_CALLED(Switch);
820     ok(hres == S_OK, "Switch failed: %08x\n", hres);
821
822     prot_state = 3;
823     SET_EXPECT(Switch);
824     hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
825     CHECK_CALLED(Switch);
826     ok(hres == S_OK, "Switch failed: %08x\n", hres);
827
828     SetEvent(event_complete);
829
830     return 0;
831 }
832
833 static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
834         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
835         DWORD grfPI, DWORD dwReserved)
836 {
837     BINDINFO bindinfo, exp_bindinfo;
838     DWORD cbindf = 0;
839     HRESULT hres;
840
841     CHECK_EXPECT(Start);
842
843     ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
844     ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
845     ok(pOIProtSink != &protocol_sink, "unexpected pOIProtSink\n");
846     ok(pOIBindInfo != &bind_info, "unexpected pOIBindInfo\n");
847     ok(!grfPI, "grfPI = %x\n", grfPI);
848     ok(!dwReserved, "dwReserved = %d\n", dwReserved);
849
850     memset(&bindinfo, 0, sizeof(bindinfo));
851     bindinfo.cbSize = sizeof(bindinfo);
852     memcpy(&exp_bindinfo, &bindinfo, sizeof(bindinfo));
853     SET_EXPECT(GetBindInfo);
854     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &cbindf, &bindinfo);
855     ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres);
856     CHECK_CALLED(GetBindInfo);
857     ok(cbindf == (bindf|BINDF_FROMURLMON), "bindf = %x, expected %x\n",
858        cbindf, (bindf|BINDF_FROMURLMON));
859     ok(!memcmp(&exp_bindinfo, &bindinfo, sizeof(bindinfo)), "unexpected bindinfo\n");
860     ReleaseBindInfo(&bindinfo);
861
862     SET_EXPECT(ReportProgress_SENDINGREQUEST);
863     hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, emptyW);
864     ok(hres == S_OK, "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
865     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
866
867     if(tested_protocol == HTTP_TEST) {
868         IServiceProvider *service_provider;
869         IHttpNegotiate *http_negotiate;
870         IHttpNegotiate2 *http_negotiate2;
871         LPWSTR ua = (LPWSTR)0xdeadbeef, accept_mimes[256];
872         LPWSTR additional_headers = NULL;
873         BYTE sec_id[100];
874         DWORD fetched = 0, size = 100;
875
876         SET_EXPECT(GetBindString_USER_AGENT);
877         hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_USER_AGENT,
878                                                &ua, 1, &fetched);
879         CHECK_CALLED(GetBindString_USER_AGENT);
880         ok(hres == S_OK, "GetBindString(BINDSTRING_USER_AGETNT) failed: %08x\n", hres);
881         ok(fetched == 1, "fetched = %d, expected 254\n", fetched);
882         ok(ua != NULL, "ua =  %p\n", ua);
883         ok(!lstrcmpW(ua, user_agentW), "unexpected user agent %s\n", debugstr_w(ua));
884         CoTaskMemFree(ua);
885
886         fetched = 256;
887         SET_EXPECT(GetBindString_ACCEPT_MIMES);
888         hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_ACCEPT_MIMES,
889                                                accept_mimes, 256, &fetched);
890         CHECK_CALLED(GetBindString_ACCEPT_MIMES);
891
892         ok(hres == S_OK,
893            "GetBindString(BINDSTRING_ACCEPT_MIMES) failed: %08x\n", hres);
894         ok(fetched == 1, "fetched = %d, expected 1\n", fetched);
895         ok(!lstrcmpW(acc_mimeW, accept_mimes[0]), "unexpected mimes %s\n", debugstr_w(accept_mimes[0]));
896
897         hres = IInternetBindInfo_QueryInterface(pOIBindInfo, &IID_IServiceProvider,
898                                                 (void**)&service_provider);
899         ok(hres == S_OK, "QueryInterface failed: %08x\n", hres);
900
901         SET_EXPECT(QueryService_HttpNegotiate);
902         hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
903                 &IID_IHttpNegotiate, (void**)&http_negotiate);
904         CHECK_CALLED(QueryService_HttpNegotiate);
905         ok(hres == S_OK, "QueryService failed: %08x\n", hres);
906
907         SET_EXPECT(BeginningTransaction);
908         hres = IHttpNegotiate_BeginningTransaction(http_negotiate, binding_urls[tested_protocol],
909                                                    NULL, 0, &additional_headers);
910         CHECK_CALLED(BeginningTransaction);
911         IHttpNegotiate_Release(http_negotiate);
912         ok(hres == S_OK, "BeginningTransction failed: %08x\n", hres);
913         ok(additional_headers == NULL, "additional_headers=%p\n", additional_headers);
914
915         SET_EXPECT(QueryService_HttpNegotiate);
916         hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2,
917                 &IID_IHttpNegotiate2, (void**)&http_negotiate2);
918         CHECK_CALLED(QueryService_HttpNegotiate);
919         ok(hres == S_OK, "QueryService failed: %08x\n", hres);
920
921         size = 512;
922         SET_EXPECT(GetRootSecurityId);
923         hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, sec_id, &size, 0);
924         CHECK_CALLED(GetRootSecurityId);
925         IHttpNegotiate2_Release(http_negotiate2);
926         ok(hres == E_FAIL, "GetRootSecurityId failed: %08x, expected E_FAIL\n", hres);
927         ok(size == 13, "size=%d\n", size);
928
929         IServiceProvider_Release(service_provider);
930
931         CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
932
933         return S_OK;
934     }
935
936     SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
937     hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
938             BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
939     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
940     CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
941
942     SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
943     hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE,
944                                                 expect_wsz = text_htmlW);
945     ok(hres == S_OK,
946        "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres);
947     CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
948
949     SET_EXPECT(ReportData);
950     hres = IInternetProtocolSink_ReportData(pOIProtSink,
951             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION, 13, 13);
952     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
953     CHECK_CALLED(ReportData);
954
955     if(tested_protocol == BIND_TEST) {
956         hres = IInternetProtocol_Terminate(binding_protocol, 0);
957         ok(hres == E_FAIL, "Termiante failed: %08x\n", hres);
958     }
959
960     SET_EXPECT(ReportResult);
961     hres = IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
962     ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
963     CHECK_CALLED(ReportResult);
964
965     return S_OK;
966 }
967
968 static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
969         PROTOCOLDATA *pProtocolData)
970 {
971     DWORD bscf = 0;
972     HRESULT hres;
973
974     CHECK_EXPECT(Continue);
975
976     ok(pProtocolData != NULL, "pProtocolData == NULL\n");
977     if(!pProtocolData || tested_protocol == BIND_TEST)
978         return S_OK;
979
980     switch(prot_state) {
981     case 1: {
982         IServiceProvider *service_provider;
983         IHttpNegotiate *http_negotiate;
984         static WCHAR header[] = {'?',0};
985
986         hres = IInternetProtocolSink_QueryInterface(binding_sink, &IID_IServiceProvider,
987                                                     (void**)&service_provider);
988         ok(hres == S_OK, "Could not get IServiceProvicder\n");
989
990         SET_EXPECT(QueryService_HttpNegotiate);
991         hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
992                                              &IID_IHttpNegotiate, (void**)&http_negotiate);
993         IServiceProvider_Release(service_provider);
994         CHECK_CALLED(QueryService_HttpNegotiate);
995         ok(hres == S_OK, "Could not get IHttpNegotiate\n");
996
997         SET_EXPECT(OnResponse);
998         hres = IHttpNegotiate_OnResponse(http_negotiate, 200, header, NULL, NULL);
999         IHttpNegotiate_Release(http_negotiate);
1000         CHECK_CALLED(OnResponse);
1001         IHttpNegotiate_Release(http_negotiate);
1002         ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
1003
1004         SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1005         hres = IInternetProtocolSink_ReportProgress(binding_sink,
1006                 BINDSTATUS_MIMETYPEAVAILABLE, text_htmlW);
1007         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1008         ok(hres == S_OK,
1009            "ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) failed: %08x\n", hres);
1010
1011         bscf |= BSCF_FIRSTDATANOTIFICATION;
1012         break;
1013     }
1014     case 2:
1015     case 3:
1016         bscf = BSCF_INTERMEDIATEDATANOTIFICATION;
1017         break;
1018     }
1019
1020     SET_EXPECT(ReportData);
1021     hres = IInternetProtocolSink_ReportData(binding_sink, bscf, 100, 400);
1022     CHECK_CALLED(ReportData);
1023     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
1024
1025     if(prot_state == 3)
1026         prot_state = 4;
1027
1028     return S_OK;
1029 }
1030
1031 static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
1032         DWORD dwOptions)
1033 {
1034     ok(0, "unexpected call\n");
1035     return E_NOTIMPL;
1036 }
1037
1038 static HRESULT WINAPI Protocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
1039 {
1040     CHECK_EXPECT(Terminate);
1041     ok(!dwOptions, "dwOptions=%d\n", dwOptions);
1042     return S_OK;
1043 }
1044
1045 static HRESULT WINAPI Protocol_Suspend(IInternetProtocol *iface)
1046 {
1047     ok(0, "unexpected call\n");
1048     return E_NOTIMPL;
1049 }
1050
1051 static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface)
1052 {
1053     ok(0, "unexpected call\n");
1054     return E_NOTIMPL;
1055 }
1056
1057 static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv,
1058         ULONG cb, ULONG *pcbRead)
1059 {
1060     static BOOL b = TRUE;
1061
1062     CHECK_EXPECT(Read);
1063
1064     ok(pv == expect_pv, "pv != expect_pv\n");
1065     ok(cb == 1000, "cb=%d\n", cb);
1066     ok(pcbRead != NULL, "pcbRead == NULL\n");
1067     ok(!*pcbRead, "*pcbRead = %d\n", *pcbRead);
1068
1069     if(prot_state == 3) {
1070         HRESULT hres;
1071
1072         SET_EXPECT(ReportResult);
1073         hres = IInternetProtocolSink_ReportResult(binding_sink, S_OK, ERROR_SUCCESS, NULL);
1074         CHECK_CALLED(ReportResult);
1075
1076         return S_FALSE;
1077     }
1078
1079     if((b = !b))
1080         return tested_protocol == HTTP_TEST ? E_PENDING : S_FALSE;
1081
1082     memset(pv, 'x', 100);
1083     prot_read += *pcbRead = 100;
1084     return S_OK;
1085 }
1086
1087 static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface,
1088         LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
1089 {
1090     ok(0, "unexpected call\n");
1091     return E_NOTIMPL;
1092 }
1093
1094 static HRESULT WINAPI Protocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
1095 {
1096     CHECK_EXPECT(LockRequest);
1097     ok(dwOptions == 0, "dwOptions=%x\n", dwOptions);
1098     return S_OK;
1099 }
1100
1101 static HRESULT WINAPI Protocol_UnlockRequest(IInternetProtocol *iface)
1102 {
1103     CHECK_EXPECT(UnlockRequest);
1104     return S_OK;
1105 }
1106
1107 static const IInternetProtocolVtbl ProtocolVtbl = {
1108     Protocol_QueryInterface,
1109     Protocol_AddRef,
1110     Protocol_Release,
1111     Protocol_Start,
1112     Protocol_Continue,
1113     Protocol_Abort,
1114     Protocol_Terminate,
1115     Protocol_Suspend,
1116     Protocol_Resume,
1117     Protocol_Read,
1118     Protocol_Seek,
1119     Protocol_LockRequest,
1120     Protocol_UnlockRequest
1121 };
1122
1123 static IInternetProtocol Protocol = { &ProtocolVtbl };
1124
1125 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
1126 {
1127     ok(0, "unexpected call\n");
1128     return E_NOINTERFACE;
1129 }
1130
1131 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
1132 {
1133     return 2;
1134 }
1135
1136 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
1137 {
1138     return 1;
1139 }
1140
1141 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
1142                                         REFIID riid, void **ppv)
1143 {
1144     CHECK_EXPECT(CreateInstance);
1145
1146     ok(pOuter == (IUnknown*)prot_bind_info, "pOuter != protocol_unk\n");
1147     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
1148     ok(ppv != NULL, "ppv == NULL\n");
1149
1150     *ppv = &Protocol;
1151     return S_OK;
1152 }
1153
1154 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
1155 {
1156     ok(0, "unexpected call\n");
1157     return S_OK;
1158 }
1159
1160 static const IClassFactoryVtbl ClassFactoryVtbl = {
1161     ClassFactory_QueryInterface,
1162     ClassFactory_AddRef,
1163     ClassFactory_Release,
1164     ClassFactory_CreateInstance,
1165     ClassFactory_LockServer
1166 };
1167
1168 static IClassFactory ClassFactory = { &ClassFactoryVtbl };
1169
1170 static void test_priority(IInternetProtocol *protocol)
1171 {
1172     IInternetPriority *priority;
1173     LONG pr;
1174     HRESULT hres;
1175
1176     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority,
1177                                             (void**)&priority);
1178     ok(hres == S_OK, "QueryInterface(IID_IInternetPriority) failed: %08x\n", hres);
1179     if(FAILED(hres))
1180         return;
1181
1182     hres = IInternetPriority_GetPriority(priority, &pr);
1183     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1184     ok(pr == 0, "pr=%d, expected 0\n", pr);
1185
1186     hres = IInternetPriority_SetPriority(priority, 1);
1187     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
1188
1189     hres = IInternetPriority_GetPriority(priority, &pr);
1190     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1191     ok(pr == 1, "pr=%d, expected 1\n", pr);
1192
1193     IInternetPriority_Release(priority);
1194 }
1195
1196 static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL is_first)
1197 {
1198     HRESULT hres;
1199
1200     SET_EXPECT(GetBindInfo);
1201     if(!(bindf & BINDF_FROMURLMON))
1202        SET_EXPECT(ReportProgress_DIRECTBIND);
1203     if(is_first) {
1204         SET_EXPECT(ReportProgress_SENDINGREQUEST);
1205         SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
1206         if(bindf & BINDF_FROMURLMON)
1207             SET_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
1208         else
1209             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1210     }
1211     SET_EXPECT(ReportData);
1212     if(is_first)
1213         SET_EXPECT(ReportResult);
1214
1215     expect_hrResult = S_OK;
1216
1217     hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0);
1218     ok(hres == S_OK, "Start failed: %08x\n", hres);
1219
1220     CHECK_CALLED(GetBindInfo);
1221     if(!(bindf & BINDF_FROMURLMON))
1222        CHECK_CALLED(ReportProgress_DIRECTBIND);
1223     if(is_first) {
1224         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1225         CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
1226         if(bindf & BINDF_FROMURLMON)
1227             CHECK_CALLED(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
1228         else
1229             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1230     }
1231     CHECK_CALLED(ReportData);
1232     if(is_first)
1233         CHECK_CALLED(ReportResult);
1234 }
1235
1236 static void test_file_protocol_url(LPCWSTR url)
1237 {
1238     IInternetProtocolInfo *protocol_info;
1239     IUnknown *unk;
1240     IClassFactory *factory;
1241     HRESULT hres;
1242
1243     hres = CoGetClassObject(&CLSID_FileProtocol, CLSCTX_INPROC_SERVER, NULL,
1244             &IID_IUnknown, (void**)&unk);
1245     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
1246     if(!SUCCEEDED(hres))
1247         return;
1248
1249     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
1250     ok(hres == E_NOINTERFACE,
1251             "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n", hres);
1252
1253     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
1254     ok(hres == S_OK, "Could not get IClassFactory interface\n");
1255     if(SUCCEEDED(hres)) {
1256         IInternetProtocol *protocol;
1257         BYTE buf[512];
1258         ULONG cb;
1259         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
1260         ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
1261
1262         if(SUCCEEDED(hres)) {
1263             file_protocol_start(protocol, url, TRUE);
1264             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
1265             ok(hres == S_OK, "Read failed: %08x\n", hres);
1266             ok(cb == 2, "cb=%u expected 2\n", cb);
1267             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
1268             ok(hres == S_FALSE, "Read failed: %08x\n", hres);
1269             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
1270             ok(hres == S_FALSE, "Read failed: %08x expected S_FALSE\n", hres);
1271             ok(cb == 0, "cb=%u expected 0\n", cb);
1272             hres = IInternetProtocol_UnlockRequest(protocol);
1273             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
1274
1275             file_protocol_start(protocol, url, FALSE);
1276             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
1277             ok(hres == S_FALSE, "Read failed: %08x\n", hres);
1278             hres = IInternetProtocol_LockRequest(protocol, 0);
1279             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
1280             hres = IInternetProtocol_UnlockRequest(protocol);
1281             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
1282
1283             IInternetProtocol_Release(protocol);
1284         }
1285
1286         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
1287         ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
1288
1289         if(SUCCEEDED(hres)) {
1290             file_protocol_start(protocol, url, TRUE);
1291             hres = IInternetProtocol_LockRequest(protocol, 0);
1292             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
1293             hres = IInternetProtocol_Terminate(protocol, 0);
1294             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1295             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
1296             ok(hres == S_OK, "Read failed: %08x\n\n", hres);
1297             hres = IInternetProtocol_UnlockRequest(protocol);
1298             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
1299             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
1300             ok(hres == S_OK, "Read failed: %08x\n", hres);
1301             hres = IInternetProtocol_Terminate(protocol, 0);
1302             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1303
1304             IInternetProtocol_Release(protocol);
1305         }
1306
1307         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
1308         ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
1309
1310         if(SUCCEEDED(hres)) {
1311             file_protocol_start(protocol, url, TRUE);
1312             hres = IInternetProtocol_Terminate(protocol, 0);
1313             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1314             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
1315             ok(hres == S_OK, "Read failed: %08x\n", hres);
1316             ok(cb == 2, "cb=%u expected 2\n", cb);
1317
1318             IInternetProtocol_Release(protocol);
1319         }
1320
1321         IClassFactory_Release(factory);
1322     }
1323
1324     IUnknown_Release(unk);
1325 }
1326
1327 static void test_file_protocol_fail(void)
1328 {
1329     IInternetProtocol *protocol;
1330     HRESULT hres;
1331
1332     static const WCHAR index_url2[] =
1333         {'f','i','l','e',':','/','/','i','n','d','e','x','.','h','t','m','l',0};
1334
1335     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
1336             &IID_IInternetProtocol, (void**)&protocol);
1337     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
1338     if(FAILED(hres))
1339         return;
1340
1341     SET_EXPECT(GetBindInfo);
1342     expect_hrResult = MK_E_SYNTAX;
1343     hres = IInternetProtocol_Start(protocol, wszIndexHtml, &protocol_sink, &bind_info, 0, 0);
1344     ok(hres == MK_E_SYNTAX, "Start failed: %08x, expected MK_E_SYNTAX\n", hres);
1345     CHECK_CALLED(GetBindInfo);
1346
1347     SET_EXPECT(GetBindInfo);
1348     if(!(bindf & BINDF_FROMURLMON))
1349         SET_EXPECT(ReportProgress_DIRECTBIND);
1350     SET_EXPECT(ReportProgress_SENDINGREQUEST);
1351     SET_EXPECT(ReportResult);
1352     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
1353     hres = IInternetProtocol_Start(protocol, index_url, &protocol_sink, &bind_info, 0, 0);
1354     ok(hres == INET_E_RESOURCE_NOT_FOUND,
1355             "Start failed: %08x expected INET_E_RESOURCE_NOT_FOUND\n", hres);
1356     CHECK_CALLED(GetBindInfo);
1357     if(!(bindf & BINDF_FROMURLMON))
1358         CHECK_CALLED(ReportProgress_DIRECTBIND);
1359     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1360     CHECK_CALLED(ReportResult);
1361
1362     IInternetProtocol_Release(protocol);
1363
1364     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
1365             &IID_IInternetProtocol, (void**)&protocol);
1366     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
1367     if(FAILED(hres))
1368         return;
1369
1370     SET_EXPECT(GetBindInfo);
1371     if(!(bindf & BINDF_FROMURLMON))
1372         SET_EXPECT(ReportProgress_DIRECTBIND);
1373     SET_EXPECT(ReportProgress_SENDINGREQUEST);
1374     SET_EXPECT(ReportResult);
1375     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
1376
1377     hres = IInternetProtocol_Start(protocol, index_url2, &protocol_sink, &bind_info, 0, 0);
1378     ok(hres == INET_E_RESOURCE_NOT_FOUND,
1379             "Start failed: %08x, expected INET_E_RESOURCE_NOT_FOUND\n", hres);
1380     CHECK_CALLED(GetBindInfo);
1381     if(!(bindf & BINDF_FROMURLMON))
1382         CHECK_CALLED(ReportProgress_DIRECTBIND);
1383     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1384     CHECK_CALLED(ReportResult);
1385
1386     IInternetProtocol_Release(protocol);
1387 }
1388
1389 static void test_file_protocol(void) {
1390     WCHAR buf[MAX_PATH];
1391     DWORD size;
1392     ULONG len;
1393     HANDLE file;
1394
1395     static const WCHAR wszFile[] = {'f','i','l','e',':',0};
1396     static const WCHAR wszFile2[] = {'f','i','l','e',':','/','/',0};
1397     static const WCHAR wszFile3[] = {'f','i','l','e',':','/','/','/',0};
1398     static const char html_doc[] = "<HTML></HTML>";
1399
1400     trace("Testing file protocol...\n");
1401     tested_protocol = FILE_TEST;
1402
1403     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1404             FILE_ATTRIBUTE_NORMAL, NULL);
1405     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
1406     if(file == INVALID_HANDLE_VALUE)
1407         return;
1408     WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL);
1409     CloseHandle(file);
1410
1411     file_name = wszIndexHtml;
1412     bindf = 0;
1413     test_file_protocol_url(index_url);
1414     bindf = BINDF_FROMURLMON;
1415     test_file_protocol_url(index_url);
1416     bindf = BINDF_FROMURLMON | BINDF_NEEDFILE;
1417     test_file_protocol_url(index_url);
1418
1419     memcpy(buf, wszFile, sizeof(wszFile));
1420     len = sizeof(wszFile)/sizeof(WCHAR)-1;
1421     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
1422     buf[len++] = '\\';
1423     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
1424
1425     file_name = buf + sizeof(wszFile)/sizeof(WCHAR)-1;
1426     bindf = 0;
1427     test_file_protocol_url(buf);
1428     bindf = BINDF_FROMURLMON;
1429     test_file_protocol_url(buf);
1430
1431     memcpy(buf, wszFile2, sizeof(wszFile2));
1432     len = sizeof(wszFile2)/sizeof(WCHAR)-1;
1433     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
1434     buf[len++] = '\\';
1435     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
1436
1437     file_name = buf + sizeof(wszFile2)/sizeof(WCHAR)-1;
1438     bindf = 0;
1439     test_file_protocol_url(buf);
1440     bindf = BINDF_FROMURLMON;
1441     test_file_protocol_url(buf);
1442
1443     memcpy(buf, wszFile3, sizeof(wszFile3));
1444     len = sizeof(wszFile3)/sizeof(WCHAR)-1;
1445     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
1446     buf[len++] = '\\';
1447     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
1448
1449     file_name = buf + sizeof(wszFile3)/sizeof(WCHAR)-1;
1450     bindf = 0;
1451     test_file_protocol_url(buf);
1452     bindf = BINDF_FROMURLMON;
1453     test_file_protocol_url(buf);
1454
1455     DeleteFileW(wszIndexHtml);
1456
1457     bindf = 0;
1458     test_file_protocol_fail();
1459     bindf = BINDF_FROMURLMON;
1460     test_file_protocol_fail();
1461 }
1462
1463 static BOOL http_protocol_start(LPCWSTR url, BOOL is_first)
1464 {
1465     static BOOL got_user_agent = FALSE;
1466     HRESULT hres;
1467
1468     first_data_notif = TRUE;
1469     state = 0;
1470
1471     SET_EXPECT(GetBindInfo);
1472     if (!(bindf & BINDF_FROMURLMON))
1473         SET_EXPECT(ReportProgress_DIRECTBIND);
1474     SET_EXPECT(GetBindString_USER_AGENT);
1475     SET_EXPECT(GetBindString_ACCEPT_MIMES);
1476     SET_EXPECT(QueryService_HttpNegotiate);
1477     SET_EXPECT(BeginningTransaction);
1478     SET_EXPECT(GetRootSecurityId);
1479     if (http_post_test)
1480         SET_EXPECT(GetBindString_POST_COOKIE);
1481
1482     hres = IInternetProtocol_Start(http_protocol, url, &protocol_sink, &bind_info, 0, 0);
1483     ok(hres == S_OK, "Start failed: %08x\n", hres);
1484     if(FAILED(hres))
1485         return FALSE;
1486
1487     CHECK_CALLED(GetBindInfo);
1488     if (!(bindf & BINDF_FROMURLMON))
1489         CHECK_CALLED(ReportProgress_DIRECTBIND);
1490     if (!got_user_agent)
1491     {
1492         CHECK_CALLED(GetBindString_USER_AGENT);
1493         got_user_agent = TRUE;
1494     }
1495     else todo_wine
1496     {
1497         /* user agent only retrieved once, even with different URLs */
1498         CHECK_NOT_CALLED(GetBindString_USER_AGENT);
1499     }
1500     CHECK_CALLED(GetBindString_ACCEPT_MIMES);
1501     CHECK_CALLED(QueryService_HttpNegotiate);
1502     CHECK_CALLED(BeginningTransaction);
1503     /* GetRootSecurityId called on WinXP but not on Win98 */
1504     CLEAR_CALLED(GetRootSecurityId);
1505     if (http_post_test)
1506         CHECK_CALLED(GetBindString_POST_COOKIE);
1507
1508     return TRUE;
1509 }
1510
1511 /* is_first refers to whether this is the first call to this function
1512  * _for this url_ */
1513 static void test_http_protocol_url(LPCWSTR url, BOOL is_first)
1514 {
1515     IInternetProtocolInfo *protocol_info;
1516     IClassFactory *factory;
1517     IUnknown *unk;
1518     HRESULT hres;
1519
1520     http_url = url;
1521     http_is_first = is_first;
1522
1523     hres = CoGetClassObject(&CLSID_HttpProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
1524     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
1525     if(!SUCCEEDED(hres))
1526         return;
1527
1528     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
1529     ok(hres == E_NOINTERFACE,
1530         "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n",
1531         hres);
1532
1533     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
1534     ok(hres == S_OK, "Could not get IClassFactory interface\n");
1535     IUnknown_Release(unk);
1536     if(FAILED(hres))
1537         return;
1538
1539     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
1540                                         (void**)&http_protocol);
1541     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
1542     if(SUCCEEDED(hres)) {
1543         BYTE buf[3600];
1544         DWORD cb;
1545         int *called = (bindf & BINDF_FROMURLMON) ? &called_Switch : &called_ReportData;
1546
1547         test_priority(http_protocol);
1548
1549         SET_EXPECT(ReportProgress_FINDINGRESOURCE);
1550         SET_EXPECT(ReportProgress_CONNECTING);
1551         SET_EXPECT(ReportProgress_SENDINGREQUEST);
1552         if(!(bindf & BINDF_FROMURLMON)) {
1553             SET_EXPECT(OnResponse);
1554             SET_EXPECT(ReportProgress_RAWMIMETYPE);
1555             SET_EXPECT(ReportData);
1556         } else {
1557             SET_EXPECT(Switch);
1558         }
1559
1560         if(!http_protocol_start(url, is_first))
1561             return;
1562
1563         SET_EXPECT(ReportResult);
1564         expect_hrResult = S_OK;
1565
1566         hres = IInternetProtocol_Read(http_protocol, buf, 1, &cb);
1567         ok((!*called && hres == E_PENDING && cb==0) ||
1568            (*called && hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb);
1569
1570         WaitForSingleObject(event_complete, INFINITE);
1571         if(bindf & BINDF_FROMURLMON)
1572             CHECK_CALLED(Switch);
1573         else
1574             CHECK_CALLED(ReportData);
1575
1576         while(1) {
1577             if(bindf & BINDF_FROMURLMON)
1578                 SET_EXPECT(Switch);
1579             else
1580                 SET_EXPECT(ReportData);
1581             hres = IInternetProtocol_Read(http_protocol, buf, sizeof(buf), &cb);
1582             if(hres == E_PENDING) {
1583                 hres = IInternetProtocol_Read(http_protocol, buf, 1, &cb);
1584                 ok((!*called && hres == E_PENDING && cb==0) ||
1585                    (*called && hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb);
1586                 WaitForSingleObject(event_complete, INFINITE);
1587                 if(bindf & BINDF_FROMURLMON)
1588                     CHECK_CALLED(Switch);
1589                 else
1590                     CHECK_CALLED(ReportData);
1591             } else {
1592                 if(bindf & BINDF_FROMURLMON)
1593                     CHECK_NOT_CALLED(Switch);
1594                 else
1595                     CHECK_NOT_CALLED(ReportData);
1596                 if(cb == 0) break;
1597             }
1598         }
1599         ok(hres == S_FALSE, "Read failed: %08x\n", hres);
1600         CHECK_CALLED(ReportResult);
1601
1602         hres = IInternetProtocol_LockRequest(http_protocol, 0);
1603         ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
1604
1605         hres = IInternetProtocol_Read(http_protocol, buf, 1, &cb);
1606         ok(hres == S_FALSE, "Read failed: %08x\n", hres);
1607
1608         hres = IInternetProtocol_Terminate(http_protocol, 0);
1609         ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1610
1611         /* This wait is to give the internet handles being freed in Terminate
1612          * enough time to actually terminate in all cases. Internet handles
1613          * terminate asynchronously and native reuses the main InternetOpen
1614          * handle. The only case in which this seems to be necessary is on
1615          * wine with native wininet and urlmon, resulting in the next time
1616          * test_http_protocol_url being called the first data notification actually
1617          * being an extra last data notification from the previous connection
1618          * about once out of every ten times. */
1619         Sleep(100);
1620
1621         hres = IInternetProtocol_UnlockRequest(http_protocol);
1622         ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
1623
1624         IInternetProtocol_Release(http_protocol);
1625     }
1626
1627     IClassFactory_Release(factory);
1628 }
1629
1630 static void test_http_protocol(void)
1631 {
1632     static const WCHAR winehq_url[] =
1633         {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
1634             'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
1635     static const WCHAR posttest_url[] =
1636         {'h','t','t','p',':','/','/','c','r','o','s','s','o','v','e','r','.',
1637          'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m','/',
1638          'p','o','s','t','t','e','s','t','.','p','h','p',0};
1639
1640     trace("Testing http protocol (not from urlmon)...\n");
1641     tested_protocol = HTTP_TEST;
1642     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
1643     test_http_protocol_url(winehq_url, TRUE);
1644
1645     trace("Testing http protocol (from urlmon)...\n");
1646     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
1647     test_http_protocol_url(winehq_url, FALSE);
1648
1649     trace("Testing http protocol (to file)...\n");
1650     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NEEDFILE;
1651     test_http_protocol_url(winehq_url, FALSE);
1652
1653     trace("Testing http protocol (post data)...\n");
1654     http_post_test = TRUE;
1655     /* Without this flag we get a ReportProgress_CACHEFILENAMEAVAILABLE
1656      * notification with BINDVERB_POST */
1657     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE;
1658     test_http_protocol_url(posttest_url, TRUE);
1659     http_post_test = FALSE;
1660 }
1661
1662 static void test_mk_protocol(void)
1663 {
1664     IInternetProtocolInfo *protocol_info;
1665     IInternetProtocol *protocol;
1666     IClassFactory *factory;
1667     IUnknown *unk;
1668     HRESULT hres;
1669
1670     static const WCHAR wrong_url1[] = {'t','e','s','t',':','@','M','S','I','T','S','t','o','r','e',
1671                                        ':',':','/','t','e','s','t','.','h','t','m','l',0};
1672     static const WCHAR wrong_url2[] = {'m','k',':','/','t','e','s','t','.','h','t','m','l',0};
1673
1674     trace("Testing mk protocol...\n");
1675     tested_protocol = MK_TEST;
1676
1677     hres = CoGetClassObject(&CLSID_MkProtocol, CLSCTX_INPROC_SERVER, NULL,
1678             &IID_IUnknown, (void**)&unk);
1679     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
1680
1681     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
1682     ok(hres == E_NOINTERFACE,
1683         "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n",
1684         hres);
1685
1686     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
1687     ok(hres == S_OK, "Could not get IClassFactory interface\n");
1688     IUnknown_Release(unk);
1689     if(FAILED(hres))
1690         return;
1691
1692     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
1693                                         (void**)&protocol);
1694     IClassFactory_Release(factory);
1695     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
1696
1697     SET_EXPECT(GetBindInfo);
1698     hres = IInternetProtocol_Start(protocol, wrong_url1, &protocol_sink, &bind_info, 0, 0);
1699     ok(hres == MK_E_SYNTAX || hres == INET_E_INVALID_URL,
1700        "Start failed: %08x, expected MK_E_SYNTAX or INET_E_INVALID_URL\n", hres);
1701     CLEAR_CALLED(GetBindInfo);
1702
1703     SET_EXPECT(GetBindInfo);
1704     SET_EXPECT(ReportProgress_DIRECTBIND);
1705     SET_EXPECT(ReportProgress_SENDINGREQUEST);
1706     SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1707     SET_EXPECT(ReportResult);
1708     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
1709
1710     hres = IInternetProtocol_Start(protocol, wrong_url2, &protocol_sink, &bind_info, 0, 0);
1711     ok(hres == INET_E_RESOURCE_NOT_FOUND, "Start failed: %08x, expected INET_E_RESOURCE_NOT_FOUND\n", hres);
1712
1713     CHECK_CALLED(GetBindInfo);
1714     CHECK_CALLED(ReportProgress_DIRECTBIND);
1715     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1716     CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1717     CHECK_CALLED(ReportResult);
1718
1719     IInternetProtocol_Release(protocol);
1720 }
1721
1722 static void test_CreateBinding(void)
1723 {
1724     IInternetProtocolSink *sink;
1725     IInternetProtocol *protocol;
1726     IInternetPriority *priority;
1727     IInternetSession *session;
1728     LONG p;
1729     BYTE buf[1000];
1730     DWORD read;
1731     HRESULT hres;
1732
1733     static const WCHAR test_url[] =
1734         {'t','e','s','t',':','/','/','f','i','l','e','.','h','t','m','l',0};
1735     static const WCHAR wsz_test[] = {'t','e','s','t',0};
1736
1737     trace("Testing CreateBinding...\n");
1738     tested_protocol = BIND_TEST;
1739     binding_test = TRUE;
1740
1741     hres = CoInternetGetSession(0, &session, 0);
1742     ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
1743
1744     hres = IInternetSession_RegisterNameSpace(session, &ClassFactory, &IID_NULL, wsz_test, 0, NULL, 0);
1745     ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres);
1746
1747     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
1748     binding_protocol = protocol;
1749     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
1750     ok(protocol != NULL, "protocol == NULL\n");
1751
1752     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info);
1753     ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres);
1754
1755     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&sink);
1756     ok(hres == S_OK, "Could not get IInternetProtocolSink: %08x\n", hres);
1757
1758     hres = IInternetProtocol_Start(protocol, test_url, NULL, &bind_info, 0, 0);
1759     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
1760     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, NULL, 0, 0);
1761     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
1762     hres = IInternetProtocol_Start(protocol, NULL, &protocol_sink, &bind_info, 0, 0);
1763     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
1764
1765     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
1766     ok(hres == S_OK, "QueryInterface(IID_IInternetPriority) failed: %08x\n", hres);
1767
1768     p = 0xdeadbeef;
1769     hres = IInternetPriority_GetPriority(priority, &p);
1770     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1771     ok(!p, "p=%d\n", p);
1772
1773     ex_priority = 100;
1774     hres = IInternetPriority_SetPriority(priority, 100);
1775     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
1776
1777     p = 0xdeadbeef;
1778     hres = IInternetPriority_GetPriority(priority, &p);
1779     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1780     ok(p == 100, "p=%d\n", p);
1781
1782     SET_EXPECT(QueryService_InternetProtocol);
1783     SET_EXPECT(CreateInstance);
1784     SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
1785     SET_EXPECT(SetPriority);
1786     SET_EXPECT(Start);
1787
1788     expect_hrResult = S_OK;
1789     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, &bind_info, 0, 0);
1790     ok(hres == S_OK, "Start failed: %08x\n", hres);
1791
1792     CHECK_CALLED(QueryService_InternetProtocol);
1793     CHECK_CALLED(CreateInstance);
1794     CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
1795     CHECK_CALLED(SetPriority);
1796     CHECK_CALLED(Start);
1797
1798     SET_EXPECT(Read);
1799     read = 0xdeadbeef;
1800     hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
1801     ok(hres == S_OK, "Read failed: %08x\n", hres);
1802     ok(read == 100, "read = %d\n", read);
1803     CHECK_CALLED(Read);
1804
1805     SET_EXPECT(Read);
1806     read = 0xdeadbeef;
1807     hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
1808     ok(hres == S_FALSE, "Read failed: %08x\n", hres);
1809     ok(!read, "read = %d\n", read);
1810     CHECK_CALLED(Read);
1811
1812     p = 0xdeadbeef;
1813     hres = IInternetPriority_GetPriority(priority, &p);
1814     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1815     ok(p == 100, "p=%d\n", p);
1816
1817     hres = IInternetPriority_SetPriority(priority, 101);
1818     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
1819
1820     SET_EXPECT(Terminate);
1821     hres = IInternetProtocol_Terminate(protocol, 0xdeadbeef);
1822     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1823     CHECK_CALLED(Terminate);
1824
1825     SET_EXPECT(Continue);
1826     hres = IInternetProtocolSink_Switch(sink, &protocoldata);
1827     ok(hres == S_OK, "Switch failed: %08x\n", hres);
1828     CHECK_CALLED(Continue);
1829
1830     hres = IInternetProtocolSink_ReportProgress(sink,
1831             BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
1832     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
1833
1834     hres = IInternetProtocolSink_ReportResult(sink, S_OK, ERROR_SUCCESS, NULL);
1835     ok(hres == E_FAIL, "ReportResult failed: %08x, expected E_FAIL\n", hres);
1836
1837     hres = IInternetProtocolSink_ReportData(sink, 0, 0, 0);
1838     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
1839
1840     IInternetProtocolSink_Release(sink);
1841     IInternetPriority_Release(priority);
1842     IInternetBindInfo_Release(prot_bind_info);
1843     IInternetProtocol_Release(protocol);
1844     IInternetSession_Release(session);
1845 }
1846
1847 static void test_binding(int prot)
1848 {
1849     IInternetProtocol *protocol;
1850     IInternetSession *session;
1851     ULONG ref;
1852     HRESULT hres;
1853
1854     trace("Testing %s binding...\n", debugstr_w(protocol_names[prot]));
1855
1856     tested_protocol = prot;
1857     binding_test = TRUE;
1858     first_data_notif = TRUE;
1859     prot_read = 0;
1860
1861     hres = CoInternetGetSession(0, &session, 0);
1862     ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
1863
1864     hres = IInternetSession_RegisterNameSpace(session, &ClassFactory, &IID_NULL, protocol_names[prot], 0, NULL, 0);
1865     ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres);
1866
1867     hres = IInternetSession_CreateBinding(session, NULL, binding_urls[prot], NULL, NULL, &protocol, 0);
1868     binding_protocol = protocol;
1869     IInternetSession_Release(session);
1870     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
1871     ok(protocol != NULL, "protocol == NULL\n");
1872
1873     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info);
1874     ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres);
1875
1876     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&binding_sink);
1877     ok(hres == S_OK, "QueryInterface(IID_IInternetProtocolSink) failed: %08x\n", hres);
1878
1879     ex_priority = 0;
1880     SET_EXPECT(QueryService_InternetProtocol);
1881     SET_EXPECT(CreateInstance);
1882     SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
1883     SET_EXPECT(SetPriority);
1884     SET_EXPECT(Start);
1885
1886     expect_hrResult = S_OK;
1887     hres = IInternetProtocol_Start(protocol, binding_urls[prot], &protocol_sink, &bind_info, 0, 0);
1888     ok(hres == S_OK, "Start failed: %08x\n", hres);
1889
1890     CHECK_CALLED(QueryService_InternetProtocol);
1891     CHECK_CALLED(CreateInstance);
1892     CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
1893     CHECK_CALLED(SetPriority);
1894     CHECK_CALLED(Start);
1895
1896     if(prot == HTTP_TEST) {
1897         while(prot_state < 4) {
1898             WaitForSingleObject(event_complete, INFINITE);
1899             SET_EXPECT(Continue);
1900             IInternetProtocol_Continue(protocol, pdata);
1901             CHECK_CALLED(Continue);
1902             SetEvent(event_complete2);
1903         }
1904
1905         WaitForSingleObject(event_complete, INFINITE);
1906     }else {
1907         SET_EXPECT(LockRequest);
1908         hres = IInternetProtocol_LockRequest(protocol, 0);
1909         ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
1910         CHECK_CALLED(LockRequest);
1911
1912         SET_EXPECT(UnlockRequest);
1913         hres = IInternetProtocol_UnlockRequest(protocol);
1914         ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
1915         CHECK_CALLED(UnlockRequest);
1916     }
1917
1918     SET_EXPECT(Terminate);
1919     hres = IInternetProtocol_Terminate(protocol, 0);
1920     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1921     CHECK_CALLED(Terminate);
1922
1923     IInternetBindInfo_Release(prot_bind_info);
1924     IInternetProtocolSink_Release(binding_sink);
1925     ref = IInternetProtocol_Release(protocol);
1926     ok(!ref, "ref=%u, expected 0\n", ref);
1927 }
1928
1929 START_TEST(protocol)
1930 {
1931     OleInitialize(NULL);
1932
1933     event_complete = CreateEvent(NULL, FALSE, FALSE, NULL);
1934     event_complete2 = CreateEvent(NULL, FALSE, FALSE, NULL);
1935
1936     test_file_protocol();
1937     test_http_protocol();
1938     test_mk_protocol();
1939     test_CreateBinding();
1940     test_binding(FILE_TEST);
1941     test_binding(HTTP_TEST);
1942
1943     CloseHandle(event_complete);
1944     CloseHandle(event_complete2);
1945
1946     OleUninitialize();
1947 }