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)
150 WS_SERVICE_PROXY
*proxy
;
151 WS_SERVICE_PROXY_STATE state
;
152 WS_HTTP_POLICY_DESCRIPTION policy
;
153 WS_ENDPOINT_ADDRESS addr
;
155 memset( &policy
, 0, sizeof(policy
) );
156 hr
= WsCreateServiceProxyFromTemplate( WS_CHANNEL_TYPE_REQUEST
, NULL
, 0, WS_HTTP_BINDING_TEMPLATE_TYPE
,
157 NULL
, 0, &policy
, sizeof(policy
), &proxy
, NULL
);
158 ok( hr
== S_OK
, "got %08x\n", hr
);
161 hr
= WsGetServiceProxyProperty( proxy
, WS_PROXY_PROPERTY_STATE
, &state
, sizeof(state
), NULL
);
162 ok( hr
== S_OK
, "got %08x\n", hr
);
163 ok( state
== WS_SERVICE_PROXY_STATE_CREATED
, "got %u\n", state
);
165 memset( &addr
, 0, sizeof(addr
) );
166 addr
.url
.length
= ARRAY_SIZE( L
"http://localhost/" ) - 1;
167 addr
.url
.chars
= (WCHAR
*)L
"http://localhost/";
168 hr
= WsOpenServiceProxy( proxy
, &addr
, NULL
, NULL
);
169 ok( hr
== S_OK
, "got %08x\n", hr
);
172 hr
= WsGetServiceProxyProperty( proxy
, WS_PROXY_PROPERTY_STATE
, &state
, sizeof(state
), NULL
);
173 ok( hr
== S_OK
, "got %08x\n", hr
);
174 ok( state
== WS_SERVICE_PROXY_STATE_OPEN
, "got %u\n", state
);
176 hr
= WsCloseServiceProxy( proxy
, NULL
, NULL
);
177 ok( hr
== S_OK
, "got %08x\n", hr
);
180 hr
= WsGetServiceProxyProperty( proxy
, WS_PROXY_PROPERTY_STATE
, &state
, sizeof(state
), NULL
);
181 ok( hr
== S_OK
, "got %08x\n", hr
);
182 ok( state
== WS_SERVICE_PROXY_STATE_CLOSED
, "got %u\n", state
);
184 WsFreeServiceProxy( proxy
);
187 static void test_WsResetServiceProxy(void)
190 WS_SERVICE_PROXY
*proxy
;
191 WS_ENDPOINT_ADDRESS addr
;
192 WS_SERVICE_PROXY_STATE state
;
194 hr
= WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST
, WS_HTTP_CHANNEL_BINDING
, NULL
, NULL
,
195 0, NULL
, 0, &proxy
, NULL
);
196 ok( hr
== S_OK
, "got %08x\n", hr
);
198 hr
= WsResetServiceProxy( proxy
, NULL
);
199 ok( hr
== S_OK
, "got %08x\n", hr
);
202 hr
= WsGetServiceProxyProperty( proxy
, WS_PROXY_PROPERTY_STATE
, &state
, sizeof(state
), NULL
);
203 ok( hr
== S_OK
, "got %08x\n", hr
);
204 ok( state
== WS_SERVICE_PROXY_STATE_CREATED
, "got %u\n", state
);
206 memset( &addr
, 0, sizeof(addr
) );
207 addr
.url
.length
= ARRAY_SIZE( L
"http://localhost/" ) - 1;
208 addr
.url
.chars
= (WCHAR
*)L
"http://localhost/";
209 hr
= WsOpenServiceProxy( proxy
, &addr
, NULL
, NULL
);
210 ok( hr
== S_OK
, "got %08x\n", hr
);
212 hr
= WsResetServiceProxy( proxy
, NULL
);
213 ok( hr
== WS_E_INVALID_OPERATION
, "got %08x\n", hr
);
215 hr
= WsCloseServiceProxy( proxy
, NULL
, NULL
);
216 ok( hr
== S_OK
, "got %08x\n", hr
);
218 hr
= WsResetServiceProxy( proxy
, NULL
);
219 ok( hr
== S_OK
, "got %08x\n", hr
);
222 hr
= WsGetServiceProxyProperty( proxy
, WS_PROXY_PROPERTY_STATE
, &state
, sizeof(state
), NULL
);
223 ok( hr
== S_OK
, "got %08x\n", hr
);
224 ok( state
== WS_SERVICE_PROXY_STATE_CREATED
, "got %u\n", state
);
226 WsFreeServiceProxy( proxy
);
229 static HRESULT
create_channel( int port
, WS_CHANNEL
**ret
)
231 WS_CHANNEL_PROPERTY prop
[2];
232 WS_ENVELOPE_VERSION env_version
= WS_ENVELOPE_VERSION_SOAP_1_1
;
233 WS_ADDRESSING_VERSION addr_version
= WS_ADDRESSING_VERSION_TRANSPORT
;
235 WS_ENDPOINT_ADDRESS addr
;
239 prop
[0].id
= WS_CHANNEL_PROPERTY_ENVELOPE_VERSION
;
240 prop
[0].value
= &env_version
;
241 prop
[0].valueSize
= sizeof(env_version
);
243 prop
[1].id
= WS_CHANNEL_PROPERTY_ADDRESSING_VERSION
;
244 prop
[1].value
= &addr_version
;
245 prop
[1].valueSize
= sizeof(addr_version
);
248 hr
= WsCreateChannel( WS_CHANNEL_TYPE_REQUEST
, WS_HTTP_CHANNEL_BINDING
, prop
, 2, NULL
, &channel
, NULL
);
249 if (hr
!= S_OK
) return hr
;
251 memset( &addr
, 0, sizeof(addr
) );
252 addr
.url
.length
= wsprintfW( buf
, L
"http://127.0.0.1:%u", port
);
253 addr
.url
.chars
= buf
;
254 hr
= WsOpenChannel( channel
, &addr
, NULL
, NULL
);
255 if (hr
== S_OK
) *ret
= channel
;
256 else WsFreeChannel( channel
);
260 static const char req_test1
[] =
261 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
262 "<req_test1 xmlns=\"ns\">-1</req_test1>"
263 "</s:Body></s:Envelope>";
265 static const char resp_test1
[] =
266 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
267 "<resp_test1 xmlns=\"ns\">-2</resp_test1>"
268 "</s:Body></s:Envelope>";
270 static void test_WsSendMessage( int port
, WS_XML_STRING
*action
)
272 WS_XML_STRING req
= {9, (BYTE
*)"req_test1"}, ns
= {2, (BYTE
*)"ns"};
275 WS_ELEMENT_DESCRIPTION body
;
276 WS_MESSAGE_DESCRIPTION desc
;
280 hr
= create_channel( port
, &channel
);
281 ok( hr
== S_OK
, "got %08x\n", hr
);
283 hr
= WsCreateMessageForChannel( channel
, NULL
, 0, &msg
, NULL
);
284 ok( hr
== S_OK
, "got %08x\n", hr
);
286 set_elem_desc( &body
, &req
, &ns
, WS_INT32_TYPE
, NULL
);
287 set_msg_desc( &desc
, action
, &body
);
288 hr
= WsSendMessage( NULL
, msg
, &desc
, WS_WRITE_REQUIRED_VALUE
, &val
, sizeof(val
), NULL
, NULL
);
289 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
291 hr
= WsSendMessage( channel
, NULL
, &desc
, WS_WRITE_REQUIRED_VALUE
, &val
, sizeof(val
), NULL
, NULL
);
292 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
294 hr
= WsSendMessage( channel
, msg
, NULL
, WS_WRITE_REQUIRED_VALUE
, &val
, sizeof(val
), NULL
, NULL
);
295 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
297 hr
= WsSendMessage( channel
, msg
, &desc
, WS_WRITE_REQUIRED_VALUE
, &val
, sizeof(val
), NULL
, NULL
);
298 ok( hr
== S_OK
, "got %08x\n", hr
);
300 hr
= WsCloseChannel( channel
, NULL
, NULL
);
301 ok( hr
== S_OK
, "got %08x\n", hr
);
303 WsFreeChannel( channel
);
304 WsFreeMessage( msg
);
307 static void test_WsReceiveMessage( int port
)
309 WS_XML_STRING req
= {9, (BYTE
*)"req_test1"}, resp
= {10, (BYTE
*)"resp_test1"}, ns
= {2, (BYTE
*)"ns"};
312 WS_ELEMENT_DESCRIPTION body
;
313 WS_MESSAGE_DESCRIPTION desc_req
, desc_resp
;
314 const WS_MESSAGE_DESCRIPTION
*desc
[1];
318 hr
= create_channel( port
, &channel
);
319 ok( hr
== S_OK
, "got %08x\n", hr
);
321 hr
= WsCreateMessageForChannel( channel
, NULL
, 0, &msg
, NULL
);
322 ok( hr
== S_OK
, "got %08x\n", hr
);
324 set_elem_desc( &body
, &req
, &ns
, WS_INT32_TYPE
, NULL
);
325 set_msg_desc( &desc_req
, &req
, &body
);
326 hr
= WsSendMessage( channel
, msg
, &desc_req
, WS_WRITE_REQUIRED_VALUE
, &val
, sizeof(val
), NULL
, NULL
);
327 ok( hr
== S_OK
, "got %08x\n", hr
);
328 WsFreeMessage( msg
);
330 hr
= WsCreateMessageForChannel( channel
, NULL
, 0, &msg
, NULL
);
331 ok( hr
== S_OK
, "got %08x\n", hr
);
333 set_elem_desc( &body
, &resp
, &ns
, WS_INT32_TYPE
, NULL
);
334 set_msg_desc( &desc_resp
, &resp
, &body
);
335 desc
[0] = &desc_resp
;
336 hr
= WsReceiveMessage( NULL
, msg
, desc
, 1, WS_RECEIVE_REQUIRED_MESSAGE
, WS_READ_REQUIRED_VALUE
,
337 NULL
, &val
, sizeof(val
), NULL
, NULL
, NULL
);
338 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
340 hr
= WsReceiveMessage( channel
, NULL
, 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
, msg
, NULL
, 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
, desc
, 1, WS_RECEIVE_REQUIRED_MESSAGE
, WS_READ_REQUIRED_VALUE
,
349 NULL
, &val
, sizeof(val
), NULL
, NULL
, NULL
);
350 ok( hr
== S_OK
, "got %08x\n", hr
);
351 ok( val
== -2, "got %d\n", val
);
353 hr
= WsCloseChannel( channel
, NULL
, NULL
);
354 ok( hr
== S_OK
, "got %08x\n", hr
);
356 WsFreeChannel( channel
);
357 WsFreeMessage( msg
);
360 static WS_HTTP_HEADER_MAPPING mapped_request_header
=
362 {19, (BYTE
*)"MappedRequestHeader"}
365 static WS_HTTP_HEADER_MAPPING
*request_header_mappings
[] =
367 &mapped_request_header
370 static WS_HTTP_HEADER_MAPPING mapped_response_header
=
372 {20, (BYTE
*)"MappedResponseHeader"}
375 static WS_HTTP_HEADER_MAPPING
*response_header_mappings
[] =
377 &mapped_response_header
380 static HRESULT
create_proxy( int port
, WS_SERVICE_PROXY
**ret
)
382 WS_ENVELOPE_VERSION env_version
;
383 WS_ADDRESSING_VERSION addr_version
;
384 WS_HTTP_MESSAGE_MAPPING mapping
;
385 WS_CHANNEL_PROPERTY prop
[3];
386 WS_ENDPOINT_ADDRESS addr
;
387 WS_SERVICE_PROXY
*proxy
;
391 env_version
= WS_ENVELOPE_VERSION_SOAP_1_1
;
392 prop
[0].id
= WS_CHANNEL_PROPERTY_ENVELOPE_VERSION
;
393 prop
[0].value
= &env_version
;
394 prop
[0].valueSize
= sizeof(env_version
);
396 addr_version
= WS_ADDRESSING_VERSION_TRANSPORT
;
397 prop
[1].id
= WS_CHANNEL_PROPERTY_ADDRESSING_VERSION
;
398 prop
[1].value
= &addr_version
;
399 prop
[1].valueSize
= sizeof(addr_version
);
401 mapping
.requestMappingOptions
= 0;
402 mapping
.responseMappingOptions
= 0;
403 mapping
.requestHeaderMappings
= request_header_mappings
;
404 mapping
.requestHeaderMappingCount
= ARRAY_SIZE(request_header_mappings
);
405 mapping
.responseHeaderMappings
= response_header_mappings
;
406 mapping
.responseHeaderMappingCount
= ARRAY_SIZE(response_header_mappings
);
408 prop
[2].id
= WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
;
409 prop
[2].value
= &mapping
;
410 prop
[2].valueSize
= sizeof(mapping
);
413 hr
= WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST
, WS_HTTP_CHANNEL_BINDING
, NULL
, NULL
,
414 0, prop
, ARRAY_SIZE( prop
), &proxy
, NULL
);
415 if (hr
!= S_OK
) return hr
;
417 memset( &addr
, 0, sizeof(addr
) );
418 addr
.url
.length
= wsprintfW( url
, L
"http://127.0.0.1:%u", port
);
419 addr
.url
.chars
= url
;
420 hr
= WsOpenServiceProxy( proxy
, &addr
, NULL
, NULL
);
421 if (hr
== S_OK
) *ret
= proxy
;
422 else WsFreeServiceProxy( proxy
);
426 static HRESULT
set_output( WS_XML_WRITER
*writer
)
428 WS_XML_WRITER_TEXT_ENCODING text
= {{ WS_XML_WRITER_ENCODING_TYPE_TEXT
}, WS_CHARSET_UTF8
};
429 WS_XML_WRITER_BUFFER_OUTPUT buf
= {{ WS_XML_WRITER_OUTPUT_TYPE_BUFFER
}};
430 return WsSetOutput( writer
, &text
.encoding
, &buf
.output
, NULL
, 0, NULL
);
433 static void check_output_headers( WS_MESSAGE
*msg
)
435 WS_XML_WRITER
*writer
;
440 hr
= WsCreateWriter( NULL
, 0, &writer
, NULL
);
441 ok( hr
== S_OK
, "got %08x\n", hr
);
443 hr
= set_output( writer
);
444 ok( hr
== S_OK
, "got %08x\n", hr
);
446 hr
= WsGetMessageProperty( msg
, WS_MESSAGE_PROPERTY_HEADER_BUFFER
, &buf
, sizeof(buf
), NULL
);
447 ok( hr
== S_OK
, "got %08x\n", hr
);
449 hr
= WsWriteXmlBuffer( writer
, buf
, NULL
);
450 ok( hr
== S_OK
, "got %08x\n", hr
);
452 memset( &bytes
, 0, sizeof(bytes
) );
453 hr
= WsGetWriterProperty( writer
, WS_XML_WRITER_PROPERTY_BYTES
, &bytes
, sizeof(bytes
), NULL
);
454 ok( hr
== S_OK
, "got %08x\n", hr
);
455 WsFreeWriter( writer
);
458 static const char req_test2
[] =
459 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
460 "<req_test2 xmlns=\"ns\"><val>1</val><str>test</str><str>test2</str></req_test2>"
461 "</s:Body></s:Envelope>";
463 static const char resp_test2
[] =
464 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
465 "<resp_test2 xmlns=\"ns\"><str>test</str><val>1</val><val>2</val></resp_test2>"
466 "</s:Body></s:Envelope>";
468 static HRESULT CALLBACK
send_callback( WS_MESSAGE
*msg
, WS_HEAP
*heap
, void *state
, WS_ERROR
*error
)
470 static const WS_XML_STRING header
= {19, (BYTE
*)"MappedRequestHeader"}, value
= {5, (BYTE
*)"value"};
473 hr
= WsAddMappedHeader( msg
, &header
, WS_XML_STRING_TYPE
, WS_WRITE_REQUIRED_VALUE
, &value
, sizeof(value
), NULL
);
474 ok( hr
== S_OK
, "got %08x\n", hr
);
475 check_output_headers( msg
);
479 static HRESULT CALLBACK
recv_callback( WS_MESSAGE
*msg
, WS_HEAP
*heap
, void *state
, WS_ERROR
*error
)
481 static const WS_XML_STRING header
= {20, (BYTE
*)"MappedResponseHeader"};
485 check_output_headers( msg
);
486 hr
= WsGetMappedHeader( msg
, &header
, WS_SINGLETON_HEADER
, 0, WS_WSZ_TYPE
, WS_READ_OPTIONAL_POINTER
, heap
,
487 &str
, sizeof(str
), NULL
);
488 ok( hr
== S_OK
, "got %08x\n", hr
);
489 ok( !wcscmp(str
, L
"value"), "wrong value %s\n", wine_dbgstr_w(str
) );
493 static void test_WsCall( int port
)
495 WS_XML_STRING str
= {3, (BYTE
*)"str"};
496 WS_XML_STRING req
= {3, (BYTE
*)"req"};
497 WS_XML_STRING resp
= {4, (BYTE
*)"resp"};
498 WS_XML_STRING req_elem
= {9, (BYTE
*)"req_test2"};
499 WS_XML_STRING resp_elem
= {10, (BYTE
*)"resp_test2"};
500 WS_XML_STRING req_action
= {9, (BYTE
*)"req_test2"};
501 WS_XML_STRING resp_action
= {10, (BYTE
*)"resp_test2"};
502 WS_XML_STRING val
= {3, (BYTE
*)"val"};
503 WS_XML_STRING ns
= {2, (BYTE
*)"ns"};
505 WS_SERVICE_PROXY
*proxy
;
506 WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_send
;
507 WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_recv
;
508 WS_CALL_PROPERTY prop
[2];
509 WS_OPERATION_DESCRIPTION op
;
510 WS_MESSAGE_DESCRIPTION input_msg
, output_msg
;
511 WS_ELEMENT_DESCRIPTION input_elem
, output_elem
;
512 WS_STRUCT_DESCRIPTION input_struct
, output_struct
;
513 WS_FIELD_DESCRIPTION f
, f2
, f3
, f4
, *fields
[2], *fields2
[2];
514 WS_PARAMETER_DESCRIPTION param
[6];
520 const WCHAR
*str_array
[2];
534 hr
= WsCreateHeap( 1 << 16, 0, NULL
, 0, &heap
, NULL
);
535 ok( hr
== S_OK
, "got %08x\n", hr
);
537 hr
= WsCall( NULL
, NULL
, NULL
, NULL
, NULL
, 0, NULL
, NULL
);
538 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
540 hr
= create_proxy( port
, &proxy
);
541 ok( hr
== S_OK
, "got %08x\n", hr
);
543 hr
= WsCall( proxy
, NULL
, NULL
, NULL
, NULL
, 0, NULL
, NULL
);
544 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
546 set_field_desc( &f
, WS_ELEMENT_FIELD_MAPPING
, &val
, &ns
, WS_INT32_TYPE
, NULL
, 0, 0, 0, NULL
, NULL
);
547 set_field_desc( &f4
, WS_REPEATING_ELEMENT_FIELD_MAPPING
, NULL
, NULL
, WS_WSZ_TYPE
, NULL
,
548 FIELD_OFFSET(struct input
, str
), 0, FIELD_OFFSET(struct input
, count
), &str
, &ns
);
552 set_struct_desc( &input_struct
, sizeof(struct input
), TYPE_ALIGNMENT(struct input
), fields
, 2, &req
, &ns
, 0 );
553 set_elem_desc( &input_elem
, &req_elem
, &ns
, WS_STRUCT_TYPE
, &input_struct
);
554 set_msg_desc( &input_msg
, &req_action
, &input_elem
);
556 set_field_desc( &f2
, WS_ELEMENT_FIELD_MAPPING
, &str
, &ns
, WS_WSZ_TYPE
, NULL
, FIELD_OFFSET(struct output
, str
),
558 set_field_desc( &f3
, WS_REPEATING_ELEMENT_FIELD_MAPPING
, NULL
, NULL
, WS_INT32_TYPE
, NULL
,
559 FIELD_OFFSET(struct output
, val
), 0, FIELD_OFFSET(struct output
, count
), &val
, &ns
);
563 set_struct_desc( &output_struct
, sizeof(struct output
), TYPE_ALIGNMENT(struct output
), fields2
, 2, &resp
, &ns
, 0 );
564 set_elem_desc( &output_elem
, &resp_elem
, &ns
, WS_STRUCT_TYPE
, &output_struct
);
565 set_msg_desc( &output_msg
, &resp_action
, &output_elem
);
567 set_param_desc( ¶m
[0], WS_PARAMETER_TYPE_NORMAL
, 0, 0xffff );
568 set_param_desc( ¶m
[1], WS_PARAMETER_TYPE_ARRAY
, 1, 0xffff );
569 set_param_desc( ¶m
[2], WS_PARAMETER_TYPE_ARRAY_COUNT
, 1, 0xffff );
570 set_param_desc( ¶m
[3], WS_PARAMETER_TYPE_NORMAL
, 0xffff, 0 );
571 set_param_desc( ¶m
[4], WS_PARAMETER_TYPE_ARRAY
, 0xffff, 1 );
572 set_param_desc( ¶m
[5], WS_PARAMETER_TYPE_ARRAY_COUNT
, 0xffff, 1 );
574 set_op_desc( &op
, &input_msg
, &output_msg
, 6, param
);
575 hr
= WsCall( proxy
, &op
, NULL
, NULL
, NULL
, 0, NULL
, NULL
);
576 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
579 str_array
[0] = L
"test";
580 str_array
[1] = L
"test2";
593 count_ptr
= &out
.count
;
597 args
[5] = &count_ptr
;
599 ctx_send
.callback
= send_callback
;
600 ctx_send
.state
= NULL
;
602 prop
[0].id
= WS_CALL_PROPERTY_SEND_MESSAGE_CONTEXT
;
603 prop
[0].value
= &ctx_send
;
604 prop
[0].valueSize
= sizeof(ctx_send
);
606 ctx_recv
.callback
= recv_callback
;
607 ctx_recv
.state
= NULL
;
609 prop
[1].id
= WS_CALL_PROPERTY_RECEIVE_MESSAGE_CONTEXT
;
610 prop
[1].value
= &ctx_recv
;
611 prop
[1].valueSize
= sizeof(ctx_recv
);
613 hr
= WsCall( proxy
, &op
, args
, heap
, prop
, ARRAY_SIZE(prop
), NULL
, NULL
);
614 ok( hr
== S_OK
, "got %08x\n", hr
);
615 ok( !wcscmp( out
.str
, L
"test" ), "wrong data\n" );
616 ok( out
.count
== 2, "got %u\n", out
.count
);
617 ok( out
.val
[0] == 1, "got %u\n", out
.val
[0] );
618 ok( out
.val
[1] == 2, "got %u\n", out
.val
[1] );
620 hr
= WsCloseServiceProxy( proxy
, NULL
, NULL
);
621 ok( hr
== S_OK
, "got %08x\n", hr
);
623 WsFreeServiceProxy( proxy
);
627 static const char req_test3
[] =
628 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>"
629 "<req_test3 xmlns=\"ns\"><val>1</val></req_test3>"
630 "</s:Body></s:Envelope>";
632 static const char resp_test3
[] =
633 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body/></s:Envelope>";
635 static void test_empty_response( int port
)
637 WS_XML_STRING req
= {3, (BYTE
*)"req"};
638 WS_XML_STRING resp
= {4, (BYTE
*)"resp"};
639 WS_XML_STRING req_action
= {9, (BYTE
*)"req_test3"};
640 WS_XML_STRING resp_action
= {10, (BYTE
*)"resp_test3"};
641 WS_XML_STRING req_elem
= {9, (BYTE
*)"req_test3"};
642 WS_XML_STRING resp_elem
= {10, (BYTE
*)"resp_test3"};
643 WS_XML_STRING ns
= {2, (BYTE
*)"ns"};
644 WS_XML_STRING ns2
= {0, (BYTE
*)""};
645 WS_XML_STRING val
= {3, (BYTE
*)"val"};
647 WS_SERVICE_PROXY
*proxy
;
648 WS_FIELD_DESCRIPTION f
, *fields
[1];
649 WS_STRUCT_DESCRIPTION input_struct
, output_struct
;
650 WS_ELEMENT_DESCRIPTION input_elem
, output_elem
;
651 WS_MESSAGE_DESCRIPTION input_msg
, output_msg
;
652 WS_PARAMETER_DESCRIPTION param
[1];
653 WS_OPERATION_DESCRIPTION op
;
661 hr
= WsCreateHeap( 1 << 16, 0, NULL
, 0, &heap
, NULL
);
662 ok( hr
== S_OK
, "got %08x\n", hr
);
664 hr
= create_proxy( port
, &proxy
);
665 ok( hr
== S_OK
, "got %08x\n", hr
);
667 set_field_desc( &f
, WS_ELEMENT_FIELD_MAPPING
, &val
, &ns
, WS_INT32_TYPE
, NULL
, 0, 0, 0, NULL
, NULL
);
670 set_struct_desc( &input_struct
, sizeof(struct input
), TYPE_ALIGNMENT(struct input
), fields
, 1, &req
, &ns
, 0 );
671 set_elem_desc( &input_elem
, &req_elem
, &ns
, WS_STRUCT_TYPE
, &input_struct
);
672 set_msg_desc( &input_msg
, &req_action
, &input_elem
);
674 set_struct_desc( &output_struct
, 0, 1, NULL
, 0, &resp
, &ns2
, 0x6 );
675 set_elem_desc( &output_elem
, &resp_elem
, &ns
, WS_STRUCT_TYPE
, NULL
);
676 set_msg_desc( &output_msg
, &resp_action
, &output_elem
);
678 set_param_desc( param
, WS_PARAMETER_TYPE_NORMAL
, 0, 0xffff );
679 set_op_desc( &op
, &input_msg
, &output_msg
, 1, param
);
683 hr
= WsCall( proxy
, &op
, args
, heap
, NULL
, 0, NULL
, NULL
);
684 ok( hr
== E_INVALIDARG
, "got %08x\n", hr
);
686 set_elem_desc( &output_elem
, &resp_elem
, &ns
, WS_STRUCT_TYPE
, &output_struct
);
687 hr
= WsCall( proxy
, &op
, args
, heap
, NULL
, 0, NULL
, NULL
);
688 ok( hr
== WS_E_INVALID_FORMAT
, "got %08x\n", hr
);
690 hr
= WsCloseServiceProxy( proxy
, NULL
, NULL
);
691 ok( hr
== S_OK
, "got %08x\n", hr
);
693 WsFreeServiceProxy( proxy
);
697 static const char status_200
[] = "HTTP/1.1 200 OK\r\n";
701 const char *req_action
;
702 const char *req_data
;
703 unsigned int req_len
;
704 const char *resp_status
;
705 const char *resp_data
;
706 unsigned int resp_len
;
710 { "req_test1", req_test1
, sizeof(req_test1
)-1, status_200
, resp_test1
, sizeof(resp_test1
)-1 },
711 { "req_test2", req_test2
, sizeof(req_test2
)-1, status_200
, resp_test2
, sizeof(resp_test2
)-1 },
712 { "req_test3", req_test3
, sizeof(req_test3
)-1, status_200
, resp_test3
, sizeof(resp_test3
)-1 },
715 static void send_response( int c
, const char *status
, const char *data
, unsigned int len
)
717 static const char headers
[] =
718 "Content-Type: text/xml; charset=utf-8\r\nConnection: close\r\nMappedResponseHeader: value\r\n";
719 static const char fmt
[] =
720 "Content-Length: %u\r\n\r\n";
723 send( c
, status
, strlen(status
), 0 );
724 send( c
, headers
, sizeof(headers
) - 1, 0 );
725 sprintf( buf
, fmt
, len
);
726 send( c
, buf
, strlen(buf
), 0 );
727 send( c
, data
, len
, 0 );
736 static DWORD CALLBACK
server_proc( void *arg
)
738 struct server_info
*info
= arg
;
739 int len
, res
, c
= -1, i
, j
, on
= 1, quit
;
742 struct sockaddr_in sa
;
746 WSAStartup( MAKEWORD(1,1), &wsa
);
747 if ((s
= socket( AF_INET
, SOCK_STREAM
, 0 )) == INVALID_SOCKET
) return 1;
748 setsockopt( s
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&on
, sizeof(on
) );
750 memset( &sa
, 0, sizeof(sa
) );
751 sa
.sin_family
= AF_INET
;
752 sa
.sin_port
= htons( info
->port
);
753 sa
.sin_addr
.S_un
.S_addr
= inet_addr( "127.0.0.1" );
754 if (bind( s
, (struct sockaddr
*)&sa
, sizeof(sa
) ) < 0) return 1;
757 SetEvent( info
->event
);
760 c
= accept( s
, NULL
, NULL
);
763 for (i
= 0; i
< sizeof(buf
) - 1; i
++)
765 if ((res
= recv( c
, &buf
[i
], 1, 0 )) != 1) break;
767 if (buf
[i
- 2] == '\n' && buf
[i
] == '\n' && buf
[i
- 3] == '\r' && buf
[i
- 1] == '\r')
771 quit
= strstr( buf
, "SOAPAction: \"quit\"" ) != NULL
;
774 if ((p
= strstr( buf
, "Content-Length: " )))
776 p
+= strlen( "Content-Length: " );
777 while (isdigit( *p
))
783 for (i
= 0; i
< len
; i
++)
785 if ((res
= recv( c
, &buf
[i
], 1, 0 )) != 1) break;
789 for (j
= 0; j
< ARRAY_SIZE( tests
); j
++)
791 if (strstr( buf
, tests
[j
].req_action
))
793 if (tests
[j
].req_data
)
795 int data_len
= strlen( buf
);
796 ok( tests
[j
].req_len
== data_len
, "%u: got data length %u expected %u\n",
797 j
, data_len
, tests
[j
].req_len
);
798 if (tests
[j
].req_len
== data_len
)
799 ok( !memcmp( tests
[j
].req_data
, buf
, tests
[j
].req_len
),
800 "%u: got data '%s' expected '%s'\n", j
, buf
, tests
[j
].req_data
);
802 send_response( c
, tests
[j
].resp_status
, tests
[j
].resp_data
, tests
[j
].resp_len
);
818 WS_XML_STRING test1
= {9, (BYTE
*)"req_test1"};
819 WS_XML_STRING quit
= {4, (BYTE
*)"quit"};
820 struct server_info info
;
824 test_WsCreateServiceProxy();
825 test_WsCreateServiceProxyFromTemplate();
826 test_WsOpenServiceProxy();
827 test_WsResetServiceProxy();
830 info
.event
= CreateEventW( NULL
, 0, 0, NULL
);
831 thread
= CreateThread( NULL
, 0, server_proc
, &info
, 0, NULL
);
832 ok( thread
!= NULL
, "failed to create server thread %u\n", GetLastError() );
834 ret
= WaitForSingleObject( info
.event
, 3000 );
835 ok(ret
== WAIT_OBJECT_0
, "failed to start test server %u\n", GetLastError());
836 if (ret
!= WAIT_OBJECT_0
)
842 test_WsSendMessage( info
.port
, &test1
);
843 test_WsReceiveMessage( info
.port
);
844 test_WsCall( info
.port
);
845 test_empty_response( info
.port
);
847 test_WsSendMessage( info
.port
, &quit
);
848 WaitForSingleObject( thread
, 3000 );