5
WS-Addressing plugin for stand-alone services.
7
gSOAP XML Web services tools
8
Copyright (C) 2000-2007, Robert van Engelen, Genivia Inc., All Rights Reserved.
9
This part of the software is released under one of the following licenses:
10
GPL, the gSOAP public license, or Genivia's license for commercial use.
11
--------------------------------------------------------------------------------
14
The contents of this file are subject to the gSOAP Public License Version 1.3
15
(the "License"); you may not use this file except in compliance with the
16
License. You may obtain a copy of the License at
17
http://www.cs.fsu.edu/~engelen/soaplicense.html
18
Software distributed under the License is distributed on an "AS IS" basis,
19
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20
for the specific language governing rights and limitations under the License.
22
The Initial Developer of the Original Code is Robert A. van Engelen.
23
Copyright (C) 2000-2007, Robert van Engelen, Genivia Inc., All Rights Reserved.
24
--------------------------------------------------------------------------------
27
This program is free software; you can redistribute it and/or modify it under
28
the terms of the GNU General Public License as published by the Free Software
29
Foundation; either version 2 of the License, or (at your option) any later
32
This program is distributed in the hope that it will be useful, but WITHOUT ANY
33
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
34
PARTICULAR PURPOSE. See the GNU General Public License for more details.
36
You should have received a copy of the GNU General Public License along with
37
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
38
Place, Suite 330, Boston, MA 02111-1307 USA
40
Author contact information:
41
engelen@genivia.com / engelen@acm.org
42
--------------------------------------------------------------------------------
43
A commercial use license is available from Genivia, Inc., contact@genivia.com
44
--------------------------------------------------------------------------------
51
- @ref wsa documents the wsa plugin for WS-Addressing (2003/2004/2005
58
@page wsa The wsa plugin for stand-alone services
60
@section wsa_1 WS-Addressing Setup
62
The material in this section relates to the WS-Addressing specification.
64
To use the wsa plugin:
65
-# Run wsdl2h -t typemap.dat on a WSDL of a service that requires WS-Addressing
66
headers. The typemap.dat file included in the gSOAP package is used to
67
recognize and translate Addressing header blocks.
68
-# Run soapcpp2 -a on the header file produced by wsdl2h. To enable
69
addressing-based service operation selection, you MUST use soapcpp2 option
70
-a. This allows the service to dispatch methods based on the WS-Addressing
71
action information header value (assuming the wsa plugin is registered).
72
-# (Re-)compile stdsoap2.c/pp, dom.c/pp, wsaapi.c and the generated
74
-# Use the wsa plugin API functions described below.
76
An example wsa client/server application can be found in samples/wsa.
78
To use WS-Addressing, the gSOAP header file for a service should declare a SOAP
79
Header with the required WS-Addressing information headers. The header file is
80
automatically generated by wsdl2h for a set of WSDLs. The gSOAP header file is
81
further processed by soapcpp2 to generate the binding code.
83
The SOAP Header structure contains the WS-Addressing information headers
84
extracted from the WSDL and the WS-Addressing specification. For example:
87
#import "wsa.h" // or wsa3.h (2003/03), wsa4.h (2004/03), wsa5.h (2005/03)
89
struct SOAP_ENV__Header
91
_wsa__MessageID wsa__MessageID 0;
92
_wsa__RelatesTo *wsa__RelatesTo 0;
93
_wsa__From *wsa__From 0;
94
mustUnderstand _wsa__ReplyTo *wsa__ReplyTo 0;
95
mustUnderstand _wsa__FaultTo *wsa__FaultTo 0;
96
mustUnderstand _wsa__To wsa__To 0;
97
mustUnderstand _wsa__Action wsa__Action 0;
100
Note: when importing wsa3.h, wsa4.h, or wsa5.h use type and member names
101
prefixed with wsa3, wsa4, and wsa5, respectively. The mustUnderstand qualifier
102
ensures that the information headers must be understood by a receiving SOAP
105
The SOAP Header struct is automatically generated by wsdl2h from a WSDL. But it
106
must be manually defined when creating new services from gSOAP header files.
107
In either case, the gSOAP header file is processed with soapcpp2 to generate
108
the client-side and/or server-side binding code.
110
Note that the wsa.h header file located in the import directory of the gSOAP
111
package declares the WS-Addressing information header elements and types. The
112
soap12.h header file enables SOAP 1.2 messaging.
114
For developers: the WS-Addressing header blocks in wsa.h were generated from
115
the WS-Addressing schema with the wsdl2h tool and WS/WS-typemap.dat as follows:
118
$ wsdl2h -cegy -o wsa.h -t WS/WS-typemap.dat WS/WS-Addressing.xsd
120
Refer to wsa.h for more details.
122
@section wsa_2 Client-side Usage
124
@subsection wsa_2_1 Constructing WS-Addressing Information Headers
126
To associate WS-Addressing information headers with service operations, the
127
SOAP Header struct must have been defined and for each service operation that
128
uses WS-Addressing method-header-part directives should be used in the gSOAP
129
header file of the service as follows:
133
struct SOAP_ENV__Header { ... };
135
//gsoap ns service method-header-part: example wsa__MessageID
136
//gsoap ns service method-header-part: example wsa__RelatesTo
137
//gsoap ns service method-header-part: example wsa__From
138
//gsoap ns service method-header-part: example wsa__ReplyTo
139
//gsoap ns service method-header-part: example wsa__FaultTo
140
//gsoap ns service method-header-part: example wsa__To
141
//gsoap ns service method-header-part: example wsa__Action
142
//gsoap ns service method-action: example urn:example/examplePort/example
143
int ns__example(char *in, struct ns__exampleResponse *out);
146
In the client-side code, the WS-Addressing information headers are set with
147
soap_wsa_request() by passing an optional message UUID string, a mandatory
148
destination address URI string, and a mandatory request action URI string. The
149
wsa plugin should be registered with the currenct soap struct context. An
150
optional source address information header can be added with
151
soap_wsa_add_From() (must be invoked after the soap_wsa_request call).
155
soap_register_plugin(soap, soap_wsa);
157
soap_wsa_request(soap, RequestMessageID, ToAddress, RequestAction);
158
soap_wsa_add_From(soap, FromAddress); // optional: add a 'From' address
160
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
161
soap_print_fault(soap, stderr); // an error occurred
163
// process the response
166
@subsection wsa_2_2 Information Headers for Relaying Server Responses
168
To relay the response to another destination, the WS-Addressing ReplyTo
169
information header is added with soap_wsa_add_ReplyTo() by passing a reply
170
address URI string. The service returns HTTP 202 ACCEPTED to the client when
171
the response message relay was successful.
175
soap_register_plugin(soap, soap_wsa);
177
soap_wsa_request(soap, RequestMessageID, ToAddress, RequestAction);
178
soap_wsa_add_From(soap, FromAddress); // optional: add a 'From' address
179
soap_wsa_add_ReplyTo(soap, ReplyToAddress);
181
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
183
if (soap->error == 202) // HTTP ACCEPTED
184
printf("Request was accepted and results were forwarded\n");
186
soap_print_fault(soap, stderr); // an error occurred
189
// error: for some reason the response was not relayed
192
Note: the response message will be relayed when the From address is absent or
193
different than the ReplyTo address
195
@subsection wsa_2_3 Information Headers for Relaying Server Faults
197
To relay a server fault message to another destination, the WS-Addressing
198
FaultTo information header is added with soap_wsa_add_FaultTo() by passing a
199
relay address URI string. The service returns HTTP 202 ACCEPTED to the client
200
when the fault was relayed.
204
soap_register_plugin(soap, soap_wsa);
206
soap_wsa_request(soap, RequestMessageID, ToAddress, RequestAction);
207
soap_wsa_add_From(soap, FromAddress); // optional: add a 'From' address
208
soap_wsa_add_FaultTo(soap, FaultToAddress);
210
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
212
if (soap->error == 202) // HTTP ACCEPTED
213
printf("A fault occurred and the fault details were forwarded\n");
215
soap_print_fault(soap, stderr); // a connection error occurred
221
Note that the call can still return a fault, such as a connection error when
222
the service is not responding. In addition to the fault relay, the responses
223
can be relayed with soap_wsa_add_ReplyTo().
225
@subsection wsa_2_4 Error Handling
227
SOAP and HTTP errors set the soap->error attribute, as shown in this example:
229
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
231
if (soap->error == 202) // HTTP ACCEPTED
232
printf("A fault occurred and the fault details were forwarded\n");
234
soap_print_fault(soap, stderr); // a connection error occurred
239
When a WS-Addressing error occurred, the a wsa error code is stored in the SOAP
240
Fault Subcode field. This information can be retrieved with:
242
wsa__FaultSubcodeValues fault;
243
if (soap_wsa_check_fault(soap, &fault))
247
case wsa__InvalidMessageInformationHeader: ...
248
case wsa__MessageInformationHeaderRequired: ...
249
case wsa__DestinationUreachable: ...
250
case wsa__ActionNotSupported: ...
251
case wsa__EndpointUnavailable: ...
255
When using wsa5.h, please refer to the standards and fault codes for this
256
implementation. For the wsa5.h 2005/03 standard, several faults have an
257
additional parameter (SOAP Fault detail):
259
wsa5__FaultCodesType fault;
261
if (soap_wsa_check_fault(soap, &fault, &info))
265
case wsa5__InvalidAddressingHeader:
267
printf("The invalid addressing header element is %s\n", info);
273
@section wsa_3 Server-side Usage
275
The wsa plugin should be registered with:
277
soap_register_plugin(soap, soap_wsa);
280
Once the plugin is registered, the soap_bind(), soap_accept(), and soap_serve() functions can be called to process requests.
282
Important: to dispatch service operations based on the WS-Addressing wsa:Action
283
information header, use soapcpp2 option -a. The generates a new dispatcher (in
284
soapServer.c) based on the action value.
286
A service operation implementation should use soap_wsa_check() to verify the
287
validity of the WS-Addressing information headers in the SOAP request message.
288
To allow response message to be automatically relayed based on the ReplyTo
289
information header, the service operation should return soap_wsa_reply() with
290
an optional message UUID string and a mandatory response action string.
294
int ns__example(struct soap *soap, char *in, struct ns__exampleResponse *out)
295
{ if (soap_wsa_check(soap))
298
return soap_wsa_reply(soap, ResponseMessageID, ResponseAction);
302
To return a SOAP fault that is automatically relayed to a fault service based
303
on the FaultTo information header, the soap_wsa_sender_fault(),
304
soap_wsa_receiver_fault(), soap_wsa_sender_fault_subcode(), and
305
soap_wsa_receiver_fault_subcode() functions should be used instead of the
306
soap_sender_fault(), soap_receiver_fault(), soap_sender_fault_subcode(), and
307
soap_receiver_fault_subcode(), respectively.
311
int ns__example(struct soap *soap, char *in, struct ns__exampleResponse *out)
312
{ if (soap_wsa_check(soap))
315
// ... an error occurred, need to return fault possibly to fault service:
316
return soap_wsa_sender_fault(soap, "Exception in service operation", NULL);
317
// ... normal execution continues
318
return soap_wsa_reply(soap, ResponseMessageID, ResponseAction);
322
@section wsa_4 Implementing a Server for Handling ReplyTo Response Messages
324
To implement a separate server for handling relayed SOAP response messages
325
based on the ReplyTo information header in the request message, the gSOAP
326
header file should include a one-way service operation for the response
329
For example, suppose a service operation returns an exampleResponse message. We
330
declare the one-way exampleResponse operation as follows:
334
struct SOAP_ENV__Header { ... };
336
//gsoap ns service method-header-part: exampleResult wsa__MessageID
337
//gsoap ns service method-header-part: exampleResult wsa__RelatesTo
338
//gsoap ns service method-header-part: exampleResult wsa__From
339
//gsoap ns service method-header-part: exampleResult wsa__ReplyTo
340
//gsoap ns service method-header-part: exampleResult wsa__FaultTo
341
//gsoap ns service method-header-part: exampleResult wsa__To
342
//gsoap ns service method-header-part: exampleResult wsa__Action
343
//gsoap ns service method-action: exampleResult urn:example/examplePort/exampleResponse
344
int ns__exampleResponse(char *out, void);
347
Note that the action information is important, because it is used by the
348
service dispatcher (assuming soapcpp2 option -a is used).
350
The implementation in the server code uses soap_wsa_check() to check the
351
presense and validity of the WS-Addressing information header in the message.
352
The soap_send_empty_response() function should be used to return an
353
acknowledgment HTTP header with HTTP 202 ACCEPTED to the sender:
355
int ns__exampleResponse(struct soap *soap, char *out)
356
{ if (soap_wsa_check(soap))
357
return soap_send_empty_response(soap, 500); // HTTP 500 Internal Server Error
359
return soap_send_empty_response(soap, SOAP_OK); // HTTP 202 ACCEPTED
363
@section wsa_5 Implementing a Server for Handling FaultTo Fault Messages
365
To implement a separate server for handling relayed SOAP fault messages based
366
on the FaultTo information header in the request message, the gSOAP header file
367
for soapcpp2 should include a SOAP fault service operation. This operation
368
accepts fault messages that are relayed by other services.
370
Basically, we use a trick to generate the SOAP-ENV:Fault struct via a one-way
371
service operation. This allows us both to implement a one-way service operation
372
that accepts faults and to automatically generate the fault struct for fault
373
data storage and manipulation.
375
The fault operation in the header file should be declared as follows (for the
378
//gsoap SOAP_ENV service method-action: Fault http://schemas.xmlsoap.org/ws/2004/08/addressing/fault
380
( _QName faultcode, // SOAP 1.1
381
char *faultstring, // SOAP 1.1
382
char *faultactor, // SOAP 1.1
383
struct SOAP_ENV__Detail *detail, // SOAP 1.1
384
struct SOAP_ENV__Code *SOAP_ENV__Code, // SOAP 1.2
385
struct SOAP_ENV__Reason *SOAP_ENV__Reason, // SOAP 1.2
386
char *SOAP_ENV__Node, // SOAP 1.2
387
char *SOAP_ENV__Role, // SOAP 1.2
388
struct SOAP_ENV__Detail *SOAP_ENV__Detail, // SOAP 1.2
393
Because each service operation has a struct to hold its input parameters, we
394
automatically generate the (original) SOAP_ENV__Fault struct on the fly!
396
Note: it is important to associate the wsa fault action with this operation as
399
The implementation of the service operation in the server code is:
401
int SOAP_ENV__Fault(struct soap *soap, char *faultcode, char *faultstring, char *faultactor, struct SOAP_ENV__Detail *detail, struct SOAP_ENV__Code *SOAP_ENV__Code, struct SOAP_ENV__Reason *SOAP_ENV__Reason, char *SOAP_ENV__Node, char *SOAP_ENV__Role, struct SOAP_ENV__Detail *SOAP_ENV__Detail)
403
... = faultcode; // SOAP 1.1 fault code string (QName)
404
... = faultstring; // SOAP 1.1 fault string
405
... = faultactor; // SOAP 1.1 fault actor string
406
... = detail; // SOAP 1.1 fault detail struct
407
... = SOAP_ENV__Code; // SOAP 1.2 fault code struct
408
... = SOAP_ENV__Reason; // SOAP 1.2 reason struct
409
... = SOAP_ENV__Node; // SOAP 1.2 node string
410
... = SOAP_ENV__Role; // SOAP 1.2 role string
411
... = SOAP_ENV__Detail; // SOAP 1.2 detail struct
416
Note that SOAP 1.1 or SOAP 1.2 parameters are set based on the 1.1/1.2
417
messaging requirements.
423
/** Plugin identification for plugin registry */
424
const char soap_wsa_id[13] = SOAP_WSA_ID;
426
#if defined(SOAP_WSA_2003)
427
/** Anonymous Reply/To endpoint address */
428
const char *soap_wsa_anonymousURI = "http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous";
429
/** Specifies no Reply endpoint address (no reply) */
430
const char *soap_wsa_noneURI = "addressing/none not supported";
431
const char *soap_wsa_faultAction = "http://schemas.xmlsoap.org/ws/2003/03/addressing/fault";
432
#elif defined(SOAP_WSA_2004)
433
/** Anonymous Reply/To endpoint address */
434
const char *soap_wsa_anonymousURI = "http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous";
435
/** Specifies no Reply endpoint address (no reply) */
436
const char *soap_wsa_noneURI = "addressing/none not supported";
437
const char *soap_wsa_faultAction = "http://schemas.xmlsoap.org/ws/2004/03/addressing/fault";
438
#elif defined(SOAP_WSA_2005)
439
/** Anonymous Reply/To endpoint address */
440
const char *soap_wsa_anonymousURI = "http://www.w3.org/2005/08/addressing/anonymous";
441
/** Specifies no Reply endpoint address (no reply) */
442
const char *soap_wsa_noneURI = "http://www.w3.org/2005/08/addressing/none";
443
const char *soap_wsa_faultAction = "http://www.w3.org/2005/08/addressing/soap/fault";
445
/** Anonymous Reply/To endpoint address */
446
const char *soap_wsa_anonymousURI = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
447
/** Specifies no Reply endpoint address (no reply) */
448
const char *soap_wsa_noneURI = "addressing/none not supported";
449
const char *soap_wsa_faultAction = "http://schemas.xmlsoap.org/ws/2004/08/addressing/fault";
452
/******************************************************************************\
456
\******************************************************************************/
458
static int soap_wsa_fault_subcode(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail);
460
static int soap_wsa_init(struct soap *soap, struct soap_wsa_data *data);
461
static void soap_wsa_delete(struct soap *soap, struct soap_plugin *p);
463
static int soap_wsa_header(struct soap *soap);
464
static void soap_wsa_set_error(struct soap *soap, const char **c, const char **s);
465
static int soap_wsa_response(struct soap *soap, int status, size_t count);
467
static int soap_wsa_alloc_header(struct soap *soap);
469
/******************************************************************************\
471
* Client-side Request
473
\******************************************************************************/
476
@fn int soap_wsa_request(struct soap *soap, const char *id, const char *to, const char *action)
477
@brief Sets the WS-Addressing information header for the next request message
478
with optional MessageID, To (required), and Action (required).
481
@param[in] id is the message ID (optional)
482
@param[in] to is the target endpoint (required)
483
@param[in] action is the target action (required)
486
Note: use soap_wsa_add_From, soap_wsa_add_ReplyTo, soap_wsa_add_FaultTo to add
487
other addressing fields following this function call.
490
soap_wsa_request(struct soap *soap, const char *id, const char *to, const char *action)
491
{ soap_wsa_alloc_header(soap);
492
soap_default_SOAP_ENV__Header(soap, soap->header);
493
soap->header->SOAP_WSA(MessageID) = soap_strdup(soap, id);
494
soap->header->SOAP_WSA(To) = soap_strdup(soap, to);
495
soap->header->SOAP_WSA(Action) = soap_strdup(soap, action);
500
@fn int soap_wsa_add_From(struct soap *soap, const char *from)
501
@brief Sets WS-Addressing From header for request message.
503
@param[in] from endpoint URI
504
@return SOAP_OK or SOAP_ERR
506
Use soap_wsa_request to populate the WS-Addressing header first.
509
soap_wsa_add_From(struct soap *soap, const char *from)
512
soap->header->SOAP_WSA(From) = (SOAP_WSA_(,From)*)soap_malloc(soap, sizeof(SOAP_WSA_(,From)));
513
SOAP_WSA_(soap_default,EndpointReferenceType)(soap, soap->header->SOAP_WSA(From));
514
soap->header->SOAP_WSA(From)->Address = soap_strdup(soap, from);
519
@fn int soap_wsa_add_NoReply(struct soap *soap)
520
@brief Sets WS-Addressing ReplyTo header to 'none' (no reply)
522
@return SOAP_OK or SOAP_ERR
524
Note: WS-Addressing 2005/08 standard.
526
Use soap_wsa_request to populate the WS-Addressing header.
529
soap_wsa_add_NoReply(struct soap *soap)
530
{ return soap_wsa_add_ReplyTo(soap, soap_wsa_noneURI);
534
@fn int soap_wsa_add_ReplyTo(struct soap *soap, const char *replyTo)
535
@brief Sets WS-Addressing ReplyTo header for request message.
537
@param[in] replyTo endpoint URI
538
@return SOAP_OK or SOAP_ERR
540
Use soap_wsa_request to populate the WS-Addressing header.
543
soap_wsa_add_ReplyTo(struct soap *soap, const char *replyTo)
547
{ soap->header->SOAP_WSA(ReplyTo) = (SOAP_WSA_(,ReplyTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,ReplyTo)));
548
SOAP_WSA_(soap_default,EndpointReferenceType)(soap, soap->header->SOAP_WSA(ReplyTo));
549
soap->header->SOAP_WSA(ReplyTo)->Address = soap_strdup(soap, replyTo);
555
@fn int soap_wsa_add_FaultTo(struct soap *soap, const char *faultTo)
556
@brief Sets WS-Addressing FaultTo header for request message.
558
@param[in] faultTo endpoint URI
559
@return SOAP_OK or SOAP_ERR
561
Use soap_wsa_request to populate the WS-Addressing header first.
564
soap_wsa_add_FaultTo(struct soap *soap, const char *faultTo)
568
{ soap->header->SOAP_WSA(FaultTo) = (SOAP_WSA_(,FaultTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,FaultTo)));
569
SOAP_WSA_(soap_default,EndpointReferenceType)(soap, soap->header->SOAP_WSA(FaultTo));
570
soap->header->SOAP_WSA(FaultTo)->Address = soap_strdup(soap, faultTo);
575
/******************************************************************************\
579
\******************************************************************************/
582
@fn int soap_wsa_check(struct soap *soap)
583
@brief Checks the presence and validity of WS-Addressing information headers.
585
@return SOAP_OK or fault
588
soap_wsa_check(struct soap *soap)
589
{ if (!soap->header || !soap->header->SOAP_WSA(To) || !soap->header->SOAP_WSA(Action))
590
#if defined(SOAP_WSA_2005)
591
return soap_wsa_error(soap, wsa5__MessageAddressingHeaderRequired, NULL);
592
#elif defined(SOAP_WSA_2003)
593
return soap_wsa_error(soap, "WS-Addressing header missing");
595
return soap_wsa_error(soap, SOAP_WSA(MessageInformationHeaderRequired));
600
/******************************************************************************\
604
\******************************************************************************/
607
@fn int soap_wsa_reply(struct soap *soap, const char *id, const char *action)
608
@brief Sets WS-Addressing header fields for server response.
610
@param[in] id is the messageID (optional)
611
@param[in] action is the target action (required)
612
@return SOAP_OK or fault
615
soap_wsa_reply(struct soap *soap, const char *id, const char *action)
616
{ struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
617
struct SOAP_ENV__Header *header;
618
DBGFUN1("soap_wsa_reply", "action=%s", action?action:"");
620
return SOAP_PLUGIN_ERROR;
621
/* if endpoint address for reply is 'none' return immediately */
622
if (soap->header && soap->header->SOAP_WSA(ReplyTo) && soap->header->SOAP_WSA(ReplyTo)->Address && !strcmp(soap->header->SOAP_WSA(ReplyTo)->Address, soap_wsa_noneURI))
623
return soap_send_empty_response(soap, SOAP_OK);
624
header = (struct SOAP_ENV__Header*)soap_malloc(soap, sizeof(struct SOAP_ENV__Header));
625
soap_default_SOAP_ENV__Header(soap, header);
626
if (soap->header && soap->header->SOAP_WSA(MessageID))
627
{ header->SOAP_WSA(RelatesTo) = (SOAP_WSA_(,RelatesTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,RelatesTo)));
628
SOAP_WSA_(soap_default_,RelatesTo)(soap, header->SOAP_WSA(RelatesTo));
629
header->SOAP_WSA(RelatesTo)->__item = soap->header->SOAP_WSA(MessageID);
631
header->SOAP_WSA(MessageID) = soap_strdup(soap, id);
632
header->SOAP_WSA(Action) = soap_strdup(soap, action);
633
if (soap->header && soap->header->SOAP_WSA(ReplyTo) && soap->header->SOAP_WSA(ReplyTo)->Address && strcmp(soap->header->SOAP_WSA(ReplyTo)->Address, soap_wsa_anonymousURI))
634
{ header->SOAP_WSA(To) = soap->header->SOAP_WSA(ReplyTo)->Address;
635
/* (re)connect to fault endpoint if From != ReplyTo */
636
if (!soap->header->SOAP_WSA(From) || !soap->header->SOAP_WSA(From)->Address || strcmp(soap->header->SOAP_WSA(From)->Address, soap->header->SOAP_WSA(ReplyTo)->Address))
637
{ struct soap *reply_soap = soap_copy(soap);
639
{ soap_copy_stream(reply_soap, soap);
640
soap_clr_omode(reply_soap, SOAP_ENC_MIME | SOAP_ENC_DIME | SOAP_ENC_MTOM);
641
soap->socket = SOAP_INVALID_SOCKET; /* prevents close */
642
if (soap_connect(soap, header->SOAP_WSA(To), header->SOAP_WSA(Action)))
644
soap_copy_stream(soap, reply_soap);
645
#if defined(SOAP_WSA_2005)
646
err = soap_wsa_error(soap, SOAP_WSA(DestinationUnreachable), header->SOAP_WSA(To));
647
#elif defined(SOAP_WSA_2003)
648
err = soap_wsa_error(soap, "WS-Addessing destination unreachable");
650
err = soap_wsa_error(soap, SOAP_WSA(DestinationUnreachable));
652
reply_soap->socket = SOAP_INVALID_SOCKET;
653
soap_end(reply_soap);
654
soap_free(reply_soap);
657
soap_send_empty_response(reply_soap, SOAP_OK); /* HTTP ACCEPTED */
658
soap_closesock(reply_soap);
659
soap_end(reply_soap);
660
soap_free(reply_soap);
661
data->fresponse = soap->fresponse;
662
soap->fresponse = soap_wsa_response; /* response will be a POST */
666
else if (soap->header && soap->header->SOAP_WSA(From))
667
header->SOAP_WSA(To) = soap->header->SOAP_WSA(From)->Address;
669
header->SOAP_WSA(To) = (char*)soap_wsa_anonymousURI;
670
soap->header = header;
674
/******************************************************************************\
676
* Server-side SOAP Fault
678
\******************************************************************************/
681
@fn int soap_wsa_fault_subcode(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail)
682
@brief Sets sender/receiver SOAP Fault (sub)code for server fault response.
684
@param[in] flag 0=receiver, 1=sender
685
@param[in] faultsubcode sub code string
686
@param[in] faultstring fault string
687
@param[in] faultdetail detail string
691
soap_wsa_fault_subcode(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail)
692
{ struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
693
struct SOAP_ENV__Header *header = (struct SOAP_ENV__Header*)soap_malloc(soap, sizeof(struct SOAP_ENV__Header));
694
DBGFUN2("soap_wsa_fault_subcode", "faultsubcode=%s", faultsubcode?faultsubcode:"", "faultstring=%s", faultstring?faultstring:"");
696
return SOAP_PLUGIN_ERROR;
697
soap_default_SOAP_ENV__Header(soap, header);
698
soap_wsa_alloc_header(soap);
699
if (soap->header && soap->header->SOAP_WSA(MessageID))
700
{ header->SOAP_WSA(RelatesTo) = (SOAP_WSA_(,RelatesTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,RelatesTo)));
701
SOAP_WSA_(soap_default_,RelatesTo)(soap, header->SOAP_WSA(RelatesTo));
702
header->SOAP_WSA(RelatesTo)->__item = soap->header->SOAP_WSA(MessageID);
704
/* header->wsa__MessageID = "..."; */
705
header->SOAP_WSA(Action) = (char*)soap_wsa_faultAction;
706
if (soap->header && soap->header->SOAP_WSA(FaultTo) && soap->header->SOAP_WSA(FaultTo)->Address && strcmp(soap->header->SOAP_WSA(FaultTo)->Address, soap_wsa_anonymousURI))
707
{ header->SOAP_WSA(To) = soap->header->SOAP_WSA(FaultTo)->Address;
708
/* (re)connect to fault endpoint if To != FaultTo */
709
if (!soap->header->SOAP_WSA(From) || !soap->header->SOAP_WSA(From)->Address || strcmp(soap->header->SOAP_WSA(From)->Address, soap->header->SOAP_WSA(ReplyTo)->Address))
710
{ soap->keep_alive = 0;
711
soap_send_empty_response(soap, SOAP_OK); /* HTTP ACCEPTED */
712
if (soap_connect(soap, header->SOAP_WSA(To), header->SOAP_WSA(Action)))
713
return SOAP_STOP; /* nowhere to go */
714
soap_set_endpoint(soap, header->SOAP_WSA(To));
715
soap->action = header->SOAP_WSA(Action);
716
data->fresponse = soap->fresponse;
717
soap->fresponse = soap_wsa_response; /* response will be a POST */
720
else if (soap->header && soap->header->SOAP_WSA(From))
721
header->SOAP_WSA(To) = soap->header->SOAP_WSA(From)->Address;
723
header->SOAP_WSA(To) = (char*)soap_wsa_anonymousURI;
724
soap->header = header;
726
return soap_sender_fault_subcode(soap, faultsubcode, faultstring, faultdetail);
727
return soap_receiver_fault_subcode(soap, faultsubcode, faultstring, faultdetail);
731
@fn int soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
732
@brief Sets sender SOAP Fault (sub)code for server fault response.
734
@param[in] faultsubcode sub code string
735
@param[in] faultstring fault string
736
@param[in] faultdetail detail string
740
soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
741
{ return soap_wsa_fault_subcode(soap, 1, faultsubcode, faultstring, faultdetail);
745
@fn int soap_wsa_receiver_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
746
@brief Sets receiver SOAP Fault (sub)code for server fault response.
748
@param[in] faultsubcode sub code string
749
@param[in] faultstring fault string
750
@param[in] faultdetail detail string
754
soap_wsa_receiver_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
755
{ return soap_wsa_fault_subcode(soap, 0, faultsubcode, faultstring, faultdetail);
759
@fn int soap_wsa_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
760
@brief Sets sender SOAP Fault for server fault response.
762
@param[in] faultstring fault string
763
@param[in] faultdetail detail string
767
soap_wsa_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
768
{ return soap_wsa_fault_subcode(soap, 1, NULL, faultstring, faultdetail);
772
@fn int soap_wsa_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
773
@brief Sets receiver SOAP Fault for server fault response.
775
@param[in] faultstring fault string
776
@param[in] faultdetail detail string
780
soap_wsa_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
781
{ return soap_wsa_fault_subcode(soap, 0, NULL, faultstring, faultdetail);
784
/******************************************************************************\
786
* WS-Addressing Fault
788
\******************************************************************************/
790
#if defined(SOAP_WSA_2005)
792
@fn int soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultCodesType) *fault, char **info)
793
@brief Checks the presence of a WS-Addressing fault
795
@param[out] fault code
796
@param[out] info string pointer related to the wsa fault (or set to NULL)
797
@return SOAP_OK (no fault) or fault code
800
soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultCodesType) *fault, char **info)
801
{ if (soap->error && soap->fault && soap->fault->SOAP_ENV__Code)
802
{ const char *code = *soap_faultsubcode(soap);
804
{ SOAP_WSA__(soap_s2,FaultCodesType)(soap, code, fault);
806
{ struct SOAP_ENV__Detail *detail;
808
if (soap->fault->detail)
809
detail = soap->fault->detail;
811
detail = soap->fault->SOAP_ENV__Detail;
813
{ switch (detail->__type)
814
{ case SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName):
815
case SOAP_WSA_(SOAP_TYPE_,ProblemIRI):
816
*info = (char*)detail->fault;
818
case SOAP_WSA_(SOAP_TYPE_,ProblemAction):
819
*info = ((SOAP_WSA_(,ProblemAction)*)detail->fault)->Action;
831
#elif defined(SOAP_WSA_2003)
833
soap_wsa_check_fault(struct soap *soap, char **fault)
834
{ struct SOAP_ENV__Detail detail;
836
if (soap->error && soap->fault)
837
{ if (soap->fault->detail)
838
detail = soap->fault->detail;
840
detail = soap->fault->SOAP_ENV__Detail;
843
{ *fault = detail->__any;
851
@fn int soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultSubcodeValues) *fault)
852
@brief Checks the presence of a WS-Addressing fault
854
@param[out] fault code
855
@return SOAP_OK (no fault) or fault code
858
soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultSubcodeValues) *fault)
859
{ if (soap->error && soap->fault && soap->fault->SOAP_ENV__Code)
860
{ const char *code = *soap_faultsubcode(soap);
862
{ SOAP_WSA__(soap_s2,FaultSubcodeValues)(soap, code, fault);
870
#if defined(SOAP_WSA_2005)
872
@fn int soap_wsa_error(struct soap *soap, SOAP_WSA(FaultCodesType) fault, const char *info)
873
@brief Sets SOAP Fault (sub)code for server WS-Addressing fault response.
875
@param[in] fault is one of wsa:FaultCodesType enumeration values
876
@param[in] info is the value of the element in the Fault detail field
880
soap_wsa_error(struct soap *soap, SOAP_WSA(FaultCodesType) fault, const char *info)
881
{ const char *code = SOAP_WSA_(soap,FaultCodesType2s)(soap, fault);
882
/* populate the SOAP Fault as per WS-Addressing spec */
884
{ case SOAP_WSA(InvalidAddressingHeader):
885
soap_wsa_sender_fault_subcode(soap, code, "A header representing a Message Addressing Property is not valid and the message cannot be processed.", NULL);
886
soap_faultdetail(soap);
887
if (soap->version == 1)
888
{ soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
889
soap->fault->detail->fault = (void*)info;
892
{ soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
893
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
896
case SOAP_WSA(InvalidAddress):
897
soap_wsa_sender_fault_subcode(soap, code, "Invalid address.", NULL);
899
case SOAP_WSA(InvalidEPR):
900
soap_wsa_sender_fault_subcode(soap, code, "Invalid EPR.", NULL);
902
case SOAP_WSA(InvalidCardinality):
903
soap_wsa_sender_fault_subcode(soap, code, "Invalid cardinality of headers.", NULL);
905
case SOAP_WSA(MissingAddressInEPR):
906
soap_wsa_sender_fault_subcode(soap, code, "Missing EPR address.", NULL);
908
case SOAP_WSA(DuplicateMessageID):
909
soap_wsa_sender_fault_subcode(soap, code, "Message contains the message ID of a message already received.", NULL);
911
case SOAP_WSA(ActionMismatch):
912
soap_wsa_sender_fault_subcode(soap, code, "Action and SOAP action of the message do not match.", NULL);
914
case SOAP_WSA(MessageAddressingHeaderRequired):
915
soap_wsa_sender_fault_subcode(soap, code, "A required header representing a Message Addressing Property is not present.", NULL);
916
soap_faultdetail(soap);
917
if (soap->version == 1)
918
{ soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
919
soap->fault->detail->fault = (void*)info;
922
{ soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
923
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
926
case SOAP_WSA(DestinationUnreachable):
927
soap_wsa_sender_fault_subcode(soap, code, "No route can be determined to reach [destination]", NULL);
928
soap_faultdetail(soap);
929
if (soap->version == 1)
930
{ soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
931
soap->fault->detail->fault = (void*)info;
934
{ soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
935
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
938
case SOAP_WSA(ActionNotSupported):
939
soap_wsa_sender_fault_subcode(soap, code, "The [action] cannot be processed at the receiver.", NULL);
940
soap_faultdetail(soap);
941
if (soap->version == 1)
942
{ soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemAction);
943
soap->fault->detail->fault = (void*)soap_malloc(soap, sizeof(SOAP_WSA_(,ProblemAction)));
944
SOAP_WSA_(soap_default_,ProblemAction)(soap, (SOAP_WSA_(,ProblemAction)*)soap->fault->detail->fault);
945
((SOAP_WSA_(,ProblemAction)*)soap->fault->detail->fault)->Action = (char*)info;
948
{ soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemAction);
949
soap->fault->SOAP_ENV__Detail->fault = (void*)soap_malloc(soap, sizeof(SOAP_WSA_(,ProblemAction)));
950
SOAP_WSA_(soap_default_,ProblemAction)(soap, (SOAP_WSA_(,ProblemAction)*)soap->fault->SOAP_ENV__Detail->fault);
951
((SOAP_WSA_(,ProblemAction)*)soap->fault->SOAP_ENV__Detail->fault)->Action = (char*)info;
954
case SOAP_WSA(EndpointUnavailable):
955
soap_wsa_receiver_fault_subcode(soap, code, "The endpoint is unable to process the message at this time.", NULL);
956
soap_faultdetail(soap);
957
if (soap->version == 1)
958
{ soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
959
soap->fault->detail->fault = (void*)info;
962
{ soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
963
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
971
#elif defined(SOAP_WSA_2003)
973
soap_wsa_error(struct soap *soap, const char *fault)
974
{ return soap_wsa_sender_fault_subcode(soap, NULL, fault, NULL);
978
@fn int soap_wsa_error(struct soap *soap, SOAP_WSA(FaultSubcodeValues) fault)
979
@brief Sets SOAP Fault (sub)code for server WS-Addressing fault response.
981
@param[in] fault is one of wsa:FaultSubcodeValues
985
soap_wsa_error(struct soap *soap, SOAP_WSA(FaultSubcodeValues) fault)
986
{ const char *code = SOAP_WSA_(soap,FaultSubcodeValues2s)(soap, fault);
987
/* populate the SOAP Fault as per WS-Addressing spec */
989
{ case SOAP_WSA(InvalidMessageInformationHeader):
990
return soap_wsa_sender_fault_subcode(soap, code, "A message information header is not valid and the message cannot be processed. The validity failure can be either structural or semantic, e.g. a [destination] that is not a URI or a [relationship] to a [message id] that was never issued.", "Invalid header");
991
case SOAP_WSA(MessageInformationHeaderRequired):
992
return soap_wsa_sender_fault_subcode(soap, code, "A required message information header, To, MessageID, or Action, is not present.", "Missing Header QName");
993
case SOAP_WSA(DestinationUnreachable):
994
return soap_wsa_sender_fault_subcode(soap, code, "No route can be determined to reach the destination role defined by the WS-Addressing To.", NULL);
995
case SOAP_WSA(ActionNotSupported):
996
return soap_wsa_sender_fault_subcode(soap, code, "The [action] cannot be processed at the receiver.", soap->action);
997
case SOAP_WSA(EndpointUnavailable):
998
return soap_wsa_receiver_fault_subcode(soap, code, "The endpoint is unable to process the message at this time.", NULL);
1006
/******************************************************************************\
1008
* Plugin registry functions
1010
\******************************************************************************/
1013
@fn int soap_wsa(struct soap *soap, struct soap_plugin *p, void *arg)
1014
@brief Plugin registry function, used with soap_register_plugin.
1016
@param[in,out] p plugin created in registry
1017
@param[in] arg passed from soap_register_plugin_arg
1021
soap_wsa(struct soap *soap, struct soap_plugin *p, void *arg)
1022
{ DBGFUN("soap_wsa");
1023
p->id = soap_wsa_id;
1024
p->data = (void*)SOAP_MALLOC(soap, sizeof(struct soap_wsa_data));
1026
p->fdelete = soap_wsa_delete;
1028
{ if (soap_wsa_init(soap, (struct soap_wsa_data*)p->data))
1029
{ SOAP_FREE(soap, p->data);
1037
@fn int soap_wsa_init(struct soap *soap, struct soap_wsa_data *data)
1038
@brief Initializes plugin data.
1040
@param[in,out] data plugin data
1044
soap_wsa_init(struct soap *soap, struct soap_wsa_data *data)
1045
{ DBGFUN("soap_wsa_init");
1046
data->fheader = soap->fheader;
1047
data->fseterror = soap->fseterror;
1048
soap->fheader = soap_wsa_header;
1049
soap->fseterror = soap_wsa_set_error;
1054
@fn void soap_wsa_delete(struct soap *soap, struct soap_plugin *p)
1055
@brief Deletes plugin data.
1057
@param[in,out] p plugin
1061
soap_wsa_delete(struct soap *soap, struct soap_plugin *p)
1062
{ DBGFUN("soap_wsa_delete");
1063
SOAP_FREE(soap, p->data);
1066
/******************************************************************************\
1068
* Callbacks registered by plugin
1070
\******************************************************************************/
1073
@fn int soap_wsa_header(struct soap *soap)
1074
@brief Copies WS-Addressing action to SOAP action
1076
@return SOAP_OK or fault
1078
This callback is invoked to copy the WS-Addressing action to the SOAP action
1079
before invoking the service operation.
1082
soap_wsa_header(struct soap *soap)
1083
{ struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
1084
DBGFUN("soap_wsa_header");
1086
return SOAP_PLUGIN_ERROR;
1087
if (data->fheader && data->fheader(soap))
1089
if (soap->header && soap->header->SOAP_WSA(Action))
1090
soap->action = soap->header->SOAP_WSA(Action);
1095
@fn void soap_wsa_set_error(struct soap *soap, const char **c, const char **s)
1096
@brief Copies WS-Addressing action to SOAP action
1099
@param s fault string
1102
soap_wsa_set_error(struct soap *soap, const char **c, const char **s)
1103
{ struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
1104
DBGFUN("soap_wsa_set_error");
1107
if (data->fseterror)
1108
data->fseterror(soap, c, s);
1109
if (soap->error == SOAP_NO_METHOD)
1111
#if defined(SOAP_WSA_2005)
1112
soap->error = soap_wsa_error(soap, SOAP_WSA(ActionNotSupported), soap->action);
1113
#elif defined(SOAP_WSA_2003)
1114
soap->error = soap_wsa_error(soap, "Action not supported");
1116
soap->error = soap_wsa_error(soap, SOAP_WSA(ActionNotSupported));
1122
@fn int soap_wsa_response(struct soap *soap, int status, size_t count)
1123
@brief Overrides the HTTP response operations to send an HTTP POST
1126
@param count message length (if non-chunked)
1129
soap_wsa_response(struct soap *soap, int status, size_t count)
1130
{ struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
1131
DBGFUN2("soap_wsa_response", "status=%d", status, "count=%lu", (unsigned long)count);
1133
return SOAP_PLUGIN_ERROR;
1134
soap->fresponse = data->fresponse; /* reset (HTTP response) */
1135
return soap->fpost(soap, soap_strdup(soap, soap->endpoint), soap->host, soap->port, soap->path, soap->action, count);
1138
/******************************************************************************\
1142
\******************************************************************************/
1145
@fn int soap_wsa_alloc_header(struct soap *soap)
1146
@brief Adds SOAP Header if not present.
1151
soap_wsa_alloc_header(struct soap *soap)
1152
{ soap_header(soap);