webservices: Fixed memory leak in build_custom_header (Coverity).
[wine.git] / dlls / webservices / msg.c
blob1b5ec0413719323b338e99aaa686072d5535abd3
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 struct prop_desc msg_props[] =
36 { sizeof(WS_MESSAGE_STATE), TRUE }, /* WS_MESSAGE_PROPERTY_STATE */
37 { sizeof(WS_HEAP *), TRUE }, /* WS_MESSAGE_PROPERTY_HEAP */
38 { sizeof(WS_ENVELOPE_VERSION), TRUE }, /* WS_MESSAGE_PROPERTY_ENVELOPE_VERSION */
39 { sizeof(WS_ADDRESSING_VERSION), TRUE }, /* WS_MESSAGE_PROPERTY_ADDRESSING_VERSION */
40 { sizeof(WS_XML_BUFFER *), TRUE }, /* WS_MESSAGE_PROPERTY_HEADER_BUFFER */
41 { sizeof(WS_XML_NODE_POSITION *), TRUE }, /* WS_MESSAGE_PROPERTY_HEADER_POSITION */
42 { sizeof(WS_XML_READER *), TRUE }, /* WS_MESSAGE_PROPERTY_BODY_READER */
43 { sizeof(WS_XML_WRITER *), TRUE }, /* WS_MESSAGE_PROPERTY_BODY_WRITER */
44 { sizeof(BOOL), TRUE }, /* WS_MESSAGE_PROPERTY_IS_ADDRESSED */
47 struct header
49 WS_HEADER_TYPE type;
50 BOOL mapped;
51 WS_XML_STRING name;
52 WS_XML_STRING ns;
53 union
55 WS_XML_BUFFER *buf;
56 WS_XML_STRING *text;
57 } u;
60 struct msg
62 ULONG magic;
63 CRITICAL_SECTION cs;
64 WS_MESSAGE_INITIALIZATION init;
65 WS_MESSAGE_STATE state;
66 GUID id;
67 WS_ENVELOPE_VERSION version_env;
68 WS_ADDRESSING_VERSION version_addr;
69 BOOL is_addressed;
70 WS_STRING addr;
71 WS_STRING action;
72 WS_HEAP *heap;
73 WS_XML_BUFFER *buf;
74 WS_XML_WRITER *writer;
75 WS_XML_WRITER *writer_body;
76 WS_XML_READER *reader;
77 WS_XML_READER *reader_body;
78 ULONG header_count;
79 ULONG header_size;
80 struct header **header;
81 WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_send;
82 WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_receive;
83 ULONG prop_count;
84 struct prop prop[sizeof(msg_props)/sizeof(msg_props[0])];
87 #define MSG_MAGIC (('M' << 24) | ('E' << 16) | ('S' << 8) | 'S')
88 #define HEADER_ARRAY_SIZE 2
90 static struct msg *alloc_msg(void)
92 static const ULONG count = sizeof(msg_props)/sizeof(msg_props[0]);
93 struct msg *ret;
94 ULONG size = sizeof(*ret) + prop_size( msg_props, count );
96 if (!(ret = heap_alloc_zero( size ))) return NULL;
97 if (!(ret->header = heap_alloc( HEADER_ARRAY_SIZE * sizeof(struct header *) )))
99 heap_free( ret );
100 return NULL;
102 ret->magic = MSG_MAGIC;
103 ret->state = WS_MESSAGE_STATE_EMPTY;
104 ret->header_size = HEADER_ARRAY_SIZE;
106 InitializeCriticalSection( &ret->cs );
107 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": msg.cs");
109 prop_init( msg_props, count, ret->prop, &ret[1] );
110 ret->prop_count = count;
111 return ret;
114 static void free_header( struct header *header )
116 heap_free( header->name.bytes );
117 heap_free( header->ns.bytes );
118 if (header->mapped) free_xml_string( header->u.text );
119 heap_free( header );
122 static void reset_msg( struct msg *msg )
124 ULONG i;
126 msg->state = WS_MESSAGE_STATE_EMPTY;
127 msg->init = 0;
128 UuidCreate( &msg->id );
129 msg->is_addressed = FALSE;
130 heap_free( msg->addr.chars );
131 msg->addr.chars = NULL;
132 msg->addr.length = 0;
134 heap_free( msg->action.chars );
135 msg->action.chars = NULL;
136 msg->action.length = 0;
138 WsResetHeap( msg->heap, NULL );
139 msg->buf = NULL; /* allocated on msg->heap */
140 msg->writer_body = NULL; /* owned by caller */
141 msg->reader_body = NULL; /* owned by caller */
143 for (i = 0; i < msg->header_count; i++)
145 free_header( msg->header[i] );
146 msg->header[i] = NULL;
148 msg->header_count = 0;
150 memset( &msg->ctx_send, 0, sizeof(msg->ctx_send) );
151 memset( &msg->ctx_receive, 0, sizeof(msg->ctx_receive) );
154 static void free_msg( struct msg *msg )
156 reset_msg( msg );
158 WsFreeWriter( msg->writer );
159 WsFreeReader( msg->reader );
160 WsFreeHeap( msg->heap );
161 heap_free( msg->header );
163 msg->cs.DebugInfo->Spare[0] = 0;
164 DeleteCriticalSection( &msg->cs );
165 heap_free( msg );
168 #define HEAP_MAX_SIZE (1 << 16)
169 static HRESULT create_msg( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
170 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle )
172 struct msg *msg;
173 HRESULT hr;
174 ULONG i;
176 if (!(msg = alloc_msg())) return E_OUTOFMEMORY;
178 for (i = 0; i < count; i++)
180 if (properties[i].id == WS_MESSAGE_PROPERTY_ENVELOPE_VERSION ||
181 properties[i].id == WS_MESSAGE_PROPERTY_ADDRESSING_VERSION)
183 free_msg( msg );
184 return E_INVALIDARG;
186 hr = prop_set( msg->prop, msg->prop_count, properties[i].id, properties[i].value,
187 properties[i].valueSize );
188 if (hr != S_OK)
190 free_msg( msg );
191 return hr;
195 if ((hr = WsCreateHeap( HEAP_MAX_SIZE, 0, NULL, 0, &msg->heap, NULL )) != S_OK)
197 free_msg( msg );
198 return hr;
201 UuidCreate( &msg->id );
202 msg->version_env = env_version;
203 msg->version_addr = addr_version;
205 *handle = (WS_MESSAGE *)msg;
206 return S_OK;
209 /**************************************************************************
210 * WsCreateMessage [webservices.@]
212 HRESULT WINAPI WsCreateMessage( WS_ENVELOPE_VERSION env_version, WS_ADDRESSING_VERSION addr_version,
213 const WS_MESSAGE_PROPERTY *properties, ULONG count, WS_MESSAGE **handle,
214 WS_ERROR *error )
216 TRACE( "%u %u %p %u %p %p\n", env_version, addr_version, properties, count, handle, error );
217 if (error) FIXME( "ignoring error parameter\n" );
219 if (!handle || !env_version || !addr_version ||
220 (env_version == WS_ENVELOPE_VERSION_NONE && addr_version != WS_ADDRESSING_VERSION_TRANSPORT))
222 return E_INVALIDARG;
224 return create_msg( env_version, addr_version, properties, count, handle );
227 /**************************************************************************
228 * WsCreateMessageForChannel [webservices.@]
230 HRESULT WINAPI WsCreateMessageForChannel( WS_CHANNEL *channel_handle, const WS_MESSAGE_PROPERTY *properties,
231 ULONG count, WS_MESSAGE **handle, WS_ERROR *error )
233 WS_ENVELOPE_VERSION version_env;
234 WS_ADDRESSING_VERSION version_addr;
235 HRESULT hr;
237 TRACE( "%p %p %u %p %p\n", channel_handle, properties, count, handle, error );
238 if (error) FIXME( "ignoring error parameter\n" );
240 if (!channel_handle || !handle) return E_INVALIDARG;
242 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION, &version_env,
243 sizeof(version_env), NULL )) != S_OK || !version_env)
244 version_env = WS_ENVELOPE_VERSION_SOAP_1_2;
246 if ((hr = WsGetChannelProperty( channel_handle, WS_CHANNEL_PROPERTY_ADDRESSING_VERSION, &version_addr,
247 sizeof(version_addr), NULL )) != S_OK || !version_addr)
248 version_addr = WS_ADDRESSING_VERSION_1_0;
250 return create_msg( version_env, version_addr, properties, count, handle );
253 /**************************************************************************
254 * WsFreeMessage [webservices.@]
256 void WINAPI WsFreeMessage( WS_MESSAGE *handle )
258 struct msg *msg = (struct msg *)handle;
260 TRACE( "%p\n", handle );
262 if (!msg) return;
264 EnterCriticalSection( &msg->cs );
266 if (msg->magic != MSG_MAGIC)
268 LeaveCriticalSection( &msg->cs );
269 return;
272 msg->magic = 0;
274 LeaveCriticalSection( &msg->cs );
275 free_msg( msg );
278 /**************************************************************************
279 * WsResetMessage [webservices.@]
281 HRESULT WINAPI WsResetMessage( WS_MESSAGE *handle, WS_ERROR *error )
283 struct msg *msg = (struct msg *)handle;
285 TRACE( "%p %p\n", handle, error );
286 if (error) FIXME( "ignoring error parameter\n" );
288 if (!msg) return E_INVALIDARG;
290 EnterCriticalSection( &msg->cs );
292 if (msg->magic != MSG_MAGIC)
294 LeaveCriticalSection( &msg->cs );
295 return E_INVALIDARG;
298 reset_msg( msg );
300 LeaveCriticalSection( &msg->cs );
301 return S_OK;
304 /**************************************************************************
305 * WsGetMessageProperty [webservices.@]
307 HRESULT WINAPI WsGetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, void *buf,
308 ULONG size, WS_ERROR *error )
310 struct msg *msg = (struct msg *)handle;
311 HRESULT hr = S_OK;
313 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
314 if (error) FIXME( "ignoring error parameter\n" );
316 if (!msg) return E_INVALIDARG;
318 EnterCriticalSection( &msg->cs );
320 if (msg->magic != MSG_MAGIC)
322 LeaveCriticalSection( &msg->cs );
323 return E_INVALIDARG;
326 switch (id)
328 case WS_MESSAGE_PROPERTY_STATE:
329 if (!buf || size != sizeof(msg->state)) hr = E_INVALIDARG;
330 else *(WS_MESSAGE_STATE *)buf = msg->state;
331 break;
333 case WS_MESSAGE_PROPERTY_HEAP:
334 if (!buf || size != sizeof(msg->heap)) hr = E_INVALIDARG;
335 else *(WS_HEAP **)buf = msg->heap;
336 break;
338 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
339 if (!buf || size != sizeof(msg->version_env)) hr = E_INVALIDARG;
340 else *(WS_ENVELOPE_VERSION *)buf = msg->version_env;
341 break;
343 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
344 if (!buf || size != sizeof(msg->version_addr)) hr = E_INVALIDARG;
345 else *(WS_ADDRESSING_VERSION *)buf = msg->version_addr;
346 break;
348 case WS_MESSAGE_PROPERTY_HEADER_BUFFER:
349 if (!buf || size != sizeof(msg->buf)) hr = E_INVALIDARG;
350 else *(WS_XML_BUFFER **)buf = msg->buf;
351 break;
353 case WS_MESSAGE_PROPERTY_BODY_READER:
354 if (!buf || size != sizeof(msg->reader_body)) hr = E_INVALIDARG;
355 else *(WS_XML_READER **)buf = msg->reader_body;
356 break;
358 case WS_MESSAGE_PROPERTY_BODY_WRITER:
359 if (!buf || size != sizeof(msg->writer_body)) hr = E_INVALIDARG;
360 else *(WS_XML_WRITER **)buf = msg->writer_body;
361 break;
363 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
364 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) hr = WS_E_INVALID_OPERATION;
365 else *(BOOL *)buf = msg->is_addressed;
366 break;
368 default:
369 hr = prop_get( msg->prop, msg->prop_count, id, buf, size );
372 LeaveCriticalSection( &msg->cs );
373 return hr;
376 /**************************************************************************
377 * WsSetMessageProperty [webservices.@]
379 HRESULT WINAPI WsSetMessageProperty( WS_MESSAGE *handle, WS_MESSAGE_PROPERTY_ID id, const void *value,
380 ULONG size, WS_ERROR *error )
382 struct msg *msg = (struct msg *)handle;
383 HRESULT hr;
385 TRACE( "%p %u %p %u\n", handle, id, value, size );
386 if (error) FIXME( "ignoring error parameter\n" );
388 if (!msg) return E_INVALIDARG;
390 EnterCriticalSection( &msg->cs );
392 if (msg->magic != MSG_MAGIC)
394 LeaveCriticalSection( &msg->cs );
395 return E_INVALIDARG;
398 switch (id)
400 case WS_MESSAGE_PROPERTY_STATE:
401 case WS_MESSAGE_PROPERTY_ENVELOPE_VERSION:
402 case WS_MESSAGE_PROPERTY_ADDRESSING_VERSION:
403 case WS_MESSAGE_PROPERTY_IS_ADDRESSED:
404 if (msg->state < WS_MESSAGE_STATE_INITIALIZED) hr = WS_E_INVALID_OPERATION;
405 else hr = E_INVALIDARG;
406 break;
408 default:
409 hr = prop_set( msg->prop, msg->prop_count, id, value, size );
412 LeaveCriticalSection( &msg->cs );
413 return hr;
416 /**************************************************************************
417 * WsAddressMessage [webservices.@]
419 HRESULT WINAPI WsAddressMessage( WS_MESSAGE *handle, const WS_ENDPOINT_ADDRESS *addr, WS_ERROR *error )
421 struct msg *msg = (struct msg *)handle;
422 HRESULT hr = S_OK;
424 TRACE( "%p %p %p\n", handle, addr, error );
425 if (error) FIXME( "ignoring error parameter\n" );
426 if (addr && (addr->headers || addr->extensions || addr->identity))
428 FIXME( "headers, extensions or identity not supported\n" );
429 return E_NOTIMPL;
432 if (!msg) return E_INVALIDARG;
434 EnterCriticalSection( &msg->cs );
436 if (msg->magic != MSG_MAGIC)
438 LeaveCriticalSection( &msg->cs );
439 return E_INVALIDARG;
442 if (msg->state < WS_MESSAGE_STATE_INITIALIZED || msg->is_addressed)
444 LeaveCriticalSection( &msg->cs );
445 return WS_E_INVALID_OPERATION;
448 if (addr && addr->url.length)
450 if (!(msg->addr.chars = heap_alloc( addr->url.length * sizeof(WCHAR) ))) hr = E_OUTOFMEMORY;
451 else
453 memcpy( msg->addr.chars, addr->url.chars, addr->url.length * sizeof(WCHAR) );
454 msg->addr.length = addr->url.length;
458 if (hr == S_OK) msg->is_addressed = TRUE;
460 LeaveCriticalSection( &msg->cs );
461 return hr;
464 static const WS_XML_STRING *get_env_namespace( WS_ENVELOPE_VERSION version )
466 static const WS_XML_STRING namespaces[] =
468 {41, (BYTE *)"http://schemas.xmlsoap.org/soap/envelope/"},
469 {39, (BYTE *)"http://www.w3.org/2003/05/soap-envelope"},
470 {0, NULL},
473 if (version < WS_ENVELOPE_VERSION_SOAP_1_1 || version > WS_ENVELOPE_VERSION_NONE)
475 ERR( "unknown version %u\n", version );
476 return NULL;
479 return &namespaces[version - 1];
482 static const WS_XML_STRING *get_addr_namespace( WS_ADDRESSING_VERSION version )
484 static const WS_XML_STRING namespaces[] =
486 {48, (BYTE *)"http://schemas.xmlsoap.org/ws/2004/08/addressing"},
487 {36, (BYTE *)"http://www.w3.org/2005/08/addressing"},
488 {55, (BYTE *)"http://schemas.microsoft.com/ws/2005/05/addressing/none"},
491 if (version < WS_ADDRESSING_VERSION_0_9 || version > WS_ADDRESSING_VERSION_TRANSPORT)
493 ERR( "unknown version %u\n", version );
494 return NULL;
497 return &namespaces[version - 1];
500 static const WS_XML_STRING *get_header_name( WS_HEADER_TYPE type )
502 static const WS_XML_STRING headers[] =
504 {6, (BYTE *)"Action"},
505 {2, (BYTE *)"To"},
506 {9, (BYTE *)"MessageID"},
507 {9, (BYTE *)"RelatesTo"},
508 {4, (BYTE *)"From"},
509 {7, (BYTE *)"ReplyTo"},
510 {7, (BYTE *)"FaultTo"},
513 if (type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER)
515 ERR( "unknown type %u\n", type );
516 return NULL;
519 return &headers[type - 1];
522 static HRESULT write_headers( struct msg *msg, WS_XML_WRITER *writer, const WS_XML_STRING *prefix_env,
523 const WS_XML_STRING *ns_env, const WS_XML_STRING *prefix_addr,
524 const WS_XML_STRING *ns_addr )
526 static const char anonymous[] = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
527 static const WS_XML_STRING header = {6, (BYTE *)"Header"}, address = {7, (BYTE *)"Address"};
528 const WS_XML_STRING *msgid = get_header_name( WS_MESSAGE_ID_HEADER );
529 const WS_XML_STRING *replyto = get_header_name( WS_REPLY_TO_HEADER );
530 WS_XML_UTF8_TEXT urn, addr;
531 HRESULT hr;
532 ULONG i;
534 if ((hr = WsWriteXmlnsAttribute( writer, prefix_addr, ns_addr, FALSE, NULL )) != S_OK) return hr;
535 if ((hr = WsWriteStartElement( writer, prefix_env, &header, ns_env, NULL )) != S_OK) return hr;
537 if ((hr = WsWriteStartElement( writer, prefix_addr, msgid, ns_addr, NULL )) != S_OK) return hr;
538 urn.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
539 memcpy( &urn.value, &msg->id, sizeof(msg->id) );
540 if ((hr = WsWriteText( writer, &urn.text, NULL )) != S_OK) return hr;
541 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:MessageID> */
543 if (msg->version_addr == WS_ADDRESSING_VERSION_0_9)
545 if ((hr = WsWriteStartElement( writer, prefix_addr, replyto, ns_addr, NULL )) != S_OK) return hr;
546 if ((hr = WsWriteStartElement( writer, prefix_addr, &address, ns_addr, NULL )) != S_OK) return hr;
548 addr.text.textType = WS_XML_TEXT_TYPE_UTF8;
549 addr.value.bytes = (BYTE *)anonymous;
550 addr.value.length = sizeof(anonymous) - 1;
551 if ((hr = WsWriteText( writer, &addr.text, NULL )) != S_OK) return hr;
552 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:Address> */
553 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </a:ReplyTo> */
556 for (i = 0; i < msg->header_count; i++)
558 if (msg->header[i]->mapped) continue;
559 if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr;
562 return WsWriteEndElement( writer, NULL ); /* </s:Header> */
565 static HRESULT write_headers_transport( struct msg *msg, WS_XML_WRITER *writer, const WS_XML_STRING *prefix,
566 const WS_XML_STRING *ns )
568 static const WS_XML_STRING header = {6, (BYTE *)"Header"};
569 HRESULT hr = S_OK;
570 ULONG i;
572 if ((msg->header_count || !msg->action.length) &&
573 (hr = WsWriteStartElement( writer, prefix, &header, ns, NULL )) != S_OK) return hr;
575 for (i = 0; i < msg->header_count; i++)
577 if (msg->header[i]->mapped) continue;
578 if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr;
581 if (msg->header_count || !msg->action.length) hr = WsWriteEndElement( writer, NULL ); /* </s:Header> */
582 return hr;
585 static HRESULT write_envelope_start( struct msg *msg, WS_XML_WRITER *writer )
587 static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, body = {4, (BYTE *)"Body"};
588 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
589 const WS_XML_STRING *prefix_env = (msg->version_env == WS_ENVELOPE_VERSION_NONE) ? NULL : &prefix_s;
590 const WS_XML_STRING *prefix_addr = (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT) ? NULL : &prefix_a;
591 const WS_XML_STRING *ns_env = get_env_namespace( msg->version_env );
592 const WS_XML_STRING *ns_addr = get_addr_namespace( msg->version_addr );
593 HRESULT hr;
595 if ((hr = WsWriteStartElement( writer, prefix_env, &envelope, ns_env, NULL )) != S_OK) return hr;
597 if (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT)
598 hr = write_headers_transport( msg, writer, prefix_env, ns_env );
599 else
600 hr = write_headers( msg, writer, prefix_env, ns_env, prefix_addr, ns_addr );
601 if (hr != S_OK) return hr;
603 return WsWriteStartElement( writer, prefix_env, &body, ns_env, NULL ); /* <s:Body> */
606 static HRESULT write_envelope_end( WS_XML_WRITER *writer )
608 HRESULT hr;
609 if ((hr = WsWriteEndElement( writer, NULL )) != S_OK) return hr; /* </s:Body> */
610 return WsWriteEndElement( writer, NULL ); /* </s:Envelope> */
613 static HRESULT write_envelope( struct msg *msg )
615 HRESULT hr;
616 if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) return hr;
617 if (!msg->buf && (hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &msg->buf, NULL )) != S_OK) return hr;
618 if ((hr = WsSetOutputToBuffer( msg->writer, msg->buf, NULL, 0, NULL )) != S_OK) return hr;
619 if ((hr = write_envelope_start( msg, msg->writer )) != S_OK) return hr;
620 return write_envelope_end( msg->writer );
623 /**************************************************************************
624 * WsWriteEnvelopeStart [webservices.@]
626 HRESULT WINAPI WsWriteEnvelopeStart( WS_MESSAGE *handle, WS_XML_WRITER *writer,
627 WS_MESSAGE_DONE_CALLBACK cb, void *state, WS_ERROR *error )
629 struct msg *msg = (struct msg *)handle;
630 HRESULT hr;
632 TRACE( "%p %p %p %p %p\n", handle, writer, cb, state, error );
633 if (error) FIXME( "ignoring error parameter\n" );
634 if (cb)
636 FIXME( "callback not supported\n" );
637 return E_NOTIMPL;
640 if (!msg || !writer) return E_INVALIDARG;
642 EnterCriticalSection( &msg->cs );
644 if (msg->magic != MSG_MAGIC)
646 LeaveCriticalSection( &msg->cs );
647 return E_INVALIDARG;
650 if (msg->state != WS_MESSAGE_STATE_INITIALIZED)
652 LeaveCriticalSection( &msg->cs );
653 return WS_E_INVALID_OPERATION;
656 if ((hr = write_envelope( msg )) != S_OK) goto done;
657 if ((hr = write_envelope_start( msg, writer )) != S_OK) goto done;
659 msg->writer_body = writer;
660 msg->state = WS_MESSAGE_STATE_WRITING;
662 done:
663 LeaveCriticalSection( &msg->cs );
664 return hr;
667 /**************************************************************************
668 * WsWriteEnvelopeEnd [webservices.@]
670 HRESULT WINAPI WsWriteEnvelopeEnd( WS_MESSAGE *handle, WS_ERROR *error )
672 struct msg *msg = (struct msg *)handle;
673 HRESULT hr;
675 TRACE( "%p %p\n", handle, error );
676 if (error) FIXME( "ignoring error parameter\n" );
678 if (!msg) return E_INVALIDARG;
680 EnterCriticalSection( &msg->cs );
682 if (msg->magic != MSG_MAGIC)
684 LeaveCriticalSection( &msg->cs );
685 return E_INVALIDARG;
688 if (msg->state != WS_MESSAGE_STATE_WRITING)
690 LeaveCriticalSection( &msg->cs );
691 return WS_E_INVALID_OPERATION;
694 if ((hr = write_envelope_end( msg->writer_body )) == S_OK) msg->state = WS_MESSAGE_STATE_DONE;
696 LeaveCriticalSection( &msg->cs );
697 return hr;
700 /**************************************************************************
701 * WsWriteBody [webservices.@]
703 HRESULT WINAPI WsWriteBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
704 const void *value, ULONG size, WS_ERROR *error )
706 struct msg *msg = (struct msg *)handle;
707 HRESULT hr;
709 TRACE( "%p %p %08x %p %u %p\n", handle, desc, option, value, size, error );
710 if (error) FIXME( "ignoring error parameter\n" );
712 if (!msg || !desc) return E_INVALIDARG;
714 EnterCriticalSection( &msg->cs );
716 if (msg->magic != MSG_MAGIC)
718 LeaveCriticalSection( &msg->cs );
719 return E_INVALIDARG;
722 if (msg->state != WS_MESSAGE_STATE_WRITING)
724 LeaveCriticalSection( &msg->cs );
725 return WS_E_INVALID_OPERATION;
728 if (desc->elementLocalName &&
729 (hr = WsWriteStartElement( msg->writer_body, NULL, desc->elementLocalName, desc->elementNs,
730 NULL )) != S_OK) goto done;
732 if ((hr = WsWriteType( msg->writer_body, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
733 option, value, size, NULL )) != S_OK) goto done;
735 if (desc->elementLocalName) hr = WsWriteEndElement( msg->writer_body, NULL );
737 done:
738 LeaveCriticalSection( &msg->cs );
739 return hr;
742 static BOOL match_current_element( WS_XML_READER *reader, const WS_XML_STRING *localname )
744 const WS_XML_NODE *node;
745 const WS_XML_ELEMENT_NODE *elem;
747 if (WsGetReaderNode( reader, &node, NULL ) != S_OK) return FALSE;
748 if (node->nodeType != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
749 elem = (const WS_XML_ELEMENT_NODE *)node;
750 return WsXmlStringEquals( elem->localName, localname, NULL ) == S_OK;
753 static HRESULT read_envelope_start( WS_XML_READER *reader )
755 static const WS_XML_STRING envelope = {8, (BYTE *)"Envelope"}, body = {4, (BYTE *)"Body"};
756 static const WS_XML_STRING header = {6, (BYTE *)"Header"};
757 HRESULT hr;
759 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
760 if (!match_current_element( reader, &envelope )) return WS_E_INVALID_FORMAT;
761 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
762 if (match_current_element( reader, &header ))
764 for (;;)
766 /* FIXME: store headers */
767 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
768 if (match_current_element( reader, &body )) break;
771 if (!match_current_element( reader, &body )) return WS_E_INVALID_FORMAT;
772 return WsReadNode( reader, NULL );
775 /**************************************************************************
776 * WsReadEnvelopeStart [webservices.@]
778 HRESULT WINAPI WsReadEnvelopeStart( WS_MESSAGE *handle, WS_XML_READER *reader, WS_MESSAGE_DONE_CALLBACK cb,
779 void *state, WS_ERROR *error )
781 struct msg *msg = (struct msg *)handle;
782 HRESULT hr;
784 TRACE( "%p %p %p %p %p\n", handle, reader, cb, state, error );
785 if (error) FIXME( "ignoring error parameter\n" );
786 if (cb)
788 FIXME( "callback not supported\n" );
789 return E_NOTIMPL;
792 if (!msg || !reader) return E_INVALIDARG;
794 EnterCriticalSection( &msg->cs );
796 if (msg->magic != MSG_MAGIC)
798 LeaveCriticalSection( &msg->cs );
799 return E_INVALIDARG;
802 if (msg->state != WS_MESSAGE_STATE_EMPTY)
804 LeaveCriticalSection( &msg->cs );
805 return WS_E_INVALID_OPERATION;
808 if ((hr = read_envelope_start( reader )) == S_OK)
810 msg->reader_body = reader;
811 msg->state = WS_MESSAGE_STATE_READING;
814 LeaveCriticalSection( &msg->cs );
815 return hr;
818 static HRESULT read_envelope_end( WS_XML_READER *reader )
820 HRESULT hr;
821 if ((hr = WsReadEndElement( reader, NULL )) != S_OK) return hr; /* </s:Body> */
822 return WsReadEndElement( reader, NULL ); /* </s:Envelope> */
825 /**************************************************************************
826 * WsReadEnvelopeEnd [webservices.@]
828 HRESULT WINAPI WsReadEnvelopeEnd( WS_MESSAGE *handle, WS_ERROR *error )
830 struct msg *msg = (struct msg *)handle;
831 HRESULT hr;
833 TRACE( "%p %p\n", handle, error );
834 if (error) FIXME( "ignoring error parameter\n" );
836 if (!msg) return E_INVALIDARG;
838 EnterCriticalSection( &msg->cs );
840 if (msg->magic != MSG_MAGIC)
842 LeaveCriticalSection( &msg->cs );
843 return E_INVALIDARG;
846 if (msg->state != WS_MESSAGE_STATE_READING)
848 LeaveCriticalSection( &msg->cs );
849 return WS_E_INVALID_OPERATION;
852 if ((hr = read_envelope_end( msg->reader_body )) == S_OK) msg->state = WS_MESSAGE_STATE_DONE;
854 LeaveCriticalSection( &msg->cs );
855 return hr;
858 /**************************************************************************
859 * WsReadBody [webservices.@]
861 HRESULT WINAPI WsReadBody( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_READ_OPTION option,
862 WS_HEAP *heap, void *value, ULONG size, WS_ERROR *error )
864 struct msg *msg = (struct msg *)handle;
865 HRESULT hr;
867 TRACE( "%p %p %08x %p %p %u %p\n", handle, desc, option, heap, value, size, error );
868 if (error) FIXME( "ignoring error parameter\n" );
870 if (!msg || !desc) return E_INVALIDARG;
872 EnterCriticalSection( &msg->cs );
874 if (msg->magic != MSG_MAGIC)
876 LeaveCriticalSection( &msg->cs );
877 return E_INVALIDARG;
880 if (msg->state != WS_MESSAGE_STATE_READING)
882 LeaveCriticalSection( &msg->cs );
883 return WS_E_INVALID_OPERATION;
886 hr = WsReadElement( msg->reader_body, desc, option, heap, value, size, NULL );
888 LeaveCriticalSection( &msg->cs );
889 return hr;
892 /**************************************************************************
893 * WsInitializeMessage [webservices.@]
895 HRESULT WINAPI WsInitializeMessage( WS_MESSAGE *handle, WS_MESSAGE_INITIALIZATION init,
896 WS_MESSAGE *src_handle, WS_ERROR *error )
898 struct msg *msg = (struct msg *)handle;
899 HRESULT hr;
901 TRACE( "%p %u %p %p\n", handle, init, src_handle, error );
902 if (error) FIXME( "ignoring error parameter\n" );
903 if (src_handle)
905 FIXME( "src message not supported\n" );
906 return E_NOTIMPL;
909 if (!msg || init > WS_FAULT_MESSAGE) return E_INVALIDARG;
911 EnterCriticalSection( &msg->cs );
913 if (msg->magic != MSG_MAGIC)
915 LeaveCriticalSection( &msg->cs );
916 return E_INVALIDARG;
919 if (msg->state >= WS_MESSAGE_STATE_INITIALIZED)
921 LeaveCriticalSection( &msg->cs );
922 return WS_E_INVALID_OPERATION;
925 if ((hr = write_envelope( msg )) == S_OK)
927 msg->init = init;
928 msg->state = WS_MESSAGE_STATE_INITIALIZED;
931 LeaveCriticalSection( &msg->cs );
932 return hr;
935 static HRESULT grow_header_array( struct msg *msg, ULONG size )
937 struct header **tmp;
938 if (size <= msg->header_size) return S_OK;
939 if (!(tmp = heap_realloc( msg->header, 2 * msg->header_size * sizeof(struct header *) )))
940 return E_OUTOFMEMORY;
941 msg->header = tmp;
942 msg->header_size *= 2;
943 return S_OK;
946 static struct header *alloc_header( WS_HEADER_TYPE type, BOOL mapped, const WS_XML_STRING *name,
947 const WS_XML_STRING *ns )
949 struct header *ret;
950 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
951 if (name && name->length)
953 if (!(ret->name.bytes = heap_alloc( name->length )))
955 free_header( ret );
956 return NULL;
958 memcpy( ret->name.bytes, name->bytes, name->length );
959 ret->name.length = name->length;
961 if (ns && ns->length)
963 if (!(ret->ns.bytes = heap_alloc( ns->length )))
965 free_header( ret );
966 return NULL;
968 memcpy( ret->ns.bytes, ns->bytes, ns->length );
969 ret->ns.length = ns->length;
971 ret->type = type;
972 ret->mapped = mapped;
973 return ret;
976 static HRESULT write_standard_header( struct msg *msg, WS_HEADER_TYPE type, WS_TYPE value_type,
977 WS_WRITE_OPTION option, const void *value, ULONG size )
979 static const WS_XML_STRING ns = {0, NULL}, understand = {14, (BYTE *)"mustUnderstand"};
980 static const WS_XML_STRING prefix_s = {1, (BYTE *)"s"}, prefix_a = {1, (BYTE *)"a"};
981 const WS_XML_STRING *prefix_env = (msg->version_env == WS_ENVELOPE_VERSION_NONE) ? NULL : &prefix_s;
982 const WS_XML_STRING *prefix_addr = (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT) ? NULL : &prefix_a;
983 const WS_XML_STRING *localname = get_header_name( type );
984 WS_XML_INT32_TEXT one = {{WS_XML_TEXT_TYPE_INT32}, 1};
985 HRESULT hr;
987 if ((hr = WsWriteStartElement( msg->writer, prefix_addr, localname, &ns, NULL )) != S_OK) return hr;
988 if ((hr = WsWriteStartAttribute( msg->writer, prefix_env, &understand, &ns, FALSE, NULL )) != S_OK) return hr;
989 if ((hr = WsWriteText( msg->writer, &one.text, NULL )) != S_OK) return hr;
990 if ((hr = WsWriteEndAttribute( msg->writer, NULL )) != S_OK) return hr;
991 if (msg->version_addr == WS_ADDRESSING_VERSION_TRANSPORT)
993 const WS_XML_STRING *ns_addr = get_addr_namespace( WS_ADDRESSING_VERSION_TRANSPORT );
994 if ((hr = WsWriteXmlnsAttribute( msg->writer, NULL, ns_addr, FALSE, NULL )) != S_OK) return hr;
996 if ((hr = WsWriteType( msg->writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, value_type, NULL, option, value, size,
997 NULL )) != S_OK) return hr;
998 return WsWriteEndElement( msg->writer, NULL );
1001 static HRESULT build_standard_header( struct msg *msg, WS_HEADER_TYPE type, WS_TYPE value_type,
1002 WS_WRITE_OPTION option, const void *value, ULONG size,
1003 struct header **ret )
1005 struct header *header;
1006 WS_XML_BUFFER *buf;
1007 HRESULT hr;
1009 if (!(header = alloc_header( type, FALSE, get_header_name(type), NULL ))) return E_OUTOFMEMORY;
1011 if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) goto done;
1012 if ((hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
1013 if ((hr = WsSetOutputToBuffer( msg->writer, buf, NULL, 0, NULL )) != S_OK) goto done;
1014 if ((hr = write_standard_header( msg, type, value_type, option, value, size )) != S_OK) goto done;
1016 header->u.buf = buf;
1018 done:
1019 if (hr != S_OK) free_header( header );
1020 else *ret = header;
1021 return hr;
1024 /**************************************************************************
1025 * WsSetHeader [webservices.@]
1027 HRESULT WINAPI WsSetHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_TYPE value_type,
1028 WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error )
1030 struct msg *msg = (struct msg *)handle;
1031 struct header *header;
1032 BOOL found = FALSE;
1033 HRESULT hr;
1034 ULONG i;
1036 TRACE( "%p %u %u %08x %p %u %p\n", handle, type, value_type, option, value, size, error );
1037 if (error) FIXME( "ignoring error parameter\n" );
1039 if (!msg || type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER) return E_INVALIDARG;
1041 EnterCriticalSection( &msg->cs );
1043 if (msg->magic != MSG_MAGIC)
1045 LeaveCriticalSection( &msg->cs );
1046 return E_INVALIDARG;
1049 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1051 LeaveCriticalSection( &msg->cs );
1052 return WS_E_INVALID_OPERATION;
1055 for (i = 0; i < msg->header_count; i++)
1057 if (msg->header[i]->type == type)
1059 found = TRUE;
1060 break;
1064 if (!found)
1066 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done;
1067 i = msg->header_count;
1070 if ((hr = build_standard_header( msg, type, value_type, option, value, size, &header )) != S_OK)
1071 goto done;
1073 if (!found) msg->header_count++;
1074 else free_header( msg->header[i] );
1076 msg->header[i] = header;
1077 hr = write_envelope( msg );
1079 done:
1080 LeaveCriticalSection( &msg->cs );
1081 return hr;
1084 static HRESULT find_header( WS_XML_READER *reader, const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1086 const WS_XML_NODE *node;
1087 const WS_XML_ELEMENT_NODE *elem;
1088 HRESULT hr;
1090 for (;;)
1092 if ((hr = WsReadNode( reader, NULL )) != S_OK) return hr;
1093 if ((hr = WsGetReaderNode( reader, &node, NULL )) != S_OK) return hr;
1094 if (node->nodeType == WS_XML_NODE_TYPE_EOF) return WS_E_INVALID_FORMAT;
1095 if (node->nodeType != WS_XML_NODE_TYPE_ELEMENT) continue;
1097 elem = (const WS_XML_ELEMENT_NODE *)node;
1098 if (WsXmlStringEquals( elem->localName, localname, NULL ) == S_OK &&
1099 WsXmlStringEquals( elem->ns, ns, NULL ) == S_OK) break;
1102 return S_OK;
1105 static HRESULT get_standard_header( struct msg *msg, WS_HEADER_TYPE type, WS_TYPE value_type,
1106 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size )
1108 const WS_XML_STRING *localname = get_header_name( type );
1109 const WS_XML_STRING *ns = get_addr_namespace( msg->version_addr );
1110 HRESULT hr;
1112 if (!heap) heap = msg->heap;
1113 if (!msg->reader && (hr = WsCreateReader( NULL, 0, &msg->reader, NULL )) != S_OK) return hr;
1114 if ((hr = WsSetInputToBuffer( msg->reader, msg->buf, NULL, 0, NULL )) != S_OK) return hr;
1116 if ((hr = find_header( msg->reader, localname, ns )) != S_OK) return hr;
1117 return read_header( msg->reader, localname, ns, value_type, NULL, option, heap, value, size );
1120 /**************************************************************************
1121 * WsGetHeader [webservices.@]
1123 HRESULT WINAPI WsGetHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_TYPE value_type, WS_READ_OPTION option,
1124 WS_HEAP *heap, void *value, ULONG size, WS_ERROR *error )
1126 struct msg *msg = (struct msg *)handle;
1127 HRESULT hr;
1129 TRACE( "%p %u %u %08x %p %p %u %p\n", handle, type, value_type, option, heap, value, size, error );
1130 if (error) FIXME( "ignoring error parameter\n" );
1132 if (!msg || type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER || option < WS_READ_REQUIRED_VALUE ||
1133 option > WS_READ_OPTIONAL_POINTER) return E_INVALIDARG;
1135 EnterCriticalSection( &msg->cs );
1137 if (msg->magic != MSG_MAGIC)
1139 LeaveCriticalSection( &msg->cs );
1140 return E_INVALIDARG;
1143 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1145 LeaveCriticalSection( &msg->cs );
1146 return WS_E_INVALID_OPERATION;
1149 hr = get_standard_header( msg, type, value_type, option, heap, value, size );
1151 LeaveCriticalSection( &msg->cs );
1152 return hr;
1155 static void remove_header( struct msg *msg, ULONG i )
1157 free_header( msg->header[i] );
1158 memmove( &msg->header[i], &msg->header[i + 1], (msg->header_count - i - 1) * sizeof(struct header *) );
1159 msg->header_count--;
1162 /**************************************************************************
1163 * WsRemoveHeader [webservices.@]
1165 HRESULT WINAPI WsRemoveHeader( WS_MESSAGE *handle, WS_HEADER_TYPE type, WS_ERROR *error )
1167 struct msg *msg = (struct msg *)handle;
1168 BOOL removed = FALSE;
1169 HRESULT hr = S_OK;
1170 ULONG i;
1172 TRACE( "%p %u %p\n", handle, type, error );
1173 if (error) FIXME( "ignoring error parameter\n" );
1175 if (!msg) return E_INVALIDARG;
1177 EnterCriticalSection( &msg->cs );
1179 if (msg->magic != MSG_MAGIC)
1181 LeaveCriticalSection( &msg->cs );
1182 return E_INVALIDARG;
1185 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1187 LeaveCriticalSection( &msg->cs );
1188 return WS_E_INVALID_OPERATION;
1191 if (type < WS_ACTION_HEADER || type > WS_FAULT_TO_HEADER)
1193 LeaveCriticalSection( &msg->cs );
1194 return E_INVALIDARG;
1197 for (i = 0; i < msg->header_count; i++)
1199 if (msg->header[i]->type == type)
1201 remove_header( msg, i );
1202 removed = TRUE;
1203 break;
1207 if (removed) hr = write_envelope( msg );
1209 LeaveCriticalSection( &msg->cs );
1210 return hr;
1213 static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_WRITE_OPTION option,
1214 const void *value, ULONG size, struct header **ret )
1216 struct header *header;
1218 if (!(header = alloc_header( 0, TRUE, name, NULL ))) return E_OUTOFMEMORY;
1219 switch (type)
1221 case WS_WSZ_TYPE:
1223 int len;
1224 const WCHAR *src;
1226 if (option != WS_WRITE_REQUIRED_POINTER || size != sizeof(WCHAR *))
1228 free_header( header );
1229 return E_INVALIDARG;
1231 src = *(const WCHAR **)value;
1232 len = WideCharToMultiByte( CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL ) - 1;
1233 if (!(header->u.text = alloc_xml_string( NULL, len )))
1235 free_header( header );
1236 return E_OUTOFMEMORY;
1238 WideCharToMultiByte( CP_UTF8, 0, src, -1, (char *)header->u.text->bytes, len, NULL, NULL );
1239 break;
1241 case WS_XML_STRING_TYPE:
1243 const WS_XML_STRING *str = value;
1245 if (option != WS_WRITE_REQUIRED_VALUE)
1247 FIXME( "unhandled write option %u\n", option );
1248 free_header( header );
1249 return E_NOTIMPL;
1251 if (size != sizeof(*str))
1253 free_header( header );
1254 return E_INVALIDARG;
1256 if (!(header->u.text = alloc_xml_string( NULL, str->length )))
1258 free_header( header );
1259 return E_OUTOFMEMORY;
1261 memcpy( header->u.text->bytes, str->bytes, str->length );
1262 break;
1264 case WS_STRING_TYPE:
1266 int len;
1267 const WS_STRING *str = value;
1269 if (option != WS_WRITE_REQUIRED_VALUE)
1271 FIXME( "unhandled write option %u\n", option );
1272 free_header( header );
1273 return E_NOTIMPL;
1275 if (size != sizeof(*str))
1277 free_header( header );
1278 return E_INVALIDARG;
1280 len = WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, NULL, 0, NULL, NULL );
1281 if (!(header->u.text = alloc_xml_string( NULL, len )))
1283 free_header( header );
1284 return E_OUTOFMEMORY;
1286 WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, (char *)header->u.text->bytes,
1287 len, NULL, NULL );
1288 break;
1290 default:
1291 FIXME( "unhandled type %u\n", type );
1292 free_header( header );
1293 return E_NOTIMPL;
1296 *ret = header;
1297 return S_OK;
1300 /**************************************************************************
1301 * WsAddMappedHeader [webservices.@]
1303 HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type,
1304 WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error )
1306 struct msg *msg = (struct msg *)handle;
1307 struct header *header;
1308 BOOL found = FALSE;
1309 HRESULT hr;
1310 ULONG i;
1312 TRACE( "%p %s %u %08x %p %u %p\n", handle, debugstr_xmlstr(name), type, option, value, size, error );
1313 if (error) FIXME( "ignoring error parameter\n" );
1315 if (!msg || !name) return E_INVALIDARG;
1317 EnterCriticalSection( &msg->cs );
1319 if (msg->magic != MSG_MAGIC)
1321 LeaveCriticalSection( &msg->cs );
1322 return E_INVALIDARG;
1325 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1327 LeaveCriticalSection( &msg->cs );
1328 return WS_E_INVALID_OPERATION;
1331 for (i = 0; i < msg->header_count; i++)
1333 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
1334 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
1336 found = TRUE;
1337 break;
1341 if (!found)
1343 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done;
1344 i = msg->header_count;
1347 if ((hr = build_mapped_header( name, type, option, value, size, &header )) != S_OK) goto done;
1349 if (!found) msg->header_count++;
1350 else free_header( msg->header[i] );
1352 msg->header[i] = header;
1354 done:
1355 LeaveCriticalSection( &msg->cs );
1356 return hr;
1359 /**************************************************************************
1360 * WsRemoveMappedHeader [webservices.@]
1362 HRESULT WINAPI WsRemoveMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_ERROR *error )
1364 struct msg *msg = (struct msg *)handle;
1365 ULONG i;
1367 TRACE( "%p %s %p\n", handle, debugstr_xmlstr(name), error );
1368 if (error) FIXME( "ignoring error parameter\n" );
1370 if (!msg || !name) return E_INVALIDARG;
1372 EnterCriticalSection( &msg->cs );
1374 if (msg->magic != MSG_MAGIC)
1376 LeaveCriticalSection( &msg->cs );
1377 return E_INVALIDARG;
1380 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1382 LeaveCriticalSection( &msg->cs );
1383 return WS_E_INVALID_OPERATION;
1386 for (i = 0; i < msg->header_count; i++)
1388 if (msg->header[i]->type || !msg->header[i]->mapped) continue;
1389 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK)
1391 remove_header( msg, i );
1392 break;
1396 LeaveCriticalSection( &msg->cs );
1397 return S_OK;
1400 static HRESULT write_custom_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1401 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
1402 ULONG size )
1404 HRESULT hr;
1405 if ((hr = WsWriteStartElement( writer, NULL, name, ns, NULL )) != S_OK) return hr;
1406 if ((hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, type, desc, option, value, size,
1407 NULL )) != S_OK) return hr;
1408 return WsWriteEndElement( writer, NULL );
1411 static HRESULT build_custom_header( struct msg *msg, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1412 WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value,
1413 ULONG size, struct header **ret )
1415 struct header *header;
1416 WS_XML_BUFFER *buf;
1417 HRESULT hr;
1419 if (!(header = alloc_header( 0, FALSE, name, ns ))) return E_OUTOFMEMORY;
1421 if (!msg->writer && (hr = WsCreateWriter( NULL, 0, &msg->writer, NULL )) != S_OK) goto done;
1422 if ((hr = WsCreateXmlBuffer( msg->heap, NULL, 0, &buf, NULL )) != S_OK) goto done;
1423 if ((hr = WsSetOutputToBuffer( msg->writer, buf, NULL, 0, NULL )) != S_OK) goto done;
1424 if ((hr = write_custom_header( msg->writer, name, ns, type, desc, option, value, size )) != S_OK) goto done;
1426 header->u.buf = buf;
1428 done:
1429 if (hr != S_OK) free_header( header );
1430 else *ret = header;
1431 return hr;
1434 /**************************************************************************
1435 * WsAddCustomHeader [webservices.@]
1437 HRESULT WINAPI WsAddCustomHeader( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc, WS_WRITE_OPTION option,
1438 const void *value, ULONG size, ULONG attrs, WS_ERROR *error )
1440 struct msg *msg = (struct msg *)handle;
1441 struct header *header;
1442 HRESULT hr;
1444 TRACE( "%p %p %08x %p %u %08x %p\n", handle, desc, option, value, size, attrs, error );
1445 if (error) FIXME( "ignoring error parameter\n" );
1447 if (!msg || !desc) return E_INVALIDARG;
1449 EnterCriticalSection( &msg->cs );
1451 if (msg->magic != MSG_MAGIC)
1453 LeaveCriticalSection( &msg->cs );
1454 return E_INVALIDARG;
1457 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1459 LeaveCriticalSection( &msg->cs );
1460 return WS_E_INVALID_OPERATION;
1463 if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done;
1464 if ((hr = build_custom_header( msg, desc->elementLocalName, desc->elementNs, desc->type,
1465 desc->typeDescription, option, value, size, &header )) != S_OK) goto done;
1466 msg->header[msg->header_count++] = header;
1467 hr = write_envelope( msg );
1469 done:
1470 LeaveCriticalSection( &msg->cs );
1471 return hr;
1474 static HRESULT get_custom_header( struct msg *msg, const WS_ELEMENT_DESCRIPTION *desc, WS_READ_OPTION option,
1475 WS_HEAP *heap, void *value, ULONG size )
1477 HRESULT hr;
1478 if (!heap) heap = msg->heap;
1479 if (!msg->reader && (hr = WsCreateReader( NULL, 0, &msg->reader, NULL )) != S_OK) return hr;
1480 if ((hr = WsSetInputToBuffer( msg->reader, msg->buf, NULL, 0, NULL )) != S_OK) return hr;
1482 if ((hr = find_header( msg->reader, desc->elementLocalName, desc->elementNs )) != S_OK) return hr;
1483 return read_header( msg->reader, desc->elementLocalName, desc->elementNs, desc->type, desc->typeDescription,
1484 option, heap, value, size );
1487 /**************************************************************************
1488 * WsGetCustomHeader [webservices.@]
1490 HRESULT WINAPI WsGetCustomHeader( WS_MESSAGE *handle, const WS_ELEMENT_DESCRIPTION *desc,
1491 WS_REPEATING_HEADER_OPTION repeat_option, ULONG index, WS_READ_OPTION option,
1492 WS_HEAP *heap, void *value, ULONG size, ULONG *attrs, WS_ERROR *error )
1494 struct msg *msg = (struct msg *)handle;
1495 HRESULT hr;
1497 TRACE( "%p %p %08x %u %08x %p %p %u %p %p\n", handle, desc, repeat_option, index, option, heap, value,
1498 size, attrs, error );
1499 if (error) FIXME( "ignoring error parameter\n" );
1501 if (!msg || !desc || repeat_option < WS_REPEATING_HEADER || repeat_option > WS_SINGLETON_HEADER ||
1502 (repeat_option == WS_SINGLETON_HEADER && index)) return E_INVALIDARG;
1504 if (repeat_option == WS_REPEATING_HEADER)
1506 FIXME( "repeating header not supported\n" );
1507 return E_NOTIMPL;
1509 if (attrs)
1511 FIXME( "attributes not supported\n" );
1512 return E_NOTIMPL;
1515 EnterCriticalSection( &msg->cs );
1517 if (msg->magic != MSG_MAGIC)
1519 LeaveCriticalSection( &msg->cs );
1520 return E_INVALIDARG;
1523 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1525 LeaveCriticalSection( &msg->cs );
1526 return WS_E_INVALID_OPERATION;
1529 hr = get_custom_header( msg, desc, option, heap, value, size );
1531 LeaveCriticalSection( &msg->cs );
1532 return hr;
1535 /**************************************************************************
1536 * WsRemoveCustomHeader [webservices.@]
1538 HRESULT WINAPI WsRemoveCustomHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, const WS_XML_STRING *ns,
1539 WS_ERROR *error )
1541 struct msg *msg = (struct msg *)handle;
1542 BOOL removed = FALSE;
1543 HRESULT hr = S_OK;
1544 ULONG i;
1546 TRACE( "%p %s %s %p\n", handle, debugstr_xmlstr(name), debugstr_xmlstr(ns), error );
1547 if (error) FIXME( "ignoring error parameter\n" );
1549 if (!msg || !name || !ns) return E_INVALIDARG;
1551 EnterCriticalSection( &msg->cs );
1553 if (msg->magic != MSG_MAGIC)
1555 LeaveCriticalSection( &msg->cs );
1556 return E_INVALIDARG;
1559 if (msg->state < WS_MESSAGE_STATE_INITIALIZED)
1561 LeaveCriticalSection( &msg->cs );
1562 return WS_E_INVALID_OPERATION;
1565 for (i = 0; i < msg->header_count; i++)
1567 if (msg->header[i]->type || msg->header[i]->mapped) continue;
1568 if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK &&
1569 WsXmlStringEquals( ns, &msg->header[i]->ns, NULL ) == S_OK)
1571 remove_header( msg, i );
1572 removed = TRUE;
1573 i--;
1577 if (removed) hr = write_envelope( msg );
1579 LeaveCriticalSection( &msg->cs );
1580 return hr;
1583 static WCHAR *build_http_header( const WCHAR *name, const WCHAR *value, ULONG *ret_len )
1585 static const WCHAR fmtW[] = {'%','s',':',' ','%','s',0};
1586 WCHAR *ret = heap_alloc( (strlenW(name) + strlenW(value) + 3) * sizeof(WCHAR) );
1587 if (ret) *ret_len = sprintfW( ret, fmtW, name, value );
1588 return ret;
1591 static inline HRESULT insert_http_header( HINTERNET req, const WCHAR *header, ULONG len, ULONG flags )
1593 if (WinHttpAddRequestHeaders( req, header, len, flags )) return S_OK;
1594 return HRESULT_FROM_WIN32( GetLastError() );
1597 HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req )
1599 static const WCHAR contenttypeW[] =
1600 {'C','o','n','t','e','n','t','-','T','y','p','e',0};
1601 static const WCHAR soapxmlW[] =
1602 {'a','p','p','l','i','c','a','t','i','o','n','/','s','o','a','p','+','x','m','l',0};
1603 static const WCHAR textxmlW[] =
1604 {'t','e','x','t','/','x','m','l',0};
1605 static const WCHAR charsetW[] =
1606 {'c','h','a','r','s','e','t','=','u','t','f','-','8',0};
1607 struct msg *msg = (struct msg *)handle;
1608 HRESULT hr = E_OUTOFMEMORY;
1609 WCHAR *header = NULL, *buf;
1610 ULONG len;
1612 EnterCriticalSection( &msg->cs );
1614 if (msg->magic != MSG_MAGIC)
1616 LeaveCriticalSection( &msg->cs );
1617 return E_INVALIDARG;
1620 switch (msg->version_env)
1622 case WS_ENVELOPE_VERSION_SOAP_1_1:
1623 header = build_http_header( contenttypeW, textxmlW, &len );
1624 break;
1626 case WS_ENVELOPE_VERSION_SOAP_1_2:
1627 header = build_http_header( contenttypeW, soapxmlW, &len );
1628 break;
1630 default:
1631 FIXME( "unhandled envelope version %u\n", msg->version_env );
1632 hr = E_NOTIMPL;
1634 if (!header) goto done;
1636 if ((hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_ADD )) != S_OK) goto done;
1637 heap_free( header );
1639 hr = E_OUTOFMEMORY;
1640 if (!(header = build_http_header( contenttypeW, charsetW, &len ))) goto done;
1641 if ((hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON )) != S_OK)
1642 goto done;
1643 heap_free( header );
1644 header = NULL;
1646 switch (msg->version_env)
1648 case WS_ENVELOPE_VERSION_SOAP_1_1:
1650 static const WCHAR soapactionW[] = {'S','O','A','P','A','c','t','i','o','n',0};
1652 if (!(len = msg->action.length)) break;
1654 hr = E_OUTOFMEMORY;
1655 if (!(buf = heap_alloc( (len + 3) * sizeof(WCHAR) ))) goto done;
1656 buf[0] = '"';
1657 memcpy( buf + 1, msg->action.chars, len * sizeof(WCHAR) );
1658 buf[len + 1] = '"';
1659 buf[len + 2] = 0;
1661 header = build_http_header( soapactionW, buf, &len );
1662 heap_free( buf );
1663 if (!header) goto done;
1665 hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_ADD );
1666 break;
1668 case WS_ENVELOPE_VERSION_SOAP_1_2:
1670 static const WCHAR actionW[] = {'a','c','t','i','o','n','=','"'};
1671 ULONG len_action = sizeof(actionW)/sizeof(actionW[0]);
1673 if (!(len = msg->action.length)) break;
1675 hr = E_OUTOFMEMORY;
1676 if (!(buf = heap_alloc( (len + len_action + 2) * sizeof(WCHAR) ))) goto done;
1677 memcpy( buf, actionW, len_action * sizeof(WCHAR) );
1678 memcpy( buf + len_action, msg->action.chars, len * sizeof(WCHAR) );
1679 len += len_action;
1680 buf[len++] = '"';
1681 buf[len] = 0;
1683 header = build_http_header( contenttypeW, buf, &len );
1684 heap_free( buf );
1685 if (!header) goto done;
1687 hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON );
1688 break;
1690 default:
1691 FIXME( "unhandled envelope version %u\n", msg->version_env );
1692 hr = E_NOTIMPL;
1695 done:
1696 heap_free( header );
1697 LeaveCriticalSection( &msg->cs );
1698 return hr;
1701 void message_set_send_context( WS_MESSAGE *handle, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT *ctx )
1703 struct msg *msg = (struct msg *)handle;
1705 EnterCriticalSection( &msg->cs );
1707 if (msg->magic != MSG_MAGIC)
1709 LeaveCriticalSection( &msg->cs );
1710 return;
1713 msg->ctx_send.callback = ctx->callback;
1714 msg->ctx_send.state = ctx->state;
1716 LeaveCriticalSection( &msg->cs );
1719 void message_set_receive_context( WS_MESSAGE *handle, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT *ctx )
1721 struct msg *msg = (struct msg *)handle;
1723 EnterCriticalSection( &msg->cs );
1725 if (msg->magic != MSG_MAGIC)
1727 LeaveCriticalSection( &msg->cs );
1728 return;
1731 msg->ctx_receive.callback = ctx->callback;
1732 msg->ctx_receive.state = ctx->state;
1734 LeaveCriticalSection( &msg->cs );
1737 void message_do_send_callback( WS_MESSAGE *handle )
1739 struct msg *msg = (struct msg *)handle;
1741 EnterCriticalSection( &msg->cs );
1743 if (msg->magic != MSG_MAGIC)
1745 LeaveCriticalSection( &msg->cs );
1746 return;
1749 if (msg->ctx_send.callback)
1751 HRESULT hr;
1752 TRACE( "executing callback %p\n", msg->ctx_send.callback );
1753 hr = msg->ctx_send.callback( handle, msg->heap, msg->ctx_send.state, NULL );
1754 TRACE( "callback %p returned %08x\n", msg->ctx_send.callback, hr );
1757 LeaveCriticalSection( &msg->cs );
1760 void message_do_receive_callback( WS_MESSAGE *handle )
1762 struct msg *msg = (struct msg *)handle;
1764 EnterCriticalSection( &msg->cs );
1766 if (msg->magic != MSG_MAGIC)
1768 LeaveCriticalSection( &msg->cs );
1769 return;
1772 if (msg->ctx_receive.callback)
1774 HRESULT hr;
1775 TRACE( "executing callback %p\n", msg->ctx_receive.callback );
1776 hr = msg->ctx_receive.callback( handle, msg->heap, msg->ctx_receive.state, NULL );
1777 TRACE( "callback %p returned %08x\n", msg->ctx_receive.callback, hr );
1780 LeaveCriticalSection( &msg->cs );
1783 HRESULT message_set_action( WS_MESSAGE *handle, const WS_XML_STRING *action )
1785 struct msg *msg = (struct msg *)handle;
1786 HRESULT hr = S_OK;
1788 EnterCriticalSection( &msg->cs );
1790 if (msg->magic != MSG_MAGIC)
1792 LeaveCriticalSection( &msg->cs );
1793 return E_INVALIDARG;
1796 if (!action || !action->length)
1798 heap_free( msg->action.chars );
1799 msg->action.chars = NULL;
1800 msg->action.length = 0;
1802 else
1804 WCHAR *chars;
1805 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)action->bytes, action->length, NULL, 0 );
1806 if (!(chars = heap_alloc( len * sizeof(WCHAR) ))) hr = E_OUTOFMEMORY;
1807 else
1809 MultiByteToWideChar( CP_UTF8, 0, (char *)action->bytes, action->length, chars, len );
1810 heap_free( msg->action.chars );
1811 msg->action.chars = chars;
1812 msg->action.length = len;
1816 LeaveCriticalSection( &msg->cs );
1817 return hr;