[8/8] webservices: Implement WsReceiveMessage.

Hans Leidekker hans at codeweavers.com
Wed Sep 28 05:38:06 CDT 2016


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/channel.c             | 122 +++++++++++++++++++++++++++++++++
 dlls/webservices/tests/proxy.c         |  60 ++++++++++++++++
 dlls/webservices/webservices.spec      |   2 +-
 dlls/webservices/webservices_private.h |   2 +
 4 files changed, 185 insertions(+), 1 deletion(-)

diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c
index 9431ad0..e7fb52b 100644
--- a/dlls/webservices/channel.c
+++ b/dlls/webservices/channel.c
@@ -92,6 +92,7 @@ struct channel
     WS_CHANNEL_STATE        state;
     WS_ENDPOINT_ADDRESS     addr;
     WS_XML_WRITER          *writer;
+    WS_XML_READER          *reader;
     HINTERNET               http_session;
     HINTERNET               http_connect;
     HINTERNET               http_request;
@@ -115,6 +116,7 @@ static void free_channel( struct channel *channel )
 {
     if (!channel) return;
     WsFreeWriter( channel->writer );
+    WsFreeReader( channel->reader );
     WinHttpCloseHandle( channel->http_request );
     WinHttpCloseHandle( channel->http_connect );
     WinHttpCloseHandle( channel->http_session );
@@ -475,3 +477,123 @@ HRESULT WINAPI WsSendMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESS
 
     return channel_send_message( handle, msg );
 }
+
+#define INITIAL_READ_BUFFER_SIZE 4096
+static HRESULT receive_message( struct channel *channel, ULONG max_len, char **ret, ULONG *ret_len )
+{
+    DWORD len, bytes_read, offset = 0, size = INITIAL_READ_BUFFER_SIZE;
+    char *buf;
+
+    if (!(buf = heap_alloc( size ))) return E_OUTOFMEMORY;
+    *ret_len = 0;
+    for (;;)
+    {
+        if (!WinHttpQueryDataAvailable( channel->http_request, &len ))
+        {
+            heap_free( buf );
+            return HRESULT_FROM_WIN32( GetLastError() );
+        }
+        if (!len) break;
+        if (*ret_len + len > max_len)
+        {
+            heap_free( buf );
+            return WS_E_QUOTA_EXCEEDED;
+        }
+        if (*ret_len + len > size)
+        {
+            char *tmp;
+            DWORD new_size = max( len, size * 2 );
+            if (!(tmp = heap_realloc( buf, new_size )))
+            {
+                heap_free( buf );
+                return E_OUTOFMEMORY;
+            }
+            buf = tmp;
+            size = new_size;
+        }
+        if (!WinHttpReadData( channel->http_request, buf + offset, len, &bytes_read ))
+        {
+            heap_free( buf );
+            return HRESULT_FROM_WIN32( GetLastError() );
+        }
+        if (!bytes_read) break;
+        *ret_len += bytes_read;
+        offset += bytes_read;
+    }
+
+    *ret = buf;
+    return S_OK;
+}
+
+HRESULT channel_receive_message( WS_CHANNEL *handle, char **buf, ULONG *len )
+{
+    struct channel *channel = (struct channel *)handle;
+    ULONG max_len;
+
+    WsGetChannelProperty( handle, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE, &max_len, sizeof(max_len), NULL );
+    return receive_message( channel, max_len, buf, len );
+}
+
+HRESULT set_input( WS_XML_READER *reader, char *data, ULONG size )
+{
+    WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8};
+    WS_XML_READER_BUFFER_INPUT buf;
+
+    buf.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
+    buf.encodedData     = data;
+    buf.encodedDataSize = size;
+    return WsSetInput( reader, &text.encoding, &buf.input, NULL, 0, NULL );
+}
+
+static HRESULT read_message( WS_MESSAGE *handle, WS_XML_READER *reader, const WS_ELEMENT_DESCRIPTION *desc,
+                             WS_READ_OPTION option, WS_HEAP *heap, void *body, ULONG size )
+{
+    HRESULT hr;
+    if ((hr = WsReadEnvelopeStart( handle, reader, NULL, NULL, NULL )) != S_OK) return hr;
+    if ((hr = WsReadBody( handle, desc, option, heap, body, size, NULL )) != S_OK) return hr;
+    return WsReadEnvelopeEnd( handle, NULL );
+}
+
+/**************************************************************************
+ *          WsReceiveMessage		[webservices.@]
+ */
+HRESULT WINAPI WsReceiveMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION **desc,
+                                 ULONG count, WS_RECEIVE_OPTION option, WS_READ_OPTION read_option, WS_HEAP *heap,
+                                 void *value, ULONG size, ULONG *index, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
+{
+    struct channel *channel = (struct channel *)handle;
+    char *buf = NULL;
+    ULONG len;
+    HRESULT hr;
+
+    TRACE( "%p %p %p %u %08x %08x %p %p %u %p %p %p\n", handle, msg, desc, count, option, read_option, heap,
+           value, size, index, ctx, error );
+    if (error) FIXME( "ignoring error parameter\n" );
+    if (ctx) FIXME( "ignoring ctx parameter\n" );
+    if (index)
+    {
+        FIXME( "index parameter not supported\n" );
+        return E_NOTIMPL;
+    }
+    if (count != 1)
+    {
+        FIXME( "no support for multiple descriptions\n" );
+        return E_NOTIMPL;
+    }
+    if (option != WS_RECEIVE_REQUIRED_MESSAGE)
+    {
+        FIXME( "receive option %08x not supported\n", option );
+        return E_NOTIMPL;
+    }
+
+    if (!handle || !msg || !desc || !count) return E_INVALIDARG;
+
+    if ((hr = channel_receive_message( handle, &buf, &len )) != S_OK) return hr;
+    if (!channel->reader && (hr = WsCreateReader( NULL, 0, &channel->reader, NULL )) != S_OK) goto done;
+    if ((hr = set_input( channel->reader, buf, len )) != S_OK) goto done;
+    hr = read_message( msg, channel->reader, desc[0]->bodyElementDescription, read_option, heap, value, size );
+
+done:
+    heap_free( buf );
+    return hr;
+}
diff --git a/dlls/webservices/tests/proxy.c b/dlls/webservices/tests/proxy.c
index ef64faf..fa4348a 100644
--- a/dlls/webservices/tests/proxy.c
+++ b/dlls/webservices/tests/proxy.c
@@ -191,6 +191,64 @@ static void test_WsSendMessage( int port, WS_XML_STRING *action )
     WsFreeMessage( msg );
 }
 
+static void test_WsReceiveMessage( int port )
+{
+    WS_XML_STRING req = {9, (BYTE *)"req_test1"}, resp = {10, (BYTE *)"resp_test1"}, ns = {2, (BYTE *)"ns"};
+    WS_CHANNEL *channel;
+    WS_MESSAGE *msg;
+    WS_ELEMENT_DESCRIPTION body;
+    WS_MESSAGE_DESCRIPTION desc_req, desc_resp;
+    const WS_MESSAGE_DESCRIPTION *desc[1];
+    INT32 val = -1;
+    HRESULT hr;
+
+    hr = create_channel( port, &channel );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    body.elementLocalName = &req;
+    body.elementNs        = &ns;
+    body.type             = WS_INT32_TYPE;
+    body.typeDescription  = NULL;
+    desc_req.action                 = &req;
+    desc_req.bodyElementDescription = &body;
+    hr = WsSendMessage( channel, msg, &desc_req, WS_WRITE_REQUIRED_VALUE, &val, sizeof(val), NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    WsFreeMessage( msg );
+
+    hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    body.elementLocalName = &resp;
+    desc_resp.action                 = &resp;
+    desc_resp.bodyElementDescription = &body;
+    desc[0] = &desc_resp;
+    hr = WsReceiveMessage( NULL, msg, desc, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
+                           NULL, &val, sizeof(val), NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = WsReceiveMessage( channel, NULL, desc, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
+                           NULL, &val, sizeof(val), NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = WsReceiveMessage( channel, msg, NULL, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
+                           NULL, &val, sizeof(val), NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = WsReceiveMessage( channel, msg, desc, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
+                           NULL, &val, sizeof(val), NULL, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( val == -2, "got %d\n", val );
+
+    hr = WsCloseChannel( channel, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    WsFreeChannel( channel );
+    WsFreeMessage( msg );
+}
+
 static const struct
 {
     const char   *req_action;
@@ -324,6 +382,8 @@ START_TEST(proxy)
     if (ret != WAIT_OBJECT_0) return;
 
     test_WsSendMessage( info.port, &test1 );
+    test_WsReceiveMessage( info.port );
+
     test_WsSendMessage( info.port, &quit );
     WaitForSingleObject( thread, 3000 );
 }
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index 27853b2..a03b7bd 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -125,7 +125,7 @@
 @ stdcall WsReadValue(ptr long ptr long ptr)
 @ stub WsReadXmlBuffer
 @ stub WsReadXmlBufferFromBytes
-@ stub WsReceiveMessage
+@ stdcall WsReceiveMessage(ptr ptr ptr long long long ptr ptr long ptr ptr ptr)
 @ stub WsRegisterOperationForCancel
 @ stdcall WsRemoveCustomHeader(ptr ptr ptr ptr)
 @ stdcall WsRemoveHeader(ptr long ptr)
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index ffbf77a..f72d2b9 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -38,6 +38,7 @@ WS_TYPE map_value_type( WS_VALUE_TYPE ) DECLSPEC_HIDDEN;
 BOOL set_fp_rounding( unsigned short * ) DECLSPEC_HIDDEN;
 void restore_fp_rounding( unsigned short ) DECLSPEC_HIDDEN;
 HRESULT set_output( WS_XML_WRITER * ) DECLSPEC_HIDDEN;
+HRESULT set_input( WS_XML_READER *, char *, ULONG ) DECLSPEC_HIDDEN;
 ULONG get_type_size( WS_TYPE, const WS_STRUCT_DESCRIPTION * ) DECLSPEC_HIDDEN;
 
 struct node
@@ -97,6 +98,7 @@ HRESULT message_set_action( WS_MESSAGE *, const WS_XML_STRING * ) DECLSPEC_HIDDE
 HRESULT message_insert_http_headers( WS_MESSAGE *, HINTERNET ) DECLSPEC_HIDDEN;
 
 HRESULT channel_send_message( WS_CHANNEL *, WS_MESSAGE * ) DECLSPEC_HIDDEN;
+HRESULT channel_receive_message( WS_CHANNEL *, char **, ULONG * ) DECLSPEC_HIDDEN;
 
 static inline BOOL is_nil_value( const char *value, ULONG size )
 {
-- 
2.1.4




More information about the wine-patches mailing list