msvcrt: Stop at trylevel for ControlPc on target frame for non-consolidate unwinds.
[wine.git] / dlls / webservices / msg.c
blobac955bd4f13d3a22b99dc21cc5f3e535a1dcb4cc
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 ULONG magic;
68 CRITICAL_SECTION cs;
69 WS_MESSAGE_INITIALIZATION init;
70 WS_MESSAGE_STATE state;
71 GUID id;
72 WS_ENVELOPE_VERSION version_env;
73 WS_ADDRESSING_VERSION version_addr;
74 BOOL is_addressed;
75 WS_STRING addr;
76 WS_STRING action;
77 WS_HEAP *heap;
78 WS_XML_BUFFER *buf;
79 WS_XML_WRITER *writer;
80 WS_XML_WRITER *writer_body;
81 WS_XML_READER *reader_body;
82 ULONG header_count;
83 ULONG header_size;
84 struct header **header;
85 WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_send;
86 WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_receive;
87 ULONG prop_count;
88 struct prop prop[sizeof(msg_props)/sizeof(msg_props[0])];
91 #define MSG_MAGIC (('M' << 24) | ('E' << 16) | ('S' << 8) | 'S')
92 #define HEADER_ARRAY_SIZE 2
94 static struct msg *alloc_msg(void)
96 static const ULONG count = sizeof(msg_props)/sizeof(msg_props[0]);
97 struct msg *ret;
98 ULONG size = sizeof(*ret) + prop_size( msg_props, count );
100 if (!(ret = heap_alloc_zero( size ))) return NULL;
101 if (!(ret->header = heap_alloc( HEADER_ARRAY_SIZE * sizeof(struct header *) )))
103 heap_free( ret );
104 return NULL;
106 ret->magic = MSG_MAGIC;
107 ret->state = WS_MESSAGE_STATE_EMPTY;
108 ret->header_size = HEADER_ARRAY_SIZE;
110 InitializeCriticalSection( &ret->cs );
111 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": msg.cs");
113 prop_init( msg_props, count, ret->prop, &ret[1] );
114 ret->prop_count = count;
115 return ret;
118 static void free_header( struct header *header )
120 heap_free( header->name.bytes );
121 heap_free( header->ns.bytes );
122 if (header->mapped) heap_free( header->u.text );
123 heap_free( header );
126 static void reset_msg( struct msg *msg )
128 ULONG i;
130 msg->state = WS_MESSAGE_STATE_EMPTY;
131 msg->init = 0;
132 UuidCreate( &msg->id );
133 msg->is_addressed = FALSE;
134 heap_free( msg->addr.chars );
135 msg->addr.chars = NULL;
136 msg->addr.length = 0;
138 heap_free( msg->action.chars );
139 msg->action.chars = NULL;
140 msg->action.length = 0;
142 WsResetHeap( msg->heap, NULL );
143 msg->buf = NULL; /* allocated on msg->heap */
144 msg->writer_body = NULL; /* owned by caller */
145 msg->reader_body = NULL; /* owned by caller */
147 for (i = 0; i < msg->header_count; i++)
149 free_header( msg->header[i] );
150 msg->header[i] = NULL;
152 msg->header_count = 0;
154 memset( &msg->ctx_send, 0, sizeof(msg->ctx_send) );
155 memset( &msg->ctx_receive, 0, sizeof(msg->ctx_receive) );
158 static void free_msg( struct msg *msg )
160 reset_msg( msg );
162 WsFreeWriter( msg->writer );
163 WsFreeHeap( msg->heap );
164 heap_free( msg->header );
166 msg->cs.DebugInfo->Spare[0] = 0;
167 DeleteCriticalSection( &msg->cs );
168 heap_free( msg );
171 #define HEAP_MAX_SIZE (1 << 16)
172 static HRESULT create_msg( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
173 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle )
175 struct msg *msg;
176 HRESULT hr;
177 ULONG i;
179 if (!(msg = alloc_msg())) return E_OUTOFMEMORY;
181 for (i = 0; i < count; i++)
183 if (properties[i].id == WS_MESSAGE_PROPERTY_ENVELOPE_VERSION ||
184 properties[i].id == WS_MESSAGE_PROPERTY_ADDRESSING_VERSION)
186 free_msg( msg );
187 return E_INVALIDARG;
189 hr = prop_set( msg->prop, msg->prop_count, properties[i].id, properties[i].value,
190 properties[i].valueSize );
191 if (hr != S_OK)
193 free_msg( msg );
194 return hr;
198 if ((hr = WsCreateHeap( HEAP_MAX_SIZE, 0, NULL, 0, &msg->heap, NULL )) != S_OK)
200 free_msg( msg );
201 return hr;
204 UuidCreate( &msg->id );
205 msg->version_env = env_version;
206 msg->version_addr = addr_version;
208 *handle = (WS_MESSAGE *)msg;
209 return S_OK;
212 /**************************************************************************
213 * WsCreateMessage [webservices.@]
215 HRESULT WINAPI WsCreateMessage( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
216 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle,
217 WS_ERROR *error )
219 TRACE( "%u %u %p %u %p %p\n", env_version, addr_version, properties, count, handle, error );
220 if (error) FIXME( "ignoring error parameter\n" );
222 if (!handle || !env_version || !addr_version) return E_INVALIDARG;
223 return create_msg( env_version, addr_version, properties, count, handle );
226 /**************************************************************************
227 * WsCreateMessageForChannel [webservices.@]
229 HRESULT WINAPI WsCreateMessageForChannel( WS_CHANNEL *channel_handle, const WS_MESSAGE_PROPERTY *properties,
230 ULONG count, WS_MESSAGE **handle, WS_ERROR *error )
232 WS_ENVELOPE_VERSION version_env;
233 WS_ADDRESSING_VERSION version_addr;
234 HRESULT hr;
236 TRACE( "%p %p %u %p %p\n", channel_handle, properties, count, handle, error );
237 if (error) FIXME( "ignoring error parameter\n" );
239 if (!channel_handle || !handle) return E_INVALIDARG;
241 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION, &version_env,
242 sizeof(version_env), NULL )) != S_OK || !version_env)
243 version_env = WS_ENVELOPE_VERSION_SOAP_1_2;
245 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ADDRESSING_VERSION, &version_addr,
246 sizeof(version_addr), NULL )) != S_OK || !version_addr)
247 version_addr = WS_ADDRESSING_VERSION_1_0;
249 return create_msg( version_env, version_addr, properties, count, handle );
252 /**************************************************************************
253 * WsFreeMessage [webservices.@]
255 void WINAPI WsFreeMessage( WS_MESSAGE *handle )
257 struct msg *msg = (struct msg *)handle;
259 TRACE( "%p\n", handle );
261 if (!msg) return;
263 EnterCriticalSection( &msg->cs );
265 if (msg->magic != MSG_MAGIC)
267 LeaveCriticalSection( &msg->cs );
268 return;
271 msg->magic = 0;
273 LeaveCriticalSection( &msg->cs );
274 free_msg( msg );
277 /**************************************************************************
278 * WsResetMessage [webservices.@]
280 HRESULT WINAPI WsResetMessage( WS_MESSAGE *handle, WS_ERROR *error )
282 struct msg *msg = (struct msg *)handle;
284 TRACE( "%p %p\n", handle, error );
285 if (error) FIXME( "ignoring error parameter\n" );
287 if (!msg) return E_INVALIDARG;
289 EnterCriticalSection( &msg->cs );
291 if (msg->magic != MSG_MAGIC)
293 LeaveCriticalSection( &msg->cs );
294 return E_INVALIDARG;
297 reset_msg( msg );
299 LeaveCriticalSection( &msg->cs );
300 return S_OK;
303 /**************************************************************************
304 * WsGetMessageProperty [webservices.@]
306 HRESULT WINAPI WsGetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, void *buf,
307 ULONG size, WS_ERROR *error )
309 struct msg *msg = (struct msg *)handle;
310 HRESULT hr = S_OK;
312 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
313 if (error) FIXME( "ignoring error parameter\n" );
315 if (!msg) return E_INVALIDARG;
317 EnterCriticalSection( &msg->cs );
319 if (msg->magic != MSG_MAGIC)
321 LeaveCriticalSection( &msg->cs );
322 return E_INVALIDARG;
325 switch (id)
327 case WS_MESSAGE_PROPERTY_STATE:
328 if (!buf || size != sizeof(msg->state)) hr = E_INVALIDARG;
329 else *(WS_MESSAGE_STATE *)buf = msg->state;
330 break;
332 case WS_MESSAGE_PROPERTY_HEAP:
333 if (!buf || size != sizeof(msg->heap)) hr = E_INVALIDARG;
334 else *(WS_HEAP **)buf = msg->heap;
335 break;
337 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
338 if (!buf || size != sizeof(msg->version_env)) hr = E_INVALIDARG;
339 else *(WS_ENVELOPE_VERSION *)buf = msg->version_env;
340 break;
342 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
343 if (!buf || size != sizeof(msg->version_addr)) hr = E_INVALIDARG;
344 else *(WS_ADDRESSING_VERSION *)buf = msg->version_addr;
345 break;
347 case WS_MESSAGE_PROPERTY_HEADER_BUFFER:
348 if (!buf || size != sizeof(msg->buf)) hr = E_INVALIDARG;
349 else *(WS_XML_BUFFER **)buf = msg->buf;
350 break;
352 case WS_MESSAGE_PROPERTY_BODY_READER:
353 if (!buf || size != sizeof(msg->reader_body)) hr = E_INVALIDARG;
354 else *(WS_XML_READER **)buf = msg->reader_body;
355 break;
357 case WS_MESSAGE_PROPERTY_BODY_WRITER:
358 if (!buf || size != sizeof(msg->writer_body)) hr = E_INVALIDARG;
359 else *(WS_XML_WRITER **)buf = msg->writer_body;
360 break;
362 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
363 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) hr = WS_E_INVALID_OPERATION;
364 else *(BOOL *)buf = msg->is_addressed;
365 break;
367 default:
368 hr = prop_get( msg->prop, msg->prop_count, id, buf, size );
371 LeaveCriticalSection( &msg->cs );
372 return hr;
375 /**************************************************************************
376 * WsSetMessageProperty [webservices.@]
378 HRESULT WINAPI WsSetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, const void *value,
379 ULONG size, WS_ERROR *error )
381 struct msg *msg = (struct msg *)handle;
382 HRESULT hr;
384 TRACE( "%p %u %p %u\n", handle, id, value, size );
385 if (error) FIXME( "ignoring error parameter\n" );
387 if (!msg) return E_INVALIDARG;
389 EnterCriticalSection( &msg->cs );
391 if (msg->magic != MSG_MAGIC)
393 LeaveCriticalSection( &msg->cs );
394 return E_INVALIDARG;
397 switch (id)
399 case WS_MESSAGE_PROPERTY_STATE:
400 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
401 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
402 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
403 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) hr = WS_E_INVALID_OPERATION;
404 else hr = E_INVALIDARG;
405 break;
407 default:
408 hr = prop_set( msg->prop, msg->prop_count, id, value, size );
411 LeaveCriticalSection( &msg->cs );
412 return hr;
415 /**************************************************************************
416 * WsAddressMessage [webservices.@]
418 HRESULT WINAPI WsAddressMessage( WS_MESSAGE *handle, const WS_ENDPOINT_ADDRESS *addr, WS_ERROR *error )
420 struct msg *msg = (struct msg *)handle;
421 HRESULT hr = S_OK;
423 TRACE( "%p %p %p\n", handle, addr, error );
424 if (error) FIXME( "ignoring error parameter\n" );
425 if (addr && (addr->headers || addr->extensions || addr->identity))
427 FIXME( "headers, extensions or identity not supported\n" );
428 return E_NOTIMPL;
431 if (!msg) return E_INVALIDARG;
433 EnterCriticalSection( &msg->cs );
435 if (msg->magic != MSG_MAGIC)
437 LeaveCriticalSection( &msg->cs );
438 return E_INVALIDARG;
441 if (msg->state < WS_MESSAGE_STATE_INITIALIZED || msg->is_addressed)
443 LeaveCriticalSection( &msg->cs );
444 return WS_E_INVALID_OPERATION;
447 if (addr && addr->url.length)
449 if (!(msg->addr.chars = heap_alloc( addr->url.length * sizeof(WCHAR) ))) hr = E_OUTOFMEMORY;
450 else
452 memcpy( msg->addr.chars, addr->url.chars, addr->url.length * sizeof(WCHAR) );
453 msg->addr.length = addr->url.length;
457 if (hr == S_OK) msg->is_addressed = TRUE;
459 LeaveCriticalSection( &msg->cs );
460 return hr;
463 static HRESULT get_env_namespace( WS_ENVELOPE_VERSION ver, WS_XML_STRING *str )
465 switch (ver)
467 case WS_ENVELOPE_VERSION_SOAP_1_1:
468 str->bytes = (BYTE *)ns_env_1_1;
469 str->length = sizeof(ns_env_1_1)/sizeof(ns_env_1_1[0]) - 1;
470 return S_OK;
472 case WS_ENVELOPE_VERSION_SOAP_1_2:
473 str->bytes = (BYTE *)ns_env_1_2;
474 str->length = sizeof(ns_env_1_2)/sizeof(ns_env_1_2[0]) - 1;
475 return S_OK;
477 default:
478 ERR( "unhandled envelope version %u\n", ver );
479 return E_NOTIMPL;
483 static HRESULT get_addr_namespace( WS_ADDRESSING_VERSION ver, WS_XML_STRING *str )
485 switch (ver)
487 case WS_ADDRESSING_VERSION_0_9:
488 str->bytes = (BYTE *)ns_addr_0_9;
489 str->length = sizeof(ns_addr_0_9)/sizeof(ns_addr_0_9[0]) - 1;
490 return S_OK;
492 case WS_ADDRESSING_VERSION_1_0:
493 str->bytes = (BYTE *)ns_addr_1_0;
494 str->length = sizeof(ns_addr_1_0)/sizeof(ns_addr_1_0[0]) - 1;
495 return S_OK;
497 case WS_ADDRESSING_VERSION_TRANSPORT:
498 str->bytes = NULL;
499 str->length = 0;
500 return S_OK;
502 default:
503 ERR( "unhandled addressing version %u\n", ver );
504 return E_NOTIMPL;
508 static const WS_XML_STRING *get_header_name( WS_HEADER_TYPE type )
510 static const WS_XML_STRING headers[] =
512 {6, (BYTE *)"Action"},
513 {2, (BYTE *)"To"},
514 {9, (BYTE *)"MessageID"},
515 {9, (BYTE *)"RelatesTo"},
516 {4, (BYTE *)"From"},
517 {7, (BYTE *)"ReplyTo"},
518 {7, (BYTE *)"FaultTo"},
521 if (type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER)
523 ERR( "unknown type %u\n", type );
524 return NULL;
527 return &headers[type - 1];
530 static HRESULT write_headers( struct msg *msg, const WS_XML_STRING *ns_env, const WS_XML_STRING *ns_addr,
531 WS_XML_WRITER *writer )
533 static const char anonymous[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
534 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
535 static const WS_XML_STRING msgid = {9, (BYTE *)"MessageID"}, replyto = {7, (BYTE *)"ReplyTo"};
536 static const WS_XML_STRING address = {7, (BYTE *)"Address"}, header = {6, (BYTE *)"Header"};
537 WS_XML_UTF8_TEXT urn, addr;
538 HRESULT hr;
539 ULONG i;
541 if ((hr = WsWriteXmlnsAttribute( writer, &prefix_a, ns_addr, FALSE, NULL )) != S_OK) return hr;
542 if ((hr = WsWriteStartElement( writer, &prefix_s, &header, ns_env, NULL )) != S_OK) return hr;
544 if ((hr = WsWriteStartElement( writer, &prefix_a, &msgid, ns_addr, NULL )) != S_OK) return hr;
545 urn.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
546 memcpy( &urn.value, &msg->id, sizeof(msg->id) );
547 if ((hr = WsWriteText( writer, &urn.text, NULL )) != S_OK) return hr;
548 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:MessageID> */
550 if (msg->version_addr == WS_ADDRESSING_VERSION_0_9)
552 if ((hr = WsWriteStartElement( writer, &prefix_a, &replyto, ns_addr, NULL )) != S_OK) return hr;
553 if ((hr = WsWriteStartElement( writer, &prefix_a, &address, ns_addr, NULL )) != S_OK) return hr;
555 addr.text.textType = WS_XML_TEXT_TYPE_UTF8;
556 addr.value.bytes = (BYTE *)anonymous;
557 addr.value.length = sizeof(anonymous) - 1;
558 if ((hr = WsWriteText( writer, &addr.text, NULL )) != S_OK) return hr;
559 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:Address> */
560 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:ReplyTo> */
563 for (i = 0; i < msg->header_count; i++)
565 if (msg->header[i]->mapped) continue;
566 if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr;
569 return WsWriteEndElement( writer, NULL ); /* </s:Header> */
572 static HRESULT write_headers_transport( struct msg *msg, const WS_XML_STRING *ns_env, WS_XML_WRITER *writer )
574 static const WS_XML_STRING prefix = {1, (BYTE *)"s"}, header = {6, (BYTE *)"Header"};
575 HRESULT hr = S_OK;
576 ULONG i;
578 if ((msg->header_count || !msg->action.length) &&
579 (hr = WsWriteStartElement( writer, &prefix, &header, ns_env, NULL )) != S_OK) return hr;
581 for (i = 0; i < msg->header_count; i++)
583 if (msg->header[i]->mapped) continue;
584 if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr;
587 if (msg->header_count || !msg->action.length) hr = WsWriteEndElement( writer, NULL ); /* </s:Header> */
588 return hr;
591 static HRESULT write_envelope_start( struct msg *msg, WS_XML_WRITER *writer )
593 static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, body = {4, (BYTE *)"Body"};
594 static const WS_XML_STRING prefix = {1, (BYTE *)"s"};
595 WS_XML_STRING ns_env, ns_addr;
596 HRESULT hr;
598 if ((hr = get_env_namespace( msg->version_env, &ns_env )) != S_OK) return hr;
599 if ((hr = get_addr_namespace( msg->version_addr, &ns_addr )) != S_OK) return hr;
600 if ((hr = WsWriteStartElement( writer, &prefix, &envelope, &ns_env, NULL )) != S_OK) return hr;
602 if (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT)
603 hr = write_headers_transport( msg, &ns_env, writer );
604 else
605 hr = write_headers( msg, &ns_env, &ns_addr, writer );
606 if (hr != S_OK) return hr;
608 return WsWriteStartElement( writer, &prefix, &body, &ns_env, NULL ); /* <s:Body> */
611 static HRESULT write_envelope_end( WS_XML_WRITER *writer )
613 HRESULT hr;
614 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </s:Body> */
615 return WsWriteEndElement( writer, NULL ); /* </s:Envelope> */
618 static HRESULT write_envelope( struct msg *msg )
620 HRESULT hr;
621 if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) return hr;
622 if (!msg->buf && (hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &msg->buf, NULL )) != S_OK) return hr;
623 if ((hr = WsSetOutputToBuffer( msg->writer, msg->buf, NULL, 0, NULL )) != S_OK) return hr;
624 if ((hr = write_envelope_start( msg, msg->writer )) != S_OK) return hr;
625 return write_envelope_end( msg->writer );
628 /**************************************************************************
629 * WsWriteEnvelopeStart [webservices.@]
631 HRESULT WINAPI WsWriteEnvelopeStart( WS_MESSAGE *handle, WS_XML_WRITER *writer,
632 WS_MESSAGE_DONE_CALLBACK cb, void *state, WS_ERROR *error )
634 struct msg *msg = (struct msg *)handle;
635 HRESULT hr;
637 TRACE( "%p %p %p %p %p\n", handle, writer, cb, state, error );
638 if (error) FIXME( "ignoring error parameter\n" );
639 if (cb)
641 FIXME( "callback not supported\n" );
642 return E_NOTIMPL;
645 if (!msg || !writer) return E_INVALIDARG;
647 EnterCriticalSection( &msg->cs );
649 if (msg->magic != MSG_MAGIC)
651 LeaveCriticalSection( &msg->cs );
652 return E_INVALIDARG;
655 if (msg->state != WS_MESSAGE_STATE_INITIALIZED)
657 LeaveCriticalSection( &msg->cs );
658 return WS_E_INVALID_OPERATION;
661 if ((hr = write_envelope( msg )) != S_OK) goto done;
662 if ((hr = write_envelope_start( msg, writer )) != S_OK) goto done;
664 msg->writer_body = writer;
665 msg->state = WS_MESSAGE_STATE_WRITING;
667 done:
668 LeaveCriticalSection( &msg->cs );
669 return hr;
672 /**************************************************************************
673 * WsWriteEnvelopeEnd [webservices.@]
675 HRESULT WINAPI WsWriteEnvelopeEnd( WS_MESSAGE *handle, WS_ERROR *error )
677 struct msg *msg = (struct msg *)handle;
678 HRESULT hr;
680 TRACE( "%p %p\n", handle, error );
681 if (error) FIXME( "ignoring error parameter\n" );
683 if (!msg) return E_INVALIDARG;
685 EnterCriticalSection( &msg->cs );
687 if (msg->magic != MSG_MAGIC)
689 LeaveCriticalSection( &msg->cs );
690 return E_INVALIDARG;
693 if (msg->state != WS_MESSAGE_STATE_WRITING)
695 LeaveCriticalSection( &msg->cs );
696 return WS_E_INVALID_OPERATION;
699 if ((hr = write_envelope_end( msg->writer_body )) == S_OK) msg->state = WS_MESSAGE_STATE_DONE;
701 LeaveCriticalSection( &msg->cs );
702 return hr;
705 /**************************************************************************
706 * WsWriteBody [webservices.@]
708 HRESULT WINAPI WsWriteBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
709 const void *value, ULONG size, WS_ERROR *error )
711 struct msg *msg = (struct msg *)handle;
712 HRESULT hr;
714 TRACE( "%p %p %08x %p %u %p\n", handle, desc, option, value, size, error );
715 if (error) FIXME( "ignoring error parameter\n" );
717 if (!msg || !desc) return E_INVALIDARG;
719 EnterCriticalSection( &msg->cs );
721 if (msg->magic != MSG_MAGIC)
723 LeaveCriticalSection( &msg->cs );
724 return E_INVALIDARG;
727 if (msg->state != WS_MESSAGE_STATE_WRITING)
729 LeaveCriticalSection( &msg->cs );
730 return WS_E_INVALID_OPERATION;
733 if (desc->elementLocalName &&
734 (hr = WsWriteStartElement( msg->writer_body, NULL, desc->elementLocalName, desc->elementNs,
735 NULL )) != S_OK) goto done;
737 if ((hr = WsWriteType( msg->writer_body, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
738 option, value, size, NULL )) != S_OK) goto done;
740 if (desc->elementLocalName) hr = WsWriteEndElement( msg->writer_body, NULL );
742 done:
743 LeaveCriticalSection( &msg->cs );
744 return hr;
747 static BOOL match_current_element( WS_XML_READER *reader, const WS_XML_STRING *localname )
749 const WS_XML_NODE *node;
750 const WS_XML_ELEMENT_NODE *elem;
752 if (WsGetReaderNode( reader, &node, NULL ) != S_OK) return FALSE;
753 if (node->nodeType != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
754 elem = (const WS_XML_ELEMENT_NODE *)node;
755 return WsXmlStringEquals( elem->localName, localname, NULL ) == S_OK;
758 static HRESULT read_envelope_start( WS_XML_READER *reader )
760 static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, body = {4, (BYTE *)"Body"};
761 static const WS_XML_STRING header = {6, (BYTE *)"Header"};
762 HRESULT hr;
764 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
765 if (!match_current_element( reader, &envelope )) return WS_E_INVALID_FORMAT;
766 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
767 if (match_current_element( reader, &header ))
769 for (;;)
771 /* FIXME: store headers */
772 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
773 if (match_current_element( reader, &body )) break;
776 if (!match_current_element( reader, &body )) return WS_E_INVALID_FORMAT;
777 return WsReadNode( reader, NULL );
780 /**************************************************************************
781 * WsReadEnvelopeStart [webservices.@]
783 HRESULT WINAPI WsReadEnvelopeStart( WS_MESSAGE *handle, WS_XML_READER *reader, WS_MESSAGE_DONE_CALLBACK cb,
784 void *state, WS_ERROR *error )
786 struct msg *msg = (struct msg *)handle;
787 HRESULT hr;
789 TRACE( "%p %p %p %p %p\n", handle, reader, cb, state, error );
790 if (error) FIXME( "ignoring error parameter\n" );
791 if (cb)
793 FIXME( "callback not supported\n" );
794 return E_NOTIMPL;
797 if (!msg || !reader) return E_INVALIDARG;
799 EnterCriticalSection( &msg->cs );
801 if (msg->magic != MSG_MAGIC)
803 LeaveCriticalSection( &msg->cs );
804 return E_INVALIDARG;
807 if (msg->state != WS_MESSAGE_STATE_EMPTY)
809 LeaveCriticalSection( &msg->cs );
810 return WS_E_INVALID_OPERATION;
813 if ((hr = read_envelope_start( reader )) == S_OK)
815 msg->reader_body = reader;
816 msg->state = WS_MESSAGE_STATE_READING;
819 LeaveCriticalSection( &msg->cs );
820 return hr;
823 static HRESULT read_envelope_end( WS_XML_READER *reader )
825 HRESULT hr;
826 if ((hr = WsReadEndElement( reader, NULL )) != S_OK) return hr; /* </s:Body> */
827 return WsReadEndElement( reader, NULL ); /* </s:Envelope> */
830 /**************************************************************************
831 * WsReadEnvelopeEnd [webservices.@]
833 HRESULT WINAPI WsReadEnvelopeEnd( WS_MESSAGE *handle, WS_ERROR *error )
835 struct msg *msg = (struct msg *)handle;
836 HRESULT hr;
838 TRACE( "%p %p\n", handle, error );
839 if (error) FIXME( "ignoring error parameter\n" );
841 if (!msg) return E_INVALIDARG;
843 EnterCriticalSection( &msg->cs );
845 if (msg->magic != MSG_MAGIC)
847 LeaveCriticalSection( &msg->cs );
848 return E_INVALIDARG;
851 if (msg->state != WS_MESSAGE_STATE_READING)
853 LeaveCriticalSection( &msg->cs );
854 return WS_E_INVALID_OPERATION;
857 if ((hr = read_envelope_end( msg->reader_body )) == S_OK) msg->state = WS_MESSAGE_STATE_DONE;
859 LeaveCriticalSection( &msg->cs );
860 return hr;
863 /**************************************************************************
864 * WsReadBody [webservices.@]
866 HRESULT WINAPI WsReadBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_READ_OPTION option,
867 WS_HEAP *heap, void *value, ULONG size, WS_ERROR *error )
869 struct msg *msg = (struct msg *)handle;
870 HRESULT hr;
872 TRACE( "%p %p %08x %p %p %u %p\n", handle, desc, option, heap, value, size, error );
873 if (error) FIXME( "ignoring error parameter\n" );
875 if (!msg || !desc) return E_INVALIDARG;
877 EnterCriticalSection( &msg->cs );
879 if (msg->magic != MSG_MAGIC)
881 LeaveCriticalSection( &msg->cs );
882 return E_INVALIDARG;
885 if (msg->state != WS_MESSAGE_STATE_READING)
887 LeaveCriticalSection( &msg->cs );
888 return WS_E_INVALID_OPERATION;
891 hr = WsReadElement( msg->reader_body, desc, option, heap, value, size, NULL );
893 LeaveCriticalSection( &msg->cs );
894 return hr;
897 /**************************************************************************
898 * WsInitializeMessage [webservices.@]
900 HRESULT WINAPI WsInitializeMessage( WS_MESSAGE *handle, WS_MESSAGE_INITIALIZATION init,
901 WS_MESSAGE *src_handle, WS_ERROR *error )
903 struct msg *msg = (struct msg *)handle;
904 HRESULT hr;
906 TRACE( "%p %u %p %p\n", handle, init, src_handle, error );
907 if (error) FIXME( "ignoring error parameter\n" );
908 if (src_handle)
910 FIXME( "src message not supported\n" );
911 return E_NOTIMPL;
914 if (!msg || init > WS_FAULT_MESSAGE) return E_INVALIDARG;
916 EnterCriticalSection( &msg->cs );
918 if (msg->magic != MSG_MAGIC)
920 LeaveCriticalSection( &msg->cs );
921 return E_INVALIDARG;
924 if (msg->state >= WS_MESSAGE_STATE_INITIALIZED)
926 LeaveCriticalSection( &msg->cs );
927 return WS_E_INVALID_OPERATION;
930 if ((hr = write_envelope( msg )) == S_OK)
932 msg->init = init;
933 msg->state = WS_MESSAGE_STATE_INITIALIZED;
936 LeaveCriticalSection( &msg->cs );
937 return hr;
940 static HRESULT grow_header_array( struct msg *msg, ULONG size )
942 struct header **tmp;
943 if (size <= msg->header_size) return S_OK;
944 if (!(tmp = heap_realloc( msg->header, 2 * msg->header_size * sizeof(struct header *) )))
945 return E_OUTOFMEMORY;
946 msg->header = tmp;
947 msg->header_size *= 2;
948 return S_OK;
951 static struct header *alloc_header( WS_HEADER_TYPE type, BOOL mapped, const WS_XML_STRING *name,
952 const WS_XML_STRING *ns )
954 struct header *ret;
955 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
956 if (name && name->length)
958 if (!(ret->name.bytes = heap_alloc( name->length )))
960 free_header( ret );
961 return NULL;
963 memcpy( ret->name.bytes, name->bytes, name->length );
964 ret->name.length = name->length;
966 if (ns && ns->length)
968 if (!(ret->ns.bytes = heap_alloc( ns->length )))
970 free_header( ret );
971 return NULL;
973 memcpy( ret->ns.bytes, ns->bytes, ns->length );
974 ret->ns.length = ns->length;
976 ret->type = type;
977 ret->mapped = mapped;
978 return ret;
981 static HRESULT write_standard_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, WS_TYPE value_type,
982 WS_WRITE_OPTION option, const void *value, ULONG size )
984 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
985 static const WS_XML_STRING understand = {14, (BYTE *)"mustUnderstand"}, ns = {0, NULL};
986 WS_XML_INT32_TEXT one = {{WS_XML_TEXT_TYPE_INT32}, 1};
987 HRESULT hr;
989 if ((hr = WsWriteStartElement( writer, &prefix_a, name, &ns, NULL )) != S_OK) return hr;
990 if ((hr = WsWriteStartAttribute( writer, &prefix_s, &understand, &ns, FALSE, NULL )) != S_OK) return hr;
991 if ((hr = WsWriteText( writer, &one.text, NULL )) != S_OK) return hr;
992 if ((hr = WsWriteEndAttribute( writer, NULL )) != S_OK) return hr;
993 if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, value_type, NULL, option, value, size,
994 NULL )) != S_OK) return hr;
995 return WsWriteEndElement( writer, NULL );
998 static HRESULT build_standard_header( WS_HEAP *heap, WS_HEADER_TYPE type, WS_TYPE value_type,
999 WS_WRITE_OPTION option, const void *value, ULONG size,
1000 struct header **ret )
1002 const WS_XML_STRING *name = get_header_name( type );
1003 struct header *header;
1004 WS_XML_WRITER *writer;
1005 WS_XML_BUFFER *buf;
1006 HRESULT hr;
1008 if (!(header = alloc_header( type, FALSE, name, NULL ))) return E_OUTOFMEMORY;
1010 if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
1011 if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
1012 if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
1013 if ((hr = write_standard_header( writer, name, value_type, option, value, size )) != S_OK)
1014 goto done;
1016 header->u.buf = buf;
1018 done:
1019 if (hr != S_OK) free_header( header );
1020 else *ret = header;
1021 WsFreeWriter( writer );
1022 return hr;
1025 /**************************************************************************
1026 * WsSetHeader [webservices.@]
1028 HRESULT WINAPI WsSetHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_TYPE value_type,
1029 WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error )
1031 struct msg *msg = (struct msg *)handle;
1032 struct header *header;
1033 BOOL found = FALSE;
1034 HRESULT hr;
1035 ULONG i;
1037 TRACE( "%p %u %u %08x %p %u %p\n", handle, type, value_type, option, value, size, error );
1038 if (error) FIXME( "ignoring error parameter\n" );
1040 if (!msg || type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER) return E_INVALIDARG;
1042 EnterCriticalSection( &msg->cs );
1044 if (msg->magic != MSG_MAGIC)
1046 LeaveCriticalSection( &msg->cs );
1047 return E_INVALIDARG;
1050 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1052 LeaveCriticalSection( &msg->cs );
1053 return WS_E_INVALID_OPERATION;
1056 for (i = 0; i < msg->header_count; i++)
1058 if (msg->header[i]->type == type)
1060 found = TRUE;
1061 break;
1065 if (!found)
1067 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done;
1068 i = msg->header_count;
1071 if ((hr = build_standard_header( msg->heap, type, value_type, option, value, size, &header )) != S_OK)
1072 goto done;
1074 if (!found) msg->header_count++;
1075 else free_header( msg->header[i] );
1077 msg->header[i] = header;
1078 hr = write_envelope( msg );
1080 done:
1081 LeaveCriticalSection( &msg->cs );
1082 return hr;
1085 static void remove_header( struct msg *msg, ULONG i )
1087 free_header( msg->header[i] );
1088 memmove( &msg->header[i], &msg->header[i + 1], (msg->header_count - i - 1) * sizeof(struct header *) );
1089 msg->header_count--;
1092 /**************************************************************************
1093 * WsRemoveHeader [webservices.@]
1095 HRESULT WINAPI WsRemoveHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_ERROR *error )
1097 struct msg *msg = (struct msg *)handle;
1098 BOOL removed = FALSE;
1099 HRESULT hr = S_OK;
1100 ULONG i;
1102 TRACE( "%p %u %p\n", handle, type, error );
1103 if (error) FIXME( "ignoring error parameter\n" );
1105 if (!msg) return E_INVALIDARG;
1107 EnterCriticalSection( &msg->cs );
1109 if (msg->magic != MSG_MAGIC)
1111 LeaveCriticalSection( &msg->cs );
1112 return E_INVALIDARG;
1115 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1117 LeaveCriticalSection( &msg->cs );
1118 return WS_E_INVALID_OPERATION;
1121 if (type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER)
1123 LeaveCriticalSection( &msg->cs );
1124 return E_INVALIDARG;
1127 for (i = 0; i < msg->header_count; i++)
1129 if (msg->header[i]->type == type)
1131 remove_header( msg, i );
1132 removed = TRUE;
1133 break;
1137 if (removed) hr = write_envelope( msg );
1139 LeaveCriticalSection( &msg->cs );
1140 return hr;
1143 static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_WRITE_OPTION option,
1144 const void *value, ULONG size, struct header **ret )
1146 struct header *header;
1148 if (!(header = alloc_header( 0, TRUE, name, NULL ))) return E_OUTOFMEMORY;
1149 switch (type)
1151 case WS_WSZ_TYPE:
1153 int len;
1154 const WCHAR *src;
1156 if (option != WS_WRITE_REQUIRED_POINTER || size != sizeof(WCHAR *))
1158 free_header( header );
1159 return E_INVALIDARG;
1161 src = *(const WCHAR **)value;
1162 len = WideCharToMultiByte( CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL ) - 1;
1163 if (!(header->u.text = alloc_xml_string( NULL, len )))
1165 free_header( header );
1166 return E_OUTOFMEMORY;
1168 WideCharToMultiByte( CP_UTF8, 0, src, -1, (char *)header->u.text->bytes, len, NULL, NULL );
1169 break;
1171 case WS_XML_STRING_TYPE:
1173 const WS_XML_STRING *str = value;
1175 if (option != WS_WRITE_REQUIRED_VALUE)
1177 FIXME( "unhandled write option %u\n", option );
1178 free_header( header );
1179 return E_NOTIMPL;
1181 if (size != sizeof(*str))
1183 free_header( header );
1184 return E_INVALIDARG;
1186 if (!(header->u.text = alloc_xml_string( NULL, str->length )))
1188 free_header( header );
1189 return E_OUTOFMEMORY;
1191 memcpy( header->u.text->bytes, str->bytes, str->length );
1192 break;
1194 case WS_STRING_TYPE:
1196 int len;
1197 const WS_STRING *str = value;
1199 if (option != WS_WRITE_REQUIRED_VALUE)
1201 FIXME( "unhandled write option %u\n", option );
1202 free_header( header );
1203 return E_NOTIMPL;
1205 if (size != sizeof(*str))
1207 free_header( header );
1208 return E_INVALIDARG;
1210 len = WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, NULL, 0, NULL, NULL );
1211 if (!(header->u.text = alloc_xml_string( NULL, len )))
1213 free_header( header );
1214 return E_OUTOFMEMORY;
1216 WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, (char *)header->u.text->bytes,
1217 len, NULL, NULL );
1218 break;
1220 default:
1221 FIXME( "unhandled type %u\n", type );
1222 free_header( header );
1223 return E_NOTIMPL;
1226 *ret = header;
1227 return S_OK;
1230 /**************************************************************************
1231 * WsAddMappedHeader [webservices.@]
1233 HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type,
1234 WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error )
1236 struct msg *msg = (struct msg *)handle;
1237 struct header *header;
1238 BOOL found = FALSE;
1239 HRESULT hr;
1240 ULONG i;
1242 TRACE( "%p %s %u %08x %p %u %p\n", handle, debugstr_xmlstr(name), type, option, value, size, error );
1243 if (error) FIXME( "ignoring error parameter\n" );
1245 if (!msg || !name) return E_INVALIDARG;
1247 EnterCriticalSection( &msg->cs );
1249 if (msg->magic != MSG_MAGIC)
1251 LeaveCriticalSection( &msg->cs );
1252 return E_INVALIDARG;
1255 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1257 LeaveCriticalSection( &msg->cs );
1258 return WS_E_INVALID_OPERATION;
1261 for (i = 0; i < msg->header_count; i++)
1263 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
1264 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
1266 found = TRUE;
1267 break;
1271 if (!found)
1273 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done;
1274 i = msg->header_count;
1277 if ((hr = build_mapped_header( name, type, option, value, size, &header )) != S_OK) goto done;
1279 if (!found) msg->header_count++;
1280 else free_header( msg->header[i] );
1282 msg->header[i] = header;
1284 done:
1285 LeaveCriticalSection( &msg->cs );
1286 return hr;
1289 /**************************************************************************
1290 * WsRemoveMappedHeader [webservices.@]
1292 HRESULT WINAPI WsRemoveMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_ERROR *error )
1294 struct msg *msg = (struct msg *)handle;
1295 ULONG i;
1297 TRACE( "%p %s %p\n", handle, debugstr_xmlstr(name), error );
1298 if (error) FIXME( "ignoring error parameter\n" );
1300 if (!msg || !name) return E_INVALIDARG;
1302 EnterCriticalSection( &msg->cs );
1304 if (msg->magic != MSG_MAGIC)
1306 LeaveCriticalSection( &msg->cs );
1307 return E_INVALIDARG;
1310 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1312 LeaveCriticalSection( &msg->cs );
1313 return WS_E_INVALID_OPERATION;
1316 for (i = 0; i < msg->header_count; i++)
1318 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
1319 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
1321 remove_header( msg, i );
1322 break;
1326 LeaveCriticalSection( &msg->cs );
1327 return S_OK;
1330 static HRESULT write_custom_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1331 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
1332 ULONG size )
1334 HRESULT hr;
1335 if ((hr = WsWriteStartElement( writer, NULL, name, ns, NULL )) != S_OK) return hr;
1336 if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, type, desc, option, value, size,
1337 NULL )) != S_OK) return hr;
1338 return WsWriteEndElement( writer, NULL );
1341 static HRESULT build_custom_header( WS_HEAP *heap, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1342 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
1343 ULONG size, struct header **ret )
1345 struct header *header;
1346 WS_XML_WRITER *writer;
1347 WS_XML_BUFFER *buf;
1348 HRESULT hr;
1350 if (!(header = alloc_header( 0, FALSE, name, ns ))) return E_OUTOFMEMORY;
1352 if ((hr = WsCreateWriter( NULL, 0, &writer, NULL )) != S_OK) goto done;
1353 if ((hr = WsCreateXmlBuffer( heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
1354 if ((hr = WsSetOutputToBuffer( writer, buf, NULL, 0, NULL )) != S_OK) goto done;
1355 if ((hr = write_custom_header( writer, name, ns, type, desc, option, value, size )) != S_OK) goto done;
1357 header->u.buf = buf;
1359 done:
1360 if (hr != S_OK) free_header( header );
1361 else *ret = header;
1362 WsFreeWriter( writer );
1363 return hr;
1366 /**************************************************************************
1367 * WsAddCustomHeader [webservices.@]
1369 HRESULT WINAPI WsAddCustomHeader( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
1370 const void *value, ULONG size, ULONG attrs, WS_ERROR *error )
1372 struct msg *msg = (struct msg *)handle;
1373 struct header *header;
1374 HRESULT hr;
1376 TRACE( "%p %p %08x %p %u %08x %p\n", handle, desc, option, value, size, attrs, error );
1377 if (error) FIXME( "ignoring error parameter\n" );
1379 if (!msg || !desc) return E_INVALIDARG;
1381 EnterCriticalSection( &msg->cs );
1383 if (msg->magic != MSG_MAGIC)
1385 LeaveCriticalSection( &msg->cs );
1386 return E_INVALIDARG;
1389 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1391 LeaveCriticalSection( &msg->cs );
1392 return WS_E_INVALID_OPERATION;
1395 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done;
1396 if ((hr = build_custom_header( msg->heap, desc->elementLocalName, desc->elementNs, desc->type,
1397 desc->typeDescription, option, value, size, &header )) != S_OK) goto done;
1398 msg->header[msg->header_count++] = header;
1399 hr = write_envelope( msg );
1401 done:
1402 LeaveCriticalSection( &msg->cs );
1403 return hr;
1406 /**************************************************************************
1407 * WsRemoveCustomHeader [webservices.@]
1409 HRESULT WINAPI WsRemoveCustomHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1410 WS_ERROR *error )
1412 struct msg *msg = (struct msg *)handle;
1413 BOOL removed = FALSE;
1414 HRESULT hr = S_OK;
1415 ULONG i;
1417 TRACE( "%p %s %s %p\n", handle, debugstr_xmlstr(name), debugstr_xmlstr(ns), error );
1418 if (error) FIXME( "ignoring error parameter\n" );
1420 if (!msg || !name || !ns) return E_INVALIDARG;
1422 EnterCriticalSection( &msg->cs );
1424 if (msg->magic != MSG_MAGIC)
1426 LeaveCriticalSection( &msg->cs );
1427 return E_INVALIDARG;
1430 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1432 LeaveCriticalSection( &msg->cs );
1433 return WS_E_INVALID_OPERATION;
1436 for (i = 0; i < msg->header_count; i++)
1438 if (msg->header[i]->type || msg->header[i]->mapped) continue;
1439 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK &&
1440 WsXmlStringEquals( ns, &msg->header[i]->ns, NULL ) == S_OK)
1442 remove_header( msg, i );
1443 removed = TRUE;
1444 i--;
1448 if (removed) hr = write_envelope( msg );
1450 LeaveCriticalSection( &msg->cs );
1451 return hr;
1454 static WCHAR *build_http_header( const WCHAR *name, const WCHAR *value, ULONG *ret_len )
1456 static const WCHAR fmtW[] = {'%','s',':',' ','%','s',0};
1457 WCHAR *ret = heap_alloc( (strlenW(name) + strlenW(value) + 3) * sizeof(WCHAR) );
1458 if (ret) *ret_len = sprintfW( ret, fmtW, name, value );
1459 return ret;
1462 static inline HRESULT insert_http_header( HINTERNET req, const WCHAR *header, ULONG len, ULONG flags )
1464 if (WinHttpAddRequestHeaders( req, header, len, flags )) return S_OK;
1465 return HRESULT_FROM_WIN32( GetLastError() );
1468 HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req )
1470 static const WCHAR contenttypeW[] =
1471 {'C','o','n','t','e','n','t','-','T','y','p','e',0};
1472 static const WCHAR soapxmlW[] =
1473 {'a','p','p','l','i','c','a','t','i','o','n','/','s','o','a','p','+','x','m','l',0};
1474 static const WCHAR textxmlW[] =
1475 {'t','e','x','t','/','x','m','l',0};
1476 static const WCHAR charsetW[] =
1477 {'c','h','a','r','s','e','t','=','u','t','f','-','8',0};
1478 struct msg *msg = (struct msg *)handle;
1479 HRESULT hr = E_OUTOFMEMORY;
1480 WCHAR *header = NULL, *buf;
1481 ULONG len;
1483 EnterCriticalSection( &msg->cs );
1485 if (msg->magic != MSG_MAGIC)
1487 LeaveCriticalSection( &msg->cs );
1488 return E_INVALIDARG;
1491 switch (msg->version_env)
1493 case WS_ENVELOPE_VERSION_SOAP_1_1:
1494 header = build_http_header( contenttypeW, textxmlW, &len );
1495 break;
1497 case WS_ENVELOPE_VERSION_SOAP_1_2:
1498 header = build_http_header( contenttypeW, soapxmlW, &len );
1499 break;
1501 default:
1502 FIXME( "unhandled envelope version %u\n", msg->version_env );
1503 hr = E_NOTIMPL;
1505 if (!header) goto done;
1507 if ((hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_ADD )) != S_OK) goto done;
1508 heap_free( header );
1510 hr = E_OUTOFMEMORY;
1511 if (!(header = build_http_header( contenttypeW, charsetW, &len ))) goto done;
1512 if ((hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON )) != S_OK)
1513 goto done;
1514 heap_free( header );
1515 header = NULL;
1517 switch (msg->version_env)
1519 case WS_ENVELOPE_VERSION_SOAP_1_1:
1521 static const WCHAR soapactionW[] = {'S','O','A','P','A','c','t','i','o','n',0};
1523 if (!(len = msg->action.length)) break;
1525 hr = E_OUTOFMEMORY;
1526 if (!(buf = heap_alloc( (len + 3) * sizeof(WCHAR) ))) goto done;
1527 buf[0] = '"';
1528 memcpy( buf + 1, msg->action.chars, len * sizeof(WCHAR) );
1529 buf[len + 1] = '"';
1530 buf[len + 2] = 0;
1532 header = build_http_header( soapactionW, buf, &len );
1533 heap_free( buf );
1534 if (!header) goto done;
1536 hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_ADD );
1537 break;
1539 case WS_ENVELOPE_VERSION_SOAP_1_2:
1541 static const WCHAR actionW[] = {'a','c','t','i','o','n','=','"'};
1542 ULONG len_action = sizeof(actionW)/sizeof(actionW[0]);
1544 if (!(len = msg->action.length)) break;
1546 hr = E_OUTOFMEMORY;
1547 if (!(buf = heap_alloc( (len + len_action + 2) * sizeof(WCHAR) ))) goto done;
1548 memcpy( buf, actionW, len_action * sizeof(WCHAR) );
1549 memcpy( buf + len_action, msg->action.chars, len * sizeof(WCHAR) );
1550 len += len_action;
1551 buf[len++] = '"';
1552 buf[len] = 0;
1554 header = build_http_header( contenttypeW, buf, &len );
1555 heap_free( buf );
1556 if (!header) goto done;
1558 hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON );
1559 break;
1561 default:
1562 FIXME( "unhandled envelope version %u\n", msg->version_env );
1563 hr = E_NOTIMPL;
1566 done:
1567 heap_free( header );
1568 LeaveCriticalSection( &msg->cs );
1569 return hr;
1572 void message_set_send_context( WS_MESSAGE *handle, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT *ctx )
1574 struct msg *msg = (struct msg *)handle;
1576 EnterCriticalSection( &msg->cs );
1578 if (msg->magic != MSG_MAGIC)
1580 LeaveCriticalSection( &msg->cs );
1581 return;
1584 msg->ctx_send.callback = ctx->callback;
1585 msg->ctx_send.state = ctx->state;
1587 LeaveCriticalSection( &msg->cs );
1590 void message_set_receive_context( WS_MESSAGE *handle, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT *ctx )
1592 struct msg *msg = (struct msg *)handle;
1594 EnterCriticalSection( &msg->cs );
1596 if (msg->magic != MSG_MAGIC)
1598 LeaveCriticalSection( &msg->cs );
1599 return;
1602 msg->ctx_receive.callback = ctx->callback;
1603 msg->ctx_receive.state = ctx->state;
1605 LeaveCriticalSection( &msg->cs );
1608 void message_do_send_callback( WS_MESSAGE *handle )
1610 struct msg *msg = (struct msg *)handle;
1612 EnterCriticalSection( &msg->cs );
1614 if (msg->magic != MSG_MAGIC)
1616 LeaveCriticalSection( &msg->cs );
1617 return;
1620 if (msg->ctx_send.callback)
1622 HRESULT hr;
1623 TRACE( "executing callback %p\n", msg->ctx_send.callback );
1624 hr = msg->ctx_send.callback( handle, msg->heap, msg->ctx_send.state, NULL );
1625 TRACE( "callback %p returned %08x\n", msg->ctx_send.callback, hr );
1628 LeaveCriticalSection( &msg->cs );
1631 void message_do_receive_callback( WS_MESSAGE *handle )
1633 struct msg *msg = (struct msg *)handle;
1635 EnterCriticalSection( &msg->cs );
1637 if (msg->magic != MSG_MAGIC)
1639 LeaveCriticalSection( &msg->cs );
1640 return;
1643 if (msg->ctx_receive.callback)
1645 HRESULT hr;
1646 TRACE( "executing callback %p\n", msg->ctx_receive.callback );
1647 hr = msg->ctx_receive.callback( handle, msg->heap, msg->ctx_receive.state, NULL );
1648 TRACE( "callback %p returned %08x\n", msg->ctx_receive.callback, hr );
1651 LeaveCriticalSection( &msg->cs );
1654 HRESULT message_set_action( WS_MESSAGE *handle, const WS_XML_STRING *action )
1656 struct msg *msg = (struct msg *)handle;
1657 HRESULT hr = S_OK;
1659 EnterCriticalSection( &msg->cs );
1661 if (msg->magic != MSG_MAGIC)
1663 LeaveCriticalSection( &msg->cs );
1664 return E_INVALIDARG;
1667 if (!action || !action->length)
1669 heap_free( msg->action.chars );
1670 msg->action.chars = NULL;
1671 msg->action.length = 0;
1673 else
1675 WCHAR *chars;
1676 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)action->bytes, action->length, NULL, 0 );
1677 if (!(chars = heap_alloc( len * sizeof(WCHAR) ))) hr = E_OUTOFMEMORY;
1678 else
1680 MultiByteToWideChar( CP_UTF8, 0, (char *)action->bytes, action->length, chars, len );
1681 heap_free( msg->action.chars );
1682 msg->action.chars = chars;
1683 msg->action.length = len;
1687 LeaveCriticalSection( &msg->cs );
1688 return hr;