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