Commit 21c28028 authored by Shaun Ren's avatar Shaun Ren Committed by Alexandre Julliard

webservices: Add support for receiving fault messages.

parent a5359f36
......@@ -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 );
......
......@@ -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;
}
......@@ -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 );
......
......@@ -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/\"><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/\"><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\" "
"xmlns:a=\"http://schemas.datacontract.org/2004/07/Microsoft.Office.LicensingService\" "
"xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><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 );
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment