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