xref: /reactos/dll/win32/urlmon/bindprot.c (revision 6c3c2e33)
1 /*
2  * Copyright 2007-2009 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 #include "urlmon_main.h"
20 #include "wine/debug.h"
21 
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
23 
24 typedef void (*task_proc_t)(BindProtocol*,task_header_t*);
25 
26 struct _task_header_t {
27     task_proc_t proc;
28     task_header_t *next;
29 };
30 
31 #define BUFFER_SIZE     2048
32 #define MIME_TEST_SIZE  255
33 
34 #define WM_MK_CONTINUE   (WM_USER+101)
35 #define WM_MK_RELEASE    (WM_USER+102)
36 
process_tasks(BindProtocol * This)37 static void process_tasks(BindProtocol *This)
38 {
39     task_header_t *task;
40 
41     while(1) {
42         EnterCriticalSection(&This->section);
43 
44         task = This->task_queue_head;
45         if(task) {
46             This->task_queue_head = task->next;
47             if(!This->task_queue_head)
48                 This->task_queue_tail = NULL;
49         }
50 
51         LeaveCriticalSection(&This->section);
52 
53         if(!task)
54             break;
55 
56         This->continue_call++;
57         task->proc(This, task);
58         This->continue_call--;
59     }
60 }
61 
notif_wnd_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)62 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
63 {
64     switch(msg) {
65     case WM_MK_CONTINUE: {
66         BindProtocol *This = (BindProtocol*)lParam;
67 
68         process_tasks(This);
69 
70         IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
71         return 0;
72     }
73     case WM_MK_RELEASE: {
74         tls_data_t *data = get_tls_data();
75 
76         if(!--data->notif_hwnd_cnt) {
77             DestroyWindow(hwnd);
78             data->notif_hwnd = NULL;
79         }
80     }
81     }
82 
83     return DefWindowProcW(hwnd, msg, wParam, lParam);
84 }
85 
86 static const WCHAR wszURLMonikerNotificationWindow[] =
87     {'U','R','L',' ','M','o','n','i','k','e','r',' ',
88      'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
89 
90 static ATOM notif_wnd_class;
91 
register_notif_wnd_class(INIT_ONCE * once,void * param,void ** context)92 static BOOL WINAPI register_notif_wnd_class(INIT_ONCE *once, void *param, void **context)
93 {
94     static WNDCLASSEXW wndclass = {
95         sizeof(wndclass), 0, notif_wnd_proc, 0, 0,
96         NULL, NULL, NULL, NULL, NULL,
97         wszURLMonikerNotificationWindow, NULL
98     };
99 
100     wndclass.hInstance = hProxyDll;
101     notif_wnd_class = RegisterClassExW(&wndclass);
102     return TRUE;
103 }
104 
unregister_notif_wnd_class(void)105 void unregister_notif_wnd_class(void)
106 {
107     if(notif_wnd_class)
108         UnregisterClassW(MAKEINTRESOURCEW(notif_wnd_class), hProxyDll);
109 }
110 
get_notif_hwnd(void)111 HWND get_notif_hwnd(void)
112 {
113     tls_data_t *tls_data;
114 
115     static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
116 
117     tls_data = get_tls_data();
118     if(!tls_data)
119         return NULL;
120 
121     if(tls_data->notif_hwnd_cnt) {
122         tls_data->notif_hwnd_cnt++;
123         return tls_data->notif_hwnd;
124     }
125 
126     InitOnceExecuteOnce(&init_once, register_notif_wnd_class, NULL, NULL);
127     if(!notif_wnd_class)
128         return NULL;
129 
130     tls_data->notif_hwnd = CreateWindowExW(0, MAKEINTRESOURCEW(notif_wnd_class),
131             wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
132             NULL, hProxyDll, NULL);
133     if(tls_data->notif_hwnd)
134         tls_data->notif_hwnd_cnt++;
135 
136     TRACE("hwnd = %p\n", tls_data->notif_hwnd);
137 
138     return tls_data->notif_hwnd;
139 }
140 
release_notif_hwnd(HWND hwnd)141 void release_notif_hwnd(HWND hwnd)
142 {
143     tls_data_t *data = get_tls_data();
144 
145     if(!data)
146         return;
147 
148     if(data->notif_hwnd != hwnd) {
149         PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
150         return;
151     }
152 
153     if(!--data->notif_hwnd_cnt) {
154         DestroyWindow(data->notif_hwnd);
155         data->notif_hwnd = NULL;
156     }
157 }
158 
push_task(BindProtocol * This,task_header_t * task,task_proc_t proc)159 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
160 {
161     BOOL do_post = FALSE;
162 
163     task->proc = proc;
164     task->next = NULL;
165 
166     EnterCriticalSection(&This->section);
167 
168     if(This->task_queue_tail) {
169         This->task_queue_tail->next = task;
170         This->task_queue_tail = task;
171     }else {
172         This->task_queue_tail = This->task_queue_head = task;
173         do_post = !This->continue_call;
174     }
175 
176     LeaveCriticalSection(&This->section);
177 
178     if(do_post) {
179         IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
180         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
181     }
182 }
183 
is_apartment_thread(BindProtocol * This)184 static inline BOOL is_apartment_thread(BindProtocol *This)
185 {
186     return This->apartment_thread == GetCurrentThreadId();
187 }
188 
do_direct_notif(BindProtocol * This)189 static inline BOOL do_direct_notif(BindProtocol *This)
190 {
191     return !(This->pi & PI_APARTMENTTHREADED) || (is_apartment_thread(This) && !This->continue_call);
192 }
193 
handle_mime_filter(BindProtocol * This,IInternetProtocol * mime_filter)194 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter)
195 {
196     PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
197     HRESULT hres;
198 
199     hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&This->protocol_sink_handler);
200     if(FAILED(hres)) {
201         This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
202         return hres;
203     }
204 
205     IInternetProtocol_AddRef(mime_filter);
206     This->protocol_handler = mime_filter;
207 
208     filter_data.pProtocol = &This->default_protocol_handler.IInternetProtocol_iface;
209     hres = IInternetProtocol_Start(mime_filter, This->mime, &This->default_protocol_handler.IInternetProtocolSink_iface,
210             &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC,
211             (HANDLE_PTR)&filter_data);
212     if(FAILED(hres)) {
213         IInternetProtocolSink_Release(This->protocol_sink_handler);
214         IInternetProtocol_Release(This->protocol_handler);
215         This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
216         This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
217         return hres;
218     }
219 
220     /* NOTE: IE9 calls it on the new protocol_sink. It doesn't make sense so it seems to be a bug there. */
221     IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
222 
223     return S_OK;
224 }
225 
mime_available(BindProtocol * This,LPCWSTR mime,BOOL verified)226 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
227 {
228     IInternetProtocol *mime_filter;
229     HRESULT hres;
230 
231     heap_free(This->mime);
232     This->mime = heap_strdupW(mime);
233 
234     if(This->protocol_handler==&This->default_protocol_handler.IInternetProtocol_iface
235             && (mime_filter = get_mime_filter(mime))) {
236         TRACE("Got mime filter for %s\n", debugstr_w(mime));
237 
238         hres = handle_mime_filter(This, mime_filter);
239         IInternetProtocol_Release(mime_filter);
240         if(FAILED(hres))
241             FIXME("MIME filter failed: %08x\n", hres);
242     }
243 
244     if(This->reported_mime || verified || !(This->pi & PI_MIMEVERIFICATION)) {
245         This->reported_mime = TRUE;
246         IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
247     }
248 }
249 
impl_from_IInternetProtocolEx(IInternetProtocolEx * iface)250 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
251 {
252     return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
253 }
254 
BindProtocol_QueryInterface(IInternetProtocolEx * iface,REFIID riid,void ** ppv)255 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
256 {
257     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
258 
259     *ppv = NULL;
260     if(IsEqualGUID(&IID_IUnknown, riid)) {
261         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
262         *ppv = &This->IInternetProtocolEx_iface;
263     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
264         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
265         *ppv = &This->IInternetProtocolEx_iface;
266     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
267         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
268         *ppv = &This->IInternetProtocolEx_iface;
269     }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
270         TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
271         *ppv = &This->IInternetProtocolEx_iface;
272     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
273         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
274         *ppv = &This->IInternetBindInfo_iface;
275     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
276         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
277         *ppv = &This->IInternetPriority_iface;
278     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
279         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
280     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
281         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
282         *ppv = &This->IServiceProvider_iface;
283     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
284         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
285         *ppv = &This->IInternetProtocolSink_iface;
286     }else if(This->protocol_unk) {
287         HRESULT hres;
288         hres = IUnknown_QueryInterface(This->protocol_unk, riid, ppv);
289         TRACE("(%p) aggregated handler returned %08x for %s\n", This, hres, debugstr_guid(riid));
290         return hres;
291     }else {
292         WARN("not supported interface %s\n", debugstr_guid(riid));
293     }
294 
295     if(!*ppv)
296         return E_NOINTERFACE;
297 
298     IUnknown_AddRef((IUnknown*)*ppv);
299     return S_OK;
300 }
301 
BindProtocol_AddRef(IInternetProtocolEx * iface)302 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
303 {
304     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
305     LONG ref = InterlockedIncrement(&This->ref);
306     TRACE("(%p) ref=%d\n", This, ref);
307     return ref;
308 }
309 
release_protocol_handler(BindProtocol * This)310 static void release_protocol_handler(BindProtocol *This)
311 {
312     if(This->protocol) {
313         IInternetProtocol_Release(This->protocol);
314         This->protocol = NULL;
315     }
316     if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface) {
317         IInternetProtocol_Release(This->protocol_handler);
318         This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
319     }
320     if(This->protocol_sink_handler &&
321        This->protocol_sink_handler != &This->default_protocol_handler.IInternetProtocolSink_iface) {
322         IInternetProtocolSink_Release(This->protocol_sink_handler);
323         This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
324     }
325     if(This->protocol_unk) {
326         IUnknown_Release(This->protocol_unk);
327         This->protocol_unk = NULL;
328     }
329 }
330 
BindProtocol_Release(IInternetProtocolEx * iface)331 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
332 {
333     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
334     LONG ref = InterlockedDecrement(&This->ref);
335 
336     TRACE("(%p) ref=%d\n", This, ref);
337 
338     if(!ref) {
339         release_protocol_handler(This);
340         if(This->redirect_callback)
341             IBindCallbackRedirect_Release(This->redirect_callback);
342         if(This->bind_info)
343             IInternetBindInfo_Release(This->bind_info);
344         if(This->uri)
345             IUri_Release(This->uri);
346         SysFreeString(This->display_uri);
347 
348         set_binding_sink(This, NULL, NULL);
349 
350         if(This->notif_hwnd)
351             release_notif_hwnd(This->notif_hwnd);
352         This->section.DebugInfo->Spare[0] = 0;
353         DeleteCriticalSection(&This->section);
354 
355         heap_free(This->mime);
356         heap_free(This);
357 
358         URLMON_UnlockModule();
359     }
360 
361     return ref;
362 }
363 
BindProtocol_Start(IInternetProtocolEx * iface,LPCWSTR szUrl,IInternetProtocolSink * pOIProtSink,IInternetBindInfo * pOIBindInfo,DWORD grfPI,HANDLE_PTR dwReserved)364 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
365         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
366         DWORD grfPI, HANDLE_PTR dwReserved)
367 {
368     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
369     IUri *uri;
370     HRESULT hres;
371 
372     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
373             pOIBindInfo, grfPI, dwReserved);
374 
375     hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
376     if(FAILED(hres))
377         return hres;
378 
379     hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
380             pOIBindInfo, grfPI, (HANDLE*)dwReserved);
381 
382     IUri_Release(uri);
383     return hres;
384 }
385 
BindProtocol_Continue(IInternetProtocolEx * iface,PROTOCOLDATA * pProtocolData)386 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
387 {
388     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
389 
390     TRACE("(%p)->(%p)\n", This, pProtocolData);
391 
392     return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
393 }
394 
BindProtocol_Abort(IInternetProtocolEx * iface,HRESULT hrReason,DWORD dwOptions)395 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
396         DWORD dwOptions)
397 {
398     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
399 
400     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
401 
402     return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
403 }
404 
BindProtocol_Terminate(IInternetProtocolEx * iface,DWORD dwOptions)405 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
406 {
407     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
408 
409     TRACE("(%p)->(%08x)\n", This, dwOptions);
410 
411     return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
412 }
413 
BindProtocol_Suspend(IInternetProtocolEx * iface)414 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
415 {
416     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
417     FIXME("(%p)\n", This);
418     return E_NOTIMPL;
419 }
420 
BindProtocol_Resume(IInternetProtocolEx * iface)421 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
422 {
423     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
424     FIXME("(%p)\n", This);
425     return E_NOTIMPL;
426 }
427 
BindProtocol_Read(IInternetProtocolEx * iface,void * pv,ULONG cb,ULONG * pcbRead)428 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
429         ULONG cb, ULONG *pcbRead)
430 {
431     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
432 
433     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
434 
435     if(pcbRead)
436         *pcbRead = 0;
437     return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
438 }
439 
BindProtocol_Seek(IInternetProtocolEx * iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER * plibNewPosition)440 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
441         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
442 {
443     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
444     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
445     return E_NOTIMPL;
446 }
447 
BindProtocol_LockRequest(IInternetProtocolEx * iface,DWORD dwOptions)448 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
449 {
450     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
451 
452     TRACE("(%p)->(%08x)\n", This, dwOptions);
453 
454     return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
455 }
456 
BindProtocol_UnlockRequest(IInternetProtocolEx * iface)457 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
458 {
459     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
460 
461     TRACE("(%p)\n", This);
462 
463     return IInternetProtocol_UnlockRequest(This->protocol_handler);
464 }
465 
BindProtocol_StartEx(IInternetProtocolEx * iface,IUri * pUri,IInternetProtocolSink * pOIProtSink,IInternetBindInfo * pOIBindInfo,DWORD grfPI,HANDLE * dwReserved)466 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
467         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
468         DWORD grfPI, HANDLE *dwReserved)
469 {
470     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
471     IInternetProtocol *protocol = NULL;
472     IInternetProtocolEx *protocolex;
473     IInternetPriority *priority;
474     IServiceProvider *service_provider;
475     CLSID clsid = IID_NULL;
476     IUnknown *protocol_unk = NULL;
477     LPOLESTR clsid_str;
478     HRESULT hres;
479 
480     TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
481 
482     if(!pUri || !pOIProtSink || !pOIBindInfo)
483         return E_INVALIDARG;
484 
485     This->pi = grfPI;
486 
487     if(This->uri) {
488         SysFreeString(This->display_uri);
489         IUri_Release(This->uri);
490     }
491     IUri_AddRef(pUri);
492     This->uri = pUri;
493 
494     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
495                                                 (void**)&service_provider);
496     if(SUCCEEDED(hres)) {
497         /* FIXME: What's protocol CLSID here? */
498         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
499                 &IID_IInternetProtocol, (void**)&protocol);
500         IServiceProvider_Release(service_provider);
501     }
502 
503     if(!protocol) {
504         IClassFactory *cf;
505 
506         hres = get_protocol_handler(pUri, &clsid, &cf);
507         if(FAILED(hres))
508             return hres;
509 
510         hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
511                 &IID_IUnknown, (void**)&protocol_unk);
512         if(SUCCEEDED(hres)) {
513             hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocol, (void**)&protocol);
514             if(SUCCEEDED(hres))
515                 This->protocol_unk = protocol_unk;
516             else
517                 IUnknown_Release(protocol_unk);
518         }
519         else if(hres == CLASS_E_NOAGGREGATION)
520             hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
521 
522         IClassFactory_Release(cf);
523         if(FAILED(hres))
524             return hres;
525     }
526 
527     StringFromCLSID(&clsid, &clsid_str);
528     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
529     CoTaskMemFree(clsid_str);
530 
531     This->protocol_unk = protocol_unk;
532     This->protocol = protocol;
533 
534     if(!protocol_unk)
535         protocol_unk = (IUnknown*)protocol;
536 
537     set_binding_sink(This, pOIProtSink, pOIBindInfo);
538 
539     hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetPriority, (void**)&priority);
540     if(SUCCEEDED(hres)) {
541         IInternetPriority_SetPriority(priority, This->priority);
542         IInternetPriority_Release(priority);
543     }
544 
545     hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocolEx, (void**)&protocolex);
546     if(SUCCEEDED(hres)) {
547         hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
548                 &This->IInternetBindInfo_iface, 0, NULL);
549         IInternetProtocolEx_Release(protocolex);
550     }else {
551         hres = IUri_GetDisplayUri(pUri, &This->display_uri);
552         if(FAILED(hres))
553             return hres;
554 
555         hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface,
556                 &This->IInternetBindInfo_iface, 0, 0);
557     }
558 
559     if(SUCCEEDED(hres))
560         process_tasks(This);
561     return hres;
562 }
563 
set_binding_sink(BindProtocol * This,IInternetProtocolSink * sink,IInternetBindInfo * bind_info)564 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
565 {
566     IInternetProtocolSink *prev_sink;
567     IServiceProvider *service_provider = NULL;
568 
569     if(sink)
570         IInternetProtocolSink_AddRef(sink);
571     prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
572     if(prev_sink)
573         IInternetProtocolSink_Release(prev_sink);
574 
575     if(sink)
576         IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
577     service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
578     if(service_provider)
579         IServiceProvider_Release(service_provider);
580 
581     if(bind_info)
582         IInternetBindInfo_AddRef(bind_info);
583     bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
584     if(bind_info)
585         IInternetBindInfo_Release(bind_info);
586 }
587 
588 static const IInternetProtocolExVtbl BindProtocolVtbl = {
589     BindProtocol_QueryInterface,
590     BindProtocol_AddRef,
591     BindProtocol_Release,
592     BindProtocol_Start,
593     BindProtocol_Continue,
594     BindProtocol_Abort,
595     BindProtocol_Terminate,
596     BindProtocol_Suspend,
597     BindProtocol_Resume,
598     BindProtocol_Read,
599     BindProtocol_Seek,
600     BindProtocol_LockRequest,
601     BindProtocol_UnlockRequest,
602     BindProtocol_StartEx
603 };
604 
impl_from_IInternetProtocol(IInternetProtocol * iface)605 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
606 {
607     return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
608 }
609 
ProtocolHandler_QueryInterface(IInternetProtocol * iface,REFIID riid,void ** ppv)610 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
611 {
612     BindProtocol *This = impl_from_IInternetProtocol(iface);
613 
614     *ppv = NULL;
615     if(IsEqualGUID(&IID_IUnknown, riid)) {
616         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
617         *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
618     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
619         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
620         *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
621     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
622         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
623         *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
624     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
625         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
626         *ppv = &This->default_protocol_handler.IInternetProtocolSink_iface;
627     }
628 
629     if(*ppv) {
630         IInternetProtocol_AddRef(iface);
631         return S_OK;
632     }
633 
634     WARN("not supported interface %s\n", debugstr_guid(riid));
635     return E_NOINTERFACE;
636 }
637 
ProtocolHandler_AddRef(IInternetProtocol * iface)638 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
639 {
640     BindProtocol *This = impl_from_IInternetProtocol(iface);
641     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
642 }
643 
ProtocolHandler_Release(IInternetProtocol * iface)644 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
645 {
646     BindProtocol *This = impl_from_IInternetProtocol(iface);
647     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
648 }
649 
ProtocolHandler_Start(IInternetProtocol * iface,LPCWSTR szUrl,IInternetProtocolSink * pOIProtSink,IInternetBindInfo * pOIBindInfo,DWORD grfPI,HANDLE_PTR dwReserved)650 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
651         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
652         DWORD grfPI, HANDLE_PTR dwReserved)
653 {
654     ERR("Should not be called\n");
655     return E_NOTIMPL;
656 }
657 
ProtocolHandler_Continue(IInternetProtocol * iface,PROTOCOLDATA * pProtocolData)658 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
659 {
660     BindProtocol *This = impl_from_IInternetProtocol(iface);
661     IInternetProtocol *protocol = NULL;
662     HRESULT hres;
663 
664     TRACE("(%p)->(%p)\n", This, pProtocolData);
665 
666     /* FIXME: This should not be needed. */
667     if(!This->protocol) {
668         if(!This->protocol_unk)
669             return E_FAIL;
670         hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol, (void**)&protocol);
671         if(FAILED(hres))
672             return E_FAIL;
673     }
674 
675     hres = IInternetProtocol_Continue(protocol ? protocol : This->protocol, pProtocolData);
676 
677     heap_free(pProtocolData);
678     if(protocol)
679         IInternetProtocol_Release(protocol);
680     return hres;
681 }
682 
ProtocolHandler_Abort(IInternetProtocol * iface,HRESULT hrReason,DWORD dwOptions)683 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
684         DWORD dwOptions)
685 {
686     BindProtocol *This = impl_from_IInternetProtocol(iface);
687 
688     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
689 
690     if(This->protocol && !This->reported_result)
691         return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
692 
693     return S_OK;
694 }
695 
ProtocolHandler_Terminate(IInternetProtocol * iface,DWORD dwOptions)696 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
697 {
698     BindProtocol *This = impl_from_IInternetProtocol(iface);
699 
700     TRACE("(%p)->(%08x)\n", This, dwOptions);
701 
702     if(!This->reported_result)
703         return E_FAIL;
704 
705     /* This may get released in Terminate call. */
706     IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
707 
708     if(This->protocol) {
709         IInternetProtocol_Terminate(This->protocol, 0);
710 
711         if (This->protocol_unk) {
712             IInternetProtocol_Release(This->protocol);
713             This->protocol = NULL;
714         }
715     }
716 
717     set_binding_sink(This, NULL, NULL);
718 
719     if(This->bind_info) {
720         IInternetBindInfo_Release(This->bind_info);
721         This->bind_info = NULL;
722     }
723 
724     if(This->redirect_callback) {
725         IBindCallbackRedirect_Release(This->redirect_callback);
726         This->redirect_callback = NULL;
727     }
728 
729     IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
730     return S_OK;
731 }
732 
ProtocolHandler_Suspend(IInternetProtocol * iface)733 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
734 {
735     BindProtocol *This = impl_from_IInternetProtocol(iface);
736     FIXME("(%p)\n", This);
737     return E_NOTIMPL;
738 }
739 
ProtocolHandler_Resume(IInternetProtocol * iface)740 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
741 {
742     BindProtocol *This = impl_from_IInternetProtocol(iface);
743     FIXME("(%p)\n", This);
744     return E_NOTIMPL;
745 }
746 
ProtocolHandler_Read(IInternetProtocol * iface,void * pv,ULONG cb,ULONG * pcbRead)747 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
748         ULONG cb, ULONG *pcbRead)
749 {
750     BindProtocol *This = impl_from_IInternetProtocol(iface);
751     ULONG read = 0;
752     HRESULT hres = S_OK;
753 
754     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
755 
756     if(This->buf_size) {
757         read = min(cb, This->buf_size);
758         memcpy(pv, This->buf, read);
759 
760         if(read == This->buf_size) {
761             heap_free(This->buf);
762             This->buf = NULL;
763         }else {
764             memmove(This->buf, This->buf+cb, This->buf_size-cb);
765         }
766 
767         This->buf_size -= read;
768     }
769 
770     if(read < cb) {
771         IInternetProtocol *protocol;
772         ULONG cread = 0;
773 
774         /* FIXME: We shouldn't need it, but out binding code currently depends on it. */
775         if(!This->protocol && This->protocol_unk) {
776             hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol,
777                                            (void**)&protocol);
778             if(FAILED(hres))
779                 return E_ABORT;
780         }else {
781             protocol = This->protocol;
782         }
783 
784         if(is_apartment_thread(This))
785             This->continue_call++;
786         hres = IInternetProtocol_Read(protocol, (BYTE*)pv+read, cb-read, &cread);
787         if(is_apartment_thread(This))
788             This->continue_call--;
789         read += cread;
790 
791         if(!This->protocol)
792             IInternetProtocol_Release(protocol);
793     }
794 
795     *pcbRead = read;
796     return hres;
797 }
798 
ProtocolHandler_Seek(IInternetProtocol * iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER * plibNewPosition)799 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
800         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
801 {
802     BindProtocol *This = impl_from_IInternetProtocol(iface);
803     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
804     return E_NOTIMPL;
805 }
806 
ProtocolHandler_LockRequest(IInternetProtocol * iface,DWORD dwOptions)807 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
808 {
809     BindProtocol *This = impl_from_IInternetProtocol(iface);
810 
811     TRACE("(%p)->(%08x)\n", This, dwOptions);
812 
813     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
814 }
815 
ProtocolHandler_UnlockRequest(IInternetProtocol * iface)816 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
817 {
818     BindProtocol *This = impl_from_IInternetProtocol(iface);
819 
820     TRACE("(%p)\n", This);
821 
822     return IInternetProtocol_UnlockRequest(This->protocol);
823 }
824 
825 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
826     ProtocolHandler_QueryInterface,
827     ProtocolHandler_AddRef,
828     ProtocolHandler_Release,
829     ProtocolHandler_Start,
830     ProtocolHandler_Continue,
831     ProtocolHandler_Abort,
832     ProtocolHandler_Terminate,
833     ProtocolHandler_Suspend,
834     ProtocolHandler_Resume,
835     ProtocolHandler_Read,
836     ProtocolHandler_Seek,
837     ProtocolHandler_LockRequest,
838     ProtocolHandler_UnlockRequest
839 };
840 
impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink * iface)841 static inline BindProtocol *impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink *iface)
842 {
843     return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocolSink_iface);
844 }
845 
ProtocolSinkHandler_QueryInterface(IInternetProtocolSink * iface,REFIID riid,void ** ppvObject)846 static HRESULT WINAPI ProtocolSinkHandler_QueryInterface(IInternetProtocolSink *iface,
847         REFIID riid, void **ppvObject)
848 {
849     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
850     return IInternetProtocol_QueryInterface(&This->default_protocol_handler.IInternetProtocol_iface,
851             riid, ppvObject);
852 }
853 
ProtocolSinkHandler_AddRef(IInternetProtocolSink * iface)854 static ULONG WINAPI ProtocolSinkHandler_AddRef(IInternetProtocolSink *iface)
855 {
856     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
857     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
858 }
859 
ProtocolSinkHandler_Release(IInternetProtocolSink * iface)860 static ULONG WINAPI ProtocolSinkHandler_Release(IInternetProtocolSink *iface)
861 {
862     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
863     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
864 }
865 
ProtocolSinkHandler_Switch(IInternetProtocolSink * iface,PROTOCOLDATA * pProtocolData)866 static HRESULT WINAPI ProtocolSinkHandler_Switch(IInternetProtocolSink *iface,
867         PROTOCOLDATA *pProtocolData)
868 {
869     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
870 
871     TRACE("(%p)->(%p)\n", This, pProtocolData);
872 
873     if(!This->protocol_sink) {
874         IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
875         return S_OK;
876     }
877 
878     return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
879 }
880 
ProtocolSinkHandler_ReportProgress(IInternetProtocolSink * iface,ULONG status_code,LPCWSTR status_text)881 static HRESULT WINAPI ProtocolSinkHandler_ReportProgress(IInternetProtocolSink *iface,
882         ULONG status_code, LPCWSTR status_text)
883 {
884     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
885 
886     TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(status_code), debugstr_w(status_text));
887 
888     if(!This->protocol_sink)
889         return S_OK;
890 
891     switch(status_code) {
892     case BINDSTATUS_FINDINGRESOURCE:
893     case BINDSTATUS_CONNECTING:
894     case BINDSTATUS_REDIRECTING:
895     case BINDSTATUS_SENDINGREQUEST:
896     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
897     case BINDSTATUS_DIRECTBIND:
898     case BINDSTATUS_ACCEPTRANGES:
899     case BINDSTATUS_DECODING:
900         IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
901         break;
902 
903     case BINDSTATUS_BEGINDOWNLOADDATA:
904         IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max);
905         break;
906 
907     case BINDSTATUS_MIMETYPEAVAILABLE:
908         mime_available(This, status_text, FALSE);
909         break;
910 
911     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
912         mime_available(This, status_text, TRUE);
913         break;
914 
915     default:
916         FIXME("unsupported ulStatusCode %u\n", status_code);
917     }
918 
919     return S_OK;
920 }
921 
ProtocolSinkHandler_ReportData(IInternetProtocolSink * iface,DWORD bscf,ULONG progress,ULONG progress_max)922 static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface,
923         DWORD bscf, ULONG progress, ULONG progress_max)
924 {
925     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
926 
927     TRACE("(%p)->(%x %u %u)\n", This, bscf, progress, progress_max);
928 
929     This->bscf = bscf;
930     This->progress = progress;
931     This->progress_max = progress_max;
932 
933     if(!This->protocol_sink)
934         return S_OK;
935 
936     if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
937         BYTE buf[BUFFER_SIZE];
938         DWORD read = 0;
939         LPWSTR mime;
940         HRESULT hres;
941 
942         do {
943             read = 0;
944             if(is_apartment_thread(This))
945                 This->continue_call++;
946             hres = IInternetProtocol_Read(This->protocol, buf,
947                     sizeof(buf)-This->buf_size, &read);
948             if(is_apartment_thread(This))
949                 This->continue_call--;
950             if(FAILED(hres) && hres != E_PENDING)
951                 return hres;
952 
953             if(!This->buf) {
954                 This->buf = heap_alloc(BUFFER_SIZE);
955                 if(!This->buf)
956                     return E_OUTOFMEMORY;
957             }else if(read + This->buf_size > BUFFER_SIZE) {
958                 BYTE *tmp;
959 
960                 tmp = heap_realloc(This->buf, read+This->buf_size);
961                 if(!tmp)
962                     return E_OUTOFMEMORY;
963                 This->buf = tmp;
964             }
965 
966             memcpy(This->buf+This->buf_size, buf, read);
967             This->buf_size += read;
968         }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
969 
970         if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
971             return S_OK;
972 
973         bscf = BSCF_FIRSTDATANOTIFICATION;
974         if(hres == S_FALSE)
975             bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
976 
977         if(!This->reported_mime) {
978             BSTR raw_uri;
979 
980             hres = IUri_GetRawUri(This->uri, &raw_uri);
981             if(FAILED(hres))
982                 return hres;
983 
984             hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
985                     This->mime, 0, &mime, 0);
986             SysFreeString(raw_uri);
987             if(FAILED(hres))
988                 return hres;
989 
990             heap_free(This->mime);
991             This->mime = heap_strdupW(mime);
992             CoTaskMemFree(mime);
993             This->reported_mime = TRUE;
994             if(This->protocol_sink)
995                 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
996         }
997     }
998 
999     if(!This->protocol_sink)
1000         return S_OK;
1001 
1002     return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1003 }
1004 
handle_redirect(BindProtocol * This,const WCHAR * url)1005 static HRESULT handle_redirect(BindProtocol *This, const WCHAR *url)
1006 {
1007     HRESULT hres;
1008 
1009     if(This->redirect_callback) {
1010         VARIANT_BOOL cancel = VARIANT_FALSE;
1011         IBindCallbackRedirect_Redirect(This->redirect_callback, url, &cancel);
1012         if(cancel)
1013             return INET_E_REDIRECT_FAILED;
1014     }
1015 
1016     if(This->protocol_sink) {
1017         hres = IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_REDIRECTING, url);
1018         if(FAILED(hres))
1019             return hres;
1020     }
1021 
1022     IInternetProtocol_Terminate(This->protocol, 0); /* should this be done in StartEx? */
1023     release_protocol_handler(This);
1024 
1025     return IInternetProtocolEx_Start(&This->IInternetProtocolEx_iface, url, This->protocol_sink, This->bind_info, This->pi, 0);
1026 }
1027 
ProtocolSinkHandler_ReportResult(IInternetProtocolSink * iface,HRESULT hrResult,DWORD dwError,LPCWSTR szResult)1028 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface,
1029         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1030 {
1031     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
1032 
1033     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1034 
1035     if(hrResult == INET_E_REDIRECT_FAILED) {
1036         hrResult = handle_redirect(This, szResult);
1037         if(hrResult == S_OK)
1038             return S_OK;
1039         szResult = NULL;
1040     }
1041 
1042     if(This->protocol_sink)
1043         return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1044     return S_OK;
1045 }
1046 
1047 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = {
1048     ProtocolSinkHandler_QueryInterface,
1049     ProtocolSinkHandler_AddRef,
1050     ProtocolSinkHandler_Release,
1051     ProtocolSinkHandler_Switch,
1052     ProtocolSinkHandler_ReportProgress,
1053     ProtocolSinkHandler_ReportData,
1054     ProtocolSinkHandler_ReportResult
1055 };
1056 
impl_from_IInternetBindInfo(IInternetBindInfo * iface)1057 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
1058 {
1059     return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
1060 }
1061 
BindInfo_QueryInterface(IInternetBindInfo * iface,REFIID riid,void ** ppv)1062 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
1063         REFIID riid, void **ppv)
1064 {
1065     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1066     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1067 }
1068 
BindInfo_AddRef(IInternetBindInfo * iface)1069 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
1070 {
1071     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1072     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1073 }
1074 
BindInfo_Release(IInternetBindInfo * iface)1075 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
1076 {
1077     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1078     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1079 }
1080 
BindInfo_GetBindInfo(IInternetBindInfo * iface,DWORD * grfBINDF,BINDINFO * pbindinfo)1081 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
1082         DWORD *grfBINDF, BINDINFO *pbindinfo)
1083 {
1084     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1085     HRESULT hres;
1086 
1087     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1088 
1089     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
1090     if(FAILED(hres)) {
1091         WARN("GetBindInfo failed: %08x\n", hres);
1092         return hres;
1093     }
1094 
1095     if((pbindinfo->dwOptions & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS) && !This->redirect_callback) {
1096         IServiceProvider *service_provider;
1097 
1098         hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider, (void**)&service_provider);
1099         if(SUCCEEDED(hres)) {
1100             hres = IServiceProvider_QueryService(service_provider, &IID_IBindCallbackRedirect, &IID_IBindCallbackRedirect,
1101                                                  (void**)&This->redirect_callback);
1102             IServiceProvider_Release(service_provider);
1103         }
1104     }
1105 
1106     *grfBINDF |= BINDF_FROMURLMON;
1107     return hres;
1108 }
1109 
BindInfo_GetBindString(IInternetBindInfo * iface,ULONG ulStringType,LPOLESTR * ppwzStr,ULONG cEl,ULONG * pcElFetched)1110 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
1111         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1112 {
1113     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1114 
1115     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1116 
1117     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
1118 }
1119 
1120 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1121     BindInfo_QueryInterface,
1122     BindInfo_AddRef,
1123     BindInfo_Release,
1124     BindInfo_GetBindInfo,
1125     BindInfo_GetBindString
1126 };
1127 
impl_from_IInternetPriority(IInternetPriority * iface)1128 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
1129 {
1130     return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
1131 }
1132 
InternetPriority_QueryInterface(IInternetPriority * iface,REFIID riid,void ** ppv)1133 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
1134         REFIID riid, void **ppv)
1135 {
1136     BindProtocol *This = impl_from_IInternetPriority(iface);
1137     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1138 }
1139 
InternetPriority_AddRef(IInternetPriority * iface)1140 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
1141 {
1142     BindProtocol *This = impl_from_IInternetPriority(iface);
1143     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1144 }
1145 
InternetPriority_Release(IInternetPriority * iface)1146 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
1147 {
1148     BindProtocol *This = impl_from_IInternetPriority(iface);
1149     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1150 }
1151 
InternetPriority_SetPriority(IInternetPriority * iface,LONG nPriority)1152 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
1153 {
1154     BindProtocol *This = impl_from_IInternetPriority(iface);
1155 
1156     TRACE("(%p)->(%d)\n", This, nPriority);
1157 
1158     This->priority = nPriority;
1159     return S_OK;
1160 }
1161 
InternetPriority_GetPriority(IInternetPriority * iface,LONG * pnPriority)1162 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
1163 {
1164     BindProtocol *This = impl_from_IInternetPriority(iface);
1165 
1166     TRACE("(%p)->(%p)\n", This, pnPriority);
1167 
1168     *pnPriority = This->priority;
1169     return S_OK;
1170 }
1171 
1172 static const IInternetPriorityVtbl InternetPriorityVtbl = {
1173     InternetPriority_QueryInterface,
1174     InternetPriority_AddRef,
1175     InternetPriority_Release,
1176     InternetPriority_SetPriority,
1177     InternetPriority_GetPriority
1178 
1179 };
1180 
impl_from_IInternetProtocolSink(IInternetProtocolSink * iface)1181 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
1182 {
1183     return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
1184 }
1185 
BPInternetProtocolSink_QueryInterface(IInternetProtocolSink * iface,REFIID riid,void ** ppv)1186 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
1187         REFIID riid, void **ppv)
1188 {
1189     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1190     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1191 }
1192 
BPInternetProtocolSink_AddRef(IInternetProtocolSink * iface)1193 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
1194 {
1195     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1196     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1197 }
1198 
BPInternetProtocolSink_Release(IInternetProtocolSink * iface)1199 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
1200 {
1201     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1202     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1203 }
1204 
1205 typedef struct {
1206     task_header_t header;
1207     PROTOCOLDATA *data;
1208 } switch_task_t;
1209 
switch_proc(BindProtocol * bind,task_header_t * t)1210 static void switch_proc(BindProtocol *bind, task_header_t *t)
1211 {
1212     switch_task_t *task = (switch_task_t*)t;
1213 
1214     IInternetProtocol_Continue(bind->protocol_handler, task->data);
1215 
1216     heap_free(task);
1217 }
1218 
BPInternetProtocolSink_Switch(IInternetProtocolSink * iface,PROTOCOLDATA * pProtocolData)1219 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
1220         PROTOCOLDATA *pProtocolData)
1221 {
1222     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1223     PROTOCOLDATA *data;
1224 
1225     TRACE("(%p)->(%p)\n", This, pProtocolData);
1226 
1227     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
1228           pProtocolData->pData, pProtocolData->cbData);
1229 
1230     data = heap_alloc(sizeof(PROTOCOLDATA));
1231     if(!data)
1232         return E_OUTOFMEMORY;
1233     memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
1234 
1235     if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
1236             || !do_direct_notif(This)) {
1237         switch_task_t *task;
1238 
1239         task = heap_alloc(sizeof(switch_task_t));
1240         if(!task)
1241         {
1242             heap_free(data);
1243             return E_OUTOFMEMORY;
1244         }
1245 
1246         task->data = data;
1247 
1248         push_task(This, &task->header, switch_proc);
1249         return S_OK;
1250     }
1251 
1252     return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
1253 }
1254 
1255 typedef struct {
1256     task_header_t header;
1257 
1258     ULONG status_code;
1259     LPWSTR status_text;
1260 } on_progress_task_t;
1261 
on_progress_proc(BindProtocol * This,task_header_t * t)1262 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1263 {
1264     on_progress_task_t *task = (on_progress_task_t*)t;
1265 
1266     IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
1267 
1268     heap_free(task->status_text);
1269     heap_free(task);
1270 }
1271 
BPInternetProtocolSink_ReportProgress(IInternetProtocolSink * iface,ULONG ulStatusCode,LPCWSTR szStatusText)1272 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1273         ULONG ulStatusCode, LPCWSTR szStatusText)
1274 {
1275     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1276 
1277     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1278 
1279     if(do_direct_notif(This)) {
1280         IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
1281     }else {
1282         on_progress_task_t *task;
1283 
1284         task = heap_alloc(sizeof(on_progress_task_t));
1285 
1286         task->status_code = ulStatusCode;
1287         task->status_text = heap_strdupW(szStatusText);
1288 
1289         push_task(This, &task->header, on_progress_proc);
1290     }
1291 
1292     return S_OK;
1293 }
1294 
1295 typedef struct {
1296     task_header_t header;
1297     DWORD bscf;
1298     ULONG progress;
1299     ULONG progress_max;
1300 } report_data_task_t;
1301 
report_data_proc(BindProtocol * This,task_header_t * t)1302 static void report_data_proc(BindProtocol *This, task_header_t *t)
1303 {
1304     report_data_task_t *task = (report_data_task_t*)t;
1305 
1306     IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1307             task->bscf, task->progress, task->progress_max);
1308 
1309     heap_free(task);
1310 }
1311 
BPInternetProtocolSink_ReportData(IInternetProtocolSink * iface,DWORD grfBSCF,ULONG ulProgress,ULONG ulProgressMax)1312 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1313         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1314 {
1315     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1316 
1317     TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1318 
1319     if(!This->protocol_sink)
1320         return S_OK;
1321 
1322     if(!do_direct_notif(This)) {
1323         report_data_task_t *task;
1324 
1325         task = heap_alloc(sizeof(report_data_task_t));
1326         if(!task)
1327             return E_OUTOFMEMORY;
1328 
1329         task->bscf = grfBSCF;
1330         task->progress = ulProgress;
1331         task->progress_max = ulProgressMax;
1332 
1333         push_task(This, &task->header, report_data_proc);
1334         return S_OK;
1335     }
1336 
1337     return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1338             grfBSCF, ulProgress, ulProgressMax);
1339 }
1340 
1341 typedef struct {
1342     task_header_t header;
1343 
1344     HRESULT hres;
1345     DWORD err;
1346     LPWSTR str;
1347 } report_result_task_t;
1348 
report_result_proc(BindProtocol * This,task_header_t * t)1349 static void report_result_proc(BindProtocol *This, task_header_t *t)
1350 {
1351     report_result_task_t *task = (report_result_task_t*)t;
1352 
1353     IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
1354 
1355     heap_free(task->str);
1356     heap_free(task);
1357 }
1358 
BPInternetProtocolSink_ReportResult(IInternetProtocolSink * iface,HRESULT hrResult,DWORD dwError,LPCWSTR szResult)1359 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1360         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1361 {
1362     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1363 
1364     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1365 
1366     if(!This->protocol_sink)
1367         return E_FAIL;
1368     This->reported_result = TRUE;
1369 
1370     if(!do_direct_notif(This)) {
1371         report_result_task_t *task;
1372 
1373         task = heap_alloc(sizeof(report_result_task_t));
1374         if(!task)
1375             return E_OUTOFMEMORY;
1376 
1377         task->hres = hrResult;
1378         task->err = dwError;
1379         task->str = heap_strdupW(szResult);
1380 
1381         push_task(This, &task->header, report_result_proc);
1382         return S_OK;
1383     }
1384 
1385     return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
1386 }
1387 
1388 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1389     BPInternetProtocolSink_QueryInterface,
1390     BPInternetProtocolSink_AddRef,
1391     BPInternetProtocolSink_Release,
1392     BPInternetProtocolSink_Switch,
1393     BPInternetProtocolSink_ReportProgress,
1394     BPInternetProtocolSink_ReportData,
1395     BPInternetProtocolSink_ReportResult
1396 };
1397 
impl_from_IServiceProvider(IServiceProvider * iface)1398 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1399 {
1400     return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1401 }
1402 
BPServiceProvider_QueryInterface(IServiceProvider * iface,REFIID riid,void ** ppv)1403 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1404         REFIID riid, void **ppv)
1405 {
1406     BindProtocol *This = impl_from_IServiceProvider(iface);
1407     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1408 }
1409 
BPServiceProvider_AddRef(IServiceProvider * iface)1410 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1411 {
1412     BindProtocol *This = impl_from_IServiceProvider(iface);
1413     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1414 }
1415 
BPServiceProvider_Release(IServiceProvider * iface)1416 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1417 {
1418     BindProtocol *This = impl_from_IServiceProvider(iface);
1419     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1420 }
1421 
BPServiceProvider_QueryService(IServiceProvider * iface,REFGUID guidService,REFIID riid,void ** ppv)1422 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1423         REFGUID guidService, REFIID riid, void **ppv)
1424 {
1425     BindProtocol *This = impl_from_IServiceProvider(iface);
1426 
1427     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1428 
1429     if(!This->service_provider)
1430         return E_NOINTERFACE;
1431 
1432     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1433 }
1434 
1435 static const IServiceProviderVtbl ServiceProviderVtbl = {
1436     BPServiceProvider_QueryInterface,
1437     BPServiceProvider_AddRef,
1438     BPServiceProvider_Release,
1439     BPServiceProvider_QueryService
1440 };
1441 
create_binding_protocol(BindProtocol ** protocol)1442 HRESULT create_binding_protocol(BindProtocol **protocol)
1443 {
1444     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1445 
1446     ret->IInternetProtocolEx_iface.lpVtbl   = &BindProtocolVtbl;
1447     ret->IInternetBindInfo_iface.lpVtbl     = &InternetBindInfoVtbl;
1448     ret->IInternetPriority_iface.lpVtbl     = &InternetPriorityVtbl;
1449     ret->IServiceProvider_iface.lpVtbl      = &ServiceProviderVtbl;
1450     ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1451 
1452     ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1453     ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1454 
1455     ret->ref = 1;
1456     ret->apartment_thread = GetCurrentThreadId();
1457     ret->notif_hwnd = get_notif_hwnd();
1458     ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1459     ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1460     InitializeCriticalSection(&ret->section);
1461     ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1462 
1463     URLMON_LockModule();
1464 
1465     *protocol = ret;
1466     return S_OK;
1467 }
1468