2 * Web Services on Devices
4 * Copyright 2017-2018 Owen Rudge for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wsdapi_internal.h"
27 #include "wine/debug.h"
28 #include "webservices.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
32 #define APP_MAX_DELAY 500
34 static const WCHAR
*discoveryTo
= L
"urn:schemas-xmlsoap-org:ws:2005:04:discovery";
36 static const WCHAR
*actionProbe
= L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
38 static const WCHAR
*addressingNsUri
= L
"http://schemas.xmlsoap.org/ws/2004/08/addressing";
39 static const WCHAR
*discoveryNsUri
= L
"http://schemas.xmlsoap.org/ws/2005/04/discovery";
40 static const WCHAR
*envelopeNsUri
= L
"http://www.w3.org/2003/05/soap-envelope";
42 static const WCHAR
*addressingPrefix
= L
"wsa";
43 static const WCHAR
*discoveryPrefix
= L
"wsd";
44 static const WCHAR
*envelopePrefix
= L
"soap";
45 static const WCHAR
*headerString
= L
"Header";
46 static const WCHAR
*actionString
= L
"Action";
47 static const WCHAR
*messageIdString
= L
"MessageID";
48 static const WCHAR
*toString
= L
"To";
49 static const WCHAR
*relatesToString
= L
"RelatesTo";
50 static const WCHAR
*appSequenceString
= L
"AppSequence";
51 static const WCHAR
*instanceIdString
= L
"InstanceId";
52 static const WCHAR
*messageNumberString
= L
"MessageNumber";
53 static const WCHAR
*sequenceIdString
= L
"SequenceId";
54 static const WCHAR
*bodyString
= L
"Body";
55 static const WCHAR
*helloString
= L
"Hello";
56 static const WCHAR
*probeString
= L
"Probe";
57 static const WCHAR
*probeMatchString
= L
"ProbeMatch";
58 static const WCHAR
*probeMatchesString
= L
"ProbeMatches";
59 static const WCHAR
*byeString
= L
"Bye";
60 static const WCHAR
*endpointReferenceString
= L
"EndpointReference";
61 static const WCHAR
*addressString
= L
"Address";
62 static const WCHAR
*referenceParametersString
= L
"ReferenceParameters";
63 static const WCHAR
*typesString
= L
"Types";
64 static const WCHAR
*scopesString
= L
"Scopes";
65 static const WCHAR
*xAddrsString
= L
"XAddrs";
66 static const WCHAR
*metadataVersionString
= L
"MetadataVersion";
68 struct discovered_namespace
75 static LPWSTR
utf8_to_wide(void *parent
, const char *utf8_str
, int length
)
77 int utf8_str_len
= 0, chars_needed
= 0, bytes_needed
= 0;
78 LPWSTR new_str
= NULL
;
80 if (utf8_str
== NULL
) return NULL
;
82 utf8_str_len
= (length
< 0) ? lstrlenA(utf8_str
) : length
;
83 chars_needed
= MultiByteToWideChar(CP_UTF8
, 0, utf8_str
, utf8_str_len
, NULL
, 0);
85 if (chars_needed
<= 0) return NULL
;
87 bytes_needed
= sizeof(WCHAR
) * (chars_needed
+ 1);
88 new_str
= WSDAllocateLinkedMemory(parent
, bytes_needed
);
90 MultiByteToWideChar(CP_UTF8
, 0, utf8_str
, utf8_str_len
, new_str
, chars_needed
);
91 new_str
[chars_needed
] = 0;
96 static char *wide_to_utf8(LPCWSTR wide_string
, int *length
)
98 char *new_string
= NULL
;
100 if (wide_string
== NULL
)
103 *length
= WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, NULL
, 0, NULL
, NULL
);
108 new_string
= malloc(*length
);
109 WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, new_string
, *length
, NULL
, NULL
);
114 static WS_XML_STRING
*populate_xml_string(LPCWSTR str
)
116 WS_XML_STRING
*xml
= calloc(1, sizeof(*xml
));
122 xml
->bytes
= (BYTE
*)wide_to_utf8(str
, &utf8Length
);
124 if (xml
->bytes
== NULL
)
130 xml
->dictionary
= NULL
;
132 xml
->length
= (xml
->bytes
== NULL
) ? 0 : (utf8Length
- 1);
137 static inline void free_xml_string(WS_XML_STRING
*value
)
147 static HRESULT
write_xml_attribute(WSDXML_ATTRIBUTE
*attribute
, WS_XML_WRITER
*writer
)
149 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
150 WS_XML_UTF16_TEXT utf16_text
;
151 HRESULT ret
= E_OUTOFMEMORY
;
154 if (attribute
== NULL
)
157 /* Start the attribute */
158 local_name
= populate_xml_string(attribute
->Name
->LocalName
);
159 if (local_name
== NULL
) goto cleanup
;
161 if (attribute
->Name
->Space
== NULL
)
163 element_ns
= populate_xml_string(L
"");
164 if (element_ns
== NULL
) goto cleanup
;
170 element_ns
= populate_xml_string(attribute
->Name
->Space
->Uri
);
171 if (element_ns
== NULL
) goto cleanup
;
173 ns_prefix
= populate_xml_string(attribute
->Name
->Space
->PreferredPrefix
);
174 if (ns_prefix
== NULL
) goto cleanup
;
177 ret
= WsWriteStartAttribute(writer
, ns_prefix
, local_name
, element_ns
, FALSE
, NULL
);
178 if (FAILED(ret
)) goto cleanup
;
180 text_len
= lstrlenW(attribute
->Value
);
182 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
183 utf16_text
.bytes
= (BYTE
*)attribute
->Value
;
184 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
186 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
187 if (FAILED(ret
)) goto cleanup
;
189 ret
= WsWriteEndAttribute(writer
, NULL
);
190 if (FAILED(ret
)) goto cleanup
;
193 free_xml_string(local_name
);
194 free_xml_string(element_ns
);
195 free_xml_string(ns_prefix
);
200 static HRESULT
write_xml_element(WSDXML_ELEMENT
*element
, WS_XML_WRITER
*writer
)
202 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
203 WSDXML_ATTRIBUTE
*current_attribute
;
204 WS_XML_UTF16_TEXT utf16_text
;
205 WSDXML_NODE
*current_child
;
206 WSDXML_TEXT
*node_as_text
;
208 HRESULT ret
= E_OUTOFMEMORY
;
213 /* Start the element */
214 local_name
= populate_xml_string(element
->Name
->LocalName
);
215 if (local_name
== NULL
) goto cleanup
;
217 element_ns
= populate_xml_string(element
->Name
->Space
->Uri
);
218 if (element_ns
== NULL
) goto cleanup
;
220 ns_prefix
= populate_xml_string(element
->Name
->Space
->PreferredPrefix
);
221 if (ns_prefix
== NULL
) goto cleanup
;
223 ret
= WsWriteStartElement(writer
, ns_prefix
, local_name
, element_ns
, NULL
);
224 if (FAILED(ret
)) goto cleanup
;
226 /* Write attributes */
227 current_attribute
= element
->FirstAttribute
;
229 while (current_attribute
!= NULL
)
231 ret
= write_xml_attribute(current_attribute
, writer
);
232 if (FAILED(ret
)) goto cleanup
;
233 current_attribute
= current_attribute
->Next
;
236 /* Write child elements */
237 current_child
= element
->FirstChild
;
239 while (current_child
!= NULL
)
241 if (current_child
->Type
== ElementType
)
243 ret
= write_xml_element((WSDXML_ELEMENT
*)current_child
, writer
);
244 if (FAILED(ret
)) goto cleanup
;
246 else if (current_child
->Type
== TextType
)
248 node_as_text
= (WSDXML_TEXT
*)current_child
;
249 text_len
= lstrlenW(node_as_text
->Text
);
251 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
252 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
253 utf16_text
.bytes
= (BYTE
*)node_as_text
->Text
;
255 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
256 if (FAILED(ret
)) goto cleanup
;
259 current_child
= current_child
->Next
;
262 /* End the element */
263 ret
= WsWriteEndElement(writer
, NULL
);
266 free_xml_string(local_name
);
267 free_xml_string(element_ns
);
268 free_xml_string(ns_prefix
);
273 static HRESULT
add_child_element(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
,
274 LPCWSTR name
, LPCWSTR text
, WSDXML_ELEMENT
**out
)
276 WSDXML_ELEMENT
*element_obj
;
277 WSDXML_NAME
*name_obj
;
280 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
);
281 if (FAILED(ret
)) return ret
;
283 ret
= WSDXMLBuildAnyForSingleElement(name_obj
, text
, &element_obj
);
284 WSDFreeLinkedMemory(name_obj
);
286 if (FAILED(ret
)) return ret
;
288 /* Add the element as a child - this will link the element's memory allocation to the parent's */
289 ret
= WSDXMLAddChild(parent
, element_obj
);
293 WSDFreeLinkedMemory(element_obj
);
297 if (out
!= NULL
) *out
= element_obj
;
301 HRESULT
register_namespaces(IWSDXMLContext
*xml_context
)
305 ret
= IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, NULL
);
306 if (FAILED(ret
)) return ret
;
308 ret
= IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, NULL
);
309 if (FAILED(ret
)) return ret
;
311 return IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, NULL
);
314 static BOOL
create_guid(LPWSTR buffer
)
316 WCHAR
* uuidString
= NULL
;
319 if (UuidCreate(&uuid
) != RPC_S_OK
)
322 UuidToStringW(&uuid
, (RPC_WSTR
*)&uuidString
);
324 if (uuidString
== NULL
)
327 wsprintfW(buffer
, L
"urn:uuid:%s", uuidString
);
328 RpcStringFreeW((RPC_WSTR
*)&uuidString
);
333 static void populate_soap_header(WSD_SOAP_HEADER
*header
, LPCWSTR to
, LPCWSTR action
, LPCWSTR message_id
,
334 WSD_APP_SEQUENCE
*sequence
, const WSDXML_ELEMENT
*any_headers
)
336 ZeroMemory(header
, sizeof(WSD_SOAP_HEADER
));
339 header
->Action
= action
;
340 header
->MessageID
= message_id
;
341 header
->AppSequence
= sequence
;
342 header
->AnyHeaders
= (WSDXML_ELEMENT
*)any_headers
;
344 /* TODO: Implement RelatesTo, ReplyTo, From, FaultTo */
347 #define MAX_ULONGLONG_STRING_SIZE 25
349 static LPWSTR
ulonglong_to_string(void *parent
, ULONGLONG value
)
353 ret
= WSDAllocateLinkedMemory(parent
, MAX_ULONGLONG_STRING_SIZE
* sizeof(WCHAR
));
358 wsprintfW(ret
, L
"%I64u", value
);
362 static WSDXML_ATTRIBUTE
*add_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
)
364 WSDXML_ATTRIBUTE
*attribute
, *cur_attrib
;
365 WSDXML_NAME
*name_obj
= NULL
;
369 name_obj
= WSDAllocateLinkedMemory(NULL
, sizeof(WSDXML_NAME
));
370 name_obj
->LocalName
= duplicate_string(name_obj
, name
);
371 name_obj
->Space
= NULL
;
375 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
)))
379 attribute
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_ATTRIBUTE
));
381 if (attribute
== NULL
)
383 WSDFreeLinkedMemory(name_obj
);
387 attribute
->Element
= parent
;
388 attribute
->Name
= name_obj
;
389 attribute
->Next
= NULL
;
390 attribute
->Value
= NULL
;
392 if (name_obj
!= NULL
)
393 WSDAttachLinkedMemory(attribute
, name_obj
);
395 if (parent
->FirstAttribute
== NULL
)
397 /* Make this the first attribute of the parent */
398 parent
->FirstAttribute
= attribute
;
402 /* Find the last attribute and add this as the next one */
403 cur_attrib
= parent
->FirstAttribute
;
405 while (cur_attrib
->Next
!= NULL
)
407 cur_attrib
= cur_attrib
->Next
;
410 cur_attrib
->Next
= attribute
;
416 static void remove_attribute(WSDXML_ELEMENT
*parent
, WSDXML_ATTRIBUTE
*attribute
)
418 WSDXML_ATTRIBUTE
*cur_attrib
;
420 /* Find the last attribute and add this as the next one */
421 cur_attrib
= parent
->FirstAttribute
;
423 if (cur_attrib
== attribute
)
424 parent
->FirstAttribute
= cur_attrib
->Next
;
427 while (cur_attrib
!= NULL
)
429 /* Is our attribute the next attribute? */
430 if (cur_attrib
->Next
== attribute
)
432 /* Remove it from the list */
433 cur_attrib
->Next
= attribute
->Next
;
437 cur_attrib
= cur_attrib
->Next
;
441 WSDFreeLinkedMemory(attribute
);
444 static HRESULT
add_ulonglong_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
447 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
449 if (attribute
== NULL
)
452 attribute
->Value
= ulonglong_to_string(attribute
, value
);
454 if (attribute
->Value
== NULL
)
456 remove_attribute(parent
, attribute
);
463 static HRESULT
add_string_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
466 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
468 if (attribute
== NULL
)
471 attribute
->Value
= duplicate_string(attribute
, value
);
473 if (attribute
->Value
== NULL
)
475 remove_attribute(parent
, attribute
);
482 static BOOL
add_discovered_namespace(struct list
*namespaces
, WSDXML_NAMESPACE
*discovered_ns
)
484 struct discovered_namespace
*ns
;
486 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct discovered_namespace
, entry
)
488 if (lstrcmpW(ns
->uri
, discovered_ns
->Uri
) == 0)
489 return TRUE
; /* Already added */
492 ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct discovered_namespace
));
497 ns
->prefix
= duplicate_string(ns
, discovered_ns
->PreferredPrefix
);
498 ns
->uri
= duplicate_string(ns
, discovered_ns
->Uri
);
500 if ((ns
->prefix
== NULL
) || (ns
->uri
== NULL
))
503 list_add_tail(namespaces
, &ns
->entry
);
507 static HRESULT
build_types_list(LPWSTR buffer
, size_t buffer_size
, const WSD_NAME_LIST
*list
, struct list
*namespaces
)
509 LPWSTR current_buf_pos
= buffer
;
510 size_t memory_needed
= 0;
511 const WSD_NAME_LIST
*cur
= list
;
515 /* Calculate space needed, including NULL character, colon and potential trailing space */
516 memory_needed
= sizeof(WCHAR
) * (lstrlenW(cur
->Element
->LocalName
) +
517 lstrlenW(cur
->Element
->Space
->PreferredPrefix
) + 3);
519 if (current_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
523 *current_buf_pos
++ = ' ';
525 current_buf_pos
+= wsprintfW(current_buf_pos
, L
"%s:%s", cur
->Element
->Space
->PreferredPrefix
,
526 cur
->Element
->LocalName
);
528 /* Record the namespace in the discovered namespaces list */
529 if (!add_discovered_namespace(namespaces
, cur
->Element
->Space
))
533 } while (cur
!= NULL
);
538 static HRESULT
build_uri_list(LPWSTR buffer
, size_t buffer_size
, const WSD_URI_LIST
*list
)
540 size_t memory_needed
= 0, string_len
= 0;
541 const WSD_URI_LIST
*cur
= list
;
542 LPWSTR cur_buf_pos
= buffer
;
546 /* Calculate space needed, including trailing space */
547 string_len
= lstrlenW(cur
->Element
);
548 memory_needed
= (string_len
+ 1) * sizeof(WCHAR
);
550 if (cur_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
554 *cur_buf_pos
++ = ' ';
556 memcpy(cur_buf_pos
, cur
->Element
, memory_needed
);
557 cur_buf_pos
+= string_len
;
560 } while (cur
!= NULL
);
565 static HRESULT
duplicate_element(WSDXML_ELEMENT
*parent
, const WSDXML_ELEMENT
*node
, struct list
*namespaces
)
567 WSDXML_ATTRIBUTE
*cur_attribute
, *new_attribute
, *last_attribute
= NULL
;
568 WSDXML_ELEMENT
*new_element
;
569 WSDXML_TEXT
*text_node
;
570 WSDXML_NODE
*cur_node
;
573 /* First record the namespace in the discovered namespaces list */
574 if (!add_discovered_namespace(namespaces
, node
->Name
->Space
))
577 ret
= WSDXMLBuildAnyForSingleElement(node
->Name
, NULL
, &new_element
);
578 if (FAILED(ret
)) return ret
;
580 /* Duplicate the nodes */
581 cur_node
= node
->FirstChild
;
583 while (cur_node
!= NULL
)
585 if (cur_node
->Type
== ElementType
)
587 ret
= duplicate_element(new_element
, (WSDXML_ELEMENT
*)cur_node
, namespaces
);
588 if (FAILED(ret
)) goto cleanup
;
590 else if (cur_node
->Type
== TextType
)
592 text_node
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_TEXT
));
593 if (text_node
== NULL
) goto failed
;
595 text_node
->Node
.Parent
= NULL
;
596 text_node
->Node
.Next
= NULL
;
597 text_node
->Node
.Type
= TextType
;
598 text_node
->Text
= duplicate_string(text_node
, ((WSDXML_TEXT
*)cur_node
)->Text
);
600 if (text_node
->Text
== NULL
) goto failed
;
602 ret
= WSDXMLAddChild(new_element
, (WSDXML_ELEMENT
*)text_node
);
603 if (FAILED(ret
)) goto cleanup
;
606 cur_node
= cur_node
->Next
;
609 /* Duplicate the attributes */
610 cur_attribute
= node
->FirstAttribute
;
612 while (cur_attribute
!= NULL
)
614 if ((cur_attribute
->Name
->Space
!= NULL
) && (!add_discovered_namespace(namespaces
, cur_attribute
->Name
->Space
)))
617 new_attribute
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_ATTRIBUTE
));
618 if (new_attribute
== NULL
) goto failed
;
620 new_attribute
->Element
= new_element
;
621 new_attribute
->Name
= duplicate_name(new_attribute
, cur_attribute
->Name
);
622 new_attribute
->Value
= duplicate_string(new_attribute
, cur_attribute
->Value
);
623 new_attribute
->Next
= NULL
;
625 if ((new_attribute
->Name
== NULL
) || (new_attribute
->Value
== NULL
)) goto failed
;
627 if (last_attribute
== NULL
)
628 new_element
->FirstAttribute
= new_attribute
;
630 last_attribute
->Next
= new_attribute
;
632 last_attribute
= new_attribute
;
633 cur_attribute
= cur_attribute
->Next
;
636 ret
= WSDXMLAddChild(parent
, new_element
);
637 if (FAILED(ret
)) goto cleanup
;
645 WSDXMLCleanupElement(new_element
);
649 static HRESULT
create_soap_header_xml_elements(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
,
650 struct list
*discovered_namespaces
, WSDXML_ELEMENT
**out_element
)
652 WSDXML_ELEMENT
*header_element
= NULL
, *app_sequence_element
= NULL
, *temp_element
;
653 WSDXML_NAME
*header_name
= NULL
;
657 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, envelopeNsUri
, headerString
, &header_name
);
658 if (FAILED(ret
)) goto cleanup
;
660 ret
= WSDXMLBuildAnyForSingleElement(header_name
, NULL
, &header_element
);
661 if (FAILED(ret
)) goto cleanup
;
663 WSDFreeLinkedMemory(header_name
);
666 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, actionString
, header
->Action
, &temp_element
);
667 if (FAILED(ret
)) goto cleanup
;
670 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, messageIdString
, header
->MessageID
, &temp_element
);
671 if (FAILED(ret
)) goto cleanup
;
674 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, toString
, header
->To
, &temp_element
);
675 if (FAILED(ret
)) goto cleanup
;
678 if (header
->RelatesTo
.MessageID
!= NULL
)
680 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, relatesToString
,
681 header
->RelatesTo
.MessageID
, &temp_element
);
682 if (FAILED(ret
)) goto cleanup
;
685 /* <d:AppSequence> */
686 ret
= add_child_element(xml_context
, header_element
, discoveryNsUri
, appSequenceString
, L
"", &app_sequence_element
);
687 if (FAILED(ret
)) goto cleanup
;
689 /* InstanceId attribute */
690 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, instanceIdString
, min(UINT_MAX
,
691 header
->AppSequence
->InstanceId
));
692 if (FAILED(ret
)) goto cleanup
;
694 /* SequenceID attribute */
695 if (header
->AppSequence
->SequenceId
!= NULL
)
697 ret
= add_string_attribute(xml_context
, app_sequence_element
, NULL
, sequenceIdString
, header
->AppSequence
->SequenceId
);
698 if (FAILED(ret
)) goto cleanup
;
701 /* MessageNumber attribute */
702 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, messageNumberString
, min(UINT_MAX
,
703 header
->AppSequence
->MessageNumber
));
704 if (FAILED(ret
)) goto cleanup
;
706 /* </d:AppSequence> */
708 /* Write any headers */
709 if (header
->AnyHeaders
!= NULL
)
711 ret
= duplicate_element(header_element
, header
->AnyHeaders
, discovered_namespaces
);
712 if (FAILED(ret
)) goto cleanup
;
717 *out_element
= header_element
;
721 if (header_name
!= NULL
) WSDFreeLinkedMemory(header_name
);
722 WSDXMLCleanupElement(header_element
);
727 static HRESULT
create_soap_envelope(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
728 WS_HEAP
**heap
, char **output_xml
, ULONG
*xml_length
, struct list
*discovered_namespaces
)
730 WS_XML_STRING
*actual_envelope_prefix
= NULL
, *envelope_uri_xmlstr
= NULL
, *tmp_prefix
= NULL
, *tmp_uri
= NULL
;
731 WSDXML_NAMESPACE
*addressing_ns
= NULL
, *discovery_ns
= NULL
, *envelope_ns
= NULL
;
732 WSDXML_ELEMENT
*header_element
= NULL
;
733 struct discovered_namespace
*ns
;
734 WS_XML_BUFFER
*buffer
= NULL
;
735 WS_XML_WRITER
*writer
= NULL
;
736 WS_XML_STRING envelope
;
737 HRESULT ret
= E_OUTOFMEMORY
;
738 static BYTE envelopeString
[] = "Envelope";
740 /* Create the necessary XML prefixes */
741 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, &addressing_ns
))) goto cleanup
;
742 if (!add_discovered_namespace(discovered_namespaces
, addressing_ns
)) goto cleanup
;
744 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, &discovery_ns
))) goto cleanup
;
745 if (!add_discovered_namespace(discovered_namespaces
, discovery_ns
)) goto cleanup
;
747 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, &envelope_ns
))) goto cleanup
;
748 if (!add_discovered_namespace(discovered_namespaces
, envelope_ns
)) goto cleanup
;
750 envelope
.bytes
= envelopeString
;
751 envelope
.length
= sizeof(envelopeString
) - 1;
752 envelope
.dictionary
= NULL
;
755 actual_envelope_prefix
= populate_xml_string(envelope_ns
->PreferredPrefix
);
756 envelope_uri_xmlstr
= populate_xml_string(envelope_ns
->Uri
);
758 if ((actual_envelope_prefix
== NULL
) || (envelope_uri_xmlstr
== NULL
)) goto cleanup
;
760 /* Now try to create the appropriate WebServices buffers, etc */
761 ret
= WsCreateHeap(16384, 4096, NULL
, 0, heap
, NULL
);
762 if (FAILED(ret
)) goto cleanup
;
764 ret
= WsCreateXmlBuffer(*heap
, NULL
, 0, &buffer
, NULL
);
765 if (FAILED(ret
)) goto cleanup
;
767 ret
= WsCreateWriter(NULL
, 0, &writer
, NULL
);
768 if (FAILED(ret
)) goto cleanup
;
770 ret
= WsSetOutputToBuffer(writer
, buffer
, NULL
, 0, NULL
);
771 if (FAILED(ret
)) goto cleanup
;
773 /* Create the header XML elements */
774 ret
= create_soap_header_xml_elements(xml_context
, header
, discovered_namespaces
, &header_element
);
775 if (FAILED(ret
)) goto cleanup
;
778 ret
= WsWriteStartElement(writer
, actual_envelope_prefix
, &envelope
, envelope_uri_xmlstr
, NULL
);
779 if (FAILED(ret
)) goto cleanup
;
781 LIST_FOR_EACH_ENTRY(ns
, discovered_namespaces
, struct discovered_namespace
, entry
)
783 tmp_prefix
= populate_xml_string(ns
->prefix
);
784 tmp_uri
= populate_xml_string(ns
->uri
);
786 if ((tmp_prefix
== NULL
) || (tmp_uri
== NULL
)) goto cleanup
;
788 ret
= WsWriteXmlnsAttribute(writer
, tmp_prefix
, tmp_uri
, FALSE
, NULL
);
789 if (FAILED(ret
)) goto cleanup
;
791 free_xml_string(tmp_prefix
);
792 free_xml_string(tmp_uri
);
798 /* Write the header */
799 ret
= write_xml_element(header_element
, writer
);
800 if (FAILED(ret
)) goto cleanup
;
803 ret
= write_xml_element(body_element
, writer
);
804 if (FAILED(ret
)) goto cleanup
;
806 ret
= WsWriteEndElement(writer
, NULL
);
807 if (FAILED(ret
)) goto cleanup
;
811 /* Generate the bytes of the document */
812 ret
= WsWriteXmlBufferToBytes(writer
, buffer
, NULL
, NULL
, 0, *heap
, (void**)output_xml
, xml_length
, NULL
);
813 if (FAILED(ret
)) goto cleanup
;
816 WSDFreeLinkedMemory(addressing_ns
);
817 WSDFreeLinkedMemory(discovery_ns
);
818 WSDFreeLinkedMemory(envelope_ns
);
820 WSDXMLCleanupElement(header_element
);
822 free_xml_string(actual_envelope_prefix
);
823 free_xml_string(envelope_uri_xmlstr
);
826 WsFreeWriter(writer
);
828 /* Don't free the heap unless the operation has failed */
829 if ((FAILED(ret
)) && (*heap
!= NULL
))
838 static HRESULT
write_and_send_message(IWSDiscoveryPublisherImpl
*impl
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
839 struct list
*discovered_namespaces
, IWSDUdpAddress
*remote_address
, int max_initial_delay
)
841 static const char xml_header
[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
842 ULONG xml_length
= 0, xml_header_len
= sizeof(xml_header
) - 1;
843 WS_HEAP
*heap
= NULL
;
848 ret
= create_soap_envelope(impl
->xmlContext
, header
, body_element
, &heap
, &xml
, &xml_length
, discovered_namespaces
);
849 if (ret
!= S_OK
) return ret
;
851 /* Prefix the XML header */
852 full_xml
= malloc(xml_length
+ xml_header_len
+ 1);
854 if (full_xml
== NULL
)
857 return E_OUTOFMEMORY
;
860 memcpy(full_xml
, xml_header
, xml_header_len
);
861 memcpy(full_xml
+ xml_header_len
, xml
, xml_length
);
862 full_xml
[xml_length
+ xml_header_len
] = 0;
864 if (remote_address
== NULL
)
866 /* Send the message via UDP multicast */
867 ret
= send_udp_multicast(impl
, full_xml
, xml_length
+ xml_header_len
, max_initial_delay
) ? S_OK
: E_FAIL
;
871 /* Send the message via UDP unicast */
872 ret
= send_udp_unicast(full_xml
, xml_length
+ xml_header_len
, remote_address
, max_initial_delay
);
881 HRESULT
send_hello_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
882 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
883 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*hdr_any
, const WSDXML_ELEMENT
*ref_param_any
,
884 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
886 WSDXML_ELEMENT
*body_element
= NULL
, *hello_element
, *endpoint_reference_element
, *ref_params_element
;
887 struct list
*discoveredNamespaces
= NULL
;
888 WSDXML_NAME
*body_name
= NULL
;
889 WSD_SOAP_HEADER soapHeader
;
890 WSD_APP_SEQUENCE sequence
;
891 WCHAR message_id
[64];
892 HRESULT ret
= E_OUTOFMEMORY
;
895 sequence
.InstanceId
= instance_id
;
896 sequence
.MessageNumber
= msg_num
;
897 sequence
.SequenceId
= session_id
;
899 if (!create_guid(message_id
)) goto failed
;
901 discoveredNamespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
902 if (!discoveredNamespaces
) goto failed
;
904 list_init(discoveredNamespaces
);
906 populate_soap_header(&soapHeader
, discoveryTo
, L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/Hello", message_id
, &sequence
, hdr_any
);
908 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
909 if (FAILED(ret
)) goto cleanup
;
911 /* <soap:Body>, <wsd:Hello> */
912 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
913 if (FAILED(ret
)) goto cleanup
;
915 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, helloString
, NULL
, &hello_element
);
916 if (FAILED(ret
)) goto cleanup
;
918 /* <wsa:EndpointReference>, <wsa:Address> */
919 ret
= add_child_element(impl
->xmlContext
, hello_element
, addressingNsUri
, endpointReferenceString
, NULL
,
920 &endpoint_reference_element
);
921 if (FAILED(ret
)) goto cleanup
;
923 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, addressString
, id
, NULL
);
924 if (FAILED(ret
)) goto cleanup
;
926 /* Write any reference parameters */
927 if (ref_param_any
!= NULL
)
929 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, referenceParametersString
,
930 NULL
, &ref_params_element
);
931 if (FAILED(ret
)) goto cleanup
;
933 ret
= duplicate_element(ref_params_element
, ref_param_any
, discoveredNamespaces
);
934 if (FAILED(ret
)) goto cleanup
;
937 /* Write any endpoint reference headers */
938 if (endpoint_ref_any
!= NULL
)
940 ret
= duplicate_element(endpoint_reference_element
, endpoint_ref_any
, discoveredNamespaces
);
941 if (FAILED(ret
)) goto cleanup
;
945 if (types_list
!= NULL
)
947 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
948 if (buffer
== NULL
) goto failed
;
950 ret
= build_types_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), types_list
, discoveredNamespaces
);
951 if (FAILED(ret
)) goto cleanup
;
953 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, typesString
, buffer
, NULL
);
954 if (FAILED(ret
)) goto cleanup
;
958 if (scopes_list
!= NULL
)
960 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
961 if (buffer
== NULL
) goto failed
;
963 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), scopes_list
);
964 if (FAILED(ret
)) goto cleanup
;
966 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, scopesString
, buffer
, NULL
);
967 if (FAILED(ret
)) goto cleanup
;
971 if (xaddrs_list
!= NULL
)
973 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
974 if (buffer
== NULL
) goto failed
;
976 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), xaddrs_list
);
977 if (FAILED(ret
)) goto cleanup
;
979 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, xAddrsString
, buffer
, NULL
);
980 if (FAILED(ret
)) goto cleanup
;
983 /* <wsd:MetadataVersion> */
984 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, metadataVersionString
,
985 ulonglong_to_string(hello_element
, min(UINT_MAX
, metadata_ver
)), NULL
);
987 if (FAILED(ret
)) goto cleanup
;
989 /* Write any body elements */
992 ret
= duplicate_element(hello_element
, any
, discoveredNamespaces
);
993 if (FAILED(ret
)) goto cleanup
;
996 /* Write and send the message */
997 ret
= write_and_send_message(impl
, &soapHeader
, body_element
, discoveredNamespaces
, NULL
, APP_MAX_DELAY
);
1001 ret
= E_OUTOFMEMORY
;
1004 WSDFreeLinkedMemory(body_name
);
1005 WSDFreeLinkedMemory(body_element
);
1006 WSDFreeLinkedMemory(discoveredNamespaces
);
1011 HRESULT
send_bye_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG instance_id
, ULONGLONG msg_num
,
1012 LPCWSTR session_id
, const WSDXML_ELEMENT
*any
)
1014 WSDXML_ELEMENT
*body_element
= NULL
, *bye_element
, *endpoint_reference_element
;
1015 struct list
*discovered_namespaces
= NULL
;
1016 WSDXML_NAME
*body_name
= NULL
;
1017 WSD_SOAP_HEADER soap_header
;
1018 WSD_APP_SEQUENCE sequence
;
1019 WCHAR message_id
[64];
1020 HRESULT ret
= E_OUTOFMEMORY
;
1022 sequence
.InstanceId
= instance_id
;
1023 sequence
.MessageNumber
= msg_num
;
1024 sequence
.SequenceId
= session_id
;
1026 if (!create_guid(message_id
)) goto failed
;
1028 discovered_namespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
1029 if (!discovered_namespaces
) goto failed
;
1031 list_init(discovered_namespaces
);
1033 populate_soap_header(&soap_header
, discoveryTo
, L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/Bye", message_id
, &sequence
, NULL
);
1035 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
1036 if (FAILED(ret
)) goto cleanup
;
1038 /* <soap:Body>, <wsd:Bye> */
1039 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
1040 if (FAILED(ret
)) goto cleanup
;
1042 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, byeString
, NULL
, &bye_element
);
1043 if (FAILED(ret
)) goto cleanup
;
1045 /* <wsa:EndpointReference>, <wsa:Address> */
1046 ret
= add_child_element(impl
->xmlContext
, bye_element
, addressingNsUri
, endpointReferenceString
, NULL
,
1047 &endpoint_reference_element
);
1048 if (FAILED(ret
)) goto cleanup
;
1050 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, addressString
, id
, NULL
);
1051 if (FAILED(ret
)) goto cleanup
;
1053 /* Write any body elements */
1056 ret
= duplicate_element(bye_element
, any
, discovered_namespaces
);
1057 if (FAILED(ret
)) goto cleanup
;
1060 /* Write and send the message */
1061 ret
= write_and_send_message(impl
, &soap_header
, body_element
, discovered_namespaces
, NULL
, 0);
1065 ret
= E_OUTOFMEMORY
;
1068 WSDFreeLinkedMemory(body_name
);
1069 WSDFreeLinkedMemory(body_element
);
1070 WSDFreeLinkedMemory(discovered_namespaces
);
1075 HRESULT
send_probe_matches_message(IWSDiscoveryPublisherImpl
*impl
, const WSD_SOAP_MESSAGE
*probe_msg
,
1076 IWSDMessageParameters
*message_params
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
1077 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
1078 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*header_any
, const WSDXML_ELEMENT
*ref_param_any
,
1079 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
1081 WSDXML_ELEMENT
*body_element
= NULL
, *probe_matches_element
, *probe_match_element
, *endpoint_ref_element
;
1082 WSDXML_ELEMENT
*ref_params_element
= NULL
;
1083 struct list
*discovered_namespaces
= NULL
;
1084 IWSDUdpAddress
*remote_udp_addr
= NULL
;
1085 IWSDAddress
*remote_addr
= NULL
;
1086 WSDXML_NAME
*body_name
= NULL
;
1087 WSD_SOAP_HEADER soap_header
;
1088 WSD_APP_SEQUENCE sequence
;
1093 ret
= IWSDMessageParameters_GetRemoteAddress(message_params
, &remote_addr
);
1097 WARN("Unable to retrieve remote address from IWSDMessageParameters\n");
1101 ret
= IWSDAddress_QueryInterface(remote_addr
, &IID_IWSDUdpAddress
, (LPVOID
*) &remote_udp_addr
);
1105 WARN("Remote address is not a UDP address\n");
1109 sequence
.InstanceId
= instance_id
;
1110 sequence
.MessageNumber
= msg_num
;
1111 sequence
.SequenceId
= session_id
;
1113 if (!create_guid(msg_id
)) goto failed
;
1115 discovered_namespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
1116 if (!discovered_namespaces
) goto failed
;
1118 list_init(discovered_namespaces
);
1120 populate_soap_header(&soap_header
, L
"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous",
1121 L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches", msg_id
, &sequence
, header_any
);
1122 soap_header
.RelatesTo
.MessageID
= probe_msg
->Header
.MessageID
;
1124 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
1125 if (FAILED(ret
)) goto cleanup
;
1127 /* <soap:Body>, <wsd:ProbeMatches> */
1128 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
1129 if (FAILED(ret
)) goto cleanup
;
1131 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, probeMatchesString
, NULL
,
1132 &probe_matches_element
);
1133 if (FAILED(ret
)) goto cleanup
;
1135 /* <wsd:ProbeMatch> */
1136 ret
= add_child_element(impl
->xmlContext
, probe_matches_element
, discoveryNsUri
, probeMatchString
, NULL
,
1137 &probe_match_element
);
1138 if (FAILED(ret
)) goto cleanup
;
1140 /* <wsa:EndpointReference>, <wsa:Address> */
1141 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, addressingNsUri
, endpointReferenceString
, NULL
,
1142 &endpoint_ref_element
);
1143 if (FAILED(ret
)) goto cleanup
;
1145 ret
= add_child_element(impl
->xmlContext
, endpoint_ref_element
, addressingNsUri
, addressString
, id
, NULL
);
1146 if (FAILED(ret
)) goto cleanup
;
1148 /* Write any reference parameters */
1149 if (ref_param_any
!= NULL
)
1151 ret
= add_child_element(impl
->xmlContext
, endpoint_ref_element
, addressingNsUri
, referenceParametersString
,
1152 NULL
, &ref_params_element
);
1153 if (FAILED(ret
)) goto cleanup
;
1155 ret
= duplicate_element(ref_params_element
, ref_param_any
, discovered_namespaces
);
1156 if (FAILED(ret
)) goto cleanup
;
1159 /* Write any endpoint reference headers */
1160 if (endpoint_ref_any
!= NULL
)
1162 ret
= duplicate_element(endpoint_ref_element
, endpoint_ref_any
, discovered_namespaces
);
1163 if (FAILED(ret
)) goto cleanup
;
1167 if (types_list
!= NULL
)
1169 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1170 if (buffer
== NULL
) goto failed
;
1172 ret
= build_types_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), types_list
, discovered_namespaces
);
1173 if (FAILED(ret
)) goto cleanup
;
1175 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, typesString
, buffer
, NULL
);
1176 if (FAILED(ret
)) goto cleanup
;
1180 if (scopes_list
!= NULL
)
1182 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1183 if (buffer
== NULL
) goto failed
;
1185 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), scopes_list
);
1186 if (FAILED(ret
)) goto cleanup
;
1188 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, scopesString
, buffer
, NULL
);
1189 if (FAILED(ret
)) goto cleanup
;
1193 if (xaddrs_list
!= NULL
)
1195 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1196 if (buffer
== NULL
) goto failed
;
1198 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), xaddrs_list
);
1199 if (FAILED(ret
)) goto cleanup
;
1201 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, xAddrsString
, buffer
, NULL
);
1202 if (FAILED(ret
)) goto cleanup
;
1205 /* <wsd:MetadataVersion> */
1206 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, metadataVersionString
,
1207 ulonglong_to_string(probe_match_element
, min(UINT_MAX
, metadata_ver
)), NULL
);
1208 if (FAILED(ret
)) goto cleanup
;
1210 /* Write any body elements */
1213 ret
= duplicate_element(probe_match_element
, any
, discovered_namespaces
);
1214 if (FAILED(ret
)) goto cleanup
;
1217 /* Write and send the message */
1218 ret
= write_and_send_message(impl
, &soap_header
, body_element
, discovered_namespaces
, remote_udp_addr
, APP_MAX_DELAY
);
1225 WSDFreeLinkedMemory(body_name
);
1226 WSDFreeLinkedMemory(body_element
);
1227 WSDFreeLinkedMemory(discovered_namespaces
);
1229 if (remote_udp_addr
!= NULL
) IWSDUdpAddress_Release(remote_udp_addr
);
1230 if (remote_addr
!= NULL
) IWSDAddress_Release(remote_addr
);
1235 static LPWSTR
xml_text_to_wide_string(void *parent_memory
, WS_XML_TEXT
*text
)
1237 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
)
1239 WS_XML_UTF8_TEXT
*utf8_text
= (WS_XML_UTF8_TEXT
*) text
;
1240 return utf8_to_wide(parent_memory
, (const char *) utf8_text
->value
.bytes
, utf8_text
->value
.length
);
1242 else if (text
->textType
== WS_XML_TEXT_TYPE_UTF16
)
1244 WS_XML_UTF16_TEXT
*utf_16_text
= (WS_XML_UTF16_TEXT
*) text
;
1245 return duplicate_string(parent_memory
, (LPCWSTR
) utf_16_text
->bytes
);
1248 FIXME("Support for text type %d not implemented.\n", text
->textType
);
1252 static inline BOOL
read_isspace(unsigned int ch
)
1254 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
1257 static HRESULT
str_to_uint64(const unsigned char *str
, ULONG len
, UINT64 max
, UINT64
*ret
)
1259 const unsigned char *ptr
= str
;
1262 while (len
&& read_isspace(*ptr
)) { ptr
++; len
--; }
1263 while (len
&& read_isspace(ptr
[len
- 1])) { len
--; }
1264 if (!len
) return WS_E_INVALID_FORMAT
;
1270 if (!isdigit(*ptr
)) return WS_E_INVALID_FORMAT
;
1273 if ((*ret
> max
/ 10 || *ret
* 10 > max
- val
)) return WS_E_NUMERIC_OVERFLOW
;
1274 *ret
= *ret
* 10 + val
;
1281 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
1283 static HRESULT
wide_text_to_ulonglong(LPCWSTR text
, ULONGLONG
*value
)
1289 utf8_text
= wide_to_utf8(text
, &utf8_length
);
1291 if (utf8_text
== NULL
) return E_OUTOFMEMORY
;
1292 if (utf8_length
== 1) return E_FAIL
;
1294 ret
= str_to_uint64((const unsigned char *) utf8_text
, utf8_length
- 1, MAX_UINT64
, value
);
1300 static HRESULT
move_to_element(WS_XML_READER
*reader
, const char *element_name
, WS_XML_STRING
*uri
)
1302 WS_XML_STRING envelope
;
1306 envelope
.bytes
= (BYTE
*) element_name
;
1307 envelope
.length
= strlen(element_name
);
1308 envelope
.dictionary
= NULL
;
1311 ret
= WsReadToStartElement(reader
, &envelope
, uri
, &found
, NULL
);
1312 if (FAILED(ret
)) return ret
;
1314 return found
? ret
: E_FAIL
;
1317 static void trim_trailing_slash(LPWSTR uri
)
1319 /* Trim trailing slash from URI */
1320 int uri_len
= lstrlenW(uri
);
1321 if (uri_len
> 0 && uri
[uri_len
- 1] == '/') uri
[uri_len
- 1] = 0;
1324 static HRESULT
ws_element_to_wsdxml_element(WS_XML_READER
*reader
, IWSDXMLContext
*context
, WSDXML_ELEMENT
*parent_element
)
1326 WSDXML_ATTRIBUTE
*cur_wsd_attrib
= NULL
, *new_wsd_attrib
= NULL
;
1327 const WS_XML_ELEMENT_NODE
*element_node
= NULL
;
1328 WSDXML_ELEMENT
*cur_element
= parent_element
;
1329 const WS_XML_TEXT_NODE
*text_node
= NULL
;
1330 LPWSTR uri
= NULL
, element_name
= NULL
;
1331 WS_XML_STRING
*ns_string
= NULL
;
1332 WS_XML_ATTRIBUTE
*attrib
= NULL
;
1333 WSDXML_ELEMENT
*element
= NULL
;
1334 const WS_XML_NODE
*node
= NULL
;
1335 WSDXML_NAME
*name
= NULL
;
1336 WSDXML_TEXT
*text
= NULL
;
1342 if (cur_element
== NULL
) break;
1344 ret
= WsReadNode(reader
, NULL
);
1345 if (FAILED(ret
)) goto cleanup
;
1347 ret
= WsGetReaderNode(reader
, &node
, NULL
);
1348 if (FAILED(ret
)) goto cleanup
;
1350 switch (node
->nodeType
)
1352 case WS_XML_NODE_TYPE_ELEMENT
:
1353 element_node
= (const WS_XML_ELEMENT_NODE
*) node
;
1355 uri
= utf8_to_wide(NULL
, (const char *) element_node
->ns
->bytes
, element_node
->ns
->length
);
1356 if (uri
== NULL
) goto outofmemory
;
1358 /* Link element_name to uri so they will be freed at the same time */
1359 element_name
= utf8_to_wide(uri
, (const char *) element_node
->localName
->bytes
,
1360 element_node
->localName
->length
);
1361 if (element_name
== NULL
) goto outofmemory
;
1363 trim_trailing_slash(uri
);
1365 ret
= IWSDXMLContext_AddNameToNamespace(context
, uri
, element_name
, &name
);
1366 if (FAILED(ret
)) goto cleanup
;
1368 WSDFreeLinkedMemory(uri
);
1371 ret
= WSDXMLBuildAnyForSingleElement(name
, NULL
, &element
);
1372 if (FAILED(ret
)) goto cleanup
;
1373 WSDXMLAddChild(cur_element
, element
);
1375 WSDFreeLinkedMemory(name
);
1378 cur_wsd_attrib
= NULL
;
1380 /* Add attributes */
1381 for (i
= 0; i
< element_node
->attributeCount
; i
++)
1383 attrib
= element_node
->attributes
[i
];
1384 if (attrib
->isXmlNs
) continue;
1386 new_wsd_attrib
= WSDAllocateLinkedMemory(element
, sizeof(WSDXML_ATTRIBUTE
));
1387 if (new_wsd_attrib
== NULL
) goto outofmemory
;
1389 ns_string
= attrib
->ns
;
1390 if (ns_string
->length
== 0) ns_string
= element_node
->ns
;
1392 uri
= utf8_to_wide(NULL
, (const char *) ns_string
->bytes
, ns_string
->length
);
1393 if (uri
== NULL
) goto outofmemory
;
1395 trim_trailing_slash(uri
);
1397 /* Link element_name to uri so they will be freed at the same time */
1398 element_name
= utf8_to_wide(uri
, (const char *) attrib
->localName
->bytes
, attrib
->localName
->length
);
1399 if (element_name
== NULL
) goto outofmemory
;
1401 ret
= IWSDXMLContext_AddNameToNamespace(context
, uri
, element_name
, &name
);
1402 if (FAILED(ret
)) goto cleanup
;
1404 WSDFreeLinkedMemory(uri
);
1407 new_wsd_attrib
->Value
= xml_text_to_wide_string(new_wsd_attrib
, attrib
->value
);
1408 if (new_wsd_attrib
->Value
== NULL
) goto outofmemory
;
1410 new_wsd_attrib
->Name
= name
;
1411 new_wsd_attrib
->Element
= cur_element
;
1412 new_wsd_attrib
->Next
= NULL
;
1414 WSDAttachLinkedMemory(new_wsd_attrib
, name
);
1417 if (cur_wsd_attrib
== NULL
)
1418 element
->FirstAttribute
= new_wsd_attrib
;
1420 cur_wsd_attrib
->Next
= new_wsd_attrib
;
1422 cur_wsd_attrib
= new_wsd_attrib
;
1425 cur_element
= element
;
1428 case WS_XML_NODE_TYPE_TEXT
:
1429 text_node
= (const WS_XML_TEXT_NODE
*) node
;
1431 if (cur_element
== NULL
)
1433 WARN("No parent element open but encountered text element!\n");
1437 if (cur_element
->FirstChild
!= NULL
)
1439 WARN("Text node encountered but parent already has child!\n");
1443 text
= WSDAllocateLinkedMemory(element
, sizeof(WSDXML_TEXT
));
1444 if (text
== NULL
) goto outofmemory
;
1446 text
->Node
.Parent
= element
;
1447 text
->Node
.Next
= NULL
;
1448 text
->Node
.Type
= TextType
;
1449 text
->Text
= xml_text_to_wide_string(text
, text_node
->text
);
1451 if (text
->Text
== NULL
)
1453 WARN("Text node returned null string.\n");
1454 WSDFreeLinkedMemory(text
);
1458 cur_element
->FirstChild
= (WSDXML_NODE
*) text
;
1461 case WS_XML_NODE_TYPE_END_ELEMENT
:
1462 /* Go up a level to the parent element */
1463 cur_element
= cur_element
->Node
.Parent
;
1474 ret
= E_OUTOFMEMORY
;
1477 /* Free uri and element_name if applicable */
1478 WSDFreeLinkedMemory(uri
);
1479 WSDFreeLinkedMemory(name
);
1483 static WSDXML_ELEMENT
*find_element(WSDXML_ELEMENT
*parent
, LPCWSTR name
, LPCWSTR ns_uri
)
1485 WSDXML_ELEMENT
*cur
= (WSDXML_ELEMENT
*) parent
->FirstChild
;
1489 if ((lstrcmpW(cur
->Name
->LocalName
, name
) == 0) && (lstrcmpW(cur
->Name
->Space
->Uri
, ns_uri
) == 0))
1492 cur
= (WSDXML_ELEMENT
*) cur
->Node
.Next
;
1498 static void remove_element(WSDXML_ELEMENT
*element
)
1502 if (element
== NULL
)
1505 if (element
->Node
.Parent
->FirstChild
== (WSDXML_NODE
*) element
)
1506 element
->Node
.Parent
->FirstChild
= element
->Node
.Next
;
1509 cur
= element
->Node
.Parent
->FirstChild
;
1513 if (cur
->Next
== (WSDXML_NODE
*) element
)
1515 cur
->Next
= element
->Node
.Next
;
1523 WSDDetachLinkedMemory(element
);
1524 WSDFreeLinkedMemory(element
);
1527 static WSD_NAME_LIST
*build_types_list_from_string(IWSDXMLContext
*context
, LPCWSTR buffer
, void *parent
)
1529 WSD_NAME_LIST
*list
= NULL
, *cur_list
= NULL
, *prev_list
= NULL
;
1530 LPWSTR name_start
= NULL
, temp_buffer
= NULL
;
1531 LPCWSTR prefix_start
= buffer
;
1532 WSDXML_NAMESPACE
*ns
;
1539 temp_buffer
= duplicate_string(parent
, buffer
);
1540 if (temp_buffer
== NULL
) goto cleanup
;
1542 buffer_len
= lstrlenW(temp_buffer
);
1544 list
= WSDAllocateLinkedMemory(parent
, sizeof(WSD_NAME_LIST
));
1545 if (list
== NULL
) goto cleanup
;
1547 ZeroMemory(list
, sizeof(WSD_NAME_LIST
));
1548 prefix_start
= temp_buffer
;
1550 for (i
= 0; i
< buffer_len
; i
++)
1552 if (temp_buffer
[i
] == ':')
1555 name_start
= &temp_buffer
[i
+ 1];
1557 else if ((temp_buffer
[i
] == ' ') || (i
== buffer_len
- 1))
1559 WSDXML_NAMESPACE
*known_ns
;
1561 if (temp_buffer
[i
] == ' ')
1564 if (cur_list
== NULL
)
1568 cur_list
= WSDAllocateLinkedMemory(parent
, sizeof(WSD_NAME_LIST
));
1569 if (cur_list
== NULL
) goto cleanup
;
1571 prev_list
->Next
= cur_list
;
1574 name
= WSDAllocateLinkedMemory(cur_list
, sizeof(WSDXML_NAME
));
1575 if (name
== NULL
) goto cleanup
;
1577 ns
= WSDAllocateLinkedMemory(cur_list
, sizeof(WSDXML_NAMESPACE
));
1578 if (ns
== NULL
) goto cleanup
;
1580 ZeroMemory(ns
, sizeof(WSDXML_NAMESPACE
));
1581 ns
->PreferredPrefix
= duplicate_string(ns
, prefix_start
);
1583 known_ns
= xml_context_find_namespace_by_prefix(context
, ns
->PreferredPrefix
);
1585 if (known_ns
!= NULL
)
1586 ns
->Uri
= duplicate_string(ns
, known_ns
->Uri
);
1589 name
->LocalName
= duplicate_string(name
, name_start
);
1591 cur_list
->Element
= name
;
1592 prefix_start
= &temp_buffer
[i
+ 1];
1597 WSDFreeLinkedMemory(temp_buffer
);
1601 WSDFreeLinkedMemory(list
);
1602 WSDFreeLinkedMemory(temp_buffer
);
1607 static WSDXML_TYPE
*generate_type(LPCWSTR uri
, void *parent
)
1609 WSDXML_TYPE
*type
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_TYPE
));
1614 type
->Uri
= duplicate_string(parent
, uri
);
1620 static BOOL
is_duplicate_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
)
1622 struct message_id
*msg_id
, *msg_id_cursor
;
1626 EnterCriticalSection(&impl
->message_ids_critical_section
);
1628 LIST_FOR_EACH_ENTRY_SAFE(msg_id
, msg_id_cursor
, &impl
->message_ids
, struct message_id
, entry
)
1630 if (lstrcmpW(msg_id
->id
, id
) == 0)
1637 msg_id
= malloc(sizeof(*msg_id
));
1638 if (!msg_id
) goto end
;
1640 len
= (lstrlenW(id
) + 1) * sizeof(WCHAR
);
1641 msg_id
->id
= malloc(len
);
1649 memcpy(msg_id
->id
, id
, len
);
1650 list_add_tail(&impl
->message_ids
, &msg_id
->entry
);
1653 LeaveCriticalSection(&impl
->message_ids_critical_section
);
1657 HRESULT
read_message(IWSDiscoveryPublisherImpl
*impl
, const char *xml
, int xml_length
, WSD_SOAP_MESSAGE
**out_msg
, int *msg_type
)
1659 WSDXML_ELEMENT
*envelope
= NULL
, *header_element
, *appsequence_element
, *body_element
;
1660 WS_XML_READER_TEXT_ENCODING encoding
;
1661 WS_XML_ELEMENT_NODE
*envelope_node
;
1662 WSD_SOAP_MESSAGE
*soap_msg
= NULL
;
1663 WS_XML_READER_BUFFER_INPUT input
;
1664 WS_XML_ATTRIBUTE
*attrib
= NULL
;
1665 IWSDXMLContext
*context
= NULL
;
1666 WS_XML_STRING
*soap_uri
= NULL
;
1667 const WS_XML_NODE
*node
;
1668 WS_XML_READER
*reader
= NULL
;
1669 LPCWSTR value
= NULL
;
1671 WS_HEAP
*heap
= NULL
;
1675 *msg_type
= MSGTYPE_UNKNOWN
;
1677 ret
= WsCreateHeap(16384, 4096, NULL
, 0, &heap
, NULL
);
1678 if (FAILED(ret
)) goto cleanup
;
1680 ret
= WsCreateReader(NULL
, 0, &reader
, NULL
);
1681 if (FAILED(ret
)) goto cleanup
;
1683 encoding
.encoding
.encodingType
= WS_XML_READER_ENCODING_TYPE_TEXT
;
1684 encoding
.charSet
= WS_CHARSET_AUTO
;
1686 input
.input
.inputType
= WS_XML_READER_INPUT_TYPE_BUFFER
;
1687 input
.encodedData
= (char *) xml
;
1688 input
.encodedDataSize
= xml_length
;
1690 ret
= WsSetInput(reader
, (WS_XML_READER_ENCODING
*) &encoding
, (WS_XML_READER_INPUT
*) &input
, NULL
, 0, NULL
);
1691 if (FAILED(ret
)) goto cleanup
;
1693 soap_uri
= populate_xml_string(envelopeNsUri
);
1694 if (soap_uri
== NULL
) goto outofmemory
;
1696 ret
= move_to_element(reader
, "Envelope", soap_uri
);
1697 if (FAILED(ret
)) goto cleanup
;
1699 ret
= WsGetReaderNode(reader
, &node
, NULL
);
1700 if (FAILED(ret
)) goto cleanup
;
1702 if (node
->nodeType
!= WS_XML_NODE_TYPE_ELEMENT
)
1704 WARN("Unexpected node type (%d)\n", node
->nodeType
);
1709 envelope_node
= (WS_XML_ELEMENT_NODE
*) node
;
1711 ret
= WSDXMLCreateContext(&context
);
1712 if (FAILED(ret
)) goto cleanup
;
1714 /* Find XML namespaces from the envelope element's attributes */
1715 for (i
= 0; i
< envelope_node
->attributeCount
; i
++)
1717 attrib
= envelope_node
->attributes
[i
];
1719 if (attrib
->isXmlNs
)
1721 uri
= utf8_to_wide(NULL
, (const char *) attrib
->ns
->bytes
, attrib
->ns
->length
);
1722 if (uri
== NULL
) continue;
1724 trim_trailing_slash(uri
);
1726 prefix
= utf8_to_wide(uri
, (const char *) attrib
->localName
->bytes
, attrib
->localName
->length
);
1730 WSDFreeLinkedMemory(uri
);
1734 IWSDXMLContext_AddNamespace(context
, uri
, prefix
, NULL
);
1735 WSDFreeLinkedMemory(uri
);
1739 /* Create the SOAP message to return to the caller */
1740 soap_msg
= WSDAllocateLinkedMemory(NULL
, sizeof(WSD_SOAP_MESSAGE
));
1741 if (soap_msg
== NULL
) goto outofmemory
;
1743 ZeroMemory(soap_msg
, sizeof(WSD_SOAP_MESSAGE
));
1745 envelope
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSDXML_ELEMENT
));
1746 if (envelope
== NULL
) goto outofmemory
;
1748 ZeroMemory(envelope
, sizeof(WSDXML_ELEMENT
));
1750 ret
= ws_element_to_wsdxml_element(reader
, context
, envelope
);
1751 if (FAILED(ret
)) goto cleanup
;
1753 /* Find the header element */
1754 header_element
= find_element(envelope
, headerString
, envelopeNsUri
);
1756 if (header_element
== NULL
)
1758 WARN("Unable to find header element in received SOAP message\n");
1763 ret
= WSDXMLGetValueFromAny(addressingNsUri
, actionString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1764 if (FAILED(ret
)) goto cleanup
;
1765 soap_msg
->Header
.Action
= duplicate_string(soap_msg
, value
);
1766 if (soap_msg
->Header
.Action
== NULL
) goto outofmemory
;
1768 ret
= WSDXMLGetValueFromAny(addressingNsUri
, toString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1769 if (FAILED(ret
)) goto cleanup
;
1770 soap_msg
->Header
.To
= duplicate_string(soap_msg
, value
);
1771 if (soap_msg
->Header
.To
== NULL
) goto outofmemory
;
1773 ret
= WSDXMLGetValueFromAny(addressingNsUri
, messageIdString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1774 if (FAILED(ret
)) goto cleanup
;
1776 /* Detect duplicate messages */
1777 if (is_duplicate_message(impl
, value
))
1783 soap_msg
->Header
.MessageID
= duplicate_string(soap_msg
, value
);
1784 if (soap_msg
->Header
.MessageID
== NULL
) goto outofmemory
;
1786 /* Look for optional AppSequence element */
1787 appsequence_element
= find_element(header_element
, appSequenceString
, discoveryNsUri
);
1789 if (appsequence_element
!= NULL
)
1791 WSDXML_ATTRIBUTE
*current_attrib
;
1793 soap_msg
->Header
.AppSequence
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSD_APP_SEQUENCE
));
1794 if (soap_msg
->Header
.AppSequence
== NULL
) goto outofmemory
;
1796 ZeroMemory(soap_msg
->Header
.AppSequence
, sizeof(WSD_APP_SEQUENCE
));
1798 current_attrib
= appsequence_element
->FirstAttribute
;
1800 while (current_attrib
!= NULL
)
1802 if (lstrcmpW(current_attrib
->Name
->Space
->Uri
, discoveryNsUri
) != 0)
1804 current_attrib
= current_attrib
->Next
;
1808 if (lstrcmpW(current_attrib
->Name
->LocalName
, instanceIdString
) == 0)
1810 ret
= wide_text_to_ulonglong(current_attrib
->Value
, &soap_msg
->Header
.AppSequence
->InstanceId
);
1811 if (FAILED(ret
)) goto cleanup
;
1813 else if (lstrcmpW(current_attrib
->Name
->LocalName
, messageNumberString
) == 0)
1815 ret
= wide_text_to_ulonglong(current_attrib
->Value
, &soap_msg
->Header
.AppSequence
->MessageNumber
);
1816 if (FAILED(ret
)) goto cleanup
;
1818 else if (lstrcmpW(current_attrib
->Name
->LocalName
, sequenceIdString
) == 0)
1820 soap_msg
->Header
.AppSequence
->SequenceId
= duplicate_string(soap_msg
, current_attrib
->Value
);
1821 if (soap_msg
->Header
.AppSequence
->SequenceId
== NULL
) goto outofmemory
;
1824 current_attrib
= current_attrib
->Next
;
1828 /* Now detach and free known headers to leave the "any" elements */
1829 remove_element(find_element(header_element
, actionString
, addressingNsUri
));
1830 remove_element(find_element(header_element
, toString
, addressingNsUri
));
1831 remove_element(find_element(header_element
, messageIdString
, addressingNsUri
));
1832 remove_element(find_element(header_element
, appSequenceString
, discoveryNsUri
));
1834 soap_msg
->Header
.AnyHeaders
= (WSDXML_ELEMENT
*) header_element
->FirstChild
;
1836 if (soap_msg
->Header
.AnyHeaders
!= NULL
)
1837 soap_msg
->Header
.AnyHeaders
->Node
.Parent
= NULL
;
1839 /* Find the body element */
1840 body_element
= find_element(envelope
, bodyString
, envelopeNsUri
);
1842 if (body_element
== NULL
)
1844 WARN("Unable to find body element in received SOAP message\n");
1849 /* Now figure out which message we've been sent */
1850 if (lstrcmpW(soap_msg
->Header
.Action
, actionProbe
) == 0)
1852 WSDXML_ELEMENT
*probe_element
;
1853 WSD_PROBE
*probe
= NULL
;
1855 probe_element
= find_element(body_element
, probeString
, discoveryNsUri
);
1856 if (probe_element
== NULL
) goto cleanup
;
1858 probe
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSD_PROBE
));
1859 if (probe
== NULL
) goto cleanup
;
1861 ZeroMemory(probe
, sizeof(WSD_PROBE
));
1863 /* Check for the "types" element */
1864 ret
= WSDXMLGetValueFromAny(discoveryNsUri
, typesString
, (WSDXML_ELEMENT
*) probe_element
->FirstChild
, &value
);
1868 WARN("Unable to find Types element in received Probe message\n");
1872 probe
->Types
= build_types_list_from_string(context
, value
, probe
);
1874 /* Now detach and free known headers to leave the "any" elements */
1875 remove_element(find_element(probe_element
, typesString
, discoveryNsUri
));
1876 remove_element(find_element(probe_element
, scopesString
, discoveryNsUri
));
1878 probe
->Any
= (WSDXML_ELEMENT
*) probe_element
->FirstChild
;
1880 if (probe
->Any
!= NULL
)
1881 probe
->Any
->Node
.Parent
= NULL
;
1883 soap_msg
->Body
= probe
;
1884 soap_msg
->BodyType
= generate_type(actionProbe
, soap_msg
);
1885 if (soap_msg
->BodyType
== NULL
) goto cleanup
;
1887 *out_msg
= soap_msg
;
1888 soap_msg
= NULL
; /* caller will clean this up */
1889 *msg_type
= MSGTYPE_PROBE
;
1895 ret
= E_OUTOFMEMORY
;
1898 free_xml_string(soap_uri
);
1899 WSDFreeLinkedMemory(soap_msg
);
1900 if (context
!= NULL
) IWSDXMLContext_Release(context
);
1901 if (reader
!= NULL
) WsFreeReader(reader
);
1902 if (heap
!= NULL
) WsFreeHeap(heap
);