urlmon: Improved ERROR_INTERNET_SEC_CERT_REV_FAILED error handling.
[wine/multimedia.git] / dlls / urlmon / http.c
blobd5f2b33780f0ea073f8d63747823683733cb9836
1 /*
2 * Copyright 2005 Jacek Caban
3 * Copyright 2007 Misha Koshelev
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "urlmon_main.h"
21 #include "wininet.h"
23 #define NO_SHLWAPI_REG
24 #include "shlwapi.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
30 typedef struct {
31 Protocol base;
33 IInternetProtocolEx IInternetProtocolEx_iface;
34 IInternetPriority IInternetPriority_iface;
35 IWinInetHttpInfo IWinInetHttpInfo_iface;
37 BOOL https;
38 IHttpNegotiate *http_negotiate;
39 WCHAR *full_header;
41 LONG ref;
42 } HttpProtocol;
44 static inline HttpProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
46 return CONTAINING_RECORD(iface, HttpProtocol, IInternetProtocolEx_iface);
49 static inline HttpProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
51 return CONTAINING_RECORD(iface, HttpProtocol, IInternetPriority_iface);
54 static inline HttpProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
56 return CONTAINING_RECORD(iface, HttpProtocol, IWinInetHttpInfo_iface);
59 static const WCHAR default_headersW[] = {
60 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',':',' ','g','z','i','p',',',' ','d','e','f','l','a','t','e',0};
62 static LPWSTR query_http_info(HttpProtocol *This, DWORD option)
64 LPWSTR ret = NULL;
65 DWORD len = 0;
66 BOOL res;
68 res = HttpQueryInfoW(This->base.request, option, NULL, &len, NULL);
69 if (!res && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
70 ret = heap_alloc(len);
71 res = HttpQueryInfoW(This->base.request, option, ret, &len, NULL);
73 if(!res) {
74 TRACE("HttpQueryInfoW(%d) failed: %08x\n", option, GetLastError());
75 heap_free(ret);
76 return NULL;
79 return ret;
82 static inline BOOL set_security_flag(HttpProtocol *This, DWORD new_flag)
84 DWORD flags, size = sizeof(flags);
85 BOOL res;
87 res = InternetQueryOptionW(This->base.request, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size);
88 if(res) {
89 flags |= new_flag;
90 res = InternetSetOptionW(This->base.request, INTERNET_OPTION_SECURITY_FLAGS, &flags, size);
92 if(!res)
93 ERR("Failed to set security flag(s): %x\n", new_flag);
95 return res;
98 static inline HRESULT internet_error_to_hres(DWORD error)
100 switch(error)
102 case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
103 case ERROR_INTERNET_SEC_CERT_CN_INVALID:
104 case ERROR_INTERNET_INVALID_CA:
105 case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
106 case ERROR_INTERNET_SEC_INVALID_CERT:
107 case ERROR_INTERNET_SEC_CERT_ERRORS:
108 case ERROR_INTERNET_SEC_CERT_REV_FAILED:
109 case ERROR_INTERNET_SEC_CERT_NO_REV:
110 case ERROR_INTERNET_SEC_CERT_REVOKED:
111 return INET_E_INVALID_CERTIFICATE;
112 case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
113 case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
114 case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION:
115 return INET_E_REDIRECT_FAILED;
116 default:
117 return INET_E_DOWNLOAD_FAILURE;
121 static HRESULT handle_http_error(HttpProtocol *This, DWORD error)
123 IServiceProvider *serv_prov;
124 IWindowForBindingUI *wfb_ui;
125 IHttpSecurity *http_security;
126 BOOL security_problem;
127 DWORD dlg_flags;
128 HWND hwnd;
129 DWORD res;
130 HRESULT hres;
132 switch(error) {
133 case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
134 case ERROR_INTERNET_SEC_CERT_CN_INVALID:
135 case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
136 case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
137 case ERROR_INTERNET_INVALID_CA:
138 case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
139 case ERROR_INTERNET_SEC_INVALID_CERT:
140 case ERROR_INTERNET_SEC_CERT_ERRORS:
141 case ERROR_INTERNET_SEC_CERT_REV_FAILED:
142 case ERROR_INTERNET_SEC_CERT_NO_REV:
143 case ERROR_INTERNET_SEC_CERT_REVOKED:
144 case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION:
145 security_problem = TRUE;
146 break;
147 default:
148 security_problem = FALSE;
151 hres = IInternetProtocolSink_QueryInterface(This->base.protocol_sink, &IID_IServiceProvider,
152 (void**)&serv_prov);
153 if(FAILED(hres)) {
154 ERR("Failed to get IServiceProvider.\n");
155 return E_ABORT;
158 if(security_problem) {
159 hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpSecurity, &IID_IHttpSecurity,
160 (void**)&http_security);
161 if(SUCCEEDED(hres)) {
162 hres = IHttpSecurity_OnSecurityProblem(http_security, error);
163 IHttpSecurity_Release(http_security);
165 if(hres != S_FALSE)
167 BOOL res = FALSE;
169 IServiceProvider_Release(serv_prov);
171 if(hres == S_OK) {
172 if(error == ERROR_INTERNET_SEC_CERT_DATE_INVALID)
173 res = set_security_flag(This, SECURITY_FLAG_IGNORE_CERT_DATE_INVALID);
174 else if(error == ERROR_INTERNET_SEC_CERT_CN_INVALID)
175 res = set_security_flag(This, SECURITY_FLAG_IGNORE_CERT_CN_INVALID);
176 else if(error == ERROR_INTERNET_INVALID_CA)
177 res = set_security_flag(This, SECURITY_FLAG_IGNORE_UNKNOWN_CA);
179 if(res)
180 return RPC_E_RETRY;
182 FIXME("Don't know how to ignore error %d\n", error);
183 return E_ABORT;
186 if(hres == E_ABORT)
187 return E_ABORT;
188 if(hres == RPC_E_RETRY)
189 return RPC_E_RETRY;
191 return internet_error_to_hres(error);
196 switch(error) {
197 case ERROR_INTERNET_SEC_CERT_REV_FAILED:
198 if(hres == S_FALSE) {
199 hres = internet_error_to_hres(error);
200 }else {
201 /* Silently ignore the error. We will get more detailed error from wininet anyway. */
202 set_security_flag(This, SECURITY_FLAG_IGNORE_REVOCATION);
203 hres = RPC_E_RETRY;
205 break;
207 default:
208 hres = IServiceProvider_QueryService(serv_prov, &IID_IWindowForBindingUI, &IID_IWindowForBindingUI, (void**)&wfb_ui);
209 if(SUCCEEDED(hres)) {
210 const IID *iid_reason;
212 if(security_problem)
213 iid_reason = &IID_IHttpSecurity;
214 else if(error == ERROR_INTERNET_INCORRECT_PASSWORD)
215 iid_reason = &IID_IAuthenticate;
216 else
217 iid_reason = &IID_IWindowForBindingUI;
219 hres = IWindowForBindingUI_GetWindow(wfb_ui, iid_reason, &hwnd);
220 IWindowForBindingUI_Release(wfb_ui);
221 if(FAILED(hres))
222 hwnd = NULL;
226 dlg_flags = FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA;
227 if(This->base.bindf & BINDF_NO_UI)
228 dlg_flags |= FLAGS_ERROR_UI_FLAGS_NO_UI;
230 res = InternetErrorDlg(hwnd, This->base.request, error, dlg_flags, NULL);
231 hres = res == ERROR_INTERNET_FORCE_RETRY || res == ERROR_SUCCESS ? RPC_E_RETRY : internet_error_to_hres(error);
234 IServiceProvider_Release(serv_prov);
235 return hres;
238 static ULONG send_http_request(HttpProtocol *This)
240 INTERNET_BUFFERSW send_buffer = {sizeof(INTERNET_BUFFERSW)};
241 BOOL res;
243 send_buffer.lpcszHeader = This->full_header;
244 send_buffer.dwHeadersLength = send_buffer.dwHeadersTotal = strlenW(This->full_header);
246 if(This->base.bind_info.dwBindVerb != BINDVERB_GET) {
247 switch(This->base.bind_info.stgmedData.tymed) {
248 case TYMED_HGLOBAL:
249 /* Native does not use GlobalLock/GlobalUnlock, so we won't either */
250 send_buffer.lpvBuffer = This->base.bind_info.stgmedData.u.hGlobal;
251 send_buffer.dwBufferLength = send_buffer.dwBufferTotal = This->base.bind_info.cbstgmedData;
252 break;
253 case TYMED_ISTREAM: {
254 LARGE_INTEGER offset;
256 send_buffer.dwBufferTotal = This->base.bind_info.cbstgmedData;
257 if(!This->base.post_stream) {
258 This->base.post_stream = This->base.bind_info.stgmedData.u.pstm;
259 IStream_AddRef(This->base.post_stream);
262 offset.QuadPart = 0;
263 IStream_Seek(This->base.post_stream, offset, STREAM_SEEK_SET, NULL);
264 break;
266 default:
267 FIXME("Unsupported This->base.bind_info.stgmedData.tymed %d\n", This->base.bind_info.stgmedData.tymed);
271 if(This->base.post_stream)
272 res = HttpSendRequestExW(This->base.request, &send_buffer, NULL, 0, 0);
273 else
274 res = HttpSendRequestW(This->base.request, send_buffer.lpcszHeader, send_buffer.dwHeadersLength,
275 send_buffer.lpvBuffer, send_buffer.dwBufferLength);
277 return res ? 0 : GetLastError();
280 static inline HttpProtocol *impl_from_Protocol(Protocol *prot)
282 return CONTAINING_RECORD(prot, HttpProtocol, base);
285 static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD request_flags,
286 HINTERNET internet_session, IInternetBindInfo *bind_info)
288 HttpProtocol *This = impl_from_Protocol(prot);
289 LPWSTR addl_header = NULL, post_cookie = NULL;
290 IServiceProvider *service_provider = NULL;
291 IHttpNegotiate2 *http_negotiate2 = NULL;
292 BSTR url, host, user, pass, path;
293 LPOLESTR accept_mimes[257];
294 const WCHAR **accept_types;
295 BYTE security_id[512];
296 DWORD len, port, flags;
297 ULONG num, error;
298 BOOL res, b;
299 HRESULT hres;
301 static const WCHAR wszBindVerb[BINDVERB_CUSTOM][5] =
302 {{'G','E','T',0},
303 {'P','O','S','T',0},
304 {'P','U','T',0}};
306 hres = IUri_GetPort(uri, &port);
307 if(FAILED(hres))
308 return hres;
310 hres = IUri_GetHost(uri, &host);
311 if(FAILED(hres))
312 return hres;
314 hres = IUri_GetUserName(uri, &user);
315 if(SUCCEEDED(hres)) {
316 hres = IUri_GetPassword(uri, &pass);
318 if(SUCCEEDED(hres)) {
319 This->base.connection = InternetConnectW(internet_session, host, port, user, pass,
320 INTERNET_SERVICE_HTTP, This->https ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)&This->base);
321 SysFreeString(pass);
323 SysFreeString(user);
325 SysFreeString(host);
326 if(FAILED(hres))
327 return hres;
328 if(!This->base.connection) {
329 WARN("InternetConnect failed: %d\n", GetLastError());
330 return INET_E_CANNOT_CONNECT;
333 num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1;
334 hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ACCEPT_MIMES, accept_mimes, num, &num);
335 if(hres == INET_E_USE_DEFAULT_SETTING) {
336 static const WCHAR default_accept_mimeW[] = {'*','/','*',0};
337 static const WCHAR *default_accept_mimes[] = {default_accept_mimeW, NULL};
339 accept_types = default_accept_mimes;
340 num = 0;
341 }else if(hres == S_OK) {
342 accept_types = (const WCHAR**)accept_mimes;
343 }else {
344 WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres);
345 return INET_E_NO_VALID_MEDIA;
347 accept_mimes[num] = 0;
349 if(This->https)
350 request_flags |= INTERNET_FLAG_SECURE;
352 hres = IUri_GetPathAndQuery(uri, &path);
353 if(SUCCEEDED(hres)) {
354 This->base.request = HttpOpenRequestW(This->base.connection,
355 This->base.bind_info.dwBindVerb < BINDVERB_CUSTOM
356 ? wszBindVerb[This->base.bind_info.dwBindVerb] : This->base.bind_info.szCustomVerb,
357 path, NULL, NULL, accept_types, request_flags, (DWORD_PTR)&This->base);
358 SysFreeString(path);
360 while(num--)
361 CoTaskMemFree(accept_mimes[num]);
362 if(FAILED(hres))
363 return hres;
364 if (!This->base.request) {
365 WARN("HttpOpenRequest failed: %d\n", GetLastError());
366 return INET_E_RESOURCE_NOT_FOUND;
369 hres = IInternetProtocolSink_QueryInterface(This->base.protocol_sink, &IID_IServiceProvider,
370 (void **)&service_provider);
371 if (hres != S_OK) {
372 WARN("IInternetProtocolSink_QueryInterface IID_IServiceProvider failed: %08x\n", hres);
373 return hres;
376 hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
377 &IID_IHttpNegotiate, (void **)&This->http_negotiate);
378 if (hres != S_OK) {
379 WARN("IServiceProvider_QueryService IID_IHttpNegotiate failed: %08x\n", hres);
380 IServiceProvider_Release(service_provider);
381 return hres;
384 hres = IUri_GetAbsoluteUri(uri, &url);
385 if(FAILED(hres)) {
386 IServiceProvider_Release(service_provider);
387 return hres;
390 hres = IHttpNegotiate_BeginningTransaction(This->http_negotiate, url, default_headersW,
391 0, &addl_header);
392 SysFreeString(url);
393 if(hres != S_OK) {
394 WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres);
395 IServiceProvider_Release(service_provider);
396 return hres;
399 len = addl_header ? strlenW(addl_header) : 0;
401 This->full_header = heap_alloc(len*sizeof(WCHAR)+sizeof(default_headersW));
402 if(!This->full_header) {
403 IServiceProvider_Release(service_provider);
404 return E_OUTOFMEMORY;
407 if(len)
408 memcpy(This->full_header, addl_header, len*sizeof(WCHAR));
409 CoTaskMemFree(addl_header);
410 memcpy(This->full_header+len, default_headersW, sizeof(default_headersW));
412 hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2,
413 &IID_IHttpNegotiate2, (void **)&http_negotiate2);
414 IServiceProvider_Release(service_provider);
415 if(hres != S_OK) {
416 WARN("IServiceProvider_QueryService IID_IHttpNegotiate2 failed: %08x\n", hres);
417 /* No goto done as per native */
418 }else {
419 len = sizeof(security_id)/sizeof(security_id[0]);
420 hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, security_id, &len, 0);
421 IHttpNegotiate2_Release(http_negotiate2);
422 if (hres != S_OK)
423 WARN("IHttpNegotiate2_GetRootSecurityId failed: %08x\n", hres);
426 /* FIXME: Handle security_id. Native calls undocumented function IsHostInProxyBypassList. */
428 if(This->base.bind_info.dwBindVerb == BINDVERB_POST) {
429 num = 0;
430 hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_POST_COOKIE, &post_cookie, 1, &num);
431 if(hres == S_OK && num) {
432 if(!InternetSetOptionW(This->base.request, INTERNET_OPTION_SECONDARY_CACHE_KEY,
433 post_cookie, lstrlenW(post_cookie)))
434 WARN("InternetSetOption INTERNET_OPTION_SECONDARY_CACHE_KEY failed: %d\n", GetLastError());
435 CoTaskMemFree(post_cookie);
439 flags = INTERNET_ERROR_MASK_COMBINED_SEC_CERT;
440 res = InternetSetOptionW(This->base.request, INTERNET_OPTION_ERROR_MASK, &flags, sizeof(flags));
441 if(!res)
442 WARN("InternetSetOption(INTERNET_OPTION_ERROR_MASK) failed: %u\n", GetLastError());
444 b = TRUE;
445 res = InternetSetOptionW(This->base.request, INTERNET_OPTION_HTTP_DECODING, &b, sizeof(b));
446 if(!res)
447 WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %u\n", GetLastError());
449 do {
450 error = send_http_request(This);
452 if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
453 return S_OK;
455 hres = handle_http_error(This, error);
457 } while(hres == RPC_E_RETRY);
459 WARN("HttpSendRequest failed: %d\n", error);
460 return hres;
463 static HRESULT HttpProtocol_end_request(Protocol *protocol)
465 BOOL res;
467 res = HttpEndRequestW(protocol->request, NULL, 0, 0);
468 if(!res && GetLastError() != ERROR_IO_PENDING) {
469 FIXME("HttpEndRequest failed: %u\n", GetLastError());
470 return E_FAIL;
473 return S_OK;
476 static HRESULT HttpProtocol_start_downloading(Protocol *prot)
478 HttpProtocol *This = impl_from_Protocol(prot);
479 LPWSTR content_type, content_length, ranges;
480 DWORD len = sizeof(DWORD);
481 DWORD status_code;
482 BOOL res;
483 HRESULT hres;
485 static const WCHAR wszDefaultContentType[] =
486 {'t','e','x','t','/','h','t','m','l',0};
488 if(!This->http_negotiate) {
489 WARN("Expected IHttpNegotiate pointer to be non-NULL\n");
490 return S_OK;
493 res = HttpQueryInfoW(This->base.request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
494 &status_code, &len, NULL);
495 if(res) {
496 LPWSTR response_headers = query_http_info(This, HTTP_QUERY_RAW_HEADERS_CRLF);
497 if(response_headers) {
498 hres = IHttpNegotiate_OnResponse(This->http_negotiate, status_code, response_headers,
499 NULL, NULL);
500 heap_free(response_headers);
501 if (hres != S_OK) {
502 WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres);
503 return S_OK;
506 }else {
507 WARN("HttpQueryInfo failed: %d\n", GetLastError());
510 ranges = query_http_info(This, HTTP_QUERY_ACCEPT_RANGES);
511 if(ranges) {
512 IInternetProtocolSink_ReportProgress(This->base.protocol_sink, BINDSTATUS_ACCEPTRANGES, NULL);
513 heap_free(ranges);
516 content_type = query_http_info(This, HTTP_QUERY_CONTENT_TYPE);
517 if(content_type) {
518 /* remove the charset, if present */
519 LPWSTR p = strchrW(content_type, ';');
520 if (p) *p = '\0';
522 IInternetProtocolSink_ReportProgress(This->base.protocol_sink,
523 (This->base.bindf & BINDF_FROMURLMON)
524 ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE,
525 content_type);
526 heap_free(content_type);
527 }else {
528 WARN("HttpQueryInfo failed: %d\n", GetLastError());
529 IInternetProtocolSink_ReportProgress(This->base.protocol_sink,
530 (This->base.bindf & BINDF_FROMURLMON)
531 ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE,
532 wszDefaultContentType);
535 content_length = query_http_info(This, HTTP_QUERY_CONTENT_LENGTH);
536 if(content_length) {
537 This->base.content_length = atoiW(content_length);
538 heap_free(content_length);
541 return S_OK;
544 static void HttpProtocol_close_connection(Protocol *prot)
546 HttpProtocol *This = impl_from_Protocol(prot);
548 if(This->http_negotiate) {
549 IHttpNegotiate_Release(This->http_negotiate);
550 This->http_negotiate = NULL;
553 heap_free(This->full_header);
554 This->full_header = NULL;
557 static void HttpProtocol_on_error(Protocol *prot, DWORD error)
559 HttpProtocol *This = impl_from_Protocol(prot);
560 HRESULT hres;
562 TRACE("(%p) %d\n", prot, error);
564 if(prot->flags & FLAG_FIRST_CONTINUE_COMPLETE) {
565 FIXME("Not handling error %d\n", error);
566 return;
569 while((hres = handle_http_error(This, error)) == RPC_E_RETRY) {
570 error = send_http_request(This);
572 if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
573 return;
576 protocol_abort(prot, hres);
577 protocol_close_connection(prot);
578 return;
581 static const ProtocolVtbl AsyncProtocolVtbl = {
582 HttpProtocol_open_request,
583 HttpProtocol_end_request,
584 HttpProtocol_start_downloading,
585 HttpProtocol_close_connection,
586 HttpProtocol_on_error
589 static HRESULT WINAPI HttpProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
591 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
593 *ppv = NULL;
594 if(IsEqualGUID(&IID_IUnknown, riid)) {
595 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
596 *ppv = &This->IInternetProtocolEx_iface;
597 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
598 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
599 *ppv = &This->IInternetProtocolEx_iface;
600 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
601 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
602 *ppv = &This->IInternetProtocolEx_iface;
603 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
604 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
605 *ppv = &This->IInternetProtocolEx_iface;
606 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
607 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
608 *ppv = &This->IInternetPriority_iface;
609 }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
610 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
611 *ppv = &This->IWinInetHttpInfo_iface;
612 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
613 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
614 *ppv = &This->IWinInetHttpInfo_iface;
617 if(*ppv) {
618 IInternetProtocol_AddRef(iface);
619 return S_OK;
622 WARN("not supported interface %s\n", debugstr_guid(riid));
623 return E_NOINTERFACE;
626 static ULONG WINAPI HttpProtocol_AddRef(IInternetProtocolEx *iface)
628 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
629 LONG ref = InterlockedIncrement(&This->ref);
630 TRACE("(%p) ref=%d\n", This, ref);
631 return ref;
634 static ULONG WINAPI HttpProtocol_Release(IInternetProtocolEx *iface)
636 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
637 LONG ref = InterlockedDecrement(&This->ref);
639 TRACE("(%p) ref=%d\n", This, ref);
641 if(!ref) {
642 protocol_close_connection(&This->base);
643 heap_free(This);
645 URLMON_UnlockModule();
648 return ref;
651 static HRESULT WINAPI HttpProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
652 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
653 DWORD grfPI, HANDLE_PTR dwReserved)
655 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
656 IUri *uri;
657 HRESULT hres;
659 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
660 pOIBindInfo, grfPI, dwReserved);
662 hres = CreateUri(szUrl, 0, 0, &uri);
663 if(FAILED(hres))
664 return hres;
666 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
667 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
669 IUri_Release(uri);
670 return hres;
673 static HRESULT WINAPI HttpProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
675 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
677 TRACE("(%p)->(%p)\n", This, pProtocolData);
679 return protocol_continue(&This->base, pProtocolData);
682 static HRESULT WINAPI HttpProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
683 DWORD dwOptions)
685 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
687 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
689 return protocol_abort(&This->base, hrReason);
692 static HRESULT WINAPI HttpProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
694 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
696 TRACE("(%p)->(%08x)\n", This, dwOptions);
698 protocol_close_connection(&This->base);
699 return S_OK;
702 static HRESULT WINAPI HttpProtocol_Suspend(IInternetProtocolEx *iface)
704 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
705 FIXME("(%p)\n", This);
706 return E_NOTIMPL;
709 static HRESULT WINAPI HttpProtocol_Resume(IInternetProtocolEx *iface)
711 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
712 FIXME("(%p)\n", This);
713 return E_NOTIMPL;
716 static HRESULT WINAPI HttpProtocol_Read(IInternetProtocolEx *iface, void *pv,
717 ULONG cb, ULONG *pcbRead)
719 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
721 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
723 return protocol_read(&This->base, pv, cb, pcbRead);
726 static HRESULT WINAPI HttpProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
727 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
729 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
730 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
731 return E_NOTIMPL;
734 static HRESULT WINAPI HttpProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
736 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
738 TRACE("(%p)->(%08x)\n", This, dwOptions);
740 return protocol_lock_request(&This->base);
743 static HRESULT WINAPI HttpProtocol_UnlockRequest(IInternetProtocolEx *iface)
745 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
747 TRACE("(%p)\n", This);
749 return protocol_unlock_request(&This->base);
752 static HRESULT WINAPI HttpProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
753 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
754 DWORD grfPI, HANDLE *dwReserved)
756 HttpProtocol *This = impl_from_IInternetProtocolEx(iface);
757 DWORD scheme = 0;
758 HRESULT hres;
760 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink,
761 pOIBindInfo, grfPI, dwReserved);
763 hres = IUri_GetScheme(pUri, &scheme);
764 if(FAILED(hres))
765 return hres;
766 if(scheme != (This->https ? URL_SCHEME_HTTPS : URL_SCHEME_HTTP))
767 return MK_E_SYNTAX;
769 return protocol_start(&This->base, (IInternetProtocol*)&This->IInternetProtocolEx_iface, pUri,
770 pOIProtSink, pOIBindInfo);
773 static const IInternetProtocolExVtbl HttpProtocolVtbl = {
774 HttpProtocol_QueryInterface,
775 HttpProtocol_AddRef,
776 HttpProtocol_Release,
777 HttpProtocol_Start,
778 HttpProtocol_Continue,
779 HttpProtocol_Abort,
780 HttpProtocol_Terminate,
781 HttpProtocol_Suspend,
782 HttpProtocol_Resume,
783 HttpProtocol_Read,
784 HttpProtocol_Seek,
785 HttpProtocol_LockRequest,
786 HttpProtocol_UnlockRequest,
787 HttpProtocol_StartEx
790 static HRESULT WINAPI HttpPriority_QueryInterface(IInternetPriority *iface, REFIID riid, void **ppv)
792 HttpProtocol *This = impl_from_IInternetPriority(iface);
793 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
796 static ULONG WINAPI HttpPriority_AddRef(IInternetPriority *iface)
798 HttpProtocol *This = impl_from_IInternetPriority(iface);
799 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
802 static ULONG WINAPI HttpPriority_Release(IInternetPriority *iface)
804 HttpProtocol *This = impl_from_IInternetPriority(iface);
805 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
808 static HRESULT WINAPI HttpPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
810 HttpProtocol *This = impl_from_IInternetPriority(iface);
812 TRACE("(%p)->(%d)\n", This, nPriority);
814 This->base.priority = nPriority;
815 return S_OK;
818 static HRESULT WINAPI HttpPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
820 HttpProtocol *This = impl_from_IInternetPriority(iface);
822 TRACE("(%p)->(%p)\n", This, pnPriority);
824 *pnPriority = This->base.priority;
825 return S_OK;
828 static const IInternetPriorityVtbl HttpPriorityVtbl = {
829 HttpPriority_QueryInterface,
830 HttpPriority_AddRef,
831 HttpPriority_Release,
832 HttpPriority_SetPriority,
833 HttpPriority_GetPriority
836 static HRESULT WINAPI HttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
838 HttpProtocol *This = impl_from_IWinInetHttpInfo(iface);
839 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
842 static ULONG WINAPI HttpInfo_AddRef(IWinInetHttpInfo *iface)
844 HttpProtocol *This = impl_from_IWinInetHttpInfo(iface);
845 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
848 static ULONG WINAPI HttpInfo_Release(IWinInetHttpInfo *iface)
850 HttpProtocol *This = impl_from_IWinInetHttpInfo(iface);
851 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
854 static HRESULT WINAPI HttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
855 void *pBuffer, DWORD *pcbBuffer)
857 HttpProtocol *This = impl_from_IWinInetHttpInfo(iface);
858 TRACE("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
860 if(!This->base.request)
861 return E_FAIL;
863 if(!InternetQueryOptionW(This->base.request, dwOption, pBuffer, pcbBuffer))
864 return S_FALSE;
865 return S_OK;
868 static HRESULT WINAPI HttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
869 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
871 HttpProtocol *This = impl_from_IWinInetHttpInfo(iface);
872 TRACE("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
874 if(!This->base.request)
875 return E_FAIL;
877 if(!HttpQueryInfoW(This->base.request, dwOption, pBuffer, pcbBuffer, pdwFlags)) {
878 if(pBuffer)
879 memset(pBuffer, 0, *pcbBuffer);
880 return S_OK;
882 return S_OK;
885 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
886 HttpInfo_QueryInterface,
887 HttpInfo_AddRef,
888 HttpInfo_Release,
889 HttpInfo_QueryOption,
890 HttpInfo_QueryInfo
893 static HRESULT create_http_protocol(BOOL https, void **ppobj)
895 HttpProtocol *ret;
897 ret = heap_alloc_zero(sizeof(HttpProtocol));
898 if(!ret)
899 return E_OUTOFMEMORY;
901 ret->base.vtbl = &AsyncProtocolVtbl;
902 ret->IInternetProtocolEx_iface.lpVtbl = &HttpProtocolVtbl;
903 ret->IInternetPriority_iface.lpVtbl = &HttpPriorityVtbl;
904 ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl;
906 ret->https = https;
907 ret->ref = 1;
909 *ppobj = &ret->IInternetProtocolEx_iface;
911 URLMON_LockModule();
912 return S_OK;
915 HRESULT HttpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
917 TRACE("(%p %p)\n", pUnkOuter, ppobj);
919 return create_http_protocol(FALSE, ppobj);
922 HRESULT HttpSProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
924 TRACE("(%p %p)\n", pUnkOuter, ppobj);
926 return create_http_protocol(TRUE, ppobj);