Jacek Caban : urlmon: Added support for sending post data from stream.

Alexandre Julliard julliard at winehq.org
Thu Oct 7 11:24:24 CDT 2010


Module: wine
Branch: master
Commit: 237264dc61e362c55d23cfd2fb15da9845721a8d
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=237264dc61e362c55d23cfd2fb15da9845721a8d

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Oct  6 21:36:44 2010 +0200

urlmon: Added support for sending post data from stream.

---

 dlls/urlmon/ftp.c         |    6 +++++
 dlls/urlmon/gopher.c      |    6 +++++
 dlls/urlmon/http.c        |   53 +++++++++++++++++++++++++++++++++++++-------
 dlls/urlmon/protocol.c    |   46 +++++++++++++++++++++++++++++++++++++++
 dlls/urlmon/urlmon_main.h |    3 ++
 5 files changed, 105 insertions(+), 9 deletions(-)

diff --git a/dlls/urlmon/ftp.c b/dlls/urlmon/ftp.c
index 86ddab7..c2b48d2 100644
--- a/dlls/urlmon/ftp.c
+++ b/dlls/urlmon/ftp.c
@@ -59,6 +59,11 @@ static HRESULT FtpProtocol_open_request(Protocol *prot, IUri *uri, DWORD request
     return S_OK;
 }
 
+static HRESULT FtpProtocol_end_request(Protocol *prot)
+{
+    return E_NOTIMPL;
+}
+
 static HRESULT FtpProtocol_start_downloading(Protocol *prot)
 {
     FtpProtocol *This = ASYNCPROTOCOL_THIS(prot);
@@ -82,6 +87,7 @@ static void FtpProtocol_close_connection(Protocol *prot)
 
 static const ProtocolVtbl AsyncProtocolVtbl = {
     FtpProtocol_open_request,
+    FtpProtocol_end_request,
     FtpProtocol_start_downloading,
     FtpProtocol_close_connection
 };
diff --git a/dlls/urlmon/gopher.c b/dlls/urlmon/gopher.c
index 4fb61b3..da241e9 100644
--- a/dlls/urlmon/gopher.c
+++ b/dlls/urlmon/gopher.c
@@ -56,6 +56,11 @@ static HRESULT GopherProtocol_open_request(Protocol *prot, IUri *uri, DWORD requ
     return S_OK;
 }
 
+static HRESULT GopherProtocol_end_request(Protocol *prot)
+{
+    return E_NOTIMPL;
+}
+
 static HRESULT GopherProtocol_start_downloading(Protocol *prot)
 {
     return S_OK;
@@ -69,6 +74,7 @@ static void GopherProtocol_close_connection(Protocol *prot)
 
 static const ProtocolVtbl AsyncProtocolVtbl = {
     GopherProtocol_open_request,
+    GopherProtocol_end_request,
     GopherProtocol_start_downloading,
     GopherProtocol_close_connection
 };
diff --git a/dlls/urlmon/http.c b/dlls/urlmon/http.c
index 52a2425..e95ea6c 100644
--- a/dlls/urlmon/http.c
+++ b/dlls/urlmon/http.c
@@ -71,7 +71,8 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
         HINTERNET internet_session, IInternetBindInfo *bind_info)
 {
     HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
-    LPWSTR addl_header = NULL, post_cookie = NULL, optional = NULL;
+    INTERNET_BUFFERSW send_buffer = {sizeof(INTERNET_BUFFERSW)};
+    LPWSTR addl_header = NULL, post_cookie = NULL;
     IServiceProvider *service_provider = NULL;
     IHttpNegotiate2 *http_negotiate2 = NULL;
     BSTR url, host, user, pass, path;
@@ -220,13 +221,30 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
         }
     }
 
+    send_buffer.lpcszHeader = This->full_header;
+    send_buffer.dwHeadersLength = send_buffer.dwHeadersTotal = strlenW(This->full_header);
+
     if(This->base.bind_info.dwBindVerb != BINDVERB_GET) {
-        /* Native does not use GlobalLock/GlobalUnlock, so we won't either */
-        if (This->base.bind_info.stgmedData.tymed != TYMED_HGLOBAL)
-            WARN("Expected This->base.bind_info.stgmedData.tymed to be TYMED_HGLOBAL, not %d\n",
-                 This->base.bind_info.stgmedData.tymed);
-        else
-            optional = (LPWSTR)This->base.bind_info.stgmedData.u.hGlobal;
+        switch(This->base.bind_info.stgmedData.tymed) {
+        case TYMED_HGLOBAL:
+            /* Native does not use GlobalLock/GlobalUnlock, so we won't either */
+            send_buffer.lpvBuffer = This->base.bind_info.stgmedData.u.hGlobal;
+            send_buffer.dwBufferLength = send_buffer.dwBufferTotal = This->base.bind_info.cbstgmedData;
+            break;
+        case TYMED_ISTREAM: {
+            LARGE_INTEGER offset;
+
+            send_buffer.dwBufferTotal = This->base.bind_info.cbstgmedData;
+            This->base.post_stream = This->base.bind_info.stgmedData.u.pstm;
+            IStream_AddRef(This->base.post_stream);
+
+            offset.QuadPart = 0;
+            IStream_Seek(This->base.post_stream, offset, STREAM_SEEK_SET, NULL);
+            break;
+        }
+        default:
+            FIXME("Unsupported This->base.bind_info.stgmedData.tymed %d\n", This->base.bind_info.stgmedData.tymed);
+        }
     }
 
     b = TRUE;
@@ -234,8 +252,11 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
     if(!res)
         WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %08x\n", GetLastError());
 
-    res = HttpSendRequestW(This->base.request, This->full_header, lstrlenW(This->full_header),
-            optional, optional ? This->base.bind_info.cbstgmedData : 0);
+    if(This->base.post_stream)
+        res = HttpSendRequestExW(This->base.request, &send_buffer, NULL, 0, 0);
+    else
+        res = HttpSendRequestW(This->base.request, send_buffer.lpcszHeader, send_buffer.dwHeadersLength,
+                send_buffer.lpvBuffer, send_buffer.dwBufferLength);
     if(!res && GetLastError() != ERROR_IO_PENDING) {
         WARN("HttpSendRequest failed: %d\n", GetLastError());
         return INET_E_DOWNLOAD_FAILURE;
@@ -244,6 +265,19 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
     return S_OK;
 }
 
+static HRESULT HttpProtocol_end_request(Protocol *protocol)
+{
+    BOOL res;
+
+    res = HttpEndRequestW(protocol->request, NULL, 0, 0);
+    if(!res && GetLastError() != ERROR_IO_PENDING) {
+        FIXME("HttpEndRequest failed: %u\n", GetLastError());
+        return E_FAIL;
+    }
+
+    return S_OK;
+}
+
 static HRESULT HttpProtocol_start_downloading(Protocol *prot)
 {
     HttpProtocol *This = ASYNCPROTOCOL_THIS(prot);
@@ -332,6 +366,7 @@ static void HttpProtocol_close_connection(Protocol *prot)
 
 static const ProtocolVtbl AsyncProtocolVtbl = {
     HttpProtocol_open_request,
+    HttpProtocol_end_request,
     HttpProtocol_start_downloading,
     HttpProtocol_close_connection
 };
diff --git a/dlls/urlmon/protocol.c b/dlls/urlmon/protocol.c
index 85af513..669343b 100644
--- a/dlls/urlmon/protocol.c
+++ b/dlls/urlmon/protocol.c
@@ -104,6 +104,8 @@ static void request_complete(Protocol *protocol, INTERNET_ASYNC_RESULT *ar)
 {
     PROTOCOLDATA data;
 
+    TRACE("(%p)->(%p)\n", protocol, ar);
+
     if(!ar->dwResult) {
         WARN("request failed: %d\n", ar->dwError);
         return;
@@ -191,6 +193,42 @@ static void WINAPI internet_status_callback(HINTERNET internet, DWORD_PTR contex
     }
 }
 
+static HRESULT write_post_stream(Protocol *protocol)
+{
+    BYTE buf[0x20000];
+    DWORD written;
+    ULONG size;
+    BOOL res;
+    HRESULT hres;
+
+    protocol->flags &= ~FLAG_REQUEST_COMPLETE;
+
+    while(1) {
+        size = 0;
+        hres = IStream_Read(protocol->post_stream, buf, sizeof(buf), &size);
+        if(FAILED(hres) || !size)
+            break;
+        res = InternetWriteFile(protocol->request, buf, size, &written);
+        if(!res) {
+            FIXME("InternetWriteFile failed: %u\n", GetLastError());
+            hres = E_FAIL;
+            break;
+        }
+    }
+
+    if(SUCCEEDED(hres)) {
+        IStream_Release(protocol->post_stream);
+        protocol->post_stream = NULL;
+
+        hres = protocol->vtbl->end_request(protocol);
+    }
+
+    if(FAILED(hres))
+        return report_result(protocol, hres);
+
+    return S_OK;
+}
+
 static HINTERNET create_internet_session(IInternetBindInfo *bind_info)
 {
     LPWSTR global_user_agent = NULL;
@@ -293,6 +331,9 @@ HRESULT protocol_continue(Protocol *protocol, PROTOCOLDATA *data)
         return S_OK;
     }
 
+    if(protocol->post_stream)
+        return write_post_stream(protocol);
+
     if(data->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA) {
         hres = protocol->vtbl->start_downloading(protocol);
         if(FAILED(hres)) {
@@ -450,5 +491,10 @@ void protocol_close_connection(Protocol *protocol)
     if(protocol->connection)
         InternetCloseHandle(protocol->connection);
 
+    if(protocol->post_stream) {
+        IStream_Release(protocol->post_stream);
+        protocol->post_stream = NULL;
+    }
+
     protocol->flags = 0;
 }
diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h
index 7391982..215a868 100644
--- a/dlls/urlmon/urlmon_main.h
+++ b/dlls/urlmon/urlmon_main.h
@@ -103,11 +103,14 @@ typedef struct {
     ULONG content_length;
     ULONG available_bytes;
 
+    IStream *post_stream;
+
     LONG priority;
 } Protocol;
 
 struct ProtocolVtbl {
     HRESULT (*open_request)(Protocol*,IUri*,DWORD,HINTERNET,IInternetBindInfo*);
+    HRESULT (*end_request)(Protocol*);
     HRESULT (*start_downloading)(Protocol*);
     void (*close_connection)(Protocol*);
 };




More information about the wine-cvs mailing list