urlmon: Fixed memory leaks in tests.
[wine.git] / dlls / urlmon / bindprot.c
blob095194ed0ea8833316b0dc9c07050cbd7338b644
1 /*
2 * Copyright 2007-2009 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef void (*task_proc_t)(BindProtocol*,task_header_t*);
26 struct _task_header_t {
27 task_proc_t proc;
28 task_header_t *next;
31 #define BUFFER_SIZE 2048
32 #define MIME_TEST_SIZE 255
34 #define WM_MK_CONTINUE (WM_USER+101)
35 #define WM_MK_RELEASE (WM_USER+102)
37 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
39 switch(msg) {
40 case WM_MK_CONTINUE: {
41 BindProtocol *This = (BindProtocol*)lParam;
42 task_header_t *task;
44 while(1) {
45 EnterCriticalSection(&This->section);
47 task = This->task_queue_head;
48 if(task) {
49 This->task_queue_head = task->next;
50 if(!This->task_queue_head)
51 This->task_queue_tail = NULL;
54 LeaveCriticalSection(&This->section);
56 if(!task)
57 break;
59 This->continue_call++;
60 task->proc(This, task);
61 This->continue_call--;
64 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
65 return 0;
67 case WM_MK_RELEASE: {
68 tls_data_t *data = get_tls_data();
70 if(!--data->notif_hwnd_cnt) {
71 DestroyWindow(hwnd);
72 data->notif_hwnd = NULL;
77 return DefWindowProcW(hwnd, msg, wParam, lParam);
80 HWND get_notif_hwnd(void)
82 static ATOM wnd_class = 0;
83 tls_data_t *tls_data;
85 static const WCHAR wszURLMonikerNotificationWindow[] =
86 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
87 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
89 tls_data = get_tls_data();
90 if(!tls_data)
91 return NULL;
93 if(tls_data->notif_hwnd_cnt) {
94 tls_data->notif_hwnd_cnt++;
95 return tls_data->notif_hwnd;
98 if(!wnd_class) {
99 static WNDCLASSEXW wndclass = {
100 sizeof(wndclass), 0,
101 notif_wnd_proc, 0, 0,
102 NULL, NULL, NULL, NULL, NULL,
103 wszURLMonikerNotificationWindow,
104 NULL
107 wndclass.hInstance = hProxyDll;
109 wnd_class = RegisterClassExW(&wndclass);
110 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
111 wnd_class = 1;
114 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
115 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
116 NULL, hProxyDll, NULL);
117 if(tls_data->notif_hwnd)
118 tls_data->notif_hwnd_cnt++;
120 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
122 return tls_data->notif_hwnd;
125 void release_notif_hwnd(HWND hwnd)
127 tls_data_t *data = get_tls_data();
129 if(!data)
130 return;
132 if(data->notif_hwnd != hwnd) {
133 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
134 return;
137 if(!--data->notif_hwnd_cnt) {
138 DestroyWindow(data->notif_hwnd);
139 data->notif_hwnd = NULL;
143 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
145 BOOL do_post = FALSE;
147 task->proc = proc;
148 task->next = NULL;
150 EnterCriticalSection(&This->section);
152 if(This->task_queue_tail) {
153 This->task_queue_tail->next = task;
154 This->task_queue_tail = task;
155 }else {
156 This->task_queue_tail = This->task_queue_head = task;
157 do_post = !This->continue_call;
160 LeaveCriticalSection(&This->section);
162 if(do_post) {
163 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
164 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
168 static inline BOOL do_direct_notif(BindProtocol *This)
170 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
173 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
175 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
176 IInternetProtocolSink *protocol_sink, *old_sink;
177 ProtocolProxy *filter_proxy;
178 HRESULT hres;
180 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
181 if(FAILED(hres))
182 return hres;
184 hres = create_protocol_proxy(&This->default_protocol_handler.IInternetProtocol_iface, This->protocol_sink, &filter_proxy);
185 if(FAILED(hres)) {
186 IInternetProtocolSink_Release(protocol_sink);
187 return hres;
190 old_sink = This->protocol_sink;
191 This->protocol_sink = protocol_sink;
192 This->filter_proxy = filter_proxy;
194 IInternetProtocol_AddRef(mime_filter);
195 This->protocol_handler = mime_filter;
197 filter_data.pProtocol = &filter_proxy->IInternetProtocol_iface;
198 hres = IInternetProtocol_Start(mime_filter, mime, &filter_proxy->IInternetProtocolSink_iface,
199 &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC,
200 (HANDLE_PTR)&filter_data);
201 if(FAILED(hres)) {
202 IInternetProtocolSink_Release(old_sink);
203 return hres;
206 IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
207 IInternetProtocolSink_Release(old_sink);
209 This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
210 return S_OK;
213 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
215 IInternetProtocol *mime_filter;
216 HRESULT hres;
218 heap_free(This->mime);
219 This->mime = NULL;
221 mime_filter = get_mime_filter(mime);
222 if(mime_filter) {
223 TRACE("Got mime filter for %s\n", debugstr_w(mime));
225 hres = handle_mime_filter(This, mime_filter, mime);
226 IInternetProtocol_Release(mime_filter);
227 if(FAILED(hres))
228 FIXME("MIME filter failed: %08x\n", hres);
229 }else {
230 This->mime = heap_strdupW(mime);
232 if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
233 This->reported_mime = TRUE;
235 if(This->protocol_sink)
236 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
241 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
243 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
246 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
248 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
250 *ppv = NULL;
251 if(IsEqualGUID(&IID_IUnknown, riid)) {
252 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
253 *ppv = &This->IInternetProtocolEx_iface;
254 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
255 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
256 *ppv = &This->IInternetProtocolEx_iface;
257 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
258 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
259 *ppv = &This->IInternetProtocolEx_iface;
260 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
261 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
262 *ppv = &This->IInternetProtocolEx_iface;
263 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
264 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
265 *ppv = &This->IInternetBindInfo_iface;
266 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
267 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
268 *ppv = &This->IInternetPriority_iface;
269 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
270 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
271 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
272 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
273 *ppv = &This->IServiceProvider_iface;
274 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
275 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
276 *ppv = &This->IInternetProtocolSink_iface;
277 }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
278 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
280 if(This->protocol) {
281 IWinInetInfo *inet_info;
282 HRESULT hres;
284 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
285 if(SUCCEEDED(hres)) {
286 *ppv = &This->IWinInetHttpInfo_iface;
287 IWinInetInfo_Release(inet_info);
290 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
291 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
293 if(This->protocol) {
294 IWinInetHttpInfo *http_info;
295 HRESULT hres;
297 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
298 if(SUCCEEDED(hres)) {
299 *ppv = &This->IWinInetHttpInfo_iface;
300 IWinInetHttpInfo_Release(http_info);
303 }else {
304 WARN("not supported interface %s\n", debugstr_guid(riid));
307 if(!*ppv)
308 return E_NOINTERFACE;
310 IUnknown_AddRef((IUnknown*)*ppv);
311 return S_OK;
314 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
316 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
317 LONG ref = InterlockedIncrement(&This->ref);
318 TRACE("(%p) ref=%d\n", This, ref);
319 return ref;
322 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
324 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
325 LONG ref = InterlockedDecrement(&This->ref);
327 TRACE("(%p) ref=%d\n", This, ref);
329 if(!ref) {
330 if(This->wininet_info)
331 IWinInetInfo_Release(This->wininet_info);
332 if(This->protocol)
333 IInternetProtocol_Release(This->protocol);
334 if(This->bind_info)
335 IInternetBindInfo_Release(This->bind_info);
336 if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface)
337 IInternetProtocol_Release(This->protocol_handler);
338 if(This->filter_proxy)
339 IInternetProtocol_Release(&This->filter_proxy->IInternetProtocol_iface);
340 if(This->uri)
341 IUri_Release(This->uri);
343 set_binding_sink(This, NULL, NULL);
345 if(This->notif_hwnd)
346 release_notif_hwnd(This->notif_hwnd);
347 DeleteCriticalSection(&This->section);
349 heap_free(This->mime);
350 heap_free(This);
352 URLMON_UnlockModule();
355 return ref;
358 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
359 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
360 DWORD grfPI, HANDLE_PTR dwReserved)
362 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
363 IUri *uri;
364 HRESULT hres;
366 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
367 pOIBindInfo, grfPI, dwReserved);
369 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
370 if(FAILED(hres))
371 return hres;
373 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
374 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
376 IUri_Release(uri);
377 return hres;
380 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
382 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
384 TRACE("(%p)->(%p)\n", This, pProtocolData);
386 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
389 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
390 DWORD dwOptions)
392 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
394 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
396 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
399 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
401 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
403 TRACE("(%p)->(%08x)\n", This, dwOptions);
405 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
408 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
410 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
411 FIXME("(%p)\n", This);
412 return E_NOTIMPL;
415 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
417 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
418 FIXME("(%p)\n", This);
419 return E_NOTIMPL;
422 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
423 ULONG cb, ULONG *pcbRead)
425 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
427 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
429 if(pcbRead)
430 *pcbRead = 0;
431 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
434 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
435 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
437 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
438 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
439 return E_NOTIMPL;
442 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
444 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
446 TRACE("(%p)->(%08x)\n", This, dwOptions);
448 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
451 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
453 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
455 TRACE("(%p)\n", This);
457 return IInternetProtocol_UnlockRequest(This->protocol_handler);
460 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
461 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
462 DWORD grfPI, HANDLE *dwReserved)
464 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
465 IInternetProtocol *protocol = NULL;
466 IInternetProtocolEx *protocolex;
467 IInternetPriority *priority;
468 IServiceProvider *service_provider;
469 BOOL urlmon_protocol = FALSE;
470 CLSID clsid = IID_NULL;
471 LPOLESTR clsid_str;
472 HRESULT hres;
474 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
476 if(!pUri || !pOIProtSink || !pOIBindInfo)
477 return E_INVALIDARG;
479 This->pi = grfPI;
481 IUri_AddRef(pUri);
482 This->uri = pUri;
484 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
485 (void**)&service_provider);
486 if(SUCCEEDED(hres)) {
487 /* FIXME: What's protocol CLSID here? */
488 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
489 &IID_IInternetProtocol, (void**)&protocol);
490 IServiceProvider_Release(service_provider);
493 if(!protocol) {
494 IClassFactory *cf;
495 IUnknown *unk;
497 hres = get_protocol_handler(pUri, &clsid, &urlmon_protocol, &cf);
498 if(FAILED(hres))
499 return hres;
501 if(This->from_urlmon) {
502 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
503 IClassFactory_Release(cf);
504 if(FAILED(hres))
505 return hres;
506 }else {
507 hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
508 &IID_IUnknown, (void**)&unk);
509 IClassFactory_Release(cf);
510 if(FAILED(hres))
511 return hres;
513 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
514 IUnknown_Release(unk);
515 if(FAILED(hres))
516 return hres;
520 StringFromCLSID(&clsid, &clsid_str);
521 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
522 CoTaskMemFree(clsid_str);
524 This->protocol = protocol;
526 if(urlmon_protocol)
527 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
529 set_binding_sink(This, pOIProtSink, pOIBindInfo);
531 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
532 if(SUCCEEDED(hres)) {
533 IInternetPriority_SetPriority(priority, This->priority);
534 IInternetPriority_Release(priority);
537 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
538 if(SUCCEEDED(hres)) {
539 hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
540 &This->IInternetBindInfo_iface, 0, NULL);
541 IInternetProtocolEx_Release(protocolex);
542 }else {
543 BSTR display_uri;
545 hres = IUri_GetDisplayUri(pUri, &display_uri);
546 if(FAILED(hres))
547 return hres;
549 hres = IInternetProtocol_Start(protocol, display_uri, &This->IInternetProtocolSink_iface,
550 &This->IInternetBindInfo_iface, 0, 0);
551 SysFreeString(display_uri);
554 return hres;
557 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
559 IInternetProtocolSink *prev_sink;
560 IServiceProvider *service_provider = NULL;
562 if(sink)
563 IInternetProtocolSink_AddRef(sink);
564 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
565 if(prev_sink)
566 IInternetProtocolSink_Release(prev_sink);
568 if(sink)
569 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
570 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
571 if(service_provider)
572 IServiceProvider_Release(service_provider);
574 if(bind_info)
575 IInternetBindInfo_AddRef(bind_info);
576 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
577 if(bind_info)
578 IInternetBindInfo_Release(bind_info);
581 static const IInternetProtocolExVtbl BindProtocolVtbl = {
582 BindProtocol_QueryInterface,
583 BindProtocol_AddRef,
584 BindProtocol_Release,
585 BindProtocol_Start,
586 BindProtocol_Continue,
587 BindProtocol_Abort,
588 BindProtocol_Terminate,
589 BindProtocol_Suspend,
590 BindProtocol_Resume,
591 BindProtocol_Read,
592 BindProtocol_Seek,
593 BindProtocol_LockRequest,
594 BindProtocol_UnlockRequest,
595 BindProtocol_StartEx
598 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
600 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
603 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
605 ERR("should not be called\n");
606 return E_NOINTERFACE;
609 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
611 BindProtocol *This = impl_from_IInternetProtocol(iface);
612 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
615 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
617 BindProtocol *This = impl_from_IInternetProtocol(iface);
618 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
621 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
622 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
623 DWORD grfPI, HANDLE_PTR dwReserved)
625 ERR("Should not be called\n");
626 return E_NOTIMPL;
629 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
631 BindProtocol *This = impl_from_IInternetProtocol(iface);
632 HRESULT hres;
634 TRACE("(%p)->(%p)\n", This, pProtocolData);
636 hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
638 heap_free(pProtocolData);
639 return hres;
642 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
643 DWORD dwOptions)
645 BindProtocol *This = impl_from_IInternetProtocol(iface);
647 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
649 if(This->protocol && !This->reported_result)
650 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
652 return S_OK;
655 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
657 BindProtocol *This = impl_from_IInternetProtocol(iface);
659 TRACE("(%p)->(%08x)\n", This, dwOptions);
661 if(!This->reported_result)
662 return E_FAIL;
664 IInternetProtocol_Terminate(This->protocol, 0);
666 if(This->filter_proxy) {
667 IInternetProtocol_Release(&This->filter_proxy->IInternetProtocol_iface);
668 This->filter_proxy = NULL;
671 set_binding_sink(This, NULL, NULL);
673 if(This->bind_info) {
674 IInternetBindInfo_Release(This->bind_info);
675 This->bind_info = NULL;
678 return S_OK;
681 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
683 BindProtocol *This = impl_from_IInternetProtocol(iface);
684 FIXME("(%p)\n", This);
685 return E_NOTIMPL;
688 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
690 BindProtocol *This = impl_from_IInternetProtocol(iface);
691 FIXME("(%p)\n", This);
692 return E_NOTIMPL;
695 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
696 ULONG cb, ULONG *pcbRead)
698 BindProtocol *This = impl_from_IInternetProtocol(iface);
699 ULONG read = 0;
700 HRESULT hres = S_OK;
702 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
704 if(This->buf_size) {
705 read = min(cb, This->buf_size);
706 memcpy(pv, This->buf, read);
708 if(read == This->buf_size) {
709 heap_free(This->buf);
710 This->buf = NULL;
711 }else {
712 memmove(This->buf, This->buf+cb, This->buf_size-cb);
715 This->buf_size -= read;
718 if(read < cb) {
719 ULONG cread = 0;
721 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
722 read += cread;
725 *pcbRead = read;
726 return hres;
729 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
730 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
732 BindProtocol *This = impl_from_IInternetProtocol(iface);
733 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
734 return E_NOTIMPL;
737 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
739 BindProtocol *This = impl_from_IInternetProtocol(iface);
741 TRACE("(%p)->(%08x)\n", This, dwOptions);
743 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
746 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
748 BindProtocol *This = impl_from_IInternetProtocol(iface);
750 TRACE("(%p)\n", This);
752 return IInternetProtocol_UnlockRequest(This->protocol);
755 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
756 ProtocolHandler_QueryInterface,
757 ProtocolHandler_AddRef,
758 ProtocolHandler_Release,
759 ProtocolHandler_Start,
760 ProtocolHandler_Continue,
761 ProtocolHandler_Abort,
762 ProtocolHandler_Terminate,
763 ProtocolHandler_Suspend,
764 ProtocolHandler_Resume,
765 ProtocolHandler_Read,
766 ProtocolHandler_Seek,
767 ProtocolHandler_LockRequest,
768 ProtocolHandler_UnlockRequest
771 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
773 return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
776 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
777 REFIID riid, void **ppv)
779 BindProtocol *This = impl_from_IInternetBindInfo(iface);
780 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
783 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
785 BindProtocol *This = impl_from_IInternetBindInfo(iface);
786 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
789 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
791 BindProtocol *This = impl_from_IInternetBindInfo(iface);
792 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
795 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
796 DWORD *grfBINDF, BINDINFO *pbindinfo)
798 BindProtocol *This = impl_from_IInternetBindInfo(iface);
799 HRESULT hres;
801 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
803 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
804 if(FAILED(hres)) {
805 WARN("GetBindInfo failed: %08x\n", hres);
806 return hres;
809 *grfBINDF |= BINDF_FROMURLMON;
810 return hres;
813 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
814 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
816 BindProtocol *This = impl_from_IInternetBindInfo(iface);
818 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
820 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
823 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
824 BindInfo_QueryInterface,
825 BindInfo_AddRef,
826 BindInfo_Release,
827 BindInfo_GetBindInfo,
828 BindInfo_GetBindString
831 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
833 return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
836 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
837 REFIID riid, void **ppv)
839 BindProtocol *This = impl_from_IInternetPriority(iface);
840 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
843 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
845 BindProtocol *This = impl_from_IInternetPriority(iface);
846 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
849 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
851 BindProtocol *This = impl_from_IInternetPriority(iface);
852 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
855 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
857 BindProtocol *This = impl_from_IInternetPriority(iface);
859 TRACE("(%p)->(%d)\n", This, nPriority);
861 This->priority = nPriority;
862 return S_OK;
865 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
867 BindProtocol *This = impl_from_IInternetPriority(iface);
869 TRACE("(%p)->(%p)\n", This, pnPriority);
871 *pnPriority = This->priority;
872 return S_OK;
875 static const IInternetPriorityVtbl InternetPriorityVtbl = {
876 InternetPriority_QueryInterface,
877 InternetPriority_AddRef,
878 InternetPriority_Release,
879 InternetPriority_SetPriority,
880 InternetPriority_GetPriority
884 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
886 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
889 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
890 REFIID riid, void **ppv)
892 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
893 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
896 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
898 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
899 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
902 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
904 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
905 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
908 typedef struct {
909 task_header_t header;
910 PROTOCOLDATA *data;
911 } switch_task_t;
913 static void switch_proc(BindProtocol *bind, task_header_t *t)
915 switch_task_t *task = (switch_task_t*)t;
917 IInternetProtocol_Continue(bind->protocol_handler, task->data);
919 heap_free(task);
922 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
923 PROTOCOLDATA *pProtocolData)
925 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
926 PROTOCOLDATA *data;
928 TRACE("(%p)->(%p)\n", This, pProtocolData);
930 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
931 pProtocolData->pData, pProtocolData->cbData);
933 data = heap_alloc(sizeof(PROTOCOLDATA));
934 if(!data)
935 return E_OUTOFMEMORY;
936 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
938 if(!do_direct_notif(This)) {
939 switch_task_t *task;
941 task = heap_alloc(sizeof(switch_task_t));
942 if(!task)
943 return E_OUTOFMEMORY;
945 task->data = data;
947 push_task(This, &task->header, switch_proc);
948 return S_OK;
951 if(!This->protocol_sink) {
952 IInternetProtocol_Continue(This->protocol_handler, data);
953 return S_OK;
956 return IInternetProtocolSink_Switch(This->protocol_sink, data);
959 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
961 switch(status_code) {
962 case BINDSTATUS_FINDINGRESOURCE:
963 case BINDSTATUS_CONNECTING:
964 case BINDSTATUS_REDIRECTING:
965 case BINDSTATUS_BEGINDOWNLOADDATA:
966 case BINDSTATUS_SENDINGREQUEST:
967 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
968 case BINDSTATUS_DIRECTBIND:
969 case BINDSTATUS_ACCEPTRANGES:
970 if(This->protocol_sink)
971 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
972 break;
974 case BINDSTATUS_MIMETYPEAVAILABLE:
975 mime_available(This, status_text, FALSE);
976 break;
978 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
979 mime_available(This, status_text, TRUE);
980 break;
982 default:
983 FIXME("unsupported ulStatusCode %u\n", status_code);
987 typedef struct {
988 task_header_t header;
990 ULONG status_code;
991 LPWSTR status_text;
992 } on_progress_task_t;
994 static void on_progress_proc(BindProtocol *This, task_header_t *t)
996 on_progress_task_t *task = (on_progress_task_t*)t;
998 report_progress(This, task->status_code, task->status_text);
1000 heap_free(task->status_text);
1001 heap_free(task);
1004 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1005 ULONG ulStatusCode, LPCWSTR szStatusText)
1007 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1009 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1011 if(do_direct_notif(This)) {
1012 report_progress(This, ulStatusCode, szStatusText);
1013 }else {
1014 on_progress_task_t *task;
1016 task = heap_alloc(sizeof(on_progress_task_t));
1018 task->status_code = ulStatusCode;
1019 task->status_text = heap_strdupW(szStatusText);
1021 push_task(This, &task->header, on_progress_proc);
1024 return S_OK;
1027 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
1029 if(!This->protocol_sink)
1030 return S_OK;
1032 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
1033 BYTE buf[BUFFER_SIZE];
1034 DWORD read = 0;
1035 LPWSTR mime;
1036 HRESULT hres;
1038 do {
1039 read = 0;
1040 hres = IInternetProtocol_Read(This->protocol, buf,
1041 sizeof(buf)-This->buf_size, &read);
1042 if(FAILED(hres) && hres != E_PENDING)
1043 return hres;
1045 if(!This->buf) {
1046 This->buf = heap_alloc(BUFFER_SIZE);
1047 if(!This->buf)
1048 return E_OUTOFMEMORY;
1049 }else if(read + This->buf_size > BUFFER_SIZE) {
1050 BYTE *tmp;
1052 tmp = heap_realloc(This->buf, read+This->buf_size);
1053 if(!tmp)
1054 return E_OUTOFMEMORY;
1055 This->buf = tmp;
1058 memcpy(This->buf+This->buf_size, buf, read);
1059 This->buf_size += read;
1060 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1062 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1063 return S_OK;
1065 bscf = BSCF_FIRSTDATANOTIFICATION;
1066 if(hres == S_FALSE)
1067 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
1069 if(!This->reported_mime) {
1070 BSTR raw_uri;
1072 hres = IUri_GetRawUri(This->uri, &raw_uri);
1073 if(FAILED(hres))
1074 return hres;
1076 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1077 This->mime, 0, &mime, 0);
1078 SysFreeString(raw_uri);
1079 if(FAILED(hres))
1080 return hres;
1082 mime_available(This, mime, TRUE);
1083 CoTaskMemFree(mime);
1087 if(!This->protocol_sink)
1088 return S_OK;
1090 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1093 typedef struct {
1094 task_header_t header;
1095 DWORD bscf;
1096 ULONG progress;
1097 ULONG progress_max;
1098 } report_data_task_t;
1100 static void report_data_proc(BindProtocol *This, task_header_t *t)
1102 report_data_task_t *task = (report_data_task_t*)t;
1104 report_data(This, task->bscf, task->progress, task->progress_max);
1105 heap_free(task);
1108 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1109 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1111 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1113 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1115 if(!This->protocol_sink)
1116 return S_OK;
1118 if(!do_direct_notif(This)) {
1119 report_data_task_t *task;
1121 task = heap_alloc(sizeof(report_data_task_t));
1122 if(!task)
1123 return E_OUTOFMEMORY;
1125 task->bscf = grfBSCF;
1126 task->progress = ulProgress;
1127 task->progress_max = ulProgressMax;
1129 push_task(This, &task->header, report_data_proc);
1130 return S_OK;
1133 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1136 typedef struct {
1137 task_header_t header;
1139 HRESULT hres;
1140 DWORD err;
1141 LPWSTR str;
1142 } report_result_task_t;
1144 static void report_result_proc(BindProtocol *This, task_header_t *t)
1146 report_result_task_t *task = (report_result_task_t*)t;
1148 if(This->protocol_sink)
1149 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1151 heap_free(task->str);
1152 heap_free(task);
1155 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1156 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1158 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1160 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1162 if(!This->protocol_sink)
1163 return E_FAIL;
1165 This->reported_result = TRUE;
1167 if(!do_direct_notif(This)) {
1168 report_result_task_t *task;
1170 task = heap_alloc(sizeof(report_result_task_t));
1171 if(!task)
1172 return E_OUTOFMEMORY;
1174 task->hres = hrResult;
1175 task->err = dwError;
1176 task->str = heap_strdupW(szResult);
1178 push_task(This, &task->header, report_result_proc);
1179 return S_OK;
1182 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1185 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1186 BPInternetProtocolSink_QueryInterface,
1187 BPInternetProtocolSink_AddRef,
1188 BPInternetProtocolSink_Release,
1189 BPInternetProtocolSink_Switch,
1190 BPInternetProtocolSink_ReportProgress,
1191 BPInternetProtocolSink_ReportData,
1192 BPInternetProtocolSink_ReportResult
1195 static inline BindProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1197 return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
1200 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1202 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1203 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1206 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1208 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1209 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1212 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1214 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1215 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1218 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1219 void *pBuffer, DWORD *pcbBuffer)
1221 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1222 FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1223 return E_NOTIMPL;
1226 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1227 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1229 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1230 FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1231 return E_NOTIMPL;
1234 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1235 WinInetHttpInfo_QueryInterface,
1236 WinInetHttpInfo_AddRef,
1237 WinInetHttpInfo_Release,
1238 WinInetHttpInfo_QueryOption,
1239 WinInetHttpInfo_QueryInfo
1242 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1244 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1247 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1248 REFIID riid, void **ppv)
1250 BindProtocol *This = impl_from_IServiceProvider(iface);
1251 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1254 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1256 BindProtocol *This = impl_from_IServiceProvider(iface);
1257 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1260 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1262 BindProtocol *This = impl_from_IServiceProvider(iface);
1263 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1266 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1267 REFGUID guidService, REFIID riid, void **ppv)
1269 BindProtocol *This = impl_from_IServiceProvider(iface);
1271 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1273 if(!This->service_provider)
1274 return E_NOINTERFACE;
1276 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1279 static const IServiceProviderVtbl ServiceProviderVtbl = {
1280 BPServiceProvider_QueryInterface,
1281 BPServiceProvider_AddRef,
1282 BPServiceProvider_Release,
1283 BPServiceProvider_QueryService
1286 HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
1288 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1290 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl;
1291 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
1292 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
1293 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1294 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1295 ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl;
1297 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1299 ret->ref = 1;
1300 ret->from_urlmon = from_urlmon;
1301 ret->apartment_thread = GetCurrentThreadId();
1302 ret->notif_hwnd = get_notif_hwnd();
1303 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1304 InitializeCriticalSection(&ret->section);
1306 URLMON_LockModule();
1308 *protocol = ret;
1309 return S_OK;