Commit 4c129514 authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

urlmon: Move HttpProtocol::Read implementation to generic Protocol object.

parent a30ffca1
......@@ -144,14 +144,6 @@ static void HTTPPROTOCOL_ReportData(HttpProtocol *This)
}
}
static void HTTPPROTOCOL_AllDataRead(HttpProtocol *This)
{
if (!(This->base.flags & FLAG_ALL_DATA_READ))
This->base.flags |= FLAG_ALL_DATA_READ;
HTTPPROTOCOL_ReportData(This);
HTTPPROTOCOL_ReportResult(This, S_OK);
}
static void CALLBACK HTTPPROTOCOL_InternetStatusCallback(
HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
......@@ -735,80 +727,10 @@ static HRESULT WINAPI HttpProtocol_Read(IInternetProtocol *iface, void *pv,
ULONG cb, ULONG *pcbRead)
{
HttpProtocol *This = PROTOCOL_THIS(iface);
ULONG read = 0, len = 0;
HRESULT hres = S_FALSE;
TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
if (!(This->base.flags & FLAG_REQUEST_COMPLETE))
{
hres = E_PENDING;
}
else while (!(This->base.flags & FLAG_ALL_DATA_READ) &&
read < cb)
{
if (This->base.available_bytes == 0)
{
/* 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)
{
hres = E_PENDING;
}
else
{
WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
hres = INET_E_DATA_NOT_AVAILABLE;
HTTPPROTOCOL_ReportResult(This, hres);
}
goto done;
}
else if (This->base.available_bytes == 0)
{
HTTPPROTOCOL_AllDataRead(This);
}
}
else
{
if (!InternetReadFile(This->base.request, ((BYTE *)pv)+read,
This->base.available_bytes > cb-read ?
cb-read : This->base.available_bytes, &len))
{
WARN("InternetReadFile failed: %d\n", GetLastError());
hres = INET_E_DOWNLOAD_FAILURE;
HTTPPROTOCOL_ReportResult(This, hres);
goto done;
}
else if (len == 0)
{
HTTPPROTOCOL_AllDataRead(This);
}
else
{
read += len;
This->base.current_position += len;
This->base.available_bytes -= len;
}
}
}
/* Per MSDN this should be if (read == cb), but native returns S_OK
* if any bytes were read, so we will too */
if (read)
hres = S_OK;
done:
if (pcbRead)
*pcbRead = read;
if (hres != E_PENDING)
This->base.flags |= FLAG_REQUEST_COMPLETE;
return hres;
return protocol_read(&This->base, pv, cb, pcbRead);
}
static HRESULT WINAPI HttpProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
......
......@@ -23,6 +23,149 @@
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
/* Flags are needed for, among other things, return HRESULTs from the Read function
* to conform to native. For example, Read returns:
*
* 1. E_PENDING if called before the request has completed,
* (flags = 0)
* 2. S_FALSE after all data has been read and S_OK has been reported,
* (flags = FLAG_REQUEST_COMPLETE | FLAG_ALL_DATA_READ | FLAG_RESULT_REPORTED)
* 3. INET_E_DATA_NOT_AVAILABLE if InternetQueryDataAvailable fails. The first time
* this occurs, INET_E_DATA_NOT_AVAILABLE will also be reported to the sink,
* (flags = FLAG_REQUEST_COMPLETE)
* but upon subsequent calls to Read no reporting will take place, yet
* InternetQueryDataAvailable will still be called, and, on failure,
* INET_E_DATA_NOT_AVAILABLE will still be returned.
* (flags = FLAG_REQUEST_COMPLETE | FLAG_RESULT_REPORTED)
*
* FLAG_FIRST_DATA_REPORTED and FLAG_LAST_DATA_REPORTED are needed for proper
* ReportData reporting. For example, if OnResponse returns S_OK, Continue will
* report BSCF_FIRSTDATANOTIFICATION, and when all data has been read Read will
* report BSCF_INTERMEDIATEDATANOTIFICATION|BSCF_LASTDATANOTIFICATION. However,
* if OnResponse does not return S_OK, Continue will not report data, and Read
* will report BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION when all
* data has been read.
*/
#define FLAG_REQUEST_COMPLETE 0x0001
#define FLAG_FIRST_CONTINUE_COMPLETE 0x0002
#define FLAG_FIRST_DATA_REPORTED 0x0004
#define FLAG_ALL_DATA_READ 0x0008
#define FLAG_LAST_DATA_REPORTED 0x0010
#define FLAG_RESULT_REPORTED 0x0020
static inline HRESULT report_result(Protocol *protocol, HRESULT hres)
{
if (!(protocol->flags & FLAG_RESULT_REPORTED) && protocol->protocol_sink) {
protocol->flags |= FLAG_RESULT_REPORTED;
IInternetProtocolSink_ReportResult(protocol->protocol_sink, hres, 0, NULL);
}
return hres;
}
static void report_data(Protocol *protocol)
{
DWORD bscf;
if((protocol->flags & FLAG_LAST_DATA_REPORTED) || !protocol->protocol_sink)
return;
if(protocol->flags & FLAG_FIRST_DATA_REPORTED) {
bscf = BSCF_INTERMEDIATEDATANOTIFICATION;
}else {
protocol->flags |= FLAG_FIRST_DATA_REPORTED;
bscf = BSCF_FIRSTDATANOTIFICATION;
}
if(protocol->flags & FLAG_ALL_DATA_READ && !(protocol->flags & FLAG_LAST_DATA_REPORTED)) {
protocol->flags |= FLAG_LAST_DATA_REPORTED;
bscf |= BSCF_LASTDATANOTIFICATION;
}
IInternetProtocolSink_ReportData(protocol->protocol_sink, bscf,
protocol->current_position+protocol->available_bytes,
protocol->content_length);
}
static void all_data_read(Protocol *protocol)
{
protocol->flags |= FLAG_ALL_DATA_READ;
report_data(protocol);
report_result(protocol, S_OK);
}
HRESULT protocol_read(Protocol *protocol, void *buf, ULONG size, ULONG *read_ret)
{
ULONG read = 0;
BOOL res;
HRESULT hres = S_FALSE;
if(!(protocol->flags & FLAG_REQUEST_COMPLETE)) {
*read_ret = 0;
return E_PENDING;
}
if(protocol->flags & FLAG_ALL_DATA_READ) {
*read_ret = 0;
return S_FALSE;
}
while(read < size) {
if(protocol->available_bytes) {
ULONG len;
res = InternetReadFile(protocol->request, ((BYTE *)buf)+read,
protocol->available_bytes > size-read ? size-read : protocol->available_bytes, &len);
if(!res) {
WARN("InternetReadFile failed: %d\n", GetLastError());
hres = INET_E_DOWNLOAD_FAILURE;
report_result(protocol, hres);
break;
}
if(!len) {
all_data_read(protocol);
break;
}
read += len;
protocol->current_position += len;
protocol->available_bytes -= len;
}else {
/* 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) {
if (GetLastError() == ERROR_IO_PENDING) {
hres = E_PENDING;
}else {
WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
hres = INET_E_DATA_NOT_AVAILABLE;
report_result(protocol, hres);
}
break;
}
if(!protocol->available_bytes) {
all_data_read(protocol);
break;
}
}
}
*read_ret = read;
if (hres != E_PENDING)
protocol->flags |= FLAG_REQUEST_COMPLETE;
if(FAILED(hres))
return hres;
return read ? S_OK : S_FALSE;
}
HRESULT protocol_lock_request(Protocol *protocol)
{
if (!InternetLockRequestFile(protocol->request, &protocol->lock))
......
......@@ -106,6 +106,7 @@ struct ProtocolVtbl {
void (*close_connection)(Protocol*);
};
HRESULT protocol_read(Protocol*,void*,ULONG,ULONG*);
HRESULT protocol_lock_request(Protocol*);
HRESULT protocol_unlock_request(Protocol*);
void protocol_close_connection(Protocol*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment