1 /*
2  * Copyright 2005-2011 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 <wine/heap.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "ole2.h"
30 #include "urlmon.h"
31 #include "wininet.h"
32 
33 static HRESULT (WINAPI *pCoInternetGetSession)(DWORD, IInternetSession **, DWORD);
34 static HRESULT (WINAPI *pReleaseBindInfo)(BINDINFO*);
35 static HRESULT (WINAPI *pCreateUri)(LPCWSTR, DWORD, DWORD_PTR, IUri**);
36 
37 #define DEFINE_EXPECT(func) \
38     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
39 
40 #define SET_EXPECT(func) \
41     expect_ ## func = TRUE
42 
43 #define CHECK_EXPECT2(func) \
44     do { \
45         ok(expect_ ##func, "unexpected call " #func  "\n"); \
46         called_ ## func = TRUE; \
47     }while(0)
48 
49 #define CHECK_EXPECT(func) \
50     do { \
51         CHECK_EXPECT2(func);     \
52         expect_ ## func = FALSE; \
53     }while(0)
54 
55 #define CHECK_CALLED(func) \
56     do { \
57         ok(called_ ## func, "expected " #func "\n"); \
58         expect_ ## func = called_ ## func = FALSE; \
59     }while(0)
60 
61 #define CHECK_NOT_CALLED(func) \
62     do { \
63         ok(!called_ ## func, "unexpected " #func "\n"); \
64         expect_ ## func = called_ ## func = FALSE; \
65     }while(0)
66 
67 #define CLEAR_CALLED(func) \
68     expect_ ## func = called_ ## func = FALSE
69 
70 DEFINE_EXPECT(GetBindInfo);
71 DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
72 DEFINE_EXPECT(ReportProgress_DIRECTBIND);
73 DEFINE_EXPECT(ReportProgress_RAWMIMETYPE);
74 DEFINE_EXPECT(ReportProgress_FINDINGRESOURCE);
75 DEFINE_EXPECT(ReportProgress_CONNECTING);
76 DEFINE_EXPECT(ReportProgress_SENDINGREQUEST);
77 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
78 DEFINE_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
79 DEFINE_EXPECT(ReportProgress_PROTOCOLCLASSID);
80 DEFINE_EXPECT(ReportProgress_COOKIE_SENT);
81 DEFINE_EXPECT(ReportProgress_REDIRECTING);
82 DEFINE_EXPECT(ReportProgress_ENCODING);
83 DEFINE_EXPECT(ReportProgress_ACCEPTRANGES);
84 DEFINE_EXPECT(ReportProgress_PROXYDETECTING);
85 DEFINE_EXPECT(ReportProgress_LOADINGMIMEHANDLER);
86 DEFINE_EXPECT(ReportProgress_DECODING);
87 DEFINE_EXPECT(ReportData);
88 DEFINE_EXPECT(ReportData2);
89 DEFINE_EXPECT(ReportResult);
90 DEFINE_EXPECT(GetBindString_ACCEPT_MIMES);
91 DEFINE_EXPECT(GetBindString_USER_AGENT);
92 DEFINE_EXPECT(GetBindString_POST_COOKIE);
93 DEFINE_EXPECT(GetBindString_URL);
94 DEFINE_EXPECT(GetBindString_ROOTDOC_URL);
95 DEFINE_EXPECT(QueryService_HttpNegotiate);
96 DEFINE_EXPECT(QueryService_InternetProtocol);
97 DEFINE_EXPECT(QueryService_HttpSecurity);
98 DEFINE_EXPECT(QueryService_IBindCallbackRedirect);
99 DEFINE_EXPECT(QueryInterface_IWinInetInfo);
100 DEFINE_EXPECT(QueryInterface_IWinInetHttpInfo);
101 DEFINE_EXPECT(BeginningTransaction);
102 DEFINE_EXPECT(GetRootSecurityId);
103 DEFINE_EXPECT(OnResponse);
104 DEFINE_EXPECT(Switch);
105 DEFINE_EXPECT(Continue);
106 DEFINE_EXPECT(CreateInstance);
107 DEFINE_EXPECT(Start);
108 DEFINE_EXPECT(StartEx);
109 DEFINE_EXPECT(Terminate);
110 DEFINE_EXPECT(Read);
111 DEFINE_EXPECT(Read2);
112 DEFINE_EXPECT(SetPriority);
113 DEFINE_EXPECT(LockRequest);
114 DEFINE_EXPECT(UnlockRequest);
115 DEFINE_EXPECT(Abort);
116 DEFINE_EXPECT(MimeFilter_CreateInstance);
117 DEFINE_EXPECT(MimeFilter_Start);
118 DEFINE_EXPECT(MimeFilter_ReportData);
119 DEFINE_EXPECT(MimeFilter_ReportResult);
120 DEFINE_EXPECT(MimeFilter_Terminate);
121 DEFINE_EXPECT(MimeFilter_LockRequest);
122 DEFINE_EXPECT(MimeFilter_UnlockRequest);
123 DEFINE_EXPECT(MimeFilter_Read);
124 DEFINE_EXPECT(MimeFilter_Switch);
125 DEFINE_EXPECT(MimeFilter_Continue);
126 DEFINE_EXPECT(Stream_Seek);
127 DEFINE_EXPECT(Stream_Read);
128 DEFINE_EXPECT(Redirect);
129 DEFINE_EXPECT(outer_QI_test);
130 DEFINE_EXPECT(Protocol_destructor);
131 
132 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
133 static const WCHAR index_url[] =
134     {'f','i','l','e',':','i','n','d','e','x','.','h','t','m','l',0};
135 
136 static const WCHAR acc_mimeW[] = {'*','/','*',0};
137 static const WCHAR user_agentW[] = {'W','i','n','e',0};
138 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
139 static const WCHAR hostW[] = {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
140 static const WCHAR winehq_ipW[] = {'2','0','9','.','4','6','.','2','5','.','1','3','4',0};
141 static const WCHAR emptyW[] = {0};
142 static const WCHAR pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
143 static const WCHAR gifW[] = {'i','m','a','g','e','/','g','i','f',0};
144 
145 static HRESULT expect_hrResult;
146 static LPCWSTR file_name, http_url, expect_wsz;
147 static IInternetProtocol *async_protocol = NULL;
148 static BOOL first_data_notif, http_is_first, test_redirect, redirect_on_continue;
149 static int prot_state, read_report_data, post_stream_read;
150 static DWORD bindf, ex_priority , pi, bindinfo_options;
151 static IInternetProtocol *binding_protocol, *filtered_protocol;
152 static IInternetBindInfo *prot_bind_info;
153 static IInternetProtocolSink *binding_sink, *filtered_sink;
154 static void *expect_pv;
155 static HANDLE event_complete, event_complete2, event_continue, event_continue_done;
156 static BOOL binding_test;
157 static PROTOCOLDATA protocoldata, *pdata, continue_protdata;
158 static DWORD prot_read, filter_state, http_post_test, thread_id;
159 static BOOL security_problem, test_async_req, impl_protex;
160 static BOOL async_read_pending, mimefilter_test, direct_read, wait_for_switch, emulate_prot, short_read, test_abort;
161 static BOOL empty_file, no_mime, bind_from_cache, file_with_hash, reuse_protocol_thread;
162 
163 enum {
164     STATE_CONNECTING,
165     STATE_SENDINGREQUEST,
166     STATE_STARTDOWNLOADING,
167     STATE_DOWNLOADING
168 } state;
169 
170 static enum {
171     FILE_TEST,
172     HTTP_TEST,
173     HTTPS_TEST,
174     FTP_TEST,
175     MK_TEST,
176     ITS_TEST,
177     BIND_TEST
178 } tested_protocol;
179 
180 typedef struct {
181     IUnknown IUnknown_inner;
182     IInternetProtocolEx IInternetProtocolEx_iface;
183     IInternetPriority IInternetPriority_iface;
184     IUnknown *outer;
185     LONG inner_ref;
186     LONG outer_ref;
187 } Protocol;
188 
189 static Protocol *protocol_emul;
190 
191 static const WCHAR protocol_names[][10] = {
192     {'f','i','l','e',0},
193     {'h','t','t','p',0},
194     {'h','t','t','p','s',0},
195     {'f','t','p',0},
196     {'m','k',0},
197     {'i','t','s',0},
198     {'t','e','s','t',0}
199 };
200 
201 static const WCHAR binding_urls[][130] = {
202     {'f','i','l','e',':','t','e','s','t','.','h','t','m','l',0},
203     {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
204      'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0},
205     {'h','t','t','p','s',':','/','/','w','w','w','.','c','o','d','e','w','e','a','v','e','r','s',
206      '.','c','o','m','/','t','e','s','t','.','h','t','m','l',0},
207     {'f','t','p',':','/','/','f','t','p','.','w','i','n','e','h','q','.','o','r','g',
208      '/','p','u','b','/','o','t','h','e','r',
209      '/','w','i','n','e','l','o','g','o','.','x','c','f','.','t','a','r','.','b','z','2',0},
210     {'m','k',':','t','e','s','t',0},
211     {'i','t','s',':','t','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0},
212     {'t','e','s','t',':','/','/','f','i','l','e','.','h','t','m','l',0}
213 };
214 
215 static const CHAR post_data[] = "mode=Test";
216 
217 static int strcmp_wa(LPCWSTR strw, const char *stra)
218 {
219     CHAR buf[512];
220     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
221     return lstrcmpA(stra, buf);
222 }
223 
224 static const char *w2a(LPCWSTR str)
225 {
226     static char buf[INTERNET_MAX_URL_LENGTH];
227     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
228     return buf;
229 }
230 
231 static HRESULT WINAPI HttpSecurity_QueryInterface(IHttpSecurity *iface, REFIID riid, void **ppv)
232 {
233     if(IsEqualGUID(&IID_IUnknown, riid)
234             || IsEqualGUID(&IID_IHttpSecurity, riid)) {
235         *ppv = iface;
236         return S_OK;
237     }
238 
239     ok(0, "unexpected call\n");
240     return E_NOINTERFACE;
241 }
242 
243 static ULONG WINAPI HttpSecurity_AddRef(IHttpSecurity *iface)
244 {
245     return 2;
246 }
247 
248 static ULONG WINAPI HttpSecurity_Release(IHttpSecurity *iface)
249 {
250     return 1;
251 }
252 
253 static  HRESULT WINAPI HttpSecurity_GetWindow(IHttpSecurity* iface, REFGUID rguidReason, HWND *phwnd)
254 {
255     trace("HttpSecurity_GetWindow\n");
256 
257     return S_FALSE;
258 }
259 
260 static HRESULT WINAPI HttpSecurity_OnSecurityProblem(IHttpSecurity *iface, DWORD dwProblem)
261 {
262     win_skip("Security problem: %u\n", dwProblem);
263     ok(dwProblem == ERROR_INTERNET_SEC_CERT_REV_FAILED || dwProblem == ERROR_INTERNET_INVALID_CA,
264        "Expected got %u security problem\n", dwProblem);
265 
266     /* Only retry once */
267     if (security_problem)
268         return E_ABORT;
269 
270     security_problem = TRUE;
271     if(dwProblem == ERROR_INTERNET_INVALID_CA)
272         return E_ABORT;
273     SET_EXPECT(BeginningTransaction);
274 
275     return RPC_E_RETRY;
276 }
277 
278 static IHttpSecurityVtbl HttpSecurityVtbl = {
279     HttpSecurity_QueryInterface,
280     HttpSecurity_AddRef,
281     HttpSecurity_Release,
282     HttpSecurity_GetWindow,
283     HttpSecurity_OnSecurityProblem
284 };
285 
286 static IHttpSecurity http_security = { &HttpSecurityVtbl };
287 
288 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv)
289 {
290     if(IsEqualGUID(&IID_IUnknown, riid)
291             || IsEqualGUID(&IID_IHttpNegotiate, riid)
292             || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
293         *ppv = iface;
294         return S_OK;
295     }
296 
297     ok(0, "unexpected call\n");
298     return E_NOINTERFACE;
299 }
300 
301 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
302 {
303     return 2;
304 }
305 
306 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
307 {
308     return 1;
309 }
310 
311 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL,
312         LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
313 {
314     LPWSTR addl_headers;
315 
316     static const WCHAR wszHeaders[] =
317         {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ','a','p','p','l','i','c','a','t',
318          'i','o','n','/','x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o',
319          'd','e','d','\r','\n',0};
320 
321     CHECK_EXPECT(BeginningTransaction);
322 
323     if(binding_test)
324         ok(!lstrcmpW(szURL, binding_urls[tested_protocol]), "szURL != http_url\n");
325     else
326         ok(!lstrcmpW(szURL, http_url), "szURL != http_url\n");
327     ok(!dwReserved, "dwReserved=%d, expected 0\n", dwReserved);
328     ok(pszAdditionalHeaders != NULL, "pszAdditionalHeaders == NULL\n");
329     if(pszAdditionalHeaders)
330     {
331         ok(*pszAdditionalHeaders == NULL, "*pszAdditionalHeaders != NULL\n");
332         if (http_post_test)
333         {
334             addl_headers = CoTaskMemAlloc(sizeof(wszHeaders));
335             memcpy(addl_headers, wszHeaders, sizeof(wszHeaders));
336             *pszAdditionalHeaders = addl_headers;
337         }
338     }
339 
340     return S_OK;
341 }
342 
343 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
344         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
345 {
346     CHECK_EXPECT(OnResponse);
347 
348     ok(dwResponseCode == 200, "dwResponseCode=%d, expected 200\n", dwResponseCode);
349     ok(szResponseHeaders != NULL, "szResponseHeaders == NULL\n");
350     ok(szRequestHeaders == NULL, "szRequestHeaders != NULL\n");
351     ok(pszAdditionalRequestHeaders == NULL, "pszAdditionalHeaders != NULL\n");
352 
353     return S_OK;
354 }
355 
356 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
357         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
358 {
359     static const BYTE sec_id[] = {'h','t','t','p',':','t','e','s','t',1,0,0,0};
360 
361     CHECK_EXPECT(GetRootSecurityId);
362 
363     ok(!dwReserved, "dwReserved=%ld, expected 0\n", dwReserved);
364     ok(pbSecurityId != NULL, "pbSecurityId == NULL\n");
365     ok(pcbSecurityId != NULL, "pcbSecurityId == NULL\n");
366 
367     if(pcbSecurityId) {
368         ok(*pcbSecurityId == 512, "*pcbSecurityId=%d, expected 512\n", *pcbSecurityId);
369         *pcbSecurityId = sizeof(sec_id);
370     }
371 
372     if(pbSecurityId)
373         memcpy(pbSecurityId, sec_id, sizeof(sec_id));
374 
375     return E_FAIL;
376 }
377 
378 static IHttpNegotiate2Vtbl HttpNegotiateVtbl = {
379     HttpNegotiate_QueryInterface,
380     HttpNegotiate_AddRef,
381     HttpNegotiate_Release,
382     HttpNegotiate_BeginningTransaction,
383     HttpNegotiate_OnResponse,
384     HttpNegotiate_GetRootSecurityId
385 };
386 
387 static IHttpNegotiate2 http_negotiate = { &HttpNegotiateVtbl };
388 
389 static HRESULT WINAPI BindCallbackRedirect_QueryInterface(IBindCallbackRedirect *iface, REFIID riid, void **ppv)
390 {
391     ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
392     *ppv = NULL;
393     return E_NOINTERFACE;
394 }
395 
396 static ULONG WINAPI BindCallbackRedirect_AddRef(IBindCallbackRedirect *iface)
397 {
398     return 2;
399 }
400 
401 static ULONG WINAPI BindCallbackRedirect_Release(IBindCallbackRedirect *iface)
402 {
403     return 1;
404 }
405 
406 static HRESULT WINAPI BindCallbackRedirect_Redirect(IBindCallbackRedirect *iface, const WCHAR *url, VARIANT_BOOL *cancel)
407 {
408     CHECK_EXPECT(Redirect);
409     *cancel = VARIANT_FALSE;
410     return S_OK;
411 }
412 
413 static const IBindCallbackRedirectVtbl BindCallbackRedirectVtbl = {
414     BindCallbackRedirect_QueryInterface,
415     BindCallbackRedirect_AddRef,
416     BindCallbackRedirect_Release,
417     BindCallbackRedirect_Redirect
418 };
419 
420 static IBindCallbackRedirect redirect_callback = { &BindCallbackRedirectVtbl };
421 
422 static HRESULT QueryInterface(REFIID,void**);
423 
424 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
425 {
426     return QueryInterface(riid, ppv);
427 }
428 
429 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
430 {
431     return 2;
432 }
433 
434 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
435 {
436     return 1;
437 }
438 
439 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
440         REFIID riid, void **ppv)
441 {
442     if(IsEqualGUID(&IID_IHttpNegotiate, guidService) || IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
443         CHECK_EXPECT2(QueryService_HttpNegotiate);
444         return IHttpNegotiate2_QueryInterface(&http_negotiate, riid, ppv);
445     }
446 
447     if(IsEqualGUID(&IID_IInternetProtocol, guidService)) {
448         ok(IsEqualGUID(&IID_IInternetProtocol, riid), "unexpected riid\n");
449         CHECK_EXPECT(QueryService_InternetProtocol);
450         return E_NOINTERFACE;
451     }
452 
453     if(IsEqualGUID(&IID_IHttpSecurity, guidService)) {
454         ok(IsEqualGUID(&IID_IHttpSecurity, riid), "unexpected riid\n");
455         CHECK_EXPECT(QueryService_HttpSecurity);
456         return IHttpSecurity_QueryInterface(&http_security, riid, ppv);
457     }
458 
459     if(IsEqualGUID(&IID_IBindCallbackRedirect, guidService)) {
460         CHECK_EXPECT(QueryService_IBindCallbackRedirect);
461         ok(IsEqualGUID(&IID_IBindCallbackRedirect, riid), "riid = %s\n", wine_dbgstr_guid(riid));
462         *ppv = &redirect_callback;
463         return S_OK;
464     }
465 
466     if(IsEqualGUID(&IID_IGetBindHandle, guidService)) {
467         trace("QueryService(IID_IGetBindHandle)\n");
468         *ppv = NULL;
469         return E_NOINTERFACE;
470     }
471 
472     if(IsEqualGUID(&IID_IWindowForBindingUI, guidService)) {
473         trace("QueryService(IID_IWindowForBindingUI)\n");
474         *ppv = NULL;
475         return E_NOINTERFACE;
476     }
477 
478     ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService));
479     return E_FAIL;
480 }
481 
482 static const IServiceProviderVtbl ServiceProviderVtbl = {
483     ServiceProvider_QueryInterface,
484     ServiceProvider_AddRef,
485     ServiceProvider_Release,
486     ServiceProvider_QueryService
487 };
488 
489 static IServiceProvider service_provider = { &ServiceProviderVtbl };
490 
491 static HRESULT WINAPI Stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
492 {
493     static const IID IID_strm_unknown = {0x2f68429a,0x199a,0x4043,{0x93,0x11,0xf2,0xfe,0x7c,0x13,0xcc,0xb9}};
494 
495     if(!IsEqualGUID(&IID_strm_unknown, riid)) /* IE11 */
496         ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
497 
498     *ppv = NULL;
499     return E_NOINTERFACE;
500 }
501 
502 static ULONG WINAPI Stream_AddRef(IStream *iface)
503 {
504     return 2;
505 }
506 
507 static ULONG WINAPI Stream_Release(IStream *iface)
508 {
509     return 1;
510 }
511 
512 static HRESULT WINAPI Stream_Read(IStream *iface, void *pv,
513         ULONG cb, ULONG *pcbRead)
514 {
515     CHECK_EXPECT2(Stream_Read);
516 
517     ok(GetCurrentThreadId() != thread_id, "wrong thread %d\n", GetCurrentThreadId());
518 
519     ok(pv != NULL, "pv == NULL\n");
520     ok(cb == 0x20000 || broken(cb == 0x2000), "cb = %d\n", cb);
521     ok(pcbRead != NULL, "pcbRead == NULL\n");
522 
523     if(post_stream_read) {
524         *pcbRead = 0;
525         return S_FALSE;
526     }
527 
528     memcpy(pv, post_data, sizeof(post_data)-1);
529     post_stream_read += *pcbRead = sizeof(post_data)-1;
530     return S_OK;
531 }
532 
533 static HRESULT WINAPI Stream_Write(IStream *iface, const void *pv,
534         ULONG cb, ULONG *pcbWritten)
535 {
536     ok(0, "unexpected call\n");
537     return E_NOTIMPL;
538 }
539 
540 static HRESULT WINAPI Stream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
541         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
542 {
543     CHECK_EXPECT(Stream_Seek);
544 
545     ok(!dlibMove.QuadPart, "dlibMove != 0\n");
546     ok(dwOrigin == STREAM_SEEK_SET, "dwOrigin = %d\n", dwOrigin);
547     ok(!plibNewPosition, "plibNewPosition == NULL\n");
548 
549     return S_OK;
550 }
551 
552 static HRESULT WINAPI Stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
553 {
554     ok(0, "unexpected call\n");
555     return E_NOTIMPL;
556 }
557 
558 static HRESULT WINAPI Stream_CopyTo(IStream *iface, IStream *pstm,
559         ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
560 {
561     ok(0, "unexpected call\n");
562     return E_NOTIMPL;
563 }
564 
565 static HRESULT WINAPI Stream_Commit(IStream *iface, DWORD grfCommitFlags)
566 {
567     ok(0, "unexpected call\n");
568     return E_NOTIMPL;
569 }
570 
571 static HRESULT WINAPI Stream_Revert(IStream *iface)
572 {
573     ok(0, "unexpected call\n");
574     return E_NOTIMPL;
575 }
576 
577 static HRESULT WINAPI Stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
578         ULARGE_INTEGER cb, DWORD dwLockType)
579 {
580     ok(0, "unexpected call\n");
581     return E_NOTIMPL;
582 }
583 
584 static HRESULT WINAPI Stream_UnlockRegion(IStream *iface,
585         ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
586 {
587     ok(0, "unexpected call\n");
588     return E_NOTIMPL;
589 }
590 
591 static HRESULT WINAPI Stream_Stat(IStream *iface, STATSTG *pstatstg,
592         DWORD dwStatFlag)
593 {
594     ok(0, "unexpected call\n");
595     return E_NOTIMPL;
596 }
597 
598 static HRESULT WINAPI Stream_Clone(IStream *iface, IStream **ppstm)
599 {
600     ok(0, "unexpected call\n");
601     return E_NOTIMPL;
602 }
603 
604 static const IStreamVtbl StreamVtbl = {
605     Stream_QueryInterface,
606     Stream_AddRef,
607     Stream_Release,
608     Stream_Read,
609     Stream_Write,
610     Stream_Seek,
611     Stream_SetSize,
612     Stream_CopyTo,
613     Stream_Commit,
614     Stream_Revert,
615     Stream_LockRegion,
616     Stream_UnlockRegion,
617     Stream_Stat,
618     Stream_Clone
619 };
620 
621 static IStream Stream = { &StreamVtbl };
622 
623 static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv)
624 {
625     return QueryInterface(riid, ppv);
626 }
627 
628 static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface)
629 {
630     return 2;
631 }
632 
633 static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface)
634 {
635     return 1;
636 }
637 
638 static void call_continue(PROTOCOLDATA *protocol_data)
639 {
640     HRESULT hres;
641 
642     if (winetest_debug > 1)
643         trace("continue in state %d\n", state);
644 
645     if(state == STATE_CONNECTING) {
646         if(tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST || tested_protocol == FTP_TEST) {
647             if (http_is_first){
648                 CLEAR_CALLED(ReportProgress_FINDINGRESOURCE);
649                 CLEAR_CALLED(ReportProgress_PROXYDETECTING);
650             }
651             CLEAR_CALLED(ReportProgress_CONNECTING);
652         }
653         if(tested_protocol == FTP_TEST)
654             todo_wine CHECK_CALLED(ReportProgress_SENDINGREQUEST);
655         else if (tested_protocol != HTTPS_TEST)
656             CHECK_CALLED(ReportProgress_SENDINGREQUEST);
657         if(test_redirect && !(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS))
658             CHECK_CALLED(ReportProgress_REDIRECTING);
659         state = test_async_req ? STATE_SENDINGREQUEST : STATE_STARTDOWNLOADING;
660     }
661 
662     switch(state) {
663     case STATE_SENDINGREQUEST:
664         SET_EXPECT(Stream_Read);
665         SET_EXPECT(ReportProgress_SENDINGREQUEST);
666         break;
667     case STATE_STARTDOWNLOADING:
668         if((tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST)
669            && (!test_redirect || !(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS))) {
670             SET_EXPECT(OnResponse);
671             if(tested_protocol == HTTPS_TEST || test_redirect || test_abort || empty_file)
672                 SET_EXPECT(ReportProgress_ACCEPTRANGES);
673             SET_EXPECT(ReportProgress_ENCODING);
674             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
675             if(bindf & BINDF_NEEDFILE)
676                 SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
677         }
678     default:
679         break;
680     }
681 
682     if(state != STATE_SENDINGREQUEST && (!test_redirect || !(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS)))
683         SET_EXPECT(ReportData);
684     hres = IInternetProtocol_Continue(async_protocol, protocol_data);
685     ok(hres == S_OK, "Continue failed: %08x\n", hres);
686     if(tested_protocol == FTP_TEST || security_problem)
687         CLEAR_CALLED(ReportData);
688     else if(state != STATE_SENDINGREQUEST && (!test_redirect || !(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS)))
689         CHECK_CALLED(ReportData);
690 
691     switch(state) {
692     case STATE_SENDINGREQUEST:
693         CHECK_CALLED(Stream_Read);
694         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
695         state = STATE_STARTDOWNLOADING;
696         break;
697     case STATE_STARTDOWNLOADING:
698         if(!security_problem) {
699             state = STATE_DOWNLOADING;
700             if((tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST)
701                && (!test_redirect || !(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS))) {
702                 CHECK_CALLED(OnResponse);
703                 if(tested_protocol == HTTPS_TEST || empty_file)
704                     CHECK_CALLED(ReportProgress_ACCEPTRANGES);
705                 else if(test_redirect || test_abort)
706                     CLEAR_CALLED(ReportProgress_ACCEPTRANGES);
707                 CLEAR_CALLED(ReportProgress_ENCODING);
708                 CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
709                 if(bindf & BINDF_NEEDFILE)
710                     CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
711             }
712         }
713         else
714         {
715             security_problem = FALSE;
716             SET_EXPECT(ReportProgress_CONNECTING);
717         }
718     default:
719         break;
720     }
721 }
722 
723 static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData)
724 {
725     if(tested_protocol == FTP_TEST)
726         CHECK_EXPECT2(Switch);
727     else
728         CHECK_EXPECT(Switch);
729 
730     ok(pProtocolData != NULL, "pProtocolData == NULL\n");
731     if(binding_test) {
732         ok(pProtocolData != &protocoldata, "pProtocolData == &protocoldata\n");
733         ok(pProtocolData->grfFlags == protocoldata.grfFlags, "grfFlags wrong %x/%x\n",
734            pProtocolData->grfFlags, protocoldata.grfFlags );
735         ok(pProtocolData->dwState == protocoldata.dwState, "dwState wrong %x/%x\n",
736            pProtocolData->dwState, protocoldata.dwState );
737         ok(pProtocolData->pData == protocoldata.pData, "pData wrong %p/%p\n",
738            pProtocolData->pData, protocoldata.pData );
739         ok(pProtocolData->cbData == protocoldata.cbData, "cbData wrong %x/%x\n",
740            pProtocolData->cbData, protocoldata.cbData );
741     }
742 
743     pdata = pProtocolData;
744 
745     if(binding_test) {
746         SetEvent(event_complete);
747         ok( WaitForSingleObject(event_complete2, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
748         return S_OK;
749     }if(direct_read) {
750         continue_protdata = *pProtocolData;
751         SetEvent(event_continue);
752         ok( WaitForSingleObject(event_continue_done, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
753     }else {
754         call_continue(pProtocolData);
755         SetEvent(event_complete);
756     }
757 
758     return S_OK;
759 }
760 
761 static const char *status_names[] =
762 {
763     "0",
764     "FINDINGRESOURCE",
765     "CONNECTING",
766     "REDIRECTING",
767     "BEGINDOWNLOADDATA",
768     "DOWNLOADINGDATA",
769     "ENDDOWNLOADDATA",
770     "BEGINDOWNLOADCOMPONENTS",
771     "INSTALLINGCOMPONENTS",
772     "ENDDOWNLOADCOMPONENTS",
773     "USINGCACHEDCOPY",
774     "SENDINGREQUEST",
775     "CLASSIDAVAILABLE",
776     "MIMETYPEAVAILABLE",
777     "CACHEFILENAMEAVAILABLE",
778     "BEGINSYNCOPERATION",
779     "ENDSYNCOPERATION",
780     "BEGINUPLOADDATA",
781     "UPLOADINGDATA",
782     "ENDUPLOADINGDATA",
783     "PROTOCOLCLASSID",
784     "ENCODING",
785     "VERIFIEDMIMETYPEAVAILABLE",
786     "CLASSINSTALLLOCATION",
787     "DECODING",
788     "LOADINGMIMEHANDLER",
789     "CONTENTDISPOSITIONATTACH",
790     "FILTERREPORTMIMETYPE",
791     "CLSIDCANINSTANTIATE",
792     "IUNKNOWNAVAILABLE",
793     "DIRECTBIND",
794     "RAWMIMETYPE",
795     "PROXYDETECTING",
796     "ACCEPTRANGES",
797     "COOKIE_SENT",
798     "COMPACT_POLICY_RECEIVED",
799     "COOKIE_SUPPRESSED",
800     "COOKIE_STATE_UNKNOWN",
801     "COOKIE_STATE_ACCEPT",
802     "COOKIE_STATE_REJECT",
803     "COOKIE_STATE_PROMPT",
804     "COOKIE_STATE_LEASH",
805     "COOKIE_STATE_DOWNGRADE",
806     "POLICY_HREF",
807     "P3P_HEADER",
808     "SESSION_COOKIE_RECEIVED",
809     "PERSISTENT_COOKIE_RECEIVED",
810     "SESSION_COOKIES_ALLOWED",
811     "CACHECONTROL",
812     "CONTENTDISPOSITIONFILENAME",
813     "MIMETEXTPLAINMISMATCH",
814     "PUBLISHERAVAILABLE",
815     "DISPLAYNAMEAVAILABLE"
816 };
817 
818 static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode,
819         LPCWSTR szStatusText)
820 {
821     static const WCHAR null_guid[] = {'{','0','0','0','0','0','0','0','0','-','0','0','0','0','-',
822         '0','0','0','0','-','0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0','}',0};
823     static const WCHAR text_plain[] = {'t','e','x','t','/','p','l','a','i','n',0};
824 
825     if (winetest_debug > 1)
826     {
827         if (ulStatusCode < sizeof(status_names)/sizeof(status_names[0]))
828             trace( "progress: %s %s\n", status_names[ulStatusCode], wine_dbgstr_w(szStatusText) );
829         else
830             trace( "progress: %u %s\n", ulStatusCode, wine_dbgstr_w(szStatusText) );
831     }
832 
833     switch(ulStatusCode) {
834     case BINDSTATUS_MIMETYPEAVAILABLE:
835         CHECK_EXPECT2(ReportProgress_MIMETYPEAVAILABLE);
836         if(tested_protocol != FILE_TEST && tested_protocol != ITS_TEST && !mimefilter_test && (pi & PI_MIMEVERIFICATION)) {
837             if(!short_read || !direct_read)
838                 CHECK_CALLED(Read); /* set in Continue */
839             else if(short_read)
840                 CHECK_CALLED(Read2); /* set in Read */
841         }
842         ok(szStatusText != NULL, "szStatusText == NULL\n");
843         if(szStatusText) {
844             if(tested_protocol == BIND_TEST)
845                 ok(!lstrcmpW(szStatusText, expect_wsz), "unexpected szStatusText %s\n", wine_dbgstr_w(szStatusText));
846             else if (http_post_test)
847                 ok(lstrlenW(text_plain) <= lstrlenW(szStatusText) &&
848                    !memcmp(szStatusText, text_plain, lstrlenW(text_plain)*sizeof(WCHAR)),
849                    "szStatusText != text/plain\n");
850             else if(empty_file)
851                 ok(!strcmp_wa(szStatusText, "application/javascript"), "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
852             else if((pi & PI_MIMEVERIFICATION) && emulate_prot && !mimefilter_test
853                     && tested_protocol==HTTP_TEST && !short_read)
854                 ok(lstrlenW(gifW) <= lstrlenW(szStatusText) &&
855                    !memcmp(szStatusText, gifW, lstrlenW(gifW)*sizeof(WCHAR)),
856                    "szStatusText != image/gif\n");
857             else if(!mimefilter_test)
858                 ok(lstrlenW(text_htmlW) <= lstrlenW(szStatusText) &&
859                    !memcmp(szStatusText, text_htmlW, lstrlenW(text_htmlW)*sizeof(WCHAR)),
860                    "szStatusText != text/html\n");
861         }
862         break;
863     case BINDSTATUS_DIRECTBIND:
864         CHECK_EXPECT2(ReportProgress_DIRECTBIND);
865         ok(szStatusText == NULL, "szStatusText != NULL\n");
866         break;
867     case BINDSTATUS_RAWMIMETYPE:
868         CHECK_EXPECT2(ReportProgress_RAWMIMETYPE);
869         ok(szStatusText != NULL, "szStatusText == NULL\n");
870         if(szStatusText)
871             ok(lstrlenW(szStatusText) < lstrlenW(text_htmlW) ||
872                !memcmp(szStatusText, text_htmlW, lstrlenW(text_htmlW)*sizeof(WCHAR)),
873                "szStatusText != text/html\n");
874         break;
875     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
876         CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
877         ok(szStatusText != NULL, "szStatusText == NULL\n");
878         if(szStatusText) {
879             if(binding_test)
880                 ok(!lstrcmpW(szStatusText, expect_wsz), "unexpected szStatusText\n");
881             else if(tested_protocol == FILE_TEST)
882                 ok(!lstrcmpW(szStatusText, file_name), "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
883             else
884                 ok(szStatusText != NULL, "szStatusText == NULL\n");
885         }
886         break;
887     case BINDSTATUS_FINDINGRESOURCE:
888         CHECK_EXPECT2(ReportProgress_FINDINGRESOURCE);
889         ok(szStatusText != NULL, "szStatusText == NULL\n");
890         break;
891     case BINDSTATUS_CONNECTING:
892         CHECK_EXPECT2(ReportProgress_CONNECTING);
893         ok(szStatusText != NULL, "szStatusText == NULL\n");
894         break;
895     case BINDSTATUS_SENDINGREQUEST:
896         CHECK_EXPECT2(ReportProgress_SENDINGREQUEST);
897         if(tested_protocol == FILE_TEST || tested_protocol == ITS_TEST) {
898             ok(szStatusText != NULL, "szStatusText == NULL\n");
899             if(szStatusText)
900                 ok(!*szStatusText, "wrong szStatusText\n");
901         }
902         break;
903     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
904         CHECK_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
905         ok(szStatusText != NULL, "szStatusText == NULL\n");
906         if(szStatusText)
907             ok(!strcmp_wa(szStatusText, "text/html"), "szStatusText != text/html\n");
908         break;
909     case BINDSTATUS_PROTOCOLCLASSID:
910         CHECK_EXPECT(ReportProgress_PROTOCOLCLASSID);
911         ok(szStatusText != NULL, "szStatusText == NULL\n");
912         ok(!lstrcmpW(szStatusText, null_guid), "unexpected classid %s\n", wine_dbgstr_w(szStatusText));
913         break;
914     case BINDSTATUS_COOKIE_SENT:
915         CHECK_EXPECT2(ReportProgress_COOKIE_SENT);
916         ok(szStatusText == NULL, "szStatusText != NULL\n");
917         break;
918     case BINDSTATUS_REDIRECTING:
919         CHECK_EXPECT(ReportProgress_REDIRECTING);
920         if(test_redirect)
921             ok(!strcmp_wa(szStatusText, "http://test.winehq.org/tests/hello.html"), "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
922         else
923             ok(szStatusText == NULL, "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
924         break;
925     case BINDSTATUS_ENCODING:
926         CHECK_EXPECT(ReportProgress_ENCODING);
927         ok(!strcmp_wa(szStatusText, "gzip"), "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
928         break;
929     case BINDSTATUS_ACCEPTRANGES:
930         CHECK_EXPECT(ReportProgress_ACCEPTRANGES);
931         ok(!szStatusText, "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
932         break;
933     case BINDSTATUS_PROXYDETECTING:
934         if(!called_ReportProgress_PROXYDETECTING)
935             SET_EXPECT(ReportProgress_CONNECTING);
936         CHECK_EXPECT2(ReportProgress_PROXYDETECTING);
937         ok(!szStatusText, "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
938         break;
939     case BINDSTATUS_LOADINGMIMEHANDLER:
940         CHECK_EXPECT(ReportProgress_LOADINGMIMEHANDLER);
941         ok(!szStatusText, "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
942         break;
943     case BINDSTATUS_DECODING:
944         CHECK_EXPECT(ReportProgress_DECODING);
945         ok(!lstrcmpW(szStatusText, pjpegW), "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
946         break;
947     case BINDSTATUS_RESERVED_7:
948         trace("BINDSTATUS_RESERVED_7\n");
949         break;
950     case BINDSTATUS_RESERVED_8:
951         trace("BINDSTATUS_RESERVED_8\n");
952         break;
953     default:
954         ok(0, "Unexpected status %d (%d)\n", ulStatusCode, ulStatusCode-BINDSTATUS_LAST);
955     };
956 
957     return S_OK;
958 }
959 
960 static void test_http_info(IInternetProtocol *protocol)
961 {
962     IWinInetHttpInfo *info;
963     char buf[1024];
964     DWORD size, len;
965     HRESULT hres;
966 
967     static const WCHAR connectionW[] = {'c','o','n','n','e','c','t','i','o','n',0};
968 
969     hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&info);
970     ok(hres == S_OK, "Could not get IWinInterHttpInfo iface: %08x\n", hres);
971 
972     size = sizeof(buf);
973     strcpy(buf, "connection");
974     hres = IWinInetHttpInfo_QueryInfo(info, HTTP_QUERY_CUSTOM, buf, &size, NULL, NULL);
975     if(tested_protocol != FTP_TEST) {
976         ok(hres == S_OK, "QueryInfo failed: %08x\n", hres);
977 
978         ok(!strcmp(buf, "Keep-Alive"), "buf = %s\n", buf);
979         len = strlen(buf);
980         ok(size == len, "size = %u, expected %u\n", size, len);
981 
982         size = sizeof(buf);
983         memcpy(buf, connectionW, sizeof(connectionW));
984         hres = IWinInetHttpInfo_QueryInfo(info, HTTP_QUERY_CUSTOM, buf, &size, NULL, NULL);
985         ok(hres == S_FALSE, "QueryInfo returned %08x\n", hres);
986     }else {
987         ok(hres == S_FALSE, "QueryInfo failed: %08x\n", hres);
988     }
989 
990     IWinInetHttpInfo_Release(info);
991 }
992 
993 static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF,
994         ULONG ulProgress, ULONG ulProgressMax)
995 {
996     HRESULT hres;
997 
998     static int rec_depth;
999     rec_depth++;
1000 
1001     if(!mimefilter_test && (tested_protocol == FILE_TEST || tested_protocol == ITS_TEST)) {
1002         CHECK_EXPECT2(ReportData);
1003 
1004         ok(ulProgress == ulProgressMax, "ulProgress (%d) != ulProgressMax (%d)\n",
1005            ulProgress, ulProgressMax);
1006         if(!file_with_hash)
1007             ok(ulProgressMax == 13, "ulProgressMax=%d, expected 13\n", ulProgressMax);
1008         /* BSCF_SKIPDRAINDATAFORFILEURLS added in IE8 */
1009         if(tested_protocol == FILE_TEST)
1010             ok((grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION)) ||
1011                (grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_SKIPDRAINDATAFORFILEURLS)),
1012                "grcfBSCF = %08x\n", grfBSCF);
1013         else
1014             ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE), "grcfBSCF = %08x\n", grfBSCF);
1015     }else if(bind_from_cache) {
1016         CHECK_EXPECT(ReportData);
1017 
1018         ok(grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE), "grcfBSCF = %08x\n", grfBSCF);
1019         ok(ulProgress == 1000, "ulProgress = %u\n", ulProgress);
1020         ok(!ulProgressMax, "ulProgressMax = %u\n", ulProgressMax);
1021     }else if(direct_read) {
1022         BYTE buf[14096];
1023         ULONG read;
1024 
1025         if(!read_report_data && rec_depth == 1) {
1026             BOOL reported_all_data = called_ReportData2;
1027 
1028             CHECK_EXPECT2(ReportData);
1029 
1030             if(short_read) {
1031                 ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE)
1032                    || grfBSCF == BSCF_FIRSTDATANOTIFICATION, /* < IE8 */
1033                    "grcfBSCF = %08x\n", grfBSCF);
1034                 CHECK_CALLED(Read); /* Set in Continue */
1035                 first_data_notif = FALSE;
1036             }else if(first_data_notif) {
1037                 ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION, "grcfBSCF = %08x\n", grfBSCF);
1038                 first_data_notif = FALSE;
1039             }else if(reported_all_data) {
1040                 ok(grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION),
1041                    "grcfBSCF = %08x\n", grfBSCF);
1042             }else if(!direct_read) {
1043                 ok(grfBSCF == BSCF_INTERMEDIATEDATANOTIFICATION, "grcfBSCF = %08x\n", grfBSCF);
1044             }
1045 
1046             do {
1047                 read = 0;
1048                 if(emulate_prot)
1049                     SET_EXPECT(Read);
1050                 else
1051                     SET_EXPECT(ReportData2);
1052                 SET_EXPECT(ReportResult);
1053                 if(!emulate_prot)
1054                     SET_EXPECT(Switch);
1055                 hres = IInternetProtocol_Read(binding_test ? binding_protocol : async_protocol, expect_pv = buf, sizeof(buf), &read);
1056                 ok(hres == E_PENDING || hres == S_FALSE || hres == S_OK, "Read failed: %08x\n", hres);
1057                 if(hres == S_OK)
1058                     ok(read, "read == 0\n");
1059                 if(reported_all_data)
1060                     ok(hres == S_FALSE, "Read failed: %08x, expected S_FALSE\n", hres);
1061                 if(!emulate_prot && hres != E_PENDING)
1062                     CHECK_NOT_CALLED(Switch); /* otherwise checked in wait_for_switch loop */
1063                 if(emulate_prot)
1064                     CHECK_CALLED(Read);
1065                 if(!reported_all_data && called_ReportData2) {
1066                     if(!emulate_prot)
1067                         CHECK_CALLED(ReportData2);
1068                     CHECK_CALLED(ReportResult);
1069                     reported_all_data = TRUE;
1070                 }else {
1071                     if(!emulate_prot)
1072                         CHECK_NOT_CALLED(ReportData2);
1073                     CHECK_NOT_CALLED(ReportResult);
1074                 }
1075             }while(hres == S_OK);
1076             if(hres == S_FALSE)
1077                 wait_for_switch = FALSE;
1078         }else {
1079             CHECK_EXPECT(ReportData2);
1080 
1081             ok(grfBSCF & BSCF_LASTDATANOTIFICATION, "grfBSCF = %08x\n", grfBSCF);
1082 
1083             read = 0xdeadbeef;
1084             if(emulate_prot)
1085                 SET_EXPECT(Read2);
1086             hres = IInternetProtocol_Read(binding_test ? binding_protocol : async_protocol, expect_pv = buf, sizeof(buf), &read);
1087             if(emulate_prot)
1088                 CHECK_CALLED(Read2);
1089             ok(hres == S_FALSE, "Read returned: %08x, expected E_FALSE\n", hres);
1090             ok(!read, "read = %d\n", read);
1091         }
1092     }else if(!binding_test && (tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST
1093             || tested_protocol == FTP_TEST)) {
1094         if(empty_file)
1095             CHECK_EXPECT2(ReportData);
1096         else if(!(grfBSCF & BSCF_LASTDATANOTIFICATION) || (grfBSCF & BSCF_DATAFULLYAVAILABLE))
1097             CHECK_EXPECT(ReportData);
1098         else if (http_post_test)
1099             ok(ulProgress == 13, "Read %u bytes instead of 13\n", ulProgress);
1100 
1101         if(empty_file) {
1102             ok(!ulProgress, "ulProgress = %d\n", ulProgress);
1103             ok(!ulProgressMax, "ulProgressMax = %d\n", ulProgressMax);
1104         }else {
1105             ok(ulProgress, "ulProgress == 0\n");
1106         }
1107 
1108         if(empty_file) {
1109             ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION),
1110                "grcfBSCF = %08x\n", grfBSCF);
1111             first_data_notif = FALSE;
1112         }else if(first_data_notif) {
1113             ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION
1114                || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE),
1115                "grcfBSCF = %08x\n", grfBSCF);
1116             first_data_notif = FALSE;
1117         } else {
1118             ok(grfBSCF == BSCF_INTERMEDIATEDATANOTIFICATION
1119                || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION)
1120                || broken(grfBSCF == (BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION)),
1121                "grcfBSCF = %08x\n", grfBSCF);
1122         }
1123 
1124         if((grfBSCF & BSCF_FIRSTDATANOTIFICATION) && !binding_test)
1125             test_http_info(async_protocol);
1126 
1127         if(!(bindf & BINDF_FROMURLMON) &&
1128            !(grfBSCF & BSCF_LASTDATANOTIFICATION)) {
1129             if(state == STATE_CONNECTING) {
1130                 state = STATE_DOWNLOADING;
1131                 if(http_is_first) {
1132                     CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
1133                     CHECK_CALLED(ReportProgress_CONNECTING);
1134                 }
1135                 CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1136                 CHECK_CALLED(OnResponse);
1137                 CHECK_CALLED(ReportProgress_RAWMIMETYPE);
1138             }
1139             SetEvent(event_complete);
1140         }
1141     }else if(!read_report_data) {
1142         BYTE buf[1000];
1143         ULONG read;
1144         HRESULT hres;
1145 
1146         CHECK_EXPECT(ReportData);
1147 
1148         if(tested_protocol != BIND_TEST) {
1149             do {
1150                 if(mimefilter_test)
1151                     SET_EXPECT(MimeFilter_Read);
1152                 else if(rec_depth > 1)
1153                     SET_EXPECT(Read2);
1154                 else
1155                     SET_EXPECT(Read);
1156                 hres = IInternetProtocol_Read(binding_protocol, expect_pv=buf, sizeof(buf), &read);
1157                 if(mimefilter_test)
1158                     CHECK_CALLED(MimeFilter_Read);
1159                 else if(rec_depth > 1)
1160                     CHECK_CALLED(Read2);
1161                 else
1162                     CHECK_CALLED(Read);
1163             }while(hres == S_OK);
1164         }
1165     }
1166 
1167     rec_depth--;
1168     return S_OK;
1169 }
1170 
1171 static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult,
1172         DWORD dwError, LPCWSTR szResult)
1173 {
1174     CHECK_EXPECT(ReportResult);
1175 
1176     if(security_problem)
1177         return S_OK;
1178 
1179     if(tested_protocol == FTP_TEST)
1180         ok(hrResult == E_PENDING || hrResult == S_OK, "hrResult = %08x, expected E_PENDING or S_OK\n", hrResult);
1181     else
1182         ok(hrResult == expect_hrResult, "hrResult = %08x, expected: %08x\n",
1183            hrResult, expect_hrResult);
1184 #ifdef __REACTOS__
1185     if(!winetest_interactive && tested_protocol != FTP_TEST && hrResult != expect_hrResult) {
1186         skip("CORE-10360/ROSTESTS-192: Test might hang, skipping the rest!\n");
1187         exit(1);
1188     }
1189 #endif
1190     if(SUCCEEDED(hrResult) || tested_protocol == FTP_TEST || test_abort || hrResult == INET_E_REDIRECT_FAILED)
1191         ok(dwError == ERROR_SUCCESS, "dwError = %d, expected ERROR_SUCCESS\n", dwError);
1192     else
1193         ok(dwError != ERROR_SUCCESS ||
1194            broken(tested_protocol == MK_TEST), /* WinME and NT4 */
1195            "dwError == ERROR_SUCCESS\n");
1196 
1197     if(hrResult == INET_E_REDIRECT_FAILED)
1198         ok(!strcmp_wa(szResult, "http://test.winehq.org/tests/hello.html"), "szResult = %s\n", wine_dbgstr_w(szResult));
1199     else
1200         ok(!szResult, "szResult = %s\n", wine_dbgstr_w(szResult));
1201 
1202     if(direct_read)
1203         SET_EXPECT(ReportData); /* checked after main loop */
1204 
1205     return S_OK;
1206 }
1207 
1208 static IInternetProtocolSinkVtbl protocol_sink_vtbl = {
1209     ProtocolSink_QueryInterface,
1210     ProtocolSink_AddRef,
1211     ProtocolSink_Release,
1212     ProtocolSink_Switch,
1213     ProtocolSink_ReportProgress,
1214     ProtocolSink_ReportData,
1215     ProtocolSink_ReportResult
1216 };
1217 
1218 static IInternetProtocolSink protocol_sink = { &protocol_sink_vtbl };
1219 
1220 static HRESULT WINAPI MimeProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv)
1221 {
1222     if(IsEqualGUID(&IID_IUnknown, riid)
1223             || IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
1224         *ppv = iface;
1225         return S_OK;
1226     }
1227 
1228     ok(0, "unexpected call\n");
1229     return E_NOTIMPL;
1230 }
1231 
1232 static ULONG WINAPI MimeProtocolSink_AddRef(IInternetProtocolSink *iface)
1233 {
1234     return 2;
1235 }
1236 
1237 static ULONG WINAPI MimeProtocolSink_Release(IInternetProtocolSink *iface)
1238 {
1239     return 1;
1240 }
1241 
1242 static HRESULT WINAPI MimeProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData)
1243 {
1244     HRESULT hres;
1245 
1246     CHECK_EXPECT(MimeFilter_Switch);
1247 
1248     SET_EXPECT(Switch);
1249     hres = IInternetProtocolSink_Switch(filtered_sink, pProtocolData);
1250     ok(hres == S_OK, "Switch failed: %08x\n", hres);
1251     CHECK_CALLED(Switch);
1252 
1253     return S_OK;
1254 }
1255 
1256 static HRESULT WINAPI MimeProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode,
1257         LPCWSTR szStatusText)
1258 {
1259     switch(ulStatusCode) {
1260     case BINDSTATUS_LOADINGMIMEHANDLER:
1261         /*
1262          * IE9 for some reason (bug?) calls this on mime handler's protocol sink instead of the
1263          * main protocol sink. We check ReportProgress_LOADINGMIMEHANDLER both here and in
1264          * ProtocolSink_ReportProgress to workaround it.
1265          */
1266         CHECK_EXPECT(ReportProgress_LOADINGMIMEHANDLER);
1267         ok(!szStatusText, "szStatusText = %s\n", wine_dbgstr_w(szStatusText));
1268         break;
1269     default:
1270         ok(0, "Unexpected status code %d\n", ulStatusCode);
1271     }
1272 
1273     return S_OK;
1274 }
1275 
1276 static HRESULT WINAPI MimeProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF,
1277         ULONG ulProgress, ULONG ulProgressMax)
1278 {
1279     DWORD read = 0;
1280     BYTE buf[8192];
1281     HRESULT hres;
1282     BOOL report_mime = FALSE;
1283 
1284     CHECK_EXPECT(MimeFilter_ReportData);
1285 
1286     if(!filter_state && !no_mime) {
1287         SET_EXPECT(Read);
1288         hres = IInternetProtocol_Read(filtered_protocol, buf, sizeof(buf), &read);
1289         if(tested_protocol == HTTP_TEST)
1290             ok(hres == S_OK || hres == E_PENDING || hres == S_FALSE, "Read failed: %08x\n", hres);
1291         else
1292             ok(hres == S_OK, "Read failed: %08x\n", hres);
1293         CHECK_CALLED(Read);
1294 
1295         SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1296         hres = IInternetProtocolSink_ReportProgress(filtered_sink, BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, text_htmlW);
1297         ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
1298         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1299 
1300         SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1301         hres = IInternetProtocolSink_ReportProgress(filtered_sink, BINDSTATUS_MIMETYPEAVAILABLE, text_htmlW);
1302         ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
1303         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1304 
1305         /* FIXME: test BINDSTATUS_CACHEFILENAMEAVAILABLE */
1306     }
1307 
1308     if(no_mime && prot_read<200) {
1309         SET_EXPECT(Read);
1310     }else if(no_mime && prot_read<300) {
1311         report_mime = TRUE;
1312         SET_EXPECT(Read);
1313         SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1314         SET_EXPECT(ReportData);
1315     }else if(!read_report_data) {
1316         SET_EXPECT(ReportData);
1317     }
1318     hres = IInternetProtocolSink_ReportData(filtered_sink, grfBSCF, ulProgress, ulProgressMax);
1319     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
1320     if(no_mime && prot_read<=200) {
1321         CHECK_CALLED(Read);
1322     }else if(report_mime) {
1323         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1324         CHECK_CALLED(ReportData);
1325     }else if(!read_report_data) {
1326         CHECK_CALLED(ReportData);
1327     }
1328 
1329     if(!filter_state)
1330         filter_state = 1;
1331 
1332     return S_OK;
1333 }
1334 
1335 static HRESULT WINAPI MimeProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult,
1336         DWORD dwError, LPCWSTR szResult)
1337 {
1338     HRESULT hres;
1339 
1340     CHECK_EXPECT(MimeFilter_ReportResult);
1341 
1342     ok(hrResult == S_OK, "hrResult = %08x\n", hrResult);
1343     ok(dwError == ERROR_SUCCESS, "dwError = %u\n", dwError);
1344     ok(!szResult, "szResult = %s\n", wine_dbgstr_w(szResult));
1345 
1346     SET_EXPECT(ReportResult);
1347     hres = IInternetProtocolSink_ReportResult(filtered_sink, hrResult, dwError, szResult);
1348     ok(SUCCEEDED(hres), "ReportResult failed: %08x\n", hres);
1349     CHECK_CALLED(ReportResult);
1350 
1351     return S_OK;
1352 }
1353 
1354 static IInternetProtocolSinkVtbl mime_protocol_sink_vtbl = {
1355     MimeProtocolSink_QueryInterface,
1356     MimeProtocolSink_AddRef,
1357     MimeProtocolSink_Release,
1358     MimeProtocolSink_Switch,
1359     MimeProtocolSink_ReportProgress,
1360     MimeProtocolSink_ReportData,
1361     MimeProtocolSink_ReportResult
1362 };
1363 
1364 static IInternetProtocolSink mime_protocol_sink = { &mime_protocol_sink_vtbl };
1365 
1366 static HRESULT QueryInterface(REFIID riid, void **ppv)
1367 {
1368     static const IID IID_undocumented = {0x58DFC7D0,0x5381,0x43E5,{0x9D,0x72,0x4C,0xDD,0xE4,0xCB,0x0F,0x1A}};
1369     static const IID IID_undocumentedIE10 = {0xc28722e5,0xbc1a,0x4c55,{0xa6,0x8d,0x33,0x21,0x9f,0x69,0x89,0x10}};
1370 
1371     *ppv = NULL;
1372 
1373     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid))
1374         *ppv = &protocol_sink;
1375     if(IsEqualGUID(&IID_IServiceProvider, riid))
1376         *ppv = &service_provider;
1377     if(IsEqualGUID(&IID_IUriContainer, riid))
1378         return E_NOINTERFACE; /* TODO */
1379 
1380     /* NOTE: IE8 queries for undocumented {58DFC7D0-5381-43E5-9D72-4CDDE4CB0F1A} interface. */
1381     if(IsEqualGUID(&IID_undocumented, riid))
1382         return E_NOINTERFACE;
1383     /* NOTE: IE10 queries for undocumented {c28722e5-bc1a-4c55-a68d-33219f698910} interface. */
1384     if(IsEqualGUID(&IID_undocumentedIE10, riid))
1385         return E_NOINTERFACE;
1386 
1387     if(*ppv)
1388         return S_OK;
1389 
1390     ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
1391     return E_NOINTERFACE;
1392 }
1393 
1394 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
1395 {
1396     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo, riid)) {
1397         *ppv = iface;
1398         return S_OK;
1399     }
1400     return E_NOINTERFACE;
1401 }
1402 
1403 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
1404 {
1405     return 2;
1406 }
1407 
1408 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
1409 {
1410     return 1;
1411 }
1412 
1413 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
1414 {
1415     DWORD cbSize;
1416 
1417     CHECK_EXPECT(GetBindInfo);
1418 
1419     ok(grfBINDF != NULL, "grfBINDF == NULL\n");
1420     ok(pbindinfo != NULL, "pbindinfo == NULL\n");
1421     ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %d\n", pbindinfo->cbSize);
1422 
1423     *grfBINDF = bindf;
1424     if(binding_test)
1425         *grfBINDF |= BINDF_FROMURLMON;
1426     cbSize = pbindinfo->cbSize;
1427     memset(pbindinfo, 0, cbSize);
1428     pbindinfo->cbSize = cbSize;
1429     pbindinfo->dwOptions = bindinfo_options;
1430 
1431     if(http_post_test)
1432     {
1433         pbindinfo->cbstgmedData = sizeof(post_data)-1;
1434         pbindinfo->dwBindVerb = BINDVERB_POST;
1435         pbindinfo->stgmedData.tymed = http_post_test;
1436 
1437         if(http_post_test == TYMED_HGLOBAL) {
1438             HGLOBAL data;
1439 
1440             /* Must be GMEM_FIXED, GMEM_MOVABLE does not work properly */
1441             data = GlobalAlloc(GPTR, sizeof(post_data));
1442             memcpy(data, post_data, sizeof(post_data));
1443             U(pbindinfo->stgmedData).hGlobal = data;
1444         }else {
1445             U(pbindinfo->stgmedData).pstm = &Stream;
1446         }
1447     }
1448 
1449     return S_OK;
1450 }
1451 
1452 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType,
1453         LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1454 {
1455     ok(ppwzStr != NULL, "ppwzStr == NULL\n");
1456     ok(pcElFetched != NULL, "pcElFetched == NULL\n");
1457 
1458     switch(ulStringType) {
1459     case BINDSTRING_ACCEPT_MIMES:
1460         CHECK_EXPECT(GetBindString_ACCEPT_MIMES);
1461         ok(cEl == 256, "cEl=%d, expected 256\n", cEl);
1462         if(pcElFetched) {
1463             ok(*pcElFetched == 256, "*pcElFetched=%d, expected 256\n", *pcElFetched);
1464             *pcElFetched = 1;
1465         }
1466         if(ppwzStr) {
1467             *ppwzStr = CoTaskMemAlloc(sizeof(acc_mimeW));
1468             memcpy(*ppwzStr, acc_mimeW, sizeof(acc_mimeW));
1469         }
1470         return S_OK;
1471     case BINDSTRING_USER_AGENT:
1472         CHECK_EXPECT(GetBindString_USER_AGENT);
1473         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
1474         if(pcElFetched) {
1475             ok(*pcElFetched == 0, "*pcElFetch=%d, expected 0\n", *pcElFetched);
1476             *pcElFetched = 1;
1477         }
1478         if(ppwzStr) {
1479             *ppwzStr = CoTaskMemAlloc(sizeof(user_agentW));
1480             memcpy(*ppwzStr, user_agentW, sizeof(user_agentW));
1481         }
1482         return S_OK;
1483     case BINDSTRING_POST_COOKIE:
1484         CHECK_EXPECT(GetBindString_POST_COOKIE);
1485         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
1486         if(pcElFetched)
1487             ok(*pcElFetched == 0, "*pcElFetch=%d, expected 0\n", *pcElFetched);
1488         return S_OK;
1489     case BINDSTRING_URL: {
1490         DWORD size;
1491 
1492         CHECK_EXPECT(GetBindString_URL);
1493         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
1494         ok(*pcElFetched == 0, "*pcElFetch=%d, expected 0\n", *pcElFetched);
1495         *pcElFetched = 1;
1496 
1497         size = (lstrlenW(binding_urls[tested_protocol])+1)*sizeof(WCHAR);
1498         *ppwzStr = CoTaskMemAlloc(size);
1499         memcpy(*ppwzStr, binding_urls[tested_protocol], size);
1500         return S_OK;
1501     }
1502     case BINDSTRING_ROOTDOC_URL:
1503         CHECK_EXPECT(GetBindString_ROOTDOC_URL);
1504         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
1505         return E_NOTIMPL;
1506     case BINDSTRING_ENTERPRISE_ID:
1507         ok(cEl == 1, "cEl=%d, expected 1\n", cEl);
1508         return E_NOTIMPL;
1509     default:
1510         ok(0, "unexpected ulStringType %d\n", ulStringType);
1511     }
1512 
1513     return E_NOTIMPL;
1514 }
1515 
1516 static IInternetBindInfoVtbl bind_info_vtbl = {
1517     BindInfo_QueryInterface,
1518     BindInfo_AddRef,
1519     BindInfo_Release,
1520     BindInfo_GetBindInfo,
1521     BindInfo_GetBindString
1522 };
1523 
1524 static IInternetBindInfo bind_info = { &bind_info_vtbl };
1525 
1526 static Protocol *impl_from_IInternetPriority(IInternetPriority *iface)
1527 {
1528     return CONTAINING_RECORD(iface, Protocol, IInternetPriority_iface);
1529 }
1530 
1531 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
1532                                                   REFIID riid, void **ppv)
1533 {
1534     ok(0, "unexpected call\n");
1535     return E_NOINTERFACE;
1536 }
1537 
1538 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
1539 {
1540     Protocol *This = impl_from_IInternetPriority(iface);
1541     This->outer_ref++;
1542     return IUnknown_AddRef(This->outer);
1543 }
1544 
1545 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
1546 {
1547     Protocol *This = impl_from_IInternetPriority(iface);
1548     This->outer_ref--;
1549     return IUnknown_Release(This->outer);
1550 }
1551 
1552 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
1553 {
1554     CHECK_EXPECT(SetPriority);
1555     ok(nPriority == ex_priority, "nPriority=%d\n", nPriority);
1556     return S_OK;
1557 }
1558 
1559 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
1560 {
1561     ok(0, "unexpected call\n");
1562     return E_NOTIMPL;
1563 }
1564 
1565 
1566 static const IInternetPriorityVtbl InternetPriorityVtbl = {
1567     InternetPriority_QueryInterface,
1568     InternetPriority_AddRef,
1569     InternetPriority_Release,
1570     InternetPriority_SetPriority,
1571     InternetPriority_GetPriority
1572 };
1573 
1574 static ULONG WINAPI Protocol_AddRef(IInternetProtocolEx *iface)
1575 {
1576     return 2;
1577 }
1578 
1579 static ULONG WINAPI Protocol_Release(IInternetProtocolEx *iface)
1580 {
1581     return 1;
1582 }
1583 
1584 static HRESULT WINAPI Protocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
1585         DWORD dwOptions)
1586 {
1587     HRESULT hres;
1588 
1589     CHECK_EXPECT(Abort);
1590 
1591     SET_EXPECT(ReportResult);
1592     hres = IInternetProtocolSink_ReportResult(binding_sink, S_OK, ERROR_SUCCESS, NULL);
1593     ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
1594     CHECK_CALLED(ReportResult);
1595 
1596     return S_OK;
1597 }
1598 
1599 static HRESULT WINAPI Protocol_Suspend(IInternetProtocolEx *iface)
1600 {
1601     ok(0, "unexpected call\n");
1602     return E_NOTIMPL;
1603 }
1604 
1605 static HRESULT WINAPI Protocol_Resume(IInternetProtocolEx *iface)
1606 {
1607     ok(0, "unexpected call\n");
1608     return E_NOTIMPL;
1609 }
1610 
1611 static HRESULT WINAPI Protocol_Seek(IInternetProtocolEx *iface,
1612         LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
1613 {
1614     ok(0, "unexpected call\n");
1615     return E_NOTIMPL;
1616 }
1617 
1618 static Protocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
1619 {
1620     return CONTAINING_RECORD(iface, Protocol, IInternetProtocolEx_iface);
1621 }
1622 
1623 static HRESULT WINAPI ProtocolEmul_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
1624 {
1625     Protocol *This = impl_from_IInternetProtocolEx(iface);
1626 
1627     static const IID unknown_iid = {0x7daf9908,0x8415,0x4005,{0x95,0xae, 0xbd,0x27,0xf6,0xe3,0xdc,0x00}};
1628     static const IID unknown_iid2 = {0x5b7ebc0c,0xf630,0x4cea,{0x89,0xd3,0x5a,0xf0,0x38,0xed,0x05,0x5c}};
1629 
1630     /* FIXME: Why is it calling here instead of outer IUnknown? */
1631     if(IsEqualGUID(riid, &IID_IInternetPriority)) {
1632         *ppv = &This->IInternetPriority_iface;
1633         IInternetPriority_AddRef(&This->IInternetPriority_iface);
1634         return S_OK;
1635     }
1636     if(!IsEqualGUID(riid, &unknown_iid) && !IsEqualGUID(riid, &unknown_iid2)) /* IE10 */
1637         ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid));
1638     *ppv = NULL;
1639     return E_NOINTERFACE;
1640 }
1641 
1642 static ULONG WINAPI ProtocolEmul_AddRef(IInternetProtocolEx *iface)
1643 {
1644     Protocol *This = impl_from_IInternetProtocolEx(iface);
1645     This->outer_ref++;
1646     return IUnknown_AddRef(This->outer);
1647 }
1648 
1649 static ULONG WINAPI ProtocolEmul_Release(IInternetProtocolEx *iface)
1650 {
1651     Protocol *This = impl_from_IInternetProtocolEx(iface);
1652     This->outer_ref--;
1653     return IUnknown_Release(This->outer);
1654 }
1655 
1656 static DWORD WINAPI thread_proc(PVOID arg)
1657 {
1658     BOOL redirect = redirect_on_continue;
1659     HRESULT hres;
1660 
1661     memset(&protocoldata, -1, sizeof(protocoldata));
1662 
1663     while(1) {
1664         prot_state = 0;
1665 
1666         SET_EXPECT(ReportProgress_FINDINGRESOURCE);
1667         hres = IInternetProtocolSink_ReportProgress(binding_sink,
1668                 BINDSTATUS_FINDINGRESOURCE, hostW);
1669         CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
1670         ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
1671 
1672         SET_EXPECT(ReportProgress_CONNECTING);
1673         hres = IInternetProtocolSink_ReportProgress(binding_sink,
1674                 BINDSTATUS_CONNECTING, winehq_ipW);
1675         CHECK_CALLED(ReportProgress_CONNECTING);
1676         ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
1677 
1678         SET_EXPECT(ReportProgress_SENDINGREQUEST);
1679         hres = IInternetProtocolSink_ReportProgress(binding_sink,
1680                 BINDSTATUS_SENDINGREQUEST, NULL);
1681         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1682         ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
1683 
1684         prot_state = 1;
1685         SET_EXPECT(Switch);
1686         hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
1687         CHECK_CALLED(Switch);
1688         ok(hres == S_OK, "Switch failed: %08x\n", hres);
1689 
1690         if(!redirect)
1691             break;
1692         redirect = FALSE;
1693     }
1694 
1695     if(!short_read) {
1696         prot_state = 2;
1697         if(mimefilter_test)
1698             SET_EXPECT(MimeFilter_Switch);
1699         else
1700             SET_EXPECT(Switch);
1701         hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
1702         ok(hres == S_OK, "Switch failed: %08x\n", hres);
1703         if(mimefilter_test)
1704             CHECK_CALLED(MimeFilter_Switch);
1705         else
1706             CHECK_CALLED(Switch);
1707 
1708         if(test_abort) {
1709             SetEvent(event_complete);
1710             return 0;
1711         }
1712 
1713         prot_state = 2;
1714         if(mimefilter_test)
1715             SET_EXPECT(MimeFilter_Switch);
1716         else
1717             SET_EXPECT(Switch);
1718         hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
1719         ok(hres == S_OK, "Switch failed: %08x\n", hres);
1720         if(mimefilter_test)
1721             CHECK_CALLED(MimeFilter_Switch);
1722         else
1723             CHECK_CALLED(Switch);
1724 
1725         prot_state = 3;
1726         if(mimefilter_test)
1727             SET_EXPECT(MimeFilter_Switch);
1728         else
1729             SET_EXPECT(Switch);
1730         hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
1731         ok(hres == S_OK, "Switch failed: %08x\n", hres);
1732         if(mimefilter_test)
1733             CHECK_CALLED(MimeFilter_Switch);
1734         else
1735             CHECK_CALLED(Switch);
1736     }
1737 
1738     SetEvent(event_complete);
1739 
1740     return 0;
1741 }
1742 
1743 static void protocol_start(IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, DWORD pi)
1744 {
1745     BINDINFO bindinfo, exp_bindinfo;
1746     DWORD cbindf = 0;
1747     HRESULT hres;
1748 
1749     ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
1750     ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
1751     ok(pOIProtSink != &protocol_sink, "unexpected pOIProtSink\n");
1752     ok(pOIBindInfo != &bind_info, "unexpected pOIBindInfo\n");
1753     ok(!pi, "pi = %x\n", pi);
1754 
1755     if(binding_test)
1756         ok(pOIProtSink == binding_sink, "pOIProtSink != binding_sink\n");
1757 
1758     memset(&bindinfo, 0, sizeof(bindinfo));
1759     bindinfo.cbSize = sizeof(bindinfo);
1760     memcpy(&exp_bindinfo, &bindinfo, sizeof(bindinfo));
1761     if(test_redirect)
1762         exp_bindinfo.dwOptions = bindinfo_options;
1763     SET_EXPECT(GetBindInfo);
1764     if(redirect_on_continue && (bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS))
1765         SET_EXPECT(QueryService_IBindCallbackRedirect);
1766     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &cbindf, &bindinfo);
1767     if(redirect_on_continue && (bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS))
1768         CHECK_CALLED(QueryService_IBindCallbackRedirect);
1769     ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres);
1770     CHECK_CALLED(GetBindInfo);
1771     ok(cbindf == (bindf|BINDF_FROMURLMON), "bindf = %x, expected %x\n",
1772        cbindf, (bindf|BINDF_FROMURLMON));
1773     ok(!memcmp(&exp_bindinfo, &bindinfo, sizeof(bindinfo)), "unexpected bindinfo\n");
1774     pReleaseBindInfo(&bindinfo);
1775 
1776     SET_EXPECT(ReportProgress_SENDINGREQUEST);
1777     hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, emptyW);
1778     ok(hres == S_OK, "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
1779     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
1780 
1781     if(tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST) {
1782         IServiceProvider *service_provider;
1783         IHttpNegotiate *http_negotiate;
1784         IHttpNegotiate2 *http_negotiate2;
1785         LPWSTR ua = (LPWSTR)0xdeadbeef, accept_mimes[256];
1786         LPWSTR additional_headers = NULL;
1787         BYTE sec_id[100];
1788         DWORD fetched = 0, size = 100;
1789         DWORD tid;
1790 
1791         SET_EXPECT(GetBindString_USER_AGENT);
1792         hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_USER_AGENT,
1793                                                &ua, 1, &fetched);
1794         CHECK_CALLED(GetBindString_USER_AGENT);
1795         ok(hres == S_OK, "GetBindString(BINDSTRING_USER_AGETNT) failed: %08x\n", hres);
1796         ok(fetched == 1, "fetched = %d, expected 254\n", fetched);
1797         ok(ua != NULL, "ua =  %p\n", ua);
1798         ok(!lstrcmpW(ua, user_agentW), "unexpected user agent %s\n", wine_dbgstr_w(ua));
1799         CoTaskMemFree(ua);
1800 
1801         fetched = 256;
1802         SET_EXPECT(GetBindString_ACCEPT_MIMES);
1803         hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_ACCEPT_MIMES,
1804                                                accept_mimes, 256, &fetched);
1805         CHECK_CALLED(GetBindString_ACCEPT_MIMES);
1806 
1807         ok(hres == S_OK,
1808            "GetBindString(BINDSTRING_ACCEPT_MIMES) failed: %08x\n", hres);
1809         ok(fetched == 1, "fetched = %d, expected 1\n", fetched);
1810         ok(!lstrcmpW(acc_mimeW, accept_mimes[0]), "unexpected mimes %s\n", wine_dbgstr_w(accept_mimes[0]));
1811         CoTaskMemFree(accept_mimes[0]);
1812 
1813         hres = IInternetBindInfo_QueryInterface(pOIBindInfo, &IID_IServiceProvider,
1814                                                 (void**)&service_provider);
1815         ok(hres == S_OK, "QueryInterface failed: %08x\n", hres);
1816 
1817         SET_EXPECT(QueryService_HttpNegotiate);
1818         hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
1819                 &IID_IHttpNegotiate, (void**)&http_negotiate);
1820         CHECK_CALLED(QueryService_HttpNegotiate);
1821         ok(hres == S_OK, "QueryService failed: %08x\n", hres);
1822 
1823         SET_EXPECT(BeginningTransaction);
1824         hres = IHttpNegotiate_BeginningTransaction(http_negotiate, binding_urls[tested_protocol],
1825                                                    NULL, 0, &additional_headers);
1826         CHECK_CALLED(BeginningTransaction);
1827         IHttpNegotiate_Release(http_negotiate);
1828         ok(hres == S_OK, "BeginningTransction failed: %08x\n", hres);
1829         ok(additional_headers == NULL, "additional_headers=%p\n", additional_headers);
1830 
1831         SET_EXPECT(QueryService_HttpNegotiate);
1832         hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2,
1833                 &IID_IHttpNegotiate2, (void**)&http_negotiate2);
1834         CHECK_CALLED(QueryService_HttpNegotiate);
1835         ok(hres == S_OK, "QueryService failed: %08x\n", hres);
1836 
1837         size = 512;
1838         SET_EXPECT(GetRootSecurityId);
1839         hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, sec_id, &size, 0);
1840         CHECK_CALLED(GetRootSecurityId);
1841         IHttpNegotiate2_Release(http_negotiate2);
1842         ok(hres == E_FAIL, "GetRootSecurityId failed: %08x, expected E_FAIL\n", hres);
1843         ok(size == 13, "size=%d\n", size);
1844 
1845         IServiceProvider_Release(service_provider);
1846 
1847         if(!reuse_protocol_thread)
1848             CreateThread(NULL, 0, thread_proc, NULL, 0, &tid);
1849         return;
1850     }
1851 
1852     SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
1853     hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
1854             BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
1855     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
1856     CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
1857 
1858     if(mimefilter_test) {
1859         SET_EXPECT(MimeFilter_CreateInstance);
1860         SET_EXPECT(MimeFilter_Start);
1861         SET_EXPECT(ReportProgress_LOADINGMIMEHANDLER);
1862     }
1863     SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
1864     hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE,
1865             mimefilter_test ? pjpegW : (expect_wsz = text_htmlW));
1866     ok(hres == S_OK,
1867        "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres);
1868     if(mimefilter_test) {
1869         CHECK_CALLED(MimeFilter_CreateInstance);
1870         CHECK_CALLED(MimeFilter_Start);
1871         CHECK_CALLED(ReportProgress_LOADINGMIMEHANDLER);
1872         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1873     }else {
1874         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
1875     }
1876 
1877     if(mimefilter_test)
1878         SET_EXPECT(MimeFilter_ReportData);
1879     else
1880         SET_EXPECT(ReportData);
1881     hres = IInternetProtocolSink_ReportData(pOIProtSink,
1882             BSCF_FIRSTDATANOTIFICATION | (tested_protocol == ITS_TEST ? BSCF_DATAFULLYAVAILABLE : BSCF_LASTDATANOTIFICATION),
1883             13, 13);
1884     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
1885     if(mimefilter_test)
1886         CHECK_CALLED(MimeFilter_ReportData);
1887     else
1888         CHECK_CALLED(ReportData);
1889 
1890     if(tested_protocol == ITS_TEST) {
1891         SET_EXPECT(ReportData);
1892         hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_BEGINDOWNLOADDATA, NULL);
1893         ok(hres == S_OK, "ReportProgress(BINDSTATUS_BEGINDOWNLOADDATA) failed: %08x\n", hres);
1894         CHECK_CALLED(ReportData);
1895     }
1896 
1897     if(tested_protocol == BIND_TEST) {
1898         hres = IInternetProtocol_Terminate(binding_protocol, 0);
1899         ok(hres == E_FAIL, "Termiante failed: %08x\n", hres);
1900     }
1901 
1902     if(mimefilter_test)
1903         SET_EXPECT(MimeFilter_ReportResult);
1904     else
1905         SET_EXPECT(ReportResult);
1906     hres = IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
1907     ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
1908     if(mimefilter_test)
1909         CHECK_CALLED(MimeFilter_ReportResult);
1910     else
1911         CHECK_CALLED(ReportResult);
1912 }
1913 
1914 static HRESULT WINAPI ProtocolEmul_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
1915         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
1916         DWORD grfPI, HANDLE_PTR dwReserved)
1917 {
1918     CHECK_EXPECT(Start);
1919 
1920     ok(!dwReserved, "dwReserved = %lx\n", dwReserved);
1921     protocol_start(pOIProtSink, pOIBindInfo, grfPI);
1922     return S_OK;
1923 }
1924 
1925 static HRESULT WINAPI ProtocolEmul_Continue(IInternetProtocolEx *iface,
1926         PROTOCOLDATA *pProtocolData)
1927 {
1928     DWORD bscf = 0, pr;
1929     HRESULT hres;
1930 
1931     CHECK_EXPECT(Continue);
1932 
1933     ok(pProtocolData != NULL, "pProtocolData == NULL\n");
1934     if(!pProtocolData || tested_protocol == BIND_TEST)
1935         return S_OK;
1936     if(binding_test) {
1937         ok(pProtocolData != &protocoldata, "pProtocolData == &protocoldata\n");
1938         ok(pProtocolData->grfFlags == protocoldata.grfFlags, "grfFlags wrong %x/%x\n",
1939            pProtocolData->grfFlags, protocoldata.grfFlags );
1940         ok(pProtocolData->dwState == protocoldata.dwState, "dwState wrong %x/%x\n",
1941            pProtocolData->dwState, protocoldata.dwState );
1942         ok(pProtocolData->pData == protocoldata.pData, "pData wrong %p/%p\n",
1943            pProtocolData->pData, protocoldata.pData );
1944         ok(pProtocolData->cbData == protocoldata.cbData, "cbData wrong %x/%x\n",
1945            pProtocolData->cbData, protocoldata.cbData );
1946     }
1947 
1948     switch(prot_state) {
1949     case 1: {
1950         IServiceProvider *service_provider;
1951         IHttpNegotiate *http_negotiate;
1952         static const WCHAR header[] = {'?',0};
1953         static const WCHAR redirect_urlW[] = {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',
1954                                               '/','t','e','s','t','s','/','h','e','l','l','o','.','h','t','m','l',0};
1955 
1956         if(redirect_on_continue) {
1957             redirect_on_continue = FALSE;
1958             reuse_protocol_thread = TRUE;
1959 
1960             if(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS)
1961                 SET_EXPECT(Redirect);
1962             SET_EXPECT(ReportProgress_REDIRECTING);
1963             SET_EXPECT(Terminate);
1964             SET_EXPECT(Protocol_destructor);
1965             SET_EXPECT(QueryService_InternetProtocol);
1966             SET_EXPECT(CreateInstance);
1967             SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
1968             SET_EXPECT(SetPriority);
1969             SET_EXPECT(Start);
1970             hres = IInternetProtocolSink_ReportResult(binding_sink, INET_E_REDIRECT_FAILED, ERROR_SUCCESS, redirect_urlW);
1971             ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
1972             if(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS)
1973                 CHECK_CALLED(Redirect);
1974             CHECK_CALLED(ReportProgress_REDIRECTING);
1975             CHECK_CALLED(Terminate);
1976             CHECK_CALLED(Protocol_destructor);
1977             CHECK_CALLED(QueryService_InternetProtocol);
1978             CHECK_CALLED(CreateInstance);
1979             CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
1980             todo_wine CHECK_NOT_CALLED(SetPriority);
1981             CHECK_CALLED(Start);
1982 
1983             return S_OK;
1984         }
1985 
1986         hres = IInternetProtocolSink_QueryInterface(binding_sink, &IID_IServiceProvider,
1987                                                     (void**)&service_provider);
1988         ok(hres == S_OK, "Could not get IServiceProvicder\n");
1989 
1990         SET_EXPECT(QueryService_HttpNegotiate);
1991         hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
1992                                              &IID_IHttpNegotiate, (void**)&http_negotiate);
1993         IServiceProvider_Release(service_provider);
1994         CHECK_CALLED(QueryService_HttpNegotiate);
1995         ok(hres == S_OK, "Could not get IHttpNegotiate\n");
1996 
1997         SET_EXPECT(OnResponse);
1998         hres = IHttpNegotiate_OnResponse(http_negotiate, 200, header, NULL, NULL);
1999         IHttpNegotiate_Release(http_negotiate);
2000         CHECK_CALLED(OnResponse);
2001         IHttpNegotiate_Release(http_negotiate);
2002         ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
2003 
2004         if(mimefilter_test) {
2005             SET_EXPECT(MimeFilter_CreateInstance);
2006             SET_EXPECT(MimeFilter_Start);
2007             SET_EXPECT(ReportProgress_LOADINGMIMEHANDLER);
2008         }else if(!(pi & PI_MIMEVERIFICATION)) {
2009             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
2010         }
2011         hres = IInternetProtocolSink_ReportProgress(binding_sink,
2012                 BINDSTATUS_MIMETYPEAVAILABLE, mimefilter_test ? pjpegW : text_htmlW);
2013         if(mimefilter_test) {
2014             CHECK_CALLED(MimeFilter_CreateInstance);
2015             CHECK_CALLED(MimeFilter_Start);
2016             CHECK_CALLED(ReportProgress_LOADINGMIMEHANDLER);
2017         }else if(!(pi & PI_MIMEVERIFICATION)) {
2018             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
2019         }
2020         ok(hres == S_OK,
2021            "ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) failed: %08x\n", hres);
2022 
2023         bscf |= BSCF_FIRSTDATANOTIFICATION;
2024         break;
2025     }
2026     case 2:
2027     case 3:
2028         bscf = BSCF_INTERMEDIATEDATANOTIFICATION;
2029         break;
2030     }
2031 
2032     pr = prot_read;
2033     if(mimefilter_test)
2034         SET_EXPECT(MimeFilter_ReportData);
2035     if((!mimefilter_test || no_mime) && (pi & PI_MIMEVERIFICATION)) {
2036         if(pr < 200)
2037             SET_EXPECT(Read); /* checked in ReportData for short_read */
2038         if(pr == 200) {
2039             if(!mimefilter_test)
2040                 SET_EXPECT(Read); /* checked in BINDSTATUS_MIMETYPEAVAILABLE or ReportData */
2041             SET_EXPECT(GetBindInfo);
2042             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
2043         }
2044         if(pr >= 200)
2045             SET_EXPECT(ReportData);
2046     }else {
2047         SET_EXPECT(ReportData);
2048     }
2049 
2050     hres = IInternetProtocolSink_ReportData(binding_sink, bscf, pr, 400);
2051     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
2052 
2053     if(mimefilter_test) {
2054         SET_EXPECT(MimeFilter_ReportData);
2055     }else if(pi & PI_MIMEVERIFICATION) {
2056         if(!short_read && pr < 200)
2057             CHECK_CALLED(Read);
2058         if(pr == 200) {
2059             CLEAR_CALLED(GetBindInfo); /* IE9 */
2060             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
2061         }
2062     }else {
2063         CHECK_CALLED(ReportData);
2064     }
2065 
2066     if(prot_state == 3)
2067         prot_state = 4;
2068 
2069     return S_OK;
2070 }
2071 
2072 static HRESULT WINAPI ProtocolEmul_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
2073 {
2074     CHECK_EXPECT(Terminate);
2075     ok(!dwOptions, "dwOptions=%d\n", dwOptions);
2076     return S_OK;
2077 }
2078 
2079 static HRESULT WINAPI ProtocolEmul_Read(IInternetProtocolEx *iface, void *pv,
2080         ULONG cb, ULONG *pcbRead)
2081 {
2082     if(read_report_data)
2083         CHECK_EXPECT2(Read2);
2084 
2085     if(mimefilter_test || short_read) {
2086         if(!read_report_data)
2087             CHECK_EXPECT2(Read);
2088     }else if((pi & PI_MIMEVERIFICATION)) {
2089         if(!read_report_data)
2090             CHECK_EXPECT2(Read);
2091 
2092         if(prot_read < 300) {
2093             ok(pv != expect_pv, "pv == expect_pv\n");
2094             if(prot_read < 300)
2095                 ok(cb == 2048-prot_read, "cb=%d\n", cb);
2096             else
2097                 ok(cb == 700, "cb=%d\n", cb);
2098         }else {
2099             ok(expect_pv <= pv && (BYTE*)pv < (BYTE*)expect_pv + cb, "pv != expect_pv\n");
2100         }
2101     }else {
2102         if(!read_report_data)
2103             CHECK_EXPECT(Read);
2104 
2105         ok(pv == expect_pv, "pv != expect_pv\n");
2106         ok(cb == 1000, "cb=%d\n", cb);
2107         ok(!*pcbRead, "*pcbRead = %d\n", *pcbRead);
2108     }
2109     ok(pcbRead != NULL, "pcbRead == NULL\n");
2110 
2111     if(prot_state == 3 || (short_read && prot_state != 4)) {
2112         HRESULT hres;
2113 
2114         prot_state = 4;
2115         if(short_read) {
2116             SET_EXPECT(Read2); /* checked in BINDSTATUS_MIMETYPEAVAILABLE */
2117             SET_EXPECT(GetBindInfo);
2118             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
2119         }
2120         if(mimefilter_test)
2121             SET_EXPECT(MimeFilter_ReportData);
2122         else if(direct_read)
2123             SET_EXPECT(ReportData2);
2124         read_report_data++;
2125         hres = IInternetProtocolSink_ReportData(binding_sink,
2126                 BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION, 0, 0);
2127         read_report_data--;
2128         ok(hres == S_OK, "ReportData failed: %08x\n", hres);
2129         if(short_read) {
2130             CLEAR_CALLED(GetBindInfo); /* IE9 */
2131             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
2132         }
2133         if(mimefilter_test)
2134             CHECK_CALLED(MimeFilter_ReportData);
2135         else if(direct_read)
2136             CHECK_CALLED(ReportData2);
2137 
2138         if(mimefilter_test)
2139             SET_EXPECT(MimeFilter_ReportResult);
2140         else
2141             SET_EXPECT(ReportResult);
2142         hres = IInternetProtocolSink_ReportResult(binding_sink, S_OK, ERROR_SUCCESS, NULL);
2143         ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
2144         if(mimefilter_test)
2145             CHECK_CALLED(MimeFilter_ReportResult);
2146         else
2147             CHECK_CALLED(ReportResult);
2148 
2149         if(cb > 100)
2150             cb = 100;
2151         memset(pv, 'x', cb);
2152         if(cb>6)
2153             memcpy(pv, "gif87a", 6);
2154         prot_read += *pcbRead = cb;
2155         return S_OK;
2156     }
2157 
2158     if(prot_state == 4) {
2159         *pcbRead = 0;
2160         return S_FALSE;
2161     }
2162 
2163     if((async_read_pending = !async_read_pending)) {
2164         *pcbRead = 0;
2165         return tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST ? E_PENDING : S_FALSE;
2166     }
2167 
2168     if(cb > 100)
2169         cb = 100;
2170     memset(pv, 'x', cb);
2171     if(cb>6)
2172         memcpy(pv, "gif87a", 6);
2173     prot_read += *pcbRead = cb;
2174     return S_OK;
2175 }
2176 
2177 static HRESULT WINAPI ProtocolEmul_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
2178 {
2179     CHECK_EXPECT(LockRequest);
2180     ok(dwOptions == 0, "dwOptions=%x\n", dwOptions);
2181     return S_OK;
2182 }
2183 
2184 static HRESULT WINAPI ProtocolEmul_UnlockRequest(IInternetProtocolEx *iface)
2185 {
2186     CHECK_EXPECT(UnlockRequest);
2187     return S_OK;
2188 }
2189 
2190 static HRESULT WINAPI ProtocolEmul_StartEx(IInternetProtocolEx *iface, IUri *pUri,
2191         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
2192         DWORD grfPI, HANDLE *dwReserved)
2193 {
2194     CHECK_EXPECT(StartEx);
2195     ok(!dwReserved, "dwReserved = %p\n", dwReserved);
2196     protocol_start(pOIProtSink, pOIBindInfo, grfPI);
2197     return S_OK;
2198 }
2199 
2200 static const IInternetProtocolExVtbl ProtocolVtbl = {
2201     ProtocolEmul_QueryInterface,
2202     ProtocolEmul_AddRef,
2203     ProtocolEmul_Release,
2204     ProtocolEmul_Start,
2205     ProtocolEmul_Continue,
2206     Protocol_Abort,
2207     ProtocolEmul_Terminate,
2208     Protocol_Suspend,
2209     Protocol_Resume,
2210     ProtocolEmul_Read,
2211     Protocol_Seek,
2212     ProtocolEmul_LockRequest,
2213     ProtocolEmul_UnlockRequest,
2214     ProtocolEmul_StartEx
2215 };
2216 
2217 static Protocol *impl_from_IUnknown(IUnknown *iface)
2218 {
2219     return CONTAINING_RECORD(iface, Protocol, IUnknown_inner);
2220 }
2221 
2222 static HRESULT WINAPI ProtocolUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2223 {
2224     Protocol *This = impl_from_IUnknown(iface);
2225 
2226     if(IsEqualGUID(&IID_IUnknown, riid)) {
2227         trace("QI(IUnknown)\n");
2228         *ppv = &This->IUnknown_inner;
2229     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
2230         trace("QI(InternetProtocol)\n");
2231         *ppv = &This->IInternetProtocolEx_iface;
2232     }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
2233         trace("QI(InternetProtocolEx)\n");
2234         if(!impl_protex) {
2235             *ppv = NULL;
2236             return E_NOINTERFACE;
2237         }
2238         *ppv = &This->IInternetProtocolEx_iface;
2239     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
2240         trace("QI(InternetPriority)\n");
2241         *ppv = &This->IInternetPriority_iface;
2242     }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
2243         trace("QI(IWinInetInfo)\n");
2244         CHECK_EXPECT(QueryInterface_IWinInetInfo);
2245         *ppv = NULL;
2246         return E_NOINTERFACE;
2247     }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
2248         trace("QI(IWinInetHttpInfo)\n");
2249         CHECK_EXPECT(QueryInterface_IWinInetHttpInfo);
2250         *ppv = NULL;
2251         return E_NOINTERFACE;
2252     }else {
2253         ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
2254         *ppv = NULL;
2255         return E_NOINTERFACE;
2256     }
2257 
2258     IUnknown_AddRef((IUnknown*)*ppv);
2259     return S_OK;
2260 }
2261 
2262 static ULONG WINAPI ProtocolUnk_AddRef(IUnknown *iface)
2263 {
2264     Protocol *This = impl_from_IUnknown(iface);
2265     return ++This->inner_ref;
2266 }
2267 
2268 static ULONG WINAPI ProtocolUnk_Release(IUnknown *iface)
2269 {
2270     Protocol *This = impl_from_IUnknown(iface);
2271     LONG ref = --This->inner_ref;
2272     if(!ref) {
2273         /* IE9 is broken on redirects. It will cause -1 outer_ref on original protocol handler
2274          * and 1 on redirected handler. */
2275         ok(!This->outer_ref
2276            || broken(test_redirect && (This->outer_ref == -1 || This->outer_ref == 1)),
2277            "outer_ref = %d\n", This->outer_ref);
2278         if(This->outer_ref)
2279             trace("outer_ref %d\n", This->outer_ref);
2280         CHECK_EXPECT(Protocol_destructor);
2281         heap_free(This);
2282     }
2283     return ref;
2284 }
2285 
2286 static const IUnknownVtbl ProtocolUnkVtbl = {
2287     ProtocolUnk_QueryInterface,
2288     ProtocolUnk_AddRef,
2289     ProtocolUnk_Release
2290 };
2291 
2292 static HRESULT WINAPI MimeProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
2293 {
2294     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) {
2295         *ppv = iface;
2296         return S_OK;
2297     }
2298 
2299     if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
2300         *ppv = &mime_protocol_sink;
2301         return S_OK;
2302     }
2303 
2304     ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid));
2305     *ppv = NULL;
2306     return E_NOINTERFACE;
2307 }
2308 
2309 static HRESULT WINAPI MimeProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
2310         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
2311         DWORD grfPI, HANDLE_PTR dwReserved)
2312 {
2313     PROTOCOLFILTERDATA *data;
2314     LPOLESTR url_str = NULL;
2315     DWORD fetched = 0;
2316     BINDINFO bindinfo;
2317     DWORD cbindf = 0;
2318     HRESULT hres;
2319 
2320     CHECK_EXPECT(MimeFilter_Start);
2321 
2322     ok(!lstrcmpW(szUrl, pjpegW), "wrong url %s\n", wine_dbgstr_w(szUrl));
2323     ok(grfPI == (PI_FILTER_MODE|PI_FORCE_ASYNC), "grfPI=%x, expected PI_FILTER_MODE|PI_FORCE_ASYNC\n", grfPI);
2324     ok(dwReserved, "dwReserved == 0\n");
2325     ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
2326     ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
2327 
2328     if(binding_test) {
2329         ok(pOIProtSink != binding_sink, "pOIProtSink == protocol_sink\n");
2330         ok(pOIBindInfo == prot_bind_info, "pOIBindInfo != bind_info\n");
2331     }else {
2332         ok(pOIProtSink == &protocol_sink, "pOIProtSink != protocol_sink\n");
2333         ok(pOIBindInfo == &bind_info, "pOIBindInfo != bind_info\n");
2334     }
2335 
2336     data = (void*)dwReserved;
2337     ok(data->cbSize == sizeof(*data), "data->cbSize = %d\n", data->cbSize);
2338     ok(!data->pProtocolSink, "data->pProtocolSink != NULL\n");
2339     ok(data->pProtocol != NULL, "data->pProtocol == NULL\n");
2340     ok(!data->pUnk, "data->pUnk != NULL\n");
2341     ok(!data->dwFilterFlags, "data->dwProtocolFlags = %x\n", data->dwFilterFlags);
2342     if(binding_test) {
2343         IInternetProtocolSink *prot_sink;
2344 
2345         IInternetProtocol_QueryInterface(data->pProtocol, &IID_IInternetProtocolSink, (void**)&prot_sink);
2346         ok(prot_sink == pOIProtSink, "QI(data->pProtocol, IID_IInternetProtocolSink) != pOIProtSink\n");
2347         IInternetProtocolSink_Release(prot_sink);
2348 
2349         ok(data->pProtocol != binding_protocol, "data->pProtocol == binding_protocol\n");
2350 
2351         filtered_protocol = data->pProtocol;
2352         IInternetProtocol_AddRef(filtered_protocol);
2353     }else {
2354         IInternetProtocol *prot;
2355 
2356         IInternetProtocol_QueryInterface(data->pProtocol, &IID_IInternetProtocol, (void**)&prot);
2357         ok(prot == async_protocol, "QI(data->pProtocol, IID_IInternetProtocol) != async_protocol\n");
2358         IInternetProtocol_Release(prot);
2359 
2360         ok(data->pProtocol != async_protocol, "data->pProtocol == async_protocol\n");
2361     }
2362 
2363     filtered_sink = pOIProtSink;
2364 
2365     SET_EXPECT(ReportProgress_DECODING);
2366     hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DECODING, pjpegW);
2367     ok(hres == S_OK, "ReportProgress(BINDSTATUS_DECODING) failed: %08x\n", hres);
2368     CHECK_CALLED(ReportProgress_DECODING);
2369 
2370     SET_EXPECT(GetBindInfo);
2371     memset(&bindinfo, 0, sizeof(bindinfo));
2372     bindinfo.cbSize = sizeof(bindinfo);
2373     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &cbindf, &bindinfo);
2374     ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres);
2375     ok(cbindf == (bindf|BINDF_FROMURLMON), "cbindf = %x, expected %x\n", cbindf, bindf);
2376     CHECK_CALLED(GetBindInfo);
2377 
2378     SET_EXPECT(GetBindString_URL);
2379     hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_URL, &url_str, 1, &fetched);
2380     ok(hres == S_OK, "GetBindString(BINDSTRING_URL) failed: %08x\n", hres);
2381     ok(fetched == 1, "fetched = %d\n", fetched);
2382     ok(!lstrcmpW(url_str, binding_urls[tested_protocol]), "wrong url_str %s\n", wine_dbgstr_w(url_str));
2383     CoTaskMemFree(url_str);
2384     CHECK_CALLED(GetBindString_URL);
2385 
2386     return S_OK;
2387 }
2388 
2389 static HRESULT WINAPI Protocol_Continue(IInternetProtocolEx *iface,
2390         PROTOCOLDATA *pProtocolData)
2391 {
2392     CHECK_EXPECT(MimeFilter_Continue);
2393     return E_NOTIMPL;
2394 }
2395 
2396 static HRESULT WINAPI MimeProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
2397 {
2398     HRESULT hres;
2399 
2400     CHECK_EXPECT(MimeFilter_Terminate);
2401 
2402     ok(!dwOptions, "dwOptions = %x\n", dwOptions);
2403 
2404     SET_EXPECT(Terminate);
2405     hres = IInternetProtocol_Terminate(filtered_protocol, dwOptions);
2406     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
2407     CHECK_CALLED(Terminate);
2408 
2409     return S_OK;
2410 }
2411 
2412 static HRESULT WINAPI MimeProtocol_Read(IInternetProtocolEx *iface, void *pv,
2413         ULONG cb, ULONG *pcbRead)
2414 {
2415     BYTE buf[2096];
2416     DWORD read = 0;
2417     HRESULT hres;
2418 
2419     CHECK_EXPECT(MimeFilter_Read);
2420 
2421     ok(pv != NULL, "pv == NULL\n");
2422     ok(cb != 0, "cb == 0\n");
2423     ok(pcbRead != NULL, "pcbRead == NULL\n");
2424 
2425     if(read_report_data)
2426         SET_EXPECT(Read2);
2427     else
2428         SET_EXPECT(Read);
2429     hres = IInternetProtocol_Read(filtered_protocol, buf, sizeof(buf), &read);
2430     ok(hres == S_OK || hres == S_FALSE || hres == E_PENDING, "Read failed: %08x\n", hres);
2431     if(read_report_data)
2432         CHECK_CALLED(Read2);
2433     else
2434         CHECK_CALLED(Read);
2435 
2436     if(pcbRead) {
2437         ok(*pcbRead == 0, "*pcbRead=%d, expected 0\n", *pcbRead);
2438         *pcbRead = read;
2439     }
2440 
2441     memset(pv, 'x', read);
2442     return hres;
2443 }
2444 
2445 static HRESULT WINAPI MimeProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
2446 {
2447     HRESULT hres;
2448 
2449     CHECK_EXPECT(MimeFilter_LockRequest);
2450 
2451     ok(!dwOptions, "dwOptions = %x\n", dwOptions);
2452 
2453     SET_EXPECT(LockRequest);
2454     hres = IInternetProtocol_LockRequest(filtered_protocol, dwOptions);
2455     ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
2456     CHECK_CALLED(LockRequest);
2457 
2458     return S_OK;
2459 }
2460 
2461 static HRESULT WINAPI MimeProtocol_UnlockRequest(IInternetProtocolEx *iface)
2462 {
2463     HRESULT hres;
2464 
2465     CHECK_EXPECT(MimeFilter_UnlockRequest);
2466 
2467     SET_EXPECT(UnlockRequest);
2468     hres = IInternetProtocol_UnlockRequest(filtered_protocol);
2469     ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
2470     CHECK_CALLED(UnlockRequest);
2471 
2472     return S_OK;
2473 }
2474 
2475 static const IInternetProtocolExVtbl MimeProtocolVtbl = {
2476     MimeProtocol_QueryInterface,
2477     Protocol_AddRef,
2478     Protocol_Release,
2479     MimeProtocol_Start,
2480     Protocol_Continue,
2481     Protocol_Abort,
2482     MimeProtocol_Terminate,
2483     Protocol_Suspend,
2484     Protocol_Resume,
2485     MimeProtocol_Read,
2486     Protocol_Seek,
2487     MimeProtocol_LockRequest,
2488     MimeProtocol_UnlockRequest
2489 };
2490 
2491 static IInternetProtocolEx MimeProtocol = { &MimeProtocolVtbl };
2492 
2493 static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
2494 {
2495     ok(0, "unexpected call\n");
2496     return E_NOINTERFACE;
2497 }
2498 
2499 static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface)
2500 {
2501     return 2;
2502 }
2503 
2504 static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface)
2505 {
2506     return 1;
2507 }
2508 
2509 static HRESULT WINAPI InternetProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
2510         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
2511         DWORD *pcchResult, DWORD dwReserved)
2512 {
2513     ok(0, "unexpected call %d\n", ParseAction);
2514     return E_NOTIMPL;
2515 }
2516 
2517 static HRESULT WINAPI InternetProtocolInfo_CombineUrl(IInternetProtocolInfo *iface,
2518         LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags,
2519         LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
2520 {
2521     ok(0, "unexpected call\n");
2522     return E_NOTIMPL;
2523 }
2524 
2525 static HRESULT WINAPI InternetProtocolInfo_CompareUrl(IInternetProtocolInfo *iface,
2526         LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags)
2527 {
2528     ok(0, "unexpected call\n");
2529     return E_NOTIMPL;
2530 }
2531 
2532 static HRESULT WINAPI InternetProtocolInfo_QueryInfo(IInternetProtocolInfo *iface,
2533         LPCWSTR pwzUrl, QUERYOPTION OueryOption, DWORD dwQueryFlags, LPVOID pBuffer,
2534         DWORD cbBuffer, DWORD *pcbBuf, DWORD dwReserved)
2535 {
2536     ok(0, "unexpected call\n");
2537     return E_NOTIMPL;
2538 }
2539 
2540 static const IInternetProtocolInfoVtbl InternetProtocolInfoVtbl = {
2541     InternetProtocolInfo_QueryInterface,
2542     InternetProtocolInfo_AddRef,
2543     InternetProtocolInfo_Release,
2544     InternetProtocolInfo_ParseUrl,
2545     InternetProtocolInfo_CombineUrl,
2546     InternetProtocolInfo_CompareUrl,
2547     InternetProtocolInfo_QueryInfo
2548 };
2549 
2550 static IInternetProtocolInfo protocol_info = { &InternetProtocolInfoVtbl };
2551 
2552 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
2553 {
2554     if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
2555         *ppv = &protocol_info;
2556         return S_OK;
2557     }
2558 
2559     ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
2560     return E_NOINTERFACE;
2561 }
2562 
2563 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
2564 {
2565     return 2;
2566 }
2567 
2568 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
2569 {
2570     return 1;
2571 }
2572 
2573 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
2574                                         REFIID riid, void **ppv)
2575 {
2576     Protocol *ret;
2577 
2578     CHECK_EXPECT(CreateInstance);
2579 
2580     ok(pOuter == (IUnknown*)prot_bind_info, "pOuter != protocol_unk\n");
2581     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
2582     ok(ppv != NULL, "ppv == NULL\n");
2583 
2584     ret = heap_alloc(sizeof(*ret));
2585     ret->IUnknown_inner.lpVtbl = &ProtocolUnkVtbl;
2586     ret->IInternetProtocolEx_iface.lpVtbl = &ProtocolVtbl;
2587     ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
2588     ret->outer = pOuter;
2589     ret->inner_ref = 1;
2590     ret->outer_ref = 0;
2591 
2592     protocol_emul = ret;
2593     *ppv = &ret->IUnknown_inner;
2594     return S_OK;
2595 }
2596 
2597 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
2598 {
2599     ok(0, "unexpected call\n");
2600     return S_OK;
2601 }
2602 
2603 static const IClassFactoryVtbl ClassFactoryVtbl = {
2604     ClassFactory_QueryInterface,
2605     ClassFactory_AddRef,
2606     ClassFactory_Release,
2607     ClassFactory_CreateInstance,
2608     ClassFactory_LockServer
2609 };
2610 
2611 static IClassFactory ClassFactory = { &ClassFactoryVtbl };
2612 
2613 static HRESULT WINAPI MimeFilter_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
2614 {
2615     CHECK_EXPECT(MimeFilter_CreateInstance);
2616 
2617     ok(!outer, "outer = %p\n", outer);
2618     ok(IsEqualGUID(&IID_IInternetProtocol, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
2619 
2620     *ppv = &MimeProtocol;
2621     return S_OK;
2622 }
2623 
2624 static const IClassFactoryVtbl MimeFilterCFVtbl = {
2625     ClassFactory_QueryInterface,
2626     ClassFactory_AddRef,
2627     ClassFactory_Release,
2628     MimeFilter_CreateInstance,
2629     ClassFactory_LockServer
2630 };
2631 
2632 static IClassFactory mimefilter_cf = { &MimeFilterCFVtbl };
2633 
2634 #define TEST_BINDING     0x0001
2635 #define TEST_FILTER      0x0002
2636 #define TEST_FIRST_HTTP  0x0004
2637 #define TEST_DIRECT_READ 0x0008
2638 #define TEST_POST        0x0010
2639 #define TEST_EMULATEPROT 0x0020
2640 #define TEST_SHORT_READ  0x0040
2641 #define TEST_REDIRECT    0x0080
2642 #define TEST_ABORT       0x0100
2643 #define TEST_ASYNCREQ    0x0200
2644 #define TEST_USEIURI     0x0400
2645 #define TEST_IMPLPROTEX  0x0800
2646 #define TEST_EMPTY       0x1000
2647 #define TEST_NOMIME      0x2000
2648 #define TEST_FROMCACHE   0x4000
2649 #define TEST_DISABLEAUTOREDIRECT  0x8000
2650 
2651 static void register_filter(BOOL do_register)
2652 {
2653     IInternetSession *session;
2654     HRESULT hres;
2655 
2656     hres = pCoInternetGetSession(0, &session, 0);
2657     ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
2658 
2659     if(do_register) {
2660         hres = IInternetSession_RegisterMimeFilter(session, &mimefilter_cf, &IID_IInternetProtocol, pjpegW);
2661         ok(hres == S_OK, "RegisterMimeFilter failed: %08x\n", hres);
2662         hres = IInternetSession_RegisterMimeFilter(session, &mimefilter_cf, &IID_IInternetProtocol, gifW);
2663         ok(hres == S_OK, "RegisterMimeFilter failed: %08x\n", hres);
2664     }else {
2665         hres = IInternetSession_UnregisterMimeFilter(session, &mimefilter_cf, pjpegW);
2666         ok(hres == S_OK, "RegisterMimeFilter failed: %08x\n", hres);
2667         hres = IInternetSession_UnregisterMimeFilter(session, &mimefilter_cf, gifW);
2668         ok(hres == S_OK, "RegisterMimeFilter failed: %08x\n", hres);
2669     }
2670 
2671     IInternetSession_Release(session);
2672 }
2673 
2674 static void init_test(int prot, DWORD flags)
2675 {
2676     tested_protocol = prot;
2677     binding_test = (flags & TEST_BINDING) != 0;
2678     first_data_notif = TRUE;
2679     prot_read = 0;
2680     prot_state = 0;
2681     async_read_pending = TRUE;
2682     mimefilter_test = (flags & TEST_FILTER) != 0;
2683     no_mime = (flags & TEST_NOMIME) != 0;
2684     filter_state = 0;
2685     post_stream_read = 0;
2686     ResetEvent(event_complete);
2687     ResetEvent(event_complete2);
2688     ResetEvent(event_continue);
2689     ResetEvent(event_continue_done);
2690     async_protocol = binding_protocol = filtered_protocol = NULL;
2691     filtered_sink = NULL;
2692     http_is_first = (flags & TEST_FIRST_HTTP) != 0;
2693     first_data_notif = TRUE;
2694     state = STATE_CONNECTING;
2695     test_async_req = (flags & TEST_ASYNCREQ) != 0;
2696     direct_read = (flags & TEST_DIRECT_READ) != 0;
2697     emulate_prot = (flags & TEST_EMULATEPROT) != 0;
2698     wait_for_switch = TRUE;
2699     short_read = (flags & TEST_SHORT_READ) != 0;
2700     http_post_test = TYMED_NULL;
2701     redirect_on_continue = test_redirect = (flags & TEST_REDIRECT) != 0;
2702     test_abort = (flags & TEST_ABORT) != 0;
2703     impl_protex = (flags & TEST_IMPLPROTEX) != 0;
2704     empty_file = (flags & TEST_EMPTY) != 0;
2705     bind_from_cache = (flags & TEST_FROMCACHE) != 0;
2706     file_with_hash = FALSE;
2707     security_problem = FALSE;
2708     reuse_protocol_thread = FALSE;
2709 
2710     bindinfo_options = 0;
2711     if(flags & TEST_DISABLEAUTOREDIRECT)
2712         bindinfo_options |= BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS;
2713 
2714     register_filter(mimefilter_test);
2715 }
2716 
2717 static void test_priority(IInternetProtocol *protocol)
2718 {
2719     IInternetPriority *priority;
2720     LONG pr;
2721     HRESULT hres;
2722 
2723     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority,
2724                                             (void**)&priority);
2725     ok(hres == S_OK, "QueryInterface(IID_IInternetPriority) failed: %08x\n", hres);
2726     if(FAILED(hres))
2727         return;
2728 
2729     hres = IInternetPriority_GetPriority(priority, &pr);
2730     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
2731     ok(pr == 0, "pr=%d, expected 0\n", pr);
2732 
2733     hres = IInternetPriority_SetPriority(priority, 1);
2734     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
2735 
2736     hres = IInternetPriority_GetPriority(priority, &pr);
2737     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
2738     ok(pr == 1, "pr=%d, expected 1\n", pr);
2739 
2740     IInternetPriority_Release(priority);
2741 }
2742 
2743 static void test_early_abort(const CLSID *clsid)
2744 {
2745     IInternetProtocol *protocol;
2746     HRESULT hres;
2747 
2748     hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
2749             &IID_IInternetProtocol, (void**)&protocol);
2750     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
2751 
2752     hres = IInternetProtocol_Abort(protocol, E_ABORT, 0);
2753     ok(hres == S_OK, "Abort failed: %08x\n", hres);
2754 
2755     hres = IInternetProtocol_Abort(protocol, E_FAIL, 0);
2756     ok(hres == S_OK, "Abort failed: %08x\n", hres);
2757 
2758     IInternetProtocol_Release(protocol);
2759 }
2760 
2761 static BOOL file_protocol_start(IInternetProtocol *protocol, LPCWSTR url,
2762         IInternetProtocolEx *protocolex, IUri *uri, BOOL is_first)
2763 {
2764     HRESULT hres;
2765 
2766     SET_EXPECT(GetBindInfo);
2767     if(!(bindf & BINDF_FROMURLMON))
2768        SET_EXPECT(ReportProgress_DIRECTBIND);
2769     if(is_first) {
2770         SET_EXPECT(ReportProgress_SENDINGREQUEST);
2771         SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
2772         if(bindf & BINDF_FROMURLMON)
2773             SET_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
2774         else
2775             SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
2776     }
2777     SET_EXPECT(ReportData);
2778     if(is_first)
2779         SET_EXPECT(ReportResult);
2780 
2781     expect_hrResult = S_OK;
2782 
2783     if(protocolex) {
2784         hres = IInternetProtocolEx_StartEx(protocolex, uri, &protocol_sink, &bind_info, 0, 0);
2785         ok(hres == S_OK, "StartEx failed: %08x\n", hres);
2786     }else {
2787         hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0);
2788         if(hres == INET_E_RESOURCE_NOT_FOUND) {
2789             win_skip("Start failed\n");
2790             return FALSE;
2791         }
2792         ok(hres == S_OK, "Start failed: %08x\n", hres);
2793     }
2794 
2795     CHECK_CALLED(GetBindInfo);
2796     if(!(bindf & BINDF_FROMURLMON))
2797         CLEAR_CALLED(ReportProgress_DIRECTBIND); /* Not called by IE10 */
2798     if(is_first) {
2799         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
2800         CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
2801         if(bindf & BINDF_FROMURLMON)
2802             CHECK_CALLED(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
2803         else
2804             CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
2805     }
2806     CHECK_CALLED(ReportData);
2807     if(is_first)
2808         CHECK_CALLED(ReportResult);
2809 
2810     return TRUE;
2811 }
2812 
2813 static void test_file_protocol_url(LPCWSTR url)
2814 {
2815     IInternetProtocolInfo *protocol_info;
2816     IUnknown *unk;
2817     IClassFactory *factory;
2818     IInternetProtocol *protocol;
2819     BYTE buf[512];
2820     ULONG cb;
2821     HRESULT hres;
2822 
2823     hres = CoGetClassObject(&CLSID_FileProtocol, CLSCTX_INPROC_SERVER, NULL,
2824             &IID_IUnknown, (void**)&unk);
2825     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
2826     if(FAILED(hres))
2827         return;
2828 
2829     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
2830     ok(hres == E_NOINTERFACE,
2831             "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n", hres);
2832 
2833     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
2834     ok(hres == S_OK, "Could not get IClassFactory interface\n");
2835     IUnknown_Release(unk);
2836     if(FAILED(hres))
2837         return;
2838 
2839     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
2840     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
2841 
2842     if(SUCCEEDED(hres)) {
2843         if(file_protocol_start(protocol, url, NULL, NULL, TRUE)) {
2844             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
2845             ok(hres == S_OK, "Read failed: %08x\n", hres);
2846             ok(cb == 2, "cb=%u expected 2\n", cb);
2847             buf[2] = 0;
2848             ok(!memcmp(buf, file_with_hash ? "XX" : "<H", 2), "Unexpected data %s\n", buf);
2849             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
2850             ok(hres == S_FALSE, "Read failed: %08x\n", hres);
2851             hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb);
2852             ok(hres == S_FALSE, "Read failed: %08x expected S_FALSE\n", hres);
2853             ok(cb == 0, "cb=%u expected 0\n", cb);
2854             hres = IInternetProtocol_UnlockRequest(protocol);
2855             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
2856         }
2857 
2858         if(file_protocol_start(protocol, url, NULL, NULL, FALSE)) {
2859             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
2860             ok(hres == S_FALSE, "Read failed: %08x\n", hres);
2861             hres = IInternetProtocol_LockRequest(protocol, 0);
2862             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
2863             hres = IInternetProtocol_UnlockRequest(protocol);
2864             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
2865         }
2866 
2867         IInternetProtocol_Release(protocol);
2868     }
2869 
2870     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
2871     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
2872     if(SUCCEEDED(hres)) {
2873         if(file_protocol_start(protocol, url, NULL, NULL, TRUE)) {
2874             hres = IInternetProtocol_LockRequest(protocol, 0);
2875             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
2876             hres = IInternetProtocol_Terminate(protocol, 0);
2877             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
2878             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
2879             ok(hres == S_OK, "Read failed: %08x\n\n", hres);
2880             hres = IInternetProtocol_UnlockRequest(protocol);
2881             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
2882             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
2883             todo_wine_if(file_with_hash) /* FIXME: An effect of UnlockRequest call? */
2884                 ok(hres == S_OK, "Read failed: %08x\n", hres);
2885             hres = IInternetProtocol_Terminate(protocol, 0);
2886             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
2887         }
2888 
2889         IInternetProtocol_Release(protocol);
2890     }
2891 
2892     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol);
2893     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
2894     if(SUCCEEDED(hres)) {
2895         if(file_protocol_start(protocol, url, NULL, NULL, TRUE)) {
2896             hres = IInternetProtocol_Terminate(protocol, 0);
2897             ok(hres == S_OK, "Terminate failed: %08x\n", hres);
2898             hres = IInternetProtocol_Read(protocol, buf, 2, &cb);
2899             ok(hres == S_OK, "Read failed: %08x\n", hres);
2900             ok(cb == 2, "cb=%u expected 2\n", cb);
2901         }
2902 
2903         IInternetProtocol_Release(protocol);
2904     }
2905 
2906     if(pCreateUri) {
2907         IInternetProtocolEx *protocolex;
2908         IUri *uri;
2909 
2910         hres = pCreateUri(url, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
2911         ok(hres == S_OK, "CreateUri failed: %08x\n", hres);
2912 
2913         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocolEx, (void**)&protocolex);
2914         ok(hres == S_OK, "Could not get IInternetProtocolEx: %08x\n", hres);
2915 
2916         if(file_protocol_start(NULL, NULL, protocolex, uri, TRUE)) {
2917             hres = IInternetProtocolEx_Read(protocolex, buf, 2, &cb);
2918             ok(hres == S_OK, "Read failed: %08x\n", hres);
2919             hres = IInternetProtocolEx_LockRequest(protocolex, 0);
2920             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
2921             hres = IInternetProtocolEx_UnlockRequest(protocolex);
2922             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
2923         }
2924 
2925         IUri_Release(uri);
2926         IInternetProtocolEx_Release(protocolex);
2927 
2928         hres = pCreateUri(url, 0, 0, &uri);
2929         ok(hres == S_OK, "CreateUri failed: %08x\n", hres);
2930 
2931         hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocolEx, (void**)&protocolex);
2932         ok(hres == S_OK, "Could not get IInternetProtocolEx: %08x\n", hres);
2933 
2934         if(file_protocol_start(NULL, NULL, protocolex, uri, TRUE)) {
2935             hres = IInternetProtocolEx_Read(protocolex, buf, 2, &cb);
2936             ok(hres == S_OK, "Read failed: %08x\n", hres);
2937             hres = IInternetProtocolEx_LockRequest(protocolex, 0);
2938             ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
2939             hres = IInternetProtocolEx_UnlockRequest(protocolex);
2940             ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
2941         }
2942 
2943         IUri_Release(uri);
2944         IInternetProtocolEx_Release(protocolex);
2945     }else {
2946         win_skip("Skipping file protocol StartEx tests\n");
2947     }
2948 
2949     IClassFactory_Release(factory);
2950 }
2951 
2952 static void test_file_protocol_fail(void)
2953 {
2954     IInternetProtocol *protocol;
2955     HRESULT hres;
2956 
2957     static const WCHAR index_url2[] =
2958         {'f','i','l','e',':','/','/','i','n','d','e','x','.','h','t','m','l',0};
2959 
2960     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
2961             &IID_IInternetProtocol, (void**)&protocol);
2962     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
2963     if(FAILED(hres))
2964         return;
2965 
2966     SET_EXPECT(GetBindInfo);
2967     expect_hrResult = MK_E_SYNTAX;
2968     hres = IInternetProtocol_Start(protocol, wszIndexHtml, &protocol_sink, &bind_info, 0, 0);
2969     ok(hres == MK_E_SYNTAX ||
2970        hres == E_INVALIDARG,
2971        "Start failed: %08x, expected MK_E_SYNTAX or E_INVALIDARG\n", hres);
2972     CLEAR_CALLED(GetBindInfo); /* GetBindInfo not called in IE7 */
2973 
2974     SET_EXPECT(GetBindInfo);
2975     if(!(bindf & BINDF_FROMURLMON))
2976         SET_EXPECT(ReportProgress_DIRECTBIND);
2977     SET_EXPECT(ReportProgress_SENDINGREQUEST);
2978     SET_EXPECT(ReportResult);
2979     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
2980     hres = IInternetProtocol_Start(protocol, index_url, &protocol_sink, &bind_info, 0, 0);
2981     ok(hres == INET_E_RESOURCE_NOT_FOUND,
2982             "Start failed: %08x expected INET_E_RESOURCE_NOT_FOUND\n", hres);
2983     CHECK_CALLED(GetBindInfo);
2984     if(!(bindf & BINDF_FROMURLMON))
2985         CHECK_CALLED(ReportProgress_DIRECTBIND);
2986     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
2987     CHECK_CALLED(ReportResult);
2988 
2989     IInternetProtocol_Release(protocol);
2990 
2991     hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
2992             &IID_IInternetProtocol, (void**)&protocol);
2993     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
2994     if(FAILED(hres))
2995         return;
2996 
2997     SET_EXPECT(GetBindInfo);
2998     if(!(bindf & BINDF_FROMURLMON))
2999         SET_EXPECT(ReportProgress_DIRECTBIND);
3000     SET_EXPECT(ReportProgress_SENDINGREQUEST);
3001     SET_EXPECT(ReportResult);
3002     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
3003 
3004     hres = IInternetProtocol_Start(protocol, index_url2, &protocol_sink, &bind_info, 0, 0);
3005     ok(hres == INET_E_RESOURCE_NOT_FOUND,
3006             "Start failed: %08x, expected INET_E_RESOURCE_NOT_FOUND\n", hres);
3007     CHECK_CALLED(GetBindInfo);
3008     if(!(bindf & BINDF_FROMURLMON))
3009         CHECK_CALLED(ReportProgress_DIRECTBIND);
3010     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
3011     CHECK_CALLED(ReportResult);
3012 
3013     SET_EXPECT(GetBindInfo);
3014     hres = IInternetProtocol_Start(protocol, NULL, &protocol_sink, &bind_info, 0, 0);
3015     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
3016     CLEAR_CALLED(GetBindInfo); /* GetBindInfo not called in IE7 */
3017 
3018     SET_EXPECT(GetBindInfo);
3019     hres = IInternetProtocol_Start(protocol, emptyW, &protocol_sink, &bind_info, 0, 0);
3020     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
3021     CLEAR_CALLED(GetBindInfo); /* GetBindInfo not called in IE7 */
3022 
3023     IInternetProtocol_Release(protocol);
3024 }
3025 
3026 static void test_file_protocol(void) {
3027     WCHAR buf[INTERNET_MAX_URL_LENGTH], file_name_buf[MAX_PATH];
3028     DWORD size;
3029     ULONG len;
3030     HANDLE file;
3031 
3032     static const WCHAR wszFile[] = {'f','i','l','e',':',0};
3033     static const WCHAR wszFile2[] = {'f','i','l','e',':','/','/',0};
3034     static const WCHAR wszFile3[] = {'f','i','l','e',':','/','/','/',0};
3035     static const WCHAR wszFile4[] = {'f','i','l','e',':','\\','\\',0};
3036     static const char html_doc[] = "<HTML></HTML>";
3037     static const WCHAR fragmentW[] = {'#','f','r','a','g',0};
3038 
3039     trace("Testing file protocol...\n");
3040     init_test(FILE_TEST, 0);
3041 
3042     SetLastError(0xdeadbeef);
3043     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3044             FILE_ATTRIBUTE_NORMAL, NULL);
3045     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
3046     if(file == INVALID_HANDLE_VALUE)
3047         return;
3048     WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL);
3049     CloseHandle(file);
3050 
3051     file_name = wszIndexHtml;
3052     bindf = 0;
3053     test_file_protocol_url(index_url);
3054     bindf = BINDF_FROMURLMON;
3055     test_file_protocol_url(index_url);
3056     bindf = BINDF_FROMURLMON | BINDF_NEEDFILE;
3057     test_file_protocol_url(index_url);
3058 
3059     memcpy(buf, wszFile, sizeof(wszFile));
3060     len = sizeof(wszFile)/sizeof(WCHAR)-1;
3061     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
3062     buf[len++] = '\\';
3063     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
3064 
3065     file_name = buf + sizeof(wszFile)/sizeof(WCHAR)-1;
3066     bindf = 0;
3067     test_file_protocol_url(buf);
3068     bindf = BINDF_FROMURLMON;
3069     test_file_protocol_url(buf);
3070 
3071     memcpy(buf, wszFile2, sizeof(wszFile2));
3072     len = GetCurrentDirectoryW(sizeof(file_name_buf)/sizeof(WCHAR), file_name_buf);
3073     file_name_buf[len++] = '\\';
3074     memcpy(file_name_buf+len, wszIndexHtml, sizeof(wszIndexHtml));
3075     lstrcpyW(buf+sizeof(wszFile2)/sizeof(WCHAR)-1, file_name_buf);
3076     file_name = file_name_buf;
3077     bindf = 0;
3078     test_file_protocol_url(buf);
3079     bindf = BINDF_FROMURLMON;
3080     test_file_protocol_url(buf);
3081 
3082     buf[sizeof(wszFile2)/sizeof(WCHAR)] = '|';
3083     test_file_protocol_url(buf);
3084 
3085     memcpy(buf, wszFile3, sizeof(wszFile3));
3086     len = sizeof(wszFile3)/sizeof(WCHAR)-1;
3087     len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len);
3088     buf[len++] = '\\';
3089     memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml));
3090 
3091     file_name = buf + sizeof(wszFile3)/sizeof(WCHAR)-1;
3092     bindf = 0;
3093     test_file_protocol_url(buf);
3094     bindf = BINDF_FROMURLMON;
3095     test_file_protocol_url(buf);
3096 
3097     memcpy(buf, wszFile4, sizeof(wszFile4));
3098     len = GetCurrentDirectoryW(sizeof(file_name_buf)/sizeof(WCHAR), file_name_buf);
3099     file_name_buf[len++] = '\\';
3100     memcpy(file_name_buf+len, wszIndexHtml, sizeof(wszIndexHtml));
3101     lstrcpyW(buf+sizeof(wszFile4)/sizeof(WCHAR)-1, file_name_buf);
3102     file_name = file_name_buf;
3103     bindf = 0;
3104     test_file_protocol_url(buf);
3105     bindf = BINDF_FROMURLMON;
3106     test_file_protocol_url(buf);
3107 
3108     buf[sizeof(wszFile4)/sizeof(WCHAR)] = '|';
3109     test_file_protocol_url(buf);
3110 
3111     /* Fragment part of URL is skipped if the file doesn't exist. */
3112     lstrcatW(buf, fragmentW);
3113     test_file_protocol_url(buf);
3114 
3115     /* Fragment part is considered a part of the file name, if the file exsists. */
3116     len = lstrlenW(file_name_buf);
3117     lstrcpyW(file_name_buf+len, fragmentW);
3118     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3119             FILE_ATTRIBUTE_NORMAL, NULL);
3120     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
3121     WriteFile(file, "XXX", 3, &size, NULL);
3122     CloseHandle(file);
3123     file_name_buf[len] = 0;
3124 
3125     file_with_hash = TRUE;
3126     test_file_protocol_url(buf);
3127 
3128     DeleteFileW(wszIndexHtml);
3129     DeleteFileW(file_name_buf);
3130 
3131     bindf = 0;
3132     test_file_protocol_fail();
3133     bindf = BINDF_FROMURLMON;
3134     test_file_protocol_fail();
3135 }
3136 
3137 static void create_cache_entry(const WCHAR *urlw)
3138 {
3139     FILETIME now, tomorrow, yesterday;
3140     char file_path[MAX_PATH];
3141     BYTE content[1000];
3142     ULARGE_INTEGER li;
3143     const char *url;
3144     HANDLE file;
3145     DWORD size;
3146     unsigned i;
3147     BOOL res;
3148 
3149     BYTE cache_headers[] = "HTTP/1.1 200 OK\r\n\r\n";
3150 
3151     trace("Testing cache read...\n");
3152 
3153     url = w2a(urlw);
3154 
3155     for(i = 0; i < sizeof(content); i++)
3156         content[i] = '0' + (i%10);
3157 
3158     GetSystemTimeAsFileTime(&now);
3159     li.u.HighPart = now.dwHighDateTime;
3160     li.u.LowPart = now.dwLowDateTime;
3161     li.QuadPart += (LONGLONG)10000000 * 3600 * 24;
3162     tomorrow.dwHighDateTime = li.u.HighPart;
3163     tomorrow.dwLowDateTime = li.u.LowPart;
3164     li.QuadPart -= (LONGLONG)10000000 * 3600 * 24 * 2;
3165     yesterday.dwHighDateTime = li.u.HighPart;
3166     yesterday.dwLowDateTime = li.u.LowPart;
3167 
3168     res = CreateUrlCacheEntryA(url, sizeof(content), "", file_path, 0);
3169     ok(res, "CreateUrlCacheEntryA failed: %u\n", GetLastError());
3170 
3171     file = CreateFileA(file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3172     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
3173 
3174     WriteFile(file, content, sizeof(content), &size, NULL);
3175     CloseHandle(file);
3176 
3177     res = CommitUrlCacheEntryA(url, file_path, tomorrow, yesterday, NORMAL_CACHE_ENTRY,
3178                                cache_headers, sizeof(cache_headers)-1, "", 0);
3179     ok(res, "CommitUrlCacheEntryA failed: %u\n", GetLastError());
3180 }
3181 
3182 static BOOL http_protocol_start(LPCWSTR url, BOOL use_iuri)
3183 {
3184     static BOOL got_user_agent = FALSE;
3185     IUri *uri = NULL;
3186     HRESULT hres;
3187 
3188     if(use_iuri && pCreateUri) {
3189         hres = pCreateUri(url, 0, 0, &uri);
3190         ok(hres == S_OK, "CreateUri failed: %08x\n", hres);
3191     }
3192 
3193     SET_EXPECT(GetBindInfo);
3194     if (!(bindf & BINDF_FROMURLMON))
3195         SET_EXPECT(ReportProgress_DIRECTBIND);
3196     if(!got_user_agent)
3197         SET_EXPECT(GetBindString_USER_AGENT);
3198     SET_EXPECT(GetBindString_ROOTDOC_URL);
3199     SET_EXPECT(GetBindString_ACCEPT_MIMES);
3200     SET_EXPECT(QueryService_HttpNegotiate);
3201     SET_EXPECT(BeginningTransaction);
3202     SET_EXPECT(GetRootSecurityId);
3203     if(http_post_test) {
3204         SET_EXPECT(GetBindString_POST_COOKIE);
3205         if(http_post_test == TYMED_ISTREAM)
3206             SET_EXPECT(Stream_Seek);
3207     }
3208     if(bind_from_cache) {
3209         SET_EXPECT(OnResponse);
3210         SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
3211         SET_EXPECT(ReportData);
3212     }
3213 
3214     if(uri) {
3215         IInternetProtocolEx *protocolex;
3216 
3217         hres = IInternetProtocol_QueryInterface(async_protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
3218         ok(hres == S_OK, "Could not get IInternetProtocolEx iface: %08x\n", hres);
3219 
3220         hres = IInternetProtocolEx_StartEx(protocolex, uri, &protocol_sink, &bind_info, 0, 0);
3221         ok(hres == S_OK, "Start failed: %08x\n", hres);
3222 
3223         IInternetProtocolEx_Release(protocolex);
3224         IUri_Release(uri);
3225     }else {
3226         hres = IInternetProtocol_Start(async_protocol, url, &protocol_sink, &bind_info, 0, 0);
3227         ok(hres == S_OK, "Start failed: %08x\n", hres);
3228     }
3229     if(FAILED(hres))
3230         return FALSE;
3231 
3232     CHECK_CALLED(GetBindInfo);
3233     if (!(bindf & BINDF_FROMURLMON))
3234         CHECK_CALLED(ReportProgress_DIRECTBIND);
3235     if (!got_user_agent)
3236     {
3237         CHECK_CALLED(GetBindString_USER_AGENT);
3238         got_user_agent = TRUE;
3239     }
3240     CLEAR_CALLED(GetBindString_ROOTDOC_URL); /* New in IE11 */
3241     CHECK_CALLED(GetBindString_ACCEPT_MIMES);
3242     CHECK_CALLED(QueryService_HttpNegotiate);
3243     CHECK_CALLED(BeginningTransaction);
3244     /* GetRootSecurityId called on WinXP but not on Win98 */
3245     CLEAR_CALLED(GetRootSecurityId);
3246     if(http_post_test) {
3247         CHECK_CALLED(GetBindString_POST_COOKIE);
3248         if(http_post_test == TYMED_ISTREAM)
3249             CHECK_CALLED(Stream_Seek);
3250     }
3251     if(bind_from_cache) {
3252         CHECK_CALLED(OnResponse);
3253         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
3254         CHECK_CALLED(ReportData);
3255     }
3256 
3257     return TRUE;
3258 }
3259 
3260 static void test_protocol_terminate(IInternetProtocol *protocol)
3261 {
3262     BYTE buf[3600];
3263     DWORD cb;
3264     HRESULT hres;
3265 
3266     hres = IInternetProtocol_LockRequest(protocol, 0);
3267     ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
3268 
3269     hres = IInternetProtocol_Read(protocol, buf, 1, &cb);
3270     ok(hres == (test_abort ? S_OK : S_FALSE), "Read failed: %08x\n", hres);
3271 
3272     hres = IInternetProtocol_Terminate(protocol, 0);
3273     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
3274 
3275     /* This wait is to give the internet handles being freed in Terminate
3276      * enough time to actually terminate in all cases. Internet handles
3277      * terminate asynchronously and native reuses the main InternetOpen
3278      * handle. The only case in which this seems to be necessary is on
3279      * wine with native wininet and urlmon, resulting in the next time
3280      * test_http_protocol_url being called the first data notification actually
3281      * being an extra last data notification from the previous connection
3282      * about once out of every ten times. */
3283     Sleep(100);
3284 
3285     hres = IInternetProtocol_UnlockRequest(protocol);
3286     ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
3287 }
3288 
3289 /* is_first refers to whether this is the first call to this function
3290  * _for this url_ */
3291 static void test_http_protocol_url(LPCWSTR url, int prot, DWORD flags, DWORD tymed)
3292 {
3293     IInternetProtocolInfo *protocol_info;
3294     IClassFactory *factory;
3295     IUnknown *unk;
3296     HRESULT hres;
3297 
3298     init_test(prot, flags);
3299     http_url = url;
3300     http_post_test = tymed;
3301     if(flags & TEST_FROMCACHE)
3302         create_cache_entry(url);
3303 
3304     hres = CoGetClassObject(prot == HTTPS_TEST ? &CLSID_HttpSProtocol : &CLSID_HttpProtocol,
3305             CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
3306     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
3307     if(FAILED(hres))
3308         return;
3309 
3310     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
3311     ok(hres == E_NOINTERFACE,
3312         "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n",
3313         hres);
3314 
3315     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
3316     ok(hres == S_OK, "Could not get IClassFactory interface\n");
3317     IUnknown_Release(unk);
3318     if(FAILED(hres))
3319         return;
3320 
3321     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
3322                                         (void**)&async_protocol);
3323     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
3324     if(SUCCEEDED(hres)) {
3325         BYTE buf[3600];
3326         DWORD cb;
3327         ULONG ref;
3328 
3329         test_priority(async_protocol);
3330 
3331         SET_EXPECT(ReportProgress_COOKIE_SENT);
3332         if(http_is_first) {
3333             SET_EXPECT(ReportProgress_FINDINGRESOURCE);
3334             SET_EXPECT(ReportProgress_CONNECTING);
3335         }
3336         SET_EXPECT(ReportProgress_SENDINGREQUEST);
3337         if(test_redirect && !(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS))
3338             SET_EXPECT(ReportProgress_REDIRECTING);
3339         SET_EXPECT(ReportProgress_PROXYDETECTING);
3340         if(prot == HTTP_TEST)
3341             SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
3342         else
3343             SET_EXPECT(QueryService_HttpSecurity);
3344         if(!(bindf & BINDF_FROMURLMON)) {
3345             SET_EXPECT(OnResponse);
3346             SET_EXPECT(ReportProgress_RAWMIMETYPE);
3347             SET_EXPECT(ReportData);
3348         } else {
3349             SET_EXPECT(Switch);
3350         }
3351 
3352         if(!http_protocol_start(url, (flags & TEST_USEIURI) != 0)) {
3353             IInternetProtocol_Abort(async_protocol, E_ABORT, 0);
3354             IInternetProtocol_Release(async_protocol);
3355             return;
3356         }
3357 
3358         if(!direct_read && !test_abort && !bind_from_cache)
3359             SET_EXPECT(ReportResult);
3360 
3361         if(flags & TEST_DISABLEAUTOREDIRECT)
3362             expect_hrResult = INET_E_REDIRECT_FAILED;
3363         else if(test_abort)
3364             expect_hrResult = E_ABORT;
3365         else
3366             expect_hrResult = S_OK;
3367 
3368         if(direct_read) {
3369             SET_EXPECT(Switch);
3370             while(wait_for_switch) {
3371                 ok( WaitForSingleObject(event_continue, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
3372                 CHECK_CALLED(Switch); /* Set in ReportData */
3373                 call_continue(&continue_protdata);
3374                 SetEvent(event_continue_done);
3375             }
3376         }else if(bind_from_cache) {
3377             BYTE buf[1500];
3378 
3379             hres = IInternetProtocol_Read(async_protocol, buf, 100, &cb);
3380             ok(hres == S_OK && cb == 100, "Read failed: %08x (%d bytes)\n", hres, cb);
3381 
3382             SET_EXPECT(ReportResult);
3383             hres = IInternetProtocol_Read(async_protocol, buf, sizeof(buf), &cb);
3384             ok(hres == S_OK && cb == 900, "Read failed: %08x (%d bytes)\n", hres, cb);
3385             CHECK_CALLED(ReportResult);
3386 
3387             hres = IInternetProtocol_Read(async_protocol, buf, sizeof(buf), &cb);
3388             ok(hres == S_FALSE && !cb, "Read failed: %08x (%d bytes)\n", hres, cb);
3389         }else {
3390             hres = IInternetProtocol_Read(async_protocol, buf, 1, &cb);
3391             ok((hres == E_PENDING && cb==0) ||
3392                (hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb);
3393 
3394             ok( WaitForSingleObject(event_complete, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
3395             if(bindf & BINDF_FROMURLMON)
3396                 CHECK_CALLED(Switch);
3397             else
3398                 CHECK_CALLED(ReportData);
3399             if(prot == HTTPS_TEST)
3400                 CLEAR_CALLED(QueryService_HttpSecurity);
3401 
3402             while(1) {
3403                 if(bindf & BINDF_FROMURLMON)
3404                     SET_EXPECT(Switch);
3405                 else
3406                     SET_EXPECT(ReportData);
3407                 hres = IInternetProtocol_Read(async_protocol, buf, sizeof(buf), &cb);
3408                 if(hres == E_PENDING) {
3409                     hres = IInternetProtocol_Read(async_protocol, buf, 1, &cb);
3410                     ok((hres == E_PENDING && cb==0) ||
3411                        (hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb);
3412                     ok( WaitForSingleObject(event_complete, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
3413                     if(bindf & BINDF_FROMURLMON)
3414                         CHECK_CALLED(Switch);
3415                     else
3416                         CHECK_CALLED(ReportData);
3417 
3418                     if(test_abort) {
3419                         HRESULT hres;
3420 
3421                         SET_EXPECT(ReportResult);
3422                         hres = IInternetProtocol_Abort(async_protocol, E_ABORT, 0);
3423                         ok(hres == S_OK, "Abort failed: %08x\n", hres);
3424                         CHECK_CALLED(ReportResult);
3425 
3426                         hres = IInternetProtocol_Abort(async_protocol, E_ABORT, 0);
3427                         ok(hres == INET_E_RESULT_DISPATCHED || hres == S_OK /* IE10 */, "Abort failed: %08x\n", hres);
3428                         break;
3429                     }
3430                 }else {
3431                     if(bindf & BINDF_FROMURLMON)
3432                         CHECK_NOT_CALLED(Switch);
3433                     else
3434                         CHECK_NOT_CALLED(ReportData);
3435                     if(cb == 0) break;
3436                 }
3437             }
3438             if(!test_abort) {
3439                 ok(hres == S_FALSE, "Read failed: %08x\n", hres);
3440                 CHECK_CALLED(ReportResult);
3441             }
3442         }
3443         if(prot == HTTPS_TEST)
3444             CLEAR_CALLED(ReportProgress_SENDINGREQUEST);
3445 
3446         if (prot == HTTP_TEST || prot == HTTPS_TEST)
3447             CLEAR_CALLED(ReportProgress_COOKIE_SENT);
3448 
3449         hres = IInternetProtocol_Abort(async_protocol, E_ABORT, 0);
3450         ok(hres == INET_E_RESULT_DISPATCHED || hres == S_OK /* IE10 */, "Abort failed: %08x\n", hres);
3451 
3452         test_protocol_terminate(async_protocol);
3453 
3454         hres = IInternetProtocol_Abort(async_protocol, E_ABORT, 0);
3455         ok(hres == S_OK, "Abort failed: %08x\n", hres);
3456 
3457         ref = IInternetProtocol_Release(async_protocol);
3458         ok(!ref, "ref=%x\n", ref);
3459     }
3460 
3461     IClassFactory_Release(factory);
3462 
3463     if(flags & TEST_FROMCACHE) {
3464         BOOL res;
3465 
3466         res = DeleteUrlCacheEntryW(url);
3467         ok(res, "DeleteUrlCacheEntryA failed: %u\n", GetLastError());
3468     }
3469 }
3470 
3471 static void test_http_protocol(void)
3472 {
3473     static const WCHAR posttest_url[] =
3474         {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g','/',
3475          't','e','s','t','s','/','p','o','s','t','.','p','h','p',0};
3476     static const WCHAR redirect_url[] =
3477         {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g','/',
3478          't','e','s','t','s','/','r','e','d','i','r','e','c','t',0};
3479     static const WCHAR winetest_url[] =
3480         {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g','/',
3481          't','e','s','t','s','/','d','a','t','a','.','p','h','p',0};
3482     static const WCHAR empty_url[] =
3483         {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g','/',
3484          't','e','s','t','s','/','e','m','p','t','y','.','j','s',0};
3485     static const WCHAR cache_only_url[] =
3486         {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g','/',
3487          't','e','s','t','s','/','c','a','c','h','e','-','o','n','l','y',0};
3488 
3489 
3490     trace("Testing http protocol (not from urlmon)...\n");
3491     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
3492     test_http_protocol_url(winetest_url, HTTP_TEST, TEST_FIRST_HTTP, TYMED_NULL);
3493 
3494     trace("Testing http protocol (from urlmon)...\n");
3495     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
3496     test_http_protocol_url(winetest_url, HTTP_TEST, 0, TYMED_NULL);
3497 
3498     trace("Testing http protocol (to file)...\n");
3499     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NEEDFILE;
3500     test_http_protocol_url(winetest_url, HTTP_TEST, 0, TYMED_NULL);
3501 
3502     trace("Testing http protocol (post data)...\n");
3503     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
3504     test_http_protocol_url(posttest_url, HTTP_TEST, TEST_FIRST_HTTP|TEST_POST, TYMED_HGLOBAL);
3505 
3506     trace("Testing http protocol (post data stream)...\n");
3507     test_http_protocol_url(posttest_url, HTTP_TEST, TEST_FIRST_HTTP|TEST_POST|TEST_ASYNCREQ, TYMED_ISTREAM);
3508 
3509     trace("Testing http protocol (direct read)...\n");
3510     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
3511     test_http_protocol_url(winetest_url, HTTP_TEST, TEST_DIRECT_READ|TEST_USEIURI, TYMED_NULL);
3512 
3513     trace("Testing http protocol (redirected)...\n");
3514     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE;
3515     test_http_protocol_url(redirect_url, HTTP_TEST, TEST_REDIRECT, TYMED_NULL);
3516 
3517     trace("Testing http protocol (redirected, disable auto redirect)...\n");
3518     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE;
3519     test_http_protocol_url(redirect_url, HTTP_TEST, TEST_REDIRECT | TEST_DISABLEAUTOREDIRECT, TYMED_NULL);
3520 
3521     trace("Testing http protocol empty file...\n");
3522     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE;
3523     test_http_protocol_url(empty_url, HTTP_TEST, TEST_EMPTY, TYMED_NULL);
3524 
3525     /* This is a bit ugly. We unconditionally disable this test on Wine. This won't work until we have
3526      * support for reading from cache via HTTP layer in wininet. Until then, Wine will fail badly, affecting
3527      * other, unrelated, tests. Working around it is not worth the trouble, we may simply make sure those
3528      * tests work on Windows and have them around for the future.
3529      */
3530     if(broken(1)) {
3531     trace("Testing http protocol (from cache)...\n");
3532     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
3533     test_http_protocol_url(cache_only_url, HTTP_TEST, TEST_FROMCACHE, TYMED_NULL);
3534     }
3535 
3536     trace("Testing http protocol abort...\n");
3537     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE;
3538     test_http_protocol_url(winetest_url, HTTP_TEST, TEST_ABORT, TYMED_NULL);
3539 
3540     test_early_abort(&CLSID_HttpProtocol);
3541     test_early_abort(&CLSID_HttpSProtocol);
3542 }
3543 
3544 static void test_https_protocol(void)
3545 {
3546     static const WCHAR https_winehq_url[] =
3547         {'h','t','t','p','s',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g','/',
3548          't','e','s','t','s','/','h','e','l','l','o','.','h','t','m','l',0};
3549 
3550     trace("Testing https protocol (from urlmon)...\n");
3551     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE;
3552     test_http_protocol_url(https_winehq_url, HTTPS_TEST, TEST_FIRST_HTTP, TYMED_NULL);
3553 }
3554 
3555 
3556 static void test_ftp_protocol(void)
3557 {
3558     IInternetProtocolInfo *protocol_info;
3559     IClassFactory *factory;
3560     IUnknown *unk;
3561     BYTE buf[4096];
3562     ULONG ref;
3563     DWORD cb;
3564     HRESULT hres;
3565 
3566     static const WCHAR ftp_urlW[] = {'f','t','p',':','/','/','f','t','p','.','w','i','n','e','h','q','.','o','r','g',
3567     '/','p','u','b','/','o','t','h','e','r','/',
3568     'w','i','n','e','l','o','g','o','.','x','c','f','.','t','a','r','.','b','z','2',0};
3569 
3570     trace("Testing ftp protocol...\n");
3571 
3572     init_test(FTP_TEST, 0);
3573 
3574     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE;
3575     state = STATE_STARTDOWNLOADING;
3576     expect_hrResult = E_PENDING;
3577 
3578     hres = CoGetClassObject(&CLSID_FtpProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
3579     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
3580     if(FAILED(hres))
3581         return;
3582 
3583     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
3584     ok(hres == E_NOINTERFACE, "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n", hres);
3585 
3586     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
3587     ok(hres == S_OK, "Could not get IClassFactory interface\n");
3588     IUnknown_Release(unk);
3589     if(FAILED(hres))
3590         return;
3591 
3592     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
3593                                         (void**)&async_protocol);
3594     IClassFactory_Release(factory);
3595     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
3596 
3597     test_priority(async_protocol);
3598 
3599     SET_EXPECT(GetBindInfo);
3600     SET_EXPECT(ReportProgress_FINDINGRESOURCE);
3601     SET_EXPECT(ReportProgress_CONNECTING);
3602     SET_EXPECT(ReportProgress_SENDINGREQUEST);
3603     SET_EXPECT(Switch);
3604 
3605     hres = IInternetProtocol_Start(async_protocol, ftp_urlW, &protocol_sink, &bind_info, 0, 0);
3606     ok(hres == S_OK, "Start failed: %08x\n", hres);
3607     CHECK_CALLED(GetBindInfo);
3608 
3609     SET_EXPECT(ReportResult);
3610 
3611     hres = IInternetProtocol_Read(async_protocol, buf, 1, &cb);
3612     ok((hres == E_PENDING && cb==0) ||
3613        (hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb);
3614 
3615     ok( WaitForSingleObject(event_complete, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
3616 
3617     while(1) {
3618         hres = IInternetProtocol_Read(async_protocol, buf, sizeof(buf), &cb);
3619         if(hres == E_PENDING)
3620         {
3621             DWORD ret = WaitForSingleObject(event_complete, 90000);
3622             ok( ret == WAIT_OBJECT_0, "wait timed out\n" );
3623             if (ret != WAIT_OBJECT_0) break;
3624         }
3625         else
3626             if(cb == 0) break;
3627     }
3628 
3629     ok(hres == S_FALSE, "Read failed: %08x\n", hres);
3630     CHECK_CALLED(ReportResult);
3631     CHECK_CALLED(Switch);
3632 
3633     test_protocol_terminate(async_protocol);
3634 
3635     if(pCreateUri) {
3636         IInternetProtocolEx *protocolex;
3637 
3638         hres = IInternetProtocol_QueryInterface(async_protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
3639         ok(hres == S_OK, "Could not get IInternetProtocolEx iface: %08x\n", hres);
3640         IInternetProtocolEx_Release(protocolex);
3641     }
3642 
3643     ref = IInternetProtocol_Release(async_protocol);
3644     ok(!ref, "ref=%d\n", ref);
3645 
3646     test_early_abort(&CLSID_FtpProtocol);
3647 }
3648 
3649 static void test_gopher_protocol(void)
3650 {
3651     IInternetProtocolInfo *protocol_info;
3652     IClassFactory *factory;
3653     IUnknown *unk;
3654     HRESULT hres;
3655 
3656     trace("Testing gopher protocol...\n");
3657 
3658     hres = CoGetClassObject(&CLSID_GopherProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
3659     ok(hres == S_OK ||
3660        broken(hres == REGDB_E_CLASSNOTREG || hres == CLASS_E_CLASSNOTAVAILABLE), /* Gopher protocol has been removed as of Vista */
3661        "CoGetClassObject failed: %08x\n", hres);
3662     if(FAILED(hres))
3663         return;
3664 
3665     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
3666     ok(hres == E_NOINTERFACE, "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n", hres);
3667 
3668     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
3669     ok(hres == S_OK, "Could not get IClassFactory interface\n");
3670     IUnknown_Release(unk);
3671     if(FAILED(hres))
3672         return;
3673 
3674     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
3675                                         (void**)&async_protocol);
3676     IClassFactory_Release(factory);
3677     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
3678 
3679     test_priority(async_protocol);
3680 
3681     IInternetProtocol_Release(async_protocol);
3682 
3683     test_early_abort(&CLSID_GopherProtocol);
3684 }
3685 
3686 static void test_mk_protocol(void)
3687 {
3688     IInternetProtocolInfo *protocol_info;
3689     IInternetProtocol *protocol;
3690     IClassFactory *factory;
3691     IUnknown *unk;
3692     HRESULT hres;
3693 
3694     static const WCHAR wrong_url1[] = {'t','e','s','t',':','@','M','S','I','T','S','t','o','r','e',
3695                                        ':',':','/','t','e','s','t','.','h','t','m','l',0};
3696     static const WCHAR wrong_url2[] = {'m','k',':','/','t','e','s','t','.','h','t','m','l',0};
3697 
3698     trace("Testing mk protocol...\n");
3699     init_test(MK_TEST, 0);
3700 
3701     hres = CoGetClassObject(&CLSID_MkProtocol, CLSCTX_INPROC_SERVER, NULL,
3702             &IID_IUnknown, (void**)&unk);
3703     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
3704 
3705     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info);
3706     ok(hres == E_NOINTERFACE,
3707         "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n",
3708         hres);
3709 
3710     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory);
3711     ok(hres == S_OK, "Could not get IClassFactory interface\n");
3712     IUnknown_Release(unk);
3713     if(FAILED(hres))
3714         return;
3715 
3716     hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol,
3717                                         (void**)&protocol);
3718     IClassFactory_Release(factory);
3719     ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres);
3720 
3721     SET_EXPECT(GetBindInfo);
3722     hres = IInternetProtocol_Start(protocol, wrong_url1, &protocol_sink, &bind_info, 0, 0);
3723     ok(hres == MK_E_SYNTAX || hres == INET_E_INVALID_URL,
3724        "Start failed: %08x, expected MK_E_SYNTAX or INET_E_INVALID_URL\n", hres);
3725     CLEAR_CALLED(GetBindInfo);
3726 
3727     SET_EXPECT(GetBindInfo);
3728     SET_EXPECT(ReportProgress_DIRECTBIND);
3729     SET_EXPECT(ReportProgress_SENDINGREQUEST);
3730     SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
3731     SET_EXPECT(ReportResult);
3732     expect_hrResult = INET_E_RESOURCE_NOT_FOUND;
3733 
3734     hres = IInternetProtocol_Start(protocol, wrong_url2, &protocol_sink, &bind_info, 0, 0);
3735     ok(hres == INET_E_RESOURCE_NOT_FOUND ||
3736        hres == INET_E_INVALID_URL, /* win2k3 */
3737        "Start failed: %08x, expected INET_E_RESOURCE_NOT_FOUND or INET_E_INVALID_URL\n", hres);
3738 
3739     if (hres == INET_E_RESOURCE_NOT_FOUND) {
3740         CHECK_CALLED(GetBindInfo);
3741         CLEAR_CALLED(ReportProgress_DIRECTBIND);
3742         CHECK_CALLED(ReportProgress_SENDINGREQUEST);
3743         CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
3744         CHECK_CALLED(ReportResult);
3745     }else {
3746         CLEAR_CALLED(GetBindInfo);
3747         CLEAR_CALLED(ReportProgress_DIRECTBIND);
3748         CLEAR_CALLED(ReportProgress_SENDINGREQUEST);
3749         CLEAR_CALLED(ReportProgress_MIMETYPEAVAILABLE);
3750         CLEAR_CALLED(ReportResult);
3751     }
3752 
3753     IInternetProtocol_Release(protocol);
3754 }
3755 
3756 static void test_CreateBinding(void)
3757 {
3758     IInternetProtocol *protocol;
3759     IInternetPriority *priority;
3760     IInternetSession *session;
3761     IWinInetHttpInfo *http_info;
3762     IWinInetInfo *inet_info;
3763     LONG p;
3764     BYTE buf[1000];
3765     DWORD read;
3766     HRESULT hres;
3767 
3768     static const WCHAR test_url[] =
3769         {'t','e','s','t',':','/','/','f','i','l','e','.','h','t','m','l',0};
3770     static const WCHAR wsz_test[] = {'t','e','s','t',0};
3771 
3772     trace("Testing CreateBinding...\n");
3773     init_test(BIND_TEST, TEST_BINDING);
3774 
3775     hres = pCoInternetGetSession(0, &session, 0);
3776     ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
3777 
3778     hres = IInternetSession_RegisterNameSpace(session, &ClassFactory, &IID_NULL, wsz_test, 0, NULL, 0);
3779     ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres);
3780 
3781     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
3782     binding_protocol = protocol;
3783     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
3784     ok(protocol != NULL, "protocol == NULL\n");
3785 
3786     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info);
3787     ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres);
3788 
3789     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&binding_sink);
3790     ok(hres == S_OK, "Could not get IInternetProtocolSink: %08x\n", hres);
3791 
3792     hres = IInternetProtocol_Start(protocol, test_url, NULL, &bind_info, 0, 0);
3793     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
3794     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, NULL, 0, 0);
3795     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
3796     hres = IInternetProtocol_Start(protocol, NULL, &protocol_sink, &bind_info, 0, 0);
3797     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
3798 
3799     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
3800     ok(hres == S_OK, "QueryInterface(IID_IInternetPriority) failed: %08x\n", hres);
3801 
3802     p = 0xdeadbeef;
3803     hres = IInternetPriority_GetPriority(priority, &p);
3804     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
3805     ok(!p, "p=%d\n", p);
3806 
3807     ex_priority = 100;
3808     hres = IInternetPriority_SetPriority(priority, 100);
3809     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
3810 
3811     p = 0xdeadbeef;
3812     hres = IInternetPriority_GetPriority(priority, &p);
3813     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
3814     ok(p == 100, "p=%d\n", p);
3815 
3816     hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&inet_info);
3817     ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres);
3818 
3819     SET_EXPECT(QueryService_InternetProtocol);
3820     SET_EXPECT(CreateInstance);
3821     SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
3822     SET_EXPECT(SetPriority);
3823     SET_EXPECT(Start);
3824 
3825     trace("Start >\n");
3826     expect_hrResult = S_OK;
3827     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, &bind_info, 0, 0);
3828     ok(hres == S_OK, "Start failed: %08x\n", hres);
3829     trace("Start <\n");
3830 
3831     CHECK_CALLED(QueryService_InternetProtocol);
3832     CHECK_CALLED(CreateInstance);
3833     CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
3834     CHECK_CALLED(SetPriority);
3835     CHECK_CALLED(Start);
3836 
3837     SET_EXPECT(QueryInterface_IWinInetInfo);
3838     hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&inet_info);
3839     ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres);
3840     CHECK_CALLED(QueryInterface_IWinInetInfo);
3841 
3842     SET_EXPECT(QueryInterface_IWinInetInfo);
3843     hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&inet_info);
3844     ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres);
3845     CHECK_CALLED(QueryInterface_IWinInetInfo);
3846 
3847     SET_EXPECT(QueryInterface_IWinInetHttpInfo);
3848     hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
3849     ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres);
3850     CHECK_CALLED(QueryInterface_IWinInetHttpInfo);
3851 
3852     SET_EXPECT(Read);
3853     read = 0xdeadbeef;
3854     hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
3855     ok(hres == S_OK, "Read failed: %08x\n", hres);
3856     ok(read == 100, "read = %d\n", read);
3857     CHECK_CALLED(Read);
3858 
3859     SET_EXPECT(Read);
3860     read = 0xdeadbeef;
3861     hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
3862     ok(hres == S_FALSE, "Read failed: %08x\n", hres);
3863     ok(!read, "read = %d\n", read);
3864     CHECK_CALLED(Read);
3865 
3866     p = 0xdeadbeef;
3867     hres = IInternetPriority_GetPriority(priority, &p);
3868     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
3869     ok(p == 100, "p=%d\n", p);
3870 
3871     hres = IInternetPriority_SetPriority(priority, 101);
3872     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
3873 
3874     SET_EXPECT(Terminate);
3875     hres = IInternetProtocol_Terminate(protocol, 0xdeadbeef);
3876     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
3877     CHECK_CALLED(Terminate);
3878 
3879     ok(protocol_emul->outer_ref == 0, "protocol_outer_ref = %u\n", protocol_emul->outer_ref);
3880 
3881     SET_EXPECT(Continue);
3882     hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
3883     ok(hres == S_OK, "Switch failed: %08x\n", hres);
3884     CHECK_CALLED(Continue);
3885 
3886     SET_EXPECT(Read);
3887     read = 0xdeadbeef;
3888     hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
3889     todo_wine
3890     ok(hres == E_ABORT, "Read failed: %08x\n", hres);
3891     todo_wine
3892     ok(read == 0, "read = %d\n", read);
3893     todo_wine
3894     CHECK_NOT_CALLED(Read);
3895 
3896     hres = IInternetProtocolSink_ReportProgress(binding_sink,
3897             BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
3898     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
3899 
3900     hres = IInternetProtocolSink_ReportResult(binding_sink, S_OK, ERROR_SUCCESS, NULL);
3901     ok(hres == E_FAIL, "ReportResult failed: %08x, expected E_FAIL\n", hres);
3902 
3903     hres = IInternetProtocolSink_ReportData(binding_sink, 0, 0, 0);
3904     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
3905 
3906     IInternetProtocolSink_Release(binding_sink);
3907     IInternetPriority_Release(priority);
3908     IInternetBindInfo_Release(prot_bind_info);
3909 
3910     SET_EXPECT(Protocol_destructor);
3911     IInternetProtocol_Release(protocol);
3912     CHECK_CALLED(Protocol_destructor);
3913 
3914     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
3915     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
3916     ok(protocol != NULL, "protocol == NULL\n");
3917 
3918     hres = IInternetProtocol_Abort(protocol, E_ABORT, 0);
3919     ok(hres == S_OK, "Abort failed: %08x\n", hres);
3920 
3921     hres = IInternetProtocol_Abort(protocol, E_FAIL, 0);
3922     ok(hres == S_OK, "Abort failed: %08x\n", hres);
3923 
3924     IInternetProtocol_Release(protocol);
3925 
3926     hres = IInternetSession_UnregisterNameSpace(session, &ClassFactory, wsz_test);
3927     ok(hres == S_OK, "UnregisterNameSpace failed: %08x\n", hres);
3928 
3929     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
3930     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
3931     ok(protocol != NULL, "protocol == NULL\n");
3932 
3933     SET_EXPECT(QueryService_InternetProtocol);
3934     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, &bind_info, 0, 0);
3935     ok(hres == MK_E_SYNTAX, "Start failed: %08x, expected MK_E_SYNTAX\n", hres);
3936     CHECK_CALLED(QueryService_InternetProtocol);
3937 
3938     IInternetProtocol_Release(protocol);
3939 
3940     IInternetSession_Release(session);
3941 }
3942 
3943 static void test_binding(int prot, DWORD grf_pi, DWORD test_flags)
3944 {
3945     IInternetProtocolEx *protocolex = NULL;
3946     IInternetProtocol *protocol;
3947     IInternetSession *session;
3948     IUri *uri = NULL;
3949     ULONG ref;
3950     HRESULT hres;
3951 
3952     pi = grf_pi;
3953 
3954     init_test(prot, test_flags|TEST_BINDING);
3955 
3956     hres = pCoInternetGetSession(0, &session, 0);
3957     ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
3958 
3959     if(test_flags & TEST_EMULATEPROT) {
3960         hres = IInternetSession_RegisterNameSpace(session, &ClassFactory, &IID_NULL, protocol_names[prot], 0, NULL, 0);
3961         ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres);
3962     }
3963 
3964     hres = IInternetSession_CreateBinding(session, NULL, binding_urls[prot], NULL, NULL, &protocol, 0);
3965     binding_protocol = protocol;
3966     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
3967     ok(protocol != NULL, "protocol == NULL\n");
3968 
3969     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info);
3970     ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres);
3971 
3972     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&binding_sink);
3973     ok(hres == S_OK, "QueryInterface(IID_IInternetProtocolSink) failed: %08x\n", hres);
3974 
3975     if(test_flags & TEST_USEIURI) {
3976         hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
3977         ok(hres == S_OK, "Could not get IInternetProtocolEx iface: %08x\n", hres);
3978 
3979         hres = pCreateUri(binding_urls[prot], Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
3980         ok(hres == S_OK, "CreateUri failed: %08x\n", hres);
3981     }
3982 
3983     ex_priority = 0;
3984     SET_EXPECT(QueryService_InternetProtocol);
3985     SET_EXPECT(CreateInstance);
3986     SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
3987     SET_EXPECT(SetPriority);
3988     if(impl_protex)
3989         SET_EXPECT(StartEx);
3990     else
3991         SET_EXPECT(Start);
3992 
3993     expect_hrResult = S_OK;
3994 
3995     if(protocolex) {
3996         hres = IInternetProtocolEx_StartEx(protocolex, uri, &protocol_sink, &bind_info, pi, 0);
3997         ok(hres == S_OK, "StartEx failed: %08x\n", hres);
3998     }else {
3999         hres = IInternetProtocol_Start(protocol, binding_urls[prot], &protocol_sink, &bind_info, pi, 0);
4000         ok(hres == S_OK, "Start failed: %08x\n", hres);
4001     }
4002 
4003     CHECK_CALLED(QueryService_InternetProtocol);
4004     CHECK_CALLED(CreateInstance);
4005     CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
4006     CLEAR_CALLED(SetPriority); /* IE11 does not call it. */
4007     if(impl_protex)
4008         CHECK_CALLED(StartEx);
4009     else
4010         CHECK_CALLED(Start);
4011 
4012     if(protocolex)
4013         IInternetProtocolEx_Release(protocolex);
4014     if(uri)
4015         IUri_Release(uri);
4016 
4017     if(prot == HTTP_TEST || prot == HTTPS_TEST) {
4018         while(prot_state < 4) {
4019             ok( WaitForSingleObject(event_complete, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
4020             if(mimefilter_test && filtered_protocol) {
4021                 SET_EXPECT(Continue);
4022                 IInternetProtocol_Continue(filtered_protocol, pdata);
4023                 CHECK_CALLED(Continue);
4024             }else {
4025                 SET_EXPECT(Continue);
4026                 IInternetProtocol_Continue(protocol, pdata);
4027                 CHECK_CALLED(Continue);
4028             }
4029             if(test_abort && prot_state == 2) {
4030                 SET_EXPECT(Abort);
4031                 hres = IInternetProtocol_Abort(protocol, E_ABORT, 0);
4032                 ok(hres == S_OK, "Abort failed: %08x\n", hres);
4033                 CHECK_CALLED(Abort);
4034 
4035                 hres = IInternetProtocol_Abort(protocol, E_ABORT, 0);
4036                 ok(hres == S_OK, "Abort failed: %08x\n", hres);
4037                 SetEvent(event_complete2);
4038                 break;
4039             }
4040             SetEvent(event_complete2);
4041         }
4042         if(direct_read)
4043             CHECK_CALLED(ReportData); /* Set in ReportResult */
4044         ok( WaitForSingleObject(event_complete, 90000) == WAIT_OBJECT_0, "wait timed out\n" );
4045     }else {
4046         if(mimefilter_test)
4047             SET_EXPECT(MimeFilter_LockRequest);
4048         else
4049             SET_EXPECT(LockRequest);
4050         hres = IInternetProtocol_LockRequest(protocol, 0);
4051         ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
4052         if(mimefilter_test)
4053             CHECK_CALLED(MimeFilter_LockRequest);
4054         else
4055             CHECK_CALLED(LockRequest);
4056 
4057         if(mimefilter_test)
4058             SET_EXPECT(MimeFilter_UnlockRequest);
4059         else
4060             SET_EXPECT(UnlockRequest);
4061         hres = IInternetProtocol_UnlockRequest(protocol);
4062         ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
4063         if(mimefilter_test)
4064             CHECK_CALLED(MimeFilter_UnlockRequest);
4065         else
4066             CHECK_CALLED(UnlockRequest);
4067     }
4068 
4069     if(mimefilter_test)
4070         SET_EXPECT(MimeFilter_Terminate);
4071     else
4072         SET_EXPECT(Terminate);
4073     hres = IInternetProtocol_Terminate(protocol, 0);
4074     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
4075     if(mimefilter_test)
4076         CLEAR_CALLED(MimeFilter_Terminate);
4077     else
4078         CHECK_CALLED(Terminate);
4079 
4080     if(filtered_protocol)
4081         IInternetProtocol_Release(filtered_protocol);
4082     IInternetBindInfo_Release(prot_bind_info);
4083     IInternetProtocolSink_Release(binding_sink);
4084 
4085     SET_EXPECT(Protocol_destructor);
4086     ref = IInternetProtocol_Release(protocol);
4087     ok(!ref, "ref=%u, expected 0\n", ref);
4088     CHECK_CALLED(Protocol_destructor);
4089 
4090     if(test_flags & TEST_EMULATEPROT) {
4091         hres = IInternetSession_UnregisterNameSpace(session, &ClassFactory, protocol_names[prot]);
4092         ok(hres == S_OK, "UnregisterNameSpace failed: %08x\n", hres);
4093     }
4094 
4095     IInternetSession_Release(session);
4096 }
4097 
4098 static const IID outer_test_iid = {0xabcabc00,0,0,{0,0,0,0,0,0,0,0x66}};
4099 
4100 static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
4101 {
4102     if(IsEqualGUID(riid, &outer_test_iid)) {
4103         CHECK_EXPECT(outer_QI_test);
4104         *ppv = (IUnknown*)0xdeadbeef;
4105         return S_OK;
4106     }
4107     ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
4108     return E_NOINTERFACE;
4109 }
4110 
4111 static ULONG WINAPI outer_AddRef(IUnknown *iface)
4112 {
4113     return 2;
4114 }
4115 
4116 static ULONG WINAPI outer_Release(IUnknown *iface)
4117 {
4118     return 1;
4119 }
4120 
4121 static const IUnknownVtbl outer_vtbl = {
4122     outer_QueryInterface,
4123     outer_AddRef,
4124     outer_Release
4125 };
4126 
4127 static void test_com_aggregation(const CLSID *clsid)
4128 {
4129     IUnknown outer = { &outer_vtbl };
4130     IClassFactory *class_factory;
4131     IUnknown *unk, *unk2, *unk3;
4132     HRESULT hres;
4133 
4134     hres = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&class_factory);
4135     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
4136 
4137     hres = IClassFactory_CreateInstance(class_factory, &outer, &IID_IUnknown, (void**)&unk);
4138     ok(hres == S_OK, "CreateInstance returned: %08x\n", hres);
4139 
4140     hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&unk2);
4141     ok(hres == S_OK, "Could not get IDispatch iface: %08x\n", hres);
4142 
4143     SET_EXPECT(outer_QI_test);
4144     hres = IUnknown_QueryInterface(unk2, &outer_test_iid, (void**)&unk3);
4145     CHECK_CALLED(outer_QI_test);
4146     ok(hres == S_OK, "Could not get IInternetProtocol iface: %08x\n", hres);
4147     ok(unk3 == (IUnknown*)0xdeadbeef, "unexpected unk2\n");
4148 
4149     IUnknown_Release(unk2);
4150     IUnknown_Release(unk);
4151 
4152     unk = (void*)0xdeadbeef;
4153     hres = IClassFactory_CreateInstance(class_factory, &outer, &IID_IInternetProtocol, (void**)&unk);
4154     ok(hres == CLASS_E_NOAGGREGATION, "CreateInstance returned: %08x\n", hres);
4155     ok(!unk, "unk = %p\n", unk);
4156 
4157     IClassFactory_Release(class_factory);
4158 }
4159 
4160 START_TEST(protocol)
4161 {
4162     HMODULE hurlmon;
4163 
4164     hurlmon = GetModuleHandleA("urlmon.dll");
4165     pCoInternetGetSession = (void*) GetProcAddress(hurlmon, "CoInternetGetSession");
4166     pReleaseBindInfo = (void*) GetProcAddress(hurlmon, "ReleaseBindInfo");
4167     pCreateUri = (void*) GetProcAddress(hurlmon, "CreateUri");
4168 
4169     if(!GetProcAddress(hurlmon, "CompareSecurityIds")) {
4170         win_skip("Various needed functions not present, too old IE\n");
4171         return;
4172     }
4173 
4174     if(!pCreateUri)
4175         win_skip("CreateUri not supported\n");
4176 
4177     OleInitialize(NULL);
4178 
4179     event_complete = CreateEventW(NULL, FALSE, FALSE, NULL);
4180     event_complete2 = CreateEventW(NULL, FALSE, FALSE, NULL);
4181     event_continue = CreateEventW(NULL, FALSE, FALSE, NULL);
4182     event_continue_done = CreateEventW(NULL, FALSE, FALSE, NULL);
4183     thread_id = GetCurrentThreadId();
4184 
4185     test_file_protocol();
4186     test_http_protocol();
4187     if(pCreateUri)
4188         test_https_protocol();
4189     else
4190         win_skip("Skipping https tests on too old platform\n");
4191     test_ftp_protocol();
4192     test_gopher_protocol();
4193     test_mk_protocol();
4194     test_CreateBinding();
4195 
4196     bindf &= ~BINDF_FROMURLMON;
4197     trace("Testing file binding (mime verification, emulate prot)...\n");
4198     test_binding(FILE_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT);
4199     trace("Testing http binding (mime verification, emulate prot)...\n");
4200     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT);
4201     trace("Testing its binding (mime verification, emulate prot)...\n");
4202     test_binding(ITS_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT);
4203     trace("Testing http binding (mime verification, emulate prot, short read, direct read)...\n");
4204     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_SHORT_READ|TEST_DIRECT_READ);
4205     trace("Testing http binding (mime verification, redirect, emulate prot)...\n");
4206     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_REDIRECT);
4207     trace("Testing http binding (mime verification, redirect, disable auto redirect, emulate prot)...\n");
4208     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_REDIRECT|TEST_DISABLEAUTOREDIRECT);
4209     trace("Testing file binding (mime verification, emulate prot, mime filter)...\n");
4210     test_binding(FILE_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_FILTER);
4211     trace("Testing http binding (mime verification, emulate prot, mime filter)...\n");
4212     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_FILTER);
4213     trace("Testing http binding (mime verification, emulate prot, mime filter, no mime)...\n");
4214     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_FILTER|TEST_NOMIME);
4215     trace("Testing http binding (mime verification, emulate prot, direct read)...\n");
4216     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_DIRECT_READ);
4217     trace("Testing http binding (mime verification, emulate prot, abort)...\n");
4218     test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_ABORT);
4219     if(pCreateUri) {
4220         trace("Testing file binding (use IUri, mime verification, emulate prot)...\n");
4221         test_binding(FILE_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_USEIURI);
4222         trace("Testing file binding (use IUri, impl StartEx, mime verification, emulate prot)...\n");
4223         test_binding(FILE_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_USEIURI|TEST_IMPLPROTEX);
4224         trace("Testing file binding (impl StartEx, mime verification, emulate prot)...\n");
4225         test_binding(FILE_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_IMPLPROTEX);
4226     }
4227 
4228     CloseHandle(event_complete);
4229     CloseHandle(event_complete2);
4230     CloseHandle(event_continue);
4231     CloseHandle(event_continue_done);
4232 
4233     test_com_aggregation(&CLSID_FileProtocol);
4234     test_com_aggregation(&CLSID_HttpProtocol);
4235     test_com_aggregation(&CLSID_HttpSProtocol);
4236     test_com_aggregation(&CLSID_FtpProtocol);
4237     test_com_aggregation(&CLSID_MkProtocol);
4238 
4239     OleUninitialize();
4240 }
4241