urlmon/tests: Add test for BINDVERB_POST in http_protocol.
[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
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 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(ReportData);
77 DEFINE_EXPECT(ReportResult);
78 DEFINE_EXPECT(GetBindString_ACCEPT_MIMES);
79 DEFINE_EXPECT(GetBindString_USER_AGENT);
80 DEFINE_EXPECT(GetBindString_POST_COOKIE);
81 DEFINE_EXPECT(QueryService_HttpNegotiate);
82 DEFINE_EXPECT(QueryService_InternetProtocol);
83 DEFINE_EXPECT(BeginningTransaction);
84 DEFINE_EXPECT(GetRootSecurityId);
85 DEFINE_EXPECT(OnResponse);
86 DEFINE_EXPECT(Switch);
87 DEFINE_EXPECT(CreateInstance);
88 DEFINE_EXPECT(Start);
89 DEFINE_EXPECT(Terminate);
90 DEFINE_EXPECT(Read);
91 DEFINE_EXPECT(SetPriority);
92
93 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
94 static const WCHAR index_url[] =
95     {'f','i','l','e',':','i','n','d','e','x','.','h','t','m','l',0};
96
97 static HRESULT expect_hrResult;
98 static LPCWSTR file_name, http_url, expect_wsz;
99 static IInternetProtocol *http_protocol = NULL;
100 static BOOL first_data_notif = FALSE, http_is_first = FALSE,
101     http_post_test = FALSE;
102 static HWND protocol_hwnd;
103 static int state = 0;
104 static DWORD bindf = 0;
105 static IInternetBindInfo *prot_bind_info;
106 static void *expect_pv;
107
108 static enum {
109     FILE_TEST,
110     HTTP_TEST,
111     MK_TEST,
112     BIND_TEST
113 } tested_protocol;
114
115 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv)
116 {
117     if(IsEqualGUID(&IID_IUnknown, riid)
118             || IsEqualGUID(&IID_IHttpNegotiate, riid)
119             || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
120         *ppv = iface;
121         return S_OK;
122     }
123
124     ok(0, "unexpected call\n");
125     return E_NOINTERFACE;
126 }
127
128 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
129 {
130     return 2;
131 }
132
133 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
134 {
135     return 1;
136 }
137
138 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL,
139         LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
140 {
141     LPWSTR addl_headers;
142
143     static const WCHAR wszHeaders[] =
144         {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ','a','p','p','l','i','c','a','t',
145          'i','o','n','/','x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o',
146          'd','e','d','\r','\n',0};
147
148     CHECK_EXPECT(BeginningTransaction);
149
150     ok(!lstrcmpW(szURL, http_url), "szURL != http_url\n");
151     ok(!dwReserved, "dwReserved=%d, expected 0\n", dwReserved);
152     ok(pszAdditionalHeaders != NULL, "pszAdditionalHeaders == NULL\n");
153     if(pszAdditionalHeaders)
154     {
155         ok(*pszAdditionalHeaders == NULL, "*pszAdditionalHeaders != NULL\n");
156         if (http_post_test)
157         {
158             addl_headers = CoTaskMemAlloc(sizeof(wszHeaders));
159             if (!addl_headers)
160             {
161                 skip("Out of memory\n");
162                 return E_OUTOFMEMORY;
163             }
164             lstrcpyW(addl_headers, wszHeaders);
165             *pszAdditionalHeaders = addl_headers;
166         }
167     }
168
169     return S_OK;
170 }
171
172 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
173         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
174 {
175     CHECK_EXPECT(OnResponse);
176
177     ok(dwResponseCode == 200, "dwResponseCode=%d, expected 200\n", dwResponseCode);
178     ok(szResponseHeaders != NULL, "szResponseHeaders == NULL\n");
179     ok(szRequestHeaders == NULL, "szRequestHeaders != NULL\n");
180     ok(pszAdditionalRequestHeaders == NULL, "pszAdditionalHeaders != NULL\n");
181
182     return S_OK;
183 }
184
185 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
186         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
187 {
188     static const BYTE sec_id[] = {'h','t','t','p',':','t','e','s','t',1,0,0,0};
189     
190     CHECK_EXPECT(GetRootSecurityId);
191
192     ok(!dwReserved, "dwReserved=%ld, expected 0\n", dwReserved);
193     ok(pbSecurityId != NULL, "pbSecurityId == NULL\n");
194     ok(pcbSecurityId != NULL, "pcbSecurityId == NULL\n");
195
196     if(pcbSecurityId) {
197         ok(*pcbSecurityId == 512, "*pcbSecurityId=%d, expected 512\n", *pcbSecurityId);
198         *pcbSecurityId = sizeof(sec_id);
199     }
200
201     if(pbSecurityId)
202         memcpy(pbSecurityId, sec_id, sizeof(sec_id));
203
204     return E_FAIL;
205 }
206
207 static IHttpNegotiate2Vtbl HttpNegotiateVtbl = {
208     HttpNegotiate_QueryInterface,
209     HttpNegotiate_AddRef,
210     HttpNegotiate_Release,
211     HttpNegotiate_BeginningTransaction,
212     HttpNegotiate_OnResponse,
213     HttpNegotiate_GetRootSecurityId
214 };
215
216 static IHttpNegotiate2 http_negotiate = { &HttpNegotiateVtbl };
217
218 static HRESULT QueryInterface(REFIID,void**);
219
220 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
221 {
222     return QueryInterface(riid, ppv);
223 }
224
225 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
226 {
227     return 2;
228 }
229
230 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
231 {
232     return 1;
233 }
234
235 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
236         REFIID riid, void **ppv)
237 {
238     if(IsEqualGUID(&IID_IHttpNegotiate, guidService) || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
239         CHECK_EXPECT2(QueryService_HttpNegotiate);
240         return IHttpNegotiate2_QueryInterface(&http_negotiate, riid, ppv);
241     }
242
243     if(IsEqualGUID(&IID_IInternetProtocol, guidService)) {
244         ok(IsEqualGUID(&IID_IInternetProtocol, riid), "unexpected riid\n");
245         CHECK_EXPECT(QueryService_InternetProtocol);
246         return E_NOINTERFACE;
247     }
248
249     ok(0, "unexpected call\n");
250     return E_FAIL;
251 }
252
253 static const IServiceProviderVtbl ServiceProviderVtbl = {
254     ServiceProvider_QueryInterface,
255     ServiceProvider_AddRef,
256     ServiceProvider_Release,
257     ServiceProvider_QueryService
258 };
259
260 static IServiceProvider service_provider = { &ServiceProviderVtbl };
261
262 static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv)
263 {
264     return QueryInterface(riid, ppv);
265 }
266
267 static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface)
268 {
269     return 2;
270 }
271
272 static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface)
273 {
274     return 1;
275 }
276
277 static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData)
278 {
279     CHECK_EXPECT2(Switch);
280     ok(pProtocolData != NULL, "pProtocolData == NULL\n");
281     SendMessage(protocol_hwnd, WM_USER, 0, (LPARAM)pProtocolData);
282     return S_OK;
283 }
284
285 static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode,
286         LPCWSTR szStatusText)
287 {
288     static const WCHAR null_guid[] = {'{','0','0','0','0','0','0','0','0','-','0','0','0','0','-',
289         '0','0','0','0','-','0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0','}',0};
290     static const WCHAR text_html[] = {'t','e','x','t','/','h','t','m','l',0};
291     static const WCHAR text_plain[] = {'t','e','x','t','/','p','l','a','i','n',0};
292     static const WCHAR host[] =
293         {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
294     static const WCHAR post_host[] =
295         {'c','r','o','s','s','o','v','e','r','.','c','o','d','e',
296          'w','e','a','v','e','r','s','.','c','o','m',0};
297     static const WCHAR wszWineHQIP[] =
298         {'2','0','9','.','4','6','.','2','5','.','1','3','4',0};
299     static const WCHAR wszCrossoverIP[] =
300         {'2','0','9','.','4','6','.','2','5','.','1','3','2',0};
301     /* I'm not sure if it's a good idea to hardcode here the IP address... */
302
303     switch(ulStatusCode) {
304     case BINDSTATUS_MIMETYPEAVAILABLE:
305         CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
306         ok(szStatusText != NULL, "szStatusText == NULL\n");
307         if(szStatusText) {
308             if(tested_protocol == BIND_TEST)
309                 ok(szStatusText == expect_wsz, "unexpected szStatusText\n");
310             else if (http_post_test)
311                 ok(lstrlenW(text_plain) <= lstrlenW(szStatusText) &&
312                    !memcmp(szStatusText, text_plain, lstrlenW(text_plain)*sizeof(WCHAR)),
313                    "szStatusText != text/plain\n");
314             else
315                 ok(lstrlenW(text_html) <= lstrlenW(szStatusText) &&
316                    !memcmp(szStatusText, text_html, lstrlenW(text_html)*sizeof(WCHAR)),
317                    "szStatusText != text/html\n");
318         }
319         break;
320     case BINDSTATUS_DIRECTBIND:
321         CHECK_EXPECT2(ReportProgress_DIRECTBIND);
322         ok(szStatusText == NULL, "szStatusText != NULL\n");
323         break;
324     case BINDSTATUS_RAWMIMETYPE:
325         CHECK_EXPECT2(ReportProgress_RAWMIMETYPE);
326         ok(szStatusText != NULL, "szStatusText == NULL\n");
327         if(szStatusText)
328             ok(lstrlenW(szStatusText) < lstrlenW(text_html) ||
329                !memcmp(szStatusText, text_html, lstrlenW(text_html)*sizeof(WCHAR)),
330                "szStatusText != text/html\n");
331         break;
332     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
333         CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
334         ok(szStatusText != NULL, "szStatusText == NULL\n");
335         if(szStatusText) {
336             if(tested_protocol == BIND_TEST)
337                 ok(szStatusText == expect_wsz, "unexpected szStatusText\n");
338             else
339                 ok(!lstrcmpW(szStatusText, file_name), "szStatusText != file_name\n");
340         }
341         break;
342     case BINDSTATUS_FINDINGRESOURCE:
343         CHECK_EXPECT(ReportProgress_FINDINGRESOURCE);
344         ok(szStatusText != NULL, "szStatusText == NULL\n");
345         if(szStatusText)
346         {
347             if (!http_post_test)
348                 ok(!lstrcmpW(szStatusText, host),
349                    "szStatustext != \"www.winehq.org\"\n");
350             else
351                 ok(!lstrcmpW(szStatusText, post_host),
352                    "szStatustext != \"crossover.codeweavers.com\"\n");
353         }
354         break;
355     case BINDSTATUS_CONNECTING:
356         CHECK_EXPECT(ReportProgress_CONNECTING);
357         ok(szStatusText != NULL, "szStatusText == NULL\n");
358         if(szStatusText)
359             ok(!lstrcmpW(szStatusText, http_post_test ?
360                          wszCrossoverIP : wszWineHQIP),
361                "Unexpected szStatusText\n");
362         break;
363     case BINDSTATUS_SENDINGREQUEST:
364         CHECK_EXPECT(ReportProgress_SENDINGREQUEST);
365         if(tested_protocol == FILE_TEST) {
366             ok(szStatusText != NULL, "szStatusText == NULL\n");
367             if(szStatusText)
368                 ok(!*szStatusText, "wrong szStatusText\n");
369         }else {
370             ok(szStatusText == NULL, "szStatusText != NULL\n");
371         }
372         break;
373     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
374         CHECK_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
375         ok(szStatusText != NULL, "szStatusText == NULL\n");
376         if(szStatusText)
377             ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n");
378         break;
379     case BINDSTATUS_PROTOCOLCLASSID:
380         CHECK_EXPECT(ReportProgress_PROTOCOLCLASSID);
381         ok(szStatusText != NULL, "szStatusText == NULL\n");
382         ok(!lstrcmpW(szStatusText, null_guid), "unexpected szStatusText\n");
383         break;
384     default:
385         ok(0, "Unexpected call %d\n", ulStatusCode);
386     };
387
388     return S_OK;
389 }
390
391 static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF,
392         ULONG ulProgress, ULONG ulProgressMax)
393 {
394     if(tested_protocol == FILE_TEST) {
395         CHECK_EXPECT2(ReportData);
396
397         ok(ulProgress == ulProgressMax, "ulProgress (%d) != ulProgressMax (%d)\n",
398            ulProgress, ulProgressMax);
399         ok(ulProgressMax == 13, "ulProgressMax=%d, expected 13\n", ulProgressMax);
400         ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION),
401                 "grcfBSCF = %08x\n", grfBSCF);
402     }else if(tested_protocol == HTTP_TEST) {
403         if(!(grfBSCF & BSCF_LASTDATANOTIFICATION))
404             CHECK_EXPECT(ReportData);
405         else if (http_post_test) todo_wine
406             ok(ulProgress == 13, "Read %u bytes instead of 13\n", ulProgress);
407
408         ok(ulProgress, "ulProgress == 0\n");
409
410         if(first_data_notif) {
411             ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION, "grcfBSCF = %08x\n", grfBSCF);
412             first_data_notif = FALSE;
413         } else {
414             ok(grfBSCF == BSCF_INTERMEDIATEDATANOTIFICATION
415                || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION),
416                "grcfBSCF = %08x\n", grfBSCF);
417         }
418
419         if (!(grfBSCF & BSCF_LASTDATANOTIFICATION) &&
420             !(bindf & BINDF_FROMURLMON))
421             SendMessage(protocol_hwnd, WM_USER, 0, 0);
422     }
423     return S_OK;
424 }
425
426 static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult,
427         DWORD dwError, LPCWSTR szResult)
428 {
429     CHECK_EXPECT(ReportResult);
430
431     ok(hrResult == expect_hrResult, "hrResult = %08x, expected: %08x\n",
432             hrResult, expect_hrResult);
433     if(SUCCEEDED(hrResult))
434         ok(dwError == ERROR_SUCCESS, "dwError = %d, expected ERROR_SUCCESS\n", dwError);
435     else
436         ok(dwError != ERROR_SUCCESS, "dwError == ERROR_SUCCESS\n");
437     ok(!szResult, "szResult != NULL\n");
438
439     return S_OK;
440 }
441
442 static IInternetProtocolSinkVtbl protocol_sink_vtbl = {
443     ProtocolSink_QueryInterface,
444     ProtocolSink_AddRef,
445     ProtocolSink_Release,
446     ProtocolSink_Switch,
447     ProtocolSink_ReportProgress,
448     ProtocolSink_ReportData,
449     ProtocolSink_ReportResult
450 };
451
452 static IInternetProtocolSink protocol_sink = { &protocol_sink_vtbl };
453
454 static HRESULT QueryInterface(REFIID riid, void **ppv)
455 {
456     *ppv = NULL;
457
458     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid))
459         *ppv = &protocol_sink;
460     if(IsEqualGUID(&IID_IServiceProvider, riid))
461         *ppv = &service_provider;
462
463     if(*ppv)
464         return S_OK;
465
466     return E_NOINTERFACE;
467 }
468
469 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
470 {
471     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo, riid)) {
472         *ppv = iface;
473         return S_OK;
474     }
475     return E_NOINTERFACE;
476 }
477
478 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
479 {
480     return 2;
481 }
482
483 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
484 {
485     return 1;
486 }
487
488 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
489 {
490     DWORD cbSize;
491
492     static const CHAR szPostData[] = "mode=Test";
493
494     CHECK_EXPECT(GetBindInfo);
495
496     ok(grfBINDF != NULL, "grfBINDF == NULL\n");
497     ok(pbindinfo != NULL, "pbindinfo == NULL\n");
498     ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %d\n", pbindinfo->cbSize);
499
500     *grfBINDF = bindf;
501     cbSize = pbindinfo->cbSize;
502     memset(pbindinfo, 0, cbSize);
503     pbindinfo->cbSize = cbSize;
504
505     if (http_post_test)
506     {
507         pbindinfo->dwBindVerb = BINDVERB_POST;
508         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
509         /* Must be GMEM_FIXED, GMEM_MOVABLE does not work properly
510          * with urlmon on native (Win98 and WinXP) */
511         pbindinfo->stgmedData.hGlobal = GlobalAlloc(GPTR, sizeof(szPostData));
512         if (!pbindinfo->stgmedData.hGlobal)
513         {
514             skip("Out of memory\n");
515             return E_OUTOFMEMORY;
516         }
517         lstrcpy((LPSTR)pbindinfo->stgmedData.hGlobal, szPostData);
518         pbindinfo->cbstgmedData = sizeof(szPostData)-1;
519     }
520
521     return S_OK;
522 }
523
524 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType,
525         LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
526 {
527     static const WCHAR acc_mime[] = {'*','/','*',0};
528     static const WCHAR user_agent[] = {'W','i','n','e',0};
529
530     ok(ppwzStr != NULL, "ppwzStr == NULL\n");
531     ok(pcElFetched != NULL, "pcElFetched == NULL\n");
532
533     switch(ulStringType) {
534     case BINDSTRING_ACCEPT_MIMES:
535         CHECK_EXPECT(GetBindString_ACCEPT_MIMES);
536         ok(cEl == 256, "cEl=%d, expected 256\n", cEl);
537         if(pcElFetched) {
538             ok(*pcElFetched == 256, "*pcElFetched=%d, expected 256\n", *pcElFetched);
539             *pcElFetched = 1;
540         }
541         if(ppwzStr) {
542             *ppwzStr = CoTaskMemAlloc(sizeof(acc_mime));
543             memcpy(*ppwzStr, acc_mime, sizeof(acc_mime));
544         }
545         return S_OK;
546     case BINDSTRING_USER_AGENT:
547         CHECK_EXPECT(GetBindString_USER_AGENT);
548         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
549         if(pcElFetched) {
550             ok(*pcElFetched == 0, "*pcElFetch=%d, expectd 0\n", *pcElFetched);
551             *pcElFetched = 1;
552         }
553         if(ppwzStr) {
554             *ppwzStr = CoTaskMemAlloc(sizeof(user_agent));
555             memcpy(*ppwzStr, user_agent, sizeof(user_agent));
556         }
557         return S_OK;
558     case BINDSTRING_POST_COOKIE:
559         CHECK_EXPECT(GetBindString_POST_COOKIE);
560         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
561         if(pcElFetched)
562             ok(*pcElFetched == 0, "*pcElFetch=%d, expectd 0\n", *pcElFetched);
563         return S_OK;
564     default:
565         ok(0, "unexpected call\n");
566     }
567
568     return E_NOTIMPL;
569 }
570
571 static IInternetBindInfoVtbl bind_info_vtbl = {
572     BindInfo_QueryInterface,
573     BindInfo_AddRef,
574     BindInfo_Release,
575     BindInfo_GetBindInfo,
576     BindInfo_GetBindString
577 };
578
579 static IInternetBindInfo bind_info = { &bind_info_vtbl };
580
581 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
582                                                   REFIID riid, void **ppv)
583 {
584     ok(0, "unexpected call\n");
585     return E_NOINTERFACE;
586 }
587
588 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
589 {
590     return 2;
591 }
592
593 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
594 {
595     return 1;
596 }
597
598 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
599 {
600     CHECK_EXPECT(SetPriority);
601     ok(nPriority == 100, "nPriority=%d\n", nPriority);
602     return S_OK;
603 }
604
605 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
606 {
607     ok(0, "unexpected call\n");
608     return E_NOTIMPL;
609 }
610
611
612 static const IInternetPriorityVtbl InternetPriorityVtbl = {
613     InternetPriority_QueryInterface,
614     InternetPriority_AddRef,
615     InternetPriority_Release,
616     InternetPriority_SetPriority,
617     InternetPriority_GetPriority
618 };
619
620 static IInternetPriority InternetPriority = { &InternetPriorityVtbl };
621
622 static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
623 {
624     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) {
625         *ppv = iface;
626         return S_OK;
627     }
628
629     if(IsEqualGUID(&IID_IInternetPriority, riid)) {
630         *ppv = &InternetPriority;
631         return S_OK;
632     }
633
634     ok(0, "unexpected call\n");
635     *ppv = NULL;
636     return E_NOINTERFACE;
637 }
638
639 static ULONG WINAPI Protocol_AddRef(IInternetProtocol *iface)
640 {
641     return 2;
642 }
643
644 static ULONG WINAPI Protocol_Release(IInternetProtocol *iface)
645 {
646     return 1;
647 }
648
649 static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
650         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
651         DWORD grfPI, DWORD dwReserved)
652 {
653     BINDINFO bindinfo, exp_bindinfo;
654     DWORD cbindf = 0;
655     HRESULT hres;
656
657     static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
658     static const WCHAR empty_str[] = {0};
659
660     CHECK_EXPECT(Start);
661
662     ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
663     ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
664     ok(!grfPI, "grfPI = %x\n", grfPI);
665     ok(!dwReserved, "dwReserved = %d\n", dwReserved);
666
667     memset(&bindinfo, 0, sizeof(bindinfo));
668     bindinfo.cbSize = sizeof(bindinfo);
669     memcpy(&exp_bindinfo, &bindinfo, sizeof(bindinfo));
670     SET_EXPECT(GetBindInfo);
671     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &cbindf, &bindinfo);
672     ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres);
673     CHECK_CALLED(GetBindInfo);
674     ok(cbindf == (bindf|BINDF_FROMURLMON), "bindf = %x, expected %x\n",
675        cbindf, (bindf|BINDF_FROMURLMON));
676     ok(!memcmp(&exp_bindinfo, &bindinfo, sizeof(bindinfo)), "unexpected bindinfo\n");
677
678     SET_EXPECT(ReportProgress_SENDINGREQUEST);
679     hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
680             BINDSTATUS_SENDINGREQUEST, empty_str);
681     ok(hres == S_OK, "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
682     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
683
684     SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
685     hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
686             BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = empty_str);
687     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
688     CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
689
690     SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
691     hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
692             BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, expect_wsz = wszTextHtml);
693     ok(hres == S_OK,
694        "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres);
695     CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
696
697     hres = IInternetProtocolSink_ReportData(pOIProtSink,
698             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION, 13, 13);
699     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
700
701     SET_EXPECT(ReportResult);
702     hres = IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
703     ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
704     CHECK_CALLED(ReportResult);
705
706     return S_OK;
707 }
708
709 static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
710         PROTOCOLDATA *pProtocolData)
711 {
712     ok(0, "unexpected call\n");
713     return E_NOTIMPL;
714 }
715
716 static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
717         DWORD dwOptions)
718 {
719     ok(0, "unexpected call\n");
720     return E_NOTIMPL;
721 }
722
723 static HRESULT WINAPI Protocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
724 {
725     CHECK_EXPECT(Terminate);
726     ok(!dwOptions, "dwOptions=%d\n", dwOptions);
727     return S_OK;
728 }
729
730 static HRESULT WINAPI Protocol_Suspend(IInternetProtocol *iface)
731 {
732     ok(0, "unexpected call\n");
733     return E_NOTIMPL;
734 }
735
736 static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface)
737 {
738     ok(0, "unexpected call\n");
739     return E_NOTIMPL;
740 }
741
742 static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv,
743         ULONG cb, ULONG *pcbRead)
744 {
745     static DWORD read;
746
747     CHECK_EXPECT(Read);
748
749     ok(pv == expect_pv, "pv != expect_pv\n");
750     ok(cb == 1000, "cb=%d\n", cb);
751     ok(pcbRead != NULL, "pcbRead == NULL\n");
752     ok(!*pcbRead, "*pcbRead = %d\n", *pcbRead);
753
754     if(read)
755         return S_FALSE;
756
757     memset(pv, 'x', 100);
758     *pcbRead = read = 100;
759     return S_OK;
760 }
761
762 static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface,
763         LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
764 {
765     ok(0, "unexpected call\n");
766     return E_NOTIMPL;
767 }
768
769 static HRESULT WINAPI Protocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
770 {
771     ok(0, "unexpected call\n");
772     return S_OK;
773 }
774
775 static HRESULT WINAPI Protocol_UnlockRequest(IInternetProtocol *iface)
776 {
777     ok(0, "unexpected call\n");
778     return S_OK;
779 }
780
781 static const IInternetProtocolVtbl ProtocolVtbl = {
782     Protocol_QueryInterface,
783     Protocol_AddRef,
784     Protocol_Release,
785     Protocol_Start,
786     Protocol_Continue,
787     Protocol_Abort,
788     Protocol_Terminate,
789     Protocol_Suspend,
790     Protocol_Resume,
791     Protocol_Read,
792     Protocol_Seek,
793     Protocol_LockRequest,
794     Protocol_UnlockRequest
795 };
796
797 static IInternetProtocol Protocol = { &ProtocolVtbl };
798
799 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
800 {
801     ok(0, "unexpected call\n");
802     return E_NOINTERFACE;
803 }
804
805 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
806 {
807     return 2;
808 }
809
810 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
811 {
812     return 1;
813 }
814
815 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
816                                         REFIID riid, void **ppv)
817 {
818     CHECK_EXPECT(CreateInstance);
819
820     ok(pOuter == (IUnknown*)prot_bind_info, "pOuter != protocol_unk\n");
821     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid\n");
822     ok(ppv != NULL, "ppv == NULL\n");
823
824     *ppv = &Protocol;
825     return S_OK;
826 }
827
828 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
829 {
830     ok(0, "unexpected call\n");
831     return S_OK;
832 }
833
834 static const IClassFactoryVtbl ClassFactoryVtbl = {
835     ClassFactory_QueryInterface,
836     ClassFactory_AddRef,
837     ClassFactory_Release,
838     ClassFactory_CreateInstance,
839     ClassFactory_LockServer
840 };
841
842 static IClassFactory ClassFactory = { &ClassFactoryVtbl };
843
844 static void test_priority(IInternetProtocol *protocol)
845 {
846     IInternetPriority *priority;
847     LONG pr;
848     HRESULT hres;
849
850     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority,
851                                             (void**)&priority);
852     ok(hres == S_OK, "QueryInterface(IID_IInternetPriority) failed: %08x\n", hres);
853     if(FAILED(hres))
854         return;
855
856     hres = IInternetPriority_GetPriority(priority, &pr);
857     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
858     ok(pr == 0, "pr=%d, expected 0\n", pr);
859
860     hres = IInternetPriority_SetPriority(priority, 1);
861     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
862
863     hres = IInternetPriority_GetPriority(priority, &pr);
864     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
865     ok(pr == 1, "pr=%d, expected 1\n", pr);
866
867     IInternetPriority_Release(priority);
868 }
869
870 static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL is_first)
871 {
872     HRESULT hres;
873
874     SET_EXPECT(GetBindInfo);
875     if(!(bindf & BINDF_FROMURLMON))
876        SET_EXPECT(ReportProgress_DIRECTBIND);
877     if(is_first) {
878         SET_EXPECT(ReportProgress_SENDINGREQUEST);
879         SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
880         if(bindf & BINDF_FROMURLMON)
881             SET_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
882         else
883             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
884     }
885     SET_EXPECT(ReportData);
886     if(is_first)
887         SET_EXPECT(ReportResult);
888
889     expect_hrResult = S_OK;
890
891     hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0);
892     ok(hres == S_OK, "Start failed: %08x\n", hres);
893
894     CHECK_CALLED(GetBindInfo);
895     if(!(bindf & BINDF_FROMURLMON))
896        CHECK_CALLED(ReportProgress_DIRECTBIND);
897     if(is_first) {
898         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
899         CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
900         if(bindf & BINDF_FROMURLMON)
901             CHECK_CALLED(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
902         else
903             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
904     }
905     CHECK_CALLED(ReportData);
906     if(is_first)
907         CHECK_CALLED(ReportResult);
908 }
909
910 static void test_file_protocol_url(LPCWSTR url)
911 {
912     IInternetProtocolInfo *protocol_info;
913     IUnknown *unk;
914     IClassFactory *factory;
915     HRESULT hres;
916
917     hres = CoGetClassObject(&CLSID_FileProtocol, CLSCTX_INPROC_SERVER, NULL,
918             &IID_IUnknown, (void**)&unk);
919     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
920     if(!SUCCEEDED(hres))
921         return;
922
923     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
924     ok(hres == E_NOINTERFACE,
925             "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n", hres);
926
927     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
928     ok(hres == S_OK, "Could not get IClassFactory interface\n");
929     if(SUCCEEDED(hres)) {
930         IInternetProtocol *protocol;
931         BYTE buf[512];
932         ULONG cb;
933         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
934         ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
935
936         if(SUCCEEDED(hres)) {
937             file_protocol_start(protocol, url, TRUE);
938             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
939             ok(hres == S_OK, "Read failed: %08x\n", hres);
940             ok(cb == 2, "cb=%u expected 2\n", cb);
941             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
942             ok(hres == S_FALSE, "Read failed: %08x\n", hres);
943             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
944             ok(hres == S_FALSE, "Read failed: %08x expected S_FALSE\n", hres);
945             ok(cb == 0, "cb=%u expected 0\n", cb);
946             hres = IInternetProtocol_UnlockRequest(protocol);
947             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
948
949             file_protocol_start(protocol, url, FALSE);
950             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
951             ok(hres == S_FALSE, "Read failed: %08x\n", hres);
952             hres = IInternetProtocol_LockRequest(protocol, 0);
953             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
954             hres = IInternetProtocol_UnlockRequest(protocol);
955             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
956
957             IInternetProtocol_Release(protocol);
958         }
959
960         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
961         ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
962
963         if(SUCCEEDED(hres)) {
964             file_protocol_start(protocol, url, TRUE);
965             hres = IInternetProtocol_LockRequest(protocol, 0);
966             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
967             hres = IInternetProtocol_Terminate(protocol, 0);
968             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
969             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
970             ok(hres == S_OK, "Read failed: %08x\n\n", hres);
971             hres = IInternetProtocol_UnlockRequest(protocol);
972             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
973             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
974             ok(hres == S_OK, "Read failed: %08x\n", hres);
975             hres = IInternetProtocol_Terminate(protocol, 0);
976             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
977
978             IInternetProtocol_Release(protocol);
979         }
980
981         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
982         ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
983
984         if(SUCCEEDED(hres)) {
985             file_protocol_start(protocol, url, TRUE);
986             hres = IInternetProtocol_Terminate(protocol, 0);
987             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
988             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
989             ok(hres == S_OK, "Read failed: %08x\n", hres);
990             ok(cb == 2, "cb=%u expected 2\n", cb);
991
992             IInternetProtocol_Release(protocol);
993         }
994
995         IClassFactory_Release(factory);
996     }
997
998     IUnknown_Release(unk);
999 }
1000
1001 static void test_file_protocol_fail(void)
1002 {
1003     IInternetProtocol *protocol;
1004     HRESULT hres;
1005
1006     static const WCHAR index_url2[] =
1007         {'f','i','l','e',':','/','/','i','n','d','e','x','.','h','t','m','l',0};
1008
1009     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
1010             &IID_IInternetProtocol, (void**)&protocol);
1011     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
1012     if(FAILED(hres))
1013         return;
1014
1015     SET_EXPECT(GetBindInfo);
1016     expect_hrResult = MK_E_SYNTAX;
1017     hres = IInternetProtocol_Start(protocol, wszIndexHtml, &protocol_sink, &bind_info, 0, 0);
1018     ok(hres == MK_E_SYNTAX, "Start failed: %08x, expected MK_E_SYNTAX\n", hres);
1019     CHECK_CALLED(GetBindInfo);
1020
1021     SET_EXPECT(GetBindInfo);
1022     if(!(bindf & BINDF_FROMURLMON))
1023         SET_EXPECT(ReportProgress_DIRECTBIND);
1024     SET_EXPECT(ReportProgress_SENDINGREQUEST);
1025     SET_EXPECT(ReportResult);
1026     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
1027     hres = IInternetProtocol_Start(protocol, index_url, &protocol_sink, &bind_info, 0, 0);
1028     ok(hres == INET_E_RESOURCE_NOT_FOUND,
1029             "Start failed: %08x expected INET_E_RESOURCE_NOT_FOUND\n", hres);
1030     CHECK_CALLED(GetBindInfo);
1031     if(!(bindf & BINDF_FROMURLMON))
1032         CHECK_CALLED(ReportProgress_DIRECTBIND);
1033     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1034     CHECK_CALLED(ReportResult);
1035
1036     IInternetProtocol_Release(protocol);
1037
1038     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
1039             &IID_IInternetProtocol, (void**)&protocol);
1040     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
1041     if(FAILED(hres))
1042         return;
1043
1044     SET_EXPECT(GetBindInfo);
1045     if(!(bindf & BINDF_FROMURLMON))
1046         SET_EXPECT(ReportProgress_DIRECTBIND);
1047     SET_EXPECT(ReportProgress_SENDINGREQUEST);
1048     SET_EXPECT(ReportResult);
1049     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
1050
1051     hres = IInternetProtocol_Start(protocol, index_url2, &protocol_sink, &bind_info, 0, 0);
1052     ok(hres == INET_E_RESOURCE_NOT_FOUND,
1053             "Start failed: %08x, expected INET_E_RESOURCE_NOT_FOUND\n", hres);
1054     CHECK_CALLED(GetBindInfo);
1055     if(!(bindf & BINDF_FROMURLMON))
1056         CHECK_CALLED(ReportProgress_DIRECTBIND);
1057     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1058     CHECK_CALLED(ReportResult);
1059
1060     IInternetProtocol_Release(protocol);
1061 }
1062
1063 static void test_file_protocol(void) {
1064     WCHAR buf[MAX_PATH];
1065     DWORD size;
1066     ULONG len;
1067     HANDLE file;
1068
1069     static const WCHAR wszFile[] = {'f','i','l','e',':',0};
1070     static const WCHAR wszFile2[] = {'f','i','l','e',':','/','/',0};
1071     static const WCHAR wszFile3[] = {'f','i','l','e',':','/','/','/',0};
1072     static const char html_doc[] = "<HTML></HTML>";
1073
1074     trace("Testing file protocol...\n");
1075     tested_protocol = FILE_TEST;
1076
1077     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1078             FILE_ATTRIBUTE_NORMAL, NULL);
1079     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
1080     if(file == INVALID_HANDLE_VALUE)
1081         return;
1082     WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL);
1083     CloseHandle(file);
1084
1085     file_name = wszIndexHtml;
1086     bindf = 0;
1087     test_file_protocol_url(index_url);
1088     bindf = BINDF_FROMURLMON;
1089     test_file_protocol_url(index_url);
1090
1091     memcpy(buf, wszFile, sizeof(wszFile));
1092     len = sizeof(wszFile)/sizeof(WCHAR)-1;
1093     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
1094     buf[len++] = '\\';
1095     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
1096
1097     file_name = buf + sizeof(wszFile)/sizeof(WCHAR)-1;
1098     bindf = 0;
1099     test_file_protocol_url(buf);
1100     bindf = BINDF_FROMURLMON;
1101     test_file_protocol_url(buf);
1102
1103     memcpy(buf, wszFile2, sizeof(wszFile2));
1104     len = sizeof(wszFile2)/sizeof(WCHAR)-1;
1105     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
1106     buf[len++] = '\\';
1107     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
1108
1109     file_name = buf + sizeof(wszFile2)/sizeof(WCHAR)-1;
1110     bindf = 0;
1111     test_file_protocol_url(buf);
1112     bindf = BINDF_FROMURLMON;
1113     test_file_protocol_url(buf);
1114
1115     memcpy(buf, wszFile3, sizeof(wszFile3));
1116     len = sizeof(wszFile3)/sizeof(WCHAR)-1;
1117     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
1118     buf[len++] = '\\';
1119     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
1120
1121     file_name = buf + sizeof(wszFile3)/sizeof(WCHAR)-1;
1122     bindf = 0;
1123     test_file_protocol_url(buf);
1124     bindf = BINDF_FROMURLMON;
1125     test_file_protocol_url(buf);
1126
1127     DeleteFileW(wszIndexHtml);
1128
1129     bindf = 0;
1130     test_file_protocol_fail();
1131     bindf = BINDF_FROMURLMON;
1132     test_file_protocol_fail();
1133 }
1134
1135 static BOOL http_protocol_start(LPCWSTR url, BOOL is_first)
1136 {
1137     static BOOL got_user_agent = FALSE;
1138     HRESULT hres;
1139
1140     first_data_notif = TRUE;
1141     state = 0;
1142
1143     SET_EXPECT(GetBindInfo);
1144     if (!(bindf & BINDF_FROMURLMON))
1145         SET_EXPECT(ReportProgress_DIRECTBIND);
1146     SET_EXPECT(GetBindString_USER_AGENT);
1147     SET_EXPECT(GetBindString_ACCEPT_MIMES);
1148     SET_EXPECT(QueryService_HttpNegotiate);
1149     SET_EXPECT(BeginningTransaction);
1150     SET_EXPECT(GetRootSecurityId);
1151     if (http_post_test)
1152         SET_EXPECT(GetBindString_POST_COOKIE);
1153
1154     hres = IInternetProtocol_Start(http_protocol, url, &protocol_sink, &bind_info, 0, 0);
1155     ok(hres == S_OK, "Start failed: %08x\n", hres);
1156     if(FAILED(hres))
1157         return FALSE;
1158
1159     CHECK_CALLED(GetBindInfo);
1160     if (!(bindf & BINDF_FROMURLMON))
1161         CHECK_CALLED(ReportProgress_DIRECTBIND);
1162     if (!got_user_agent)
1163     {
1164         CHECK_CALLED(GetBindString_USER_AGENT);
1165         got_user_agent = TRUE;
1166     }
1167     else todo_wine
1168     {
1169         /* user agent only retrieved once, even with different URLs */
1170         CHECK_NOT_CALLED(GetBindString_USER_AGENT);
1171     }
1172     CHECK_CALLED(GetBindString_ACCEPT_MIMES);
1173     CHECK_CALLED(QueryService_HttpNegotiate);
1174     CHECK_CALLED(BeginningTransaction);
1175     /* GetRootSecurityId called on WinXP but not on Win98 */
1176     CLEAR_CALLED(GetRootSecurityId);
1177     if (http_post_test) todo_wine
1178         CHECK_CALLED(GetBindString_POST_COOKIE);
1179
1180     return TRUE;
1181 }
1182
1183 /* is_first refers to whether this is the first call to this function
1184  * _for this url_ */
1185 static void test_http_protocol_url(LPCWSTR url, BOOL is_first)
1186 {
1187     IInternetProtocolInfo *protocol_info;
1188     IClassFactory *factory;
1189     IUnknown *unk;
1190     HRESULT hres;
1191
1192     trace("Testing http protocol...\n");
1193     http_url = url;
1194     http_is_first = is_first;
1195
1196     hres = CoGetClassObject(&CLSID_HttpProtocol, CLSCTX_INPROC_SERVER, NULL,
1197             &IID_IUnknown, (void**)&unk);
1198     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
1199     if(!SUCCEEDED(hres))
1200         return;
1201
1202     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
1203     ok(hres == E_NOINTERFACE,
1204         "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n",
1205         hres);
1206
1207     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
1208     ok(hres == S_OK, "Could not get IClassFactory interface\n");
1209     IUnknown_Release(unk);
1210     if(FAILED(hres))
1211         return;
1212
1213     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
1214                                         (void**)&http_protocol);
1215     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
1216     if(SUCCEEDED(hres)) {
1217         BYTE buf[512];
1218         DWORD cb;
1219         MSG msg;
1220
1221         test_priority(http_protocol);
1222
1223         SET_EXPECT(ReportProgress_FINDINGRESOURCE);
1224         SET_EXPECT(ReportProgress_CONNECTING);
1225         SET_EXPECT(ReportProgress_SENDINGREQUEST);
1226         if(!(bindf & BINDF_FROMURLMON))
1227         {
1228             SET_EXPECT(OnResponse);
1229             SET_EXPECT(ReportProgress_RAWMIMETYPE);
1230             SET_EXPECT(ReportData);
1231         }
1232
1233         if(!http_protocol_start(url, is_first))
1234             return;
1235
1236         hres = IInternetProtocol_Read(http_protocol, buf, 2, &cb);
1237         ok(hres == E_PENDING, "Read failed: %08x, expected E_PENDING\n", hres);
1238         ok(!cb, "cb=%d, expected 0\n", cb);
1239
1240         if(bindf & BINDF_FROMURLMON)
1241             SET_EXPECT(Switch);
1242         SET_EXPECT(ReportResult);
1243         expect_hrResult = S_OK;
1244
1245         GetMessage(&msg, NULL, 0, 0);
1246
1247         if(bindf & BINDF_FROMURLMON)
1248             CHECK_CALLED(Switch);
1249         CHECK_CALLED(ReportResult);
1250
1251         hres = IInternetProtocol_Terminate(http_protocol, 0);
1252         ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1253
1254         IInternetProtocol_Release(http_protocol);
1255     }
1256
1257     IClassFactory_Release(factory);
1258 }
1259
1260 static void test_http_protocol(void)
1261 {
1262     static const WCHAR winehq_url[] =
1263         {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
1264             'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
1265     static const WCHAR posttest_url[] =
1266         {'h','t','t','p',':','/','/','c','r','o','s','s','o','v','e','r','.',
1267          'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m','/',
1268          'p','o','s','t','t','e','s','t','.','p','h','p',0};
1269
1270     tested_protocol = HTTP_TEST;
1271     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
1272     test_http_protocol_url(winehq_url, TRUE);
1273     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
1274     test_http_protocol_url(winehq_url, FALSE);
1275
1276     http_post_test = TRUE;
1277     /* Without this flag we get a ReportProgress_CACHEFILENAMEAVAILABLE
1278      * notification with BINDVERB_POST */
1279     bindf |= BINDF_NOWRITECACHE;
1280     test_http_protocol_url(posttest_url, TRUE);
1281     http_post_test = FALSE;
1282 }
1283
1284 static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1285 {
1286     if(msg == WM_USER) {
1287         BOOL first_call = FALSE;
1288         HRESULT hres;
1289         DWORD cb;
1290         BYTE buf[3600];
1291
1292         if(!state) {
1293             first_call = TRUE;
1294             state = 1;
1295
1296             if (http_is_first)
1297             {
1298                 CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
1299                 CHECK_CALLED(ReportProgress_CONNECTING);
1300             }
1301             else todo_wine
1302             {
1303                 CHECK_NOT_CALLED(ReportProgress_FINDINGRESOURCE);
1304                 CHECK_NOT_CALLED(ReportProgress_CONNECTING);
1305             }
1306             CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1307             if(!(bindf & BINDF_FROMURLMON))
1308             {
1309                 CHECK_CALLED(OnResponse);
1310                 CHECK_CALLED(ReportProgress_RAWMIMETYPE);
1311                 CHECK_CALLED(ReportData);
1312             }
1313             else
1314             {
1315                 SET_EXPECT(OnResponse);
1316                 SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1317             }
1318         }
1319         SET_EXPECT(ReportData);
1320
1321         if (bindf & BINDF_FROMURLMON)
1322         {
1323             hres = IInternetProtocol_Continue(http_protocol, (PROTOCOLDATA*)lParam);
1324             ok(hres == S_OK, "Continue failed: %08x\n", hres);
1325
1326             CHECK_CALLED(ReportData);
1327             if(first_call) {
1328                 CHECK_CALLED(OnResponse);
1329                 CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1330             }
1331         }
1332
1333         do hres = IInternetProtocol_Read(http_protocol, buf, sizeof(buf), &cb);
1334         while(cb);
1335
1336         ok(hres == S_FALSE || hres == E_PENDING, "Read failed: %08x\n", hres);
1337
1338         if(hres == S_FALSE)
1339             PostMessage(protocol_hwnd, WM_USER+1, 0, 0);
1340
1341         if(first_call) {
1342             hres = IInternetProtocol_LockRequest(http_protocol, 0);
1343             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
1344
1345             do hres = IInternetProtocol_Read(http_protocol, buf, sizeof(buf), &cb);
1346             while(cb);
1347             ok(hres == S_FALSE || hres == E_PENDING, "Read failed: %08x\n", hres);
1348         }
1349     }
1350
1351     return DefWindowProc(hwnd, msg, wParam, lParam);
1352 }
1353
1354 static HWND create_protocol_window(void)
1355 {
1356     static WNDCLASSEX wndclass = {
1357         sizeof(WNDCLASSEX),
1358         0,
1359         wnd_proc,
1360         0, 0, NULL, NULL, NULL, NULL, NULL,
1361         "ProtocolWindow",
1362         NULL
1363     };
1364
1365     RegisterClassEx(&wndclass);
1366     return CreateWindow("ProtocolWindow", "ProtocolWindow",
1367                          WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1368                          CW_USEDEFAULT, NULL, NULL, NULL, NULL);
1369 }
1370
1371 static void test_mk_protocol(void)
1372 {
1373     IInternetProtocolInfo *protocol_info;
1374     IInternetProtocol *protocol;
1375     IClassFactory *factory;
1376     IUnknown *unk;
1377     HRESULT hres;
1378
1379     static const WCHAR wrong_url1[] = {'t','e','s','t',':','@','M','S','I','T','S','t','o','r','e',
1380                                        ':',':','/','t','e','s','t','.','h','t','m','l',0};
1381     static const WCHAR wrong_url2[] = {'m','k',':','/','t','e','s','t','.','h','t','m','l',0};
1382
1383     trace("Testing mk protocol...\n");
1384     tested_protocol = MK_TEST;
1385
1386     hres = CoGetClassObject(&CLSID_MkProtocol, CLSCTX_INPROC_SERVER, NULL,
1387             &IID_IUnknown, (void**)&unk);
1388     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
1389
1390     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
1391     ok(hres == E_NOINTERFACE,
1392         "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n",
1393         hres);
1394
1395     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
1396     ok(hres == S_OK, "Could not get IClassFactory interface\n");
1397     IUnknown_Release(unk);
1398     if(FAILED(hres))
1399         return;
1400
1401     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
1402                                         (void**)&protocol);
1403     IClassFactory_Release(factory);
1404     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
1405
1406     SET_EXPECT(GetBindInfo);
1407     hres = IInternetProtocol_Start(protocol, wrong_url1, &protocol_sink, &bind_info, 0, 0);
1408     ok(hres == MK_E_SYNTAX, "Start failed: %08x, expected MK_E_SYNTAX\n", hres);
1409     CHECK_CALLED(GetBindInfo);
1410
1411     SET_EXPECT(GetBindInfo);
1412     SET_EXPECT(ReportProgress_DIRECTBIND);
1413     SET_EXPECT(ReportProgress_SENDINGREQUEST);
1414     SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1415     SET_EXPECT(ReportResult);
1416     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
1417
1418     hres = IInternetProtocol_Start(protocol, wrong_url2, &protocol_sink, &bind_info, 0, 0);
1419     ok(hres == INET_E_RESOURCE_NOT_FOUND, "Start failed: %08x, expected INET_E_RESOURCE_NOT_FOUND\n", hres);
1420
1421     CHECK_CALLED(GetBindInfo);
1422     CHECK_CALLED(ReportProgress_DIRECTBIND);
1423     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1424     CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1425     CHECK_CALLED(ReportResult);
1426
1427     IInternetProtocol_Release(protocol);
1428 }
1429
1430 static void test_CreateBinding(void)
1431 {
1432     IInternetProtocol *protocol;
1433     IInternetPriority *priority;
1434     IInternetSession *session;
1435     LONG p;
1436     BYTE buf[1000];
1437     DWORD read;
1438     HRESULT hres;
1439
1440     static const WCHAR test_url[] =
1441         {'t','e','s','t',':','/','/','f','i','l','e','.','h','t','m','l',0};
1442     static const WCHAR wsz_test[] = {'t','e','s','t',0};
1443
1444     trace("Testing CreateBinding...\n");
1445     tested_protocol = BIND_TEST;
1446
1447     hres = CoInternetGetSession(0, &session, 0);
1448     ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
1449
1450     hres = IInternetSession_RegisterNameSpace(session, &ClassFactory, &IID_NULL, wsz_test, 0, NULL, 0);
1451     ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres);
1452
1453     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
1454     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
1455     ok(protocol != NULL, "protocol == NULL\n");
1456
1457     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info);
1458     ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres);
1459
1460     hres = IInternetProtocol_Start(protocol, test_url, NULL, &bind_info, 0, 0);
1461     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
1462     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, NULL, 0, 0);
1463     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
1464     hres = IInternetProtocol_Start(protocol, NULL, &protocol_sink, &bind_info, 0, 0);
1465     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
1466
1467     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
1468     ok(hres == S_OK, "QueryInterface(IID_IInternetPriority) failed: %08x\n", hres);
1469
1470     p = 0xdeadbeef;
1471     hres = IInternetPriority_GetPriority(priority, &p);
1472     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1473     ok(!p, "p=%d\n", p);
1474
1475     hres = IInternetPriority_SetPriority(priority, 100);
1476     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
1477
1478     p = 0xdeadbeef;
1479     hres = IInternetPriority_GetPriority(priority, &p);
1480     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1481     ok(p == 100, "p=%d\n", p);
1482
1483     SET_EXPECT(QueryService_InternetProtocol);
1484     SET_EXPECT(CreateInstance);
1485     SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
1486     SET_EXPECT(SetPriority);
1487     SET_EXPECT(Start);
1488
1489     expect_hrResult = S_OK;
1490     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, &bind_info, 0, 0);
1491     ok(hres == S_OK, "Start failed: %08x\n", hres);
1492
1493     CHECK_CALLED(QueryService_InternetProtocol);
1494     CHECK_CALLED(CreateInstance);
1495     CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
1496     CHECK_CALLED(SetPriority);
1497     CHECK_CALLED(Start);
1498
1499     SET_EXPECT(Read);
1500     read = 0xdeadbeef;
1501     hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
1502     ok(hres == S_OK, "Read failed: %08x\n", hres);
1503     ok(read == 100, "read = %d\n", read);
1504     CHECK_CALLED(Read);
1505
1506     SET_EXPECT(Read);
1507     read = 0xdeadbeef;
1508     hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
1509     ok(hres == S_FALSE, "Read failed: %08x\n", hres);
1510     ok(!read, "read = %d\n", read);
1511     CHECK_CALLED(Read);
1512
1513     p = 0xdeadbeef;
1514     hres = IInternetPriority_GetPriority(priority, &p);
1515     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
1516     ok(p == 100, "p=%d\n", p);
1517
1518     hres = IInternetPriority_SetPriority(priority, 101);
1519     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
1520
1521     SET_EXPECT(Terminate);
1522     hres = IInternetProtocol_Terminate(protocol, 0xdeadbeef);
1523     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
1524     CHECK_CALLED(Terminate);
1525
1526     IInternetPriority_Release(priority);
1527     IInternetBindInfo_Release(prot_bind_info);
1528     IInternetProtocol_Release(protocol);
1529     IInternetSession_Release(session);
1530 }
1531
1532 START_TEST(protocol)
1533 {
1534     OleInitialize(NULL);
1535
1536     protocol_hwnd = create_protocol_window();
1537
1538     test_file_protocol();
1539     test_http_protocol();
1540     test_mk_protocol();
1541     test_CreateBinding();
1542
1543     DestroyWindow(protocol_hwnd);
1544
1545     OleUninitialize();
1546 }