mirror of
git://source.winehq.org/git/wine.git
synced 2024-07-21 11:34:12 +00:00
webservices: Support faults in error.
Signed-off-by: Shaun Ren <sren@codeweavers.com>
This commit is contained in:
parent
da77cc8cfd
commit
ac90bc1e16
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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*,
|
||||
|
|
Loading…
Reference in a new issue