Hans Leidekker : winhttp: Implement IWinHttpRequest::get_ResponseStream.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Feb 16 10:01:21 CST 2015
Module: wine
Branch: master
Commit: 5505413a81c67547f72236674619c8ee9025a89c
URL: http://source.winehq.org/git/wine.git/?a=commit;h=5505413a81c67547f72236674619c8ee9025a89c
Author: Hans Leidekker <hans at 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 );
More information about the wine-cvs
mailing list