Module: wine Branch: master Commit: 5505413a81c67547f72236674619c8ee9025a89c URL: http://source.winehq.org/git/wine.git/?a=commit;h=5505413a81c67547f722366746...
Author: Hans Leidekker hans@codeweavers.com Date: Mon Feb 16 14:41:47 2015 +0100
winhttp: Implement IWinHttpRequest::get_ResponseStream.
---
dlls/winhttp/request.c | 195 ++++++++++++++++++++++++++++++++++++++++++- dlls/winhttp/tests/winhttp.c | 63 ++++++++++++-- 2 files changed, 248 insertions(+), 10 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 135a291..a12d73a 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3695,12 +3695,203 @@ done: return HRESULT_FROM_WIN32( err ); }
+struct stream +{ + IStream IStream_iface; + LONG refs; + char *data; + ULARGE_INTEGER pos, size; +}; + +static inline struct stream *impl_from_IStream( IStream *iface ) +{ + return CONTAINING_RECORD( iface, struct stream, IStream_iface ); +} + +static HRESULT WINAPI stream_QueryInterface( IStream *iface, REFIID riid, void **obj ) +{ + struct stream *stream = impl_from_IStream( iface ); + + TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), obj); + + if (IsEqualGUID( riid, &IID_IStream ) || IsEqualGUID( riid, &IID_IUnknown )) + { + *obj = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + IStream_AddRef( iface ); + return S_OK; +} + +static ULONG WINAPI stream_AddRef( IStream *iface ) +{ + struct stream *stream = impl_from_IStream( iface ); + return InterlockedIncrement( &stream->refs ); +} + +static ULONG WINAPI stream_Release( IStream *iface ) +{ + struct stream *stream = impl_from_IStream( iface ); + LONG refs = InterlockedDecrement( &stream->refs ); + if (!refs) + { + heap_free( stream->data ); + heap_free( stream ); + } + return refs; +} + +static HRESULT WINAPI stream_Read( IStream *iface, void *buf, ULONG len, ULONG *read ) +{ + struct stream *stream = impl_from_IStream( iface ); + ULONG size; + + if (stream->pos.QuadPart >= stream->size.QuadPart) + { + *read = 0; + return S_FALSE; + } + + size = min( stream->size.QuadPart - stream->pos.QuadPart, len ); + memcpy( buf, stream->data + stream->pos.QuadPart, size ); + stream->pos.QuadPart += size; + *read = size; + + return S_OK; +} + +static HRESULT WINAPI stream_Write( IStream *iface, const void *buf, ULONG len, ULONG *written ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Seek( IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos ) +{ + struct stream *stream = impl_from_IStream( iface ); + + if (origin == STREAM_SEEK_SET) + stream->pos.QuadPart = move.QuadPart; + else if (origin == STREAM_SEEK_CUR) + stream->pos.QuadPart += move.QuadPart; + else if (origin == STREAM_SEEK_END) + stream->pos.QuadPart = stream->size.QuadPart - move.QuadPart; + + if (newpos) newpos->QuadPart = stream->pos.QuadPart; + return S_OK; +} + +static HRESULT WINAPI stream_SetSize( IStream *iface, ULARGE_INTEGER newsize ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_CopyTo( IStream *iface, IStream *stream, ULARGE_INTEGER len, ULARGE_INTEGER *read, + ULARGE_INTEGER *written ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Commit( IStream *iface, DWORD flags ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Revert( IStream *iface ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_LockRegion( IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER len, DWORD locktype ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_UnlockRegion( IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER len, DWORD locktype ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Stat( IStream *iface, STATSTG *stg, DWORD flag ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Clone( IStream *iface, IStream **stream ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static const IStreamVtbl stream_vtbl = +{ + stream_QueryInterface, + stream_AddRef, + stream_Release, + stream_Read, + stream_Write, + stream_Seek, + stream_SetSize, + stream_CopyTo, + stream_Commit, + stream_Revert, + stream_LockRegion, + stream_UnlockRegion, + stream_Stat, + stream_Clone +}; + static HRESULT WINAPI winhttp_request_get_ResponseStream( IWinHttpRequest *iface, VARIANT *body ) { - FIXME("\n"); - return E_NOTIMPL; + struct winhttp_request *request = impl_from_IWinHttpRequest( iface ); + DWORD err = ERROR_SUCCESS; + struct stream *stream; + + TRACE("%p, %p\n", request, body); + + if (!body) return E_INVALIDARG; + + EnterCriticalSection( &request->cs ); + if (request->state < REQUEST_STATE_SENT) + { + err = ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND; + goto done; + } + if (!(stream = heap_alloc( sizeof(*stream) ))) + { + err = ERROR_OUTOFMEMORY; + goto done; + } + stream->IStream_iface.lpVtbl = &stream_vtbl; + stream->refs = 1; + if (!(stream->data = heap_alloc( request->offset ))) + { + heap_free( stream ); + err = ERROR_OUTOFMEMORY; + goto done; + } + memcpy( stream->data, request->buffer, request->offset ); + stream->pos.QuadPart = 0; + stream->size.QuadPart = request->offset; + V_VT( body ) = VT_UNKNOWN; + V_UNKNOWN( body ) = (IUnknown *)&stream->IStream_iface; + +done: + LeaveCriticalSection( &request->cs ); + return HRESULT_FROM_WIN32( err ); }
static HRESULT WINAPI winhttp_request_get_Option( diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index 2cad807..1423cef 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -2624,11 +2624,15 @@ static void test_IWinHttpRequest(void) IWinHttpRequest *req; BSTR method, url, username, password, response = NULL, status_text = NULL, headers = NULL; BSTR date, today, connection, value = NULL; - VARIANT async, empty, timeout, body, proxy_server, bypass_list, data; + VARIANT async, empty, timeout, body, body2, proxy_server, bypass_list, data; VARIANT_BOOL succeeded; LONG status; WCHAR todayW[WINHTTP_TIME_FORMAT_BUFSIZE]; SYSTEMTIME st; + IStream *stream, *stream2; + LARGE_INTEGER pos; + char buf[128]; + DWORD count;
GetSystemTime( &st ); WinHttpTimeFromSystemTime( &st, todayW ); @@ -2680,8 +2684,7 @@ static void test_IWinHttpRequest(void) hr = IWinHttpRequest_Abort( req ); ok( hr == S_OK, "got %08x\n", hr );
- hr = IWinHttpRequest_Release( req ); - ok( hr == S_OK, "got %08x\n", hr ); + IWinHttpRequest_Release( req );
hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); ok( hr == S_OK, "got %08x\n", hr ); @@ -2714,8 +2717,7 @@ static void test_IWinHttpRequest(void) hr = IWinHttpRequest_Abort( req ); ok( hr == S_OK, "got %08x\n", hr );
- hr = IWinHttpRequest_Release( req ); - ok( hr == S_OK, "got %08x\n", hr ); + IWinHttpRequest_Release( req );
hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); ok( hr == S_OK, "got %08x\n", hr ); @@ -2974,6 +2976,41 @@ static void test_IWinHttpRequest(void) hr = VariantClear( &body ); ok( hr == S_OK, "got %08x\n", hr );
+ VariantInit( &body ); + V_VT( &body ) = VT_ERROR; + hr = IWinHttpRequest_get_ResponseStream( req, &body ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( V_VT( &body ) == VT_UNKNOWN, "got %08x\n", V_VT( &body ) ); + + hr = IUnknown_QueryInterface( V_UNKNOWN( &body ), &IID_IStream, (void **)&stream ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( V_UNKNOWN( &body ) == (IUnknown *)stream, "got different interface pointer\n" ); + + buf[0] = 0; + count = 0xdeadbeef; + hr = IStream_Read( stream, buf, 128, &count ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( count != 0xdeadbeef, "count not set\n" ); + ok( buf[0], "no data\n" ); + + VariantInit( &body2 ); + V_VT( &body2 ) = VT_ERROR; + hr = IWinHttpRequest_get_ResponseStream( req, &body2 ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( V_VT( &body2 ) == VT_UNKNOWN, "got %08x\n", V_VT( &body2 ) ); + ok( V_UNKNOWN( &body ) != V_UNKNOWN( &body2 ), "got same interface pointer\n" ); + + hr = IUnknown_QueryInterface( V_UNKNOWN( &body2 ), &IID_IStream, (void **)&stream2 ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( V_UNKNOWN( &body2 ) == (IUnknown *)stream2, "got different interface pointer\n" ); + IStream_Release( stream2 ); + + hr = VariantClear( &body ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = VariantClear( &body2 ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = IWinHttpRequest_SetProxy( req, HTTPREQUEST_PROXYSETTING_PROXY, proxy_server, bypass_list ); ok( hr == S_OK, "got %08x\n", hr );
@@ -3003,8 +3040,19 @@ static void test_IWinHttpRequest(void) hr = IWinHttpRequest_Abort( req ); ok( hr == S_OK, "got %08x\n", hr );
- hr = IWinHttpRequest_Release( req ); + IWinHttpRequest_Release( req ); + + pos.QuadPart = 0; + IStream_Seek( stream, pos, STREAM_SEEK_SET, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + buf[0] = 0; + count = 0xdeadbeef; + hr = IStream_Read( stream, buf, 128, &count ); ok( hr == S_OK, "got %08x\n", hr ); + ok( count != 0xdeadbeef, "count not set\n" ); + ok( buf[0], "no data\n" ); + IStream_Release( stream );
hr = CoCreateInstance( &CLSID_WinHttpRequest, NULL, CLSCTX_INPROC_SERVER, &IID_IWinHttpRequest, (void **)&req ); ok( hr == S_OK, "got %08x\n", hr ); @@ -3020,8 +3068,7 @@ static void test_IWinHttpRequest(void) hr = IWinHttpRequest_WaitForResponse( req, timeout, &succeeded ); ok( hr == S_OK, "got %08x\n", hr );
- hr = IWinHttpRequest_Release( req ); - ok( hr == S_OK, "got %08x\n", hr ); + IWinHttpRequest_Release( req );
SysFreeString( method ); SysFreeString( url );