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
24 #include "webservices.h"
26 #include "wine/debug.h"
27 #include "wine/list.h"
28 #include "wine/unicode.h"
29 #include "webservices_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(webservices
);
34 static const struct prop_desc channel_props
[] =
36 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE */
37 { sizeof(UINT64
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_MESSAGE_SIZE */
38 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_START_SIZE */
39 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_FLUSH_SIZE */
40 { sizeof(WS_ENCODING
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENCODING */
41 { sizeof(WS_ENVELOPE_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENVELOPE_VERSION */
42 { sizeof(WS_ADDRESSING_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_ADDRESSING_VERSION */
43 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE */
44 { sizeof(WS_CHANNEL_STATE
), TRUE
}, /* WS_CHANNEL_PROPERTY_STATE */
45 { sizeof(WS_CALLBACK_MODEL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ASYNC_CALLBACK_MODEL */
46 { sizeof(WS_IP_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_IP_VERSION */
47 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RESOLVE_TIMEOUT */
48 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_CONNECT_TIMEOUT */
49 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_SEND_TIMEOUT */
50 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RECEIVE_RESPONSE_TIMEOUT */
51 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RECEIVE_TIMEOUT */
52 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_CLOSE_TIMEOUT */
53 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENABLE_TIMEOUTS */
54 { sizeof(WS_TRANSFER_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_TRANSFER_MODE */
55 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MULTICAST_INTERFACE */
56 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MULTICAST_HOPS */
57 { sizeof(WS_ENDPOINT_ADDRESS
), TRUE
}, /* WS_CHANNEL_PROPERTY_REMOTE_ADDRESS */
58 { sizeof(SOCKADDR_STORAGE
), TRUE
}, /* WS_CHANNEL_PROPERTY_REMOTE_IP_ADDRESS */
59 { sizeof(ULONGLONG
), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_CONNECTION_ID */
60 { sizeof(WS_CUSTOM_CHANNEL_CALLBACKS
), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_CALLBACKS */
61 { 0, FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_PARAMETERS */
62 { sizeof(void *), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_INSTANCE */
63 { sizeof(WS_STRING
), TRUE
}, /* WS_CHANNEL_PROPERTY_TRANSPORT_URL */
64 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_NO_DELAY */
65 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_SEND_KEEP_ALIVES */
66 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_TIME */
67 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_INTERVAL */
68 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_HTTP_SERVER_CONNECTIONS */
69 { sizeof(BOOL
), TRUE
}, /* WS_CHANNEL_PROPERTY_IS_SESSION_SHUT_DOWN */
70 { sizeof(WS_CHANNEL_TYPE
), TRUE
}, /* WS_CHANNEL_PROPERTY_CHANNEL_TYPE */
71 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_TRIM_BUFFERED_MESSAGE_SIZE */
72 { sizeof(WS_CHANNEL_ENCODER
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENCODER */
73 { sizeof(WS_CHANNEL_DECODER
), FALSE
}, /* WS_CHANNEL_PROPERTY_DECODER */
74 { sizeof(WS_PROTECTION_LEVEL
), TRUE
}, /* WS_CHANNEL_PROPERTY_PROTECTION_LEVEL */
75 { sizeof(WS_COOKIE_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_COOKIE_MODE */
76 { sizeof(WS_HTTP_PROXY_SETTING_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SETTING_MODE */
77 { sizeof(WS_CUSTOM_HTTP_PROXY
), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_HTTP_PROXY */
78 { sizeof(WS_HTTP_MESSAGE_MAPPING
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING */
79 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENABLE_HTTP_REDIRECT */
80 { sizeof(WS_HTTP_REDIRECT_CALLBACK_CONTEXT
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_REDIRECT_CALLBACK_CONTEXT */
81 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_FAULTS_AS_ERRORS */
82 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ALLOW_UNSECURED_FAULTS */
83 { sizeof(WCHAR
*), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_SERVER_SPN */
84 { sizeof(WCHAR
*), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SPN */
85 { sizeof(ULONG
), FALSE
} /* WS_CHANNEL_PROPERTY_MAX_HTTP_REQUEST_HEADERS_BUFFER_SIZE */
93 WS_CHANNEL_BINDING binding
;
94 WS_CHANNEL_STATE state
;
95 WS_ENDPOINT_ADDRESS addr
;
96 WS_XML_WRITER
*writer
;
97 WS_XML_READER
*reader
;
120 struct prop prop
[sizeof(channel_props
)/sizeof(channel_props
[0])];
123 #define CHANNEL_MAGIC (('C' << 24) | ('H' << 16) | ('A' << 8) | 'N')
125 static struct channel
*alloc_channel(void)
127 static const ULONG count
= sizeof(channel_props
)/sizeof(channel_props
[0]);
129 ULONG size
= sizeof(*ret
) + prop_size( channel_props
, count
);
131 if (!(ret
= heap_alloc_zero( size
))) return NULL
;
133 ret
->magic
= CHANNEL_MAGIC
;
134 InitializeCriticalSection( &ret
->cs
);
135 ret
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": channel.cs");
137 prop_init( channel_props
, count
, ret
->prop
, &ret
[1] );
138 ret
->prop_count
= count
;
142 static void reset_channel( struct channel
*channel
)
144 channel
->state
= WS_CHANNEL_STATE_CREATED
;
145 heap_free( channel
->addr
.url
.chars
);
146 channel
->addr
.url
.chars
= NULL
;
147 channel
->addr
.url
.length
= 0;
149 channel
->read_size
= 0;
151 switch (channel
->binding
)
153 case WS_HTTP_CHANNEL_BINDING
:
154 WinHttpCloseHandle( channel
->u
.http
.request
);
155 channel
->u
.http
.request
= NULL
;
156 WinHttpCloseHandle( channel
->u
.http
.connect
);
157 channel
->u
.http
.connect
= NULL
;
158 WinHttpCloseHandle( channel
->u
.http
.session
);
159 channel
->u
.http
.session
= NULL
;
162 case WS_TCP_CHANNEL_BINDING
:
163 closesocket( channel
->u
.tcp
.socket
);
164 channel
->u
.tcp
.socket
= -1;
167 case WS_UDP_CHANNEL_BINDING
:
168 closesocket( channel
->u
.udp
.socket
);
169 channel
->u
.udp
.socket
= -1;
176 static void free_channel( struct channel
*channel
)
178 reset_channel( channel
);
180 WsFreeWriter( channel
->writer
);
181 WsFreeReader( channel
->reader
);
183 heap_free( channel
->read_buf
);
185 channel
->cs
.DebugInfo
->Spare
[0] = 0;
186 DeleteCriticalSection( &channel
->cs
);
187 heap_free( channel
);
190 static HRESULT
create_channel( WS_CHANNEL_TYPE type
, WS_CHANNEL_BINDING binding
,
191 const WS_CHANNEL_PROPERTY
*properties
, ULONG count
, struct channel
**ret
)
193 struct channel
*channel
;
194 ULONG i
, msg_size
= 65536;
197 if (!(channel
= alloc_channel())) return E_OUTOFMEMORY
;
199 prop_set( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE
,
200 &msg_size
, sizeof(msg_size
) );
202 for (i
= 0; i
< count
; i
++)
204 hr
= prop_set( channel
->prop
, channel
->prop_count
, properties
[i
].id
, properties
[i
].value
,
205 properties
[i
].valueSize
);
208 free_channel( channel
);
213 channel
->type
= type
;
214 channel
->binding
= binding
;
216 switch (channel
->binding
)
218 case WS_TCP_CHANNEL_BINDING
:
219 channel
->u
.tcp
.socket
= -1;
222 case WS_UDP_CHANNEL_BINDING
:
223 channel
->u
.udp
.socket
= -1;
233 /**************************************************************************
234 * WsCreateChannel [webservices.@]
236 HRESULT WINAPI
WsCreateChannel( WS_CHANNEL_TYPE type
, WS_CHANNEL_BINDING binding
,
237 const WS_CHANNEL_PROPERTY
*properties
, ULONG count
,
238 const WS_SECURITY_DESCRIPTION
*desc
, WS_CHANNEL
**handle
,
241 struct channel
*channel
;
244 TRACE( "%u %u %p %u %p %p %p\n", type
, binding
, properties
, count
, desc
, handle
, error
);
245 if (error
) FIXME( "ignoring error parameter\n" );
246 if (desc
) FIXME( "ignoring security description\n" );
248 if (!handle
) return E_INVALIDARG
;
250 if (type
!= WS_CHANNEL_TYPE_REQUEST
&& type
!= WS_CHANNEL_TYPE_DUPLEX
&&
251 type
!= WS_CHANNEL_TYPE_DUPLEX_SESSION
)
253 FIXME( "channel type %u not implemented\n", type
);
256 if (binding
!= WS_HTTP_CHANNEL_BINDING
&& binding
!= WS_TCP_CHANNEL_BINDING
&&
257 binding
!= WS_UDP_CHANNEL_BINDING
)
259 FIXME( "channel binding %u not implemented\n", binding
);
263 if ((hr
= create_channel( type
, binding
, properties
, count
, &channel
)) != S_OK
) return hr
;
265 *handle
= (WS_CHANNEL
*)channel
;
269 /**************************************************************************
270 * WsCreateChannelForListener [webservices.@]
272 HRESULT WINAPI
WsCreateChannelForListener( WS_LISTENER
*listener_handle
, const WS_CHANNEL_PROPERTY
*properties
,
273 ULONG count
, WS_CHANNEL
**handle
, WS_ERROR
*error
)
275 struct channel
*channel
;
276 WS_CHANNEL_TYPE type
;
277 WS_CHANNEL_BINDING binding
;
280 TRACE( "%p %p %u %p %p\n", listener_handle
, properties
, count
, handle
, error
);
281 if (error
) FIXME( "ignoring error parameter\n" );
283 if (!listener_handle
|| !handle
) return E_INVALIDARG
;
285 if ((hr
= WsGetListenerProperty( listener_handle
, WS_LISTENER_PROPERTY_CHANNEL_TYPE
, &type
,
286 sizeof(type
), NULL
)) != S_OK
) return hr
;
288 if ((hr
= WsGetListenerProperty( listener_handle
, WS_LISTENER_PROPERTY_CHANNEL_BINDING
, &binding
,
289 sizeof(binding
), NULL
)) != S_OK
) return hr
;
291 if ((hr
= create_channel( type
, binding
, properties
, count
, &channel
)) != S_OK
) return hr
;
293 *handle
= (WS_CHANNEL
*)channel
;
297 /**************************************************************************
298 * WsFreeChannel [webservices.@]
300 void WINAPI
WsFreeChannel( WS_CHANNEL
*handle
)
302 struct channel
*channel
= (struct channel
*)handle
;
304 TRACE( "%p\n", handle
);
306 if (!channel
) return;
308 EnterCriticalSection( &channel
->cs
);
310 if (channel
->magic
!= CHANNEL_MAGIC
)
312 LeaveCriticalSection( &channel
->cs
);
318 LeaveCriticalSection( &channel
->cs
);
319 free_channel( channel
);
322 /**************************************************************************
323 * WsResetChannel [webservices.@]
325 HRESULT WINAPI
WsResetChannel( WS_CHANNEL
*handle
, WS_ERROR
*error
)
327 struct channel
*channel
= (struct channel
*)handle
;
329 TRACE( "%p %p\n", handle
, error
);
330 if (error
) FIXME( "ignoring error parameter\n" );
332 if (!channel
) return E_INVALIDARG
;
334 EnterCriticalSection( &channel
->cs
);
336 if (channel
->magic
!= CHANNEL_MAGIC
)
338 LeaveCriticalSection( &channel
->cs
);
342 if (channel
->state
!= WS_CHANNEL_STATE_CREATED
&& channel
->state
!= WS_CHANNEL_STATE_CLOSED
)
344 LeaveCriticalSection( &channel
->cs
);
345 return WS_E_INVALID_OPERATION
;
348 reset_channel( channel
);
350 LeaveCriticalSection( &channel
->cs
);
354 /**************************************************************************
355 * WsGetChannelProperty [webservices.@]
357 HRESULT WINAPI
WsGetChannelProperty( WS_CHANNEL
*handle
, WS_CHANNEL_PROPERTY_ID id
, void *buf
,
358 ULONG size
, WS_ERROR
*error
)
360 struct channel
*channel
= (struct channel
*)handle
;
363 TRACE( "%p %u %p %u %p\n", handle
, id
, buf
, size
, error
);
364 if (error
) FIXME( "ignoring error parameter\n" );
366 if (!channel
) return E_INVALIDARG
;
368 EnterCriticalSection( &channel
->cs
);
370 if (channel
->magic
!= CHANNEL_MAGIC
)
372 LeaveCriticalSection( &channel
->cs
);
378 case WS_CHANNEL_PROPERTY_CHANNEL_TYPE
:
379 if (!buf
|| size
!= sizeof(channel
->type
)) hr
= E_INVALIDARG
;
380 else *(WS_CHANNEL_TYPE
*)buf
= channel
->type
;
384 hr
= prop_get( channel
->prop
, channel
->prop_count
, id
, buf
, size
);
387 LeaveCriticalSection( &channel
->cs
);
391 /**************************************************************************
392 * WsSetChannelProperty [webservices.@]
394 HRESULT WINAPI
WsSetChannelProperty( WS_CHANNEL
*handle
, WS_CHANNEL_PROPERTY_ID id
, const void *value
,
395 ULONG size
, WS_ERROR
*error
)
397 struct channel
*channel
= (struct channel
*)handle
;
400 TRACE( "%p %u %p %u\n", handle
, id
, value
, size
);
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
);
413 hr
= prop_set( channel
->prop
, channel
->prop_count
, id
, value
, size
);
415 LeaveCriticalSection( &channel
->cs
);
419 static HRESULT
open_channel( struct channel
*channel
, const WS_ENDPOINT_ADDRESS
*endpoint
)
421 if (endpoint
->headers
|| endpoint
->extensions
|| endpoint
->identity
)
423 FIXME( "headers, extensions or identity not supported\n" );
427 if (!(channel
->addr
.url
.chars
= heap_alloc( endpoint
->url
.length
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
428 memcpy( channel
->addr
.url
.chars
, endpoint
->url
.chars
, endpoint
->url
.length
* sizeof(WCHAR
) );
429 channel
->addr
.url
.length
= endpoint
->url
.length
;
431 channel
->state
= WS_CHANNEL_STATE_OPEN
;
435 /**************************************************************************
436 * WsOpenChannel [webservices.@]
438 HRESULT WINAPI
WsOpenChannel( WS_CHANNEL
*handle
, const WS_ENDPOINT_ADDRESS
*endpoint
,
439 const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
441 struct channel
*channel
= (struct channel
*)handle
;
444 TRACE( "%p %p %p %p\n", handle
, endpoint
, ctx
, error
);
445 if (error
) FIXME( "ignoring error parameter\n" );
446 if (ctx
) FIXME( "ignoring ctx parameter\n" );
448 if (!channel
|| !endpoint
) return E_INVALIDARG
;
450 EnterCriticalSection( &channel
->cs
);
452 if (channel
->magic
!= CHANNEL_MAGIC
)
454 LeaveCriticalSection( &channel
->cs
);
458 if (channel
->state
!= WS_CHANNEL_STATE_CREATED
)
460 LeaveCriticalSection( &channel
->cs
);
461 return WS_E_INVALID_OPERATION
;
464 hr
= open_channel( channel
, endpoint
);
466 LeaveCriticalSection( &channel
->cs
);
470 static void close_channel( struct channel
*channel
)
472 reset_channel( channel
);
473 channel
->state
= WS_CHANNEL_STATE_CLOSED
;
476 /**************************************************************************
477 * WsCloseChannel [webservices.@]
479 HRESULT WINAPI
WsCloseChannel( WS_CHANNEL
*handle
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
481 struct channel
*channel
= (struct channel
*)handle
;
483 TRACE( "%p %p %p\n", handle
, ctx
, error
);
484 if (error
) FIXME( "ignoring error parameter\n" );
485 if (ctx
) FIXME( "ignoring ctx parameter\n" );
487 if (!channel
) return E_INVALIDARG
;
489 EnterCriticalSection( &channel
->cs
);
491 if (channel
->magic
!= CHANNEL_MAGIC
)
493 LeaveCriticalSection( &channel
->cs
);
497 close_channel( channel
);
499 LeaveCriticalSection( &channel
->cs
);
503 static HRESULT
parse_http_url( const WCHAR
*url
, ULONG len
, URL_COMPONENTS
*uc
)
505 HRESULT hr
= E_OUTOFMEMORY
;
509 memset( uc
, 0, sizeof(*uc
) );
510 uc
->dwStructSize
= sizeof(*uc
);
511 uc
->dwHostNameLength
= 128;
512 uc
->lpszHostName
= heap_alloc( uc
->dwHostNameLength
* sizeof(WCHAR
) );
513 uc
->dwUrlPathLength
= 128;
514 uc
->lpszUrlPath
= heap_alloc( uc
->dwUrlPathLength
* sizeof(WCHAR
) );
515 uc
->dwExtraInfoLength
= 128;
516 uc
->lpszExtraInfo
= heap_alloc( uc
->dwExtraInfoLength
* sizeof(WCHAR
) );
517 if (!uc
->lpszHostName
|| !uc
->lpszUrlPath
|| !uc
->lpszExtraInfo
) goto error
;
519 if (!WinHttpCrackUrl( url
, len
, ICU_DECODE
, uc
))
521 if ((err
= GetLastError()) != ERROR_INSUFFICIENT_BUFFER
)
523 hr
= HRESULT_FROM_WIN32( err
);
526 if (!(tmp
= heap_realloc( uc
->lpszHostName
, uc
->dwHostNameLength
* sizeof(WCHAR
) ))) goto error
;
527 uc
->lpszHostName
= tmp
;
528 if (!(tmp
= heap_realloc( uc
->lpszUrlPath
, uc
->dwUrlPathLength
* sizeof(WCHAR
) ))) goto error
;
529 uc
->lpszUrlPath
= tmp
;
530 if (!(tmp
= heap_realloc( uc
->lpszExtraInfo
, uc
->dwExtraInfoLength
* sizeof(WCHAR
) ))) goto error
;
531 uc
->lpszExtraInfo
= tmp
;
532 WinHttpCrackUrl( url
, len
, ICU_DECODE
, uc
);
538 heap_free( uc
->lpszHostName
);
539 heap_free( uc
->lpszUrlPath
);
540 heap_free( uc
->lpszExtraInfo
);
544 static HRESULT
connect_channel_http( struct channel
*channel
)
546 static const WCHAR agentW
[] =
547 {'M','S','-','W','e','b','S','e','r','v','i','c','e','s','/','1','.','0',0};
548 static const WCHAR postW
[] =
550 HINTERNET ses
= NULL
, con
= NULL
, req
= NULL
;
556 if (channel
->u
.http
.request
) return S_OK
;
558 if ((hr
= parse_http_url( channel
->addr
.url
.chars
, channel
->addr
.url
.length
, &uc
)) != S_OK
) return hr
;
559 if (!uc
.dwExtraInfoLength
) path
= uc
.lpszUrlPath
;
560 else if (!(path
= heap_alloc( (uc
.dwUrlPathLength
+ uc
.dwExtraInfoLength
+ 1) * sizeof(WCHAR
) )))
567 strcpyW( path
, uc
.lpszUrlPath
);
568 strcatW( path
, uc
.lpszExtraInfo
);
573 case INTERNET_SCHEME_HTTP
: break;
574 case INTERNET_SCHEME_HTTPS
:
575 flags
|= WINHTTP_FLAG_SECURE
;
579 hr
= WS_E_INVALID_ENDPOINT_URL
;
583 if (!(ses
= WinHttpOpen( agentW
, 0, NULL
, NULL
, 0 )))
585 hr
= HRESULT_FROM_WIN32( GetLastError() );
588 if (!(con
= WinHttpConnect( ses
, uc
.lpszHostName
, uc
.nPort
, 0 )))
590 hr
= HRESULT_FROM_WIN32( GetLastError() );
593 if (!(req
= WinHttpOpenRequest( con
, postW
, path
, NULL
, NULL
, NULL
, flags
)))
595 hr
= HRESULT_FROM_WIN32( GetLastError() );
599 if ((hr
= message_insert_http_headers( channel
->msg
, req
)) != S_OK
) goto done
;
601 channel
->u
.http
.session
= ses
;
602 channel
->u
.http
.connect
= con
;
603 channel
->u
.http
.request
= req
;
608 WinHttpCloseHandle( req
);
609 WinHttpCloseHandle( con
);
610 WinHttpCloseHandle( ses
);
612 heap_free( uc
.lpszHostName
);
613 heap_free( uc
.lpszUrlPath
);
614 heap_free( uc
.lpszExtraInfo
);
615 if (path
!= uc
.lpszUrlPath
) heap_free( path
);
619 static HRESULT
connect_channel_tcp( struct channel
*channel
)
621 struct sockaddr_storage storage
;
622 struct sockaddr
*addr
= (struct sockaddr
*)&storage
;
624 WS_URL_SCHEME_TYPE scheme
;
629 if (channel
->u
.tcp
.socket
!= -1) return S_OK
;
631 if ((hr
= parse_url( &channel
->addr
.url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
632 if (scheme
!= WS_URL_NETTCP_SCHEME_TYPE
)
635 return WS_E_INVALID_ENDPOINT_URL
;
640 hr
= resolve_hostname( host
, port
, addr
, &addr_len
);
642 if (hr
!= S_OK
) return hr
;
644 if ((channel
->u
.tcp
.socket
= socket( addr
->sa_family
, SOCK_STREAM
, 0 )) == -1)
645 return HRESULT_FROM_WIN32( WSAGetLastError() );
647 if (connect( channel
->u
.tcp
.socket
, addr
, addr_len
) < 0)
649 closesocket( channel
->u
.tcp
.socket
);
650 channel
->u
.tcp
.socket
= -1;
651 return HRESULT_FROM_WIN32( WSAGetLastError() );
657 static HRESULT
connect_channel_udp( struct channel
*channel
)
659 struct sockaddr_storage storage
;
660 struct sockaddr
*addr
= (struct sockaddr
*)&storage
;
662 WS_URL_SCHEME_TYPE scheme
;
667 if (channel
->u
.udp
.socket
!= -1) return S_OK
;
669 if ((hr
= parse_url( &channel
->addr
.url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
670 if (scheme
!= WS_URL_SOAPUDP_SCHEME_TYPE
)
673 return WS_E_INVALID_ENDPOINT_URL
;
678 hr
= resolve_hostname( host
, port
, addr
, &addr_len
);
680 if (hr
!= S_OK
) return hr
;
682 if ((channel
->u
.udp
.socket
= socket( addr
->sa_family
, SOCK_DGRAM
, 0 )) == -1)
683 return HRESULT_FROM_WIN32( WSAGetLastError() );
685 if (connect( channel
->u
.udp
.socket
, addr
, addr_len
) < 0)
687 closesocket( channel
->u
.udp
.socket
);
688 channel
->u
.udp
.socket
= -1;
689 return HRESULT_FROM_WIN32( WSAGetLastError() );
695 static HRESULT
connect_channel( struct channel
*channel
)
697 switch (channel
->binding
)
699 case WS_HTTP_CHANNEL_BINDING
:
700 return connect_channel_http( channel
);
702 case WS_TCP_CHANNEL_BINDING
:
703 return connect_channel_tcp( channel
);
705 case WS_UDP_CHANNEL_BINDING
:
706 return connect_channel_udp( channel
);
709 ERR( "unhandled binding %u\n", channel
->binding
);
714 static HRESULT
write_message( WS_MESSAGE
*handle
, WS_XML_WRITER
*writer
, const WS_ELEMENT_DESCRIPTION
*desc
,
715 WS_WRITE_OPTION option
, const void *body
, ULONG size
)
718 if ((hr
= WsWriteEnvelopeStart( handle
, writer
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
719 if ((hr
= WsWriteBody( handle
, desc
, option
, body
, size
, NULL
)) != S_OK
) return hr
;
720 return WsWriteEnvelopeEnd( handle
, NULL
);
723 static HRESULT
send_message_http( HANDLE request
, BYTE
*data
, ULONG len
)
725 if (!WinHttpSendRequest( request
, NULL
, 0, data
, len
, len
, 0 ))
726 return HRESULT_FROM_WIN32( GetLastError() );
728 if (!WinHttpReceiveResponse( request
, NULL
))
729 return HRESULT_FROM_WIN32( GetLastError() );
733 static HRESULT
send_message_sock( SOCKET socket
, BYTE
*data
, ULONG len
)
735 if (send( socket
, (const char *)data
, len
, 0 ) < 0)
736 return HRESULT_FROM_WIN32( WSAGetLastError() );
740 static HRESULT
send_message( struct channel
*channel
, WS_MESSAGE
*msg
)
742 WS_XML_WRITER
*writer
;
747 if ((hr
= connect_channel( channel
)) != S_OK
) return hr
;
749 WsGetMessageProperty( channel
->msg
, WS_MESSAGE_PROPERTY_BODY_WRITER
, &writer
, sizeof(writer
), NULL
);
750 WsGetWriterProperty( writer
, WS_XML_WRITER_PROPERTY_BYTES
, &buf
, sizeof(buf
), NULL
);
752 switch (channel
->binding
)
754 case WS_HTTP_CHANNEL_BINDING
:
755 return send_message_http( channel
->u
.http
.request
, buf
.bytes
, buf
.length
);
757 case WS_TCP_CHANNEL_BINDING
:
758 return send_message_sock( channel
->u
.tcp
.socket
, buf
.bytes
, buf
.length
);
760 case WS_UDP_CHANNEL_BINDING
:
761 return send_message_sock( channel
->u
.udp
.socket
, buf
.bytes
, buf
.length
);
764 ERR( "unhandled binding %u\n", channel
->binding
);
769 HRESULT
channel_send_message( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
)
771 struct channel
*channel
= (struct channel
*)handle
;
774 EnterCriticalSection( &channel
->cs
);
776 if (channel
->magic
!= CHANNEL_MAGIC
)
778 LeaveCriticalSection( &channel
->cs
);
782 hr
= send_message( channel
, msg
);
784 LeaveCriticalSection( &channel
->cs
);
788 HRESULT
set_output( WS_XML_WRITER
*writer
)
790 WS_XML_WRITER_TEXT_ENCODING text
= { {WS_XML_WRITER_ENCODING_TYPE_TEXT
}, WS_CHARSET_UTF8
};
791 WS_XML_WRITER_BUFFER_OUTPUT buf
= { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER
} };
792 return WsSetOutput( writer
, &text
.encoding
, &buf
.output
, NULL
, 0, NULL
);
795 static HRESULT
init_writer( struct channel
*channel
)
798 if (!channel
->writer
&& (hr
= WsCreateWriter( NULL
, 0, &channel
->writer
, NULL
)) != S_OK
) return hr
;
799 return set_output( channel
->writer
);
802 /**************************************************************************
803 * WsSendMessage [webservices.@]
805 HRESULT WINAPI
WsSendMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
806 WS_WRITE_OPTION option
, const void *body
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
,
809 struct channel
*channel
= (struct channel
*)handle
;
812 TRACE( "%p %p %p %08x %p %u %p %p\n", handle
, msg
, desc
, option
, body
, size
, ctx
, error
);
813 if (error
) FIXME( "ignoring error parameter\n" );
814 if (ctx
) FIXME( "ignoring ctx parameter\n" );
816 if (!channel
|| !msg
|| !desc
) return E_INVALIDARG
;
818 EnterCriticalSection( &channel
->cs
);
820 if (channel
->magic
!= CHANNEL_MAGIC
)
822 LeaveCriticalSection( &channel
->cs
);
826 if ((hr
= WsInitializeMessage( msg
, WS_REQUEST_MESSAGE
, NULL
, NULL
)) != S_OK
) goto done
;
827 if ((hr
= WsAddressMessage( msg
, &channel
->addr
, NULL
)) != S_OK
) goto done
;
828 if ((hr
= message_set_action( msg
, desc
->action
)) != S_OK
) goto done
;
830 if ((hr
= init_writer( channel
)) != S_OK
) goto done
;
831 if ((hr
= write_message( msg
, channel
->writer
, desc
->bodyElementDescription
, option
, body
, size
)) != S_OK
)
833 hr
= send_message( channel
, msg
);
836 LeaveCriticalSection( &channel
->cs
);
840 static HRESULT
resize_read_buffer( struct channel
*channel
, ULONG size
)
842 if (!channel
->read_buf
)
844 if (!(channel
->read_buf
= heap_alloc( size
))) return E_OUTOFMEMORY
;
845 channel
->read_buflen
= size
;
848 if (channel
->read_buflen
< size
)
851 ULONG new_size
= max( size
, channel
->read_buflen
* 2 );
852 if (!(tmp
= heap_realloc( channel
->read_buf
, new_size
))) return E_OUTOFMEMORY
;
853 channel
->read_buf
= tmp
;
854 channel
->read_buflen
= new_size
;
859 static HRESULT
set_input( WS_XML_READER
*reader
, char *data
, ULONG size
)
861 WS_XML_READER_TEXT_ENCODING text
= {{WS_XML_READER_ENCODING_TYPE_TEXT
}, WS_CHARSET_UTF8
};
862 WS_XML_READER_BUFFER_INPUT buf
;
864 buf
.input
.inputType
= WS_XML_READER_INPUT_TYPE_BUFFER
;
865 buf
.encodedData
= data
;
866 buf
.encodedDataSize
= size
;
867 return WsSetInput( reader
, &text
.encoding
, &buf
.input
, NULL
, 0, NULL
);
870 static HRESULT
init_reader( struct channel
*channel
)
873 if (!channel
->reader
&& (hr
= WsCreateReader( NULL
, 0, &channel
->reader
, NULL
)) != S_OK
) return hr
;
874 return set_input( channel
->reader
, channel
->read_buf
, channel
->read_size
);
877 #define INITIAL_READ_BUFFER_SIZE 4096
878 static HRESULT
receive_message_http( struct channel
*channel
)
880 DWORD len
, bytes_read
, offset
= 0, size
= INITIAL_READ_BUFFER_SIZE
;
884 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE
,
885 &max_len
, sizeof(max_len
) );
887 if ((hr
= resize_read_buffer( channel
, size
)) != S_OK
) return hr
;
888 channel
->read_size
= 0;
891 if (!WinHttpQueryDataAvailable( channel
->u
.http
.request
, &len
))
893 return HRESULT_FROM_WIN32( GetLastError() );
896 if (channel
->read_size
+ len
> max_len
) return WS_E_QUOTA_EXCEEDED
;
897 if ((hr
= resize_read_buffer( channel
, channel
->read_size
+ len
)) != S_OK
) return hr
;
899 if (!WinHttpReadData( channel
->u
.http
.request
, channel
->read_buf
+ offset
, len
, &bytes_read
))
901 return HRESULT_FROM_WIN32( GetLastError() );
903 if (!bytes_read
) break;
904 channel
->read_size
+= bytes_read
;
905 offset
+= bytes_read
;
908 return init_reader( channel
);
911 static HRESULT
receive_message_sock( struct channel
*channel
, SOCKET socket
)
917 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE
,
918 &max_len
, sizeof(max_len
) );
920 if ((hr
= resize_read_buffer( channel
, max_len
)) != S_OK
) return hr
;
922 channel
->read_size
= 0;
923 if ((bytes_read
= recv( socket
, channel
->read_buf
, max_len
, 0 )) < 0)
925 return HRESULT_FROM_WIN32( WSAGetLastError() );
927 channel
->read_size
= bytes_read
;
929 return init_reader( channel
);
932 static HRESULT
receive_message( struct channel
*channel
)
936 if ((hr
= connect_channel( channel
)) != S_OK
) return hr
;
938 switch (channel
->binding
)
940 case WS_HTTP_CHANNEL_BINDING
:
941 return receive_message_http( channel
);
943 case WS_TCP_CHANNEL_BINDING
:
944 return receive_message_sock( channel
, channel
->u
.tcp
.socket
);
946 case WS_UDP_CHANNEL_BINDING
:
947 return receive_message_sock( channel
, channel
->u
.udp
.socket
);
950 ERR( "unhandled binding %u\n", channel
->binding
);
955 HRESULT
channel_receive_message( WS_CHANNEL
*handle
)
957 struct channel
*channel
= (struct channel
*)handle
;
960 EnterCriticalSection( &channel
->cs
);
962 if (channel
->magic
!= CHANNEL_MAGIC
)
964 LeaveCriticalSection( &channel
->cs
);
968 hr
= receive_message( channel
);
970 LeaveCriticalSection( &channel
->cs
);
974 HRESULT
channel_get_reader( WS_CHANNEL
*handle
, WS_XML_READER
**reader
)
976 struct channel
*channel
= (struct channel
*)handle
;
978 EnterCriticalSection( &channel
->cs
);
980 if (channel
->magic
!= CHANNEL_MAGIC
)
982 LeaveCriticalSection( &channel
->cs
);
986 *reader
= channel
->reader
;
988 LeaveCriticalSection( &channel
->cs
);
992 static HRESULT
read_message( WS_MESSAGE
*handle
, WS_XML_READER
*reader
, const WS_ELEMENT_DESCRIPTION
*desc
,
993 WS_READ_OPTION option
, WS_HEAP
*heap
, void *body
, ULONG size
)
996 if ((hr
= WsReadEnvelopeStart( handle
, reader
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
997 if ((hr
= WsReadBody( handle
, desc
, option
, heap
, body
, size
, NULL
)) != S_OK
) return hr
;
998 return WsReadEnvelopeEnd( handle
, NULL
);
1001 /**************************************************************************
1002 * WsReceiveMessage [webservices.@]
1004 HRESULT WINAPI
WsReceiveMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
**desc
,
1005 ULONG count
, WS_RECEIVE_OPTION option
, WS_READ_OPTION read_option
, WS_HEAP
*heap
,
1006 void *value
, ULONG size
, ULONG
*index
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
1008 struct channel
*channel
= (struct channel
*)handle
;
1011 TRACE( "%p %p %p %u %08x %08x %p %p %u %p %p %p\n", handle
, msg
, desc
, count
, option
, read_option
, heap
,
1012 value
, size
, index
, ctx
, error
);
1013 if (error
) FIXME( "ignoring error parameter\n" );
1014 if (ctx
) FIXME( "ignoring ctx parameter\n" );
1017 FIXME( "index parameter not supported\n" );
1022 FIXME( "no support for multiple descriptions\n" );
1025 if (option
!= WS_RECEIVE_REQUIRED_MESSAGE
)
1027 FIXME( "receive option %08x not supported\n", option
);
1031 if (!channel
|| !msg
|| !desc
|| !count
) return E_INVALIDARG
;
1033 EnterCriticalSection( &channel
->cs
);
1035 if (channel
->magic
!= CHANNEL_MAGIC
)
1037 LeaveCriticalSection( &channel
->cs
);
1038 return E_INVALIDARG
;
1041 if ((hr
= receive_message( channel
)) != S_OK
) goto done
;
1042 hr
= read_message( msg
, channel
->reader
, desc
[0]->bodyElementDescription
, read_option
, heap
, value
, size
);
1045 LeaveCriticalSection( &channel
->cs
);
1049 HRESULT
channel_accept_tcp( SOCKET socket
, WS_CHANNEL
*handle
)
1051 struct channel
*channel
= (struct channel
*)handle
;
1053 EnterCriticalSection( &channel
->cs
);
1055 if (channel
->magic
!= CHANNEL_MAGIC
)
1057 LeaveCriticalSection( &channel
->cs
);
1058 return E_INVALIDARG
;
1061 if ((channel
->u
.tcp
.socket
= accept( socket
, NULL
, NULL
)) == -1)
1063 LeaveCriticalSection( &channel
->cs
);
1064 return HRESULT_FROM_WIN32( WSAGetLastError() );
1067 LeaveCriticalSection( &channel
->cs
);
1071 static HRESULT
sock_wait( SOCKET socket
)
1076 FD_SET( socket
, &read
);
1077 if (select( socket
+ 1, &read
, NULL
, NULL
, NULL
) < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
1081 HRESULT
channel_accept_udp( SOCKET socket
, WS_CHANNEL
*handle
)
1083 struct channel
*channel
= (struct channel
*)handle
;
1086 EnterCriticalSection( &channel
->cs
);
1088 if (channel
->magic
!= CHANNEL_MAGIC
)
1090 LeaveCriticalSection( &channel
->cs
);
1091 return E_INVALIDARG
;
1094 if ((hr
= sock_wait( socket
)) == S_OK
) channel
->u
.udp
.socket
= socket
;
1096 LeaveCriticalSection( &channel
->cs
);