wined3d: Handle the sampler type shift in the frontend.
[wine] / dlls / urlmon / http.c
1 /*
2  * Copyright 2005 Jacek Caban
3  * Copyright 2007 Misha Koshelev
4  *
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.
9  *
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.
14  *
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
18  */
19
20 /*
21  * TODO:
22  * - Handle redirects as native.
23  */
24
25 #include "urlmon_main.h"
26 #include "wininet.h"
27
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
31
32 typedef struct {
33     Protocol base;
34
35     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
36     const IInternetPriorityVtbl *lpInternetPriorityVtbl;
37     const IWinInetHttpInfoVtbl  *lpWinInetHttpInfoVtbl;
38
39     BOOL https;
40     IHttpNegotiate *http_negotiate;
41     LPWSTR full_header;
42
43     LONG ref;
44 } HttpProtocol;
45
46 #define PROTOCOL(x)      ((IInternetProtocol*)  &(x)->lpInternetProtocolVtbl)
47 #define PRIORITY(x)      ((IInternetPriority*)  &(x)->lpInternetPriorityVtbl)
48 #define INETHTTPINFO(x)  ((IWinInetHttpInfo*)   &(x)->lpWinInetHttpInfoVtbl)
49
50 /* Default headers from native */
51 static const WCHAR wszHeaders[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',
52                                    ':',' ','g','z','i','p',',',' ','d','e','f','l','a','t','e',0};
53
54 static LPWSTR query_http_info(HttpProtocol *This, DWORD option)
55 {
56     LPWSTR ret = NULL;
57     DWORD len = 0;
58     BOOL res;
59
60     res = HttpQueryInfoW(This->base.request, option, NULL, &len, NULL);
61     if (!res && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
62         ret = heap_alloc(len);
63         res = HttpQueryInfoW(This->base.request, option, ret, &len, NULL);
64     }
65     if(!res) {
66         TRACE("HttpQueryInfoW(%d) failed: %08x\n", option, GetLastError());
67         heap_free(ret);
68         return NULL;
69     }
70
71     return ret;
72 }
73
74 #define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(HttpProtocol, base, iface)
75
76 static HRESULT HttpProtocol_open_request(Protocol *prot, LPCWSTR url, DWORD request_flags,
77                                          IInternetBindInfo *bind_info)
78 {
79     HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
80     LPWSTR addl_header = NULL, post_cookie = NULL, optional = NULL;
81     IServiceProvider *service_provider = NULL;
82     IHttpNegotiate2 *http_negotiate2 = NULL;
83     LPWSTR host, user, pass, path;
84     LPOLESTR accept_mimes[257];
85     URL_COMPONENTSW url_comp;
86     BYTE security_id[512];
87     DWORD len = 0;
88     ULONG num = 0;
89     BOOL res;
90     HRESULT hres;
91
92     static const WCHAR wszBindVerb[BINDVERB_CUSTOM][5] =
93         {{'G','E','T',0},
94          {'P','O','S','T',0},
95          {'P','U','T',0}};
96
97     memset(&url_comp, 0, sizeof(url_comp));
98     url_comp.dwStructSize = sizeof(url_comp);
99     url_comp.dwSchemeLength = url_comp.dwHostNameLength = url_comp.dwUrlPathLength =
100         url_comp.dwUserNameLength = url_comp.dwPasswordLength = 1;
101     if (!InternetCrackUrlW(url, 0, 0, &url_comp))
102         return MK_E_SYNTAX;
103
104     if(!url_comp.nPort)
105         url_comp.nPort = This->https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
106
107     host = heap_strndupW(url_comp.lpszHostName, url_comp.dwHostNameLength);
108     user = heap_strndupW(url_comp.lpszUserName, url_comp.dwUserNameLength);
109     pass = heap_strndupW(url_comp.lpszPassword, url_comp.dwPasswordLength);
110     This->base.connection = InternetConnectW(This->base.internet, host, url_comp.nPort, user, pass,
111             INTERNET_SERVICE_HTTP, This->https ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)&This->base);
112     heap_free(pass);
113     heap_free(user);
114     heap_free(host);
115     if(!This->base.connection) {
116         WARN("InternetConnect failed: %d\n", GetLastError());
117         return INET_E_CANNOT_CONNECT;
118     }
119
120     num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1;
121     hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ACCEPT_MIMES, accept_mimes, num, &num);
122     if(hres != S_OK) {
123         WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres);
124         return INET_E_NO_VALID_MEDIA;
125     }
126     accept_mimes[num] = 0;
127
128     path = heap_strndupW(url_comp.lpszUrlPath, url_comp.dwUrlPathLength);
129     if(This->https)
130         request_flags |= INTERNET_FLAG_SECURE;
131     This->base.request = HttpOpenRequestW(This->base.connection,
132             This->base.bind_info.dwBindVerb < BINDVERB_CUSTOM
133                 ? wszBindVerb[This->base.bind_info.dwBindVerb] : This->base.bind_info.szCustomVerb,
134             path, NULL, NULL, (LPCWSTR *)accept_mimes, request_flags, (DWORD_PTR)&This->base);
135     heap_free(path);
136     while (num<sizeof(accept_mimes)/sizeof(accept_mimes[0]) && accept_mimes[num])
137         CoTaskMemFree(accept_mimes[num++]);
138     if (!This->base.request) {
139         WARN("HttpOpenRequest failed: %d\n", GetLastError());
140         return INET_E_RESOURCE_NOT_FOUND;
141     }
142
143     hres = IInternetProtocolSink_QueryInterface(This->base.protocol_sink, &IID_IServiceProvider,
144             (void **)&service_provider);
145     if (hres != S_OK) {
146         WARN("IInternetProtocolSink_QueryInterface IID_IServiceProvider failed: %08x\n", hres);
147         return hres;
148     }
149
150     hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
151             &IID_IHttpNegotiate, (void **)&This->http_negotiate);
152     if (hres != S_OK) {
153         WARN("IServiceProvider_QueryService IID_IHttpNegotiate failed: %08x\n", hres);
154         return hres;
155     }
156
157     hres = IHttpNegotiate_BeginningTransaction(This->http_negotiate, url, wszHeaders,
158             0, &addl_header);
159     if(hres != S_OK) {
160         WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres);
161         IServiceProvider_Release(service_provider);
162         return hres;
163     }
164
165     if(addl_header) {
166         int len_addl_header = strlenW(addl_header);
167
168         This->full_header = heap_alloc(len_addl_header*sizeof(WCHAR)+sizeof(wszHeaders));
169
170         lstrcpyW(This->full_header, addl_header);
171         lstrcpyW(&This->full_header[len_addl_header], wszHeaders);
172         CoTaskMemFree(addl_header);
173     }else {
174         This->full_header = (LPWSTR)wszHeaders;
175     }
176
177     hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2,
178             &IID_IHttpNegotiate2, (void **)&http_negotiate2);
179     IServiceProvider_Release(service_provider);
180     if(hres != S_OK) {
181         WARN("IServiceProvider_QueryService IID_IHttpNegotiate2 failed: %08x\n", hres);
182         /* No goto done as per native */
183     }else {
184         len = sizeof(security_id)/sizeof(security_id[0]);
185         hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, security_id, &len, 0);
186         IHttpNegotiate2_Release(http_negotiate2);
187         if (hres != S_OK)
188             WARN("IHttpNegotiate2_GetRootSecurityId failed: %08x\n", hres);
189     }
190
191     /* FIXME: Handle security_id. Native calls undocumented function IsHostInProxyBypassList. */
192
193     if(This->base.bind_info.dwBindVerb == BINDVERB_POST) {
194         num = 0;
195         hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_POST_COOKIE, &post_cookie, 1, &num);
196         if(hres == S_OK && num) {
197             if(!InternetSetOptionW(This->base.request, INTERNET_OPTION_SECONDARY_CACHE_KEY,
198                                    post_cookie, lstrlenW(post_cookie)))
199                 WARN("InternetSetOption INTERNET_OPTION_SECONDARY_CACHE_KEY failed: %d\n", GetLastError());
200             CoTaskMemFree(post_cookie);
201         }
202     }
203
204     if(This->base.bind_info.dwBindVerb != BINDVERB_GET) {
205         /* Native does not use GlobalLock/GlobalUnlock, so we won't either */
206         if (This->base.bind_info.stgmedData.tymed != TYMED_HGLOBAL)
207             WARN("Expected This->base.bind_info.stgmedData.tymed to be TYMED_HGLOBAL, not %d\n",
208                  This->base.bind_info.stgmedData.tymed);
209         else
210             optional = (LPWSTR)This->base.bind_info.stgmedData.u.hGlobal;
211     }
212
213     res = HttpSendRequestW(This->base.request, This->full_header, lstrlenW(This->full_header),
214             optional, optional ? This->base.bind_info.cbstgmedData : 0);
215     if(!res && GetLastError() != ERROR_IO_PENDING) {
216         WARN("HttpSendRequest failed: %d\n", GetLastError());
217         return INET_E_DOWNLOAD_FAILURE;
218     }
219
220     return S_OK;
221 }
222
223 static HRESULT HttpProtocol_start_downloading(Protocol *prot)
224 {
225     HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
226     LPWSTR content_type = 0, content_length = 0;
227     DWORD len = sizeof(DWORD);
228     DWORD status_code;
229     BOOL res;
230     HRESULT hres;
231
232     static const WCHAR wszDefaultContentType[] =
233         {'t','e','x','t','/','h','t','m','l',0};
234
235     if(!This->http_negotiate) {
236         WARN("Expected IHttpNegotiate pointer to be non-NULL\n");
237         return S_OK;
238     }
239
240     res = HttpQueryInfoW(This->base.request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
241             &status_code, &len, NULL);
242     if(res) {
243         LPWSTR response_headers = query_http_info(This, HTTP_QUERY_RAW_HEADERS_CRLF);
244         if(response_headers) {
245             hres = IHttpNegotiate_OnResponse(This->http_negotiate, status_code, response_headers,
246                     NULL, NULL);
247             heap_free(response_headers);
248             if (hres != S_OK) {
249                 WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres);
250                 return S_OK;
251             }
252         }
253     }else {
254         WARN("HttpQueryInfo failed: %d\n", GetLastError());
255     }
256
257     if(This->https)
258         IInternetProtocolSink_ReportProgress(This->base.protocol_sink, BINDSTATUS_ACCEPTRANGES, NULL);
259
260     content_type = query_http_info(This, HTTP_QUERY_CONTENT_TYPE);
261     if(content_type) {
262         /* remove the charset, if present */
263         LPWSTR p = strchrW(content_type, ';');
264         if (p) *p = '\0';
265
266         IInternetProtocolSink_ReportProgress(This->base.protocol_sink,
267                 (This->base.bindf & BINDF_FROMURLMON)
268                  ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE,
269                  content_type);
270         heap_free(content_type);
271     }else {
272         WARN("HttpQueryInfo failed: %d\n", GetLastError());
273         IInternetProtocolSink_ReportProgress(This->base.protocol_sink,
274                  (This->base.bindf & BINDF_FROMURLMON)
275                   ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE,
276                   wszDefaultContentType);
277     }
278
279     content_length = query_http_info(This, HTTP_QUERY_CONTENT_LENGTH);
280     if(content_length) {
281         This->base.content_length = atoiW(content_length);
282         heap_free(content_length);
283     }
284
285     return S_OK;
286 }
287
288 static void HttpProtocol_close_connection(Protocol *prot)
289 {
290     HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
291
292     if(This->http_negotiate) {
293         IHttpNegotiate_Release(This->http_negotiate);
294         This->http_negotiate = 0;
295     }
296
297     if(This->full_header) {
298         if(This->full_header != wszHeaders)
299             heap_free(This->full_header);
300         This->full_header = 0;
301     }
302 }
303
304 #undef ASYNCPROTOCOL_THIS
305
306 static const ProtocolVtbl AsyncProtocolVtbl = {
307     HttpProtocol_open_request,
308     HttpProtocol_start_downloading,
309     HttpProtocol_close_connection
310 };
311
312 #define PROTOCOL_THIS(iface) DEFINE_THIS(HttpProtocol, InternetProtocol, iface)
313
314 static HRESULT WINAPI HttpProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
315 {
316     HttpProtocol *This = PROTOCOL_THIS(iface);
317
318     *ppv = NULL;
319     if(IsEqualGUID(&IID_IUnknown, riid)) {
320         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
321         *ppv = PROTOCOL(This);
322     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
323         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
324         *ppv = PROTOCOL(This);
325     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
326         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
327         *ppv = PROTOCOL(This);
328     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
329         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
330         *ppv = PRIORITY(This);
331     }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
332         TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
333         *ppv = INETHTTPINFO(This);
334     }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
335         TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
336         *ppv = INETHTTPINFO(This);
337     }
338
339     if(*ppv) {
340         IInternetProtocol_AddRef(iface);
341         return S_OK;
342     }
343
344     WARN("not supported interface %s\n", debugstr_guid(riid));
345     return E_NOINTERFACE;
346 }
347
348 static ULONG WINAPI HttpProtocol_AddRef(IInternetProtocol *iface)
349 {
350     HttpProtocol *This = PROTOCOL_THIS(iface);
351     LONG ref = InterlockedIncrement(&This->ref);
352     TRACE("(%p) ref=%d\n", This, ref);
353     return ref;
354 }
355
356 static ULONG WINAPI HttpProtocol_Release(IInternetProtocol *iface)
357 {
358     HttpProtocol *This = PROTOCOL_THIS(iface);
359     LONG ref = InterlockedDecrement(&This->ref);
360
361     TRACE("(%p) ref=%d\n", This, ref);
362
363     if(!ref) {
364         protocol_close_connection(&This->base);
365         heap_free(This);
366
367         URLMON_UnlockModule();
368     }
369
370     return ref;
371 }
372
373 static HRESULT WINAPI HttpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
374         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
375         DWORD grfPI, HANDLE_PTR dwReserved)
376 {
377     HttpProtocol *This = PROTOCOL_THIS(iface);
378
379     static const WCHAR httpW[] = {'h','t','t','p',':'};
380     static const WCHAR httpsW[] = {'h','t','t','p','s',':'};
381
382     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
383             pOIBindInfo, grfPI, dwReserved);
384
385     if(This->https
386         ? strncmpW(szUrl, httpsW, sizeof(httpsW)/sizeof(WCHAR))
387         : strncmpW(szUrl, httpW, sizeof(httpW)/sizeof(WCHAR)))
388         return MK_E_SYNTAX;
389
390     return protocol_start(&This->base, PROTOCOL(This), szUrl, pOIProtSink, pOIBindInfo);
391 }
392
393 static HRESULT WINAPI HttpProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
394 {
395     HttpProtocol *This = PROTOCOL_THIS(iface);
396
397     TRACE("(%p)->(%p)\n", This, pProtocolData);
398
399     return protocol_continue(&This->base, pProtocolData);
400 }
401
402 static HRESULT WINAPI HttpProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
403         DWORD dwOptions)
404 {
405     HttpProtocol *This = PROTOCOL_THIS(iface);
406     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
407     return E_NOTIMPL;
408 }
409
410 static HRESULT WINAPI HttpProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
411 {
412     HttpProtocol *This = PROTOCOL_THIS(iface);
413
414     TRACE("(%p)->(%08x)\n", This, dwOptions);
415
416     protocol_close_connection(&This->base);
417     return S_OK;
418 }
419
420 static HRESULT WINAPI HttpProtocol_Suspend(IInternetProtocol *iface)
421 {
422     HttpProtocol *This = PROTOCOL_THIS(iface);
423     FIXME("(%p)\n", This);
424     return E_NOTIMPL;
425 }
426
427 static HRESULT WINAPI HttpProtocol_Resume(IInternetProtocol *iface)
428 {
429     HttpProtocol *This = PROTOCOL_THIS(iface);
430     FIXME("(%p)\n", This);
431     return E_NOTIMPL;
432 }
433
434 static HRESULT WINAPI HttpProtocol_Read(IInternetProtocol *iface, void *pv,
435         ULONG cb, ULONG *pcbRead)
436 {
437     HttpProtocol *This = PROTOCOL_THIS(iface);
438
439     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
440
441     return protocol_read(&This->base, pv, cb, pcbRead);
442 }
443
444 static HRESULT WINAPI HttpProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
445         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
446 {
447     HttpProtocol *This = PROTOCOL_THIS(iface);
448     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
449     return E_NOTIMPL;
450 }
451
452 static HRESULT WINAPI HttpProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
453 {
454     HttpProtocol *This = PROTOCOL_THIS(iface);
455
456     TRACE("(%p)->(%08x)\n", This, dwOptions);
457
458     return protocol_lock_request(&This->base);
459 }
460
461 static HRESULT WINAPI HttpProtocol_UnlockRequest(IInternetProtocol *iface)
462 {
463     HttpProtocol *This = PROTOCOL_THIS(iface);
464
465     TRACE("(%p)\n", This);
466
467     return protocol_unlock_request(&This->base);
468 }
469
470 #undef PROTOCOL_THIS
471
472 static const IInternetProtocolVtbl HttpProtocolVtbl = {
473     HttpProtocol_QueryInterface,
474     HttpProtocol_AddRef,
475     HttpProtocol_Release,
476     HttpProtocol_Start,
477     HttpProtocol_Continue,
478     HttpProtocol_Abort,
479     HttpProtocol_Terminate,
480     HttpProtocol_Suspend,
481     HttpProtocol_Resume,
482     HttpProtocol_Read,
483     HttpProtocol_Seek,
484     HttpProtocol_LockRequest,
485     HttpProtocol_UnlockRequest
486 };
487
488 #define PRIORITY_THIS(iface) DEFINE_THIS(HttpProtocol, InternetPriority, iface)
489
490 static HRESULT WINAPI HttpPriority_QueryInterface(IInternetPriority *iface, REFIID riid, void **ppv)
491 {
492     HttpProtocol *This = PRIORITY_THIS(iface);
493     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
494 }
495
496 static ULONG WINAPI HttpPriority_AddRef(IInternetPriority *iface)
497 {
498     HttpProtocol *This = PRIORITY_THIS(iface);
499     return IInternetProtocol_AddRef(PROTOCOL(This));
500 }
501
502 static ULONG WINAPI HttpPriority_Release(IInternetPriority *iface)
503 {
504     HttpProtocol *This = PRIORITY_THIS(iface);
505     return IInternetProtocol_Release(PROTOCOL(This));
506 }
507
508 static HRESULT WINAPI HttpPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
509 {
510     HttpProtocol *This = PRIORITY_THIS(iface);
511
512     TRACE("(%p)->(%d)\n", This, nPriority);
513
514     This->base.priority = nPriority;
515     return S_OK;
516 }
517
518 static HRESULT WINAPI HttpPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
519 {
520     HttpProtocol *This = PRIORITY_THIS(iface);
521
522     TRACE("(%p)->(%p)\n", This, pnPriority);
523
524     *pnPriority = This->base.priority;
525     return S_OK;
526 }
527
528 #undef PRIORITY_THIS
529
530 static const IInternetPriorityVtbl HttpPriorityVtbl = {
531     HttpPriority_QueryInterface,
532     HttpPriority_AddRef,
533     HttpPriority_Release,
534     HttpPriority_SetPriority,
535     HttpPriority_GetPriority
536 };
537
538 #define INETINFO_THIS(iface) DEFINE_THIS(HttpProtocol, WinInetHttpInfo, iface)
539
540 static HRESULT WINAPI HttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
541 {
542     HttpProtocol *This = INETINFO_THIS(iface);
543     return IBinding_QueryInterface(PROTOCOL(This), riid, ppv);
544 }
545
546 static ULONG WINAPI HttpInfo_AddRef(IWinInetHttpInfo *iface)
547 {
548     HttpProtocol *This = INETINFO_THIS(iface);
549     return IBinding_AddRef(PROTOCOL(This));
550 }
551
552 static ULONG WINAPI HttpInfo_Release(IWinInetHttpInfo *iface)
553 {
554     HttpProtocol *This = INETINFO_THIS(iface);
555     return IBinding_Release(PROTOCOL(This));
556 }
557
558 static HRESULT WINAPI HttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
559         void *pBuffer, DWORD *pcbBuffer)
560 {
561     HttpProtocol *This = INETINFO_THIS(iface);
562     FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
563     return E_NOTIMPL;
564 }
565
566 static HRESULT WINAPI HttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
567         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
568 {
569     HttpProtocol *This = INETINFO_THIS(iface);
570     FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
571     return E_NOTIMPL;
572 }
573
574 #undef INETINFO_THIS
575
576 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
577     HttpInfo_QueryInterface,
578     HttpInfo_AddRef,
579     HttpInfo_Release,
580     HttpInfo_QueryOption,
581     HttpInfo_QueryInfo
582 };
583
584 static HRESULT create_http_protocol(BOOL https, void **ppobj)
585 {
586     HttpProtocol *ret;
587
588     ret = heap_alloc_zero(sizeof(HttpProtocol));
589     if(!ret)
590         return E_OUTOFMEMORY;
591
592     ret->base.vtbl = &AsyncProtocolVtbl;
593     ret->lpInternetProtocolVtbl = &HttpProtocolVtbl;
594     ret->lpInternetPriorityVtbl = &HttpPriorityVtbl;
595     ret->lpWinInetHttpInfoVtbl  = &WinInetHttpInfoVtbl;
596
597     ret->https = https;
598     ret->ref = 1;
599
600     *ppobj = PROTOCOL(ret);
601     
602     URLMON_LockModule();
603     return S_OK;
604 }
605
606 HRESULT HttpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
607 {
608     TRACE("(%p %p)\n", pUnkOuter, ppobj);
609
610     return create_http_protocol(FALSE, ppobj);
611 }
612
613 HRESULT HttpSProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
614 {
615     TRACE("(%p %p)\n", pUnkOuter, ppobj);
616
617     return create_http_protocol(TRUE, ppobj);
618 }