From: Hans Leidekker Subject: [8/8] webservices: Implement WsReceiveMessage. Message-Id: <1475059086-6011-8-git-send-email-hans@codeweavers.com> Date: Wed, 28 Sep 2016 12:38:06 +0200 Signed-off-by: Hans Leidekker --- 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