From b72c6e606106328e2ff20eaba7d932e2e42b09be Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 8 Jul 2016 10:20:37 +0200 Subject: [PATCH] webservices: Implement WsWriteEnvelopeStart. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/Makefile.in | 2 +- dlls/webservices/msg.c | 155 ++++++++++++++++++++++++++++++ dlls/webservices/tests/msg.c | 110 +++++++++++++++++++++ dlls/webservices/webservices.spec | 2 +- dlls/webservices/writer.c | 1 + 5 files changed, 268 insertions(+), 2 deletions(-) diff --git a/dlls/webservices/Makefile.in b/dlls/webservices/Makefile.in index 12b647aa3ad..1c631dc1ad0 100644 --- a/dlls/webservices/Makefile.in +++ b/dlls/webservices/Makefile.in @@ -1,6 +1,6 @@ MODULE = webservices.dll IMPORTLIB = webservices -IMPORTS = user32 +IMPORTS = rpcrt4 user32 C_SRCS = \ channel.c \ diff --git a/dlls/webservices/msg.c b/dlls/webservices/msg.c index 360e0bd1368..50821d9bf87 100644 --- a/dlls/webservices/msg.c +++ b/dlls/webservices/msg.c @@ -21,6 +21,7 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "rpc.h" #include "webservices.h" #include "wine/debug.h" @@ -29,6 +30,11 @@ 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 */ @@ -46,10 +52,15 @@ struct msg { WS_MESSAGE_INITIALIZATION init; WS_MESSAGE_STATE state; + GUID id; WS_ENVELOPE_VERSION version_env; WS_ADDRESSING_VERSION version_addr; BOOL is_addressed; WS_STRING addr; + WS_HEAP *heap; + WS_XML_BUFFER *buf; + WS_XML_WRITER *writer; + WS_XML_WRITER *writer_body; ULONG prop_count; struct prop prop[sizeof(msg_props)/sizeof(msg_props[0])]; }; @@ -70,10 +81,14 @@ static struct msg *alloc_msg(void) static void free_msg( struct msg *msg ) { if (!msg) return; + WsFreeWriter( msg->writer ); + WsFreeHeap( msg->heap ); heap_free( msg->addr.chars ); heap_free( msg ); } +#define HEAP_MAX_SIZE (1 << 16) + static HRESULT create_msg( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version, const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle ) { @@ -100,6 +115,18 @@ static HRESULT create_msg( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSIO } } + if ((hr = WsCreateHeap( HEAP_MAX_SIZE, 0, NULL, 0, &msg->heap, NULL )) != S_OK) + { + free_msg( msg ); + return hr; + } + if ((hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &msg->buf, NULL )) != S_OK) + { + free_msg( msg ); + return hr; + } + + UuidCreate( &msg->id ); msg->version_env = env_version; msg->version_addr = addr_version; @@ -202,6 +229,11 @@ HRESULT WINAPI WsGetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID *(WS_MESSAGE_STATE *)buf = msg->state; return S_OK; + case WS_MESSAGE_PROPERTY_HEAP: + if (!buf || size != sizeof(msg->heap)) return E_INVALIDARG; + *(WS_HEAP **)buf = msg->heap; + return S_OK; + case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION: if (!buf || size != sizeof(msg->version_env)) return E_INVALIDARG; *(WS_ENVELOPE_VERSION *)buf = msg->version_env; @@ -212,6 +244,11 @@ HRESULT WINAPI WsGetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID *(WS_ADDRESSING_VERSION *)buf = msg->version_addr; return S_OK; + case WS_MESSAGE_PROPERTY_HEADER_BUFFER: + if (!buf || size != sizeof(msg->buf)) return E_INVALIDARG; + *(WS_XML_BUFFER **)buf = msg->buf; + return S_OK; + case WS_MESSAGE_PROPERTY_IS_ADDRESSED: if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION; *(BOOL *)buf = msg->is_addressed; @@ -278,3 +315,121 @@ HRESULT WINAPI WsAddressMessage( WS_MESSAGE *handle, const WS_ENDPOINT_ADDRESS * msg->is_addressed = TRUE; return S_OK; } + +static HRESULT get_env_namespace( WS_ENVELOPE_VERSION ver, WS_XML_STRING *str ) +{ + switch (ver) + { + 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; + return S_OK; + + 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; + return S_OK; + + default: + ERR( "unhandled envelope version %u\n", ver ); + return E_NOTIMPL; + } +} + +static HRESULT get_addr_namespace( WS_ADDRESSING_VERSION ver, WS_XML_STRING *str ) +{ + switch (ver) + { + 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; + return S_OK; + + 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; + return S_OK; + + default: + ERR( "unhandled adressing version %u\n", ver ); + return E_NOTIMPL; + } +} + +static HRESULT write_envelope_start( struct msg *msg, WS_XML_WRITER *writer ) +{ + static const char anonymous[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"; + WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"}, body = {4, (BYTE *)"Body"}; + WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, header = {6, (BYTE *)"Header"}; + WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, replyto = {7, (BYTE *)"ReplyTo"}; + WS_XML_STRING address = {7, (BYTE *)"Address"}, ns_env, ns_addr; + WS_XML_UTF8_TEXT urn, 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_s, &envelope, &ns_env, NULL )) != S_OK) return hr; + 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 = WsWriteStartElement( writer, &prefix_a, &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; + + if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* */ + 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; + + addr.text.textType = WS_XML_TEXT_TYPE_UTF8; + addr.value.bytes = (BYTE *)anonymous; + addr.value.length = sizeof(anonymous) - 1; + if ((hr = WsWriteText( writer, &addr.text, NULL )) != S_OK) return hr; + if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* */ + if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* */ + } + + if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* */ + return WsWriteStartElement( writer, &prefix_s, &body, &ns_env, NULL ); /* */ +} + +static HRESULT write_envelope_end( struct msg *msg, WS_XML_WRITER *writer ) +{ + HRESULT hr; + if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* */ + return WsWriteEndElement( writer, NULL ); /* */ +} + +/************************************************************************** + * WsWriteEnvelopeStart [webservices.@] + */ +HRESULT WINAPI WsWriteEnvelopeStart( WS_MESSAGE *handle, WS_XML_WRITER *writer, + WS_MESSAGE_DONE_CALLBACK cb, void *state, WS_ERROR *error ) +{ + struct msg *msg = (struct msg *)handle; + HRESULT hr; + + TRACE( "%p %p %p %p %p\n", handle, writer, cb, state, error ); + if (error) FIXME( "ignoring error parameter\n" ); + if (cb) + { + FIXME( "callback not supported\n" ); + return E_NOTIMPL; + } + + if (!handle) return E_INVALIDARG; + if (msg->state != WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION; + + if ((hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) return hr; + if ((hr = WsSetOutputToBuffer( msg->writer, msg->buf, NULL, 0, NULL )) != S_OK) return hr; + if ((hr = write_envelope_start( msg, msg->writer )) != S_OK) return hr; + if ((hr = write_envelope_start( msg, writer )) != S_OK) return hr; + if ((hr = write_envelope_end( msg, msg->writer )) != S_OK) return hr; + + msg->writer_body = writer; + msg->state = WS_MESSAGE_STATE_WRITING; + return S_OK; +} diff --git a/dlls/webservices/tests/msg.c b/dlls/webservices/tests/msg.c index 3e321d70af1..ec737c1f6e5 100644 --- a/dlls/webservices/tests/msg.c +++ b/dlls/webservices/tests/msg.c @@ -271,10 +271,120 @@ static void test_WsAddressMessage(void) WsFreeMessage( msg ); } +static HRESULT set_output( WS_XML_WRITER *writer ) +{ + WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 }; + WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} }; + return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL ); +} + +static void check_output( WS_XML_WRITER *writer, const char *expected, int len, unsigned int skip_start, + unsigned int skip_len, unsigned int line ) +{ + WS_BYTES bytes; + HRESULT hr; + + if (len == -1) len = strlen( expected ); + memset( &bytes, 0, sizeof(bytes) ); + hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, sizeof(bytes), NULL ); + ok( hr == S_OK, "%u: got %08x\n", line, hr ); + ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len ); + if (bytes.length != len) return; + if (skip_start) + { + ok( !memcmp( bytes.bytes, expected, skip_start ), "%u: got %s expected %s\n", line, + bytes.bytes, expected ); + ok( !memcmp( bytes.bytes + skip_start + skip_len, expected + skip_start + skip_len, + len - skip_start - skip_len), "%u: got %s expected %s\n", line, bytes.bytes, expected ); + } + else + ok( !memcmp( bytes.bytes, expected, len ), "%u: got %s expected %s\n", line, bytes.bytes, + expected ); +} + +static void check_output_header( WS_MESSAGE *msg, const char *expected, int len, unsigned int skip_start, + unsigned int skip_len, unsigned int line ) +{ + WS_XML_WRITER *writer; + WS_XML_BUFFER *buf; + HRESULT hr; + + hr = WsCreateWriter( NULL, 0, &writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = set_output( writer ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsGetMessageProperty( msg, WS_MESSAGE_PROPERTY_HEADER_BUFFER, &buf, sizeof(buf), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteXmlBuffer( writer, buf, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + check_output( writer, expected, len, skip_start, skip_len, line ); + WsFreeWriter( writer ); +} + +static void test_WsWriteEnvelopeStart(void) +{ + static const char expected[] = + "" + "urn:uuid:00000000-0000-0000-0000-000000000000" + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous" + ""; + static const char expected2[] = + "" + "urn:uuid:00000000-0000-0000-0000-000000000000" + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous" + ""; + HRESULT hr; + WS_MESSAGE *msg; + WS_XML_WRITER *writer; + WS_MESSAGE_STATE state; + + hr = WsWriteEnvelopeStart( NULL, NULL, NULL, NULL, NULL ); + ok( hr == E_INVALIDARG, "got %08x\n", hr ); + + hr = WsCreateWriter( NULL, 0, &writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteEnvelopeStart( NULL, writer, NULL, NULL, NULL ); + ok( hr == E_INVALIDARG, "got %08x\n", hr ); + + hr = WsCreateMessage( WS_ADDRESSING_VERSION_0_9, WS_ENVELOPE_VERSION_SOAP_1_1, NULL, 0, &msg, + NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteEnvelopeStart( msg, writer, NULL, NULL, NULL ); + ok( hr == WS_E_INVALID_OPERATION, "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( writer, expected, -1, strstr(expected, "urn:uuid:") - expected, 46, __LINE__ ); + check_output_header( msg, expected2, -1, strstr(expected2, "urn:uuid:") - expected2, 46, __LINE__ ); + + state = 0xdeadbeef; + hr = WsGetMessageProperty( msg, WS_MESSAGE_PROPERTY_STATE, &state, sizeof(state), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( state == WS_MESSAGE_STATE_WRITING, "got %u\n", state ); + + WsFreeMessage( msg ); + WsFreeWriter( writer ); +} + START_TEST(msg) { test_WsCreateMessage(); test_WsCreateMessageForChannel(); test_WsInitializeMessage(); test_WsAddressMessage(); + test_WsWriteEnvelopeStart(); } diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec index a702fc0c7ba..6a29af0f18f 100644 --- a/dlls/webservices/webservices.spec +++ b/dlls/webservices/webservices.spec @@ -176,7 +176,7 @@ @ stdcall WsWriteEndElement(ptr ptr) @ stdcall WsWriteEndStartElement(ptr ptr) @ stub WsWriteEnvelopeEnd -@ stub WsWriteEnvelopeStart +@ stdcall WsWriteEnvelopeStart(ptr ptr ptr ptr ptr) @ stub WsWriteMessageEnd @ stub WsWriteMessageStart @ stdcall WsWriteNode(ptr ptr ptr) diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index 45c5021664d..b1afcb81fc5 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -97,6 +97,7 @@ static struct writer *alloc_writer(void) static void free_writer( struct writer *writer ) { + if (!writer) return; destroy_nodes( writer->root ); heap_free( writer->current_ns ); WsFreeHeap( writer->output_heap );