From: Shaun Ren sren@codeweavers.com
Signed-off-by: Shaun Ren sren@codeweavers.com --- dlls/webservices/reader.c | 164 +++++++++++++++++++++++++++++++- dlls/webservices/tests/reader.c | 40 ++++++++ 2 files changed, 203 insertions(+), 1 deletion(-)
diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index b22bcbd51b1..b28a5cc107c 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -4312,7 +4312,7 @@ static BOOL match_element( const struct node *node, const WS_XML_STRING *localna const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node; if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE; return WsXmlStringEquals( localname, elem->localName, NULL ) == S_OK && - WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK; + (!ns || WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK); }
static HRESULT read_next_node( struct reader *reader ) @@ -6507,6 +6507,164 @@ static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping, return S_OK; }
+static HRESULT read_type_fault( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname, + const WS_XML_STRING *ns, const WS_FAULT_DESCRIPTION *desc, WS_READ_OPTION option, + WS_HEAP *heap, void *ret, ULONG size, BOOL *found ) +{ + static const WS_XML_STRING faultcode = {9, (BYTE *)"faultcode"}, faultstring = {11, (BYTE *)"faultstring"}; + static const WS_XML_STRING faultactor = {10, (BYTE *)"faultactor"}, detail = {6, (BYTE *)"detail"}; + + const struct node *root = reader->current; + WS_FAULT *fault; + HRESULT hr = S_OK; + + if (mapping != WS_ELEMENT_TYPE_MAPPING || !desc || !ret) + return E_INVALIDARG; + if (desc->envelopeVersion < WS_ENVELOPE_VERSION_SOAP_1_1 || desc->envelopeVersion >= WS_ENVELOPE_VERSION_NONE) + return E_INVALIDARG; + else if (desc->envelopeVersion != WS_ENVELOPE_VERSION_SOAP_1_1) + { + FIXME( "unhandled envelopeVersion %u\n", desc->envelopeVersion ); + return E_NOTIMPL; + } + + switch (option) + { + case WS_READ_REQUIRED_VALUE: + if (size != sizeof(*fault)) + return E_INVALIDARG; + fault = ret; + memset( fault, 0, sizeof(*fault) ); + break; + + case WS_READ_REQUIRED_POINTER: + case WS_READ_OPTIONAL_POINTER: + case WS_READ_NILLABLE_POINTER: + if (size != sizeof(void *)) + return E_INVALIDARG; + if (!(fault = ws_alloc_zero( heap, sizeof(*fault) ))) + return WS_E_QUOTA_EXCEEDED; + break; + + case WS_READ_NILLABLE_VALUE: + return E_INVALIDARG; + + default: + FIXME( "unhandled read option %u\n", option ); + return E_NOTIMPL; + } + + if ((hr = read_type_next_node( reader )) != S_OK) goto done; + for (;;) + { + if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT && reader->current->parent == root) + break; + + if (match_element( reader->current, &faultcode, ns )) + { + if (fault->code) + { + hr = WS_E_INVALID_FORMAT; + break; + } + if (!(fault->code = ws_alloc_zero( heap, sizeof(*fault->code) ))) + { + hr = WS_E_QUOTA_EXCEEDED; + break; + } + if ((hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, WS_XML_QNAME_TYPE, NULL, NULL, + NULL, WS_READ_REQUIRED_VALUE, heap, &fault->code->value, + sizeof(fault->code->value), found )) != S_OK) + break; + + } + else if (match_element( reader->current, &faultstring, ns )) + { + if (fault->reasons) + { + hr = WS_E_INVALID_FORMAT; + break; + } + if (!(fault->reasons = ws_alloc_zero( heap, sizeof(*fault->reasons) ))) + { + hr = WS_E_QUOTA_EXCEEDED; + break; + } + fault->reasonCount = 1; + /* FIXME: parse optional xml:lang attribute */ + if ((hr = read_next_node( reader )) != S_OK || + (hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, WS_STRING_TYPE, NULL, NULL, + NULL, WS_READ_REQUIRED_VALUE, heap, &fault->reasons->text, + sizeof(fault->reasons->text), found )) != S_OK) + break; + } + else if (match_element( reader->current, &faultactor, ns )) + { + if (fault->actor.length > 0) + { + hr = WS_E_INVALID_FORMAT; + break; + } + if ((hr = read_next_node( reader )) != S_OK || + (hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, WS_STRING_TYPE, NULL, NULL, + NULL, WS_READ_REQUIRED_VALUE, heap, &fault->actor, + sizeof(fault->actor), found )) != S_OK) + break; + } + else if (match_element( reader->current, &detail, ns )) + { + if (fault->detail) + { + hr = WS_E_INVALID_FORMAT; + break; + } + if ((hr = WsReadXmlBuffer( (WS_XML_READER *)reader, heap, &fault->detail, NULL )) != S_OK) + break; + } + else if ((hr = read_type_next_node( reader )) != S_OK) + break; + } + +done: + if ((!fault->code || !fault->reasons) && hr == S_OK) + hr = WS_E_INVALID_FORMAT; + + if (hr != S_OK) + { + free_fault_fields( heap, fault ); + + switch (option) + { + case WS_READ_REQUIRED_VALUE: + case WS_READ_REQUIRED_POINTER: + memset( fault, 0, sizeof(*fault) ); + break; + + case WS_READ_OPTIONAL_POINTER: + case WS_READ_NILLABLE_POINTER: + if (hr == WS_E_INVALID_FORMAT && is_nil_value( (const char *)fault, sizeof(*fault) )) + { + ws_free( heap, fault, sizeof(*fault) ); + fault = NULL; + hr = S_OK; + } + else + memset( fault, 0, sizeof(*fault) ); + break; + + default: + ERR( "unhandled option %u\n", option ); + return E_NOTIMPL; + } + } + + if (option != WS_READ_REQUIRED_VALUE) + *(WS_FAULT **)ret = fault; + + *found = TRUE; + return hr; +} + static HRESULT start_mapping( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname, const WS_XML_STRING *ns ) { @@ -6698,6 +6856,10 @@ static HRESULT read_type( struct reader *reader, WS_TYPE_MAPPING mapping, WS_TYP hr = read_type_struct( reader, mapping, localname, ns, desc, option, heap, value, size, found ); break;
+ case WS_FAULT_TYPE: + hr = read_type_fault( reader, mapping, localname, ns, desc, option, heap, value, size, found ); + break; + case WS_ENUM_TYPE: hr = read_type_enum( reader, mapping, localname, ns, desc, option, heap, value, size, found ); break; diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index 2ade3c3d4b1..d370c2ebe75 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -1355,6 +1355,8 @@ static void test_WsReadNode(void) WsFreeReader( reader ); }
+static void check_output_buffer( WS_XML_BUFFER *buffer, const char *expected, unsigned int line ); + static void prepare_type_test( WS_XML_READER *reader, const char *data, ULONG size ) { HRESULT hr; @@ -1373,6 +1375,15 @@ static void test_WsReadType(void) { static const GUID guid = {0,0,0,{0,0,0,0,0,0,0,0xa1}}; static const char utf8[] = {'<','t','>',0xe2,0x80,0x99,'<','/','t','>'}; + static const char faultxml[] = + "<s:Body xmlns:s="http://schemas.xmlsoap.org/soap/envelope/%5C%22%3E<s:Fault>" + "<faultcode>s:Client</faultcode><faultstring>Example Fault</faultstring>" + "<faultactor>http://example.com/fault</faultactor>" + "<detail><ErrorCode>1030</ErrorCode></detail></s:Fault></s:Body>"; + static const char faultcode[] = "Client"; + static const WCHAR faultstring[] = L"Example Fault"; + static const WCHAR faultactor[] = L"http://example.com/fault"; + static const char faultdetail[] = "<detail><ErrorCode>1030</ErrorCode></detail>"; HRESULT hr; WS_XML_READER *reader; WS_HEAP *heap; @@ -1396,6 +1407,8 @@ static void test_WsReadType(void) WS_STRING val_string, *ptr_string; WS_UNIQUE_ID val_id, *ptr_id; WS_XML_QNAME val_qname, *ptr_qname; + WS_FAULT_DESCRIPTION fault_desc; + WS_FAULT fault;
hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL ); ok( hr == S_OK, "got %#lx\n", hr ); @@ -1920,6 +1933,33 @@ static void test_WsReadType(void) WS_READ_REQUIRED_POINTER, heap, &ptr_qname, sizeof(ptr_qname), NULL ); ok( hr == WS_E_INVALID_FORMAT, "got %#lx\n", hr );
+ prepare_type_test( reader, faultxml, sizeof(faultxml) - 1 ); + hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + memset( &fault, 0, sizeof(fault) ); + + fault_desc.envelopeVersion = WS_ENVELOPE_VERSION_SOAP_1_1; + hr = WsReadType( reader, WS_ELEMENT_TYPE_MAPPING, WS_FAULT_TYPE, &fault_desc, + WS_READ_REQUIRED_VALUE, heap, &fault, sizeof(fault), NULL ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( fault.code->value.localName.length == sizeof(faultcode) - 1, "got %lu\n", fault.code->value.localName.length ); + ok( !memcmp( fault.code->value.localName.bytes, faultcode, sizeof(faultcode) - 1 ), "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 == ARRAY_SIZE(faultstring) - 1, "got %lu\n", fault.reasons[0].text.length ); + ok( !memcmp( fault.reasons[0].text.chars, faultstring, (ARRAY_SIZE(faultstring) - 1) * sizeof(WCHAR) ), + "wrong fault string\n" ); + ok( fault.actor.length == ARRAY_SIZE(faultactor) - 1, "got %lu\n", fault.actor.length ); + ok( !memcmp( fault.actor.chars, faultactor, ARRAY_SIZE(faultactor) - 1 ), "wrong fault actor\n" ); + ok( !fault.node.length, "fault node not empty\n" ); + ok( fault.detail != NULL, "fault detail not set\n" ); + check_output_buffer( fault.detail, faultdetail, __LINE__ ); + + fault_desc.envelopeVersion = WS_ENVELOPE_VERSION_NONE; + hr = WsReadType( reader, WS_ELEMENT_TYPE_MAPPING, WS_FAULT_TYPE, &fault_desc, + WS_READ_REQUIRED_VALUE, heap, &fault, sizeof(fault), NULL ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + WsFreeReader( reader ); WsFreeHeap( heap ); }