webservices: Add a stub implementation of WS_TYPE_ATTRIBUTE_FIELD_MAPPING in the...
[wine.git] / dlls / webservices / msg.c
blob8f44b4052e785e11862ae91e6a58744b0dd8586a
1 /*
2 * Copyright 2016 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winuser.h"
24 #include "rpc.h"
25 #include "webservices.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
29 #include "wine/unicode.h"
30 #include "webservices_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
34 static const char ns_env_1_1[] = "http://schemas.xmlsoap.org/soap/envelope/";
35 static const char ns_env_1_2[] = "http://www.w3.org/2003/05/soap-envelope";
36 static const char ns_addr_0_9[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
37 static const char ns_addr_1_0[] = "http://www.w3.org/2005/08/addressing";
39 static const struct prop_desc msg_props[] =
41 { sizeof(WS_MESSAGE_STATE), TRUE }, /* WS_MESSAGE_PROPERTY_STATE */
42 { sizeof(WS_HEAP *), TRUE }, /* WS_MESSAGE_PROPERTY_HEAP */
43 { sizeof(WS_ENVELOPE_VERSION), TRUE }, /* WS_MESSAGE_PROPERTY_ENVELOPE_VERSION */
44 { sizeof(WS_ADDRESSING_VERSION), TRUE }, /* WS_MESSAGE_PROPERTY_ADDRESSING_VERSION */
45 { sizeof(WS_XML_BUFFER *), TRUE }, /* WS_MESSAGE_PROPERTY_HEADER_BUFFER */
46 { sizeof(WS_XML_NODE_POSITION *), TRUE }, /* WS_MESSAGE_PROPERTY_HEADER_POSITION */
47 { sizeof(WS_XML_READER *), TRUE }, /* WS_MESSAGE_PROPERTY_BODY_READER */
48 { sizeof(WS_XML_WRITER *), TRUE }, /* WS_MESSAGE_PROPERTY_BODY_WRITER */
49 { sizeof(BOOL), TRUE }, /* WS_MESSAGE_PROPERTY_IS_ADDRESSED */
52 struct header
54 WS_HEADER_TYPE type;
55 BOOL mapped;
56 WS_XML_STRING name;
57 WS_XML_STRING ns;
58 union
60 WS_XML_BUFFER *buf;
61 WS_XML_STRING *text;
62 } u;
65 struct msg
67 WS_MESSAGE_INITIALIZATION init;
68 WS_MESSAGE_STATE state;
69 GUID id;
70 WS_ENVELOPE_VERSION version_env;
71 WS_ADDRESSING_VERSION version_addr;
72 BOOL is_addressed;
73 WS_STRING addr;
74 WS_STRING action;
75 WS_HEAP *heap;
76 WS_XML_BUFFER *buf;
77 WS_XML_WRITER *writer;
78 WS_XML_WRITER *writer_body;
79 WS_XML_READER *reader_body;
80 ULONG header_count;
81 ULONG header_size;
82 struct header **header;
83 ULONG prop_count;
84 struct prop prop[sizeof(msg_props)/sizeof(msg_props[0])];
87 #define HEADER_ARRAY_SIZE 2
88 static struct msg *alloc_msg(void)
90 static const ULONG count = sizeof(msg_props)/sizeof(msg_props[0]);
91 struct msg *ret;
92 ULONG size = sizeof(*ret) + prop_size( msg_props, count );
94 if (!(ret = heap_alloc_zero( size ))) return NULL;
95 if (!(ret->header = heap_alloc( HEADER_ARRAY_SIZE * sizeof(struct header *) )))
97 heap_free( ret );
98 return NULL;
100 ret->state = WS_MESSAGE_STATE_EMPTY;
101 ret->header_size = HEADER_ARRAY_SIZE;
102 prop_init( msg_props, count, ret->prop, &ret[1] );
103 ret->prop_count = count;
104 return ret;
107 static void free_header( struct header *header )
109 heap_free( header->name.bytes );
110 heap_free( header->ns.bytes );
111 if (header->mapped) heap_free( header->u.text );
112 heap_free( header );
115 static void free_msg( struct msg *msg )
117 ULONG i;
118 if (!msg) return;
119 WsFreeWriter( msg->writer );
120 WsFreeHeap( msg->heap );
121 heap_free( msg->addr.chars );
122 heap_free( msg->action.chars );
123 for (i = 0; i < msg->header_count; i++) free_header( msg->header[i] );
124 heap_free( msg->header );
125 heap_free( msg );
128 #define HEAP_MAX_SIZE (1 << 16)
129 static HRESULT create_msg( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
130 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle )
132 struct msg *msg;
133 HRESULT hr;
134 ULONG i;
136 if (!(msg = alloc_msg())) return E_OUTOFMEMORY;
138 for (i = 0; i < count; i++)
140 if (properties[i].id == WS_MESSAGE_PROPERTY_ENVELOPE_VERSION ||
141 properties[i].id == WS_MESSAGE_PROPERTY_ADDRESSING_VERSION)
143 free_msg( msg );
144 return E_INVALIDARG;
146 hr = prop_set( msg->prop, msg->prop_count, properties[i].id, properties[i].value,
147 properties[i].valueSize );
148 if (hr != S_OK)
150 free_msg( msg );
151 return hr;
155 if ((hr = WsCreateHeap( HEAP_MAX_SIZE, 0, NULL, 0, &msg->heap, NULL )) != S_OK)
157 free_msg( msg );
158 return hr;
160 if ((hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &msg->buf, NULL )) != S_OK)
162 free_msg( msg );
163 return hr;
166 UuidCreate( &msg->id );
167 msg->version_env = env_version;
168 msg->version_addr = addr_version;
170 *handle = (WS_MESSAGE *)msg;
171 return S_OK;
174 /**************************************************************************
175 * WsCreateMessage [webservices.@]
177 HRESULT WINAPI WsCreateMessage( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
178 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle,
179 WS_ERROR *error )
181 TRACE( "%u %u %p %u %p %p\n", env_version, addr_version, properties, count, handle, error );
182 if (error) FIXME( "ignoring error parameter\n" );
184 if (!handle || !env_version || !addr_version) return E_INVALIDARG;
185 return create_msg( env_version, addr_version, properties, count, handle );
188 /**************************************************************************
189 * WsCreateMessageForChannel [webservices.@]
191 HRESULT WINAPI WsCreateMessageForChannel( WS_CHANNEL *channel_handle, const WS_MESSAGE_PROPERTY *properties,
192 ULONG count, WS_MESSAGE **handle, WS_ERROR *error )
194 WS_ENVELOPE_VERSION version_env;
195 WS_ADDRESSING_VERSION version_addr;
196 HRESULT hr;
198 TRACE( "%p %p %u %p %p\n", channel_handle, properties, count, handle, error );
199 if (error) FIXME( "ignoring error parameter\n" );
201 if (!channel_handle || !handle) return E_INVALIDARG;
203 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION, &version_env,
204 sizeof(version_env), NULL )) != S_OK || !version_env)
205 version_env = WS_ENVELOPE_VERSION_SOAP_1_2;
207 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ADDRESSING_VERSION, &version_addr,
208 sizeof(version_addr), NULL )) != S_OK || !version_addr)
209 version_addr = WS_ADDRESSING_VERSION_1_0;
211 return create_msg( version_env, version_addr, properties, count, handle );
214 /**************************************************************************
215 * WsFreeMessage [webservices.@]
217 void WINAPI WsFreeMessage( WS_MESSAGE *handle )
219 struct msg *msg = (struct msg *)handle;
221 TRACE( "%p\n", handle );
222 free_msg( msg );
225 /**************************************************************************
226 * WsGetMessageProperty [webservices.@]
228 HRESULT WINAPI WsGetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, void *buf,
229 ULONG size, WS_ERROR *error )
231 struct msg *msg = (struct msg *)handle;
233 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
234 if (error) FIXME( "ignoring error parameter\n" );
236 if (!handle) return E_INVALIDARG;
238 switch (id)
240 case WS_MESSAGE_PROPERTY_STATE:
241 if (!buf || size != sizeof(msg->state)) return E_INVALIDARG;
242 *(WS_MESSAGE_STATE *)buf = msg->state;
243 return S_OK;
245 case WS_MESSAGE_PROPERTY_HEAP:
246 if (!buf || size != sizeof(msg->heap)) return E_INVALIDARG;
247 *(WS_HEAP **)buf = msg->heap;
248 return S_OK;
250 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
251 if (!buf || size != sizeof(msg->version_env)) return E_INVALIDARG;
252 *(WS_ENVELOPE_VERSION *)buf = msg->version_env;
253 return S_OK;
255 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
256 if (!buf || size != sizeof(msg->version_addr)) return E_INVALIDARG;
257 *(WS_ADDRESSING_VERSION *)buf = msg->version_addr;
258 return S_OK;
260 case WS_MESSAGE_PROPERTY_HEADER_BUFFER:
261 if (!buf || size != sizeof(msg->buf)) return E_INVALIDARG;
262 *(WS_XML_BUFFER **)buf = msg->buf;
263 return S_OK;
265 case WS_MESSAGE_PROPERTY_BODY_READER:
266 if (!buf || size != sizeof(msg->reader_body)) return E_INVALIDARG;
267 *(WS_XML_READER **)buf = msg->reader_body;
268 return S_OK;
270 case WS_MESSAGE_PROPERTY_BODY_WRITER:
271 if (!buf || size != sizeof(msg->writer_body)) return E_INVALIDARG;
272 *(WS_XML_WRITER **)buf = msg->writer_body;
273 return S_OK;
275 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
276 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
277 *(BOOL *)buf = msg->is_addressed;
278 return S_OK;
280 default:
281 return prop_get( msg->prop, msg->prop_count, id, buf, size );
285 /**************************************************************************
286 * WsSetMessageProperty [webservices.@]
288 HRESULT WINAPI WsSetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, const void *value,
289 ULONG size, WS_ERROR *error )
291 struct msg *msg = (struct msg *)handle;
293 TRACE( "%p %u %p %u\n", handle, id, value, size );
294 if (error) FIXME( "ignoring error parameter\n" );
296 if (!handle) return E_INVALIDARG;
298 switch (id)
300 case WS_MESSAGE_PROPERTY_STATE:
301 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
302 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
303 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
304 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
305 return E_INVALIDARG;
307 default:
308 break;
310 return prop_set( msg->prop, msg->prop_count, id, value, size );
313 /**************************************************************************
314 * WsAddressMessage [webservices.@]
316 HRESULT WINAPI WsAddressMessage( WS_MESSAGE *handle, const WS_ENDPOINT_ADDRESS *addr, WS_ERROR *error )
318 struct msg *msg = (struct msg *)handle;
320 TRACE( "%p %p %p\n", handle, addr, error );
321 if (error) FIXME( "ignoring error parameter\n" );
322 if (addr && (addr->headers || addr->extensions || addr->identity))
324 FIXME( "headers, extensions or identity not supported\n" );
325 return E_NOTIMPL;
328 if (!handle) return E_INVALIDARG;
329 if (msg->state < WS_MESSAGE_STATE_INITIALIZED || msg->is_addressed) return WS_E_INVALID_OPERATION;
331 if (addr && addr->url.length)
333 if (!(msg->addr.chars = heap_alloc( addr->url.length * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
334 memcpy( msg->addr.chars, addr->url.chars, addr->url.length * sizeof(WCHAR) );
335 msg->addr.length = addr->url.length;
338 msg->is_addressed = TRUE;
339 return S_OK;
342 static HRESULT get_env_namespace( WS_ENVELOPE_VERSION ver, WS_XML_STRING *str )
344 switch (ver)
346 case WS_ENVELOPE_VERSION_SOAP_1_1:
347 str->bytes = (BYTE *)ns_env_1_1;
348 str->length = sizeof(ns_env_1_1)/sizeof(ns_env_1_1[0]) - 1;
349 return S_OK;
351 case WS_ENVELOPE_VERSION_SOAP_1_2:
352 str->bytes = (BYTE *)ns_env_1_2;
353 str->length = sizeof(ns_env_1_2)/sizeof(ns_env_1_2[0]) - 1;
354 return S_OK;
356 default:
357 ERR( "unhandled envelope version %u\n", ver );
358 return E_NOTIMPL;
362 static HRESULT get_addr_namespace( WS_ADDRESSING_VERSION ver, WS_XML_STRING *str )
364 switch (ver)
366 case WS_ADDRESSING_VERSION_0_9:
367 str->bytes = (BYTE *)ns_addr_0_9;
368 str->length = sizeof(ns_addr_0_9)/sizeof(ns_addr_0_9[0]) - 1;
369 return S_OK;
371 case WS_ADDRESSING_VERSION_1_0:
372 str->bytes = (BYTE *)ns_addr_1_0;
373 str->length = sizeof(ns_addr_1_0)/sizeof(ns_addr_1_0[0]) - 1;
374 return S_OK;
376 case WS_ADDRESSING_VERSION_TRANSPORT:
377 str->bytes = NULL;
378 str->length = 0;
379 return S_OK;
381 default:
382 ERR( "unhandled addressing version %u\n", ver );
383 return E_NOTIMPL;
387 static const WS_XML_STRING *get_header_name( WS_HEADER_TYPE type )
389 static const WS_XML_STRING action = {6, (BYTE *)"Action"}, to = {2, (BYTE *)"To"};
390 static const WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, relto = {9, (BYTE *)"RelatesTo"};
391 static const WS_XML_STRING from = {4, (BYTE *)"From"}, replyto = {7, (BYTE *)"ReplyTo"};
392 static const WS_XML_STRING faultto = {7, (BYTE *)"FaultTo"};
394 switch (type)
396 case WS_ACTION_HEADER: return &action;
397 case WS_TO_HEADER: return &to;
398 case WS_MESSAGE_ID_HEADER: return &msgid;
399 case WS_RELATES_TO_HEADER: return &relto;
400 case WS_FROM_HEADER: return &from;
401 case WS_REPLY_TO_HEADER: return &replyto;
402 case WS_FAULT_TO_HEADER: return &faultto;
403 default:
404 ERR( "unknown type %u\n", type );
405 return NULL;
409 static HRESULT write_headers( struct msg *msg, const WS_XML_STRING *ns_env, const WS_XML_STRING *ns_addr,
410 WS_XML_WRITER *writer )
412 static const char anonymous[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
413 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
414 static const WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, replyto = {7, (BYTE *)"ReplyTo"};
415 static const WS_XML_STRING address = {7, (BYTE *)"Address"}, header = {6, (BYTE *)"Header"};
416 WS_XML_UTF8_TEXT urn, addr;
417 HRESULT hr;
418 ULONG i;
420 if ((hr = WsWriteXmlnsAttribute( writer, &prefix_a, ns_addr, FALSE, NULL )) != S_OK) return hr;
421 if ((hr = WsWriteStartElement( writer, &prefix_s, &header, ns_env, NULL )) != S_OK) return hr;
423 if ((hr = WsWriteStartElement( writer, &prefix_a, &msgid, ns_addr, NULL )) != S_OK) return hr;
424 urn.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
425 memcpy( &urn.value, &msg->id, sizeof(msg->id) );
426 if ((hr = WsWriteText( writer, &urn.text, NULL )) != S_OK) return hr;
427 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:MessageID> */
429 if (msg->version_addr == WS_ADDRESSING_VERSION_0_9)
431 if ((hr = WsWriteStartElement( writer, &prefix_a, &replyto, ns_addr, NULL )) != S_OK) return hr;
432 if ((hr = WsWriteStartElement( writer, &prefix_a, &address, ns_addr, NULL )) != S_OK) return hr;
434 addr.text.textType = WS_XML_TEXT_TYPE_UTF8;
435 addr.value.bytes = (BYTE *)anonymous;
436 addr.value.length = sizeof(anonymous) - 1;
437 if ((hr = WsWriteText( writer, &addr.text, NULL )) != S_OK) return hr;
438 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:Address> */
439 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:ReplyTo> */
442 for (i = 0; i < msg->header_count; i++)
444 if (msg->header[i]->mapped) continue;
445 if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr;
448 return WsWriteEndElement( writer, NULL ); /* </s:Header> */
451 static HRESULT write_headers_transport( struct msg *msg, const WS_XML_STRING *ns_env, WS_XML_WRITER *writer )
453 static const WS_XML_STRING prefix = {1, (BYTE *)"s"}, header = {6, (BYTE *)"Header"};
454 HRESULT hr = S_OK;
455 ULONG i;
457 if ((msg->header_count || !msg->action.length) &&
458 (hr = WsWriteStartElement( writer, &prefix, &header, ns_env, NULL )) != S_OK) return hr;
460 for (i = 0; i < msg->header_count; i++)
462 if (msg->header[i]->mapped) continue;
463 if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr;
466 if (msg->header_count || !msg->action.length) hr = WsWriteEndElement( writer, NULL ); /* </s:Header> */
467 return hr;
470 static HRESULT write_envelope_start( struct msg *msg, WS_XML_WRITER *writer )
472 static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, body = {4, (BYTE *)"Body"};
473 static const WS_XML_STRING prefix = {1, (BYTE *)"s"};
474 WS_XML_STRING ns_env, ns_addr;
475 HRESULT hr;
477 if ((hr = get_env_namespace( msg->version_env, &ns_env )) != S_OK) return hr;
478 if ((hr = get_addr_namespace( msg->version_addr, &ns_addr )) != S_OK) return hr;
479 if ((hr = WsWriteStartElement( writer, &prefix, &envelope, &ns_env, NULL )) != S_OK) return hr;
481 if (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT)
482 hr = write_headers_transport( msg, &ns_env, writer );
483 else
484 hr = write_headers( msg, &ns_env, &ns_addr, writer );
485 if (hr != S_OK) return hr;
487 return WsWriteStartElement( writer, &prefix, &body, &ns_env, NULL ); /* <s:Body> */
490 static HRESULT write_envelope_end( WS_XML_WRITER *writer )
492 HRESULT hr;
493 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </s:Body> */
494 return WsWriteEndElement( writer, NULL ); /* </s:Envelope> */
497 static HRESULT write_envelope( struct msg *msg )
499 HRESULT hr;
500 if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) return hr;
501 if (!msg->buf && (hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &msg->buf, NULL )) != S_OK) return hr;
502 if ((hr = WsSetOutputToBuffer( msg->writer, msg->buf, NULL, 0, NULL )) != S_OK) return hr;
503 if ((hr = write_envelope_start( msg, msg->writer )) != S_OK) return hr;
504 return write_envelope_end( msg->writer );
507 /**************************************************************************
508 * WsWriteEnvelopeStart [webservices.@]
510 HRESULT WINAPI WsWriteEnvelopeStart( WS_MESSAGE *handle, WS_XML_WRITER *writer,
511 WS_MESSAGE_DONE_CALLBACK cb, void *state, WS_ERROR *error )
513 struct msg *msg = (struct msg *)handle;
514 HRESULT hr;
516 TRACE( "%p %p %p %p %p\n", handle, writer, cb, state, error );
517 if (error) FIXME( "ignoring error parameter\n" );
518 if (cb)
520 FIXME( "callback not supported\n" );
521 return E_NOTIMPL;
524 if (!handle || !writer) return E_INVALIDARG;
525 if (msg->state != WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
527 if ((hr = write_envelope( msg )) != S_OK) return hr;
528 if ((hr = write_envelope_start( msg, writer )) != S_OK) return hr;
530 msg->writer_body = writer;
531 msg->state = WS_MESSAGE_STATE_WRITING;
532 return S_OK;
535 /**************************************************************************
536 * WsWriteEnvelopeEnd [webservices.@]
538 HRESULT WINAPI WsWriteEnvelopeEnd( WS_MESSAGE *handle, WS_ERROR *error )
540 struct msg *msg = (struct msg *)handle;
541 HRESULT hr;
543 TRACE( "%p %p\n", handle, error );
544 if (error) FIXME( "ignoring error parameter\n" );
546 if (!handle) return E_INVALIDARG;
547 if (msg->state != WS_MESSAGE_STATE_WRITING) return WS_E_INVALID_OPERATION;
549 if ((hr = write_envelope_end( msg->writer_body )) != S_OK) return hr;
551 msg->state = WS_MESSAGE_STATE_DONE;
552 return S_OK;
555 /**************************************************************************
556 * WsWriteBody [webservices.@]
558 HRESULT WINAPI WsWriteBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
559 const void *value, ULONG size, WS_ERROR *error )
561 struct msg *msg = (struct msg *)handle;
562 HRESULT hr;
564 TRACE( "%p %p %08x %p %u %p\n", handle, desc, option, value, size, error );
565 if (error) FIXME( "ignoring error parameter\n" );
567 if (!handle || !desc) return E_INVALIDARG;
568 if (msg->state != WS_MESSAGE_STATE_WRITING) return WS_E_INVALID_OPERATION;
570 if (desc->elementLocalName &&
571 (hr = WsWriteStartElement( msg->writer_body, NULL, desc->elementLocalName, desc->elementNs,
572 NULL )) != S_OK) return hr;
574 if ((hr = WsWriteType( msg->writer_body, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
575 option, value, size, NULL )) != S_OK) return hr;
577 if (desc->elementLocalName) hr = WsWriteEndElement( msg->writer_body, NULL );
578 return hr;
581 static BOOL match_current_element( WS_XML_READER *reader, const WS_XML_STRING *localname )
583 const WS_XML_NODE *node;
584 const WS_XML_ELEMENT_NODE *elem;
586 if (WsGetReaderNode( reader, &node, NULL ) != S_OK) return FALSE;
587 if (node->nodeType != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
588 elem = (const WS_XML_ELEMENT_NODE *)node;
589 return WsXmlStringEquals( elem->localName, localname, NULL ) == S_OK;
592 static HRESULT read_envelope_start( WS_XML_READER *reader )
594 static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, body = {4, (BYTE *)"Body"};
595 HRESULT hr;
597 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
598 if (!match_current_element( reader, &envelope )) return WS_E_INVALID_FORMAT;
599 /* FIXME: read headers */
600 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
601 if (!match_current_element( reader, &body )) return WS_E_INVALID_FORMAT;
602 return WsReadNode( reader, NULL );
605 /**************************************************************************
606 * WsReadEnvelopeStart [webservices.@]
608 HRESULT WINAPI WsReadEnvelopeStart( WS_MESSAGE *handle, WS_XML_READER *reader, WS_MESSAGE_DONE_CALLBACK cb,
609 void *state, WS_ERROR *error )
611 struct msg *msg = (struct msg *)handle;
612 HRESULT hr;
614 TRACE( "%p %p %p %p %p\n", handle, reader, cb, state, error );
615 if (error) FIXME( "ignoring error parameter\n" );
616 if (cb)
618 FIXME( "callback not supported\n" );
619 return E_NOTIMPL;
622 if (!handle || !reader) return E_INVALIDARG;
623 if (msg->state != WS_MESSAGE_STATE_EMPTY) return WS_E_INVALID_OPERATION;
625 if ((hr = read_envelope_start( reader )) != S_OK) return hr;
627 msg->reader_body = reader;
628 msg->state = WS_MESSAGE_STATE_READING;
629 return S_OK;
632 static HRESULT read_envelope_end( WS_XML_READER *reader )
634 HRESULT hr;
635 if ((hr = WsReadEndElement( reader, NULL )) != S_OK) return hr; /* </s:Body> */
636 return WsReadEndElement( reader, NULL ); /* </s:Envelope> */
639 /**************************************************************************
640 * WsReadEnvelopeEnd [webservices.@]
642 HRESULT WINAPI WsReadEnvelopeEnd( WS_MESSAGE *handle, WS_ERROR *error )
644 struct msg *msg = (struct msg *)handle;
645 HRESULT hr;
647 TRACE( "%p %p\n", handle, error );
648 if (error) FIXME( "ignoring error parameter\n" );
650 if (!handle) return E_INVALIDARG;
651 if (msg->state != WS_MESSAGE_STATE_READING) return WS_E_INVALID_OPERATION;
653 if ((hr = read_envelope_end( msg->reader_body )) != S_OK) return hr;
655 msg->state = WS_MESSAGE_STATE_DONE;
656 return S_OK;
659 /**************************************************************************
660 * WsReadBody [webservices.@]
662 HRESULT WINAPI WsReadBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_READ_OPTION option,
663 WS_HEAP *heap, void *value, ULONG size, WS_ERROR *error )
665 struct msg *msg = (struct msg *)handle;
667 TRACE( "%p %p %08x %p %p %u %p\n", handle, desc, option, heap, value, size, error );
668 if (error) FIXME( "ignoring error parameter\n" );
670 if (!handle || !desc) return E_INVALIDARG;
671 if (msg->state != WS_MESSAGE_STATE_READING) return WS_E_INVALID_OPERATION;
673 return WsReadElement( msg->reader_body, desc, option, heap, value, size, NULL );
676 /**************************************************************************
677 * WsInitializeMessage [webservices.@]
679 HRESULT WINAPI WsInitializeMessage( WS_MESSAGE *handle, WS_MESSAGE_INITIALIZATION init,
680 WS_MESSAGE *src_handle, WS_ERROR *error )
682 struct msg *msg = (struct msg *)handle;
684 TRACE( "%p %u %p %p\n", handle, init, src_handle, error );
685 if (error) FIXME( "ignoring error parameter\n" );
686 if (src_handle)
688 FIXME( "src message not supported\n" );
689 return E_NOTIMPL;
692 if (!handle || init > WS_FAULT_MESSAGE) return E_INVALIDARG;
693 if (msg->state >= WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
695 msg->init = init;
696 msg->state = WS_MESSAGE_STATE_INITIALIZED;
697 return write_envelope( msg );
700 static HRESULT grow_header_array( struct msg *msg, ULONG size )
702 struct header **tmp;
703 if (size <= msg->header_size) return S_OK;
704 if (!(tmp = heap_realloc( msg->header, 2 * msg->header_size * sizeof(struct header *) )))
705 return E_OUTOFMEMORY;
706 msg->header = tmp;
707 msg->header_size *= 2;
708 return S_OK;
711 static struct header *alloc_header( WS_HEADER_TYPE type, BOOL mapped, const WS_XML_STRING *name,
712 const WS_XML_STRING *ns )
714 struct header *ret;
715 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
716 if (name && name->length)
718 if (!(ret->name.bytes = heap_alloc( name->length )))
720 free_header( ret );
721 return NULL;
723 memcpy( ret->name.bytes, name->bytes, name->length );
724 ret->name.length = name->length;
726 if (ns && ns->length)
728 if (!(ret->ns.bytes = heap_alloc( ns->length )))
730 free_header( ret );
731 return NULL;
733 memcpy( ret->ns.bytes, ns->bytes, ns->length );
734 ret->ns.length = ns->length;
736 ret->type = type;
737 ret->mapped = mapped;
738 return ret;
741 static HRESULT write_standard_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, WS_TYPE value_type,
742 WS_WRITE_OPTION option, const void *value, ULONG size )
744 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
745 static const WS_XML_STRING understand = {14, (BYTE *)"mustUnderstand"}, ns = {0, NULL};
746 WS_XML_INT32_TEXT one = {{WS_XML_TEXT_TYPE_INT32}, 1};
747 HRESULT hr;
749 if ((hr = WsWriteStartElement( writer, &prefix_a, name, &ns, NULL )) != S_OK) return hr;
750 if ((hr = WsWriteStartAttribute( writer, &prefix_s, &understand, &ns, FALSE, NULL )) != S_OK) return hr;
751 if ((hr = WsWriteText( writer, &one.text, NULL )) != S_OK) return hr;
752 if ((hr = WsWriteEndAttribute( writer, NULL )) != S_OK) return hr;
753 if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, value_type, NULL, option, value, size,
754 NULL )) != S_OK) return hr;
755 return WsWriteEndElement( writer, NULL );
758 static HRESULT build_standard_header( WS_HEAP *heap, WS_HEADER_TYPE type, WS_TYPE value_type,
759 WS_WRITE_OPTION option, const void *value, ULONG size,
760 struct header **ret )
762 const WS_XML_STRING *name = get_header_name( type );
763 struct header *header;
764 WS_XML_WRITER *writer;
765 WS_XML_BUFFER *buf;
766 HRESULT hr;
768 if (!(header = alloc_header( type, FALSE, name, NULL ))) return E_OUTOFMEMORY;
770 if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
771 if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
772 if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
773 if ((hr = write_standard_header( writer, name, value_type, option, value, size )) != S_OK)
774 goto done;
776 header->u.buf = buf;
778 done:
779 if (hr != S_OK) free_header( header );
780 else *ret = header;
781 WsFreeWriter( writer );
782 return hr;
785 /**************************************************************************
786 * WsSetHeader [webservices.@]
788 HRESULT WINAPI WsSetHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_TYPE value_type,
789 WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error )
791 struct msg *msg = (struct msg *)handle;
792 struct header *header;
793 BOOL found = FALSE;
794 HRESULT hr;
795 ULONG i;
797 TRACE( "%p %u %u %08x %p %u %p\n", handle, type, value_type, option, value, size, error );
798 if (error) FIXME( "ignoring error parameter\n" );
800 if (!handle || type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER) return E_INVALIDARG;
801 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
803 for (i = 0; i < msg->header_count; i++)
805 if (msg->header[i]->type == type)
807 found = TRUE;
808 break;
812 if (!found)
814 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) return hr;
815 i = msg->header_count;
818 if ((hr = build_standard_header( msg->heap, type, value_type, option, value, size, &header )) != S_OK)
819 return hr;
821 if (!found) msg->header_count++;
822 else free_header( msg->header[i] );
824 msg->header[i] = header;
825 return write_envelope( msg );
828 static void remove_header( struct msg *msg, ULONG i )
830 free_header( msg->header[i] );
831 memmove( &msg->header[i], &msg->header[i + 1], (msg->header_count - i - 1) * sizeof(struct header *) );
832 msg->header_count--;
835 /**************************************************************************
836 * WsRemoveHeader [webservices.@]
838 HRESULT WINAPI WsRemoveHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_ERROR *error )
840 struct msg *msg = (struct msg *)handle;
841 BOOL removed = FALSE;
842 ULONG i;
844 TRACE( "%p %u %p\n", handle, type, error );
845 if (error) FIXME( "ignoring error parameter\n" );
847 if (!handle) return E_INVALIDARG;
848 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
849 if (type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER) return E_INVALIDARG;
851 for (i = 0; i < msg->header_count; i++)
853 if (msg->header[i]->type == type)
855 remove_header( msg, i );
856 removed = TRUE;
857 break;
861 if (removed) return write_envelope( msg );
862 return S_OK;
865 static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_WRITE_OPTION option,
866 const void *value, ULONG size, struct header **ret )
868 struct header *header;
870 if (!(header = alloc_header( 0, TRUE, name, NULL ))) return E_OUTOFMEMORY;
871 switch (type)
873 case WS_WSZ_TYPE:
875 int len;
876 const WCHAR *src;
878 if (option != WS_WRITE_REQUIRED_POINTER || size != sizeof(WCHAR *))
880 free_header( header );
881 return E_INVALIDARG;
883 src = *(const WCHAR **)value;
884 len = WideCharToMultiByte( CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL ) - 1;
885 if (!(header->u.text = alloc_xml_string( NULL, len )))
887 free_header( header );
888 return E_OUTOFMEMORY;
890 WideCharToMultiByte( CP_UTF8, 0, src, -1, (char *)header->u.text->bytes, len, NULL, NULL );
891 break;
893 case WS_XML_STRING_TYPE:
895 const WS_XML_STRING *str = value;
897 if (option != WS_WRITE_REQUIRED_VALUE)
899 FIXME( "unhandled write option %u\n", option );
900 free_header( header );
901 return E_NOTIMPL;
903 if (size != sizeof(*str))
905 free_header( header );
906 return E_INVALIDARG;
908 if (!(header->u.text = alloc_xml_string( NULL, str->length )))
910 free_header( header );
911 return E_OUTOFMEMORY;
913 memcpy( header->u.text->bytes, str->bytes, str->length );
914 break;
916 case WS_STRING_TYPE:
918 int len;
919 const WS_STRING *str = value;
921 if (option != WS_WRITE_REQUIRED_VALUE)
923 FIXME( "unhandled write option %u\n", option );
924 free_header( header );
925 return E_NOTIMPL;
927 if (size != sizeof(*str))
929 free_header( header );
930 return E_INVALIDARG;
932 len = WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, NULL, 0, NULL, NULL );
933 if (!(header->u.text = alloc_xml_string( NULL, len )))
935 free_header( header );
936 return E_OUTOFMEMORY;
938 WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, (char *)header->u.text->bytes,
939 len, NULL, NULL );
940 break;
942 default:
943 FIXME( "unhandled type %u\n", type );
944 free_header( header );
945 return E_NOTIMPL;
948 *ret = header;
949 return S_OK;
952 /**************************************************************************
953 * WsAddMappedHeader [webservices.@]
955 HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type,
956 WS_WRITE_OPTION option, const void *value, ULONG size , WS_ERROR *error )
958 struct msg *msg = (struct msg *)handle;
959 struct header *header;
960 BOOL found = FALSE;
961 HRESULT hr;
962 ULONG i;
964 TRACE( "%p %s %u %08x %p %u %p\n", handle, debugstr_xmlstr(name), type, option, value, size, error );
965 if (error) FIXME( "ignoring error parameter\n" );
967 if (!handle || !name) return E_INVALIDARG;
968 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
970 for (i = 0; i < msg->header_count; i++)
972 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
973 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
975 found = TRUE;
976 break;
980 if (!found)
982 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) return hr;
983 i = msg->header_count;
986 if ((hr = build_mapped_header( name, type, option, value, size, &header )) != S_OK) return hr;
988 if (!found) msg->header_count++;
989 else free_header( msg->header[i] );
991 msg->header[i] = header;
992 return S_OK;
995 /**************************************************************************
996 * WsRemoveMappedHeader [webservices.@]
998 HRESULT WINAPI WsRemoveMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_ERROR *error )
1000 struct msg *msg = (struct msg *)handle;
1001 ULONG i;
1003 TRACE( "%p %s %p\n", handle, debugstr_xmlstr(name), error );
1004 if (error) FIXME( "ignoring error parameter\n" );
1006 if (!handle || !name) return E_INVALIDARG;
1007 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
1009 for (i = 0; i < msg->header_count; i++)
1011 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
1012 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
1014 remove_header( msg, i );
1015 break;
1019 return S_OK;
1022 static HRESULT write_custom_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1023 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
1024 ULONG size )
1026 HRESULT hr;
1027 if ((hr = WsWriteStartElement( writer, NULL, name, ns, NULL )) != S_OK) return hr;
1028 if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, type, desc, option, value, size,
1029 NULL )) != S_OK) return hr;
1030 return WsWriteEndElement( writer, NULL );
1033 static HRESULT build_custom_header( WS_HEAP *heap, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1034 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
1035 ULONG size, struct header **ret )
1037 struct header *header;
1038 WS_XML_WRITER *writer;
1039 WS_XML_BUFFER *buf;
1040 HRESULT hr;
1042 if (!(header = alloc_header( 0, FALSE, name, ns ))) return E_OUTOFMEMORY;
1044 if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
1045 if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
1046 if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
1047 if ((hr = write_custom_header( writer, name, ns, type, desc, option, value, size )) != S_OK) goto done;
1049 header->u.buf = buf;
1051 done:
1052 if (hr != S_OK) free_header( header );
1053 else *ret = header;
1054 WsFreeWriter( writer );
1055 return hr;
1058 /**************************************************************************
1059 * WsAddCustomHeader [webservices.@]
1061 HRESULT WINAPI WsAddCustomHeader( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
1062 const void *value, ULONG size, ULONG attrs, WS_ERROR *error )
1064 struct msg *msg = (struct msg *)handle;
1065 struct header *header;
1066 HRESULT hr;
1068 TRACE( "%p %p %08x %p %u %08x %p\n", handle, desc, option, value, size, attrs, error );
1069 if (error) FIXME( "ignoring error parameter\n" );
1071 if (!handle || !desc) return E_INVALIDARG;
1072 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
1074 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) return hr;
1075 if ((hr = build_custom_header( msg->heap, desc->elementLocalName, desc->elementNs, desc->type,
1076 desc->typeDescription, option, value, size, &header )) != S_OK) return hr;
1078 msg->header[msg->header_count++] = header;
1079 return write_envelope( msg );
1082 /**************************************************************************
1083 * WsRemoveCustomHeader [webservices.@]
1085 HRESULT WINAPI WsRemoveCustomHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1086 WS_ERROR *error )
1088 struct msg *msg = (struct msg *)handle;
1089 BOOL removed = FALSE;
1090 ULONG i;
1092 TRACE( "%p %s %s %p\n", handle, debugstr_xmlstr(name), debugstr_xmlstr(ns), error );
1093 if (error) FIXME( "ignoring error parameter\n" );
1095 if (!handle || !name || !ns) return E_INVALIDARG;
1096 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
1098 for (i = 0; i < msg->header_count; i++)
1100 if (msg->header[i]->type || msg->header[i]->mapped) continue;
1101 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK &&
1102 WsXmlStringEquals( ns, &msg->header[i]->ns, NULL ) == S_OK)
1104 remove_header( msg, i );
1105 removed = TRUE;
1106 i--;
1110 if (removed) return write_envelope( msg );
1111 return S_OK;
1114 static WCHAR *build_http_header( const WCHAR *name, const WCHAR *value, ULONG *ret_len )
1116 static const WCHAR fmtW[] = {'%','s',':',' ','%','s',0};
1117 WCHAR *ret = heap_alloc( (strlenW(name) + strlenW(value) + 3) * sizeof(WCHAR) );
1118 if (ret) *ret_len = sprintfW( ret, fmtW, name, value );
1119 return ret;
1122 HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req )
1124 static const WCHAR contenttypeW[] =
1125 {'C','o','n','t','e','n','t','-','T','y','p','e',0};
1126 static const WCHAR soapxmlW[] =
1127 {'a','p','p','l','i','c','a','t','i','o','n','/','s','o','a','p','+','x','m','l',0};
1128 static const WCHAR textxmlW[] =
1129 {'t','e','x','t','/','x','m','l',0};
1130 static const WCHAR charsetW[] =
1131 {'c','h','a','r','s','e','t','=','u','t','f','-','8',0};
1132 struct msg *msg = (struct msg *)handle;
1133 WCHAR *header, *buf;
1134 ULONG len;
1135 BOOL ret;
1137 switch (msg->version_env)
1139 case WS_ENVELOPE_VERSION_SOAP_1_1:
1140 header = build_http_header( contenttypeW, textxmlW, &len );
1141 break;
1143 case WS_ENVELOPE_VERSION_SOAP_1_2:
1144 header = build_http_header( contenttypeW, soapxmlW, &len );
1145 break;
1147 default:
1148 FIXME( "unhandled envelope version %u\n", msg->version_env );
1149 return E_NOTIMPL;
1151 if (!header) return E_OUTOFMEMORY;
1153 ret = WinHttpAddRequestHeaders( req, header, len, WINHTTP_ADDREQ_FLAG_ADD );
1154 heap_free( header );
1155 if (!ret) return HRESULT_FROM_WIN32( GetLastError() );
1157 if (!(header = build_http_header( contenttypeW, charsetW, &len ))) return E_OUTOFMEMORY;
1158 ret = WinHttpAddRequestHeaders( req, header, len, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON );
1159 heap_free( header );
1160 if (!ret) return HRESULT_FROM_WIN32( GetLastError() );
1162 switch (msg->version_env)
1164 case WS_ENVELOPE_VERSION_SOAP_1_1:
1166 static const WCHAR soapactionW[] = {'S','O','A','P','A','c','t','i','o','n',0};
1168 if (!(len = msg->action.length)) break;
1169 if (!(buf = heap_alloc( (len + 3) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1170 buf[0] = '"';
1171 memcpy( buf + 1, msg->action.chars, len * sizeof(WCHAR) );
1172 buf[len + 1] = '"';
1173 buf[len + 2] = 0;
1174 header = build_http_header( soapactionW, buf, &len );
1175 heap_free( buf );
1176 if (!header) return E_OUTOFMEMORY;
1178 ret = WinHttpAddRequestHeaders( req, header, len, WINHTTP_ADDREQ_FLAG_ADD );
1179 heap_free( header );
1180 if (!ret) return HRESULT_FROM_WIN32( GetLastError() );
1181 break;
1183 case WS_ENVELOPE_VERSION_SOAP_1_2:
1185 static const WCHAR actionW[] = {'a','c','t','i','o','n','=','"'};
1186 ULONG len_action = sizeof(actionW)/sizeof(actionW[0]);
1188 if (!(len = msg->action.length)) break;
1189 if (!(buf = heap_alloc( (len + len_action + 2) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1190 memcpy( buf, actionW, len_action * sizeof(WCHAR) );
1191 memcpy( buf + len_action, msg->action.chars, len * sizeof(WCHAR) );
1192 len += len_action;
1193 buf[len++] = '"';
1194 buf[len] = 0;
1195 header = build_http_header( contenttypeW, buf, &len );
1196 heap_free( buf );
1197 if (!header) return E_OUTOFMEMORY;
1199 ret = WinHttpAddRequestHeaders( req, header, len, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON );
1200 heap_free( header );
1201 if (!ret) return HRESULT_FROM_WIN32( GetLastError() );
1202 break;
1204 default:
1205 FIXME( "unhandled envelope version %u\n", msg->version_env );
1206 return E_NOTIMPL;
1209 return S_OK;
1212 HRESULT message_set_action( WS_MESSAGE *handle, const WS_XML_STRING *action )
1214 struct msg *msg = (struct msg *)handle;
1215 WCHAR *chars;
1216 int len;
1218 if (!action || !action->length)
1220 heap_free( msg->action.chars );
1221 msg->action.chars = NULL;
1222 msg->action.length = 0;
1223 return S_OK;
1225 len = MultiByteToWideChar( CP_UTF8, 0, (char *)action->bytes, action->length, NULL, 0 );
1226 if (!(chars = heap_alloc( len * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1227 MultiByteToWideChar( CP_UTF8, 0, (char *)action->bytes, action->length, chars, len );
1229 heap_free( msg->action.chars );
1230 msg->action.chars = chars;
1231 msg->action.length = len;
1233 return S_OK;