From: Jacek Caban Subject: urlmon: Use separated variable for InternetQueryDataAvailable to avoid races. Message-Id: <51276EEF.3060606@codeweavers.com> Date: Fri, 22 Feb 2013 14:13:19 +0100 --- dlls/urlmon/protocol.c | 55 +++++++++++++++++++++++++++-------------------- dlls/urlmon/urlmon_main.h | 1 + 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/dlls/urlmon/protocol.c b/dlls/urlmon/protocol.c index c7c61da..890d013 100644 --- a/dlls/urlmon/protocol.c +++ b/dlls/urlmon/protocol.c @@ -349,30 +349,35 @@ HRESULT protocol_continue(Protocol *protocol, PROTOCOLDATA *data) if(data->pData >= UlongToPtr(BINDSTATUS_DOWNLOADINGDATA)) { if(!protocol->available_bytes) { - 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) { - TRACE("available %u bytes\n", protocol->available_bytes); - if(!protocol->available_bytes) { - if(is_start) { - TRACE("empty file\n"); - all_data_read(protocol); - }else { - WARN("unexpected end of file?\n"); - report_result(protocol, INET_E_DOWNLOAD_FAILURE); + if(protocol->query_available) { + protocol->available_bytes = protocol->query_available; + }else { + 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->query_available, 0, 0); + if(res) { + TRACE("available %u bytes\n", protocol->query_available); + if(!protocol->query_available) { + if(is_start) { + TRACE("empty file\n"); + all_data_read(protocol); + }else { + WARN("unexpected end of file?\n"); + report_result(protocol, INET_E_DOWNLOAD_FAILURE); + } + return S_OK; } + protocol->available_bytes = protocol->query_available; + }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; } - }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; } protocol->flags |= FLAG_REQUEST_COMPLETE; @@ -421,12 +426,14 @@ HRESULT protocol_read(Protocol *protocol, void *buf, ULONG size, ULONG *read_ret protocol->current_position += len; protocol->available_bytes -= len; + TRACE("current_position %d, available_bytes %d\n", protocol->current_position, protocol->available_bytes); + if(!protocol->available_bytes) { /* 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); + res = InternetQueryDataAvailable(protocol->request, &protocol->query_available, 0, 0); if(!res) { if (GetLastError() == ERROR_IO_PENDING) { hres = E_PENDING; @@ -438,10 +445,12 @@ HRESULT protocol_read(Protocol *protocol, void *buf, ULONG size, ULONG *read_ret break; } - if(!protocol->available_bytes) { + if(!protocol->query_available) { all_data_read(protocol); break; } + + protocol->available_bytes = protocol->query_available; } } diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h index 01de984..ba23e74 100644 --- a/dlls/urlmon/urlmon_main.h +++ b/dlls/urlmon/urlmon_main.h @@ -104,6 +104,7 @@ typedef struct { ULONG current_position; ULONG content_length; ULONG available_bytes; + ULONG query_available; IStream *post_stream;