From: Shaun Ren sren@codeweavers.com
Signed-off-by: Shaun Ren sren@codeweavers.com --- dlls/webservices/channel.c | 30 ++++---- dlls/webservices/msg.c | 41 +++++++++++ dlls/webservices/proxy.c | 12 ++-- dlls/webservices/tests/proxy.c | 96 ++++++++++++++++++++++++++ dlls/webservices/webservices_private.h | 1 + 5 files changed, 161 insertions(+), 19 deletions(-)
diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c index 968110d56bd..5851fd9d4af 100644 --- a/dlls/webservices/channel.c +++ b/dlls/webservices/channel.c @@ -2354,17 +2354,18 @@ HRESULT channel_get_reader( WS_CHANNEL *handle, WS_XML_READER **reader ) }
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 ) + WS_READ_OPTION option, WS_HEAP *heap, void *body, ULONG size, WS_ERROR *error ) { HRESULT hr; if ((hr = WsReadEnvelopeStart( handle, reader, NULL, NULL, NULL )) != S_OK) return hr; + if ((hr = message_read_fault( handle, heap, error )) != S_OK) return hr; if ((hr = WsReadBody( handle, desc, option, heap, body, size, NULL )) != S_OK) return hr; return WsReadEnvelopeEnd( handle, NULL ); }
static HRESULT receive_message( struct channel *channel, 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 ) + void *value, ULONG size, ULONG *index, WS_ERROR *error ) { HRESULT hr; ULONG i; @@ -2375,7 +2376,7 @@ static HRESULT receive_message( struct channel *channel, WS_MESSAGE *msg, const for (i = 0; i < count; i++) { const WS_ELEMENT_DESCRIPTION *body = desc[i]->bodyElementDescription; - if ((hr = read_message( msg, channel->reader, body, read_option, heap, value, size )) == S_OK) + if ((hr = read_message( msg, channel->reader, body, read_option, heap, value, size, error )) == S_OK) { if (index) *index = i; break; @@ -2404,6 +2405,7 @@ struct receive_message ULONG size; ULONG *index; WS_ASYNC_CONTEXT ctx; + WS_ERROR *error; };
static void receive_message_proc( struct task *task ) @@ -2412,7 +2414,7 @@ static void receive_message_proc( struct task *task ) HRESULT hr;
hr = receive_message( r->channel, r->msg, r->desc, r->count, r->option, r->read_option, r->heap, r->value, - r->size, r->index ); + r->size, r->index, r->error );
TRACE( "calling %p(%#lx)\n", r->ctx.callback, hr ); r->ctx.callback( hr, WS_LONG_CALLBACK, r->ctx.callbackState ); @@ -2422,7 +2424,7 @@ static void receive_message_proc( struct task *task ) static HRESULT queue_receive_message( struct channel *channel, 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 ) + const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error ) { struct receive_message *r;
@@ -2439,6 +2441,7 @@ static HRESULT queue_receive_message( struct channel *channel, WS_MESSAGE *msg, r->size = size; r->index = index; r->ctx = *ctx; + r->error = error; return queue_task( &channel->recv_q, &r->task ); }
@@ -2456,7 +2459,6 @@ HRESULT WINAPI WsReceiveMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_M
TRACE( "%p %p %p %lu %u %u %p %p %lu %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 (!channel || !msg || !desc || !count) return E_INVALIDARG;
@@ -2475,7 +2477,7 @@ HRESULT WINAPI WsReceiveMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_M
if (!ctx) async_init( &async, &ctx_local ); hr = queue_receive_message( channel, msg, desc, count, option, read_option, heap, value, size, index, - ctx ? ctx : &ctx_local ); + ctx ? ctx : &ctx_local, error ); if (!ctx) { if (hr == WS_S_ASYNC) hr = async_wait( &async ); @@ -2491,7 +2493,7 @@ static HRESULT request_reply( struct channel *channel, WS_MESSAGE *request, const WS_MESSAGE_DESCRIPTION *request_desc, WS_WRITE_OPTION write_option, const void *request_body, ULONG request_size, WS_MESSAGE *reply, const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option, - WS_HEAP *heap, void *value, ULONG size ) + WS_HEAP *heap, void *value, ULONG size, WS_ERROR *error ) { HRESULT hr;
@@ -2499,7 +2501,7 @@ static HRESULT request_reply( struct channel *channel, WS_MESSAGE *request, return hr;
return receive_message( channel, reply, &reply_desc, 1, WS_RECEIVE_OPTIONAL_MESSAGE, read_option, heap, - value, size, NULL ); + value, size, NULL, error ); }
struct request_reply @@ -2518,6 +2520,7 @@ struct request_reply void *value; ULONG size; WS_ASYNC_CONTEXT ctx; + WS_ERROR *error; };
static void request_reply_proc( struct task *task ) @@ -2526,7 +2529,7 @@ static void request_reply_proc( struct task *task ) HRESULT hr;
hr = request_reply( r->channel, r->request, r->request_desc, r->write_option, r->request_body, r->request_size, - r->reply, r->reply_desc, r->read_option, r->heap, r->value, r->size ); + r->reply, r->reply_desc, r->read_option, r->heap, r->value, r->size, r->error );
TRACE( "calling %p(%#lx)\n", r->ctx.callback, hr ); r->ctx.callback( hr, WS_LONG_CALLBACK, r->ctx.callbackState ); @@ -2537,7 +2540,8 @@ static HRESULT queue_request_reply( struct channel *channel, WS_MESSAGE *request const WS_MESSAGE_DESCRIPTION *request_desc, WS_WRITE_OPTION write_option, const void *request_body, ULONG request_size, WS_MESSAGE *reply, const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option, - WS_HEAP *heap, void *value, ULONG size, const WS_ASYNC_CONTEXT *ctx ) + WS_HEAP *heap, void *value, ULONG size, const WS_ASYNC_CONTEXT *ctx, + WS_ERROR *error ) { struct request_reply *r;
@@ -2556,6 +2560,7 @@ static HRESULT queue_request_reply( struct channel *channel, WS_MESSAGE *request r->value = value; r->size = size; r->ctx = *ctx; + r->error = error; return queue_task( &channel->recv_q, &r->task ); }
@@ -2574,7 +2579,6 @@ HRESULT WINAPI WsRequestReply( WS_CHANNEL *handle, WS_MESSAGE *request, const WS
TRACE( "%p %p %p %u %p %lu %p %p %u %p %p %lu %p %p\n", handle, request, request_desc, write_option, request_body, request_size, reply, reply_desc, read_option, heap, value, size, ctx, error ); - if (error) FIXME( "ignoring error parameter\n" );
if (!channel || !request || !reply) return E_INVALIDARG;
@@ -2595,7 +2599,7 @@ HRESULT WINAPI WsRequestReply( WS_CHANNEL *handle, WS_MESSAGE *request, const WS
if (!ctx) async_init( &async, &ctx_local ); hr = queue_request_reply( channel, request, request_desc, write_option, request_body, request_size, reply, - reply_desc, read_option, heap, value, size, ctx ? ctx : &ctx_local ); + reply_desc, read_option, heap, value, size, ctx ? ctx : &ctx_local, error ); if (!ctx) { if (hr == WS_S_ASYNC) hr = async_wait( &async ); diff --git a/dlls/webservices/msg.c b/dlls/webservices/msg.c index 36dbe564b85..7f6cd028163 100644 --- a/dlls/webservices/msg.c +++ b/dlls/webservices/msg.c @@ -2259,3 +2259,44 @@ HRESULT message_set_request_id( WS_MESSAGE *handle, const GUID *id ) LeaveCriticalSection( &msg->cs ); return hr; } + +/* Attempt to read a fault message. If the message is a fault, WS_E_ENDPOINT_FAULT_RECEIVED will be returned. */ +HRESULT message_read_fault( WS_MESSAGE *handle, WS_HEAP *heap, WS_ERROR *error ) +{ + static const WS_ELEMENT_DESCRIPTION desc = { NULL, NULL, WS_FAULT_TYPE, NULL }; + BOOL isfault; + WS_FAULT fault = {0}; + WS_XML_STRING action; + HRESULT hr; + + if ((hr = WsGetMessageProperty( handle, WS_MESSAGE_PROPERTY_IS_FAULT, &isfault, sizeof(isfault), NULL )) != S_OK) + return hr; + if (!isfault) + return S_OK; + + if ((hr = WsReadBody( handle, &desc, WS_READ_REQUIRED_VALUE, heap, &fault, sizeof(fault), NULL )) != S_OK || + (hr = WsReadEnvelopeEnd( handle, NULL )) != S_OK) + goto done; + + if (!error) goto done; + + if ((hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) )) != S_OK) + goto done; + + if ((hr = WsGetHeader( handle, WS_ACTION_HEADER, WS_XML_STRING_TYPE, WS_READ_REQUIRED_VALUE, + heap, &action, sizeof(action), NULL )) != S_OK) + { + if (hr == WS_E_INVALID_FORMAT) + { + memset( &action, 0, sizeof(action) ); + hr = S_OK; + } + else + goto done; + } + hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &action, sizeof(action) ); + +done: + free_fault_fields( heap, &fault ); + return hr != S_OK ? hr : WS_E_ENDPOINT_FAULT_RECEIVED; +} diff --git a/dlls/webservices/proxy.c b/dlls/webservices/proxy.c index 3a8baade8dd..bde4cdb168f 100644 --- a/dlls/webservices/proxy.c +++ b/dlls/webservices/proxy.c @@ -440,17 +440,19 @@ done:
static HRESULT read_message( WS_MESSAGE *msg, WS_XML_READER *reader, WS_HEAP *heap, const WS_ELEMENT_DESCRIPTION *desc, const WS_PARAMETER_DESCRIPTION *params, - ULONG count, const void **args ) + ULONG count, const void **args, WS_ERROR *error ) { HRESULT hr; if ((hr = WsReadEnvelopeStart( msg, reader, NULL, NULL, NULL )) != S_OK) return hr; message_do_receive_callback( msg ); + if ((hr = message_read_fault( msg, heap, error )) != S_OK) return hr; if ((hr = read_output_params( reader, heap, desc, params, count, args )) != S_OK) return hr; return WsReadEnvelopeEnd( msg, NULL ); }
static HRESULT receive_message( WS_CHANNEL *channel, WS_MESSAGE *msg, WS_MESSAGE_DESCRIPTION *desc, - WS_PARAMETER_DESCRIPTION *params, ULONG count, WS_HEAP *heap, const void **args ) + WS_PARAMETER_DESCRIPTION *params, ULONG count, + WS_HEAP *heap, const void **args, WS_ERROR *error ) { WS_XML_READER *reader; HRESULT hr; @@ -458,7 +460,7 @@ static HRESULT receive_message( WS_CHANNEL *channel, WS_MESSAGE *msg, WS_MESSAGE if ((hr = message_set_action( msg, desc->action )) != S_OK) return hr; if ((hr = channel_receive_message( channel, msg )) != S_OK) return hr; if ((hr = channel_get_reader( channel, &reader )) != S_OK) return hr; - return read_message( msg, reader, heap, desc->bodyElementDescription, params, count, args ); + return read_message( msg, reader, heap, desc->bodyElementDescription, params, count, args, error ); }
static HRESULT create_input_message( WS_CHANNEL *channel, const WS_CALL_PROPERTY *properties, @@ -507,7 +509,6 @@ HRESULT WINAPI WsCall( WS_SERVICE_PROXY *handle, const WS_OPERATION_DESCRIPTION ULONG i;
TRACE( "%p %p %p %p %p %lu %p %p\n", handle, desc, args, heap, properties, count, ctx, error ); - if (error) FIXME( "ignoring error parameter\n" ); if (ctx) FIXME( "ignoring ctx parameter\n" ); for (i = 0; i < count; i++) { @@ -532,13 +533,12 @@ HRESULT WINAPI WsCall( WS_SERVICE_PROXY *handle, const WS_OPERATION_DESCRIPTION if ((hr = create_input_message( proxy->channel, properties, count, &msg )) != S_OK) goto done; if ((hr = send_message( proxy->channel, msg, desc->inputMessageDescription, desc->parameterDescription, desc->parameterCount, args )) != S_OK) goto done; - WsFreeMessage( msg ); msg = NULL;
if ((hr = create_output_message( proxy->channel, properties, count, &msg )) != S_OK) goto done; hr = receive_message( proxy->channel, msg, desc->outputMessageDescription, desc->parameterDescription, - desc->parameterCount, heap, args ); + desc->parameterCount, heap, args, error );
done: WsFreeMessage( msg ); diff --git a/dlls/webservices/tests/proxy.c b/dlls/webservices/tests/proxy.c index f03ae7b9844..59d571fb5c3 100644 --- a/dlls/webservices/tests/proxy.c +++ b/dlls/webservices/tests/proxy.c @@ -796,7 +796,101 @@ static void test_inout_params( int port ) WsFreeHeap( heap ); }
+static const char req_test5[] = + "<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/%5C%22%3E<s:Body>" + "<req_test5 xmlns="ns"><val>1</val></req_test5>" + "</s:Body></s:Envelope>"; + +static const char resp_test5[] = + "<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/%5C%22%3E<s:Body>" + "<s:Fault><faultcode>s:Client</faultcode><faultstring>OLS Exception</faultstring><detail>" + "<ServerFault xmlns="http://schemas.microsoft.com/office/licensingservice/API/2012/01/ClientApi%5..." " + "xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Office.LicensingService%5C" " + "xmlns:i="http://www.w3.org/2001/XMLSchema-instance%5C%22%3E<a:ErrorCode>1030</a:ErrorCode><a:Message/>" + "<a:Url>https://portal.office.com/Account/#installs</a:Url></ServerFault></detail>" + "</s:Fault></s:Body></s:Envelope>"; + +static void test_fault_response( int port ) +{ + WS_XML_STRING faultcode = {6, (BYTE *)"Client"}; + WS_STRING faultstring = {13, (WCHAR *)L"OLS Exception"}; + WS_XML_STRING req = {3, (BYTE *)"req"}; + WS_XML_STRING resp = {4, (BYTE *)"resp"}; + WS_XML_STRING req_action = {9, (BYTE *)"req_test5"}; + WS_XML_STRING resp_action = {10, (BYTE *)"resp_test5"}; + WS_XML_STRING req_elem = {9, (BYTE *)"req_test5"}; + WS_XML_STRING resp_elem = {10, (BYTE *)"resp_test5"}; + WS_XML_STRING ns = {2, (BYTE *)"ns"}; + WS_XML_STRING ns2 = {0, (BYTE *)""}; + WS_XML_STRING val = {3, (BYTE *)"val"}; + HRESULT hr; + WS_SERVICE_PROXY *proxy; + WS_FIELD_DESCRIPTION f, *fields[1]; + WS_STRUCT_DESCRIPTION input_struct, output_struct; + WS_ELEMENT_DESCRIPTION input_elem, output_elem; + WS_MESSAGE_DESCRIPTION input_msg, output_msg; + WS_PARAMETER_DESCRIPTION param[1]; + WS_OPERATION_DESCRIPTION op; + const void *args[1]; + WS_HEAP *heap; + struct input + { + INT32 val; + } in; + WS_ERROR *error; + WS_FAULT *fault; + + hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = create_proxy( port, &proxy ); + ok( hr == S_OK, "got %#lx\n", hr ); + + set_field_desc( &f, WS_ELEMENT_FIELD_MAPPING, &val, &ns, WS_INT32_TYPE, NULL, 0, 0, 0, NULL, NULL ); + fields[0] = &f; + + set_struct_desc( &input_struct, sizeof(struct input), TYPE_ALIGNMENT(struct input), fields, 1, &req, &ns, 0 ); + set_elem_desc( &input_elem, &req_elem, &ns, WS_STRUCT_TYPE, &input_struct ); + set_msg_desc( &input_msg, &req_action, &input_elem ); + + set_struct_desc( &output_struct, 0, 1, NULL, 0, &resp, &ns2, 0x6 ); + set_elem_desc( &output_elem, &resp_elem, &ns, WS_STRUCT_TYPE, &output_struct ); + set_msg_desc( &output_msg, &resp_action, &output_elem ); + + set_param_desc( param, WS_PARAMETER_TYPE_NORMAL, 0, 0xffff ); + set_op_desc( &op, &input_msg, &output_msg, 1, param ); + + in.val = 1; + args[0] = &in.val; + + hr = WsCreateError( NULL, 0, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsCall( proxy, &op, args, heap, NULL, 0, NULL, error ); + ok( hr == WS_E_ENDPOINT_FAULT_RECEIVED, "got %#lx\n", hr ); + + hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( fault != NULL, "fault not set\n" ); + ok( fault->code->value.localName.length == faultcode.length, "got %lu\n", fault->code->value.localName.length ); + ok( !memcmp( fault->code->value.localName.bytes, faultcode.bytes, faultcode.length ), "wrong fault code\n" ); + ok( !fault->code->subCode, "subcode is not NULL\n" ); + ok( fault->reasonCount == 1, "got %lu\n", fault->reasonCount ); + ok( fault->reasons[0].text.length == faultstring.length, "got %lu\n", fault->reasons[0].text.length ); + ok( !memcmp( fault->reasons[0].text.chars, faultstring.chars, faultstring.length * sizeof(WCHAR) ), + "wrong fault string\n" ); + ok( fault->detail != NULL, "fault detail not set\n" ); + + hr = WsCloseServiceProxy( proxy, NULL, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + + WsFreeError( error ); + WsFreeServiceProxy( proxy ); + WsFreeHeap( heap ); +} + static const char status_200[] = "HTTP/1.1 200 OK\r\n"; +static const char status_500[] = "HTTP/1.1 500 Internal Server Error\r\n";
static const struct { @@ -813,6 +907,7 @@ tests[] = { "req_test2", req_test2, sizeof(req_test2)-1, status_200, resp_test2, sizeof(resp_test2)-1 }, { "req_test3", req_test3, sizeof(req_test3)-1, status_200, resp_test3, sizeof(resp_test3)-1 }, { "req_test4", req_test4, sizeof(req_test4)-1, status_200, resp_test4, sizeof(resp_test4)-1 }, + { "req_test5", req_test5, sizeof(req_test5)-1, status_500, resp_test5, sizeof(resp_test5)-1 }, };
static void send_response( int c, const char *status, const char *data, unsigned int len ) @@ -947,6 +1042,7 @@ START_TEST(proxy) test_WsCall( info.port ); test_empty_response( info.port ); test_inout_params( info.port ); + test_fault_response( info.port );
test_WsSendMessage( info.port, &quit ); WaitForSingleObject( thread, 3000 ); diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index a2f89d47d7a..478f1aa00f3 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -164,6 +164,7 @@ void message_do_send_callback( WS_MESSAGE * ) DECLSPEC_HIDDEN; void message_do_receive_callback( WS_MESSAGE * ) DECLSPEC_HIDDEN; HRESULT message_insert_http_headers( WS_MESSAGE *, HINTERNET ) DECLSPEC_HIDDEN; HRESULT message_map_http_response_headers( WS_MESSAGE *, HINTERNET, const WS_HTTP_MESSAGE_MAPPING * ) DECLSPEC_HIDDEN; +HRESULT message_read_fault( WS_MESSAGE *, WS_HEAP *, WS_ERROR * ) DECLSPEC_HIDDEN;
HRESULT channel_send_message( WS_CHANNEL *, WS_MESSAGE * ) DECLSPEC_HIDDEN; HRESULT channel_receive_message( WS_CHANNEL *, WS_MESSAGE * ) DECLSPEC_HIDDEN;