From 237264dc61e362c55d23cfd2fb15da9845721a8d Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Wed, 6 Oct 2010 21:36:44 +0200 Subject: [PATCH] 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 86ddab75ee2..c2b48d2afd3 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 4fb61b3006a..da241e9358e 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 52a24251b71..e95ea6cd5be 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 85af51338f5..669343b211f 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 7391982ac7b..215a868c9fa 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*); };