From c2ffe977793a62a4c0bfddda395d9baf6e602826 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 2 Mar 2009 03:20:46 +0100 Subject: [PATCH] urlmon: Move HttpProtocol::Continue implementation to generic Protocol object. --- dlls/urlmon/http.c | 271 ++++++++++++-------------------------- dlls/urlmon/protocol.c | 68 ++++++++++ dlls/urlmon/urlmon_main.h | 2 + 3 files changed, 157 insertions(+), 184 deletions(-) diff --git a/dlls/urlmon/http.c b/dlls/urlmon/http.c index c7d463bdc87..5ec4cce9573 100644 --- a/dlls/urlmon/http.c +++ b/dlls/urlmon/http.c @@ -80,8 +80,93 @@ typedef struct { static const WCHAR wszHeaders[] = {'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}; +static LPWSTR query_http_info(HttpProtocol *This, DWORD option) +{ + LPWSTR ret = NULL; + DWORD len = 0; + BOOL res; + + res = HttpQueryInfoW(This->base.request, option, NULL, &len, NULL); + if (!res && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + ret = heap_alloc(len); + res = HttpQueryInfoW(This->base.request, option, ret, &len, NULL); + } + if(!res) { + TRACE("HttpQueryInfoW(%d) failed: %08x\n", option, GetLastError()); + heap_free(ret); + return NULL; + } + + return ret; +} + #define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(HttpProtocol, base, iface) +static HRESULT HttpProtocol_start_downloading(Protocol *prot) +{ + HttpProtocol *This = ASYNCPROTOCOL_THIS(prot); + LPWSTR content_type = 0, content_length = 0; + DWORD len = sizeof(DWORD); + DWORD status_code; + BOOL res; + HRESULT hres; + + static const WCHAR wszDefaultContentType[] = + {'t','e','x','t','/','h','t','m','l',0}; + + if(!This->http_negotiate) { + WARN("Expected IHttpNegotiate pointer to be non-NULL\n"); + return S_OK; + } + + res = HttpQueryInfoW(This->base.request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, + &status_code, &len, NULL); + if(res) { + LPWSTR response_headers = query_http_info(This, HTTP_QUERY_RAW_HEADERS_CRLF); + if(response_headers) { + hres = IHttpNegotiate_OnResponse(This->http_negotiate, status_code, response_headers, + NULL, NULL); + heap_free(response_headers); + if (hres != S_OK) { + WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres); + return S_OK; + } + } + }else { + WARN("HttpQueryInfo failed: %d\n", GetLastError()); + } + + if(This->https) + IInternetProtocolSink_ReportProgress(This->base.protocol_sink, BINDSTATUS_ACCEPTRANGES, NULL); + + content_type = query_http_info(This, HTTP_QUERY_CONTENT_TYPE); + if(content_type) { + /* remove the charset, if present */ + LPWSTR p = strchrW(content_type, ';'); + if (p) *p = '\0'; + + IInternetProtocolSink_ReportProgress(This->base.protocol_sink, + (This->base.bindf & BINDF_FROMURLMON) + ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE, + content_type); + heap_free(content_type); + }else { + WARN("HttpQueryInfo failed: %d\n", GetLastError()); + IInternetProtocolSink_ReportProgress(This->base.protocol_sink, + (This->base.bindf & BINDF_FROMURLMON) + ? BINDSTATUS_MIMETYPEAVAILABLE : BINDSTATUS_RAWMIMETYPE, + wszDefaultContentType); + } + + content_length = query_http_info(This, HTTP_QUERY_CONTENT_LENGTH); + if(content_length) { + This->base.content_length = atoiW(content_length); + heap_free(content_length); + } + + return S_OK; +} + static void HttpProtocol_close_connection(Protocol *prot) { HttpProtocol *This = ASYNCPROTOCOL_THIS(prot); @@ -104,46 +189,10 @@ static void HttpProtocol_close_connection(Protocol *prot) #undef ASYNCPROTOCOL_THIS static const ProtocolVtbl AsyncProtocolVtbl = { + HttpProtocol_start_downloading, HttpProtocol_close_connection }; -static void HTTPPROTOCOL_ReportResult(HttpProtocol *This, HRESULT hres) -{ - if (!(This->base.flags & FLAG_RESULT_REPORTED) && - This->base.protocol_sink) - { - This->base.flags |= FLAG_RESULT_REPORTED; - IInternetProtocolSink_ReportResult(This->base.protocol_sink, hres, 0, NULL); - } -} - -static void HTTPPROTOCOL_ReportData(HttpProtocol *This) -{ - DWORD bscf; - if (!(This->base.flags & FLAG_LAST_DATA_REPORTED) && - This->base.protocol_sink) - { - if (This->base.flags & FLAG_FIRST_DATA_REPORTED) - { - bscf = BSCF_INTERMEDIATEDATANOTIFICATION; - } - else - { - This->base.flags |= FLAG_FIRST_DATA_REPORTED; - bscf = BSCF_FIRSTDATANOTIFICATION; - } - if (This->base.flags & FLAG_ALL_DATA_READ && - !(This->base.flags & FLAG_LAST_DATA_REPORTED)) - { - This->base.flags |= FLAG_LAST_DATA_REPORTED; - bscf |= BSCF_LASTDATANOTIFICATION; - } - IInternetProtocolSink_ReportData(This->base.protocol_sink, bscf, - This->base.current_position+This->base.available_bytes, - This->base.content_length); - } -} - static void CALLBACK HTTPPROTOCOL_InternetStatusCallback( HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) @@ -539,156 +588,10 @@ done: static HRESULT WINAPI HttpProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) { HttpProtocol *This = PROTOCOL_THIS(iface); - DWORD len = sizeof(DWORD), status_code; - LPWSTR response_headers = 0, content_type = 0, content_length = 0; - - static const WCHAR wszDefaultContentType[] = - {'t','e','x','t','/','h','t','m','l',0}; TRACE("(%p)->(%p)\n", This, pProtocolData); - if (!pProtocolData) - { - WARN("Expected pProtocolData to be non-NULL\n"); - return S_OK; - } - else if (!This->base.request) - { - WARN("Expected request to be non-NULL\n"); - return S_OK; - } - else if (!This->http_negotiate) - { - WARN("Expected IHttpNegotiate pointer to be non-NULL\n"); - return S_OK; - } - else if (!This->base.protocol_sink) - { - WARN("Expected IInternetProtocolSink pointer to be non-NULL\n"); - return S_OK; - } - - if (pProtocolData->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA) - { - if (!HttpQueryInfoW(This->base.request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, - &status_code, &len, NULL)) - { - WARN("HttpQueryInfo failed: %d\n", GetLastError()); - } - else - { - len = 0; - if ((!HttpQueryInfoW(This->base.request, HTTP_QUERY_RAW_HEADERS_CRLF, response_headers, &len, - NULL) && - GetLastError() != ERROR_INSUFFICIENT_BUFFER) || - !(response_headers = heap_alloc(len)) || - !HttpQueryInfoW(This->base.request, HTTP_QUERY_RAW_HEADERS_CRLF, response_headers, &len, - NULL)) - { - WARN("HttpQueryInfo failed: %d\n", GetLastError()); - } - else - { - HRESULT hres = IHttpNegotiate_OnResponse(This->http_negotiate, status_code, - response_headers, NULL, NULL); - if (hres != S_OK) - { - WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres); - goto done; - } - } - } - - if(This->https) - IInternetProtocolSink_ReportProgress(This->base.protocol_sink, BINDSTATUS_ACCEPTRANGES, NULL); - - len = 0; - if ((!HttpQueryInfoW(This->base.request, HTTP_QUERY_CONTENT_TYPE, content_type, &len, NULL) && - GetLastError() != ERROR_INSUFFICIENT_BUFFER) || - !(content_type = heap_alloc(len)) || - !HttpQueryInfoW(This->base.request, HTTP_QUERY_CONTENT_TYPE, content_type, &len, NULL)) - { - WARN("HttpQueryInfo failed: %d\n", GetLastError()); - IInternetProtocolSink_ReportProgress(This->base.protocol_sink, - (This->base.bindf & BINDF_FROMURLMON) ? - BINDSTATUS_MIMETYPEAVAILABLE : - BINDSTATUS_RAWMIMETYPE, - wszDefaultContentType); - } - else - { - /* remove the charset, if present */ - LPWSTR p = strchrW(content_type, ';'); - if (p) *p = '\0'; - - IInternetProtocolSink_ReportProgress(This->base.protocol_sink, - (This->base.bindf & BINDF_FROMURLMON) ? - BINDSTATUS_MIMETYPEAVAILABLE : - BINDSTATUS_RAWMIMETYPE, - content_type); - } - - len = 0; - if ((!HttpQueryInfoW(This->base.request, HTTP_QUERY_CONTENT_LENGTH, content_length, &len, NULL) && - GetLastError() != ERROR_INSUFFICIENT_BUFFER) || - !(content_length = heap_alloc(len)) || - !HttpQueryInfoW(This->base.request, HTTP_QUERY_CONTENT_LENGTH, content_length, &len, NULL)) - { - WARN("HttpQueryInfo failed: %d\n", GetLastError()); - This->base.content_length = 0; - } - else - { - This->base.content_length = atoiW(content_length); - } - - if(This->base.bindf & BINDF_NEEDFILE) { - WCHAR cache_file[MAX_PATH]; - DWORD buflen = sizeof(cache_file); - - if(InternetQueryOptionW(This->base.request, INTERNET_OPTION_DATAFILE_NAME, - cache_file, &buflen)) - { - IInternetProtocolSink_ReportProgress(This->base.protocol_sink, - BINDSTATUS_CACHEFILENAMEAVAILABLE, - cache_file); - }else { - FIXME("Could not get cache file\n"); - } - } - - This->base.flags |= FLAG_FIRST_CONTINUE_COMPLETE; - } - - if (pProtocolData->pData >= (LPVOID)BINDSTATUS_DOWNLOADINGDATA) - { - /* InternetQueryDataAvailable may immediately fork and perform its asynchronous - * read, so clear the flag _before_ calling so it does not incorrectly get cleared - * after the status callback is called */ - This->base.flags &= ~FLAG_REQUEST_COMPLETE; - if (!InternetQueryDataAvailable(This->base.request, &This->base.available_bytes, 0, 0)) - { - if (GetLastError() != ERROR_IO_PENDING) - { - This->base.flags |= FLAG_REQUEST_COMPLETE; - WARN("InternetQueryDataAvailable failed: %d\n", GetLastError()); - HTTPPROTOCOL_ReportResult(This, INET_E_DATA_NOT_AVAILABLE); - } - } - else - { - This->base.flags |= FLAG_REQUEST_COMPLETE; - HTTPPROTOCOL_ReportData(This); - } - } - -done: - heap_free(response_headers); - heap_free(content_type); - heap_free(content_length); - - /* Returns S_OK on native */ - return S_OK; + return protocol_continue(&This->base, pProtocolData); } static HRESULT WINAPI HttpProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, diff --git a/dlls/urlmon/protocol.c b/dlls/urlmon/protocol.c index 46e6264c707..903e2bebff9 100644 --- a/dlls/urlmon/protocol.c +++ b/dlls/urlmon/protocol.c @@ -53,6 +53,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); #define FLAG_LAST_DATA_REPORTED 0x0010 #define FLAG_RESULT_REPORTED 0x0020 +static inline HRESULT report_progress(Protocol *protocol, ULONG status_code, LPCWSTR status_text) +{ + return IInternetProtocolSink_ReportProgress(protocol->protocol_sink, status_code, status_text); +} + static inline HRESULT report_result(Protocol *protocol, HRESULT hres) { if (!(protocol->flags & FLAG_RESULT_REPORTED) && protocol->protocol_sink) { @@ -95,6 +100,69 @@ static void all_data_read(Protocol *protocol) report_result(protocol, S_OK); } +HRESULT protocol_continue(Protocol *protocol, PROTOCOLDATA *data) +{ + HRESULT hres; + + if (!data) { + WARN("Expected pProtocolData to be non-NULL\n"); + return S_OK; + } + + if(!protocol->request) { + WARN("Expected request to be non-NULL\n"); + return S_OK; + } + + if(!protocol->protocol_sink) { + WARN("Expected IInternetProtocolSink pointer to be non-NULL\n"); + return S_OK; + } + + if(data->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA) { + hres = protocol->vtbl->start_downloading(protocol); + if(FAILED(hres)) { + protocol_close_connection(protocol); + report_result(protocol, hres); + return S_OK; + } + + if(protocol->bindf & BINDF_NEEDFILE) { + WCHAR cache_file[MAX_PATH]; + DWORD buflen = sizeof(cache_file); + + if(InternetQueryOptionW(protocol->request, INTERNET_OPTION_DATAFILE_NAME, + cache_file, &buflen)) { + report_progress(protocol, BINDSTATUS_CACHEFILENAMEAVAILABLE, cache_file); + }else { + FIXME("Could not get cache file\n"); + } + } + + protocol->flags |= FLAG_FIRST_CONTINUE_COMPLETE; + } + + if(data->pData >= (LPVOID)BINDSTATUS_DOWNLOADINGDATA) { + BOOL res; + + /* InternetQueryDataAvailable may immediately fork and perform its asynchronous + * read, so clear the flag _before_ calling so it does not incorrectly get cleared + * after the status callback is called */ + protocol->flags &= ~FLAG_REQUEST_COMPLETE; + res = InternetQueryDataAvailable(protocol->request, &protocol->available_bytes, 0, 0); + if(res) { + protocol->flags |= FLAG_REQUEST_COMPLETE; + report_data(protocol); + }else if(GetLastError() != ERROR_IO_PENDING) { + protocol->flags |= FLAG_REQUEST_COMPLETE; + WARN("InternetQueryDataAvailable failed: %d\n", GetLastError()); + report_result(protocol, INET_E_DATA_NOT_AVAILABLE); + } + } + + return S_OK; +} + HRESULT protocol_read(Protocol *protocol, void *buf, ULONG size, ULONG *read_ret) { ULONG read = 0; diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h index a75c1ed21ab..f9871fb0e5c 100644 --- a/dlls/urlmon/urlmon_main.h +++ b/dlls/urlmon/urlmon_main.h @@ -103,9 +103,11 @@ typedef struct { } Protocol; struct ProtocolVtbl { + HRESULT (*start_downloading)(Protocol*); void (*close_connection)(Protocol*); }; +HRESULT protocol_continue(Protocol*,PROTOCOLDATA*); HRESULT protocol_read(Protocol*,void*,ULONG,ULONG*); HRESULT protocol_lock_request(Protocol*); HRESULT protocol_unlock_request(Protocol*);