webservices: Implement WsAddCustomHeader.
[wine.git] / dlls / webservices / msg.c
blobffe19f9cb898ba2ddf3b9f0cdcad7cc92b75a222
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_HEAP *heap;
75 WS_XML_BUFFER *buf;
76 WS_XML_WRITER *writer;
77 WS_XML_WRITER *writer_body;
78 ULONG header_count;
79 ULONG header_size;
80 struct header **header;
81 ULONG prop_count;
82 struct prop prop[sizeof(msg_props)/sizeof(msg_props[0])];
85 #define HEADER_ARRAY_SIZE 2
86 static struct msg *alloc_msg(void)
88 static const ULONG count = sizeof(msg_props)/sizeof(msg_props[0]);
89 struct msg *ret;
90 ULONG size = sizeof(*ret) + prop_size( msg_props, count );
92 if (!(ret = heap_alloc_zero( size ))) return NULL;
93 if (!(ret->header = heap_alloc( HEADER_ARRAY_SIZE * sizeof(struct header *) )))
95 heap_free( ret );
96 return NULL;
98 ret->state = WS_MESSAGE_STATE_EMPTY;
99 ret->header_size = HEADER_ARRAY_SIZE;
100 prop_init( msg_props, count, ret->prop, &ret[1] );
101 ret->prop_count = count;
102 return ret;
105 static void free_header( struct header *header )
107 heap_free( header->name.bytes );
108 heap_free( header->ns.bytes );
109 if (header->mapped) heap_free( header->u.text );
110 heap_free( header );
113 static void free_msg( struct msg *msg )
115 ULONG i;
116 if (!msg) return;
117 WsFreeWriter( msg->writer );
118 WsFreeHeap( msg->heap );
119 heap_free( msg->addr.chars );
120 for (i = 0; i < msg->header_count; i++) free_header( msg->header[i] );
121 heap_free( msg->header );
122 heap_free( msg );
125 #define HEAP_MAX_SIZE (1 << 16)
126 static HRESULT create_msg( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
127 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle )
129 struct msg *msg;
130 HRESULT hr;
131 ULONG i;
133 if (!(msg = alloc_msg())) return E_OUTOFMEMORY;
135 for (i = 0; i < count; i++)
137 if (properties[i].id == WS_MESSAGE_PROPERTY_ENVELOPE_VERSION ||
138 properties[i].id == WS_MESSAGE_PROPERTY_ADDRESSING_VERSION)
140 free_msg( msg );
141 return E_INVALIDARG;
143 hr = prop_set( msg->prop, msg->prop_count, properties[i].id, properties[i].value,
144 properties[i].valueSize );
145 if (hr != S_OK)
147 free_msg( msg );
148 return hr;
152 if ((hr = WsCreateHeap( HEAP_MAX_SIZE, 0, NULL, 0, &msg->heap, NULL )) != S_OK)
154 free_msg( msg );
155 return hr;
157 if ((hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &msg->buf, NULL )) != S_OK)
159 free_msg( msg );
160 return hr;
163 UuidCreate( &msg->id );
164 msg->version_env = env_version;
165 msg->version_addr = addr_version;
167 *handle = (WS_MESSAGE *)msg;
168 return S_OK;
171 /**************************************************************************
172 * WsCreateMessage [webservices.@]
174 HRESULT WINAPI WsCreateMessage( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
175 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle,
176 WS_ERROR *error )
178 TRACE( "%u %u %p %u %p %p\n", env_version, addr_version, properties, count, handle, error );
179 if (error) FIXME( "ignoring error parameter\n" );
181 if (!handle || !env_version || !addr_version) return E_INVALIDARG;
182 return create_msg( env_version, addr_version, properties, count, handle );
185 /**************************************************************************
186 * WsCreateMessageForChannel [webservices.@]
188 HRESULT WINAPI WsCreateMessageForChannel( WS_CHANNEL *channel_handle, const WS_MESSAGE_PROPERTY *properties,
189 ULONG count, WS_MESSAGE **handle, WS_ERROR *error )
191 WS_ENVELOPE_VERSION version_env;
192 WS_ADDRESSING_VERSION version_addr;
193 HRESULT hr;
195 TRACE( "%p %p %u %p %p\n", channel_handle, properties, count, handle, error );
196 if (error) FIXME( "ignoring error parameter\n" );
198 if (!channel_handle || !handle) return E_INVALIDARG;
200 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION, &version_env,
201 sizeof(version_env), NULL )) != S_OK || !version_env)
202 version_env = WS_ENVELOPE_VERSION_SOAP_1_2;
204 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ADDRESSING_VERSION, &version_addr,
205 sizeof(version_addr), NULL )) != S_OK || !version_addr)
206 version_addr = WS_ADDRESSING_VERSION_1_0;
208 return create_msg( version_env, version_addr, properties, count, handle );
211 /**************************************************************************
212 * WsFreeMessage [webservices.@]
214 void WINAPI WsFreeMessage( WS_MESSAGE *handle )
216 struct msg *msg = (struct msg *)handle;
218 TRACE( "%p\n", handle );
219 free_msg( msg );
222 /**************************************************************************
223 * WsGetMessageProperty [webservices.@]
225 HRESULT WINAPI WsGetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, void *buf,
226 ULONG size, WS_ERROR *error )
228 struct msg *msg = (struct msg *)handle;
230 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
231 if (error) FIXME( "ignoring error parameter\n" );
233 if (!handle) return E_INVALIDARG;
235 switch (id)
237 case WS_MESSAGE_PROPERTY_STATE:
238 if (!buf || size != sizeof(msg->state)) return E_INVALIDARG;
239 *(WS_MESSAGE_STATE *)buf = msg->state;
240 return S_OK;
242 case WS_MESSAGE_PROPERTY_HEAP:
243 if (!buf || size != sizeof(msg->heap)) return E_INVALIDARG;
244 *(WS_HEAP **)buf = msg->heap;
245 return S_OK;
247 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
248 if (!buf || size != sizeof(msg->version_env)) return E_INVALIDARG;
249 *(WS_ENVELOPE_VERSION *)buf = msg->version_env;
250 return S_OK;
252 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
253 if (!buf || size != sizeof(msg->version_addr)) return E_INVALIDARG;
254 *(WS_ADDRESSING_VERSION *)buf = msg->version_addr;
255 return S_OK;
257 case WS_MESSAGE_PROPERTY_HEADER_BUFFER:
258 if (!buf || size != sizeof(msg->buf)) return E_INVALIDARG;
259 *(WS_XML_BUFFER **)buf = msg->buf;
260 return S_OK;
262 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
263 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
264 *(BOOL *)buf = msg->is_addressed;
265 return S_OK;
267 default:
268 return prop_get( msg->prop, msg->prop_count, id, buf, size );
272 /**************************************************************************
273 * WsSetMessageProperty [webservices.@]
275 HRESULT WINAPI WsSetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, const void *value,
276 ULONG size, WS_ERROR *error )
278 struct msg *msg = (struct msg *)handle;
280 TRACE( "%p %u %p %u\n", handle, id, value, size );
281 if (error) FIXME( "ignoring error parameter\n" );
283 if (!handle) return E_INVALIDARG;
285 switch (id)
287 case WS_MESSAGE_PROPERTY_STATE:
288 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
289 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
290 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
291 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
292 return E_INVALIDARG;
294 default:
295 break;
297 return prop_set( msg->prop, msg->prop_count, id, value, size );
300 /**************************************************************************
301 * WsAddressMessage [webservices.@]
303 HRESULT WINAPI WsAddressMessage( WS_MESSAGE *handle, const WS_ENDPOINT_ADDRESS *addr, WS_ERROR *error )
305 struct msg *msg = (struct msg *)handle;
307 TRACE( "%p %p %p\n", handle, addr, error );
308 if (error) FIXME( "ignoring error parameter\n" );
309 if (addr && (addr->headers || addr->extensions || addr->identity))
311 FIXME( "headers, extensions or identity not supported\n" );
312 return E_NOTIMPL;
315 if (!handle) return E_INVALIDARG;
316 if (msg->state < WS_MESSAGE_STATE_INITIALIZED || msg->is_addressed) return WS_E_INVALID_OPERATION;
318 if (addr && addr->url.length)
320 if (!(msg->addr.chars = heap_alloc( addr->url.length * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
321 memcpy( msg->addr.chars, addr->url.chars, addr->url.length * sizeof(WCHAR) );
322 msg->addr.length = addr->url.length;
325 msg->is_addressed = TRUE;
326 return S_OK;
329 static HRESULT get_env_namespace( WS_ENVELOPE_VERSION ver, WS_XML_STRING *str )
331 switch (ver)
333 case WS_ENVELOPE_VERSION_SOAP_1_1:
334 str->bytes = (BYTE *)ns_env_1_1;
335 str->length = sizeof(ns_env_1_1)/sizeof(ns_env_1_1[0]) - 1;
336 return S_OK;
338 case WS_ENVELOPE_VERSION_SOAP_1_2:
339 str->bytes = (BYTE *)ns_env_1_2;
340 str->length = sizeof(ns_env_1_2)/sizeof(ns_env_1_2[0]) - 1;
341 return S_OK;
343 default:
344 ERR( "unhandled envelope version %u\n", ver );
345 return E_NOTIMPL;
349 static HRESULT get_addr_namespace( WS_ADDRESSING_VERSION ver, WS_XML_STRING *str )
351 switch (ver)
353 case WS_ADDRESSING_VERSION_0_9:
354 str->bytes = (BYTE *)ns_addr_0_9;
355 str->length = sizeof(ns_addr_0_9)/sizeof(ns_addr_0_9[0]) - 1;
356 return S_OK;
358 case WS_ADDRESSING_VERSION_1_0:
359 str->bytes = (BYTE *)ns_addr_1_0;
360 str->length = sizeof(ns_addr_1_0)/sizeof(ns_addr_1_0[0]) - 1;
361 return S_OK;
363 case WS_ADDRESSING_VERSION_TRANSPORT:
364 str->bytes = NULL;
365 str->length = 0;
366 return S_OK;
368 default:
369 ERR( "unhandled addressing version %u\n", ver );
370 return E_NOTIMPL;
374 static const WS_XML_STRING *get_header_name( WS_HEADER_TYPE type )
376 static const WS_XML_STRING action = {6, (BYTE *)"Action"}, to = {2, (BYTE *)"To"};
377 static const WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, relto = {9, (BYTE *)"RelatesTo"};
378 static const WS_XML_STRING from = {4, (BYTE *)"From"}, replyto = {7, (BYTE *)"ReplyTo"};
379 static const WS_XML_STRING faultto = {7, (BYTE *)"FaultTo"};
381 switch (type)
383 case WS_ACTION_HEADER: return &action;
384 case WS_TO_HEADER: return &to;
385 case WS_MESSAGE_ID_HEADER: return &msgid;
386 case WS_RELATES_TO_HEADER: return &relto;
387 case WS_FROM_HEADER: return &from;
388 case WS_REPLY_TO_HEADER: return &replyto;
389 case WS_FAULT_TO_HEADER: return &faultto;
390 default:
391 ERR( "unknown type %u\n", type );
392 return NULL;
396 static HRESULT write_envelope_start( struct msg *msg, WS_XML_WRITER *writer )
398 static const char anonymous[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
399 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
400 static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, header = {6, (BYTE *)"Header"};
401 static const WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, replyto = {7, (BYTE *)"ReplyTo"};
402 static const WS_XML_STRING address = {7, (BYTE *)"Address"}, body = {4, (BYTE *)"Body"};
403 WS_XML_STRING ns_env, ns_addr;
404 WS_XML_UTF8_TEXT urn, addr;
405 HRESULT hr;
406 ULONG i;
408 if ((hr = get_env_namespace( msg->version_env, &ns_env )) != S_OK) return hr;
409 if ((hr = get_addr_namespace( msg->version_addr, &ns_addr )) != S_OK) return hr;
411 if ((hr = WsWriteStartElement( writer, &prefix_s, &envelope, &ns_env, NULL )) != S_OK) return hr;
412 if (msg->version_addr < WS_ADDRESSING_VERSION_TRANSPORT &&
413 (hr = WsWriteXmlnsAttribute( writer, &prefix_a, &ns_addr, FALSE, NULL )) != S_OK) return hr;
414 if ((hr = WsWriteStartElement( writer, &prefix_s, &header, &ns_env, NULL )) != S_OK) return hr;
416 if (msg->version_addr < WS_ADDRESSING_VERSION_TRANSPORT)
418 if ((hr = WsWriteStartElement( writer, &prefix_a, &msgid, &ns_addr, NULL )) != S_OK) return hr;
419 urn.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
420 memcpy( &urn.value, &msg->id, sizeof(msg->id) );
421 if ((hr = WsWriteText( writer, &urn.text, NULL )) != S_OK) return hr;
422 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:MessageID> */
425 for (i = 0; i < msg->header_count; i++)
427 if (msg->header[i]->mapped) continue;
428 if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr;
431 if (msg->version_addr == WS_ADDRESSING_VERSION_0_9)
433 if ((hr = WsWriteStartElement( writer, &prefix_a, &replyto, &ns_addr, NULL )) != S_OK) return hr;
434 if ((hr = WsWriteStartElement( writer, &prefix_a, &address, &ns_addr, NULL )) != S_OK) return hr;
436 addr.text.textType = WS_XML_TEXT_TYPE_UTF8;
437 addr.value.bytes = (BYTE *)anonymous;
438 addr.value.length = sizeof(anonymous) - 1;
439 if ((hr = WsWriteText( writer, &addr.text, NULL )) != S_OK) return hr;
440 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:Address> */
441 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:ReplyTo> */
444 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </s:Header> */
445 return WsWriteStartElement( writer, &prefix_s, &body, &ns_env, NULL ); /* <s:Body> */
448 static HRESULT write_envelope_end( WS_XML_WRITER *writer )
450 HRESULT hr;
451 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </s:Body> */
452 return WsWriteEndElement( writer, NULL ); /* </s:Envelope> */
455 static HRESULT write_envelope( struct msg *msg )
457 HRESULT hr;
458 if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) return hr;
459 if (!msg->buf && (hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &msg->buf, NULL )) != S_OK) return hr;
460 if ((hr = WsSetOutputToBuffer( msg->writer, msg->buf, NULL, 0, NULL )) != S_OK) return hr;
461 if ((hr = write_envelope_start( msg, msg->writer )) != S_OK) return hr;
462 return write_envelope_end( msg->writer );
465 /**************************************************************************
466 * WsWriteEnvelopeStart [webservices.@]
468 HRESULT WINAPI WsWriteEnvelopeStart( WS_MESSAGE *handle, WS_XML_WRITER *writer,
469 WS_MESSAGE_DONE_CALLBACK cb, void *state, WS_ERROR *error )
471 struct msg *msg = (struct msg *)handle;
472 HRESULT hr;
474 TRACE( "%p %p %p %p %p\n", handle, writer, cb, state, error );
475 if (error) FIXME( "ignoring error parameter\n" );
476 if (cb)
478 FIXME( "callback not supported\n" );
479 return E_NOTIMPL;
482 if (!handle || !writer) return E_INVALIDARG;
483 if (msg->state != WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
485 if ((hr = write_envelope( msg )) != S_OK) return hr;
486 if ((hr = write_envelope_start( msg, writer )) != S_OK) return hr;
488 msg->writer_body = writer;
489 msg->state = WS_MESSAGE_STATE_WRITING;
490 return S_OK;
493 /**************************************************************************
494 * WsWriteEnvelopeEnd [webservices.@]
496 HRESULT WINAPI WsWriteEnvelopeEnd( WS_MESSAGE *handle, WS_ERROR *error )
498 struct msg *msg = (struct msg *)handle;
499 HRESULT hr;
501 TRACE( "%p %p\n", handle, error );
502 if (error) FIXME( "ignoring error parameter\n" );
504 if (!handle) return E_INVALIDARG;
505 if (msg->state != WS_MESSAGE_STATE_WRITING) return WS_E_INVALID_OPERATION;
507 if ((hr = write_envelope_end( msg->writer_body )) != S_OK) return hr;
509 msg->state = WS_MESSAGE_STATE_DONE;
510 return S_OK;
513 /**************************************************************************
514 * WsWriteBody [webservices.@]
516 HRESULT WINAPI WsWriteBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
517 const void *value, ULONG size, WS_ERROR *error )
519 struct msg *msg = (struct msg *)handle;
520 HRESULT hr;
522 TRACE( "%p %p %08x %p %u %p\n", handle, desc, option, value, size, error );
523 if (error) FIXME( "ignoring error parameter\n" );
525 if (!handle || !desc) return E_INVALIDARG;
526 if (msg->state != WS_MESSAGE_STATE_WRITING) return WS_E_INVALID_OPERATION;
528 if (desc->elementLocalName &&
529 (hr = WsWriteStartElement( msg->writer_body, NULL, desc->elementLocalName, desc->elementNs,
530 NULL )) != S_OK) return hr;
532 if ((hr = WsWriteType( msg->writer_body, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
533 option, value, size, NULL )) != S_OK) return hr;
535 if (desc->elementLocalName) hr = WsWriteEndElement( msg->writer_body, NULL );
536 return hr;
539 /**************************************************************************
540 * WsInitializeMessage [webservices.@]
542 HRESULT WINAPI WsInitializeMessage( WS_MESSAGE *handle, WS_MESSAGE_INITIALIZATION init,
543 WS_MESSAGE *src_handle, WS_ERROR *error )
545 struct msg *msg = (struct msg *)handle;
547 TRACE( "%p %u %p %p\n", handle, init, src_handle, error );
548 if (error) FIXME( "ignoring error parameter\n" );
549 if (src_handle)
551 FIXME( "src message not supported\n" );
552 return E_NOTIMPL;
555 if (!handle || init > WS_FAULT_MESSAGE) return E_INVALIDARG;
556 if (msg->state >= WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
558 msg->init = init;
559 msg->state = WS_MESSAGE_STATE_INITIALIZED;
560 return write_envelope( msg );
563 static HRESULT grow_header_array( struct msg *msg, ULONG size )
565 struct header **tmp;
566 if (size <= msg->header_size) return S_OK;
567 if (!(tmp = heap_realloc( msg->header, 2 * msg->header_size * sizeof(struct header *) )))
568 return E_OUTOFMEMORY;
569 msg->header = tmp;
570 msg->header_size *= 2;
571 return S_OK;
574 static struct header *alloc_header( WS_HEADER_TYPE type, BOOL mapped, const WS_XML_STRING *name,
575 const WS_XML_STRING *ns )
577 struct header *ret;
578 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
579 if (name && name->length)
581 if (!(ret->name.bytes = heap_alloc( name->length )))
583 free_header( ret );
584 return NULL;
586 memcpy( ret->name.bytes, name->bytes, name->length );
587 ret->name.length = name->length;
589 if (ns && ns->length)
591 if (!(ret->ns.bytes = heap_alloc( ns->length )))
593 free_header( ret );
594 return NULL;
596 memcpy( ret->ns.bytes, ns->bytes, ns->length );
597 ret->ns.length = ns->length;
599 ret->type = type;
600 ret->mapped = mapped;
601 return ret;
604 static HRESULT write_standard_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, WS_TYPE value_type,
605 WS_WRITE_OPTION option, const void *value, ULONG size )
607 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
608 static const WS_XML_STRING understand = {14, (BYTE *)"mustUnderstand"}, ns = {0, NULL};
609 WS_XML_INT32_TEXT one = {{WS_XML_TEXT_TYPE_INT32}, 1};
610 HRESULT hr;
612 if ((hr = WsWriteStartElement( writer, &prefix_a, name, &ns, NULL )) != S_OK) return hr;
613 if ((hr = WsWriteStartAttribute( writer, &prefix_s, &understand, &ns, FALSE, NULL )) != S_OK) return hr;
614 if ((hr = WsWriteText( writer, &one.text, NULL )) != S_OK) return hr;
615 if ((hr = WsWriteEndAttribute( writer, NULL )) != S_OK) return hr;
616 if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, value_type, NULL, option, value, size,
617 NULL )) != S_OK) return hr;
618 return WsWriteEndElement( writer, NULL );
621 static HRESULT build_standard_header( WS_HEAP *heap, WS_HEADER_TYPE type, WS_TYPE value_type,
622 WS_WRITE_OPTION option, const void *value, ULONG size,
623 struct header **ret )
625 const WS_XML_STRING *name = get_header_name( type );
626 struct header *header;
627 WS_XML_WRITER *writer;
628 WS_XML_BUFFER *buf;
629 HRESULT hr;
631 if (!(header = alloc_header( type, FALSE, name, NULL ))) return E_OUTOFMEMORY;
633 if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
634 if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
635 if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
636 if ((hr = write_standard_header( writer, name, value_type, option, value, size )) != S_OK)
637 goto done;
639 header->u.buf = buf;
641 done:
642 if (hr != S_OK) free_header( header );
643 else *ret = header;
644 WsFreeWriter( writer );
645 return hr;
648 /**************************************************************************
649 * WsSetHeader [webservices.@]
651 HRESULT WINAPI WsSetHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_TYPE value_type,
652 WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error )
654 struct msg *msg = (struct msg *)handle;
655 struct header *header;
656 BOOL found = FALSE;
657 HRESULT hr;
658 ULONG i;
660 TRACE( "%p %u %u %08x %p %u %p\n", handle, type, value_type, option, value, size, error );
661 if (error) FIXME( "ignoring error parameter\n" );
663 if (!handle || type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER) return E_INVALIDARG;
664 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
666 for (i = 0; i < msg->header_count; i++)
668 if (msg->header[i]->type == type)
670 found = TRUE;
671 break;
675 if (!found)
677 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) return hr;
678 i = msg->header_count;
681 if ((hr = build_standard_header( msg->heap, type, value_type, option, value, size, &header )) != S_OK)
682 return hr;
684 if (!found) msg->header_count++;
685 else free_header( msg->header[i] );
687 msg->header[i] = header;
688 return write_envelope( msg );
691 static void remove_header( struct msg *msg, ULONG i )
693 free_header( msg->header[i] );
694 memmove( &msg->header[i], &msg->header[i + 1], (msg->header_count - i) * sizeof(struct header *) );
695 msg->header_count--;
698 /**************************************************************************
699 * WsRemoveHeader [webservices.@]
701 HRESULT WINAPI WsRemoveHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_ERROR *error )
703 struct msg *msg = (struct msg *)handle;
704 BOOL removed = FALSE;
705 ULONG i;
707 TRACE( "%p %u %p\n", handle, type, error );
708 if (error) FIXME( "ignoring error parameter\n" );
710 if (!handle) return E_INVALIDARG;
711 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
712 if (type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER) return E_INVALIDARG;
714 for (i = 0; i < msg->header_count; i++)
716 if (msg->header[i]->type == type)
718 remove_header( msg, i );
719 removed = TRUE;
720 break;
724 if (removed) return write_envelope( msg );
725 return S_OK;
728 static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_WRITE_OPTION option,
729 const void *value, ULONG size, struct header **ret )
731 struct header *header;
733 if (!(header = alloc_header( 0, TRUE, name, NULL ))) return E_OUTOFMEMORY;
734 switch (type)
736 case WS_WSZ_TYPE:
738 int len;
739 const WCHAR *src;
741 if (option != WS_WRITE_REQUIRED_POINTER || size != sizeof(WCHAR *))
743 free_header( header );
744 return E_INVALIDARG;
746 src = *(const WCHAR **)value;
747 len = WideCharToMultiByte( CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL ) - 1;
748 if (!(header->u.text = alloc_xml_string( NULL, len )))
750 free_header( header );
751 return E_OUTOFMEMORY;
753 WideCharToMultiByte( CP_UTF8, 0, src, -1, (char *)header->u.text->bytes, len, NULL, NULL );
754 break;
756 case WS_XML_STRING_TYPE:
758 const WS_XML_STRING *str = value;
760 if (option != WS_WRITE_REQUIRED_VALUE)
762 FIXME( "unhandled write option %u\n", option );
763 free_header( header );
764 return E_NOTIMPL;
766 if (size != sizeof(*str))
768 free_header( header );
769 return E_INVALIDARG;
771 if (!(header->u.text = alloc_xml_string( NULL, str->length )))
773 free_header( header );
774 return E_OUTOFMEMORY;
776 memcpy( header->u.text->bytes, str->bytes, str->length );
777 break;
779 case WS_STRING_TYPE:
781 int len;
782 const WS_STRING *str = value;
784 if (option != WS_WRITE_REQUIRED_VALUE)
786 FIXME( "unhandled write option %u\n", option );
787 free_header( header );
788 return E_NOTIMPL;
790 if (size != sizeof(*str))
792 free_header( header );
793 return E_INVALIDARG;
795 len = WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, NULL, 0, NULL, NULL );
796 if (!(header->u.text = alloc_xml_string( NULL, len )))
798 free_header( header );
799 return E_OUTOFMEMORY;
801 WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, (char *)header->u.text->bytes,
802 len, NULL, NULL );
803 break;
805 default:
806 FIXME( "unhandled type %u\n", type );
807 free_header( header );
808 return E_NOTIMPL;
811 *ret = header;
812 return S_OK;
815 /**************************************************************************
816 * WsAddMappedHeader [webservices.@]
818 HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type,
819 WS_WRITE_OPTION option, const void *value, ULONG size , WS_ERROR *error )
821 struct msg *msg = (struct msg *)handle;
822 struct header *header;
823 BOOL found = FALSE;
824 HRESULT hr;
825 ULONG i;
827 TRACE( "%p %s %u %08x %p %u %p\n", handle, debugstr_xmlstr(name), type, option, value, size, error );
828 if (error) FIXME( "ignoring error parameter\n" );
830 if (!handle || !name) return E_INVALIDARG;
831 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
833 for (i = 0; i < msg->header_count; i++)
835 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
836 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
838 found = TRUE;
839 break;
843 if (!found)
845 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) return hr;
846 i = msg->header_count;
849 if ((hr = build_mapped_header( name, type, option, value, size, &header )) != S_OK) return hr;
851 if (!found) msg->header_count++;
852 else free_header( msg->header[i] );
854 msg->header[i] = header;
855 return S_OK;
858 /**************************************************************************
859 * WsRemoveMappedHeader [webservices.@]
861 HRESULT WINAPI WsRemoveMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_ERROR *error )
863 struct msg *msg = (struct msg *)handle;
864 ULONG i;
866 TRACE( "%p %s %p\n", handle, debugstr_xmlstr(name), error );
867 if (error) FIXME( "ignoring error parameter\n" );
869 if (!handle || !name) return E_INVALIDARG;
870 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
872 for (i = 0; i < msg->header_count; i++)
874 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
875 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
877 remove_header( msg, i );
878 break;
882 return S_OK;
885 static HRESULT write_custom_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, const WS_XML_STRING *ns,
886 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
887 ULONG size )
889 HRESULT hr;
890 if ((hr = WsWriteStartElement( writer, NULL, name, ns, NULL )) != S_OK) return hr;
891 if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, type, desc, option, value, size,
892 NULL )) != S_OK) return hr;
893 return WsWriteEndElement( writer, NULL );
896 static HRESULT build_custom_header( WS_HEAP *heap, const WS_XML_STRING *name, const WS_XML_STRING *ns,
897 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
898 ULONG size, struct header **ret )
900 struct header *header;
901 WS_XML_WRITER *writer;
902 WS_XML_BUFFER *buf;
903 HRESULT hr;
905 if (!(header = alloc_header( 0, FALSE, name, ns ))) return E_OUTOFMEMORY;
907 if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
908 if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
909 if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
910 if ((hr = write_custom_header( writer, name, ns, type, desc, option, value, size )) != S_OK) goto done;
912 header->u.buf = buf;
914 done:
915 if (hr != S_OK) free_header( header );
916 else *ret = header;
917 WsFreeWriter( writer );
918 return hr;
921 /**************************************************************************
922 * WsAddCustomHeader [webservices.@]
924 HRESULT WINAPI WsAddCustomHeader( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
925 const void *value, ULONG size, ULONG attrs, WS_ERROR *error )
927 struct msg *msg = (struct msg *)handle;
928 struct header *header;
929 BOOL found = FALSE;
930 HRESULT hr;
931 ULONG i;
933 TRACE( "%p %p %08x %p %u %08x %p\n", handle, desc, option, value, size, attrs, error );
934 if (error) FIXME( "ignoring error parameter\n" );
936 if (!handle || !desc) return E_INVALIDARG;
937 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) return WS_E_INVALID_OPERATION;
939 for (i = 0; i < msg->header_count; i++)
941 if (msg->header[i]->type || msg->header[i]->mapped) continue;
942 if (WsXmlStringEquals( desc->elementLocalName, &msg->header[i]->name, NULL ) &&
943 WsXmlStringEquals( desc->elementNs, &msg->header[i]->ns, NULL ) == S_OK)
945 found = TRUE;
946 break;
950 if (!found)
952 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) return hr;
953 i = msg->header_count;
956 if ((hr = build_custom_header( msg->heap, desc->elementLocalName, desc->elementNs, desc->type,
957 desc->typeDescription, option, value, size, &header )) != S_OK) return hr;
959 if (!found) msg->header_count++;
960 else free_header( msg->header[i] );
962 msg->header[i] = header;
963 return write_envelope( msg );