webservices: Implement WsReceiveMessage.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e9a2505276
commit
dc014df696
|
@ -92,6 +92,7 @@ struct channel
|
||||||
WS_CHANNEL_STATE state;
|
WS_CHANNEL_STATE state;
|
||||||
WS_ENDPOINT_ADDRESS addr;
|
WS_ENDPOINT_ADDRESS addr;
|
||||||
WS_XML_WRITER *writer;
|
WS_XML_WRITER *writer;
|
||||||
|
WS_XML_READER *reader;
|
||||||
HINTERNET http_session;
|
HINTERNET http_session;
|
||||||
HINTERNET http_connect;
|
HINTERNET http_connect;
|
||||||
HINTERNET http_request;
|
HINTERNET http_request;
|
||||||
|
@ -115,6 +116,7 @@ static void free_channel( struct channel *channel )
|
||||||
{
|
{
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
WsFreeWriter( channel->writer );
|
WsFreeWriter( channel->writer );
|
||||||
|
WsFreeReader( channel->reader );
|
||||||
WinHttpCloseHandle( channel->http_request );
|
WinHttpCloseHandle( channel->http_request );
|
||||||
WinHttpCloseHandle( channel->http_connect );
|
WinHttpCloseHandle( channel->http_connect );
|
||||||
WinHttpCloseHandle( channel->http_session );
|
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 );
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -191,6 +191,64 @@ static void test_WsSendMessage( int port, WS_XML_STRING *action )
|
||||||
WsFreeMessage( msg );
|
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
|
static const struct
|
||||||
{
|
{
|
||||||
const char *req_action;
|
const char *req_action;
|
||||||
|
@ -324,6 +382,8 @@ START_TEST(proxy)
|
||||||
if (ret != WAIT_OBJECT_0) return;
|
if (ret != WAIT_OBJECT_0) return;
|
||||||
|
|
||||||
test_WsSendMessage( info.port, &test1 );
|
test_WsSendMessage( info.port, &test1 );
|
||||||
|
test_WsReceiveMessage( info.port );
|
||||||
|
|
||||||
test_WsSendMessage( info.port, &quit );
|
test_WsSendMessage( info.port, &quit );
|
||||||
WaitForSingleObject( thread, 3000 );
|
WaitForSingleObject( thread, 3000 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@
|
||||||
@ stdcall WsReadValue(ptr long ptr long ptr)
|
@ stdcall WsReadValue(ptr long ptr long ptr)
|
||||||
@ stub WsReadXmlBuffer
|
@ stub WsReadXmlBuffer
|
||||||
@ stub WsReadXmlBufferFromBytes
|
@ stub WsReadXmlBufferFromBytes
|
||||||
@ stub WsReceiveMessage
|
@ stdcall WsReceiveMessage(ptr ptr ptr long long long ptr ptr long ptr ptr ptr)
|
||||||
@ stub WsRegisterOperationForCancel
|
@ stub WsRegisterOperationForCancel
|
||||||
@ stdcall WsRemoveCustomHeader(ptr ptr ptr ptr)
|
@ stdcall WsRemoveCustomHeader(ptr ptr ptr ptr)
|
||||||
@ stdcall WsRemoveHeader(ptr long ptr)
|
@ stdcall WsRemoveHeader(ptr long ptr)
|
||||||
|
|
|
@ -38,6 +38,7 @@ WS_TYPE map_value_type( WS_VALUE_TYPE ) DECLSPEC_HIDDEN;
|
||||||
BOOL set_fp_rounding( unsigned short * ) DECLSPEC_HIDDEN;
|
BOOL set_fp_rounding( unsigned short * ) DECLSPEC_HIDDEN;
|
||||||
void restore_fp_rounding( unsigned short ) DECLSPEC_HIDDEN;
|
void restore_fp_rounding( unsigned short ) DECLSPEC_HIDDEN;
|
||||||
HRESULT set_output( WS_XML_WRITER * ) 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;
|
ULONG get_type_size( WS_TYPE, const WS_STRUCT_DESCRIPTION * ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
struct node
|
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 message_insert_http_headers( WS_MESSAGE *, HINTERNET ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
HRESULT channel_send_message( WS_CHANNEL *, WS_MESSAGE * ) 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 )
|
static inline BOOL is_nil_value( const char *value, ULONG size )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue