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
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
;
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
) );
49 desc
->alignment
= alignment
;
50 desc
->fields
= fields
;
51 desc
->fieldCount
= count
;
52 desc
->typeLocalName
= localname
;
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
;
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)
96 WS_SERVICE_PROXY
*proxy
;
97 WS_SERVICE_PROXY_STATE state
;
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
);
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 */
112 hr
= WsGetServiceProxyProperty( proxy
, WS_PROXY_PROPERTY_CALL_TIMEOUT
, &value
, sizeof(value
), NULL
);
113 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
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)
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
) );
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','/'};
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
);
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
);
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
);
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','/'};
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
);
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
);
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
;
239 WS_ENDPOINT_ADDRESS addr
;
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
);
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
);
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"};
279 WS_ELEMENT_DESCRIPTION body
;
280 WS_MESSAGE_DESCRIPTION desc
;
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"};
316 WS_ELEMENT_DESCRIPTION body
;
317 WS_MESSAGE_DESCRIPTION desc_req
, desc_resp
;
318 const WS_MESSAGE_DESCRIPTION
*desc
[1];
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
;
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
);
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
);
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"};
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];
435 const WCHAR
*str_array
[2];
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
);
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
),
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
);
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( ¶m
[0], WS_PARAMETER_TYPE_NORMAL
, 0, 0xffff );
483 set_param_desc( ¶m
[1], WS_PARAMETER_TYPE_ARRAY
, 1, 0xffff );
484 set_param_desc( ¶m
[2], WS_PARAMETER_TYPE_ARRAY_COUNT
, 1, 0xffff );
485 set_param_desc( ¶m
[3], WS_PARAMETER_TYPE_NORMAL
, 0xffff, 0 );
486 set_param_desc( ¶m
[4], WS_PARAMETER_TYPE_ARRAY
, 0xffff, 1 );
487 set_param_desc( ¶m
[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
);
494 str_array
[0] = testW
;
495 str_array
[1] = test2W
;
508 count_ptr
= &out
.count
;
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
);
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"};
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
;
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
);
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
);
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
);
598 static const char status_200
[] = "HTTP/1.1 200 OK\r\n";
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
;
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";
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 );
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
;
643 struct sockaddr_in sa
;
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;
658 SetEvent( info
->event
);
661 c
= accept( s
, NULL
, NULL
);
664 for (i
= 0; i
< sizeof(buf
) - 1; i
++)
666 if ((res
= recv( c
, &buf
[i
], 1, 0 )) != 1) break;
668 if (buf
[i
- 2] == '\n' && buf
[i
] == '\n' && buf
[i
- 3] == '\r' && buf
[i
- 1] == '\r')
672 quit
= strstr( buf
, "SOAPAction: \"quit\"" ) != NULL
;
675 if ((p
= strstr( buf
, "Content-Length: " )))
677 p
+= strlen( "Content-Length: " );
678 while (isdigit( *p
))
684 for (i
= 0; i
< len
; i
++)
686 if ((res
= recv( c
, &buf
[i
], 1, 0 )) != 1) break;
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
);
717 WS_XML_STRING test1
= {9, (BYTE
*)"req_test1"};
718 WS_XML_STRING quit
= {4, (BYTE
*)"quit"};
719 struct server_info info
;
723 test_WsCreateServiceProxy();
724 test_WsCreateServiceProxyFromTemplate();
725 test_WsOpenServiceProxy();
726 test_WsResetServiceProxy();
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 );