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