webservices: Support faults in error.

Signed-off-by: Shaun Ren <sren@codeweavers.com>
This commit is contained in:
Shaun Ren 2022-07-22 14:17:42 -04:00 committed by Alexandre Julliard
parent da77cc8cfd
commit ac90bc1e16
5 changed files with 702 additions and 3 deletions

View file

@ -47,6 +47,8 @@ struct error
ULONG strs_count;
ULONG strs_size; /* Maximum length of the strs array */
WS_STRING *strs;
WS_FAULT *fault;
WS_XML_STRING fault_action;
};
#define ERROR_MAGIC (('E' << 24) | ('R' << 16) | ('R' << 8) | 'O')
@ -85,6 +87,60 @@ static void free_error( struct error *error )
free( error );
}
void free_fault_fields( WS_HEAP *heap, WS_FAULT *fault )
{
WS_FAULT_CODE *code, *prev_code;
ULONG i;
code = fault->code;
while ( code )
{
ws_free( heap, code->value.localName.bytes, code->value.localName.length );
ws_free( heap, code->value.ns.bytes, code->value.ns.length );
prev_code = code;
code = code->subCode;
ws_free( heap, prev_code, sizeof(*prev_code) );
}
for (i = 0; i < fault->reasonCount; i++)
{
ws_free( heap, fault->reasons[i].text.chars, fault->reasons[i].text.length * sizeof(WCHAR) );
ws_free( heap, fault->reasons[i].lang.chars, fault->reasons[i].lang.length * sizeof(WCHAR) );
}
ws_free( heap, fault->reasons, fault->reasonCount * sizeof(*fault->reasons) );
ws_free( heap, fault->actor.chars, fault->actor.length * sizeof(WCHAR) );
ws_free( heap, fault->node.chars, fault->node.length * sizeof(WCHAR) );
free_xmlbuf((struct xmlbuf *)fault->detail);
}
static void free_fault( WS_HEAP *heap, WS_FAULT *fault )
{
if (!fault) return;
free_fault_fields( heap, fault );
ws_free( heap, fault, sizeof(*fault) );
}
static BOOL copy_xml_string( WS_HEAP *heap, const WS_XML_STRING *src, WS_XML_STRING *dst )
{
if (!src->length) return TRUE;
if (!(dst->bytes = ws_alloc( heap, src->length ))) return FALSE;
memcpy( dst->bytes, src->bytes, src->length );
dst->length = src->length;
return TRUE;
}
static BOOL copy_string( WS_HEAP *heap, const WS_STRING *src, WS_STRING *dst )
{
ULONG size;
if (!src->length) return TRUE;
size = src->length * sizeof(WCHAR);
if (!(dst->chars = ws_alloc( heap, size ))) return FALSE;
memcpy( dst->chars, src->chars, size );
dst->length = src->length;
return TRUE;
}
/* Grow the strs array to fit an extra element. */
static HRESULT grow_strs_array( struct error *error )
{
@ -115,6 +171,142 @@ static HRESULT grow_strs_array( struct error *error )
return S_OK;
}
static WS_FAULT *dup_fault( WS_HEAP *heap, const WS_FAULT *src )
{
WS_FAULT *new_fault;
WS_FAULT_CODE *code, *prev_code, *new_code;
struct xmlbuf *buf, *new_buf;
ULONG i;
BOOL success = FALSE;
if (!(new_fault = ws_alloc_zero( heap, sizeof(*new_fault) )))
return NULL;
prev_code = NULL;
code = src->code;
while ( code )
{
if (!(new_code = ws_alloc_zero( heap, sizeof(*new_code) )) ||
!copy_xml_string( heap, &code->value.localName, &new_code->value.localName ) ||
!copy_xml_string( heap, &code->value.ns, &new_code->value.ns ))
goto done;
if (prev_code)
prev_code->subCode = new_code;
else
new_fault->code = new_code;
prev_code = new_code;
code = code->subCode;
}
if (src->reasonCount > 0)
{
if (!(new_fault->reasons = ws_alloc_zero( heap, sizeof(*new_fault->reasons) * src->reasonCount )))
goto done;
new_fault->reasonCount = src->reasonCount;
for (i = 0; i < src->reasonCount; i++)
{
if (!copy_string( heap, &src->reasons[i].text, &new_fault->reasons[i].text ) ||
!copy_string( heap, &src->reasons[i].lang, &new_fault->reasons[i].lang ))
goto done;
}
}
if (!copy_string( heap, &src->actor, &new_fault->actor ) ||
!copy_string( heap, &src->node, &new_fault->node ))
goto done;
buf = (struct xmlbuf *)src->detail;
new_buf = NULL;
if (buf)
{
if (!(new_buf = alloc_xmlbuf( heap, buf->bytes.length, buf->encoding,
buf->charset, buf->dict_static, buf->dict )))
goto done;
memcpy( new_buf->bytes.bytes, buf->bytes.bytes, buf->bytes.length );
new_buf->bytes.length = buf->bytes.length;
}
new_fault->detail = (WS_XML_BUFFER *)new_buf;
success = TRUE;
done:
if (!success)
{
free_fault( heap, new_fault );
return NULL;
}
return new_fault;
}
static HRESULT set_fault( struct error *error, const WS_FAULT *value )
{
static const WCHAR prefix[] = L"The fault reason was: '";
static const WCHAR postfix[] = L"'.";
static const ULONG prefix_len = ARRAY_SIZE(prefix) - 1, postfix_len = ARRAY_SIZE(postfix) - 1;
WS_FAULT *fault;
WS_STRING *str;
WCHAR *dst;
ULONG len;
HRESULT hr = S_OK;
if (!(fault = dup_fault( error->heap, value )))
return E_OUTOFMEMORY;
/* FIXME: check if reason lang matches error property langid */
if (fault->reasonCount > 0)
{
if ((hr = grow_strs_array( error )) != S_OK) goto done;
str = &error->strs[error->strs_count];
len = prefix_len + fault->reasons[0].text.length + postfix_len;
if (!(str->chars = ws_alloc( error->heap, len * sizeof(WCHAR) )))
{
hr = E_OUTOFMEMORY;
goto done;
}
dst = str->chars;
memcpy( dst, prefix, prefix_len * sizeof(WCHAR) );
dst += prefix_len;
memcpy( dst, fault->reasons[0].text.chars, fault->reasons[0].text.length * sizeof(WCHAR) );
dst += fault->reasons[0].text.length;
memcpy( dst, postfix, postfix_len * sizeof(WCHAR) );
str->length = len;
error->strs_count++;
}
free_fault( error->heap, error->fault );
error->fault = fault;
done:
if (hr != S_OK)
free_fault( error->heap, fault );
return hr;
}
static HRESULT set_action( struct error *error, const WS_XML_STRING *value )
{
BYTE *buf;
if (value->length == 0)
{
ws_free( error->heap, error->fault_action.bytes, error->fault_action.length );
memset( &error->fault_action, 0, sizeof(error->fault_action) );
return S_OK;
}
if (!(buf = ws_alloc( error->heap, value->length )))
return E_OUTOFMEMORY;
memcpy( buf, value->bytes, value->length );
ws_free( error->heap, error->fault_action.bytes, error->fault_action.length );
error->fault_action.bytes = buf;
error->fault_action.length = value->length;
return S_OK;
}
/**************************************************************************
* WsCreateError [webservices.@]
*/
@ -160,6 +352,9 @@ static void reset_error( struct error *error )
error->strs = NULL;
error->strs_count = error->strs_size = 0;
error->fault = NULL;
memset( &error->fault_action, 0, sizeof(error->fault_action) );
WsResetHeap( error->heap, NULL );
}
@ -359,3 +554,156 @@ done:
TRACE( "returning %#lx\n", hr );
return hr;
}
/**************************************************************************
* WsGetFaultErrorDetail [webservices.@]
*/
HRESULT WINAPI WsGetFaultErrorDetail( WS_ERROR *handle, const WS_FAULT_DETAIL_DESCRIPTION *desc,
WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size )
{
static const WS_XML_STRING detail = {6, (BYTE *)"detail"};
struct error *error = (struct error *)handle;
WS_XML_READER *reader = NULL;
const WS_XML_NODE *node;
const WS_XML_ELEMENT_NODE *elem;
BOOL nil = FALSE;
HRESULT hr = S_OK;
TRACE( "%p %p %u %p %p %lu\n", handle, desc, option, heap, value, size );
if (!error || !desc || !value) return E_INVALIDARG;
if ((option == WS_READ_REQUIRED_POINTER ||
option == WS_READ_OPTIONAL_POINTER ||
option == WS_READ_NILLABLE_POINTER) && size != sizeof(void *))
return E_INVALIDARG;
EnterCriticalSection( &error->cs );
if (error->magic != ERROR_MAGIC)
{
hr = E_INVALIDARG;
goto done;
}
if (!error->fault || !error->fault->detail)
{
nil = TRUE;
goto done;
}
if ((hr = WsCreateReader( NULL, 0, &reader, NULL )) != S_OK) goto done;
if ((hr = WsSetInputToBuffer( reader, error->fault->detail, NULL, 0, NULL )) != S_OK) goto done;
if ((hr = WsReadNode( reader, NULL )) != S_OK) goto done;
if ((hr = WsGetReaderNode( reader, &node, NULL )) != S_OK) goto done;
elem = (const WS_XML_ELEMENT_NODE *)node;
if (!(node->nodeType == WS_XML_NODE_TYPE_ELEMENT &&
WsXmlStringEquals( elem->localName, &detail, NULL ) == S_OK))
{
hr = WS_E_INVALID_FORMAT;
goto done;
}
if (desc->action && error->fault_action.length &&
WsXmlStringEquals( desc->action, &error->fault_action, NULL ) != S_OK)
{
nil = TRUE;
goto done;
}
if ((hr = WsReadNode( reader, NULL )) != S_OK) goto done;
if ((hr = WsReadElement( reader, desc->detailElementDescription,
option, heap, value, size, handle )) != S_OK)
goto done;
done:
LeaveCriticalSection( &error->cs );
WsFreeReader( reader );
if ((hr != S_OK || nil) && (option == WS_READ_OPTIONAL_POINTER || option == WS_READ_NILLABLE_POINTER))
*(void **)value = NULL;
if (nil && !(option == WS_READ_OPTIONAL_POINTER || option == WS_READ_NILLABLE_POINTER))
hr = WS_E_INVALID_FORMAT;
TRACE( "returning %#lx\n", hr );
return hr;
}
/**************************************************************************
* WsGetFaultErrorProperty [webservices.@]
*/
HRESULT WINAPI WsGetFaultErrorProperty( WS_ERROR *handle, WS_FAULT_ERROR_PROPERTY_ID id,
void *buf, ULONG size )
{
struct error *error = (struct error *)handle;
HRESULT hr = S_OK;
TRACE( "%p %u %p %lu\n", handle, id, buf, size );
if (!error || !buf) return E_INVALIDARG;
if (id > WS_FAULT_ERROR_PROPERTY_HEADER) return E_INVALIDARG;
else if (id == WS_FAULT_ERROR_PROPERTY_HEADER)
{
FIXME( "WS_FAULT_ERROR_PROPERTY_HEADER not supported\n" );
return E_NOTIMPL;
}
EnterCriticalSection( &error->cs );
if (error->magic != ERROR_MAGIC)
{
hr = E_INVALIDARG;
goto done;
}
if (id == WS_FAULT_ERROR_PROPERTY_FAULT && size == sizeof(WS_FAULT *))
*(WS_FAULT **)buf = error->fault;
else if (id == WS_FAULT_ERROR_PROPERTY_ACTION && size == sizeof(WS_XML_STRING))
memcpy( buf, &error->fault_action, sizeof(WS_XML_STRING) );
else
hr = E_INVALIDARG;
done:
LeaveCriticalSection( &error->cs );
TRACE( "returning %#lx\n", hr );
return hr;
}
/**************************************************************************
* WsSetFaultErrorProperty [webservices.@]
*/
HRESULT WINAPI WsSetFaultErrorProperty( WS_ERROR *handle, WS_FAULT_ERROR_PROPERTY_ID id,
const void *value, ULONG size )
{
struct error *error = (struct error *)handle;
HRESULT hr = S_OK;
TRACE( "%p %u %p %lu\n", handle, id, value, size );
if (!error || !value) return E_INVALIDARG;
if (id > WS_FAULT_ERROR_PROPERTY_HEADER) return E_INVALIDARG;
else if (id == WS_FAULT_ERROR_PROPERTY_HEADER)
{
FIXME( "WS_FAULT_ERROR_PROPERTY_HEADER not supported\n" );
return E_NOTIMPL;
}
EnterCriticalSection( &error->cs );
if (error->magic != ERROR_MAGIC)
{
hr = E_INVALIDARG;
goto done;
}
if (id == WS_FAULT_ERROR_PROPERTY_FAULT && size == sizeof(WS_FAULT))
hr = set_fault( error, value );
else if (id == WS_FAULT_ERROR_PROPERTY_ACTION && size == sizeof(WS_XML_STRING))
hr = set_action( error, value );
else
hr = E_INVALIDARG;
done:
LeaveCriticalSection( &error->cs );
TRACE( "returning %#lx\n", hr );
return hr;
}

View file

@ -3894,6 +3894,9 @@ static void test_WsResetError(void)
WS_ERROR *error;
LANGID langid;
WS_STRING str;
WS_FAULT fault;
WS_XML_STRING xmlstr;
WS_FAULT *faultp;
HRESULT hr;
hr = WsResetError( NULL );
@ -3971,6 +3974,34 @@ static void test_WsResetError(void)
ok( count == 0, "got %lu\n", count );
WsFreeError( error );
memset( &fault, 0, sizeof(fault) );
xmlstr.bytes = (BYTE *)"str";
xmlstr.length = 3;
hr = WsCreateError( NULL, 0, &error );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &xmlstr, sizeof(WS_XML_STRING) );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsResetError( error );
ok( hr == S_OK, "got %#lx\n", hr );
faultp = (WS_FAULT *)0xdeadbeef;
hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &faultp, sizeof(faultp) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( faultp == NULL, "faultp != NULL\n" );
xmlstr.length = 0xdeadbeef;
xmlstr.bytes = (BYTE *)0xdeadbeef;
hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &xmlstr, sizeof(xmlstr) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( xmlstr.length == 0, "got %lu\n", xmlstr.length );
WsFreeError( error );
}
static void test_WsGetReaderPosition(void)
@ -7122,6 +7153,283 @@ static void test_WsAddErrorString(void)
WsFreeError( error );
}
static void test_WsSetFaultErrorProperty(void)
{
static const WCHAR expected_errorstr[] = L"The fault reason was: 'Some reason'.";
static const char detailxml[] = "<detail><ErrorCode>1030</ErrorCode></detail>";
static const LANGID langid = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
static const WS_XML_STRING action = { 24, (BYTE *)"http://example.com/fault" };
WS_ERROR_PROPERTY prop;
WS_ERROR *error;
WS_FAULT fault;
WS_FAULT *faultp;
WS_XML_STRING outxmlstr;
WS_STRING outstr;
ULONG count;
WS_HEAP *heap;
WS_XML_READER *reader;
HRESULT hr;
prop.id = WS_ERROR_PROPERTY_LANGID;
prop.value = (void *)&langid;
prop.valueSize = sizeof(langid);
hr = WsCreateError( &prop, 1, &error );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, NULL, sizeof(WS_FAULT) );
ok( hr == E_INVALIDARG, "got %#lx\n", hr );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, NULL, sizeof(WS_XML_STRING) );
ok( hr == E_INVALIDARG, "got %#lx\n", hr );
memset( &fault, 0, sizeof(fault) );
fault.code = calloc( 1, sizeof(WS_FAULT_CODE) );
fault.code->value.localName.bytes = (BYTE *)"Server";
fault.code->value.localName.length = 6;
fault.code->subCode = calloc( 1, sizeof(WS_FAULT_CODE) );
fault.code->subCode->value.localName.bytes = (BYTE *)"SubCode";
fault.code->subCode->value.localName.length = 7;
fault.reasons = calloc( 1, sizeof(*fault.reasons) );
fault.reasonCount = 1;
fault.reasons[0].lang.chars = (WCHAR *) L"en-US";
fault.reasons[0].lang.length = 5;
fault.reasons[0].text.chars = (WCHAR *) L"Some reason";
fault.reasons[0].text.length = 11;
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(WS_FAULT) );
ok( hr == S_OK, "got %#lx\n", hr );
faultp = NULL;
hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &faultp, sizeof(faultp) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( faultp != NULL, "faultp not set\n" );
ok( faultp != &fault, "fault not copied\n" );
ok( faultp->code && faultp->code != fault.code, "fault code not copied\n" );
ok( faultp->code->value.localName.length == 6, "got %lu\n", faultp->code->value.localName.length );
ok( !memcmp( faultp->code->value.localName.bytes, fault.code->value.localName.bytes, 6 ),
"wrong code localName\n" );
ok( faultp->code->value.localName.bytes != fault.code->value.localName.bytes,
"fault code localName not copied\n" );
ok( faultp->code->value.ns.length == 0, "got %lu\n", faultp->code->value.ns.length );
ok( faultp->code->subCode && faultp->code->subCode != fault.code->subCode,
"fault code subCode not copied\n" );
ok( faultp->code->subCode->value.localName.length == 7,"got %lu\n", faultp->code->subCode->value.localName.length );
ok( !memcmp( faultp->code->subCode->value.localName.bytes, fault.code->subCode->value.localName.bytes, 7 ),
"wrong subCode localName\n" );
ok( faultp->code->subCode->value.localName.bytes != fault.code->subCode->value.localName.bytes,
"fault code subCode localName not copied\n" );
ok( faultp->code->subCode->value.ns.length == 0, "got %lu\n", faultp->code->subCode->value.ns.length );
ok( faultp->code->subCode->subCode == NULL, "fault->code->subCode->subCode != NULL\n");
ok( faultp->reasons != fault.reasons, "fault reasons not copied\n" );
ok( faultp->reasonCount == 1, "got %lu\n", faultp->reasonCount );
ok( faultp->reasons[0].lang.length == 5, "got %lu\n", faultp->reasons[0].text.length );
ok( !memcmp( faultp->reasons[0].lang.chars, fault.reasons[0].lang.chars, 5 * sizeof(WCHAR) ),
"wrong fault reason lang\n" );
ok( faultp->reasons[0].lang.chars != fault.reasons[0].lang.chars,
"fault reason lang not copied\n" );
ok( faultp->reasons[0].text.length == 11, "got %lu\n", faultp->reasons[0].text.length );
ok( !memcmp( faultp->reasons[0].text.chars, fault.reasons[0].text.chars, 11 * sizeof(WCHAR) ),
"wrong fault reason text\n" );
ok( faultp->reasons[0].text.chars != fault.reasons[0].text.chars,
"fault reason text not copied\n" );
ok( faultp->actor.length == 0, "got %lu\n", faultp->actor.length );
ok( faultp->node.length == 0, "got %lu\n", faultp->node.length );
ok( faultp->detail == NULL, "faultp->detail != NULL\n" );
count = 0xdeadbeef;
hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, sizeof(count) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( count == 1, "got %lu\n", count );
hr = WsGetErrorString( error, 0, &outstr );
ok( hr == S_OK, "got %#lx\n", hr );
ok( outstr.length == ARRAY_SIZE(expected_errorstr) - 1, "got %lu\n", outstr.length );
ok( !memcmp( outstr.chars, expected_errorstr, (ARRAY_SIZE(expected_errorstr) - 1) * sizeof(WCHAR) ),
"wrong error string\n" );
outxmlstr.bytes = (BYTE *)0xdeadbeef;
outxmlstr.length = 0xdeadbeef;
hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &outxmlstr, sizeof(outxmlstr) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( outxmlstr.length == 0, "got %lu\n", outxmlstr.length );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &action, sizeof(action) );
ok( hr == S_OK, "got %#lx\n", hr );
outxmlstr.bytes = (BYTE *)0xdeadbeef;
outxmlstr.length = 0xdeadbeef;
hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &outxmlstr, sizeof(outxmlstr) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( outxmlstr.length == 24, "got %lu\n", outxmlstr.length );
ok( !memcmp( outxmlstr.bytes, action.bytes, 24 ), "wrong fault action\n" );
hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsCreateReader( NULL, 0, &reader, NULL );
ok( hr == S_OK, "got %#lx\n", hr );
hr = set_input( reader, detailxml, strlen(detailxml) );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsReadXmlBuffer( reader, heap, &fault.detail, NULL );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(WS_FAULT) );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsGetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &faultp, sizeof(faultp) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( faultp != NULL, "faultp not set\n" );
ok( faultp->detail != NULL, "fault detail not set\n" );
ok( faultp->detail != fault.detail, "fault detail not copied\n" );
check_output_buffer( faultp->detail, detailxml, __LINE__ );
free( fault.code->subCode );
free( fault.code );
free( fault.reasons );
WsFreeReader( reader );
WsFreeHeap( heap );
WsFreeError( error );
}
static void test_WsGetFaultErrorDetail(void)
{
static const char detailxml[] = "<detail><ErrorCode>1030</ErrorCode></detail>";
static const char badxml[] = "<bad><ErrorCode>1030</ErrorCode></bad>";
WS_ERROR *error;
WS_HEAP *heap;
WS_XML_READER *reader;
WS_FAULT fault;
WS_XML_STRING action = { 24, (BYTE *)"http://example.com/fault" };
WS_XML_STRING action2 = { 25, (BYTE *)"http://example.com/fault2" };
WS_XML_STRING localname = { 9, (BYTE *)"ErrorCode" }, localname2 = { 9, (BYTE *)"OtherCode" };
WS_XML_STRING ns = { 0 };
WS_ELEMENT_DESCRIPTION desc = { &localname, &ns, WS_UINT32_TYPE, NULL };
WS_ELEMENT_DESCRIPTION desc2 = { &localname2, &ns, WS_UINT32_TYPE, NULL };
WS_FAULT_DETAIL_DESCRIPTION fault_desc;
UINT32 code;
UINT32 *codep;
HRESULT hr;
hr = WsCreateError( NULL, 0, &error );
ok( hr == S_OK, "got %#lx\n", hr );
memset( &fault, 0, sizeof(fault) );
hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsCreateReader( NULL, 0, &reader, NULL );
ok( hr == S_OK, "got %#lx\n", hr );
hr = set_input( reader, detailxml, strlen(detailxml) );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsReadXmlBuffer( reader, heap, &fault.detail, NULL );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) );
ok( hr == S_OK, "got %#lx\n", hr );
fault_desc.action = NULL;
fault_desc.detailElementDescription = &desc;
code = 0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( code == 1030, "got %u\n", code );
codep = (UINT32 *)0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( codep != NULL, "codep == NULL\n" );
ok( *codep == 1030, "got %u\n", *codep );
fault_desc.action = &action;
code = 0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( code == 1030, "got %u\n", code );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_ACTION, &action, sizeof(action) );
ok( hr == S_OK, "got %#lx\n", hr );
fault_desc.action = NULL;
code = 0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( code == 1030, "got %u\n", code );
fault_desc.action = &action2;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_POINTER, heap, &codep, sizeof(codep) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
codep = (UINT32 *)0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( codep == NULL, "codep != NULL\n" );
codep = (UINT32 *)0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_NILLABLE_POINTER, heap, &codep, sizeof(codep) );
ok( hr == S_OK, "got %#lx\n", hr );
ok( codep == NULL, "codep != NULL\n" );
fault_desc.action = NULL;
fault_desc.detailElementDescription = &desc2;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_POINTER, heap, &codep, sizeof(codep) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
codep = (UINT32 *)0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
ok( codep == NULL, "codep != NULL\n" );
codep = (UINT32 *)0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_NILLABLE_POINTER, heap, &codep, sizeof(codep) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
ok( codep == NULL, "codep != NULL\n" );
hr = set_input( reader, badxml, strlen(badxml) );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsReadXmlBuffer( reader, heap, &fault.detail, NULL );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsSetFaultErrorProperty( error, WS_FAULT_ERROR_PROPERTY_FAULT, &fault, sizeof(fault) );
ok( hr == S_OK, "got %#lx\n", hr );
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_VALUE, heap, &code, sizeof(code) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_REQUIRED_POINTER, heap, &codep, sizeof(codep) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
codep = (UINT32 *)0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_OPTIONAL_POINTER, heap, &codep, sizeof(codep) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
ok( codep == NULL, "codep != NULL\n" );
codep = (UINT32 *)0xdeadbeef;
hr = WsGetFaultErrorDetail( error, &fault_desc, WS_READ_NILLABLE_POINTER, heap, &codep, sizeof(codep) );
ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
ok( codep == NULL, "codep != NULL\n" );
WsFreeReader( reader );
WsFreeHeap( heap );
WsFreeError( error );
}
START_TEST(reader)
{
test_WsCreateError();
@ -7174,4 +7482,6 @@ START_TEST(reader)
test_stream_input();
test_description_type();
test_WsAddErrorString();
test_WsSetFaultErrorProperty();
test_WsGetFaultErrorDetail();
}

View file

@ -64,8 +64,8 @@
@ stdcall WsGetDictionary(long ptr ptr)
@ stdcall WsGetErrorProperty(ptr long ptr long)
@ stdcall WsGetErrorString(ptr long ptr)
@ stub WsGetFaultErrorDetail
@ stub WsGetFaultErrorProperty
@ stdcall WsGetFaultErrorDetail(ptr ptr ptr ptr ptr long)
@ stdcall WsGetFaultErrorProperty(ptr long ptr long)
@ stdcall WsGetHeader(ptr long long long ptr ptr long ptr)
@ stub WsGetHeaderAttributes
@ stdcall WsGetHeapProperty(ptr long ptr long ptr)
@ -148,7 +148,7 @@
@ stdcall WsSetChannelProperty(ptr long ptr long ptr)
@ stdcall WsSetErrorProperty(ptr long ptr long)
@ stub WsSetFaultErrorDetail
@ stub WsSetFaultErrorProperty
@ stdcall WsSetFaultErrorProperty(ptr long ptr long)
@ stdcall WsSetHeader(ptr long long long ptr long ptr)
@ stdcall WsSetInput(ptr ptr ptr ptr long ptr)
@ stdcall WsSetInputToBuffer(ptr ptr ptr long ptr)

View file

@ -171,6 +171,8 @@ HRESULT channel_get_reader( WS_CHANNEL *, WS_XML_READER ** ) DECLSPEC_HIDDEN;
HRESULT parse_url( const WS_STRING *, WS_URL_SCHEME_TYPE *, WCHAR **, USHORT * ) DECLSPEC_HIDDEN;
void free_fault_fields( WS_HEAP *, WS_FAULT * ) DECLSPEC_HIDDEN;
enum record_type
{
/* 0x00 reserved */

View file

@ -1116,6 +1116,41 @@ struct _WS_ENDPOINT_ADDRESS {
WS_ENDPOINT_IDENTITY *identity;
};
typedef struct _WS_FAULT_CODE {
WS_XML_QNAME value;
struct _WS_FAULT_CODE *subCode;
} WS_FAULT_CODE;
typedef struct _WS_FAULT_REASON {
WS_STRING text;
WS_STRING lang;
} WS_FAULT_REASON;
typedef struct _WS_FAULT {
WS_FAULT_CODE *code;
WS_FAULT_REASON *reasons;
ULONG reasonCount;
WS_STRING actor;
WS_STRING node;
WS_XML_BUFFER *detail;
} WS_FAULT;
typedef struct _WS_FAULT_DESCRIPTION {
WS_ENVELOPE_VERSION envelopeVersion;
} WS_FAULT_DESCRIPTION;
typedef struct _WS_FAULT_DETAIL_DESCRIPTION {
WS_XML_STRING *action;
WS_ELEMENT_DESCRIPTION *detailElementDescription;
} WS_FAULT_DETAIL_DESCRIPTION;
typedef enum {
WS_FAULT_ERROR_PROPERTY_FAULT = 0,
WS_FAULT_ERROR_PROPERTY_ACTION = 1,
WS_FAULT_ERROR_PROPERTY_HEADER = 2
} WS_FAULT_ERROR_PROPERTY_ID;
struct _WS_HTTP_POLICY_DESCRIPTION {
WS_CHANNEL_PROPERTIES channelProperties;
};
@ -1649,6 +1684,9 @@ HRESULT WINAPI WsGetCustomHeader(WS_MESSAGE*, const WS_ELEMENT_DESCRIPTION*, WS_
HRESULT WINAPI WsGetDictionary(WS_ENCODING, WS_XML_DICTIONARY**, WS_ERROR*);
HRESULT WINAPI WsGetErrorProperty(WS_ERROR*, WS_ERROR_PROPERTY_ID, void*, ULONG);
HRESULT WINAPI WsGetErrorString(WS_ERROR*, ULONG, WS_STRING*);
HRESULT WINAPI WsGetFaultErrorDetail(WS_ERROR*, const WS_FAULT_DETAIL_DESCRIPTION*, WS_READ_OPTION,
WS_HEAP*, void*, ULONG);
HRESULT WINAPI WsGetFaultErrorProperty(WS_ERROR*, WS_FAULT_ERROR_PROPERTY_ID, void*, ULONG);
HRESULT WINAPI WsGetHeader(WS_MESSAGE*, WS_HEADER_TYPE, WS_TYPE, WS_READ_OPTION, WS_HEAP*, void*,
ULONG, WS_ERROR*);
HRESULT WINAPI WsGetHeapProperty(WS_HEAP*, WS_HEAP_PROPERTY_ID, void*, ULONG, WS_ERROR*);
@ -1731,6 +1769,7 @@ HRESULT WINAPI WsSendReplyMessage(WS_CHANNEL*, WS_MESSAGE*, const WS_MESSAGE_DES
const WS_ASYNC_CONTEXT*, WS_ERROR*);
HRESULT WINAPI WsSetChannelProperty(WS_CHANNEL*, WS_CHANNEL_PROPERTY_ID, const void*, ULONG, WS_ERROR*);
HRESULT WINAPI WsSetErrorProperty(WS_ERROR*, WS_ERROR_PROPERTY_ID, const void*, ULONG);
HRESULT WINAPI WsSetFaultErrorProperty(WS_ERROR*, WS_FAULT_ERROR_PROPERTY_ID, const void*, ULONG);
HRESULT WINAPI WsSetHeader(WS_MESSAGE*, WS_HEADER_TYPE, WS_TYPE, WS_WRITE_OPTION, const void*, ULONG,
WS_ERROR*);
HRESULT WINAPI WsSetInput(WS_XML_READER*, const WS_XML_READER_ENCODING*, const WS_XML_READER_INPUT*,