webservices: Write correct envelope headers for WS_ENVELOPE_VERSION_NONE.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2017-06-06 09:55:55 +02:00 committed by Alexandre Julliard
parent be0f451e4e
commit cd83b80acc
2 changed files with 106 additions and 94 deletions

View File

@ -31,11 +31,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(webservices);
static const char ns_env_1_1[] = "http://schemas.xmlsoap.org/soap/envelope/";
static const char ns_env_1_2[] = "http://www.w3.org/2003/05/soap-envelope";
static const char ns_addr_0_9[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
static const char ns_addr_1_0[] = "http://www.w3.org/2005/08/addressing";
static const struct prop_desc msg_props[] =
{
{ sizeof(WS_MESSAGE_STATE), TRUE }, /* WS_MESSAGE_PROPERTY_STATE */
@ -78,6 +73,7 @@ struct msg
WS_XML_BUFFER *buf;
WS_XML_WRITER *writer;
WS_XML_WRITER *writer_body;
WS_XML_READER *reader;
WS_XML_READER *reader_body;
ULONG header_count;
ULONG header_size;
@ -160,6 +156,7 @@ static void free_msg( struct msg *msg )
reset_msg( msg );
WsFreeWriter( msg->writer );
WsFreeReader( msg->reader );
WsFreeHeap( msg->heap );
heap_free( msg->header );
@ -219,7 +216,11 @@ HRESULT WINAPI WsCreateMessage( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_V
TRACE( "%u %u %p %u %p %p\n", env_version, addr_version, properties, count, handle, error );
if (error) FIXME( "ignoring error parameter\n" );
if (!handle || !env_version || !addr_version) return E_INVALIDARG;
if (!handle || !env_version || !addr_version ||
(env_version == WS_ENVELOPE_VERSION_NONE && addr_version != WS_ADDRESSING_VERSION_TRANSPORT))
{
return E_INVALIDARG;
}
return create_msg( env_version, addr_version, properties, count, handle );
}
@ -460,57 +461,40 @@ HRESULT WINAPI WsAddressMessage( WS_MESSAGE *handle, const WS_ENDPOINT_ADDRESS *
return hr;
}
static HRESULT get_env_namespace( WS_ENVELOPE_VERSION ver, WS_XML_STRING *str )
static const WS_XML_STRING *get_env_namespace( WS_ENVELOPE_VERSION version )
{
switch (ver)
static const WS_XML_STRING namespaces[] =
{
case WS_ENVELOPE_VERSION_SOAP_1_1:
str->bytes = (BYTE *)ns_env_1_1;
str->length = sizeof(ns_env_1_1)/sizeof(ns_env_1_1[0]) - 1;
break;
{41, (BYTE *)"http://schemas.xmlsoap.org/soap/envelope/"},
{39, (BYTE *)"http://www.w3.org/2003/05/soap-envelope"},
{0, NULL},
};
case WS_ENVELOPE_VERSION_SOAP_1_2:
str->bytes = (BYTE *)ns_env_1_2;
str->length = sizeof(ns_env_1_2)/sizeof(ns_env_1_2[0]) - 1;
break;
default:
ERR( "unhandled envelope version %u\n", ver );
return E_NOTIMPL;
if (version < WS_ENVELOPE_VERSION_SOAP_1_1 || version > WS_ENVELOPE_VERSION_NONE)
{
ERR( "unknown version %u\n", version );
return NULL;
}
str->dictionary = NULL;
str->id = 0;
return S_OK;
return &namespaces[version - 1];
}
static HRESULT get_addr_namespace( WS_ADDRESSING_VERSION ver, WS_XML_STRING *str )
static const WS_XML_STRING *get_addr_namespace( WS_ADDRESSING_VERSION version )
{
switch (ver)
static const WS_XML_STRING namespaces[] =
{
case WS_ADDRESSING_VERSION_0_9:
str->bytes = (BYTE *)ns_addr_0_9;
str->length = sizeof(ns_addr_0_9)/sizeof(ns_addr_0_9[0]) - 1;
break;
{48, (BYTE *)"http://schemas.xmlsoap.org/ws/2004/08/addressing"},
{36, (BYTE *)"http://www.w3.org/2005/08/addressing"},
{55, (BYTE *)"http://schemas.microsoft.com/ws/2005/05/addressing/none"},
};
case WS_ADDRESSING_VERSION_1_0:
str->bytes = (BYTE *)ns_addr_1_0;
str->length = sizeof(ns_addr_1_0)/sizeof(ns_addr_1_0[0]) - 1;
break;
case WS_ADDRESSING_VERSION_TRANSPORT:
str->bytes = NULL;
str->length = 0;
break;
default:
ERR( "unhandled addressing version %u\n", ver );
return E_NOTIMPL;
if (version < WS_ADDRESSING_VERSION_0_9 || version > WS_ADDRESSING_VERSION_TRANSPORT)
{
ERR( "unknown version %u\n", version );
return NULL;
}
str->dictionary = NULL;
str->id = 0;
return S_OK;
return &namespaces[version - 1];
}
static const WS_XML_STRING *get_header_name( WS_HEADER_TYPE type )
@ -535,21 +519,22 @@ static const WS_XML_STRING *get_header_name( WS_HEADER_TYPE type )
return &headers[type - 1];
}
static HRESULT write_headers( struct msg *msg, const WS_XML_STRING *ns_env, const WS_XML_STRING *ns_addr,
WS_XML_WRITER *writer )
static HRESULT write_headers( struct msg *msg, WS_XML_WRITER *writer, const WS_XML_STRING *prefix_env,
const WS_XML_STRING *ns_env, const WS_XML_STRING *prefix_addr,
const WS_XML_STRING *ns_addr )
{
static const char anonymous[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
static const WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, replyto = {7, (BYTE *)"ReplyTo"};
static const WS_XML_STRING address = {7, (BYTE *)"Address"}, header = {6, (BYTE *)"Header"};
static const WS_XML_STRING header = {6, (BYTE *)"Header"}, address = {7, (BYTE *)"Address"};
const WS_XML_STRING *msgid = get_header_name( WS_MESSAGE_ID_HEADER );
const WS_XML_STRING *replyto = get_header_name( WS_REPLY_TO_HEADER );
WS_XML_UTF8_TEXT urn, addr;
HRESULT hr;
ULONG i;
if ((hr = WsWriteXmlnsAttribute( writer, &prefix_a, ns_addr, FALSE, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, &prefix_s, &header, ns_env, NULL )) != S_OK) return hr;
if ((hr = WsWriteXmlnsAttribute( writer, prefix_addr, ns_addr, FALSE, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, prefix_env, &header, ns_env, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, &prefix_a, &msgid, ns_addr, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, prefix_addr, msgid, ns_addr, NULL )) != S_OK) return hr;
urn.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
memcpy( &urn.value, &msg->id, sizeof(msg->id) );
if ((hr = WsWriteText( writer, &urn.text, NULL )) != S_OK) return hr;
@ -557,8 +542,8 @@ static HRESULT write_headers( struct msg *msg, const WS_XML_STRING *ns_env, cons
if (msg->version_addr == WS_ADDRESSING_VERSION_0_9)
{
if ((hr = WsWriteStartElement( writer, &prefix_a, &replyto, ns_addr, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, &prefix_a, &address, ns_addr, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, prefix_addr, replyto, ns_addr, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, prefix_addr, &address, ns_addr, NULL )) != S_OK) return hr;
addr.text.textType = WS_XML_TEXT_TYPE_UTF8;
addr.value.bytes = (BYTE *)anonymous;
@ -577,14 +562,15 @@ static HRESULT write_headers( struct msg *msg, const WS_XML_STRING *ns_env, cons
return WsWriteEndElement( writer, NULL ); /* </s:Header> */
}
static HRESULT write_headers_transport( struct msg *msg, const WS_XML_STRING *ns_env, WS_XML_WRITER *writer )
static HRESULT write_headers_transport( struct msg *msg, WS_XML_WRITER *writer, const WS_XML_STRING *prefix,
const WS_XML_STRING *ns )
{
static const WS_XML_STRING prefix = {1, (BYTE *)"s"}, header = {6, (BYTE *)"Header"};
static const WS_XML_STRING header = {6, (BYTE *)"Header"};
HRESULT hr = S_OK;
ULONG i;
if ((msg->header_count || !msg->action.length) &&
(hr = WsWriteStartElement( writer, &prefix, &header, ns_env, NULL )) != S_OK) return hr;
(hr = WsWriteStartElement( writer, prefix, &header, ns, NULL )) != S_OK) return hr;
for (i = 0; i < msg->header_count; i++)
{
@ -599,21 +585,22 @@ static HRESULT write_headers_transport( struct msg *msg, const WS_XML_STRING *ns
static HRESULT write_envelope_start( struct msg *msg, WS_XML_WRITER *writer )
{
static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, body = {4, (BYTE *)"Body"};
static const WS_XML_STRING prefix = {1, (BYTE *)"s"};
WS_XML_STRING ns_env, ns_addr;
static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
const WS_XML_STRING *prefix_env = (msg->version_env == WS_ENVELOPE_VERSION_NONE) ? NULL : &prefix_s;
const WS_XML_STRING *prefix_addr = (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT) ? NULL : &prefix_a;
const WS_XML_STRING *ns_env = get_env_namespace( msg->version_env );
const WS_XML_STRING *ns_addr = get_addr_namespace( msg->version_addr );
HRESULT hr;
if ((hr = get_env_namespace( msg->version_env, &ns_env )) != S_OK) return hr;
if ((hr = get_addr_namespace( msg->version_addr, &ns_addr )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, &prefix, &envelope, &ns_env, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartElement( writer, prefix_env, &envelope, ns_env, NULL )) != S_OK) return hr;
if (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT)
hr = write_headers_transport( msg, &ns_env, writer );
hr = write_headers_transport( msg, writer, prefix_env, ns_env );
else
hr = write_headers( msg, &ns_env, &ns_addr, writer );
hr = write_headers( msg, writer, prefix_env, ns_env, prefix_addr, ns_addr );
if (hr != S_OK) return hr;
return WsWriteStartElement( writer, &prefix, &body, &ns_env, NULL ); /* <s:Body> */
return WsWriteStartElement( writer, prefix_env, &body, ns_env, NULL ); /* <s:Body> */
}
static HRESULT write_envelope_end( WS_XML_WRITER *writer )
@ -986,47 +973,51 @@ static struct header *alloc_header( WS_HEADER_TYPE type, BOOL mapped, const WS_X
return ret;
}
static HRESULT write_standard_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, WS_TYPE value_type,
static HRESULT write_standard_header( struct msg *msg, WS_HEADER_TYPE type, WS_TYPE value_type,
WS_WRITE_OPTION option, const void *value, ULONG size )
{
static const WS_XML_STRING ns = {0, NULL}, understand = {14, (BYTE *)"mustUnderstand"};
static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
static const WS_XML_STRING understand = {14, (BYTE *)"mustUnderstand"}, ns = {0, NULL};
const WS_XML_STRING *prefix_env = (msg->version_env == WS_ENVELOPE_VERSION_NONE) ? NULL : &prefix_s;
const WS_XML_STRING *prefix_addr = (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT) ? NULL : &prefix_a;
const WS_XML_STRING *localname = get_header_name( type );
WS_XML_INT32_TEXT one = {{WS_XML_TEXT_TYPE_INT32}, 1};
HRESULT hr;
if ((hr = WsWriteStartElement( writer, &prefix_a, name, &ns, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartAttribute( writer, &prefix_s, &understand, &ns, FALSE, NULL )) != S_OK) return hr;
if ((hr = WsWriteText( writer, &one.text, NULL )) != S_OK) return hr;
if ((hr = WsWriteEndAttribute( writer, NULL )) != S_OK) return hr;
if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, value_type, NULL, option, value, size,
if ((hr = WsWriteStartElement( msg->writer, prefix_addr, localname, &ns, NULL )) != S_OK) return hr;
if ((hr = WsWriteStartAttribute( msg->writer, prefix_env, &understand, &ns, FALSE, NULL )) != S_OK) return hr;
if ((hr = WsWriteText( msg->writer, &one.text, NULL )) != S_OK) return hr;
if ((hr = WsWriteEndAttribute( msg->writer, NULL )) != S_OK) return hr;
if (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT)
{
const WS_XML_STRING *ns_addr = get_addr_namespace( WS_ADDRESSING_VERSION_TRANSPORT );
if ((hr = WsWriteXmlnsAttribute( msg->writer, NULL, ns_addr, FALSE, NULL )) != S_OK) return hr;
}
if ((hr = WsWriteType( msg->writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, value_type, NULL, option, value, size,
NULL )) != S_OK) return hr;
return WsWriteEndElement( writer, NULL );
return WsWriteEndElement( msg->writer, NULL );
}
static HRESULT build_standard_header( WS_HEAP *heap, WS_HEADER_TYPE type, WS_TYPE value_type,
static HRESULT build_standard_header( struct msg *msg, WS_HEADER_TYPE type, WS_TYPE value_type,
WS_WRITE_OPTION option, const void *value, ULONG size,
struct header **ret )
{
const WS_XML_STRING *name = get_header_name( type );
struct header *header;
WS_XML_WRITER *writer;
WS_XML_BUFFER *buf;
HRESULT hr;
if (!(header = alloc_header( type, FALSE, name, NULL ))) return E_OUTOFMEMORY;
if (!(header = alloc_header( type, FALSE, get_header_name(type), NULL ))) return E_OUTOFMEMORY;
if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
if ((hr = write_standard_header( writer, name, value_type, option, value, size )) != S_OK)
goto done;
if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) return hr;
if ((hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
if ((hr = WsSetOutputToBuffer( msg->writer, buf, NULL, 0, NULL )) != S_OK) goto done;
if ((hr = write_standard_header( msg, type, value_type, option, value, size )) != S_OK) goto done;
header->u.buf = buf;
done:
if (hr != S_OK) free_header( header );
else *ret = header;
WsFreeWriter( writer );
return hr;
}
@ -1076,7 +1067,7 @@ HRESULT WINAPI WsSetHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_TYPE val
i = msg->header_count;
}
if ((hr = build_standard_header( msg->heap, type, value_type, option, value, size, &header )) != S_OK)
if ((hr = build_standard_header( msg, type, value_type, option, value, size, &header )) != S_OK)
goto done;
if (!found) msg->header_count++;
@ -1346,28 +1337,26 @@ static HRESULT write_custom_header( WS_XML_WRITER *writer, const WS_XML_STRING *
return WsWriteEndElement( writer, NULL );
}
static HRESULT build_custom_header( WS_HEAP *heap, const WS_XML_STRING *name, const WS_XML_STRING *ns,
static HRESULT build_custom_header( struct msg *msg, const WS_XML_STRING *name, const WS_XML_STRING *ns,
WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
ULONG size, struct header **ret )
{
struct header *header;
WS_XML_WRITER *writer;
WS_XML_BUFFER *buf;
HRESULT hr;
if (!(header = alloc_header( 0, FALSE, name, ns ))) return E_OUTOFMEMORY;
if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
if ((hr = write_custom_header( writer, name, ns, type, desc, option, value, size )) != S_OK) goto done;
if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) return hr;
if ((hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
if ((hr = WsSetOutputToBuffer( msg->writer, buf, NULL, 0, NULL )) != S_OK) goto done;
if ((hr = write_custom_header( msg->writer, name, ns, type, desc, option, value, size )) != S_OK) goto done;
header->u.buf = buf;
done:
if (hr != S_OK) free_header( header );
else *ret = header;
WsFreeWriter( writer );
return hr;
}
@ -1401,7 +1390,7 @@ HRESULT WINAPI WsAddCustomHeader( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTI
}
if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done;
if ((hr = build_custom_header( msg->heap, desc->elementLocalName, desc->elementNs, desc->type,
if ((hr = build_custom_header( msg, desc->elementLocalName, desc->elementNs, desc->type,
desc->typeDescription, option, value, size, &header )) != S_OK) goto done;
msg->header[msg->header_count++] = header;
hr = write_envelope( msg );

View File

@ -340,6 +340,8 @@ static void test_WsWriteEnvelopeStart(void)
"</a:ReplyTo></s:Header><s:Body/></s:Envelope>";
static const char expected3[] =
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Header/><s:Body/></s:Envelope>";
static const char expected4[] =
"<Envelope><Header/><Body/></Envelope>";
HRESULT hr;
WS_MESSAGE *msg;
WS_XML_WRITER *writer;
@ -391,8 +393,29 @@ static void test_WsWriteEnvelopeStart(void)
hr = WsWriteEnvelopeStart( msg, writer, NULL, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
check_output_header( msg, expected3, -1, 0, 0, __LINE__ );
WsFreeMessage( msg );
hr = WsCreateMessage( WS_ENVELOPE_VERSION_NONE, WS_ADDRESSING_VERSION_TRANSPORT, NULL, 0, &msg,
NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsInitializeMessage( msg, WS_REQUEST_MESSAGE, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = set_output( writer );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEnvelopeStart( msg, writer, NULL, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
check_output_header( msg, expected4, -1, 0, 0, __LINE__ );
WsFreeMessage( msg );
hr = WsCreateMessage( WS_ENVELOPE_VERSION_NONE, WS_ADDRESSING_VERSION_0_9, NULL, 0, &msg,
NULL );
ok( hr == E_INVALIDARG, "got %08x\n", hr );
hr = WsCreateMessage( WS_ENVELOPE_VERSION_NONE, WS_ADDRESSING_VERSION_1_0, NULL, 0, &msg,
NULL );
ok( hr == E_INVALIDARG, "got %08x\n", hr );
WsFreeWriter( writer );
}