msvcrt: Stop at trylevel for ControlPc on target frame for non-consolidate unwinds.
[wine.git] / dlls / webservices / tests / proxy.c
blobbc7ef81db7d1b1a718899de511a4f72fabd168e1
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 <stdio.h>
20 #include "windows.h"
21 #include "winsock2.h"
22 #include "webservices.h"
23 #include "wine/test.h"
25 static inline void set_field_desc( WS_FIELD_DESCRIPTION *desc, WS_FIELD_MAPPING mapping,
26 WS_XML_STRING *localname, WS_XML_STRING *ns, WS_TYPE type,
27 void *type_desc, ULONG offset, ULONG options, ULONG count_offset,
28 WS_XML_STRING *item_localname, WS_XML_STRING *item_ns )
30 memset( desc, 0, sizeof(*desc) );
31 desc->mapping = mapping;
32 desc->localName = localname;
33 desc->ns = ns;
34 desc->type = type;
35 desc->typeDescription = type_desc;
36 desc->offset = offset;
37 desc->options = options;
38 desc->countOffset = count_offset;
39 desc->itemLocalName = item_localname;
40 desc->itemNs = item_ns;
43 static inline void set_struct_desc( WS_STRUCT_DESCRIPTION *desc, ULONG size, ULONG alignment,
44 WS_FIELD_DESCRIPTION **fields, ULONG count, WS_XML_STRING *localname,
45 WS_XML_STRING *ns, ULONG options )
47 memset( desc, 0, sizeof(*desc) );
48 desc->size = size;
49 desc->alignment = alignment;
50 desc->fields = fields;
51 desc->fieldCount = count;
52 desc->typeLocalName = localname;
53 desc->typeNs = ns;
54 desc->structOptions = options;
57 static inline void set_elem_desc( WS_ELEMENT_DESCRIPTION *desc, WS_XML_STRING *localname, WS_XML_STRING *ns,
58 WS_TYPE type, void *type_desc )
60 desc->elementLocalName = localname;
61 desc->elementNs = ns;
62 desc->type = type;
63 desc->typeDescription = type_desc;
66 static inline void set_msg_desc( WS_MESSAGE_DESCRIPTION *desc, WS_XML_STRING *action,
67 WS_ELEMENT_DESCRIPTION *elem_desc )
69 desc->action = action;
70 desc->bodyElementDescription = elem_desc;
73 static inline void set_param_desc( WS_PARAMETER_DESCRIPTION *desc, WS_PARAMETER_TYPE type,
74 USHORT input_index, USHORT output_index )
76 desc->parameterType = type;
77 desc->inputMessageIndex = input_index;
78 desc->outputMessageIndex = output_index;
81 static inline void set_op_desc( WS_OPERATION_DESCRIPTION *desc, WS_MESSAGE_DESCRIPTION *input_msg,
82 WS_MESSAGE_DESCRIPTION *output_msg, ULONG count,
83 WS_PARAMETER_DESCRIPTION *param_desc )
85 memset( desc, 0, sizeof(*desc) );
86 desc->versionInfo = 1;
87 desc->inputMessageDescription = input_msg;
88 desc->outputMessageDescription = output_msg;
89 desc->parameterCount = count;
90 desc->parameterDescription = param_desc;
93 static void test_WsCreateServiceProxy(void)
95 HRESULT hr;
96 WS_SERVICE_PROXY *proxy;
97 WS_SERVICE_PROXY_STATE state;
98 ULONG value;
100 hr = WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL,
101 0, NULL, 0, NULL, NULL );
102 ok( hr == E_INVALIDARG, "got %08x\n", hr );
104 proxy = NULL;
105 hr = WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL,
106 0, NULL, 0, &proxy, NULL );
107 ok( hr == S_OK, "got %08x\n", hr );
108 ok( proxy != NULL, "proxy not set\n" );
110 /* write-only property */
111 value = 0xdeadbeef;
112 hr = WsGetServiceProxyProperty( proxy, WS_PROXY_PROPERTY_CALL_TIMEOUT, &value, sizeof(value), NULL );
113 ok( hr == E_INVALIDARG, "got %08x\n", hr );
115 state = 0xdeadbeef;
116 hr = WsGetServiceProxyProperty( proxy, WS_PROXY_PROPERTY_STATE, &state, sizeof(state), NULL );
117 ok( hr == S_OK, "got %08x\n", hr );
118 ok( state == WS_SERVICE_PROXY_STATE_CREATED, "got %u\n", state );
120 WsFreeServiceProxy( proxy );
123 static void test_WsCreateServiceProxyFromTemplate(void)
125 HRESULT hr;
126 WS_SERVICE_PROXY *proxy;
127 WS_HTTP_POLICY_DESCRIPTION policy;
129 hr = WsCreateServiceProxyFromTemplate( WS_CHANNEL_TYPE_REQUEST, NULL, 0, WS_HTTP_BINDING_TEMPLATE_TYPE,
130 NULL, 0, NULL, 0, NULL, NULL );
131 ok( hr == E_INVALIDARG, "got %08x\n", hr );
133 hr = WsCreateServiceProxyFromTemplate( WS_CHANNEL_TYPE_REQUEST, NULL, 0, WS_HTTP_BINDING_TEMPLATE_TYPE,
134 NULL, 0, NULL, 0, &proxy, NULL );
135 ok( hr == E_INVALIDARG, "got %08x\n", hr );
137 memset( &policy, 0, sizeof(policy) );
138 proxy = NULL;
139 hr = WsCreateServiceProxyFromTemplate( WS_CHANNEL_TYPE_REQUEST, NULL, 0, WS_HTTP_BINDING_TEMPLATE_TYPE,
140 NULL, 0, &policy, sizeof(policy), &proxy, NULL );
141 ok( hr == S_OK, "got %08x\n", hr );
142 ok( proxy != NULL, "proxy not set\n" );
144 WsFreeServiceProxy( proxy );
147 static void test_WsOpenServiceProxy(void)
149 WCHAR url[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t','/'};
150 HRESULT hr;
151 WS_SERVICE_PROXY *proxy;
152 WS_SERVICE_PROXY_STATE state;
153 WS_HTTP_POLICY_DESCRIPTION policy;
154 WS_ENDPOINT_ADDRESS addr;
156 memset( &policy, 0, sizeof(policy) );
157 hr = WsCreateServiceProxyFromTemplate( WS_CHANNEL_TYPE_REQUEST, NULL, 0, WS_HTTP_BINDING_TEMPLATE_TYPE,
158 NULL, 0, &policy, sizeof(policy), &proxy, NULL );
159 ok( hr == S_OK, "got %08x\n", hr );
161 state = 0xdeadbeef;
162 hr = WsGetServiceProxyProperty( proxy, WS_PROXY_PROPERTY_STATE, &state, sizeof(state), NULL );
163 ok( hr == S_OK, "got %08x\n", hr );
164 ok( state == WS_SERVICE_PROXY_STATE_CREATED, "got %u\n", state );
166 memset( &addr, 0, sizeof(addr) );
167 addr.url.length = sizeof(url)/sizeof(url[0]);
168 addr.url.chars = url;
169 hr = WsOpenServiceProxy( proxy, &addr, NULL, NULL );
170 ok( hr == S_OK, "got %08x\n", hr );
172 state = 0xdeadbeef;
173 hr = WsGetServiceProxyProperty( proxy, WS_PROXY_PROPERTY_STATE, &state, sizeof(state), NULL );
174 ok( hr == S_OK, "got %08x\n", hr );
175 ok( state == WS_SERVICE_PROXY_STATE_OPEN, "got %u\n", state );
177 hr = WsCloseServiceProxy( proxy , NULL, NULL );
178 ok( hr == S_OK, "got %08x\n", hr );
180 state = 0xdeadbeef;
181 hr = WsGetServiceProxyProperty( proxy, WS_PROXY_PROPERTY_STATE, &state, sizeof(state), NULL );
182 ok( hr == S_OK, "got %08x\n", hr );
183 ok( state == WS_SERVICE_PROXY_STATE_CLOSED, "got %u\n", state );
185 WsFreeServiceProxy( proxy );
188 static void test_WsResetServiceProxy(void)
190 WCHAR url[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t','/'};
191 HRESULT hr;
192 WS_SERVICE_PROXY *proxy;
193 WS_ENDPOINT_ADDRESS addr;
194 WS_SERVICE_PROXY_STATE state;
196 hr = WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL,
197 0, NULL, 0, &proxy, NULL );
198 ok( hr == S_OK, "got %08x\n", hr );
200 hr = WsResetServiceProxy( proxy, NULL );
201 ok( hr == S_OK, "got %08x\n", hr );
203 state = 0xdeadbeef;
204 hr = WsGetServiceProxyProperty( proxy, WS_PROXY_PROPERTY_STATE, &state, sizeof(state), NULL );
205 ok( hr == S_OK, "got %08x\n", hr );
206 ok( state == WS_SERVICE_PROXY_STATE_CREATED, "got %u\n", state );
208 memset( &addr, 0, sizeof(addr) );
209 addr.url.length = sizeof(url)/sizeof(url[0]);
210 addr.url.chars = url;
211 hr = WsOpenServiceProxy( proxy, &addr, NULL, NULL );
212 ok( hr == S_OK, "got %08x\n", hr );
214 hr = WsResetServiceProxy( proxy, NULL );
215 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
217 hr = WsCloseServiceProxy( proxy , NULL, NULL );
218 ok( hr == S_OK, "got %08x\n", hr );
220 hr = WsResetServiceProxy( proxy, NULL );
221 ok( hr == S_OK, "got %08x\n", hr );
223 state = 0xdeadbeef;
224 hr = WsGetServiceProxyProperty( proxy, WS_PROXY_PROPERTY_STATE, &state, sizeof(state), NULL );
225 ok( hr == S_OK, "got %08x\n", hr );
226 ok( state == WS_SERVICE_PROXY_STATE_CREATED, "got %u\n", state );
228 WsFreeServiceProxy( proxy );
231 static HRESULT create_channel( int port, WS_CHANNEL **ret )
233 static const WCHAR fmt[] =
234 {'h','t','t','p',':','/','/','1','2','7','.','0','.','0','.','1',':','%','u',0};
235 WS_CHANNEL_PROPERTY prop[2];
236 WS_ENVELOPE_VERSION env_version = WS_ENVELOPE_VERSION_SOAP_1_1;
237 WS_ADDRESSING_VERSION addr_version = WS_ADDRESSING_VERSION_TRANSPORT;
238 WS_CHANNEL *channel;
239 WS_ENDPOINT_ADDRESS addr;
240 WCHAR buf[64];
241 HRESULT hr;
243 prop[0].id = WS_CHANNEL_PROPERTY_ENVELOPE_VERSION;
244 prop[0].value = &env_version;
245 prop[0].valueSize = sizeof(env_version);
247 prop[1].id = WS_CHANNEL_PROPERTY_ADDRESSING_VERSION;
248 prop[1].value = &addr_version;
249 prop[1].valueSize = sizeof(addr_version);
251 *ret = NULL;
252 hr = WsCreateChannel( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, prop, 2, NULL, &channel, NULL );
253 if (hr != S_OK) return hr;
255 memset( &addr, 0, sizeof(addr) );
256 addr.url.length = wsprintfW( buf, fmt, port );
257 addr.url.chars = buf;
258 hr = WsOpenChannel( channel, &addr, NULL, NULL );
259 if (hr == S_OK) *ret = channel;
260 else WsFreeChannel( channel );
261 return hr;
264 static const char req_test1[] =
265 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
266 "<req_test1 xmlns=\"ns\">-1</req_test1>"
267 "</s:Body></s:Envelope>";
269 static const char resp_test1[] =
270 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
271 "<resp_test1 xmlns=\"ns\">-2</resp_test1>"
272 "</s:Body></s:Envelope>";
274 static void test_WsSendMessage( int port, WS_XML_STRING *action )
276 WS_XML_STRING req = {9, (BYTE *)"req_test1"}, ns = {2, (BYTE *)"ns"};
277 WS_CHANNEL *channel;
278 WS_MESSAGE *msg;
279 WS_ELEMENT_DESCRIPTION body;
280 WS_MESSAGE_DESCRIPTION desc;
281 INT32 val = -1;
282 HRESULT hr;
284 hr = create_channel( port, &channel );
285 ok( hr == S_OK, "got %08x\n", hr );
287 hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
288 ok( hr == S_OK, "got %08x\n", hr );
290 set_elem_desc( &body, &req, &ns, WS_INT32_TYPE, NULL );
291 set_msg_desc( &desc, action, &body );
292 hr = WsSendMessage( NULL, msg, &desc, WS_WRITE_REQUIRED_VALUE, &val, sizeof(val), NULL, NULL );
293 ok( hr == E_INVALIDARG, "got %08x\n", hr );
295 hr = WsSendMessage( channel, NULL, &desc, WS_WRITE_REQUIRED_VALUE, &val, sizeof(val), NULL, NULL );
296 ok( hr == E_INVALIDARG, "got %08x\n", hr );
298 hr = WsSendMessage( channel, msg, NULL, WS_WRITE_REQUIRED_VALUE, &val, sizeof(val), NULL, NULL );
299 ok( hr == E_INVALIDARG, "got %08x\n", hr );
301 hr = WsSendMessage( channel, msg, &desc, WS_WRITE_REQUIRED_VALUE, &val, sizeof(val), NULL, NULL );
302 ok( hr == S_OK, "got %08x\n", hr );
304 hr = WsCloseChannel( channel, NULL, NULL );
305 ok( hr == S_OK, "got %08x\n", hr );
307 WsFreeChannel( channel );
308 WsFreeMessage( msg );
311 static void test_WsReceiveMessage( int port )
313 WS_XML_STRING req = {9, (BYTE *)"req_test1"}, resp = {10, (BYTE *)"resp_test1"}, ns = {2, (BYTE *)"ns"};
314 WS_CHANNEL *channel;
315 WS_MESSAGE *msg;
316 WS_ELEMENT_DESCRIPTION body;
317 WS_MESSAGE_DESCRIPTION desc_req, desc_resp;
318 const WS_MESSAGE_DESCRIPTION *desc[1];
319 INT32 val = -1;
320 HRESULT hr;
322 hr = create_channel( port, &channel );
323 ok( hr == S_OK, "got %08x\n", hr );
325 hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
326 ok( hr == S_OK, "got %08x\n", hr );
328 set_elem_desc( &body, &req, &ns, WS_INT32_TYPE, NULL );
329 set_msg_desc( &desc_req, &req, &body );
330 hr = WsSendMessage( channel, msg, &desc_req, WS_WRITE_REQUIRED_VALUE, &val, sizeof(val), NULL, NULL );
331 ok( hr == S_OK, "got %08x\n", hr );
332 WsFreeMessage( msg );
334 hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
335 ok( hr == S_OK, "got %08x\n", hr );
337 set_elem_desc( &body, &resp, &ns, WS_INT32_TYPE, NULL );
338 set_msg_desc( &desc_resp, &resp, &body );
339 desc[0] = &desc_resp;
340 hr = WsReceiveMessage( NULL, msg, desc, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
341 NULL, &val, sizeof(val), NULL, NULL, NULL );
342 ok( hr == E_INVALIDARG, "got %08x\n", hr );
344 hr = WsReceiveMessage( channel, NULL, desc, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
345 NULL, &val, sizeof(val), NULL, NULL, NULL );
346 ok( hr == E_INVALIDARG, "got %08x\n", hr );
348 hr = WsReceiveMessage( channel, msg, NULL, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
349 NULL, &val, sizeof(val), NULL, NULL, NULL );
350 ok( hr == E_INVALIDARG, "got %08x\n", hr );
352 hr = WsReceiveMessage( channel, msg, desc, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
353 NULL, &val, sizeof(val), NULL, NULL, NULL );
354 ok( hr == S_OK, "got %08x\n", hr );
355 ok( val == -2, "got %d\n", val );
357 hr = WsCloseChannel( channel, NULL, NULL );
358 ok( hr == S_OK, "got %08x\n", hr );
360 WsFreeChannel( channel );
361 WsFreeMessage( msg );
364 static HRESULT create_proxy( int port, WS_SERVICE_PROXY **ret )
366 static const WCHAR fmt[] =
367 {'h','t','t','p',':','/','/','1','2','7','.','0','.','0','.','1',':','%','u','/',0};
368 WS_ENVELOPE_VERSION env_version;
369 WS_ADDRESSING_VERSION addr_version;
370 WS_CHANNEL_PROPERTY prop[2];
371 WS_ENDPOINT_ADDRESS addr;
372 WS_SERVICE_PROXY *proxy;
373 WCHAR url[64];
374 HRESULT hr;
376 env_version = WS_ENVELOPE_VERSION_SOAP_1_1;
377 prop[0].id = WS_CHANNEL_PROPERTY_ENVELOPE_VERSION;
378 prop[0].value = &env_version;
379 prop[0].valueSize = sizeof(env_version);
381 addr_version = WS_ADDRESSING_VERSION_TRANSPORT;
382 prop[1].id = WS_CHANNEL_PROPERTY_ADDRESSING_VERSION;
383 prop[1].value = &addr_version;
384 prop[1].valueSize = sizeof(addr_version);
386 *ret = NULL;
387 hr = WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL,
388 0, prop, sizeof(prop)/sizeof(prop[0]), &proxy, NULL );
389 if (hr != S_OK) return hr;
391 memset( &addr, 0, sizeof(addr) );
392 addr.url.length = wsprintfW( url, fmt, port );
393 addr.url.chars = url;
394 hr = WsOpenServiceProxy( proxy, &addr, NULL, NULL );
395 if (hr == S_OK) *ret = proxy;
396 else WsFreeServiceProxy( proxy );
397 return hr;
400 static const char req_test2[] =
401 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
402 "<req_test2 xmlns=\"ns\"><val>1</val><str>test</str><str>test2</str></req_test2>"
403 "</s:Body></s:Envelope>";
405 static const char resp_test2[] =
406 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
407 "<resp_test2 xmlns=\"ns\"><str>test</str><val>1</val><val>2</val></resp_test2>"
408 "</s:Body></s:Envelope>";
410 static void test_WsCall( int port )
412 static const WCHAR testW[] = {'t','e','s','t',0}, test2W[] = {'t','e','s','t','2',0};
413 WS_XML_STRING str = {3, (BYTE *)"str"};
414 WS_XML_STRING req = {3, (BYTE *)"req"};
415 WS_XML_STRING resp = {4, (BYTE *)"resp"};
416 WS_XML_STRING req_elem = {9, (BYTE *)"req_test2"};
417 WS_XML_STRING resp_elem = {10, (BYTE *)"resp_test2"};
418 WS_XML_STRING req_action = {9, (BYTE *)"req_test2"};
419 WS_XML_STRING resp_action = {10, (BYTE *)"resp_test2"};
420 WS_XML_STRING val = {3, (BYTE *)"val"};
421 WS_XML_STRING ns = {2, (BYTE *)"ns"};
422 HRESULT hr;
423 WS_SERVICE_PROXY *proxy;
424 WS_OPERATION_DESCRIPTION op;
425 WS_MESSAGE_DESCRIPTION input_msg, output_msg;
426 WS_ELEMENT_DESCRIPTION input_elem, output_elem;
427 WS_STRUCT_DESCRIPTION input_struct, output_struct;
428 WS_FIELD_DESCRIPTION f, f2, f3, f4, *fields[2], *fields2[2];
429 WS_PARAMETER_DESCRIPTION param[6];
430 const void *args[6];
431 WS_HEAP *heap;
432 INT32 **val_ptr;
433 WCHAR **str_ptr;
434 ULONG *count_ptr;
435 const WCHAR *str_array[2];
436 struct input
438 INT32 val;
439 ULONG count;
440 const WCHAR **str;
441 } in;
442 struct output
444 WCHAR *str;
445 ULONG count;
446 INT32 *val;
447 } out;
449 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
450 ok( hr == S_OK, "got %08x\n", hr );
452 hr = WsCall( NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL );
453 ok( hr == E_INVALIDARG, "got %08x\n", hr );
455 hr = create_proxy( port, &proxy );
456 ok( hr == S_OK, "got %08x\n", hr );
458 hr = WsCall( proxy, NULL, NULL, NULL, NULL, 0, NULL, NULL );
459 ok( hr == E_INVALIDARG, "got %08x\n", hr );
461 set_field_desc( &f, WS_ELEMENT_FIELD_MAPPING, &val, &ns, WS_INT32_TYPE, NULL, 0, 0, 0, NULL, NULL );
462 set_field_desc( &f4, WS_REPEATING_ELEMENT_FIELD_MAPPING, NULL, NULL, WS_WSZ_TYPE, NULL,
463 FIELD_OFFSET(struct input, str), 0, FIELD_OFFSET(struct input, count), &str, &ns );
464 fields[0] = &f;
465 fields[1] = &f4;
467 set_struct_desc( &input_struct, sizeof(struct input), TYPE_ALIGNMENT(struct input), fields, 2, &req, &ns, 0 );
468 set_elem_desc( &input_elem, &req_elem, &ns, WS_STRUCT_TYPE, &input_struct );
469 set_msg_desc( &input_msg, &req_action, &input_elem );
471 set_field_desc( &f2, WS_ELEMENT_FIELD_MAPPING, &str, &ns, WS_WSZ_TYPE, NULL, FIELD_OFFSET(struct output, str),
472 0, 0, NULL, NULL );
473 set_field_desc( &f3, WS_REPEATING_ELEMENT_FIELD_MAPPING, NULL, NULL, WS_INT32_TYPE, NULL,
474 FIELD_OFFSET(struct output, val), 0, FIELD_OFFSET(struct output, count), &val, &ns );
475 fields2[0] = &f2;
476 fields2[1] = &f3;
478 set_struct_desc( &output_struct, sizeof(struct output), TYPE_ALIGNMENT(struct output), fields2, 2, &resp, &ns, 0 );
479 set_elem_desc( &output_elem, &resp_elem, &ns, WS_STRUCT_TYPE, &output_struct );
480 set_msg_desc( &output_msg, &resp_action, &output_elem );
482 set_param_desc( &param[0], WS_PARAMETER_TYPE_NORMAL, 0, 0xffff );
483 set_param_desc( &param[1], WS_PARAMETER_TYPE_ARRAY, 1, 0xffff );
484 set_param_desc( &param[2], WS_PARAMETER_TYPE_ARRAY_COUNT, 1, 0xffff );
485 set_param_desc( &param[3], WS_PARAMETER_TYPE_NORMAL, 0xffff, 0 );
486 set_param_desc( &param[4], WS_PARAMETER_TYPE_ARRAY, 0xffff, 1 );
487 set_param_desc( &param[5], WS_PARAMETER_TYPE_ARRAY_COUNT, 0xffff, 1 );
489 set_op_desc( &op, &input_msg, &output_msg, 6, param );
490 hr = WsCall( proxy, &op, NULL, NULL, NULL, 0, NULL, NULL );
491 ok( hr == E_INVALIDARG, "got %08x\n", hr );
493 in.val = 1;
494 str_array[0] = testW;
495 str_array[1] = test2W;
496 in.str = str_array;
497 in.count = 2;
499 args[0] = &in.val;
500 args[1] = &in.str;
501 args[2] = &in.count;
503 out.str = NULL;
504 out.count = 0;
505 out.val = NULL;
506 str_ptr = &out.str;
507 val_ptr = &out.val;
508 count_ptr = &out.count;
510 args[3] = &str_ptr;
511 args[4] = &val_ptr;
512 args[5] = &count_ptr;
514 hr = WsCall( proxy, &op, args, heap, NULL, 0, NULL, NULL );
515 ok( hr == S_OK, "got %08x\n", hr );
516 ok( !lstrcmpW( out.str, testW ), "wrong data\n" );
517 ok( out.count == 2, "got %u\n", out.count );
518 ok( out.val[0] == 1, "got %u\n", out.val[0] );
519 ok( out.val[1] == 2, "got %u\n", out.val[1] );
521 hr = WsCloseServiceProxy( proxy, NULL, NULL );
522 ok( hr == S_OK, "got %08x\n", hr );
524 WsFreeServiceProxy( proxy );
525 WsFreeHeap( heap );
528 static const char req_test3[] =
529 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
530 "<req_test3 xmlns=\"ns\"><val>1</val></req_test3>"
531 "</s:Body></s:Envelope>";
533 static const char resp_test3[] =
534 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body/></s:Envelope>";
536 static void test_empty_response( int port )
538 WS_XML_STRING req = {3, (BYTE *)"req"};
539 WS_XML_STRING resp = {4, (BYTE *)"resp"};
540 WS_XML_STRING req_action = {9, (BYTE *)"req_test3"};
541 WS_XML_STRING resp_action = {10, (BYTE *)"resp_test3"};
542 WS_XML_STRING req_elem = {9, (BYTE *)"req_test3"};
543 WS_XML_STRING resp_elem = {10, (BYTE *)"resp_test3"};
544 WS_XML_STRING ns = {2, (BYTE *)"ns"};
545 WS_XML_STRING ns2 = {0, (BYTE *)""};
546 WS_XML_STRING val = {3, (BYTE *)"val"};
547 HRESULT hr;
548 WS_SERVICE_PROXY *proxy;
549 WS_FIELD_DESCRIPTION f, *fields[1];
550 WS_STRUCT_DESCRIPTION input_struct, output_struct;
551 WS_ELEMENT_DESCRIPTION input_elem, output_elem;
552 WS_MESSAGE_DESCRIPTION input_msg, output_msg;
553 WS_PARAMETER_DESCRIPTION param[1];
554 WS_OPERATION_DESCRIPTION op;
555 const void *args[1];
556 WS_HEAP *heap;
557 struct input
559 INT32 val;
560 } in;
562 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
563 ok( hr == S_OK, "got %08x\n", hr );
565 hr = create_proxy( port, &proxy );
566 ok( hr == S_OK, "got %08x\n", hr );
568 set_field_desc( &f, WS_ELEMENT_FIELD_MAPPING, &val, &ns, WS_INT32_TYPE, NULL, 0, 0, 0, NULL, NULL );
569 fields[0] = &f;
571 set_struct_desc( &input_struct, sizeof(struct input), TYPE_ALIGNMENT(struct input), fields, 1, &req, &ns, 0 );
572 set_elem_desc( &input_elem, &req_elem, &ns, WS_STRUCT_TYPE, &input_struct );
573 set_msg_desc( &input_msg, &req_action, &input_elem );
575 set_struct_desc( &output_struct, 0, 1, NULL, 0, &resp, &ns2, 0x6 );
576 set_elem_desc( &output_elem, &resp_elem, &ns, WS_STRUCT_TYPE, NULL );
577 set_msg_desc( &output_msg, &resp_action, &output_elem );
579 set_param_desc( param, WS_PARAMETER_TYPE_NORMAL, 0, 0xffff );
580 set_op_desc( &op, &input_msg, &output_msg, 1, param );
582 in.val = 1;
583 args[0] = &in.val;
584 hr = WsCall( proxy, &op, args, heap, NULL, 0, NULL, NULL );
585 ok( hr == E_INVALIDARG, "got %08x\n", hr );
587 set_elem_desc( &output_elem, &resp_elem, &ns, WS_STRUCT_TYPE, &output_struct );
588 hr = WsCall( proxy, &op, args, heap, NULL, 0, NULL, NULL );
589 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
591 hr = WsCloseServiceProxy( proxy, NULL, NULL );
592 ok( hr == S_OK, "got %08x\n", hr );
594 WsFreeServiceProxy( proxy );
595 WsFreeHeap( heap );
598 static const char status_200[] = "HTTP/1.1 200 OK\r\n";
600 static const struct
602 const char *req_action;
603 const char *req_data;
604 unsigned int req_len;
605 const char *resp_status;
606 const char *resp_data;
607 unsigned int resp_len;
609 tests[] =
611 { "req_test1", req_test1, sizeof(req_test1)-1, status_200, resp_test1, sizeof(resp_test1)-1 },
612 { "req_test2", req_test2, sizeof(req_test2)-1, status_200, resp_test2, sizeof(resp_test2)-1 },
613 { "req_test3", req_test3, sizeof(req_test3)-1, status_200, resp_test3, sizeof(resp_test3)-1 },
616 static void send_response( int c, const char *status, const char *data, unsigned int len )
618 static const char headers[] =
619 "Content-Type: text/xml; charset=utf-8\r\nConnection: close\r\n";
620 static const char fmt[] =
621 "Content-Length: %u\r\n\r\n";
622 char buf[128];
624 send( c, status, strlen(status), 0 );
625 send( c, headers, sizeof(headers) - 1, 0 );
626 sprintf( buf, fmt, len );
627 send( c, buf, strlen(buf), 0 );
628 send( c, data, len, 0 );
631 struct server_info
633 HANDLE event;
634 int port;
637 static DWORD CALLBACK server_proc( void *arg )
639 struct server_info *info = arg;
640 int len, res, c = -1, i, j, on = 1, quit;
641 WSADATA wsa;
642 SOCKET s;
643 struct sockaddr_in sa;
644 char buf[1024];
645 const char *p;
647 WSAStartup( MAKEWORD(1,1), &wsa );
648 if ((s = socket( AF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET) return 1;
649 setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on) );
651 memset( &sa, 0, sizeof(sa) );
652 sa.sin_family = AF_INET;
653 sa.sin_port = htons( info->port );
654 sa.sin_addr.S_un.S_addr = inet_addr( "127.0.0.1" );
655 if (bind( s, (struct sockaddr *)&sa, sizeof(sa) ) < 0) return 1;
657 listen( s, 0 );
658 SetEvent( info->event );
659 for (;;)
661 c = accept( s, NULL, NULL );
663 buf[0] = 0;
664 for (i = 0; i < sizeof(buf) - 1; i++)
666 if ((res = recv( c, &buf[i], 1, 0 )) != 1) break;
667 if (i < 4) continue;
668 if (buf[i - 2] == '\n' && buf[i] == '\n' && buf[i - 3] == '\r' && buf[i - 1] == '\r')
669 break;
671 buf[i] = 0;
672 quit = strstr( buf, "SOAPAction: \"quit\"" ) != NULL;
674 len = 0;
675 if ((p = strstr( buf, "Content-Length: " )))
677 p += strlen( "Content-Length: " );
678 while (isdigit( *p ))
680 len *= 10;
681 len += *p++ - '0';
684 for (i = 0; i < len; i++)
686 if ((res = recv( c, &buf[i], 1, 0 )) != 1) break;
688 buf[i] = 0;
690 for (j = 0; j < sizeof(tests)/sizeof(tests[0]); j++)
692 if (strstr( buf, tests[j].req_action ))
694 if (tests[j].req_data)
696 int data_len = strlen( buf );
697 ok( tests[j].req_len == data_len, "%u: unexpected data length %u %u\n",
698 j, data_len, tests[j].req_len );
699 if (tests[j].req_len == data_len)
700 ok( !memcmp( tests[j].req_data, buf, tests[j].req_len ), "%u: unexpected data %s\n", j, buf );
702 send_response( c, tests[j].resp_status, tests[j].resp_data, tests[j].resp_len );
703 break;
707 shutdown( c, 2 );
708 closesocket( c );
709 if (quit) break;
712 return 0;
715 START_TEST(proxy)
717 WS_XML_STRING test1 = {9, (BYTE *)"req_test1"};
718 WS_XML_STRING quit = {4, (BYTE *)"quit"};
719 struct server_info info;
720 HANDLE thread;
721 DWORD ret;
723 test_WsCreateServiceProxy();
724 test_WsCreateServiceProxyFromTemplate();
725 test_WsOpenServiceProxy();
726 test_WsResetServiceProxy();
728 info.port = 7533;
729 info.event = CreateEventW( NULL, 0, 0, NULL );
730 thread = CreateThread( NULL, 0, server_proc, &info, 0, NULL );
731 ok( thread != NULL, "failed to create server thread %u\n", GetLastError() );
733 ret = WaitForSingleObject( info.event, 3000 );
734 ok(ret == WAIT_OBJECT_0, "failed to start test server %u\n", GetLastError());
735 if (ret != WAIT_OBJECT_0) return;
737 test_WsSendMessage( info.port, &test1 );
738 test_WsReceiveMessage( info.port );
739 test_WsCall( info.port );
740 test_empty_response( info.port );
742 test_WsSendMessage( info.port, &quit );
743 WaitForSingleObject( thread, 3000 );