Jacek Caban : urlmon: Move HttpProtocol:: Read implementation to generic Protocol object.
Alexandre Julliard
julliard at winehq.org
Mon Mar 2 09:01:40 CST 2009
Module: wine
Branch: master
Commit: 4c129514b5aa9acc4c71e391235a2bb6ec14d462
URL: http://source.winehq.org/git/wine.git/?a=commit;h=4c129514b5aa9acc4c71e391235a2bb6ec14d462
Author: Jacek Caban <jacek at codeweavers.com>
Date: Mon Mar 2 03:20:26 2009 +0100
urlmon: Move HttpProtocol::Read implementation to generic Protocol object.
---
dlls/urlmon/http.c | 80 +-------------------------
dlls/urlmon/protocol.c | 143 +++++++++++++++++++++++++++++++++++++++++++++
dlls/urlmon/urlmon_main.h | 1 +
3 files changed, 145 insertions(+), 79 deletions(-)
diff --git a/dlls/urlmon/http.c b/dlls/urlmon/http.c
index 5d102a6..c7d463b 100644
--- a/dlls/urlmon/http.c
+++ b/dlls/urlmon/http.c
@@ -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,
diff --git a/dlls/urlmon/protocol.c b/dlls/urlmon/protocol.c
index a2e801b..46e6264 100644
--- a/dlls/urlmon/protocol.c
+++ b/dlls/urlmon/protocol.c
@@ -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))
diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h
index 6519630..a75c1ed 100644
--- a/dlls/urlmon/urlmon_main.h
+++ b/dlls/urlmon/urlmon_main.h
@@ -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*);
More information about the wine-cvs
mailing list