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
22 * - Handle redirects as native.
35 #include "urlmon_main.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(urlmon
);
42 /* Flags are needed for, among other things, return HRESULTs from the Read function
43 * to conform to native. For example, Read returns:
45 * 1. E_PENDING if called before the request has completed,
47 * 2. S_FALSE after all data has been read and S_OK has been reported,
48 * (flags = FLAG_REQUEST_COMPLETE | FLAG_ALL_DATA_READ | FLAG_RESULT_REPORTED)
49 * 3. INET_E_DATA_NOT_AVAILABLE if InternetQueryDataAvailable fails. The first time
50 * this occurs, INET_E_DATA_NOT_AVAILABLE will also be reported to the sink,
51 * (flags = FLAG_REQUEST_COMPLETE)
52 * but upon subsequent calls to Read no reporting will take place, yet
53 * InternetQueryDataAvailable will still be called, and, on failure,
54 * INET_E_DATA_NOT_AVAILABLE will still be returned.
55 * (flags = FLAG_REQUEST_COMPLETE | FLAG_RESULT_REPORTED)
57 * FLAG_FIRST_DATA_REPORTED and FLAG_LAST_DATA_REPORTED are needed for proper
58 * ReportData reporting. For example, if OnResponse returns S_OK, Continue will
59 * report BSCF_FIRSTDATANOTIFICATION, and when all data has been read Read will
60 * report BSCF_INTERMEDIATEDATANOTIFICATION|BSCF_LASTDATANOTIFICATION. However,
61 * if OnResponse does not return S_OK, Continue will not report data, and Read
62 * will report BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION when all
65 #define FLAG_REQUEST_COMPLETE 0x1
66 #define FLAG_FIRST_CONTINUE_COMPLETE 0x2
67 #define FLAG_FIRST_DATA_REPORTED 0x4
68 #define FLAG_ALL_DATA_READ 0x8
69 #define FLAG_LAST_DATA_REPORTED 0x10
70 #define FLAG_RESULT_REPORTED 0x20
73 const IInternetProtocolVtbl
*lpInternetProtocolVtbl
;
74 const IInternetPriorityVtbl
*lpInternetPriorityVtbl
;
76 DWORD flags
, grfBINDF
;
77 IInternetProtocolSink
*protocol_sink
;
78 IHttpNegotiate
*http_negotiate
;
79 HINTERNET internet
, connect
, request
;
81 ULONG current_position
, content_length
, available_bytes
;
91 static void HTTPPROTOCOL_ReportResult(HttpProtocol
*This
, HRESULT hres
)
93 if (!(This
->flags
& FLAG_RESULT_REPORTED
) &&
96 This
->flags
|= FLAG_RESULT_REPORTED
;
97 IInternetProtocolSink_ReportResult(This
->protocol_sink
, hres
, 0, NULL
);
101 static void HTTPPROTOCOL_ReportData(HttpProtocol
*This
)
104 if (!(This
->flags
& FLAG_LAST_DATA_REPORTED
) &&
107 if (This
->flags
& FLAG_FIRST_DATA_REPORTED
)
109 bscf
= BSCF_INTERMEDIATEDATANOTIFICATION
;
113 This
->flags
|= FLAG_FIRST_DATA_REPORTED
;
114 bscf
= BSCF_FIRSTDATANOTIFICATION
;
116 if (This
->flags
& FLAG_ALL_DATA_READ
&&
117 !(This
->flags
& FLAG_LAST_DATA_REPORTED
))
119 This
->flags
|= FLAG_LAST_DATA_REPORTED
;
120 bscf
|= BSCF_LASTDATANOTIFICATION
;
122 IInternetProtocolSink_ReportData(This
->protocol_sink
, bscf
,
123 This
->current_position
+This
->available_bytes
,
124 This
->content_length
);
128 static void HTTPPROTOCOL_AllDataRead(HttpProtocol
*This
)
130 if (!(This
->flags
& FLAG_ALL_DATA_READ
))
131 This
->flags
|= FLAG_ALL_DATA_READ
;
132 HTTPPROTOCOL_ReportData(This
);
133 HTTPPROTOCOL_ReportResult(This
, S_OK
);
136 static void HTTPPROTOCOL_Close(HttpProtocol
*This
)
138 if (This
->protocol_sink
)
140 IInternetProtocolSink_Release(This
->protocol_sink
);
141 This
->protocol_sink
= 0;
143 if (This
->http_negotiate
)
145 IHttpNegotiate_Release(This
->http_negotiate
);
146 This
->http_negotiate
= 0;
150 InternetCloseHandle(This
->request
);
155 InternetCloseHandle(This
->connect
);
160 InternetCloseHandle(This
->internet
);
166 static void CALLBACK
HTTPPROTOCOL_InternetStatusCallback(
167 HINTERNET hInternet
, DWORD_PTR dwContext
, DWORD dwInternetStatus
,
168 LPVOID lpvStatusInformation
, DWORD dwStatusInformationLength
)
170 HttpProtocol
*This
= (HttpProtocol
*)dwContext
;
174 switch (dwInternetStatus
)
176 case INTERNET_STATUS_RESOLVING_NAME
:
177 ulStatusCode
= BINDSTATUS_FINDINGRESOURCE
;
179 case INTERNET_STATUS_CONNECTING_TO_SERVER
:
180 ulStatusCode
= BINDSTATUS_CONNECTING
;
182 case INTERNET_STATUS_SENDING_REQUEST
:
183 ulStatusCode
= BINDSTATUS_SENDINGREQUEST
;
185 case INTERNET_STATUS_REQUEST_COMPLETE
:
186 This
->flags
|= FLAG_REQUEST_COMPLETE
;
187 /* PROTOCOLDATA same as native */
188 memset(&data
, 0, sizeof(data
));
189 data
.dwState
= 0xf1000000;
190 if (This
->flags
& FLAG_FIRST_CONTINUE_COMPLETE
)
191 data
.pData
= (LPVOID
)BINDSTATUS_ENDDOWNLOADCOMPONENTS
;
193 data
.pData
= (LPVOID
)BINDSTATUS_DOWNLOADINGDATA
;
194 if (This
->grfBINDF
& BINDF_FROMURLMON
)
195 IInternetProtocolSink_Switch(This
->protocol_sink
, &data
);
197 IInternetProtocol_Continue((IInternetProtocol
*)This
, &data
);
200 WARN("Unhandled Internet status callback %d\n", dwInternetStatus
);
204 IInternetProtocolSink_ReportProgress(This
->protocol_sink
, ulStatusCode
, (LPWSTR
)lpvStatusInformation
);
207 static inline LPWSTR
strndupW(LPWSTR string
, int len
)
211 (ret
= HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
))) != NULL
)
213 memcpy(ret
, string
, len
*sizeof(WCHAR
));
220 * Interface implementations
223 #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
224 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
226 #define PROTOCOL_THIS(iface) DEFINE_THIS(HttpProtocol, InternetProtocol, iface)
228 static HRESULT WINAPI
HttpProtocol_QueryInterface(IInternetProtocol
*iface
, REFIID riid
, void **ppv
)
230 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
233 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
234 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
235 *ppv
= PROTOCOL(This
);
236 }else if(IsEqualGUID(&IID_IInternetProtocolRoot
, riid
)) {
237 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This
, ppv
);
238 *ppv
= PROTOCOL(This
);
239 }else if(IsEqualGUID(&IID_IInternetProtocol
, riid
)) {
240 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This
, ppv
);
241 *ppv
= PROTOCOL(This
);
242 }else if(IsEqualGUID(&IID_IInternetPriority
, riid
)) {
243 TRACE("(%p)->(IID_IInternetPriority %p)\n", This
, ppv
);
244 *ppv
= PRIORITY(This
);
248 IInternetProtocol_AddRef(iface
);
252 WARN("not supported interface %s\n", debugstr_guid(riid
));
253 return E_NOINTERFACE
;
256 static ULONG WINAPI
HttpProtocol_AddRef(IInternetProtocol
*iface
)
258 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
259 LONG ref
= InterlockedIncrement(&This
->ref
);
260 TRACE("(%p) ref=%d\n", This
, ref
);
264 static ULONG WINAPI
HttpProtocol_Release(IInternetProtocol
*iface
)
266 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
267 LONG ref
= InterlockedDecrement(&This
->ref
);
269 TRACE("(%p) ref=%d\n", This
, ref
);
272 HTTPPROTOCOL_Close(This
);
273 HeapFree(GetProcessHeap(), 0, This
);
275 URLMON_UnlockModule();
281 static HRESULT WINAPI
HttpProtocol_Start(IInternetProtocol
*iface
, LPCWSTR szUrl
,
282 IInternetProtocolSink
*pOIProtSink
, IInternetBindInfo
*pOIBindInfo
,
283 DWORD grfPI
, DWORD dwReserved
)
285 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
288 DWORD len
= 0, request_flags
= INTERNET_FLAG_KEEP_CONNECTION
;
290 IServiceProvider
*service_provider
= 0;
291 IHttpNegotiate2
*http_negotiate2
= 0;
292 LPWSTR host
= 0, path
= 0, user
= 0, pass
= 0, addl_header
= 0,
293 full_header
= 0, post_cookie
= 0, optional
= 0;
294 BYTE security_id
[512];
295 LPOLESTR user_agent
, accept_mimes
[257];
298 static const WCHAR wszHttp
[] = {'h','t','t','p',':'};
299 static const WCHAR wszHeaders
[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',
300 ':',' ','g','z','i','p',',',' ','d','e','f','l','a','t','e',0};
301 static const WCHAR wszBindVerb
[BINDVERB_CUSTOM
][5] =
306 TRACE("(%p)->(%s %p %p %08x %d)\n", This
, debugstr_w(szUrl
), pOIProtSink
,
307 pOIBindInfo
, grfPI
, dwReserved
);
309 memset(&bindinfo
, 0, sizeof(bindinfo
));
310 bindinfo
.cbSize
= sizeof(BINDINFO
);
311 hres
= IInternetBindInfo_GetBindInfo(pOIBindInfo
, &This
->grfBINDF
, &bindinfo
);
314 WARN("GetBindInfo failed: %08x\n", hres
);
318 if (lstrlenW(szUrl
) < sizeof(wszHttp
)/sizeof(WCHAR
)
319 || memcmp(szUrl
, wszHttp
, sizeof(wszHttp
)))
325 memset(&url
, 0, sizeof(url
));
326 url
.dwStructSize
= sizeof(url
);
327 url
.dwSchemeLength
= url
.dwHostNameLength
= url
.dwUrlPathLength
= url
.dwUserNameLength
=
328 url
.dwPasswordLength
= 1;
329 if (!InternetCrackUrlW(szUrl
, 0, 0, &url
))
334 host
= strndupW(url
.lpszHostName
, url
.dwHostNameLength
);
335 path
= strndupW(url
.lpszUrlPath
, url
.dwUrlPathLength
);
336 user
= strndupW(url
.lpszUserName
, url
.dwUserNameLength
);
337 pass
= strndupW(url
.lpszPassword
, url
.dwPasswordLength
);
339 url
.nPort
= INTERNET_DEFAULT_HTTP_PORT
;
341 if(!(This
->grfBINDF
& BINDF_FROMURLMON
))
342 IInternetProtocolSink_ReportProgress(pOIProtSink
, BINDSTATUS_DIRECTBIND
, NULL
);
344 hres
= IInternetBindInfo_GetBindString(pOIBindInfo
, BINDSTRING_USER_AGENT
, &user_agent
,
346 if (hres
!= S_OK
|| !num
)
349 LPSTR user_agenta
= NULL
;
351 if ((hres
= ObtainUserAgentString(0, &null_char
, &len
)) != E_OUTOFMEMORY
)
353 WARN("ObtainUserAgentString failed: %08x\n", hres
);
355 else if (!(user_agenta
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(CHAR
))))
357 WARN("Out of memory\n");
359 else if ((hres
= ObtainUserAgentString(0, user_agenta
, &len
)) != S_OK
)
361 WARN("ObtainUserAgentString failed: %08x\n", hres
);
365 if (!(user_agent
= CoTaskMemAlloc((len
)*sizeof(WCHAR
))))
366 WARN("Out of memory\n");
368 MultiByteToWideChar(CP_ACP
, 0, user_agenta
, -1, user_agent
, len
*sizeof(WCHAR
));
370 HeapFree(GetProcessHeap(), 0, user_agenta
);
373 This
->internet
= InternetOpenW(user_agent
, 0, NULL
, NULL
, INTERNET_FLAG_ASYNC
);
376 WARN("InternetOpen failed: %d\n", GetLastError());
377 hres
= INET_E_NO_SESSION
;
381 IInternetProtocolSink_AddRef(pOIProtSink
);
382 This
->protocol_sink
= pOIProtSink
;
384 /* Native does not check for success of next call, so we won't either */
385 InternetSetStatusCallbackW(This
->internet
, HTTPPROTOCOL_InternetStatusCallback
);
387 This
->connect
= InternetConnectW(This
->internet
, host
, url
.nPort
, user
,
388 pass
, INTERNET_SERVICE_HTTP
, 0, (DWORD
)This
);
391 WARN("InternetConnect failed: %d\n", GetLastError());
392 hres
= INET_E_CANNOT_CONNECT
;
396 num
= sizeof(accept_mimes
)/sizeof(accept_mimes
[0])-1;
397 hres
= IInternetBindInfo_GetBindString(pOIBindInfo
, BINDSTRING_ACCEPT_MIMES
,
402 WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres
);
403 hres
= INET_E_NO_VALID_MEDIA
;
406 accept_mimes
[num
] = 0;
408 if (This
->grfBINDF
& BINDF_NOWRITECACHE
)
409 request_flags
|= INTERNET_FLAG_NO_CACHE_WRITE
;
410 This
->request
= HttpOpenRequestW(This
->connect
, bindinfo
.dwBindVerb
< BINDVERB_CUSTOM
?
411 wszBindVerb
[bindinfo
.dwBindVerb
] : bindinfo
.szCustomVerb
,
412 path
, NULL
, NULL
, (LPCWSTR
*)accept_mimes
,
413 request_flags
, (DWORD
)This
);
416 WARN("HttpOpenRequest failed: %d\n", GetLastError());
417 hres
= INET_E_RESOURCE_NOT_FOUND
;
421 hres
= IInternetProtocolSink_QueryInterface(pOIProtSink
, &IID_IServiceProvider
,
422 (void **)&service_provider
);
425 WARN("IInternetProtocolSink_QueryInterface IID_IServiceProvider failed: %08x\n", hres
);
429 hres
= IServiceProvider_QueryService(service_provider
, &IID_IHttpNegotiate
,
430 &IID_IHttpNegotiate
, (void **)&This
->http_negotiate
);
433 WARN("IServiceProvider_QueryService IID_IHttpNegotiate failed: %08x\n", hres
);
437 hres
= IHttpNegotiate_BeginningTransaction(This
->http_negotiate
, szUrl
, wszHeaders
,
441 WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres
);
444 else if (addl_header
== NULL
)
446 full_header
= (LPWSTR
)wszHeaders
;
450 full_header
= HeapAlloc(GetProcessHeap(), 0,
451 (lstrlenW(addl_header
)+sizeof(wszHeaders
))*sizeof(WCHAR
));
454 WARN("Out of memory\n");
455 hres
= E_OUTOFMEMORY
;
458 lstrcpyW(full_header
, addl_header
);
459 lstrcpyW(&full_header
[lstrlenW(addl_header
)], wszHeaders
);
462 hres
= IServiceProvider_QueryService(service_provider
, &IID_IHttpNegotiate2
,
463 &IID_IHttpNegotiate2
, (void **)&http_negotiate2
);
466 WARN("IServiceProvider_QueryService IID_IHttpNegotiate2 failed: %08x\n", hres
);
467 /* No goto done as per native */
471 len
= sizeof(security_id
)/sizeof(security_id
[0]);
472 hres
= IHttpNegotiate2_GetRootSecurityId(http_negotiate2
, security_id
, &len
, 0);
475 WARN("IHttpNegotiate2_GetRootSecurityId failed: %08x\n", hres
);
476 /* No goto done as per native */
480 /* FIXME: Handle security_id. Native calls undocumented function IsHostInProxyBypassList. */
482 if (bindinfo
.dwBindVerb
== BINDVERB_POST
)
485 hres
= IInternetBindInfo_GetBindString(pOIBindInfo
, BINDSTRING_POST_COOKIE
, &post_cookie
,
487 if (hres
== S_OK
&& num
&&
488 !InternetSetOptionW(This
->request
, INTERNET_OPTION_SECONDARY_CACHE_KEY
,
489 post_cookie
, lstrlenW(post_cookie
)))
491 WARN("InternetSetOption INTERNET_OPTION_SECONDARY_CACHE_KEY failed: %d\n",
496 if (bindinfo
.dwBindVerb
!= BINDVERB_GET
)
498 /* Native does not use GlobalLock/GlobalUnlock, so we won't either */
499 if (bindinfo
.stgmedData
.tymed
!= TYMED_HGLOBAL
)
500 WARN("Expected bindinfo.stgmedData.tymed to be TYMED_HGLOBAL, not %d\n",
501 bindinfo
.stgmedData
.tymed
);
503 optional
= (LPWSTR
)bindinfo
.stgmedData
.hGlobal
;
505 if (!HttpSendRequestW(This
->request
, full_header
, lstrlenW(full_header
),
507 optional
? bindinfo
.cbstgmedData
: 0) &&
508 GetLastError() != ERROR_IO_PENDING
)
510 WARN("HttpSendRequest failed: %d\n", GetLastError());
511 hres
= INET_E_DOWNLOAD_FAILURE
;
519 IInternetProtocolSink_ReportResult(pOIProtSink
, hres
, 0, NULL
);
520 HTTPPROTOCOL_Close(This
);
523 CoTaskMemFree(post_cookie
);
524 if (full_header
!= wszHeaders
)
525 HeapFree(GetProcessHeap(), 0, full_header
);
526 CoTaskMemFree(addl_header
);
528 IHttpNegotiate2_Release(http_negotiate2
);
529 if (service_provider
)
530 IServiceProvider_Release(service_provider
);
532 while (num
<sizeof(accept_mimes
)/sizeof(accept_mimes
[0]) &&
534 CoTaskMemFree(accept_mimes
[num
++]);
535 CoTaskMemFree(user_agent
);
537 HeapFree(GetProcessHeap(), 0, pass
);
538 HeapFree(GetProcessHeap(), 0, user
);
539 HeapFree(GetProcessHeap(), 0, path
);
540 HeapFree(GetProcessHeap(), 0, host
);
542 ReleaseBindInfo(&bindinfo
);
547 static HRESULT WINAPI
HttpProtocol_Continue(IInternetProtocol
*iface
, PROTOCOLDATA
*pProtocolData
)
549 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
550 DWORD len
= sizeof(DWORD
), status_code
;
551 LPWSTR response_headers
= 0, content_type
= 0, content_length
= 0;
553 static const WCHAR wszDefaultContentType
[] =
554 {'t','e','x','t','/','h','t','m','l',0};
556 TRACE("(%p)->(%p)\n", This
, pProtocolData
);
560 WARN("Expected pProtocolData to be non-NULL\n");
563 else if (!This
->request
)
565 WARN("Expected request to be non-NULL\n");
568 else if (!This
->http_negotiate
)
570 WARN("Expected IHttpNegotiate pointer to be non-NULL\n");
573 else if (!This
->protocol_sink
)
575 WARN("Expected IInternetProtocolSink pointer to be non-NULL\n");
579 if (pProtocolData
->pData
== (LPVOID
)BINDSTATUS_DOWNLOADINGDATA
)
581 if (!HttpQueryInfoW(This
->request
, HTTP_QUERY_STATUS_CODE
| HTTP_QUERY_FLAG_NUMBER
,
582 &status_code
, &len
, NULL
))
584 WARN("HttpQueryInfo failed: %d\n", GetLastError());
589 if ((!HttpQueryInfoW(This
->request
, HTTP_QUERY_RAW_HEADERS_CRLF
, response_headers
, &len
,
591 GetLastError() != ERROR_INSUFFICIENT_BUFFER
) ||
592 !(response_headers
= HeapAlloc(GetProcessHeap(), 0, len
)) ||
593 !HttpQueryInfoW(This
->request
, HTTP_QUERY_RAW_HEADERS_CRLF
, response_headers
, &len
,
596 WARN("HttpQueryInfo failed: %d\n", GetLastError());
600 HRESULT hres
= IHttpNegotiate_OnResponse(This
->http_negotiate
, status_code
,
601 response_headers
, NULL
, NULL
);
604 WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres
);
611 if ((!HttpQueryInfoW(This
->request
, HTTP_QUERY_CONTENT_TYPE
, content_type
, &len
, NULL
) &&
612 GetLastError() != ERROR_INSUFFICIENT_BUFFER
) ||
613 !(content_type
= HeapAlloc(GetProcessHeap(), 0, len
)) ||
614 !HttpQueryInfoW(This
->request
, HTTP_QUERY_CONTENT_TYPE
, content_type
, &len
, NULL
))
616 WARN("HttpQueryInfo failed: %d\n", GetLastError());
617 IInternetProtocolSink_ReportProgress(This
->protocol_sink
,
618 (This
->grfBINDF
& BINDF_FROMURLMON
) ?
619 BINDSTATUS_MIMETYPEAVAILABLE
:
620 BINDSTATUS_RAWMIMETYPE
,
621 wszDefaultContentType
);
625 IInternetProtocolSink_ReportProgress(This
->protocol_sink
,
626 (This
->grfBINDF
& BINDF_FROMURLMON
) ?
627 BINDSTATUS_MIMETYPEAVAILABLE
:
628 BINDSTATUS_RAWMIMETYPE
,
633 if ((!HttpQueryInfoW(This
->request
, HTTP_QUERY_CONTENT_LENGTH
, content_length
, &len
, NULL
) &&
634 GetLastError() != ERROR_INSUFFICIENT_BUFFER
) ||
635 !(content_length
= HeapAlloc(GetProcessHeap(), 0, len
)) ||
636 !HttpQueryInfoW(This
->request
, HTTP_QUERY_CONTENT_LENGTH
, content_length
, &len
, NULL
))
638 WARN("HttpQueryInfo failed: %d\n", GetLastError());
639 This
->content_length
= 0;
643 This
->content_length
= atoiW(content_length
);
646 This
->flags
|= FLAG_FIRST_CONTINUE_COMPLETE
;
649 if (pProtocolData
->pData
>= (LPVOID
)BINDSTATUS_DOWNLOADINGDATA
)
651 if (!InternetQueryDataAvailable(This
->request
, &This
->available_bytes
, 0, 0))
653 if (GetLastError() == ERROR_IO_PENDING
)
655 This
->flags
&= ~FLAG_REQUEST_COMPLETE
;
659 WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
660 HTTPPROTOCOL_ReportResult(This
, INET_E_DATA_NOT_AVAILABLE
);
665 HTTPPROTOCOL_ReportData(This
);
670 HeapFree(GetProcessHeap(), 0, response_headers
);
671 HeapFree(GetProcessHeap(), 0, content_type
);
672 HeapFree(GetProcessHeap(), 0, content_length
);
674 /* Returns S_OK on native */
678 static HRESULT WINAPI
HttpProtocol_Abort(IInternetProtocol
*iface
, HRESULT hrReason
,
681 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
682 FIXME("(%p)->(%08x %08x)\n", This
, hrReason
, dwOptions
);
686 static HRESULT WINAPI
HttpProtocol_Terminate(IInternetProtocol
*iface
, DWORD dwOptions
)
688 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
690 TRACE("(%p)->(%08x)\n", This
, dwOptions
);
691 HTTPPROTOCOL_Close(This
);
696 static HRESULT WINAPI
HttpProtocol_Suspend(IInternetProtocol
*iface
)
698 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
699 FIXME("(%p)\n", This
);
703 static HRESULT WINAPI
HttpProtocol_Resume(IInternetProtocol
*iface
)
705 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
706 FIXME("(%p)\n", This
);
710 static HRESULT WINAPI
HttpProtocol_Read(IInternetProtocol
*iface
, void *pv
,
711 ULONG cb
, ULONG
*pcbRead
)
713 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
714 ULONG read
= 0, len
= 0;
715 HRESULT hres
= S_FALSE
;
717 TRACE("(%p)->(%p %u %p)\n", This
, pv
, cb
, pcbRead
);
719 if (!(This
->flags
& FLAG_REQUEST_COMPLETE
))
723 else while (!(This
->flags
& FLAG_ALL_DATA_READ
) &&
726 if (This
->available_bytes
== 0)
728 if (!InternetQueryDataAvailable(This
->request
, &This
->available_bytes
, 0, 0))
730 if (GetLastError() == ERROR_IO_PENDING
)
732 This
->flags
&= ~FLAG_REQUEST_COMPLETE
;
737 WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
738 hres
= INET_E_DATA_NOT_AVAILABLE
;
739 HTTPPROTOCOL_ReportResult(This
, hres
);
743 else if (This
->available_bytes
== 0)
745 HTTPPROTOCOL_AllDataRead(This
);
750 if (!InternetReadFile(This
->request
, ((BYTE
*)pv
)+read
,
751 This
->available_bytes
> cb
-read
?
752 cb
-read
: This
->available_bytes
, &len
))
754 WARN("InternetReadFile failed: %d\n", GetLastError());
755 hres
= INET_E_DOWNLOAD_FAILURE
;
756 HTTPPROTOCOL_ReportResult(This
, hres
);
761 HTTPPROTOCOL_AllDataRead(This
);
766 This
->current_position
+= len
;
767 This
->available_bytes
-= len
;
772 /* Per MSDN this should be if (read == cb), but native returns S_OK
773 * if any bytes were read, so we will too */
784 static HRESULT WINAPI
HttpProtocol_Seek(IInternetProtocol
*iface
, LARGE_INTEGER dlibMove
,
785 DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
787 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
788 FIXME("(%p)->(%d %d %p)\n", This
, dlibMove
.u
.LowPart
, dwOrigin
, plibNewPosition
);
792 static HRESULT WINAPI
HttpProtocol_LockRequest(IInternetProtocol
*iface
, DWORD dwOptions
)
794 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
796 TRACE("(%p)->(%08x)\n", This
, dwOptions
);
798 if (!InternetLockRequestFile(This
->request
, &This
->lock
))
799 WARN("InternetLockRequest failed: %d\n", GetLastError());
804 static HRESULT WINAPI
HttpProtocol_UnlockRequest(IInternetProtocol
*iface
)
806 HttpProtocol
*This
= PROTOCOL_THIS(iface
);
808 TRACE("(%p)\n", This
);
812 if (!InternetUnlockRequestFile(This
->lock
))
813 WARN("InternetUnlockRequest failed: %d\n", GetLastError());
822 #define PRIORITY_THIS(iface) DEFINE_THIS(HttpProtocol, InternetPriority, iface)
824 static HRESULT WINAPI
HttpPriority_QueryInterface(IInternetPriority
*iface
, REFIID riid
, void **ppv
)
826 HttpProtocol
*This
= PRIORITY_THIS(iface
);
827 return IInternetProtocol_QueryInterface(PROTOCOL(This
), riid
, ppv
);
830 static ULONG WINAPI
HttpPriority_AddRef(IInternetPriority
*iface
)
832 HttpProtocol
*This
= PRIORITY_THIS(iface
);
833 return IInternetProtocol_AddRef(PROTOCOL(This
));
836 static ULONG WINAPI
HttpPriority_Release(IInternetPriority
*iface
)
838 HttpProtocol
*This
= PRIORITY_THIS(iface
);
839 return IInternetProtocol_Release(PROTOCOL(This
));
842 static HRESULT WINAPI
HttpPriority_SetPriority(IInternetPriority
*iface
, LONG nPriority
)
844 HttpProtocol
*This
= PRIORITY_THIS(iface
);
846 TRACE("(%p)->(%d)\n", This
, nPriority
);
848 This
->priority
= nPriority
;
852 static HRESULT WINAPI
HttpPriority_GetPriority(IInternetPriority
*iface
, LONG
*pnPriority
)
854 HttpProtocol
*This
= PRIORITY_THIS(iface
);
856 TRACE("(%p)->(%p)\n", This
, pnPriority
);
858 *pnPriority
= This
->priority
;
864 static const IInternetPriorityVtbl HttpPriorityVtbl
= {
865 HttpPriority_QueryInterface
,
867 HttpPriority_Release
,
868 HttpPriority_SetPriority
,
869 HttpPriority_GetPriority
872 static const IInternetProtocolVtbl HttpProtocolVtbl
= {
873 HttpProtocol_QueryInterface
,
875 HttpProtocol_Release
,
877 HttpProtocol_Continue
,
879 HttpProtocol_Terminate
,
880 HttpProtocol_Suspend
,
884 HttpProtocol_LockRequest
,
885 HttpProtocol_UnlockRequest
888 HRESULT
HttpProtocol_Construct(IUnknown
*pUnkOuter
, LPVOID
*ppobj
)
892 TRACE("(%p %p)\n", pUnkOuter
, ppobj
);
896 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(HttpProtocol
));
898 ret
->lpInternetProtocolVtbl
= &HttpProtocolVtbl
;
899 ret
->lpInternetPriorityVtbl
= &HttpPriorityVtbl
;
900 ret
->flags
= ret
->grfBINDF
= 0;
901 ret
->protocol_sink
= 0;
902 ret
->http_negotiate
= 0;
903 ret
->internet
= ret
->connect
= ret
->request
= 0;
905 ret
->current_position
= ret
->content_length
= ret
->available_bytes
= 0;
909 *ppobj
= PROTOCOL(ret
);