/*
|
wsaapi.c
|
|
WS-Addressing plugin.
|
|
gSOAP XML Web services tools
|
Copyright (C) 2000-2015, Robert van Engelen, Genivia Inc., All Rights Reserved.
|
This part of the software is released under one of the following licenses:
|
GPL or the gSOAP public license.
|
--------------------------------------------------------------------------------
|
gSOAP public license.
|
|
The contents of this file are subject to the gSOAP Public License Version 1.3
|
(the "License"); you may not use this file except in compliance with the
|
License. You may obtain a copy of the License at
|
http://www.cs.fsu.edu/~engelen/soaplicense.html
|
Software distributed under the License is distributed on an "AS IS" basis,
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
for the specific language governing rights and limitations under the License.
|
|
The Initial Developer of the Original Code is Robert A. van Engelen.
|
Copyright (C) 2000-2015, Robert van Engelen, Genivia Inc., All Rights Reserved.
|
--------------------------------------------------------------------------------
|
GPL license.
|
|
This program is free software; you can redistribute it and/or modify it under
|
the terms of the GNU General Public License as published by the Free Software
|
Foundation; either version 2 of the License, or (at your option) any later
|
version.
|
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
You should have received a copy of the GNU General Public License along with
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Author contact information:
|
engelen@genivia.com / engelen@acm.org
|
|
This program is released under the GPL with the additional exemption that
|
compiling, linking, and/or using OpenSSL is allowed.
|
--------------------------------------------------------------------------------
|
A commercial use license is available from Genivia, Inc., contact@genivia.com
|
--------------------------------------------------------------------------------
|
*/
|
|
/**
|
|
@mainpage
|
|
- @ref wsa_0 documents the wsa plugin for WS-Addressing (2003/2004/2005
|
standards) support.
|
|
*/
|
|
/**
|
|
@page wsa_0 The WS-Addressing Plugin
|
|
[TOC]
|
|
@section wsa_1 WS-Addressing Setup
|
|
The material in this section relates to the WS-Addressing specification.
|
|
To use the wsa plugin:
|
-# Run wsdl2h -t typemap.dat on a WSDL of a service that requires WS-Addressing
|
headers. The typemap.dat file included in the gSOAP package is used to
|
recognize and translate Addressing header blocks.
|
-# Run soapcpp2 -a on the header file produced by wsdl2h. To enable
|
addressing-based service operation selection, you MUST use soapcpp2 option
|
-a. This allows the service to dispatch methods based on the WS-Addressing
|
action information header value (when the wsa plugin is registered).
|
-# (Re-)compile and link stdsoap2.c/pp or libgsoap, (dom.c/pp when needed),
|
wsaapi.c and the soapcpp2-generated source files.
|
-# Use the wsa plugin API functions described below.
|
|
An example wsa client/server application can be found in `gsoap/samples/wsa`.
|
|
A gSOAP service definitions header file with a `#import "wsa.h"` to support
|
WS-Addressing is automatically generated by wsdl2h for a set of WSDLs that use
|
WS-Addressing. The wsdl2h-generated header file should be further processed by
|
soapcpp2 to generate the binding code. The wsaapi.h and wsaapi.c implement the
|
WS-Addressing API described in this document.
|
|
A wsdl2h-generated service definitions header file might include the following
|
imports:
|
|
@code
|
#import "soap12.h"
|
#import "wsa.h" // or wsa3.h (2003/03), wsa4.h (2004/03), wsa5.h (2005/03)
|
@endcode
|
|
The wsa.h header file is imported from import/wsa.h when soapcpp2 is run on
|
this file. The wsa.h import can be manually added to enable WS-Addressing when
|
needed. The gSOAP service definitions header file is processed with soapcpp2 to
|
generate the client-side and/or server-side binding code.
|
|
Note that the wsa.h, wsa3.h, wsa4.h, and wsa5.h header files are located in the
|
import directory of the gSOAP package. These files define the WS-Addressing
|
information header elements and types. The soap12.h header file enables SOAP
|
1.2 messaging.
|
|
For developers: the WS-Addressing header blocks in wsa.h (and others) were
|
generated from the WS-Addressing schema with the wsdl2h tool and
|
WS/WS-typemap.dat as follows:
|
|
wsdl2h -cegy -o wsa.h -t WS/WS-typemap.dat WS/WS-Addressing.xsd
|
|
Refer to wsa.h for more details.
|
|
@section wsa_2 Client-side Usage
|
|
@subsection wsa_2_1 Constructing WS-Addressing Information Headers
|
|
To associate WS-Addressing information headers with service operations, the
|
SOAP Header struct `SOAP_ENV__Header` must have been defined and for each service
|
operation that uses WS-Addressing method-header-part directives should be used
|
in the gSOAP service definitions header file as follows:
|
|
@code
|
#import "wsa.h"
|
//gsoap ns service method-header-part: example wsa__MessageID
|
//gsoap ns service method-header-part: example wsa__RelatesTo
|
//gsoap ns service method-header-part: example wsa__From
|
//gsoap ns service method-header-part: example wsa__ReplyTo
|
//gsoap ns service method-header-part: example wsa__FaultTo
|
//gsoap ns service method-header-part: example wsa__To
|
//gsoap ns service method-header-part: example wsa__Action
|
//gsoap ns service method-action: example urn:example/examplePort/example
|
int ns__example(char *in, struct ns__exampleResponse *out);
|
@endcode
|
|
Note that the use of wsa versions determines the wsa prefix, e.g. use `wsa5`
|
for the latest WS-Addressing as in `wsa5__MessageID`.
|
|
In the client-side code, the WS-Addressing information headers are set with
|
`soap_wsa_request` by passing an optional message UUID string, a mandatory
|
destination address URI string, and a mandatory request action URI string. The
|
wsa plugin should be registered with the current soap struct context. An
|
optional source address information header can be added with
|
`soap_wsa_add_From` (must be invoked after the `soap_wsa_request` call).
|
|
For example:
|
|
@code
|
#include "wsaapi.h"
|
soap_register_plugin(soap, soap_wsa);
|
|
if (soap_wsa_request(soap, RequestMessageID, ToAddress, RequestAction))
|
|| soap_wsa_add_From(soap, FromAddress)) // optional: add a 'From' address
|
... // error: out of memory
|
|
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
|
soap_print_fault(soap, stderr); // an error occurred
|
else
|
// process the response
|
@endcode
|
|
To generate a UUID for the RequestMessageID, use:
|
|
@code
|
const char *RequestMessageID = soap_wsa_rand_uuid(soap);
|
@endcode
|
|
@subsection wsa_2_2 Information Headers for Relaying Server Responses
|
|
To relay the response to another destination, the WS-Addressing ReplyTo
|
information header is added with `soap_wsa_add_ReplyTo` by passing a reply
|
address URI string. The service returns "HTTP 200 OK" or "HTTP 202 ACCEPTED" to
|
the client when the response message relay was successful.
|
|
For example:
|
|
@code
|
#include "wsaapi.h"
|
soap_register_plugin(soap, soap_wsa);
|
|
if (soap_wsa_request(soap, RequestMessageID, ToAddress, RequestAction)
|
|| soap_wsa_add_From(soap, FromAddress) // optional: add a 'From' address
|
|| soap_wsa_add_ReplyTo(soap, ReplyToAddress))
|
... // error: out of memory
|
|
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
|
{
|
if (soap->error == 200 || soap->error == 202) // HTTP OK or ACCEPTED
|
printf("Request was accepted and results were forwarded\n");
|
else
|
soap_print_fault(soap, stderr); // an error occurred
|
}
|
else
|
// unexpected OK: for some reason the response was not relayed
|
@endcode
|
|
Note: the response message will be relayed when the From address is absent or
|
different than the ReplyTo address
|
|
@subsection wsa_2_3 Information Headers for Relaying Server Faults
|
|
To relay a server fault message to another destination, the WS-Addressing
|
FaultTo information header is added with `soap_wsa_add_FaultTo` by passing a
|
relay address URI string. The service returns "HTTP 200 OK" or "HTTP 202
|
ACCEPTED" to the client when the fault was relayed.
|
|
For example:
|
|
@code
|
#include "wsaapi.h"
|
soap_register_plugin(soap, soap_wsa);
|
|
if (soap_wsa_request(soap, RequestMessageID, ToAddress, RequestAction)
|
|| soap_wsa_add_From(soap, FromAddress) // optional: add a 'From' address
|
|| soap_wsa_add_FaultTo(soap, FaultToAddress))
|
... // error: out of memory
|
|
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
|
{
|
if (soap->error == 200 || soap->error == 202) // HTTP OK or ACCEPTED
|
printf("A fault occurred and the fault details were forwarded\n");
|
else
|
soap_print_fault(soap, stderr); // a connection error occurred
|
}
|
else
|
... // process response
|
@endcode
|
|
Note that the call can still return a fault, such as a connection error when
|
the service is not responding. In addition to the fault relay, the responses
|
can be relayed with `soap_wsa_add_ReplyTo`.
|
|
@subsection wsa_2_4 Error Handling
|
|
SOAP and HTTP errors set the soap->error attribute, as shown in this example:
|
|
@code
|
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
|
{
|
if (soap->error == 200 || soap->error == 202) // HTTP OK or ACCEPTED
|
printf("A fault occurred and the fault details were forwarded\n");
|
else
|
soap_print_fault(soap, stderr); // a connection error occurred
|
}
|
else
|
... // process response
|
@endcode
|
|
When a WS-Addressing error occurred, the wsa error code is stored in the SOAP
|
Fault Subcode field. This information can be retrieved with:
|
|
@code
|
wsa__FaultSubcodeValues fault;
|
if (soap_wsa_check_fault(soap, &fault))
|
{
|
switch (fault)
|
{
|
case wsa__InvalidMessageInformationHeader: ...
|
case wsa__MessageInformationHeaderRequired: ...
|
case wsa__DestinationUreachable: ...
|
case wsa__ActionNotSupported: ...
|
case wsa__EndpointUnavailable: ...
|
}
|
}
|
@endcode
|
|
When using wsa5.h, please refer to the standards and fault codes for this
|
implementation. For the wsa5.h 2005/03 standard, several faults have an
|
additional parameter (SOAP Fault detail):
|
|
@code
|
wsa5__FaultCodesType fault;
|
char *info;
|
if (soap_wsa_check_fault(soap, &fault, &info))
|
{
|
switch (fault)
|
{
|
case wsa5__InvalidAddressingHeader:
|
if (info)
|
printf("The invalid addressing header element is %s\n", info);
|
...
|
}
|
}
|
@endcode
|
|
@subsection wsa_2_5 Combining WS-Addressing with WS-Security
|
|
WS-Security can be combined with WS-Addressing. To sign WS-Addressing header
|
blocks, use the `soap_wsse_set_wsu_id` WSSE-plugin call to set the wsu:Id
|
attribute and signing of these attributed elements. For example, suppose we use
|
WS-Addressing 2005 headers (which are activated with an `#import "wsa5.h"` in
|
the header file for soapcpp2):
|
|
@code
|
#include "wsaapi.h"
|
#include "wsseapi.h"
|
soap_register_plugin(soap, soap_wsa);
|
soap_register_plugin(soap, soap_wsse);
|
|
soap_wsse_set_wsu_id(soap, "wsa5:From wsa5:To wsa5:ReplyTo wsa5:FaultTo wsa5:Action wsa5:MessageID");
|
if (soap_wsa_request(soap, RequestMessageID, ToAddress, RequestAction)
|
|| soap_wsa_add_From(soap, FromAddress) // optional: add a 'From' address
|
|| soap_wsa_add_FaultTo(soap, FaultToAddress))
|
... // error: out of memory
|
if (soap_call_ns__example(soap, ToAddress, NULL, ...))
|
... // error
|
@endcode
|
|
If your are using WS-Addressing 2004 (which is activated with an
|
`#import "wsa.h"` in the header file for soapcpp2) then change one line:
|
|
@code
|
soap_wsse_set_wsu_id(soap, "wsa:From wsa:To wsa:ReplyTo wsa:FaultTo wsa:Action wsa:MessageID");
|
@endcode
|
|
Note: `soap_wsse_set_wsu_id` should only be set once. Each new call overrides
|
the previous.
|
|
For more details on WS-Security, please see the
|
[WS-Security plugin documentation](../../wsse/html/index.html).
|
|
@section wsa_3 Server-side Usage
|
|
The wsa plugin should be registered with:
|
|
@code
|
soap_register_plugin(soap, soap_wsa);
|
@endcode
|
|
Once the plugin is registered, the `soap_bind`, `soap_accept`, and `soap_serve`
|
functions can be called to process requests and semi-automatically handle the
|
WS-Addressing header blocks.
|
|
Important: to dispatch service operations based on the WS-Addressing wsa:Action
|
information header, you must use soapcpp2 option `-a`. The generates a new
|
dispatcher (in soapServer.c) based on the action value.
|
|
A service operation implementation should use `soap_wsa_check` at the start of
|
its execution to verify the validity of the WS-Addressing information headers
|
in the SOAP request message. To allow response message to be automatically
|
relayed based on the ReplyTo information header, the service operation should
|
return `soap_wsa_reply` with an optional message UUID string and a mandatory
|
response action string. The response action string is documented in the
|
wsdl2h-generated .h file for this service operation.
|
|
For example:
|
|
@code
|
int ns__example(struct soap *soap, char *in, struct ns__exampleResponse *out)
|
{
|
if (soap_wsa_check(soap))
|
return soap->error;
|
// ... service logic
|
return soap_wsa_reply(soap, ResponseMessageID, ResponseAction);
|
}
|
@endcode
|
|
To return a SOAP fault that is automatically relayed to a fault service based
|
on the FaultTo information header, the `soap_wsa_sender_fault`,
|
`soap_wsa_receiver_fault`, `soap_wsa_sender_fault_subcode`, and
|
`soap_wsa_receiver_fault_subcode` functions should be used instead of the
|
usual `soap_sender_fault`, `soap_receiver_fault`, `soap_sender_fault_subcode`,
|
and `soap_receiver_fault_subcode`, respectively:
|
|
In case a Action must be associated with a SOAP Fault, use the
|
`soap_wsa_sender_fault_subcode_action` and
|
`soap_wsa_receiver_fault_subcode_action` functions to set the WS-Addressing
|
Action (and HTTP SOAP Action header as well).
|
|
For example, the following service operation illustrates the use of
|
`soap_wsa_check` to verify and process WS-Addressing header blocks and
|
`soap_wsa_reply` to enable responses to be relayed as per ReplyTo address in
|
the WS-Addressing header:
|
|
@code
|
int ns__example(struct soap *soap, char *in, struct ns__exampleResponse *out)
|
{
|
if (soap_wsa_check(soap))
|
return soap->error;
|
// ... service logic
|
// ... an error occurred, need to return fault possibly to fault service:
|
return soap_wsa_sender_fault(soap, "Exception in service operation", NULL);
|
// ... normal execution continues
|
return soap_wsa_reply(soap, ResponseMessageID, ResponseAction);
|
}
|
@endcode
|
|
@section wsa_4 HTTPS Server-side Usage
|
|
To enable HTTPS (SSL/TSL) servers, compile the sources with -DWITH_OPENSSL (and
|
link with libgsoapssl, libssl, and libcrypto). Because WS-Addressing may relay
|
messages over HTTPS as a sender (client), you must initialize the SSL context
|
for server and client uses. Therefore, the context must have access to all the
|
certificates need to verify the authenticity of the ReplyTo and FaultTo HTTPS
|
servers. To do so, use the following SSL initialization before `soap_bind`:
|
|
@code
|
struct soap *soap = soap_new();
|
if (soap_ssl_server_context(soap,
|
SOAP_SSL_DEFAULT,
|
"server.pem", // the keyfile (server should authenticate)
|
"password", // password to read the key file
|
"cacert.pem", // cacert file to store trusted certificates (role as client)
|
NULL, // optional capath
|
NULL, // DH file name or DH param key len bits, when NULL use RSA
|
NULL, // file with random data to seed randomness
|
"myserver" // unique server identification for SSL session cache
|
))
|
{
|
soap_print_fault(soap, stderr);
|
...
|
}
|
soap->bind_flags = SO_REUSEADDR;
|
if (!soap_valid_socket(soap_bind(soap, NULL, port, 100)))
|
{
|
soap_print_fault(soap, stderr);
|
...
|
}
|
@endcode
|
|
@section wsa_5 Implementing a Server for Handling ReplyTo Response Messages
|
|
To implement a separate server for handling relayed SOAP response messages
|
based on the ReplyTo information header in the request message, the gSOAP
|
header file should include a one-way service operation for the response
|
message. These one-way response service operations are automatically generated
|
with wsdl2h option `-b`.
|
|
For example, suppose a service operation returns an exampleResponse message. We
|
declare the one-way exampleResponse operation as follows:
|
|
@code
|
#import "wsa.h"
|
//gsoap ns service method-header-part: exampleResult wsa__MessageID
|
//gsoap ns service method-header-part: exampleResult wsa__RelatesTo
|
//gsoap ns service method-header-part: exampleResult wsa__From
|
//gsoap ns service method-header-part: exampleResult wsa__ReplyTo
|
//gsoap ns service method-header-part: exampleResult wsa__FaultTo
|
//gsoap ns service method-header-part: exampleResult wsa__To
|
//gsoap ns service method-header-part: exampleResult wsa__Action
|
//gsoap ns service method-action: exampleResult urn:example/examplePort/exampleResponse
|
int ns__exampleResponse(char *out, void);
|
@endcode
|
|
Note that the action information is important, because it is used by the
|
service dispatcher (assuming soapcpp2 option `-a` is used).
|
|
The implementation in the server code uses soap_wsa_check() to check the
|
presense and validity of the WS-Addressing information header in the message.
|
The `soap_send_empty_response` function should be used to return an
|
acknowledgment HTTP header with "HTTP 202 ACCEPTED" to the sender:
|
|
@code
|
int ns__exampleResponse(struct soap *soap, char *out)
|
{
|
if (soap_wsa_check(soap))
|
return soap_send_empty_response(soap, 500); // HTTP 500 Internal Server Error
|
// ... service logic
|
return soap_send_empty_response(soap, SOAP_OK); // HTTP 202 ACCEPTED
|
}
|
@endcode
|
|
@section wsa_6 Implementing a Server for Handling FaultTo Fault Messages
|
|
To implement a separate server for handling relayed SOAP fault messages based
|
on the FaultTo information header in the request message, the gSOAP header file
|
for soapcpp2 should include a SOAP fault service operation. This operation
|
accepts fault messages that are relayed by other services.
|
|
Basically, we use a trick to generate the SOAP-ENV:Fault struct via a one-way
|
service operation. This allows us both to implement a one-way service operation
|
that accepts faults and to automatically generate the fault struct for fault
|
data storage and manipulation.
|
|
The fault operation in the WS-Addressing files (wsa5.h etc.) is declared as
|
follows (here shown for the 2004/08 standard):
|
|
@code
|
//gsoap SOAP_ENV service method-action: Fault http://schemas.xmlsoap.org/ws/2004/08/addressing/fault
|
int SOAP_ENV__Fault
|
(
|
_QName faultcode, // SOAP 1.1
|
char *faultstring, // SOAP 1.1
|
char *faultactor, // SOAP 1.1
|
struct SOAP_ENV__Detail *detail, // SOAP 1.1
|
struct SOAP_ENV__Code *SOAP_ENV__Code, // SOAP 1.2
|
struct SOAP_ENV__Reason *SOAP_ENV__Reason, // SOAP 1.2
|
char *SOAP_ENV__Node, // SOAP 1.2
|
char *SOAP_ENV__Role, // SOAP 1.2
|
struct SOAP_ENV__Detail *SOAP_ENV__Detail, // SOAP 1.2
|
void
|
);
|
@endcode
|
|
Because each service operation has a struct to hold its input parameters, we
|
automatically generate the (original) `SOAP_ENV__Fault` struct on the fly!
|
|
It is important to associate the wsa fault action with this operation as shown
|
above.
|
|
The implementation of the Fault service operation in your server code should be
|
similar to:
|
|
@code
|
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)
|
{
|
... = faultcode; // SOAP 1.1 fault code string (QName)
|
... = faultstring; // SOAP 1.1 fault string
|
... = faultactor; // SOAP 1.1 fault actor string
|
... = detail; // SOAP 1.1 fault detail struct
|
... = SOAP_ENV__Code; // SOAP 1.2 fault code struct
|
... = SOAP_ENV__Reason; // SOAP 1.2 reason struct
|
... = SOAP_ENV__Node; // SOAP 1.2 node string
|
... = SOAP_ENV__Role; // SOAP 1.2 role string
|
... = SOAP_ENV__Detail; // SOAP 1.2 detail struct
|
return SOAP_OK;
|
}
|
@endcode
|
|
Note that SOAP 1.1 or SOAP 1.2 parameters are set based on the 1.1/1.2
|
messaging requirements.
|
|
@section wsa_7 Using the WS-Addressing plugin with the Apache gSOAP module
|
|
The WS-Addressing plugin may be used with the Apache `mod_gsoap` module. The
|
server-side logic is the same. However, registering the WS-Addressing plugin
|
requires a parameter `SOAP_WSA_NEW_TRANSFER`:
|
|
@code
|
#include "plugin/wsaapi.h"
|
#include "apache_gsoap.h"
|
void mod_gsoap_init(struct soap *soap, request_rec *r)
|
{
|
soap_register_plugin_arg(soap, http_wsa, SOAP_WSA_NEW_TRANSFER)
|
}
|
IMPLEMENT_GSOAP_SERVER_INIT(mod_gsoap_init)
|
@endcode
|
|
*/
|
|
#include "wsaapi.h"
|
|
#ifdef __cplusplus
|
extern "C" {
|
#endif
|
|
/** Plugin identification for plugin registry */
|
const char soap_wsa_id[] = SOAP_WSA_ID;
|
|
#if defined(SOAP_WSA_2003)
|
/** Anonymous Reply/To endpoint address */
|
const char *soap_wsa_anonymousURI = "http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous";
|
/** Specifies no Reply endpoint address (no reply) */
|
const char *soap_wsa_noneURI = "addressing/none not supported";
|
const char *soap_wsa_faultAction = "http://schemas.xmlsoap.org/ws/2003/03/addressing/fault";
|
#elif defined(SOAP_WSA_2004)
|
/** Anonymous Reply/To endpoint address */
|
const char *soap_wsa_anonymousURI = "http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous";
|
/** Specifies no Reply endpoint address (no reply) */
|
const char *soap_wsa_noneURI = "addressing/none not supported";
|
const char *soap_wsa_faultAction = "http://schemas.xmlsoap.org/ws/2004/03/addressing/fault";
|
#elif defined(SOAP_WSA_2005)
|
/** Anonymous Reply/To endpoint address */
|
const char *soap_wsa_anonymousURI = "http://www.w3.org/2005/08/addressing/anonymous";
|
/** Specifies no Reply endpoint address (no reply) */
|
const char *soap_wsa_noneURI = "http://www.w3.org/2005/08/addressing/none";
|
const char *soap_wsa_faultAction = "http://www.w3.org/2005/08/addressing/soap/fault";
|
#else
|
/** Anonymous Reply/To endpoint address */
|
const char *soap_wsa_anonymousURI = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
|
/** Specifies no Reply endpoint address (no reply) */
|
const char *soap_wsa_noneURI = "addressing/none not supported";
|
const char *soap_wsa_faultAction = "http://schemas.xmlsoap.org/ws/2004/08/addressing/fault";
|
#endif
|
|
/** anonymous URI of 2004 and 2005 schemas */
|
const char *soap_wsa_allAnonymousURI = "http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://www.w3.org/2005/08/addressing/anonymous";
|
|
/******************************************************************************\
|
*
|
* Static protos
|
*
|
\******************************************************************************/
|
|
static int soap_wsa_init(struct soap *soap, struct soap_wsa_data *data, void *arg);
|
static void soap_wsa_delete(struct soap *soap, struct soap_plugin *p);
|
|
static int soap_wsa_header(struct soap *soap);
|
static void soap_wsa_set_error(struct soap *soap, const char **c, const char **s);
|
static int soap_wsa_response(struct soap *soap, int status, ULONG64 count);
|
static int soap_wsa_disconnect(struct soap *soap);
|
|
static int soap_wsa_alloc_header(struct soap *soap);
|
|
/******************************************************************************\
|
*
|
* UUID
|
*
|
\******************************************************************************/
|
|
/**
|
@fn const char *soap_wsa_rand_uuid(struct soap *soap)
|
@brief Generates a random UUID (UUID algorithm version 4). Compile all source
|
codes with -DWITH_OPENSSL for better randomness.
|
@param soap context
|
@return UUID "urn:uuid:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" or NULL if out of memory
|
*/
|
SOAP_FMAC1
|
const char*
|
SOAP_FMAC2
|
soap_wsa_rand_uuid(struct soap *soap)
|
{
|
return soap_strdup(soap, soap_rand_uuid(soap, "urn:uuid:"));
|
}
|
|
/******************************************************************************\
|
*
|
* Client-side Request
|
*
|
\******************************************************************************/
|
|
/**
|
@fn int soap_wsa_request(struct soap *soap, const char *id, const char *to, const char *action)
|
@brief Sets the WS-Addressing information header for the next request message
|
with MessageID (optional), To (optional), and Action (required).
|
@param soap context
|
@param[in] id is the message ID (optional)
|
@param[in] to is the target endpoint (optional, set to anonymous when NULL)
|
@param[in] action is the target action (required)
|
@return SOAP_OK or error
|
|
Note: use soap_wsa_add_From, soap_wsa_add_ReplyTo, soap_wsa_add_FaultTo to add
|
other addressing fields following this function call.
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_request(struct soap *soap, const char *id, const char *to, const char *action)
|
{
|
DBGFUN3("soap_wsa_request", "id=%s", id?id:"(null)", "to=%s", to?to:"(null)", "action=%s", action?action:"(null)");
|
if (soap_wsa_alloc_header(soap))
|
return soap->error;
|
soap->header->SOAP_WSA(MessageID) = soap_strdup(soap, id);
|
if (to)
|
soap->header->SOAP_WSA(To) = soap_strdup(soap, to);
|
else /* this is optional */
|
soap->header->SOAP_WSA(To) = (char*)soap_wsa_anonymousURI;
|
soap->header->SOAP_WSA(Action) = soap_strdup(soap, action);
|
soap->header->SOAP_WSA(RelatesTo) = NULL;
|
soap->header->SOAP_WSA(From) = NULL;
|
soap->header->SOAP_WSA(FaultTo) = NULL;
|
soap_wsa_add_ReplyTo(soap, NULL);
|
return soap_wsa_check(soap);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_add_From(struct soap *soap, const char *from)
|
@brief Sets WS-Addressing From header for request message.
|
@param soap context
|
@param[in] from endpoint URI
|
@return SOAP_OK or SOAP_ERR
|
|
Use soap_wsa_request to populate the WS-Addressing header first.
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_add_From(struct soap *soap, const char *from)
|
{
|
if (!soap->header)
|
return SOAP_ERR;
|
soap->header->SOAP_WSA(From) = (SOAP_WSA_(,From)*)soap_malloc(soap, sizeof(SOAP_WSA_(,From)));
|
SOAP_WSA_(soap_default,EndpointReferenceType)(soap, soap->header->SOAP_WSA(From));
|
soap->header->SOAP_WSA(From)->Address = soap_strdup(soap, from);
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_add_NoReply(struct soap *soap)
|
@brief Sets WS-Addressing ReplyTo header to 'none' (no reply)
|
@param soap context
|
@return SOAP_OK or SOAP_ERR
|
|
Note: WS-Addressing 2005/08 standard.
|
|
Use soap_wsa_request to populate the WS-Addressing header.
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_add_NoReply(struct soap *soap)
|
{
|
return soap_wsa_add_ReplyTo(soap, soap_wsa_noneURI);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_add_ReplyTo(struct soap *soap, const char *replyTo)
|
@brief Sets WS-Addressing ReplyTo header for request message.
|
@param soap context
|
@param[in] replyTo endpoint URI or NULL for anonymous
|
@return SOAP_OK or SOAP_ERR
|
|
Use soap_wsa_request to populate the WS-Addressing header.
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_add_ReplyTo(struct soap *soap, const char *replyTo)
|
{
|
if (!soap->header)
|
return SOAP_ERR;
|
#ifndef SOAP_WSA_2005
|
if (!replyTo)
|
replyTo = soap_wsa_anonymousURI;
|
#endif
|
if (replyTo)
|
{
|
soap->header->SOAP_WSA(ReplyTo) = (SOAP_WSA_(,ReplyTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,ReplyTo)));
|
SOAP_WSA_(soap_default,EndpointReferenceType)(soap, soap->header->SOAP_WSA(ReplyTo));
|
soap->header->SOAP_WSA(ReplyTo)->Address = soap_strdup(soap, replyTo);
|
}
|
else
|
soap->header->SOAP_WSA(ReplyTo) = NULL;
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_add_FaultTo(struct soap *soap, const char *faultTo)
|
@brief Sets WS-Addressing FaultTo header for request message.
|
@param soap context
|
@param[in] faultTo endpoint URI or NULL for remove faultTo
|
@return SOAP_OK or SOAP_ERR
|
|
Use soap_wsa_request to populate the WS-Addressing header first.
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_add_FaultTo(struct soap *soap, const char *faultTo)
|
{
|
if (!soap->header)
|
return SOAP_ERR;
|
if (faultTo)
|
{
|
soap->header->SOAP_WSA(FaultTo) = (SOAP_WSA_(,FaultTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,FaultTo)));
|
SOAP_WSA_(soap_default,EndpointReferenceType)(soap, soap->header->SOAP_WSA(FaultTo));
|
soap->header->SOAP_WSA(FaultTo)->Address = soap_strdup(soap, faultTo);
|
}
|
else
|
soap->header->SOAP_WSA(FaultTo) = NULL;
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_add_RelatesTo(struct soap *soap, const char *relatesTo)
|
@brief Sets WS-Addressing RelatesTo header.
|
@param soap context
|
@param[in] relatesTo endpoint URI
|
@return SOAP_OK or SOAP_ERR
|
|
Use soap_wsa_request to populate the WS-Addressing header.
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_add_RelatesTo(struct soap *soap, const char *relatesTo)
|
{
|
if (!soap->header)
|
return SOAP_ERR;
|
if (relatesTo)
|
{
|
soap->header->SOAP_WSA(RelatesTo) = (SOAP_WSA_(,RelatesTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,RelatesTo)));
|
SOAP_WSA_(soap_default_,RelatesTo)(soap, soap->header->SOAP_WSA(RelatesTo));
|
soap->header->SOAP_WSA(RelatesTo)->__item = soap_strdup(soap, relatesTo);
|
}
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn const char *soap_wsa_From(struct soap *soap)
|
@brief Returns WS-Addressing From header.
|
@param soap context
|
@return From string or NULL
|
*/
|
SOAP_FMAC1
|
const char*
|
SOAP_FMAC2
|
soap_wsa_From(struct soap *soap)
|
{
|
if (!soap->header || !soap->header->SOAP_WSA(From))
|
return NULL;
|
return soap->header->SOAP_WSA(From)->Address;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn const char *soap_wsa_ReplyTo(struct soap *soap)
|
@brief Returns WS-Addressing ReplyTo header.
|
@param soap context
|
@return From string or NULL
|
*/
|
SOAP_FMAC1
|
const char*
|
SOAP_FMAC2
|
soap_wsa_ReplyTo(struct soap *soap)
|
{
|
if (!soap->header || !soap->header->SOAP_WSA(ReplyTo))
|
return NULL;
|
return soap->header->SOAP_WSA(ReplyTo)->Address;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn const char *soap_wsa_FaultTo(struct soap *soap)
|
@brief Returns WS-Addressing FaultTo header.
|
@param soap context
|
@return From string or NULL
|
*/
|
SOAP_FMAC1
|
const char*
|
SOAP_FMAC2
|
soap_wsa_FaultTo(struct soap *soap)
|
{
|
if (!soap->header || !soap->header->SOAP_WSA(FaultTo))
|
return NULL;
|
return soap->header->SOAP_WSA(FaultTo)->Address;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn const char *soap_wsa_RelatesTo(struct soap *soap)
|
@brief Returns WS-Addressing RelatesTo header.
|
@param soap context
|
@return From string or NULL
|
*/
|
SOAP_FMAC1
|
const char*
|
SOAP_FMAC2
|
soap_wsa_RelatesTo(struct soap *soap)
|
{
|
if (!soap->header || !soap->header->SOAP_WSA(RelatesTo))
|
return NULL;
|
return soap->header->SOAP_WSA(RelatesTo)->__item;
|
}
|
|
/******************************************************************************\
|
*
|
* Server-side Check and Reply
|
*
|
\******************************************************************************/
|
|
/**
|
@fn int soap_wsa_check(struct soap *soap)
|
@brief Checks the presence and validity of WS-Addressing information headers.
|
@param soap context
|
@return SOAP_OK or fault
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_check(struct soap *soap)
|
{
|
DBGFUN("soap_wsa_check");
|
if (!soap->header || !soap->header->SOAP_WSA(Action))
|
#if defined(SOAP_WSA_2005)
|
return soap_wsa_error(soap, wsa5__MessageAddressingHeaderRequired, NULL);
|
#elif defined(SOAP_WSA_2003)
|
return soap_wsa_error(soap, "WS-Addressing header missing");
|
#else
|
return soap_wsa_error(soap, SOAP_WSA(MessageInformationHeaderRequired));
|
#endif
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_reply(struct soap *soap, const char *id, const char *action)
|
@brief Sets WS-Addressing header fields for server response. Automatically
|
relays the response to the ReplyTo address (when ReplyTo != to From and ReplyTo
|
!= 'none') and returns HTTP 202 Accept to sender when relay was successful.
|
@param soap context
|
@param[in] id is the messageID (optional)
|
@param[in] action is the target action (required)
|
@return SOAP_OK or fault
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_reply(struct soap *soap, const char *id, const char *action)
|
{
|
struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
|
struct SOAP_ENV__Header *oldheader, *newheader;
|
DBGFUN1("soap_wsa_reply", "action=%s", action?action:"(null)");
|
if (!data)
|
return soap->error = SOAP_PLUGIN_ERROR;
|
oldheader = soap->header;
|
soap->header = NULL;
|
/* if endpoint address for reply is 'none' return immediately and STOP engine */
|
if (oldheader && oldheader->SOAP_WSA(ReplyTo) && oldheader->SOAP_WSA(ReplyTo)->Address && !strcmp(oldheader->SOAP_WSA(ReplyTo)->Address, soap_wsa_noneURI))
|
return soap_send_empty_response(soap, SOAP_OK);
|
/* allocate a new header */
|
if (soap_wsa_alloc_header(soap))
|
return soap->error;
|
newheader = soap->header;
|
/* copy members to new header, except WSA data */
|
if (oldheader)
|
*newheader = *oldheader;
|
newheader->SOAP_WSA(MessageID) = soap_strdup(soap, id);
|
newheader->SOAP_WSA(Action) = soap_strdup(soap, action);
|
newheader->SOAP_WSA(RelatesTo) = NULL;
|
newheader->SOAP_WSA(From) = NULL;
|
newheader->SOAP_WSA(To) = NULL;
|
newheader->SOAP_WSA(ReplyTo) = NULL;
|
newheader->SOAP_WSA(FaultTo) = NULL;
|
/* check current header content */
|
if (oldheader && oldheader->SOAP_WSA(MessageID))
|
{
|
newheader->SOAP_WSA(RelatesTo) = (SOAP_WSA_(,RelatesTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,RelatesTo)));
|
SOAP_WSA_(soap_default_,RelatesTo)(soap, newheader->SOAP_WSA(RelatesTo));
|
newheader->SOAP_WSA(RelatesTo)->__item = oldheader->SOAP_WSA(MessageID);
|
}
|
#ifdef SOAP_WSA_2005
|
/* WCF Interoperability:
|
ChannelInstance is required when the WCF Application hosts multiple
|
Callback Channels within the same application. The
|
ReferenceParameters->ChannelInstance element serves as a hint to the WCF
|
Client dispatcher, as to which WCF callback instance a received SOAP
|
Envelope belongs to ChannelInstance is declared as a pointer, so it is
|
essentially an optional element. Tests with Applications not requiring
|
ChannelInstance have also been done for the following fix.
|
*/
|
if (oldheader && oldheader->SOAP_WSA(ReplyTo) && oldheader->SOAP_WSA(ReplyTo)->ReferenceParameters && oldheader->SOAP_WSA(ReplyTo)->ReferenceParameters->chan__ChannelInstance)
|
{
|
if (!newheader->chan__ChannelInstance)
|
{
|
newheader->chan__ChannelInstance = (struct chan__ChannelInstanceType*)soap_malloc(soap, sizeof(struct chan__ChannelInstanceType));
|
if (newheader->chan__ChannelInstance)
|
{
|
soap_default_chan__ChannelInstanceType(soap, newheader->chan__ChannelInstance);
|
newheader->chan__ChannelInstance->__item = *(oldheader->SOAP_WSA(ReplyTo)->ReferenceParameters->chan__ChannelInstance);
|
newheader->chan__ChannelInstance->wsa5__IsReferenceParameter = _wsa5__IsReferenceParameter__true;
|
}
|
}
|
else
|
{
|
newheader->chan__ChannelInstance->__item = *(oldheader->SOAP_WSA(ReplyTo)->ReferenceParameters->chan__ChannelInstance);
|
newheader->chan__ChannelInstance->wsa5__IsReferenceParameter = _wsa5__IsReferenceParameter__true;
|
}
|
}
|
#endif
|
if (oldheader && oldheader->SOAP_WSA(ReplyTo) && oldheader->SOAP_WSA(ReplyTo)->Address && !soap_tagsearch(soap_wsa_allAnonymousURI, oldheader->SOAP_WSA(ReplyTo)->Address))
|
{
|
newheader->SOAP_WSA(To) = oldheader->SOAP_WSA(ReplyTo)->Address;
|
/* (re)connect to ReplyTo endpoint if From != ReplyTo */
|
if (!oldheader->SOAP_WSA(From) || !oldheader->SOAP_WSA(From)->Address || strcmp(oldheader->SOAP_WSA(From)->Address, oldheader->SOAP_WSA(ReplyTo)->Address))
|
{
|
struct soap *reply_soap = soap_new();
|
if (reply_soap)
|
{
|
soap_mode omode = soap->omode;
|
/* get the default callbacks */
|
int (*fposthdr)(struct soap*, const char*, const char*) = reply_soap->fposthdr;
|
int (*fparse)(struct soap*) = reply_soap->fparse;
|
int (*fparsehdr)(struct soap*, const char*, const char*) = reply_soap->fparsehdr;
|
int (*fresolve)(struct soap*, const char*, struct in_addr* inaddr) = reply_soap->fresolve;
|
int (*fconnect)(struct soap*, const char*, const char*, int) = reply_soap->fconnect;
|
int (*fclosesocket)(struct soap*, SOAP_SOCKET) = reply_soap->fclosesocket;
|
int (*fshutdownsocket)(struct soap*, SOAP_SOCKET, int) = reply_soap->fshutdownsocket;
|
SOAP_SOCKET (*fopen)(struct soap*, const char*, const char*, int) = reply_soap->fopen;
|
int (*fclose)(struct soap*) = reply_soap->fclose;
|
int (*fsend)(struct soap*, const char*, size_t) = reply_soap->fsend;
|
size_t (*frecv)(struct soap*, char*, size_t) = reply_soap->frecv;
|
int (*fpoll)(struct soap*) = reply_soap->fpoll;
|
/* copy the context and active stream */
|
soap_copy_context(reply_soap, soap);
|
soap_copy_stream(reply_soap, soap);
|
/* prevent close in soap_connect() below */
|
soap_free_stream(soap);
|
soap->omode |= SOAP_ENC_PLAIN; /* omit HTTP header ("encode XML body only") */
|
if (data->transfer)
|
{
|
/* save callbacks */
|
data->fposthdr = soap->fposthdr;
|
data->fparse = soap->fparse;
|
data->fparsehdr = soap->fparsehdr;
|
data->fresolve = soap->fresolve;
|
data->fconnect = soap->fconnect;
|
data->fclosesocket = soap->fclosesocket;
|
data->fshutdownsocket = soap->fshutdownsocket;
|
data->fopen = soap->fopen;
|
data->fclose = soap->fclose;
|
data->fsend = soap->fsend;
|
data->frecv = soap->frecv;
|
data->fpoll = soap->fpoll;
|
/* assign default callbacks */
|
soap->fposthdr = fposthdr;
|
soap->fparse = fparse;
|
soap->fparsehdr = fparsehdr;
|
soap->fresolve = fresolve;
|
soap->fconnect = fconnect;
|
soap->fclosesocket = fclosesocket;
|
soap->fshutdownsocket = fshutdownsocket;
|
soap->fopen = fopen;
|
soap->fclose = fclose;
|
soap->fsend = fsend;
|
soap->frecv = frecv;
|
soap->fpoll = fpoll;
|
}
|
if (soap_connect(soap, newheader->SOAP_WSA(To), newheader->SOAP_WSA(Action)))
|
{
|
int err;
|
if (data->transfer)
|
{
|
/* restore callbacks */
|
soap->fposthdr = data->fposthdr;
|
soap->fparse = data->fparse;
|
soap->fparsehdr = data->fparsehdr;
|
soap->fresolve = data->fresolve;
|
soap->fconnect = data->fconnect;
|
soap->fclosesocket = data->fclosesocket;
|
soap->fshutdownsocket = data->fshutdownsocket;
|
soap->fopen = data->fopen;
|
soap->fclose = data->fclose;
|
soap->fsend = data->fsend;
|
soap->frecv = data->frecv;
|
soap->fpoll = data->fpoll;
|
}
|
soap_copy_stream(soap, reply_soap);
|
soap_free_stream(reply_soap);
|
soap_end(reply_soap);
|
soap_free(reply_soap);
|
soap->header = oldheader;
|
soap->omode = omode; /* restore omode */
|
#if defined(SOAP_WSA_2005)
|
err = soap_wsa_error(soap, SOAP_WSA(DestinationUnreachable), newheader->SOAP_WSA(To));
|
#elif defined(SOAP_WSA_2003)
|
err = soap_wsa_error(soap, "WS-Addessing destination unreachable");
|
#else
|
err = soap_wsa_error(soap, SOAP_WSA(DestinationUnreachable));
|
#endif
|
soap->header = NULL;
|
return err;
|
}
|
if (soap_valid_socket(reply_soap->socket))
|
soap_send_empty_response(reply_soap, SOAP_OK); /* HTTP ACCEPTED */
|
soap->header = newheader;
|
soap_end(reply_soap);
|
soap_free(reply_soap);
|
data->fresponse = soap->fresponse;
|
soap->fresponse = soap_wsa_response; /* response will be a POST */
|
soap->omode = omode; /* restore omode */
|
}
|
}
|
}
|
else if (oldheader && oldheader->SOAP_WSA(From))
|
{
|
newheader->SOAP_WSA(To) = oldheader->SOAP_WSA(From)->Address;
|
}
|
else
|
{
|
newheader->SOAP_WSA(To) = (char*)soap_wsa_anonymousURI;
|
}
|
soap->header = newheader;
|
soap->action = newheader->SOAP_WSA(Action);
|
return SOAP_OK;
|
}
|
|
/******************************************************************************\
|
*
|
* Server-side SOAP Fault
|
*
|
\******************************************************************************/
|
|
/**
|
@fn int soap_wsa_fault_subcode(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail)
|
@brief Sets sender/receiver SOAP Fault (sub)code for server fault response.
|
@param soap context
|
@param[in] flag 0=receiver, 1=sender
|
@param[in] faultsubcode sub code string
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_fault_subcode(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail)
|
{
|
return soap_wsa_fault_subcode_action(soap, flag, faultsubcode, faultstring, faultdetail, NULL);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_fault_subcode_action(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action)
|
@brief Sets sender/receiver SOAP Fault (sub)code and action for server fault response.
|
@param soap context
|
@param[in] flag 0=receiver, 1=sender
|
@param[in] faultsubcode sub code string
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@param[in] action WS-Addressing action string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_fault_subcode_action(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action)
|
{
|
struct SOAP_ENV__Header *oldheader, *newheader;
|
DBGFUN2("soap_wsa_fault_subcode_action", "faultsubcode=%s", faultsubcode ? faultsubcode : "(null)", "faultstring=%s", faultstring ? faultstring : "(null)");
|
oldheader = soap->header;
|
/* no FaultTo: use ReplyTo */
|
if (oldheader && oldheader->SOAP_WSA(ReplyTo) && (!oldheader->SOAP_WSA(FaultTo) || soap_tagsearch(soap_wsa_allAnonymousURI, oldheader->SOAP_WSA(FaultTo)->Address)))
|
{
|
if (!oldheader->SOAP_WSA(FaultTo))
|
{
|
oldheader->SOAP_WSA(FaultTo) = (SOAP_WSA_(,FaultTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,FaultTo)));
|
if (oldheader->SOAP_WSA(FaultTo))
|
SOAP_WSA_(soap_default,EndpointReferenceType)(soap, soap->header->SOAP_WSA(FaultTo));
|
}
|
if (oldheader->SOAP_WSA(FaultTo))
|
oldheader->SOAP_WSA(FaultTo)->Address = oldheader->SOAP_WSA(ReplyTo)->Address;
|
}
|
/* use FaultTo */
|
if (oldheader && oldheader->SOAP_WSA(FaultTo) && oldheader->SOAP_WSA(FaultTo)->Address && !strcmp(oldheader->SOAP_WSA(FaultTo)->Address, soap_wsa_noneURI))
|
return soap_send_empty_response(soap, SOAP_OK); /* HTTP ACCEPTED */
|
soap->header = NULL;
|
/* allocate a new header */
|
soap_header(soap);
|
newheader = soap->header;
|
if (newheader)
|
{
|
soap_default_SOAP_ENV__Header(soap, newheader); /* remove/clear SOAP Header */
|
/* check header */
|
if (oldheader && oldheader->SOAP_WSA(MessageID))
|
{
|
newheader->SOAP_WSA(RelatesTo) = (SOAP_WSA_(,RelatesTo)*)soap_malloc(soap, sizeof(SOAP_WSA_(,RelatesTo)));
|
SOAP_WSA_(soap_default_,RelatesTo)(soap, newheader->SOAP_WSA(RelatesTo));
|
newheader->SOAP_WSA(RelatesTo)->__item = oldheader->SOAP_WSA(MessageID);
|
}
|
/* header->wsa__MessageID = "..."; */
|
newheader->SOAP_WSA(Action) = (char*)soap_wsa_faultAction;
|
if (oldheader && oldheader->SOAP_WSA(FaultTo) && oldheader->SOAP_WSA(FaultTo)->Address && !soap_tagsearch(soap_wsa_allAnonymousURI, oldheader->SOAP_WSA(FaultTo)->Address))
|
{
|
newheader->SOAP_WSA(To) = oldheader->SOAP_WSA(FaultTo)->Address;
|
/* (re)connect to FaultTo endpoint if From != FaultTo */
|
if (!oldheader->SOAP_WSA(From) || !oldheader->SOAP_WSA(From)->Address || strcmp(oldheader->SOAP_WSA(From)->Address, oldheader->SOAP_WSA(FaultTo)->Address))
|
{
|
struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
|
if (!data)
|
return soap->error = SOAP_PLUGIN_ERROR;
|
soap->keep_alive = 0;
|
soap_send_empty_response(soap, SOAP_OK); /* HTTP ACCEPTED */
|
if (data->transfer)
|
{
|
struct soap reply_soap;
|
soap_init(&reply_soap);
|
/* save callbacks */
|
data->fposthdr = soap->fposthdr;
|
data->fparse = soap->fparse;
|
data->fparsehdr = soap->fparsehdr;
|
data->fresolve = soap->fresolve;
|
data->fconnect = soap->fconnect;
|
data->fclosesocket = soap->fclosesocket;
|
data->fshutdownsocket = soap->fshutdownsocket;
|
data->fopen = soap->fopen;
|
data->fclose = soap->fclose;
|
data->fsend = soap->fsend;
|
data->frecv = soap->frecv;
|
data->fpoll = soap->fpoll;
|
/* assign default callbacks */
|
soap->fposthdr = reply_soap.fposthdr;
|
soap->fparse = reply_soap.fparse;
|
soap->fparsehdr = reply_soap.fparsehdr;
|
soap->fresolve = reply_soap.fresolve;
|
soap->fconnect = reply_soap.fconnect;
|
soap->fclosesocket = reply_soap.fclosesocket;
|
soap->fshutdownsocket = reply_soap.fshutdownsocket;
|
soap->fopen = reply_soap.fopen;
|
soap->fclose = reply_soap.fclose;
|
soap->fsend = reply_soap.fsend;
|
soap->frecv = reply_soap.frecv;
|
soap->fpoll = reply_soap.fpoll;
|
|
soap_end(&reply_soap);
|
soap_done(&reply_soap);
|
}
|
if (soap_connect(soap, newheader->SOAP_WSA(To), newheader->SOAP_WSA(Action)))
|
{
|
if (data->transfer)
|
{
|
/* restore callbacks */
|
soap->fposthdr = data->fposthdr;
|
soap->fparse = data->fparse;
|
soap->fparsehdr = data->fparsehdr;
|
soap->fresolve = data->fresolve;
|
soap->fconnect = data->fconnect;
|
soap->fclosesocket = data->fclosesocket;
|
soap->fshutdownsocket = data->fshutdownsocket;
|
soap->fopen = data->fopen;
|
soap->fclose = data->fclose;
|
soap->fsend = data->fsend;
|
soap->frecv = data->frecv;
|
soap->fpoll = data->fpoll;
|
}
|
return soap->error = SOAP_STOP; /* nowhere to go */
|
}
|
soap_set_endpoint(soap, newheader->SOAP_WSA(To));
|
if (action)
|
soap->action = (char*)action;
|
else
|
soap->action = newheader->SOAP_WSA(Action);
|
data->fresponse = soap->fresponse;
|
soap->fresponse = soap_wsa_response; /* response will be a POST */
|
}
|
}
|
else if (oldheader && oldheader->SOAP_WSA(From))
|
{
|
newheader->SOAP_WSA(To) = oldheader->SOAP_WSA(From)->Address;
|
}
|
else
|
{
|
newheader->SOAP_WSA(To) = (char*)soap_wsa_anonymousURI;
|
}
|
soap->header = newheader;
|
}
|
if (flag)
|
return soap_sender_fault_subcode(soap, faultsubcode, faultstring, faultdetail);
|
return soap_receiver_fault_subcode(soap, faultsubcode, faultstring, faultdetail);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
|
@brief Sets sender SOAP Fault (sub)code for server fault response.
|
@param soap context
|
@param[in] faultsubcode sub code string
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
|
{
|
return soap_wsa_fault_subcode(soap, 1, faultsubcode, faultstring, faultdetail);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_sender_fault_subcode_action(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action)
|
@brief Sets sender SOAP Fault (sub)code for server fault response.
|
@param soap context
|
@param[in] faultsubcode sub code string
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@param[in] action WS-Addressing action string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_sender_fault_subcode_action(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action)
|
{
|
return soap_wsa_fault_subcode_action(soap, 1, faultsubcode, faultstring, faultdetail, action);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_receiver_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
|
@brief Sets receiver SOAP Fault (sub)code for server fault response.
|
@param soap context
|
@param[in] faultsubcode sub code string
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_receiver_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
|
{
|
return soap_wsa_fault_subcode(soap, 0, faultsubcode, faultstring, faultdetail);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_receiver_fault_subcode_action(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action)
|
@brief Sets receiver SOAP Fault (sub)code for server fault response.
|
@param soap context
|
@param[in] faultsubcode sub code string
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@param[in] action WS-Addressing action string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_receiver_fault_subcode_action(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action)
|
{
|
return soap_wsa_fault_subcode_action(soap, 0, faultsubcode, faultstring, faultdetail, action);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
|
@brief Sets sender SOAP Fault for server fault response.
|
@param soap context
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
|
{
|
return soap_wsa_fault_subcode(soap, 1, NULL, faultstring, faultdetail);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
|
@brief Sets receiver SOAP Fault for server fault response.
|
@param soap context
|
@param[in] faultstring fault string
|
@param[in] faultdetail detail string
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
|
{
|
return soap_wsa_fault_subcode(soap, 0, NULL, faultstring, faultdetail);
|
}
|
|
/******************************************************************************\
|
*
|
* WS-Addressing Faults
|
*
|
\******************************************************************************/
|
|
#if defined(SOAP_WSA_2005)
|
|
/**
|
@fn int soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultCodesType) *fault, const char **info)
|
@brief Checks the presence of a WS-Addressing fault
|
@param soap context
|
@param[out] fault code
|
@param[out] info string pointer related to the wsa fault (or set to NULL)
|
@return SOAP_OK (no fault) or fault code
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultCodesType) *fault, const char **info)
|
{
|
if (soap->error && soap->fault && soap->fault->SOAP_ENV__Code)
|
{
|
const char *code = soap_fault_subcode(soap);
|
if (code)
|
{
|
SOAP_WSA__(soap_s2,FaultCodesType)(soap, code, fault);
|
if (info)
|
{
|
struct SOAP_ENV__Detail *detail;
|
*info = NULL;
|
if (soap->fault->detail)
|
detail = soap->fault->detail;
|
else
|
detail = soap->fault->SOAP_ENV__Detail;
|
if (detail)
|
{
|
switch (detail->__type)
|
{
|
case SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName):
|
case SOAP_WSA_(SOAP_TYPE_,ProblemIRI):
|
*info = (char*)detail->fault;
|
break;
|
case SOAP_WSA_(SOAP_TYPE_,ProblemAction):
|
*info = ((SOAP_WSA_(,ProblemAction)*)detail->fault)->Action;
|
break;
|
default:
|
break;
|
}
|
}
|
}
|
return soap->error;
|
}
|
}
|
return SOAP_OK;
|
}
|
|
#elif defined(SOAP_WSA_2003)
|
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_check_fault(struct soap *soap, char **fault)
|
{
|
struct SOAP_ENV__Detail detail;
|
*fault = NULL;
|
if (soap->error && soap->fault)
|
{
|
if (soap->fault->detail)
|
detail = soap->fault->detail;
|
else
|
detail = soap->fault->SOAP_ENV__Detail;
|
}
|
if (detail)
|
{
|
*fault = detail->__any;
|
if (*fault)
|
return soap->error;
|
}
|
return SOAP_OK;
|
}
|
|
#else
|
|
/**
|
@fn int soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultSubcodeValues) *fault)
|
@brief Checks the presence of a WS-Addressing fault
|
@param soap context
|
@param[out] fault code
|
@return SOAP_OK (no fault) or fault code
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_check_fault(struct soap *soap, SOAP_WSA(FaultSubcodeValues) *fault)
|
{
|
if (soap->error && soap->fault && soap->fault->SOAP_ENV__Code)
|
{
|
const char *code = soap_fault_subcode(soap);
|
if (code)
|
{
|
SOAP_WSA__(soap_s2,FaultSubcodeValues)(soap, code, fault);
|
return soap->error;
|
}
|
}
|
return SOAP_OK;
|
}
|
#endif
|
|
#if defined(SOAP_WSA_2005)
|
|
/**
|
@fn int soap_wsa_error(struct soap *soap, SOAP_WSA(FaultCodesType) fault, const char *info)
|
@brief Sets SOAP Fault (sub)code for server WS-Addressing fault response.
|
@param soap context
|
@param[in] fault is one of wsa:FaultCodesType enumeration values
|
@param[in] info is the value of the element in the Fault detail field
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_error(struct soap *soap, SOAP_WSA(FaultCodesType) fault, const char *info)
|
{
|
const char *code = SOAP_WSA_(soap,FaultCodesType2s)(soap, fault);
|
/* populate the SOAP Fault as per WS-Addressing spec */
|
switch (fault)
|
{
|
case SOAP_WSA(InvalidAddressingHeader):
|
soap_faultdetail(soap);
|
if (soap->version == 1)
|
{
|
soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
|
soap->fault->detail->fault = (void*)info;
|
}
|
else if (soap->version == 2)
|
{
|
soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
|
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
|
}
|
soap_wsa_sender_fault_subcode(soap, code, "A header representing a Message Addressing Property is not valid and the message cannot be processed.", NULL);
|
break;
|
case SOAP_WSA(InvalidAddress):
|
soap_wsa_sender_fault_subcode(soap, code, "Invalid address.", NULL);
|
break;
|
case SOAP_WSA(InvalidEPR):
|
soap_wsa_sender_fault_subcode(soap, code, "Invalid EPR.", NULL);
|
break;
|
case SOAP_WSA(InvalidCardinality):
|
soap_wsa_sender_fault_subcode(soap, code, "Invalid cardinality of headers.", NULL);
|
break;
|
case SOAP_WSA(MissingAddressInEPR):
|
soap_wsa_sender_fault_subcode(soap, code, "Missing EPR address.", NULL);
|
break;
|
case SOAP_WSA(DuplicateMessageID):
|
soap_wsa_sender_fault_subcode(soap, code, "Message contains the message ID of a message already received.", NULL);
|
break;
|
case SOAP_WSA(ActionMismatch):
|
soap_wsa_sender_fault_subcode(soap, code, "Action and SOAP action of the message do not match.", NULL);
|
break;
|
case SOAP_WSA(MessageAddressingHeaderRequired):
|
soap_faultdetail(soap);
|
if (soap->version == 1)
|
{
|
soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
|
soap->fault->detail->fault = (void*)info;
|
}
|
else if (soap->version == 2)
|
{
|
soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemHeaderQName);
|
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
|
}
|
soap_wsa_sender_fault_subcode(soap, code, "A required header representing a Message Addressing Property is not present.", NULL);
|
break;
|
case SOAP_WSA(DestinationUnreachable):
|
soap_faultdetail(soap);
|
if (soap->version == 1)
|
{
|
soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
|
soap->fault->detail->fault = (void*)info;
|
}
|
else if (soap->version == 2)
|
{
|
soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
|
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
|
}
|
soap_wsa_sender_fault_subcode(soap, code, "No route can be determined to reach [destination]", NULL);
|
break;
|
case SOAP_WSA(ActionNotSupported):
|
soap_faultdetail(soap);
|
if (soap->version == 1)
|
{
|
soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemAction);
|
soap->fault->detail->fault = (void*)soap_malloc(soap, sizeof(SOAP_WSA_(,ProblemAction)));
|
SOAP_WSA_(soap_default_,ProblemAction)(soap, (SOAP_WSA_(,ProblemAction)*)soap->fault->detail->fault);
|
((SOAP_WSA_(,ProblemAction)*)soap->fault->detail->fault)->Action = (char*)info;
|
}
|
else if (soap->version == 2)
|
{
|
soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemAction);
|
soap->fault->SOAP_ENV__Detail->fault = (void*)soap_malloc(soap, sizeof(SOAP_WSA_(,ProblemAction)));
|
SOAP_WSA_(soap_default_,ProblemAction)(soap, (SOAP_WSA_(,ProblemAction)*)soap->fault->SOAP_ENV__Detail->fault);
|
((SOAP_WSA_(,ProblemAction)*)soap->fault->SOAP_ENV__Detail->fault)->Action = (char*)info;
|
}
|
soap_wsa_sender_fault_subcode(soap, code, "The [action] cannot be processed at the receiver.", NULL);
|
break;
|
case SOAP_WSA(EndpointUnavailable):
|
soap_faultdetail(soap);
|
if (soap->version == 1)
|
{
|
soap->fault->detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
|
soap->fault->detail->fault = (void*)info;
|
}
|
else if (soap->version == 2)
|
{
|
soap->fault->SOAP_ENV__Detail->__type = SOAP_WSA_(SOAP_TYPE_,ProblemIRI);
|
soap->fault->SOAP_ENV__Detail->fault = (void*)info;
|
}
|
soap_wsa_receiver_fault_subcode(soap, code, "The endpoint is unable to process the message at this time.", NULL);
|
break;
|
default:
|
break;
|
}
|
return SOAP_FAULT;
|
}
|
|
#elif defined(SOAP_WSA_2003)
|
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_error(struct soap *soap, const char *fault)
|
{
|
return soap_wsa_sender_fault_subcode(soap, NULL, fault, NULL);
|
}
|
|
#else
|
|
/**
|
@fn int soap_wsa_error(struct soap *soap, SOAP_WSA(FaultSubcodeValues) fault)
|
@brief Sets SOAP Fault (sub)code for server WS-Addressing fault response.
|
@param soap context
|
@param[in] fault is one of wsa:FaultSubcodeValues
|
@return SOAP_FAULT
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa_error(struct soap *soap, SOAP_WSA(FaultSubcodeValues) fault)
|
{
|
const char *code = SOAP_WSA_(soap,FaultSubcodeValues2s)(soap, fault);
|
/* populate the SOAP Fault as per WS-Addressing spec */
|
switch (fault)
|
{
|
case SOAP_WSA(InvalidMessageInformationHeader):
|
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");
|
case SOAP_WSA(MessageInformationHeaderRequired):
|
return soap_wsa_sender_fault_subcode(soap, code, "A required message information header, To, MessageID, or Action, is not present.", "Missing Header QName");
|
case SOAP_WSA(DestinationUnreachable):
|
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);
|
case SOAP_WSA(ActionNotSupported):
|
return soap_wsa_sender_fault_subcode(soap, code, "The [action] cannot be processed at the receiver.", soap->action);
|
case SOAP_WSA(EndpointUnavailable):
|
return soap_wsa_receiver_fault_subcode(soap, code, "The endpoint is unable to process the message at this time.", NULL);
|
default:
|
break;
|
}
|
return SOAP_FAULT;
|
}
|
|
#endif
|
|
/******************************************************************************\
|
*
|
* Plugin registry functions
|
*
|
\******************************************************************************/
|
|
/**
|
@fn int soap_wsa(struct soap *soap, struct soap_plugin *p, void *arg)
|
@brief Plugin registry function, used with soap_register_plugin and soap_register_plugin_arg.
|
@param soap context
|
@param[in,out] p plugin created in registry
|
@param[in] arg passed from soap_register_plugin_arg
|
@return SOAP_OK
|
*/
|
SOAP_FMAC1
|
int
|
SOAP_FMAC2
|
soap_wsa(struct soap *soap, struct soap_plugin *p, void *arg)
|
{
|
DBGFUN("soap_wsa");
|
p->id = soap_wsa_id;
|
p->data = (void*)SOAP_MALLOC(soap, sizeof(struct soap_wsa_data));
|
p->fcopy = NULL;
|
p->fdelete = soap_wsa_delete;
|
if (!p->data)
|
return SOAP_EOM;
|
if (soap_wsa_init(soap, (struct soap_wsa_data*)p->data, arg))
|
{
|
SOAP_FREE(soap, p->data);
|
return SOAP_EOM;
|
}
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_init(struct soap *soap, struct soap_wsa_data *data)
|
@brief Initializes plugin data.
|
@param soap context
|
@param[in,out] data plugin data
|
@return SOAP_OK
|
*/
|
static int
|
soap_wsa_init(struct soap *soap, struct soap_wsa_data *data, void *arg)
|
{
|
DBGFUN("soap_wsa_init");
|
data->fheader = soap->fheader;
|
data->fseterror = soap->fseterror;
|
soap->fheader = soap_wsa_header;
|
soap->fseterror = soap_wsa_set_error;
|
data->fresponse = NULL;
|
data->fdisconnect = NULL;
|
data->transfer = arg;
|
data->fsend = NULL;
|
data->frecv = NULL;
|
data->fpoll = NULL;
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn void soap_wsa_delete(struct soap *soap, struct soap_plugin *p)
|
@brief Deletes plugin data.
|
@param soap context
|
@param[in,out] p plugin
|
@return SOAP_OK
|
*/
|
static void
|
soap_wsa_delete(struct soap *soap, struct soap_plugin *p)
|
{
|
(void)soap;
|
DBGFUN("soap_wsa_delete");
|
SOAP_FREE(soap, p->data);
|
}
|
|
/******************************************************************************\
|
*
|
* Callbacks registered by plugin
|
*
|
\******************************************************************************/
|
|
/**
|
@fn int soap_wsa_header(struct soap *soap)
|
@brief Copies WS-Addressing action to SOAP action
|
@param soap context
|
@return SOAP_OK or fault
|
|
This callback is invoked to copy the WS-Addressing action to the SOAP action
|
before invoking the service operation.
|
*/
|
static int
|
soap_wsa_header(struct soap *soap)
|
{
|
struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
|
DBGFUN("soap_wsa_header");
|
if (!data)
|
return soap->error = SOAP_PLUGIN_ERROR;
|
if (data->fheader && data->fheader(soap))
|
return soap->error;
|
if (soap->header && soap->header->SOAP_WSA(Action))
|
{
|
soap->action = soap->header->SOAP_WSA(Action);
|
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "WSA action='%s'\n", soap->action));
|
}
|
return SOAP_OK;
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn void soap_wsa_set_error(struct soap *soap, const char **c, const char **s)
|
@brief Copies WS-Addressing action to SOAP action
|
@param soap context
|
@param c fault code
|
@param s fault string
|
*/
|
static void
|
soap_wsa_set_error(struct soap *soap, const char **c, const char **s)
|
{
|
struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
|
DBGFUN2("soap_wsa_set_error", "code=%s", c && *c ? *c : "(null)", "string=%s", s && *s ? *s : "(null)");
|
if (!data)
|
return;
|
if (data->fseterror)
|
data->fseterror(soap, c, s);
|
if (soap->error == SOAP_NO_METHOD || (soap->error == SOAP_TAG_MISMATCH && soap->level == 2))
|
{
|
#if defined(SOAP_WSA_2005)
|
soap->error = soap_wsa_error(soap, SOAP_WSA(ActionNotSupported), soap->action);
|
#elif defined(SOAP_WSA_2003)
|
soap->error = soap_wsa_error(soap, "Action not supported");
|
#else
|
soap->error = soap_wsa_error(soap, SOAP_WSA(ActionNotSupported));
|
#endif
|
}
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_response(struct soap *soap, int status, ULONG64 count)
|
@brief Overrides the HTTP response operations to send an HTTP POST
|
@param soap context
|
@param status code
|
@param count message length (if non-chunked)
|
*/
|
static int
|
soap_wsa_response(struct soap *soap, int status, ULONG64 count)
|
{
|
struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
|
(void)status;
|
DBGFUN2("soap_wsa_response", "status=%d", status, "count=%lu", (unsigned long)count);
|
if (!data)
|
return SOAP_PLUGIN_ERROR;
|
soap->fresponse = data->fresponse; /* reset (HTTP response) */
|
data->fdisconnect = soap->fdisconnect;
|
soap->fdisconnect = soap_wsa_disconnect; /* to accept HTTP 200 or 202 */
|
return soap->fpost(soap, soap_strdup(soap, soap->endpoint), soap->host, soap->port, soap->path, soap->action, count);
|
}
|
|
/******************************************************************************/
|
|
/**
|
@fn int soap_wsa_disconnect(struct soap *soap)
|
@brief Accepts HTTP 200 or 202 response upon HTTP POST response relay
|
@param soap context
|
*/
|
static int
|
soap_wsa_disconnect(struct soap *soap)
|
{
|
int err;
|
struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id);
|
DBGFUN("soap_wsa_disconnect");
|
if (!data)
|
return SOAP_PLUGIN_ERROR;
|
soap->fdisconnect = data->fdisconnect; /* reset */
|
err = soap_recv_empty_response(soap);
|
if (data->transfer)
|
{
|
/* restore callbacks */
|
soap->fposthdr = data->fposthdr;
|
soap->fparse = data->fparse;
|
soap->fparsehdr = data->fparsehdr;
|
soap->fresolve = data->fresolve;
|
soap->fconnect = data->fconnect;
|
soap->fclosesocket = data->fclosesocket;
|
soap->fshutdownsocket = data->fshutdownsocket;
|
soap->fopen = data->fopen;
|
soap->fclose = data->fclose;
|
soap->fsend = data->fsend;
|
soap->frecv = data->frecv;
|
soap->fpoll = data->fpoll;
|
}
|
return err;
|
}
|
|
/******************************************************************************\
|
*
|
* Misc.
|
*
|
\******************************************************************************/
|
|
/**
|
@fn int soap_wsa_alloc_header(struct soap *soap)
|
@brief Adds SOAP Header if not present.
|
@param soap context
|
@return SOAP_OK
|
*/
|
static int
|
soap_wsa_alloc_header(struct soap *soap)
|
{
|
if (soap->header)
|
return SOAP_OK;
|
soap_header(soap);
|
if (soap->header)
|
return SOAP_OK;
|
return soap->error = SOAP_EOM;
|
}
|
|
/******************************************************************************/
|
|
#ifdef __cplusplus
|
}
|
#endif
|