gdi32/tests: Add a test case for DIB color painting.
[wine.git] / dlls / webservices / channel.c
blob09cfd8075e4c691fcc7fa002ea8e277c569dc002
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"
31 #include "sock.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
35 static const struct prop_desc channel_props[] =
37 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE */
38 { sizeof(UINT64), FALSE }, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_MESSAGE_SIZE */
39 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_START_SIZE */
40 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_FLUSH_SIZE */
41 { sizeof(WS_ENCODING), TRUE }, /* WS_CHANNEL_PROPERTY_ENCODING */
42 { sizeof(WS_ENVELOPE_VERSION), FALSE }, /* WS_CHANNEL_PROPERTY_ENVELOPE_VERSION */
43 { sizeof(WS_ADDRESSING_VERSION), FALSE }, /* WS_CHANNEL_PROPERTY_ADDRESSING_VERSION */
44 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE */
45 { sizeof(WS_CHANNEL_STATE), TRUE }, /* WS_CHANNEL_PROPERTY_STATE */
46 { sizeof(WS_CALLBACK_MODEL), FALSE }, /* WS_CHANNEL_PROPERTY_ASYNC_CALLBACK_MODEL */
47 { sizeof(WS_IP_VERSION), FALSE }, /* WS_CHANNEL_PROPERTY_IP_VERSION */
48 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_RESOLVE_TIMEOUT */
49 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_CONNECT_TIMEOUT */
50 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_SEND_TIMEOUT */
51 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_RECEIVE_RESPONSE_TIMEOUT */
52 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_RECEIVE_TIMEOUT */
53 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_CLOSE_TIMEOUT */
54 { sizeof(BOOL), FALSE }, /* WS_CHANNEL_PROPERTY_ENABLE_TIMEOUTS */
55 { sizeof(WS_TRANSFER_MODE), FALSE }, /* WS_CHANNEL_PROPERTY_TRANSFER_MODE */
56 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_MULTICAST_INTERFACE */
57 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_MULTICAST_HOPS */
58 { sizeof(WS_ENDPOINT_ADDRESS), TRUE }, /* WS_CHANNEL_PROPERTY_REMOTE_ADDRESS */
59 { sizeof(SOCKADDR_STORAGE), TRUE }, /* WS_CHANNEL_PROPERTY_REMOTE_IP_ADDRESS */
60 { sizeof(ULONGLONG), TRUE }, /* WS_CHANNEL_PROPERTY_HTTP_CONNECTION_ID */
61 { sizeof(WS_CUSTOM_CHANNEL_CALLBACKS), FALSE }, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_CALLBACKS */
62 { 0, FALSE }, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_PARAMETERS */
63 { sizeof(void *), FALSE }, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_INSTANCE */
64 { sizeof(WS_STRING), TRUE }, /* WS_CHANNEL_PROPERTY_TRANSPORT_URL */
65 { sizeof(BOOL), FALSE }, /* WS_CHANNEL_PROPERTY_NO_DELAY */
66 { sizeof(BOOL), FALSE }, /* WS_CHANNEL_PROPERTY_SEND_KEEP_ALIVES */
67 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_TIME */
68 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_INTERVAL */
69 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_MAX_HTTP_SERVER_CONNECTIONS */
70 { sizeof(BOOL), TRUE }, /* WS_CHANNEL_PROPERTY_IS_SESSION_SHUT_DOWN */
71 { sizeof(WS_CHANNEL_TYPE), TRUE }, /* WS_CHANNEL_PROPERTY_CHANNEL_TYPE */
72 { sizeof(ULONG), FALSE }, /* WS_CHANNEL_PROPERTY_TRIM_BUFFERED_MESSAGE_SIZE */
73 { sizeof(WS_CHANNEL_ENCODER), FALSE }, /* WS_CHANNEL_PROPERTY_ENCODER */
74 { sizeof(WS_CHANNEL_DECODER), FALSE }, /* WS_CHANNEL_PROPERTY_DECODER */
75 { sizeof(WS_PROTECTION_LEVEL), TRUE }, /* WS_CHANNEL_PROPERTY_PROTECTION_LEVEL */
76 { sizeof(WS_COOKIE_MODE), FALSE }, /* WS_CHANNEL_PROPERTY_COOKIE_MODE */
77 { sizeof(WS_HTTP_PROXY_SETTING_MODE), FALSE }, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SETTING_MODE */
78 { sizeof(WS_CUSTOM_HTTP_PROXY), FALSE }, /* WS_CHANNEL_PROPERTY_CUSTOM_HTTP_PROXY */
79 { sizeof(WS_HTTP_MESSAGE_MAPPING), FALSE }, /* WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING */
80 { sizeof(BOOL), FALSE }, /* WS_CHANNEL_PROPERTY_ENABLE_HTTP_REDIRECT */
81 { sizeof(WS_HTTP_REDIRECT_CALLBACK_CONTEXT), FALSE }, /* WS_CHANNEL_PROPERTY_HTTP_REDIRECT_CALLBACK_CONTEXT */
82 { sizeof(BOOL), FALSE }, /* WS_CHANNEL_PROPERTY_FAULTS_AS_ERRORS */
83 { sizeof(BOOL), FALSE }, /* WS_CHANNEL_PROPERTY_ALLOW_UNSECURED_FAULTS */
84 { sizeof(WCHAR *), TRUE }, /* WS_CHANNEL_PROPERTY_HTTP_SERVER_SPN */
85 { sizeof(WCHAR *), TRUE }, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SPN */
86 { sizeof(ULONG), FALSE } /* WS_CHANNEL_PROPERTY_MAX_HTTP_REQUEST_HEADERS_BUFFER_SIZE */
89 enum session_state
91 SESSION_STATE_UNINITIALIZED,
92 SESSION_STATE_SETUP_COMPLETE,
95 struct channel
97 ULONG magic;
98 CRITICAL_SECTION cs;
99 WS_CHANNEL_TYPE type;
100 WS_CHANNEL_BINDING binding;
101 WS_CHANNEL_STATE state;
102 WS_ENDPOINT_ADDRESS addr;
103 WS_XML_WRITER *writer;
104 WS_XML_READER *reader;
105 WS_MESSAGE *msg;
106 WS_ENCODING encoding;
107 enum session_state session_state;
108 struct dictionary dict;
109 union
111 struct
113 HINTERNET session;
114 HINTERNET connect;
115 HINTERNET request;
116 } http;
117 struct
119 SOCKET socket;
120 } tcp;
121 struct
123 SOCKET socket;
124 } udp;
125 } u;
126 char *read_buf;
127 ULONG read_buflen;
128 ULONG read_size;
129 ULONG prop_count;
130 struct prop prop[sizeof(channel_props)/sizeof(channel_props[0])];
133 #define CHANNEL_MAGIC (('C' << 24) | ('H' << 16) | ('A' << 8) | 'N')
135 static struct channel *alloc_channel(void)
137 static const ULONG count = sizeof(channel_props)/sizeof(channel_props[0]);
138 struct channel *ret;
139 ULONG size = sizeof(*ret) + prop_size( channel_props, count );
141 if (!(ret = heap_alloc_zero( size ))) return NULL;
143 ret->magic = CHANNEL_MAGIC;
144 InitializeCriticalSection( &ret->cs );
145 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": channel.cs");
147 prop_init( channel_props, count, ret->prop, &ret[1] );
148 ret->prop_count = count;
149 return ret;
152 static void reset_channel( struct channel *channel )
154 channel->state = WS_CHANNEL_STATE_CREATED;
155 heap_free( channel->addr.url.chars );
156 channel->addr.url.chars = NULL;
157 channel->addr.url.length = 0;
158 channel->msg = NULL;
159 channel->read_size = 0;
160 channel->session_state = SESSION_STATE_UNINITIALIZED;
161 clear_dict( &channel->dict );
163 switch (channel->binding)
165 case WS_HTTP_CHANNEL_BINDING:
166 WinHttpCloseHandle( channel->u.http.request );
167 channel->u.http.request = NULL;
168 WinHttpCloseHandle( channel->u.http.connect );
169 channel->u.http.connect = NULL;
170 WinHttpCloseHandle( channel->u.http.session );
171 channel->u.http.session = NULL;
172 break;
174 case WS_TCP_CHANNEL_BINDING:
175 closesocket( channel->u.tcp.socket );
176 channel->u.tcp.socket = -1;
177 break;
179 case WS_UDP_CHANNEL_BINDING:
180 closesocket( channel->u.udp.socket );
181 channel->u.udp.socket = -1;
182 break;
184 default: break;
188 static void free_channel( struct channel *channel )
190 reset_channel( channel );
192 WsFreeWriter( channel->writer );
193 WsFreeReader( channel->reader );
195 heap_free( channel->read_buf );
197 channel->cs.DebugInfo->Spare[0] = 0;
198 DeleteCriticalSection( &channel->cs );
199 heap_free( channel );
202 static HRESULT create_channel( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding,
203 const WS_CHANNEL_PROPERTY *properties, ULONG count, struct channel **ret )
205 struct channel *channel;
206 ULONG i, msg_size = 65536;
207 WS_ENVELOPE_VERSION env_version = WS_ENVELOPE_VERSION_SOAP_1_2;
208 WS_ADDRESSING_VERSION addr_version = WS_ADDRESSING_VERSION_1_0;
209 HRESULT hr;
211 if (!(channel = alloc_channel())) return E_OUTOFMEMORY;
213 prop_set( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE,
214 &msg_size, sizeof(msg_size) );
215 prop_set( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION,
216 &env_version, sizeof(env_version) );
217 prop_set( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_ADDRESSING_VERSION,
218 &addr_version, sizeof(addr_version) );
220 channel->type = type;
221 channel->binding = binding;
223 switch (channel->binding)
225 case WS_HTTP_CHANNEL_BINDING:
226 channel->encoding = WS_ENCODING_XML_UTF8;
227 break;
229 case WS_TCP_CHANNEL_BINDING:
230 channel->u.tcp.socket = -1;
231 channel->encoding = WS_ENCODING_XML_BINARY_SESSION_1;
232 break;
234 case WS_UDP_CHANNEL_BINDING:
235 channel->u.udp.socket = -1;
236 channel->encoding = WS_ENCODING_XML_UTF8;
237 break;
239 default: break;
242 for (i = 0; i < count; i++)
244 switch (properties[i].id)
246 case WS_CHANNEL_PROPERTY_ENCODING:
247 if (!properties[i].value || properties[i].valueSize != sizeof(channel->encoding))
249 free_channel( channel );
250 return E_INVALIDARG;
252 channel->encoding = *(WS_ENCODING *)properties[i].value;
253 break;
255 default:
256 if ((hr = prop_set( channel->prop, channel->prop_count, properties[i].id, properties[i].value,
257 properties[i].valueSize )) != S_OK)
259 free_channel( channel );
260 return hr;
262 break;
266 *ret = channel;
267 return S_OK;
270 /**************************************************************************
271 * WsCreateChannel [webservices.@]
273 HRESULT WINAPI WsCreateChannel( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding,
274 const WS_CHANNEL_PROPERTY *properties, ULONG count,
275 const WS_SECURITY_DESCRIPTION *desc, WS_CHANNEL **handle,
276 WS_ERROR *error )
278 struct channel *channel;
279 HRESULT hr;
281 TRACE( "%u %u %p %u %p %p %p\n", type, binding, properties, count, desc, handle, error );
282 if (error) FIXME( "ignoring error parameter\n" );
283 if (desc) FIXME( "ignoring security description\n" );
285 if (!handle) return E_INVALIDARG;
287 if (type != WS_CHANNEL_TYPE_REQUEST && type != WS_CHANNEL_TYPE_DUPLEX &&
288 type != WS_CHANNEL_TYPE_DUPLEX_SESSION)
290 FIXME( "channel type %u not implemented\n", type );
291 return E_NOTIMPL;
293 if (binding != WS_HTTP_CHANNEL_BINDING && binding != WS_TCP_CHANNEL_BINDING &&
294 binding != WS_UDP_CHANNEL_BINDING)
296 FIXME( "channel binding %u not implemented\n", binding );
297 return E_NOTIMPL;
300 if ((hr = create_channel( type, binding, properties, count, &channel )) != S_OK) return hr;
302 *handle = (WS_CHANNEL *)channel;
303 return S_OK;
306 /**************************************************************************
307 * WsCreateChannelForListener [webservices.@]
309 HRESULT WINAPI WsCreateChannelForListener( WS_LISTENER *listener_handle, const WS_CHANNEL_PROPERTY *properties,
310 ULONG count, WS_CHANNEL **handle, WS_ERROR *error )
312 struct channel *channel;
313 WS_CHANNEL_TYPE type;
314 WS_CHANNEL_BINDING binding;
315 HRESULT hr;
317 TRACE( "%p %p %u %p %p\n", listener_handle, properties, count, handle, error );
318 if (error) FIXME( "ignoring error parameter\n" );
320 if (!listener_handle || !handle) return E_INVALIDARG;
322 if ((hr = WsGetListenerProperty( listener_handle, WS_LISTENER_PROPERTY_CHANNEL_TYPE, &type,
323 sizeof(type), NULL )) != S_OK) return hr;
325 if ((hr = WsGetListenerProperty( listener_handle, WS_LISTENER_PROPERTY_CHANNEL_BINDING, &binding,
326 sizeof(binding), NULL )) != S_OK) return hr;
328 if ((hr = create_channel( type, binding, properties, count, &channel )) != S_OK) return hr;
330 *handle = (WS_CHANNEL *)channel;
331 return S_OK;
334 /**************************************************************************
335 * WsFreeChannel [webservices.@]
337 void WINAPI WsFreeChannel( WS_CHANNEL *handle )
339 struct channel *channel = (struct channel *)handle;
341 TRACE( "%p\n", handle );
343 if (!channel) return;
345 EnterCriticalSection( &channel->cs );
347 if (channel->magic != CHANNEL_MAGIC)
349 LeaveCriticalSection( &channel->cs );
350 return;
353 channel->magic = 0;
355 LeaveCriticalSection( &channel->cs );
356 free_channel( channel );
359 /**************************************************************************
360 * WsResetChannel [webservices.@]
362 HRESULT WINAPI WsResetChannel( WS_CHANNEL *handle, WS_ERROR *error )
364 struct channel *channel = (struct channel *)handle;
366 TRACE( "%p %p\n", handle, error );
367 if (error) FIXME( "ignoring error parameter\n" );
369 if (!channel) return E_INVALIDARG;
371 EnterCriticalSection( &channel->cs );
373 if (channel->magic != CHANNEL_MAGIC)
375 LeaveCriticalSection( &channel->cs );
376 return E_INVALIDARG;
379 if (channel->state != WS_CHANNEL_STATE_CREATED && channel->state != WS_CHANNEL_STATE_CLOSED)
381 LeaveCriticalSection( &channel->cs );
382 return WS_E_INVALID_OPERATION;
385 reset_channel( channel );
387 LeaveCriticalSection( &channel->cs );
388 return S_OK;
391 /**************************************************************************
392 * WsGetChannelProperty [webservices.@]
394 HRESULT WINAPI WsGetChannelProperty( WS_CHANNEL *handle, WS_CHANNEL_PROPERTY_ID id, void *buf,
395 ULONG size, WS_ERROR *error )
397 struct channel *channel = (struct channel *)handle;
398 HRESULT hr = S_OK;
400 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
401 if (error) FIXME( "ignoring error parameter\n" );
403 if (!channel) return E_INVALIDARG;
405 EnterCriticalSection( &channel->cs );
407 if (channel->magic != CHANNEL_MAGIC)
409 LeaveCriticalSection( &channel->cs );
410 return E_INVALIDARG;
413 switch (id)
415 case WS_CHANNEL_PROPERTY_CHANNEL_TYPE:
416 if (!buf || size != sizeof(channel->type)) hr = E_INVALIDARG;
417 else *(WS_CHANNEL_TYPE *)buf = channel->type;
418 break;
420 case WS_CHANNEL_PROPERTY_ENCODING:
421 if (!buf || size != sizeof(channel->encoding)) hr = E_INVALIDARG;
422 else *(WS_ENCODING *)buf = channel->encoding;
423 break;
425 default:
426 hr = prop_get( channel->prop, channel->prop_count, id, buf, size );
429 LeaveCriticalSection( &channel->cs );
430 return hr;
433 /**************************************************************************
434 * WsSetChannelProperty [webservices.@]
436 HRESULT WINAPI WsSetChannelProperty( WS_CHANNEL *handle, WS_CHANNEL_PROPERTY_ID id, const void *value,
437 ULONG size, WS_ERROR *error )
439 struct channel *channel = (struct channel *)handle;
440 HRESULT hr;
442 TRACE( "%p %u %p %u\n", handle, id, value, size );
443 if (error) FIXME( "ignoring error parameter\n" );
445 if (!channel) return E_INVALIDARG;
447 EnterCriticalSection( &channel->cs );
449 if (channel->magic != CHANNEL_MAGIC)
451 LeaveCriticalSection( &channel->cs );
452 return E_INVALIDARG;
455 hr = prop_set( channel->prop, channel->prop_count, id, value, size );
457 LeaveCriticalSection( &channel->cs );
458 return hr;
461 static HRESULT open_channel( struct channel *channel, const WS_ENDPOINT_ADDRESS *endpoint )
463 if (endpoint->headers || endpoint->extensions || endpoint->identity)
465 FIXME( "headers, extensions or identity not supported\n" );
466 return E_NOTIMPL;
469 if (!(channel->addr.url.chars = heap_alloc( endpoint->url.length * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
470 memcpy( channel->addr.url.chars, endpoint->url.chars, endpoint->url.length * sizeof(WCHAR) );
471 channel->addr.url.length = endpoint->url.length;
473 channel->state = WS_CHANNEL_STATE_OPEN;
474 return S_OK;
477 /**************************************************************************
478 * WsOpenChannel [webservices.@]
480 HRESULT WINAPI WsOpenChannel( WS_CHANNEL *handle, const WS_ENDPOINT_ADDRESS *endpoint,
481 const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
483 struct channel *channel = (struct channel *)handle;
484 HRESULT hr;
486 TRACE( "%p %p %p %p\n", handle, endpoint, ctx, error );
487 if (error) FIXME( "ignoring error parameter\n" );
488 if (ctx) FIXME( "ignoring ctx parameter\n" );
490 if (!channel || !endpoint) return E_INVALIDARG;
492 EnterCriticalSection( &channel->cs );
494 if (channel->magic != CHANNEL_MAGIC)
496 LeaveCriticalSection( &channel->cs );
497 return E_INVALIDARG;
500 if (channel->state != WS_CHANNEL_STATE_CREATED)
502 LeaveCriticalSection( &channel->cs );
503 return WS_E_INVALID_OPERATION;
506 hr = open_channel( channel, endpoint );
508 LeaveCriticalSection( &channel->cs );
509 return hr;
512 static void close_channel( struct channel *channel )
514 reset_channel( channel );
515 channel->state = WS_CHANNEL_STATE_CLOSED;
518 /**************************************************************************
519 * WsCloseChannel [webservices.@]
521 HRESULT WINAPI WsCloseChannel( WS_CHANNEL *handle, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
523 struct channel *channel = (struct channel *)handle;
525 TRACE( "%p %p %p\n", handle, ctx, error );
526 if (error) FIXME( "ignoring error parameter\n" );
527 if (ctx) FIXME( "ignoring ctx parameter\n" );
529 if (!channel) return E_INVALIDARG;
531 EnterCriticalSection( &channel->cs );
533 if (channel->magic != CHANNEL_MAGIC)
535 LeaveCriticalSection( &channel->cs );
536 return E_INVALIDARG;
539 close_channel( channel );
541 LeaveCriticalSection( &channel->cs );
542 return S_OK;
545 static HRESULT parse_http_url( const WCHAR *url, ULONG len, URL_COMPONENTS *uc )
547 HRESULT hr = E_OUTOFMEMORY;
548 WCHAR *tmp;
549 DWORD err;
551 memset( uc, 0, sizeof(*uc) );
552 uc->dwStructSize = sizeof(*uc);
553 uc->dwHostNameLength = 128;
554 uc->lpszHostName = heap_alloc( uc->dwHostNameLength * sizeof(WCHAR) );
555 uc->dwUrlPathLength = 128;
556 uc->lpszUrlPath = heap_alloc( uc->dwUrlPathLength * sizeof(WCHAR) );
557 uc->dwExtraInfoLength = 128;
558 uc->lpszExtraInfo = heap_alloc( uc->dwExtraInfoLength * sizeof(WCHAR) );
559 if (!uc->lpszHostName || !uc->lpszUrlPath || !uc->lpszExtraInfo) goto error;
561 if (!WinHttpCrackUrl( url, len, ICU_DECODE, uc ))
563 if ((err = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
565 hr = HRESULT_FROM_WIN32( err );
566 goto error;
568 if (!(tmp = heap_realloc( uc->lpszHostName, uc->dwHostNameLength * sizeof(WCHAR) ))) goto error;
569 uc->lpszHostName = tmp;
570 if (!(tmp = heap_realloc( uc->lpszUrlPath, uc->dwUrlPathLength * sizeof(WCHAR) ))) goto error;
571 uc->lpszUrlPath = tmp;
572 if (!(tmp = heap_realloc( uc->lpszExtraInfo, uc->dwExtraInfoLength * sizeof(WCHAR) ))) goto error;
573 uc->lpszExtraInfo = tmp;
574 WinHttpCrackUrl( url, len, ICU_DECODE, uc );
577 return S_OK;
579 error:
580 heap_free( uc->lpszHostName );
581 heap_free( uc->lpszUrlPath );
582 heap_free( uc->lpszExtraInfo );
583 return hr;
586 static HRESULT connect_channel_http( struct channel *channel )
588 static const WCHAR agentW[] =
589 {'M','S','-','W','e','b','S','e','r','v','i','c','e','s','/','1','.','0',0};
590 static const WCHAR postW[] =
591 {'P','O','S','T',0};
592 HINTERNET ses = NULL, con = NULL, req = NULL;
593 WCHAR *path;
594 URL_COMPONENTS uc;
595 DWORD flags = 0;
596 HRESULT hr;
598 if (channel->u.http.request) return S_OK;
600 if ((hr = parse_http_url( channel->addr.url.chars, channel->addr.url.length, &uc )) != S_OK) return hr;
601 if (!uc.dwExtraInfoLength) path = uc.lpszUrlPath;
602 else if (!(path = heap_alloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) )))
604 hr = E_OUTOFMEMORY;
605 goto done;
607 else
609 strcpyW( path, uc.lpszUrlPath );
610 strcatW( path, uc.lpszExtraInfo );
613 switch (uc.nScheme)
615 case INTERNET_SCHEME_HTTP: break;
616 case INTERNET_SCHEME_HTTPS:
617 flags |= WINHTTP_FLAG_SECURE;
618 break;
620 default:
621 hr = WS_E_INVALID_ENDPOINT_URL;
622 goto done;
625 if (!(ses = WinHttpOpen( agentW, 0, NULL, NULL, 0 )))
627 hr = HRESULT_FROM_WIN32( GetLastError() );
628 goto done;
630 if (!(con = WinHttpConnect( ses, uc.lpszHostName, uc.nPort, 0 )))
632 hr = HRESULT_FROM_WIN32( GetLastError() );
633 goto done;
635 if (!(req = WinHttpOpenRequest( con, postW, path, NULL, NULL, NULL, flags )))
637 hr = HRESULT_FROM_WIN32( GetLastError() );
638 goto done;
641 if ((hr = message_insert_http_headers( channel->msg, req )) != S_OK) goto done;
643 channel->u.http.session = ses;
644 channel->u.http.connect = con;
645 channel->u.http.request = req;
647 done:
648 if (hr != S_OK)
650 WinHttpCloseHandle( req );
651 WinHttpCloseHandle( con );
652 WinHttpCloseHandle( ses );
654 heap_free( uc.lpszHostName );
655 heap_free( uc.lpszUrlPath );
656 heap_free( uc.lpszExtraInfo );
657 if (path != uc.lpszUrlPath) heap_free( path );
658 return hr;
661 static HRESULT connect_channel_tcp( struct channel *channel )
663 struct sockaddr_storage storage;
664 struct sockaddr *addr = (struct sockaddr *)&storage;
665 int addr_len;
666 WS_URL_SCHEME_TYPE scheme;
667 WCHAR *host;
668 USHORT port;
669 HRESULT hr;
671 if (channel->u.tcp.socket != -1) return S_OK;
673 if ((hr = parse_url( &channel->addr.url, &scheme, &host, &port )) != S_OK) return hr;
674 if (scheme != WS_URL_NETTCP_SCHEME_TYPE)
676 heap_free( host );
677 return WS_E_INVALID_ENDPOINT_URL;
680 winsock_init();
682 hr = resolve_hostname( host, port, addr, &addr_len, 0 );
683 heap_free( host );
684 if (hr != S_OK) return hr;
686 if ((channel->u.tcp.socket = socket( addr->sa_family, SOCK_STREAM, 0 )) == -1)
687 return HRESULT_FROM_WIN32( WSAGetLastError() );
689 if (connect( channel->u.tcp.socket, addr, addr_len ) < 0)
691 closesocket( channel->u.tcp.socket );
692 channel->u.tcp.socket = -1;
693 return HRESULT_FROM_WIN32( WSAGetLastError() );
696 return S_OK;
699 static HRESULT connect_channel_udp( struct channel *channel )
701 struct sockaddr_storage storage;
702 struct sockaddr *addr = (struct sockaddr *)&storage;
703 int addr_len;
704 WS_URL_SCHEME_TYPE scheme;
705 WCHAR *host;
706 USHORT port;
707 HRESULT hr;
709 if (channel->u.udp.socket != -1) return S_OK;
711 if ((hr = parse_url( &channel->addr.url, &scheme, &host, &port )) != S_OK) return hr;
712 if (scheme != WS_URL_SOAPUDP_SCHEME_TYPE)
714 heap_free( host );
715 return WS_E_INVALID_ENDPOINT_URL;
718 winsock_init();
720 hr = resolve_hostname( host, port, addr, &addr_len, 0 );
721 heap_free( host );
722 if (hr != S_OK) return hr;
724 if ((channel->u.udp.socket = socket( addr->sa_family, SOCK_DGRAM, 0 )) == -1)
725 return HRESULT_FROM_WIN32( WSAGetLastError() );
727 if (connect( channel->u.udp.socket, addr, addr_len ) < 0)
729 closesocket( channel->u.udp.socket );
730 channel->u.udp.socket = -1;
731 return HRESULT_FROM_WIN32( WSAGetLastError() );
734 return S_OK;
737 static HRESULT connect_channel( struct channel *channel )
739 switch (channel->binding)
741 case WS_HTTP_CHANNEL_BINDING:
742 return connect_channel_http( channel );
744 case WS_TCP_CHANNEL_BINDING:
745 return connect_channel_tcp( channel );
747 case WS_UDP_CHANNEL_BINDING:
748 return connect_channel_udp( channel );
750 default:
751 ERR( "unhandled binding %u\n", channel->binding );
752 return E_NOTIMPL;
756 static HRESULT write_message( WS_MESSAGE *handle, WS_XML_WRITER *writer, const WS_ELEMENT_DESCRIPTION *desc,
757 WS_WRITE_OPTION option, const void *body, ULONG size )
759 HRESULT hr;
760 if ((hr = WsWriteEnvelopeStart( handle, writer, NULL, NULL, NULL )) != S_OK) return hr;
761 if ((hr = WsWriteBody( handle, desc, option, body, size, NULL )) != S_OK) return hr;
762 return WsWriteEnvelopeEnd( handle, NULL );
765 static HRESULT send_message_http( HANDLE request, BYTE *data, ULONG len )
767 if (!WinHttpSendRequest( request, NULL, 0, data, len, len, 0 ))
768 return HRESULT_FROM_WIN32( GetLastError() );
770 if (!WinHttpReceiveResponse( request, NULL ))
771 return HRESULT_FROM_WIN32( GetLastError() );
772 return S_OK;
775 static HRESULT send_byte( SOCKET socket, BYTE byte )
777 int count = send( socket, (char *)&byte, 1, 0 );
778 if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
779 if (count != 1) return WS_E_OTHER;
780 return S_OK;
783 static HRESULT send_bytes( SOCKET socket, BYTE *bytes, int len )
785 int count = send( socket, (char *)bytes, len, 0 );
786 if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
787 if (count != len) return WS_E_OTHER;
788 return S_OK;
791 static HRESULT send_size( SOCKET socket, ULONG size )
793 HRESULT hr;
794 if (size < 0x80) return send_byte( socket, size );
795 if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
796 if ((size >>= 7) < 0x80) return send_byte( socket, size );
797 if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
798 if ((size >>= 7) < 0x80) return send_byte( socket, size );
799 if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
800 if ((size >>= 7) < 0x80) return send_byte( socket, size );
801 if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
802 if ((size >>= 7) < 0x08) return send_byte( socket, size );
803 return E_INVALIDARG;
806 enum frame_record_type
808 FRAME_RECORD_TYPE_VERSION,
809 FRAME_RECORD_TYPE_MODE,
810 FRAME_RECORD_TYPE_VIA,
811 FRAME_RECORD_TYPE_KNOWN_ENCODING,
812 FRAME_RECORD_TYPE_EXTENSIBLE_ENCODING,
813 FRAME_RECORD_TYPE_UNSIZED_ENVELOPE,
814 FRAME_RECORD_TYPE_SIZED_ENVELOPE,
815 FRAME_RECORD_TYPE_END,
816 FRAME_RECORD_TYPE_FAULT,
817 FRAME_RECORD_TYPE_UPGRADE_REQUEST,
818 FRAME_RECORD_TYPE_UPGRADE_RESPONSE,
819 FRAME_RECORD_TYPE_PREAMBLE_ACK,
820 FRAME_RECORD_TYPE_PREAMBLE_END,
823 static inline ULONG size_length( ULONG size )
825 if (size < 0x80) return 1;
826 if (size < 0x4000) return 2;
827 if (size < 0x200000) return 3;
828 if (size < 0x10000000) return 4;
829 return 5;
832 static ULONG string_table_size( const WS_XML_DICTIONARY *dict )
834 ULONG i, size = 0;
835 for (i = 0; i < dict->stringCount; i++)
836 size += size_length( dict->strings[i].length ) + dict->strings[i].length;
837 return size;
840 static HRESULT send_string_table( SOCKET socket, const WS_XML_DICTIONARY *dict )
842 ULONG i;
843 HRESULT hr;
844 for (i = 0; i < dict->stringCount; i++)
846 if ((hr = send_size( socket, dict->strings[i].length )) != S_OK) return hr;
847 if ((hr = send_bytes( socket, dict->strings[i].bytes, dict->strings[i].length )) != S_OK) return hr;
849 return S_OK;
852 static HRESULT string_to_utf8( const WS_STRING *str, unsigned char **ret, int *len )
854 *len = WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, NULL, 0, NULL, NULL );
855 if (!(*ret = heap_alloc( *len ))) return E_OUTOFMEMORY;
856 WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, (char *)*ret, *len, NULL, NULL );
857 return S_OK;
860 enum session_mode
862 SESSION_MODE_INVALID = 0,
863 SESSION_MODE_SINGLETON = 1,
864 SESSION_MODE_DUPLEX = 2,
865 SESSION_MODE_SIMPLEX = 3,
868 static enum session_mode map_channel_type( struct channel *channel )
870 switch (channel->type)
872 case WS_CHANNEL_TYPE_DUPLEX_SESSION: return SESSION_MODE_DUPLEX;
873 default:
874 FIXME( "unhandled channel type %08x\n", channel->type );
875 return SESSION_MODE_INVALID;
879 enum known_encoding
881 KNOWN_ENCODING_SOAP11_UTF8 = 0x00,
882 KNOWN_ENCODING_SOAP11_UTF16 = 0x01,
883 KNOWN_ENCODING_SOAP11_UTF16LE = 0x02,
884 KNOWN_ENCODING_SOAP12_UTF8 = 0x03,
885 KNOWN_ENCODING_SOAP12_UTF16 = 0x04,
886 KNOWN_ENCODING_SOAP12_UTF16LE = 0x05,
887 KNOWN_ENCODING_SOAP12_MTOM = 0x06,
888 KNOWN_ENCODING_SOAP12_BINARY = 0x07,
889 KNOWN_ENCODING_SOAP12_BINARY_SESSION = 0x08,
892 static enum known_encoding map_channel_encoding( struct channel *channel )
894 WS_ENVELOPE_VERSION version;
896 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION, &version, sizeof(version) );
898 switch (version)
900 case WS_ENVELOPE_VERSION_SOAP_1_1:
901 switch (channel->encoding)
903 case WS_ENCODING_XML_UTF8: return KNOWN_ENCODING_SOAP11_UTF8;
904 case WS_ENCODING_XML_UTF16LE: return KNOWN_ENCODING_SOAP11_UTF16LE;
905 default:
906 FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
907 return 0;
909 case WS_ENVELOPE_VERSION_SOAP_1_2:
910 switch (channel->encoding)
912 case WS_ENCODING_XML_UTF8: return KNOWN_ENCODING_SOAP12_UTF8;
913 case WS_ENCODING_XML_UTF16LE: return KNOWN_ENCODING_SOAP12_UTF16LE;
914 case WS_ENCODING_XML_BINARY_1: return KNOWN_ENCODING_SOAP12_BINARY;
915 case WS_ENCODING_XML_BINARY_SESSION_1: return KNOWN_ENCODING_SOAP12_BINARY_SESSION;
916 default:
917 FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
918 return 0;
920 default:
921 ERR( "unhandled version %u\n", version );
922 return 0;
926 #define FRAME_VERSION_MAJOR 1
927 #define FRAME_VERSION_MINOR 1
929 static HRESULT send_preamble( struct channel *channel )
931 unsigned char *url;
932 HRESULT hr;
933 int len;
935 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_VERSION )) != S_OK) return hr;
936 if ((hr = send_byte( channel->u.tcp.socket, FRAME_VERSION_MAJOR )) != S_OK) return hr;
937 if ((hr = send_byte( channel->u.tcp.socket, FRAME_VERSION_MINOR )) != S_OK) return hr;
939 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_MODE )) != S_OK) return hr;
940 if ((hr = send_byte( channel->u.tcp.socket, map_channel_type(channel) )) != S_OK) return hr;
942 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_VIA )) != S_OK) return hr;
943 if ((hr = string_to_utf8( &channel->addr.url, &url, &len )) != S_OK) return hr;
944 if ((hr = send_size( channel->u.tcp.socket, len )) != S_OK) goto done;
945 if ((hr = send_bytes( channel->u.tcp.socket, url, len )) != S_OK) goto done;
947 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_KNOWN_ENCODING )) != S_OK) goto done;
948 if ((hr = send_byte( channel->u.tcp.socket, map_channel_encoding(channel) )) != S_OK) goto done;
949 hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_PREAMBLE_END );
951 done:
952 heap_free( url );
953 return hr;
956 static HRESULT receive_bytes( struct channel *channel, unsigned char *bytes, int len )
958 int count = recv( channel->u.tcp.socket, (char *)bytes, len, 0 );
959 if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
960 if (count != len) return WS_E_INVALID_FORMAT;
961 return S_OK;
964 static HRESULT receive_preamble_ack( struct channel *channel )
966 unsigned char byte;
967 HRESULT hr;
969 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
970 if (byte != FRAME_RECORD_TYPE_PREAMBLE_ACK) return WS_E_INVALID_FORMAT;
971 channel->session_state = SESSION_STATE_SETUP_COMPLETE;
972 return S_OK;
975 static HRESULT send_sized_envelope( struct channel *channel, BYTE *data, ULONG len )
977 ULONG table_size = string_table_size( &channel->dict.dict );
978 HRESULT hr;
980 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_SIZED_ENVELOPE )) != S_OK) return hr;
981 if ((hr = send_size( channel->u.tcp.socket, size_length(table_size) + table_size + len )) != S_OK) return hr;
982 if ((hr = send_size( channel->u.tcp.socket, table_size )) != S_OK) return hr;
983 if ((hr = send_string_table( channel->u.tcp.socket, &channel->dict.dict )) != S_OK) return hr;
984 return send_bytes( channel->u.tcp.socket, data, len );
987 static HRESULT send_message( struct channel *channel, WS_MESSAGE *msg )
989 WS_XML_WRITER *writer;
990 WS_BYTES buf;
991 HRESULT hr;
993 channel->msg = msg;
994 if ((hr = connect_channel( channel )) != S_OK) return hr;
996 WsGetMessageProperty( channel->msg, WS_MESSAGE_PROPERTY_BODY_WRITER, &writer, sizeof(writer), NULL );
997 WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &buf, sizeof(buf), NULL );
999 switch (channel->binding)
1001 case WS_HTTP_CHANNEL_BINDING:
1002 return send_message_http( channel->u.http.request, buf.bytes, buf.length );
1004 case WS_TCP_CHANNEL_BINDING:
1005 if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
1007 switch (channel->session_state)
1009 case SESSION_STATE_UNINITIALIZED:
1010 if ((hr = send_preamble( channel )) != S_OK) return hr;
1011 if ((hr = receive_preamble_ack( channel )) != S_OK) return hr;
1012 /* fall through */
1014 case SESSION_STATE_SETUP_COMPLETE:
1015 return send_sized_envelope( channel, buf.bytes, buf.length );
1017 default:
1018 ERR( "unhandled session state %u\n", channel->session_state );
1019 return WS_E_OTHER;
1022 return send_bytes( channel->u.tcp.socket, buf.bytes, buf.length );
1024 case WS_UDP_CHANNEL_BINDING:
1025 return send_bytes( channel->u.udp.socket, buf.bytes, buf.length );
1027 default:
1028 ERR( "unhandled binding %u\n", channel->binding );
1029 return E_NOTIMPL;
1033 HRESULT channel_send_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
1035 struct channel *channel = (struct channel *)handle;
1036 HRESULT hr;
1038 EnterCriticalSection( &channel->cs );
1040 if (channel->magic != CHANNEL_MAGIC)
1042 LeaveCriticalSection( &channel->cs );
1043 return E_INVALIDARG;
1046 hr = send_message( channel, msg );
1048 LeaveCriticalSection( &channel->cs );
1049 return hr;
1052 static HRESULT init_writer( struct channel *channel )
1054 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
1055 WS_XML_WRITER_TEXT_ENCODING text = {{WS_XML_WRITER_ENCODING_TYPE_TEXT}};
1056 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
1057 WS_XML_WRITER_ENCODING *encoding;
1058 HRESULT hr;
1060 if (!channel->writer && (hr = WsCreateWriter( NULL, 0, &channel->writer, NULL )) != S_OK) return hr;
1062 switch (channel->encoding)
1064 case WS_ENCODING_XML_UTF8:
1065 text.charSet = WS_CHARSET_UTF8;
1066 encoding = &text.encoding;
1067 break;
1069 case WS_ENCODING_XML_BINARY_SESSION_1:
1070 bin.staticDictionary = (WS_XML_DICTIONARY *)&dict_builtin_static.dict;
1071 /* fall through */
1073 case WS_ENCODING_XML_BINARY_1:
1074 encoding = &bin.encoding;
1075 break;
1077 default:
1078 FIXME( "unhandled encoding %u\n", channel->encoding );
1079 return WS_E_NOT_SUPPORTED;
1082 return WsSetOutput( channel->writer, encoding, &buf.output, NULL, 0, NULL );
1085 /**************************************************************************
1086 * WsSendMessage [webservices.@]
1088 HRESULT WINAPI WsSendMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION *desc,
1089 WS_WRITE_OPTION option, const void *body, ULONG size, const WS_ASYNC_CONTEXT *ctx,
1090 WS_ERROR *error )
1092 struct channel *channel = (struct channel *)handle;
1093 HRESULT hr;
1095 TRACE( "%p %p %p %08x %p %u %p %p\n", handle, msg, desc, option, body, size, ctx, error );
1096 if (error) FIXME( "ignoring error parameter\n" );
1097 if (ctx) FIXME( "ignoring ctx parameter\n" );
1099 if (!channel || !msg || !desc) return E_INVALIDARG;
1101 EnterCriticalSection( &channel->cs );
1103 if (channel->magic != CHANNEL_MAGIC)
1105 LeaveCriticalSection( &channel->cs );
1106 return E_INVALIDARG;
1109 if ((hr = WsInitializeMessage( msg, WS_REQUEST_MESSAGE, NULL, NULL )) != S_OK) goto done;
1110 if ((hr = WsAddressMessage( msg, &channel->addr, NULL )) != S_OK) goto done;
1111 if ((hr = message_set_action( msg, desc->action )) != S_OK) goto done;
1113 if ((hr = init_writer( channel )) != S_OK) goto done;
1114 if ((hr = write_message( msg, channel->writer, desc->bodyElementDescription, option, body, size )) != S_OK)
1115 goto done;
1116 hr = send_message( channel, msg );
1118 done:
1119 LeaveCriticalSection( &channel->cs );
1120 return hr;
1123 static HRESULT resize_read_buffer( struct channel *channel, ULONG size )
1125 if (!channel->read_buf)
1127 if (!(channel->read_buf = heap_alloc( size ))) return E_OUTOFMEMORY;
1128 channel->read_buflen = size;
1129 return S_OK;
1131 if (channel->read_buflen < size)
1133 char *tmp;
1134 ULONG new_size = max( size, channel->read_buflen * 2 );
1135 if (!(tmp = heap_realloc( channel->read_buf, new_size ))) return E_OUTOFMEMORY;
1136 channel->read_buf = tmp;
1137 channel->read_buflen = new_size;
1139 return S_OK;
1142 static HRESULT init_reader( struct channel *channel )
1144 WS_XML_READER_BUFFER_INPUT buf = {{WS_XML_READER_INPUT_TYPE_BUFFER}};
1145 WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}};
1146 WS_XML_READER_BINARY_ENCODING bin = {{WS_XML_READER_ENCODING_TYPE_BINARY}};
1147 WS_XML_READER_ENCODING *encoding;
1148 HRESULT hr;
1150 if (!channel->reader && (hr = WsCreateReader( NULL, 0, &channel->reader, NULL )) != S_OK) return hr;
1152 switch (channel->encoding)
1154 case WS_ENCODING_XML_UTF8:
1155 text.charSet = WS_CHARSET_UTF8;
1156 encoding = &text.encoding;
1157 break;
1159 case WS_ENCODING_XML_BINARY_SESSION_1:
1160 bin.staticDictionary = (WS_XML_DICTIONARY *)&dict_builtin_static.dict;
1161 bin.dynamicDictionary = &channel->dict.dict;
1162 /* fall through */
1164 case WS_ENCODING_XML_BINARY_1:
1165 encoding = &bin.encoding;
1166 break;
1168 default:
1169 FIXME( "unhandled encoding %u\n", channel->encoding );
1170 return WS_E_NOT_SUPPORTED;
1173 buf.encodedData = channel->read_buf;
1174 buf.encodedDataSize = channel->read_size;
1175 return WsSetInput( channel->reader, encoding, &buf.input, NULL, 0, NULL );
1178 #define INITIAL_READ_BUFFER_SIZE 4096
1179 static HRESULT receive_message_http( struct channel *channel )
1181 DWORD len, bytes_read, offset = 0, size = INITIAL_READ_BUFFER_SIZE;
1182 ULONG max_len;
1183 HRESULT hr;
1185 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE,
1186 &max_len, sizeof(max_len) );
1188 if ((hr = resize_read_buffer( channel, size )) != S_OK) return hr;
1189 channel->read_size = 0;
1190 for (;;)
1192 if (!WinHttpQueryDataAvailable( channel->u.http.request, &len ))
1194 return HRESULT_FROM_WIN32( GetLastError() );
1196 if (!len) break;
1197 if (channel->read_size + len > max_len) return WS_E_QUOTA_EXCEEDED;
1198 if ((hr = resize_read_buffer( channel, channel->read_size + len )) != S_OK) return hr;
1200 if (!WinHttpReadData( channel->u.http.request, channel->read_buf + offset, len, &bytes_read ))
1202 return HRESULT_FROM_WIN32( GetLastError() );
1204 if (!bytes_read) break;
1205 channel->read_size += bytes_read;
1206 offset += bytes_read;
1209 return init_reader( channel );
1212 static HRESULT receive_message_unsized( struct channel *channel, SOCKET socket )
1214 int bytes_read;
1215 ULONG max_len;
1216 HRESULT hr;
1218 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE,
1219 &max_len, sizeof(max_len) );
1221 if ((hr = resize_read_buffer( channel, max_len )) != S_OK) return hr;
1223 channel->read_size = 0;
1224 if ((bytes_read = recv( socket, channel->read_buf, max_len, 0 )) < 0)
1226 return HRESULT_FROM_WIN32( WSAGetLastError() );
1228 channel->read_size = bytes_read;
1229 return S_OK;
1232 static HRESULT receive_message_sized( struct channel *channel, unsigned int size )
1234 unsigned int offset = 0, to_read = size;
1235 int bytes_read;
1236 HRESULT hr;
1238 if ((hr = resize_read_buffer( channel, size )) != S_OK) return hr;
1240 channel->read_size = 0;
1241 while (channel->read_size < size)
1243 if ((bytes_read = recv( channel->u.tcp.socket, channel->read_buf + offset, to_read, 0 )) < 0)
1245 return HRESULT_FROM_WIN32( WSAGetLastError() );
1247 if (!bytes_read) break;
1248 channel->read_size += bytes_read;
1249 to_read -= bytes_read;
1250 offset += bytes_read;
1252 if (channel->read_size != size) return WS_E_INVALID_FORMAT;
1253 return S_OK;
1256 static HRESULT receive_size( struct channel *channel, unsigned int *size )
1258 unsigned char byte;
1259 HRESULT hr;
1261 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
1262 *size = byte & 0x7f;
1263 if (!(byte & 0x80)) return S_OK;
1265 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
1266 *size += (byte & 0x7f) << 7;
1267 if (!(byte & 0x80)) return S_OK;
1269 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
1270 *size += (byte & 0x7f) << 14;
1271 if (!(byte & 0x80)) return S_OK;
1273 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
1274 *size += (byte & 0x7f) << 21;
1275 if (!(byte & 0x80)) return S_OK;
1277 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
1278 if (byte & ~0x0f) return WS_E_INVALID_FORMAT;
1279 *size += byte << 28;
1280 return S_OK;
1283 static WS_ENCODING map_known_encoding( enum known_encoding encoding )
1285 switch (encoding)
1287 case KNOWN_ENCODING_SOAP11_UTF8:
1288 case KNOWN_ENCODING_SOAP12_UTF8: return WS_ENCODING_XML_UTF8;
1289 case KNOWN_ENCODING_SOAP11_UTF16:
1290 case KNOWN_ENCODING_SOAP12_UTF16: return WS_ENCODING_XML_UTF16BE;
1291 case KNOWN_ENCODING_SOAP11_UTF16LE:
1292 case KNOWN_ENCODING_SOAP12_UTF16LE: return WS_ENCODING_XML_UTF16LE;
1293 case KNOWN_ENCODING_SOAP12_BINARY: return WS_ENCODING_XML_BINARY_1;
1294 case KNOWN_ENCODING_SOAP12_BINARY_SESSION: return WS_ENCODING_XML_BINARY_SESSION_1;
1295 default:
1296 WARN( "unhandled encoding %u, assuming UTF8\n", encoding );
1297 return WS_ENCODING_XML_UTF8;
1301 static HRESULT receive_preamble( struct channel *channel )
1303 unsigned char type;
1304 HRESULT hr;
1306 for (;;)
1308 if ((hr = receive_bytes( channel, &type, 1 )) != S_OK) return hr;
1309 if (type == FRAME_RECORD_TYPE_PREAMBLE_END) break;
1310 switch (type)
1312 case FRAME_RECORD_TYPE_VERSION:
1314 unsigned char major, minor;
1315 if ((hr = receive_bytes( channel, &major, 1 )) != S_OK) return hr;
1316 if ((hr = receive_bytes( channel, &minor, 1 )) != S_OK) return hr;
1317 TRACE( "major %u minor %u\n", major, major );
1318 break;
1320 case FRAME_RECORD_TYPE_MODE:
1322 unsigned char mode;
1323 if ((hr = receive_bytes( channel, &mode, 1 )) != S_OK) return hr;
1324 TRACE( "mode %u\n", mode );
1325 break;
1327 case FRAME_RECORD_TYPE_VIA:
1329 unsigned int size;
1330 unsigned char *url;
1332 if ((hr = receive_size( channel, &size )) != S_OK) return hr;
1333 if (!(url = heap_alloc( size ))) return E_OUTOFMEMORY;
1334 if ((hr = receive_bytes( channel, url, size )) != S_OK)
1336 heap_free( url );
1337 return hr;
1339 TRACE( "transport URL %s\n", debugstr_an((char *)url, size) );
1340 heap_free( url ); /* FIXME: verify */
1341 break;
1343 case FRAME_RECORD_TYPE_KNOWN_ENCODING:
1345 unsigned char encoding;
1346 if ((hr = receive_bytes( channel, &encoding, 1 )) != S_OK) return hr;
1347 TRACE( "encoding %u\n", encoding );
1348 channel->encoding = map_known_encoding( encoding );
1349 break;
1351 default:
1352 WARN( "unhandled record type %u\n", type );
1353 return WS_E_INVALID_FORMAT;
1357 return S_OK;
1360 static HRESULT receive_sized_envelope( struct channel *channel )
1362 unsigned char type;
1363 unsigned int size;
1364 HRESULT hr;
1366 if ((hr = receive_bytes( channel, &type, 1 )) != S_OK) return hr;
1367 if (type != FRAME_RECORD_TYPE_SIZED_ENVELOPE) return WS_E_INVALID_FORMAT;
1368 if ((hr = receive_size( channel, &size )) != S_OK) return hr;
1369 if ((hr = receive_message_sized( channel, size )) != S_OK) return hr;
1370 return S_OK;
1373 static HRESULT read_size( const BYTE **ptr, ULONG len, ULONG *size )
1375 const BYTE *buf = *ptr;
1377 if (len < 1) return WS_E_INVALID_FORMAT;
1378 *size = buf[0] & 0x7f;
1379 if (!(buf[0] & 0x80))
1381 *ptr += 1;
1382 return S_OK;
1384 if (len < 2) return WS_E_INVALID_FORMAT;
1385 *size += (buf[1] & 0x7f) << 7;
1386 if (!(buf[1] & 0x80))
1388 *ptr += 2;
1389 return S_OK;
1391 if (len < 3) return WS_E_INVALID_FORMAT;
1392 *size += (buf[2] & 0x7f) << 14;
1393 if (!(buf[2] & 0x80))
1395 *ptr += 3;
1396 return S_OK;
1398 if (len < 4) return WS_E_INVALID_FORMAT;
1399 *size += (buf[3] & 0x7f) << 21;
1400 if (!(buf[3] & 0x80))
1402 *ptr += 4;
1403 return S_OK;
1405 if (len < 5 || (buf[4] & ~0x07)) return WS_E_INVALID_FORMAT;
1406 *size += buf[4] << 28;
1407 *ptr += 5;
1408 return S_OK;
1411 static HRESULT build_dict( const BYTE *buf, ULONG buflen, struct dictionary *dict, ULONG *used )
1413 ULONG size, strings_size, strings_offset;
1414 const BYTE *ptr = buf;
1415 BYTE *bytes;
1416 int index;
1417 HRESULT hr;
1419 if ((hr = read_size( &ptr, buflen, &strings_size )) != S_OK) return hr;
1420 strings_offset = ptr - buf;
1421 if (buflen < strings_offset + strings_size) return WS_E_INVALID_FORMAT;
1422 *used = strings_offset + strings_size;
1423 if (!strings_size) return S_OK;
1425 UuidCreate( &dict->dict.guid );
1426 dict->dict.isConst = FALSE;
1428 buflen -= strings_offset;
1429 ptr = buf + strings_offset;
1430 while (ptr < buf + strings_size)
1432 if ((hr = read_size( &ptr, buflen, &size )) != S_OK)
1434 clear_dict( dict );
1435 return hr;
1437 if (size > buflen)
1439 clear_dict( dict );
1440 return WS_E_INVALID_FORMAT;
1442 buflen -= size;
1443 if (!(bytes = heap_alloc( size )))
1445 hr = E_OUTOFMEMORY;
1446 goto error;
1448 memcpy( bytes, ptr, size );
1449 if ((index = find_string( dict, bytes, size, NULL )) == -1) /* duplicate */
1451 heap_free( bytes );
1452 ptr += size;
1453 continue;
1455 if (!insert_string( dict, bytes, size, index, NULL ))
1457 clear_dict( dict );
1458 return E_OUTOFMEMORY;
1460 ptr += size;
1462 return S_OK;
1464 error:
1465 clear_dict( dict );
1466 return hr;
1469 static HRESULT send_preamble_ack( struct channel *channel )
1471 HRESULT hr;
1472 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_PREAMBLE_ACK )) != S_OK) return hr;
1473 channel->session_state = SESSION_STATE_SETUP_COMPLETE;
1474 return S_OK;
1477 static HRESULT receive_message_session_setup( struct channel *channel )
1479 HRESULT hr;
1481 if ((hr = receive_preamble( channel )) != S_OK) return hr;
1482 if ((hr = send_preamble_ack( channel )) != S_OK) return hr;
1483 if ((hr = receive_sized_envelope( channel )) != S_OK) return hr;
1484 if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
1486 ULONG size;
1487 if ((hr = build_dict( (const BYTE *)channel->read_buf, channel->read_size, &channel->dict, &size )) != S_OK)
1488 return hr;
1489 channel->read_size -= size;
1490 memmove( channel->read_buf, channel->read_buf + size, channel->read_size );
1493 return init_reader( channel );
1496 static HRESULT receive_message_session( struct channel *channel )
1498 HRESULT hr;
1499 if ((hr = receive_sized_envelope( channel )) != S_OK) return hr;
1500 return init_reader( channel );
1503 static HRESULT receive_message_sock( struct channel *channel, SOCKET socket )
1505 HRESULT hr;
1506 if ((hr = receive_message_unsized( channel, socket )) != S_OK) return hr;
1507 return init_reader( channel );
1510 static HRESULT receive_message( struct channel *channel )
1512 HRESULT hr;
1513 if ((hr = connect_channel( channel )) != S_OK) return hr;
1515 switch (channel->binding)
1517 case WS_HTTP_CHANNEL_BINDING:
1518 return receive_message_http( channel );
1520 case WS_TCP_CHANNEL_BINDING:
1521 if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
1523 switch (channel->session_state)
1525 case SESSION_STATE_UNINITIALIZED:
1526 return receive_message_session_setup( channel );
1528 case SESSION_STATE_SETUP_COMPLETE:
1529 return receive_message_session( channel );
1531 default:
1532 ERR( "unhandled session state %u\n", channel->session_state );
1533 return WS_E_OTHER;
1536 return receive_message_sock( channel, channel->u.tcp.socket );
1538 case WS_UDP_CHANNEL_BINDING:
1539 return receive_message_sock( channel, channel->u.udp.socket );
1541 default:
1542 ERR( "unhandled binding %u\n", channel->binding );
1543 return E_NOTIMPL;
1547 HRESULT channel_receive_message( WS_CHANNEL *handle )
1549 struct channel *channel = (struct channel *)handle;
1550 HRESULT hr;
1552 EnterCriticalSection( &channel->cs );
1554 if (channel->magic != CHANNEL_MAGIC)
1556 LeaveCriticalSection( &channel->cs );
1557 return E_INVALIDARG;
1560 hr = receive_message( channel );
1562 LeaveCriticalSection( &channel->cs );
1563 return hr;
1566 HRESULT channel_get_reader( WS_CHANNEL *handle, WS_XML_READER **reader )
1568 struct channel *channel = (struct channel *)handle;
1570 EnterCriticalSection( &channel->cs );
1572 if (channel->magic != CHANNEL_MAGIC)
1574 LeaveCriticalSection( &channel->cs );
1575 return E_INVALIDARG;
1578 *reader = channel->reader;
1580 LeaveCriticalSection( &channel->cs );
1581 return S_OK;
1584 static HRESULT read_message( WS_MESSAGE *handle, WS_XML_READER *reader, const WS_ELEMENT_DESCRIPTION *desc,
1585 WS_READ_OPTION option, WS_HEAP *heap, void *body, ULONG size )
1587 HRESULT hr;
1588 if ((hr = WsReadEnvelopeStart( handle, reader, NULL, NULL, NULL )) != S_OK) return hr;
1589 if ((hr = WsReadBody( handle, desc, option, heap, body, size, NULL )) != S_OK) return hr;
1590 return WsReadEnvelopeEnd( handle, NULL );
1593 /**************************************************************************
1594 * WsReceiveMessage [webservices.@]
1596 HRESULT WINAPI WsReceiveMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION **desc,
1597 ULONG count, WS_RECEIVE_OPTION option, WS_READ_OPTION read_option, WS_HEAP *heap,
1598 void *value, ULONG size, ULONG *index, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
1600 struct channel *channel = (struct channel *)handle;
1601 HRESULT hr;
1603 TRACE( "%p %p %p %u %08x %08x %p %p %u %p %p %p\n", handle, msg, desc, count, option, read_option, heap,
1604 value, size, index, ctx, error );
1605 if (error) FIXME( "ignoring error parameter\n" );
1606 if (ctx) FIXME( "ignoring ctx parameter\n" );
1607 if (index)
1609 FIXME( "index parameter not supported\n" );
1610 return E_NOTIMPL;
1612 if (count != 1)
1614 FIXME( "no support for multiple descriptions\n" );
1615 return E_NOTIMPL;
1617 if (option != WS_RECEIVE_REQUIRED_MESSAGE)
1619 FIXME( "receive option %08x not supported\n", option );
1620 return E_NOTIMPL;
1623 if (!channel || !msg || !desc || !count) return E_INVALIDARG;
1625 EnterCriticalSection( &channel->cs );
1627 if (channel->magic != CHANNEL_MAGIC)
1629 LeaveCriticalSection( &channel->cs );
1630 return E_INVALIDARG;
1633 if ((hr = receive_message( channel )) != S_OK) goto done;
1634 hr = read_message( msg, channel->reader, desc[0]->bodyElementDescription, read_option, heap, value, size );
1636 done:
1637 LeaveCriticalSection( &channel->cs );
1638 return hr;
1641 /**************************************************************************
1642 * WsReadMessageStart [webservices.@]
1644 HRESULT WINAPI WsReadMessageStart( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx,
1645 WS_ERROR *error )
1647 struct channel *channel = (struct channel *)handle;
1648 HRESULT hr;
1650 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
1651 if (error) FIXME( "ignoring error parameter\n" );
1652 if (ctx) FIXME( "ignoring ctx parameter\n" );
1654 if (!channel || !msg) return E_INVALIDARG;
1656 EnterCriticalSection( &channel->cs );
1658 if (channel->magic != CHANNEL_MAGIC)
1660 LeaveCriticalSection( &channel->cs );
1661 return E_INVALIDARG;
1664 if ((hr = receive_message( channel )) == S_OK)
1666 hr = WsReadEnvelopeStart( msg, channel->reader, NULL, NULL, NULL );
1669 LeaveCriticalSection( &channel->cs );
1670 return hr;
1673 /**************************************************************************
1674 * WsReadMessageEnd [webservices.@]
1676 HRESULT WINAPI WsReadMessageEnd( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx,
1677 WS_ERROR *error )
1679 struct channel *channel = (struct channel *)handle;
1680 HRESULT hr;
1682 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
1683 if (error) FIXME( "ignoring error parameter\n" );
1684 if (ctx) FIXME( "ignoring ctx parameter\n" );
1686 if (!channel || !msg) return E_INVALIDARG;
1688 EnterCriticalSection( &channel->cs );
1690 if (channel->magic != CHANNEL_MAGIC)
1692 LeaveCriticalSection( &channel->cs );
1693 return E_INVALIDARG;
1696 hr = WsReadEnvelopeEnd( msg, NULL );
1698 LeaveCriticalSection( &channel->cs );
1699 return hr;
1702 /**************************************************************************
1703 * WsWriteMessageStart [webservices.@]
1705 HRESULT WINAPI WsWriteMessageStart( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx,
1706 WS_ERROR *error )
1708 struct channel *channel = (struct channel *)handle;
1709 HRESULT hr;
1711 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
1712 if (error) FIXME( "ignoring error parameter\n" );
1713 if (ctx) FIXME( "ignoring ctx parameter\n" );
1715 if (!channel || !msg) return E_INVALIDARG;
1717 EnterCriticalSection( &channel->cs );
1719 if (channel->magic != CHANNEL_MAGIC)
1721 LeaveCriticalSection( &channel->cs );
1722 return E_INVALIDARG;
1725 if ((hr = init_writer( channel )) != S_OK) goto done;
1726 if ((hr = WsAddressMessage( msg, &channel->addr, NULL )) != S_OK) goto done;
1727 hr = WsWriteEnvelopeStart( msg, channel->writer, NULL, NULL, NULL );
1729 done:
1730 LeaveCriticalSection( &channel->cs );
1731 return hr;
1734 /**************************************************************************
1735 * WsWriteMessageEnd [webservices.@]
1737 HRESULT WINAPI WsWriteMessageEnd( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx,
1738 WS_ERROR *error )
1740 struct channel *channel = (struct channel *)handle;
1741 HRESULT hr;
1743 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
1744 if (error) FIXME( "ignoring error parameter\n" );
1745 if (ctx) FIXME( "ignoring ctx parameter\n" );
1747 if (!channel || !msg) return E_INVALIDARG;
1749 EnterCriticalSection( &channel->cs );
1751 if (channel->magic != CHANNEL_MAGIC)
1753 LeaveCriticalSection( &channel->cs );
1754 return E_INVALIDARG;
1757 if ((hr = WsWriteEnvelopeEnd( msg, NULL )) == S_OK) hr = send_message( channel, msg );
1759 LeaveCriticalSection( &channel->cs );
1760 return hr;
1763 static HRESULT sock_accept( SOCKET socket, HANDLE wait, HANDLE cancel, SOCKET *ret )
1765 HANDLE handles[] = { wait, cancel };
1766 ULONG nonblocking = 0;
1767 HRESULT hr = S_OK;
1769 if (WSAEventSelect( socket, handles[0], FD_ACCEPT )) return HRESULT_FROM_WIN32( WSAGetLastError() );
1771 switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE ))
1773 case 0:
1774 if ((*ret = accept( socket, NULL, NULL )) != -1)
1776 WSAEventSelect( *ret, NULL, 0 );
1777 ioctlsocket( *ret, FIONBIO, &nonblocking );
1778 break;
1780 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
1781 break;
1783 case 1:
1784 hr = WS_E_OPERATION_ABORTED;
1785 break;
1787 default:
1788 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
1789 break;
1792 return hr;
1795 HRESULT channel_accept_tcp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
1797 struct channel *channel = (struct channel *)handle;
1798 HRESULT hr;
1800 EnterCriticalSection( &channel->cs );
1802 if (channel->magic != CHANNEL_MAGIC)
1804 LeaveCriticalSection( &channel->cs );
1805 return E_INVALIDARG;
1808 hr = sock_accept( socket, wait, cancel, &channel->u.tcp.socket );
1810 LeaveCriticalSection( &channel->cs );
1811 return hr;
1814 static HRESULT sock_wait( SOCKET socket, HANDLE wait, HANDLE cancel )
1816 HANDLE handles[] = { wait, cancel };
1817 ULONG nonblocking = 0;
1818 HRESULT hr;
1820 if (WSAEventSelect( socket, handles[0], FD_READ )) return HRESULT_FROM_WIN32( WSAGetLastError() );
1822 switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE ))
1824 case 0:
1825 hr = S_OK;
1826 break;
1828 case 1:
1829 hr = WS_E_OPERATION_ABORTED;
1830 break;
1832 default:
1833 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
1834 break;
1837 WSAEventSelect( socket, NULL, 0 );
1838 ioctlsocket( socket, FIONBIO, &nonblocking );
1839 return hr;
1842 HRESULT channel_accept_udp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
1844 struct channel *channel = (struct channel *)handle;
1845 HRESULT hr;
1847 EnterCriticalSection( &channel->cs );
1849 if (channel->magic != CHANNEL_MAGIC)
1851 LeaveCriticalSection( &channel->cs );
1852 return E_INVALIDARG;
1855 if ((hr = sock_wait( socket, wait, cancel )) == S_OK) channel->u.udp.socket = socket;
1857 LeaveCriticalSection( &channel->cs );
1858 return hr;