From a2c733c057881b3529bc4a701d735cfb43944dbc Mon Sep 17 00:00:00 2001 From: Owen Rudge Date: Mon, 19 Mar 2018 21:46:23 +0000 Subject: [PATCH] wsdapi: Implement generation of XML from WSDXML structures. Signed-off-by: Owen Rudge Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/wsdapi/Makefile.in | 2 +- dlls/wsdapi/soap.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 177 insertions(+), 8 deletions(-) diff --git a/dlls/wsdapi/Makefile.in b/dlls/wsdapi/Makefile.in index e3f3348f91d..f5eb0fdbf06 100644 --- a/dlls/wsdapi/Makefile.in +++ b/dlls/wsdapi/Makefile.in @@ -1,6 +1,6 @@ MODULE = wsdapi.dll IMPORTLIB = wsdapi -IMPORTS = bcrypt iphlpapi rpcrt4 user32 ws2_32 +IMPORTS = bcrypt iphlpapi rpcrt4 user32 webservices ws2_32 C_SRCS = \ address.c \ diff --git a/dlls/wsdapi/soap.c b/dlls/wsdapi/soap.c index c33c73ba252..bec4b1d6655 100644 --- a/dlls/wsdapi/soap.c +++ b/dlls/wsdapi/soap.c @@ -26,6 +26,7 @@ #include "wsdapi_internal.h" #include "wine/debug.h" #include "wine/heap.h" +#include "webservices.h" WINE_DEFAULT_DEBUG_CHANNEL(wsdapi); @@ -44,6 +45,77 @@ static const WCHAR actionHello[] = { 'd','i','s','c','o','v','e','r','y','/', 'H','e','l','l','o', 0 }; +static const WCHAR addressingNsUri[] = { + 'h','t','t','p',':','/','/', + 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/', + 'w','s','/','2','0','0','4','/','0','8','/','a','d','d','r','e','s','s','i','n','g', 0 }; + +static const WCHAR discoveryNsUri[] = { + 'h','t','t','p',':','/','/', + 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/', + 'w','s','/','2','0','0','5','/','0','4','/','d','i','s','c','o','v','e','r','y', 0 }; + +static const WCHAR envelopeNsUri[] = { + 'h','t','t','p',':','/','/', + 'w','w','w','.','w','3','.','o','r','g','/', + '2','0','0','3','/','0','5','/','s','o','a','p','-','e','n','v','e','l','o','p','e', 0 }; + +static const WCHAR addressingPrefix[] = { 'w','s','a', 0 }; +static const WCHAR discoveryPrefix[] = { 'w','s','d', 0 }; +static const WCHAR envelopePrefix[] = { 's','o','a','p', 0 }; + +static char *wide_to_utf8(LPCWSTR wide_string, int *length) +{ + char *new_string = NULL; + + if (wide_string == NULL) + return NULL; + + *length = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, NULL, 0, NULL, NULL); + + if (*length < 0) + return NULL; + + new_string = heap_alloc(*length); + WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, new_string, *length, NULL, NULL); + + return new_string; +} + +static WS_XML_STRING *populate_xml_string(LPCWSTR str) +{ + WS_XML_STRING *xml = heap_alloc_zero(sizeof(WS_XML_STRING)); + int utf8Length; + + if (xml == NULL) + return NULL; + + xml->bytes = (BYTE *)wide_to_utf8(str, &utf8Length); + + if (xml->bytes == NULL) + { + heap_free(xml); + return NULL; + } + + xml->dictionary = NULL; + xml->id = 0; + xml->length = (xml->bytes == NULL) ? 0 : (utf8Length - 1); + + return xml; +} + +static inline void free_xml_string(WS_XML_STRING *value) +{ + if (value == NULL) + return; + + if (value->bytes != NULL) + heap_free(value->bytes); + + heap_free(value); +} + static BOOL create_guid(LPWSTR buffer) { const WCHAR formatString[] = { 'u','r','n',':','u','u','i','d',':','%','s', 0 }; @@ -79,30 +151,126 @@ static void populate_soap_header(WSD_SOAP_HEADER *header, LPCWSTR to, LPCWSTR ac /* TODO: Implement RelatesTo, ReplyTo, From, FaultTo */ } +static WSDXML_ELEMENT *create_soap_header_xml_elements(IWSDXMLContext *xml_context, WSD_SOAP_HEADER *header) +{ + /* TODO: Implement header generation */ + return NULL; +} + +static HRESULT create_soap_envelope(IWSDXMLContext *xml_context, WSD_SOAP_HEADER *header, WSDXML_ELEMENT *body_element, + WS_HEAP **heap, char **output_xml, ULONG *xml_length, struct list *discovered_namespaces) +{ + WS_XML_STRING *actual_envelope_prefix = NULL, *envelope_uri_xmlstr = NULL; + WSDXML_NAMESPACE *addressing_ns = NULL, *discovery_ns = NULL, *envelope_ns = NULL; + WSDXML_ELEMENT *header_element = NULL; + WS_XML_BUFFER *buffer = NULL; + WS_XML_WRITER *writer = NULL; + WS_XML_STRING envelope; + HRESULT ret = E_OUTOFMEMORY; + static BYTE envelopeString[] = "Envelope"; + + /* Create the necessary XML prefixes */ + if (FAILED(IWSDXMLContext_AddNamespace(xml_context, addressingNsUri, addressingPrefix, &addressing_ns))) goto cleanup; + + if (FAILED(IWSDXMLContext_AddNamespace(xml_context, discoveryNsUri, discoveryPrefix, &discovery_ns))) goto cleanup; + + if (FAILED(IWSDXMLContext_AddNamespace(xml_context, envelopeNsUri, envelopePrefix, &envelope_ns))) goto cleanup; + + envelope.bytes = envelopeString; + envelope.length = sizeof(envelopeString) - 1; + envelope.dictionary = NULL; + envelope.id = 0; + + actual_envelope_prefix = populate_xml_string(envelope_ns->PreferredPrefix); + envelope_uri_xmlstr = populate_xml_string(envelope_ns->Uri); + + if ((actual_envelope_prefix == NULL) || (envelope_uri_xmlstr == NULL)) goto cleanup; + + /* Now try to create the appropriate WebServices buffers, etc */ + ret = WsCreateHeap(16384, 4096, NULL, 0, heap, NULL); + if (FAILED(ret)) goto cleanup; + + ret = WsCreateXmlBuffer(*heap, NULL, 0, &buffer, NULL); + if (FAILED(ret)) goto cleanup; + + ret = WsCreateWriter(NULL, 0, &writer, NULL); + if (FAILED(ret)) goto cleanup; + + ret = WsSetOutputToBuffer(writer, buffer, NULL, 0, NULL); + if (FAILED(ret)) goto cleanup; + + /* Create the header XML elements */ + header_element = create_soap_header_xml_elements(xml_context, header); + if (header_element == NULL) goto cleanup; + + /* */ + ret = WsWriteStartElement(writer, actual_envelope_prefix, &envelope, envelope_uri_xmlstr, NULL); + if (FAILED(ret)) goto cleanup; + + /* TODO: Write the header */ + + ret = WsWriteEndElement(writer, NULL); + if (FAILED(ret)) goto cleanup; + + /* */ + + /* Generate the bytes of the document */ + ret = WsWriteXmlBufferToBytes(writer, buffer, NULL, NULL, 0, *heap, (void**)output_xml, xml_length, NULL); + if (FAILED(ret)) goto cleanup; + +cleanup: + WSDFreeLinkedMemory(addressing_ns); + WSDFreeLinkedMemory(discovery_ns); + WSDFreeLinkedMemory(envelope_ns); + + WSDXMLCleanupElement(header_element); + + free_xml_string(actual_envelope_prefix); + free_xml_string(envelope_uri_xmlstr); + + if (writer != NULL) + WsFreeWriter(writer); + + /* Don't free the heap unless the operation has failed */ + if ((FAILED(ret)) && (*heap != NULL)) + { + WsFreeHeap(*heap); + *heap = NULL; + } + + return ret; +} + static HRESULT write_and_send_message(IWSDiscoveryPublisherImpl *impl, WSD_SOAP_HEADER *header, WSDXML_ELEMENT *body_element, struct list *discovered_namespaces, IWSDUdpAddress *remote_address, int max_initial_delay) { static const char xml_header[] = ""; - ULONG xml_header_len = sizeof(xml_header) - 1; - HRESULT ret = E_FAIL; + ULONG xml_length = 0, xml_header_len = sizeof(xml_header) - 1; + WS_HEAP *heap = NULL; + char *xml = NULL; char *full_xml; + HRESULT ret; - /* TODO: Create SOAP envelope */ + ret = create_soap_envelope(impl->xmlContext, header, NULL, &heap, &xml, &xml_length, NULL); + if (ret != S_OK) return ret; /* Prefix the XML header */ - full_xml = heap_alloc(xml_header_len + 1); + full_xml = heap_alloc(xml_length + xml_header_len + 1); if (full_xml == NULL) + { + WsFreeHeap(heap); return E_OUTOFMEMORY; + } memcpy(full_xml, xml_header, xml_header_len); - full_xml[xml_header_len] = 0; + memcpy(full_xml + xml_header_len, xml, xml_length); + full_xml[xml_length + xml_header_len] = 0; if (remote_address == NULL) { /* Send the message via UDP multicast */ - if (send_udp_multicast(impl, full_xml, sizeof(xml_header), max_initial_delay)) - ret = S_OK; + ret = send_udp_multicast(impl, full_xml, xml_length + xml_header_len + 1, max_initial_delay) ? S_OK : E_FAIL; } else { @@ -111,6 +279,7 @@ static HRESULT write_and_send_message(IWSDiscoveryPublisherImpl *impl, WSD_SOAP_ } heap_free(full_xml); + WsFreeHeap(heap); return ret; } -- 2.11.4.GIT