Home | Documentation |
gSOAP user guide
updated Tue Aug 27 2024 by Robert van Engelen
|
The gSOAP toolkit offers C/C++ tools and libraries to implement efficient and secure SOAP, XML, JSON and REST client and service Web API applications. The tools also offer XML data bindings for C and C++ to generate XML serializers to efficiently read and write C/C++ data to and from files and streams.
The gSOAP wsdl2h tool consumes WSDL and XSD schema files to converts them to C/C++ source code to implement XML messaging infrastructures. This frees the developer to focus on application functionality rather than on infrastructure.
More specifically, the wsdl2h tool consumes WSDLs to generate a C or C++ interface header file, which uses a developer-friendly C/C++ header file syntax. This allows developers to inspect Web services and XML schemas from a functionality point of view, rather than getting bogged down into the underlying SOAP-based infrastructure details of WSDLs and XSDs.
The soapcpp2 tool generates all the Web service binding source code with XML serializers necessary to quickly develop server-side and client-side Web service APIs.
The soapcpp2 tool can also be used to produce, rather than consume, WSDL and XSD files to deploy XML Web services or to develop XML applications. This approach allows the deployment of legacy C/C++ applications as services. Simply describe the Web API in a C or C++ interface header file for the soapcpp2 tool to generate the C/C++ source code that glues everything together.
Besides SOAP-based services, also non-SOAP XML and JSON REST services can be implemented with the gSOAP tools. Either described by WSDLs or by XML schemas converted to C/C++ source code by wsdl2h, or by using the JSON libraries included with gSOAP to develop JSON applications.
Furthermore, the gSOAP tools can be just as easily used to develop C/C++ applications that efficiently consume and produce XML by leveraging XML data bindings for C/C++ based on XML schemas. Basically, an XML schema has an equivalent set of C/C++ data types for the components described by the schema. So XML schema strings are just C/C++ strings, XML schema enumerations are C/C++ enums, XML schema complex types are just structs and classes in C/C++, and so on. This enhances the reliability and safety of XML applications, because type-safe serializable C/C++ data types are serialized and validated in XML automatically.
This XML data binding means that your XML data is simply represented as C/C++ data. Reading and writing XML is a lot easier than using a DOM or SAX library for XML. This is not more expensive or more complex than it sounds. In fact, the generated XML serializers are very efficient to parse and validate XML and may run more than 30 times faster than validating XML parsers such as Apache Xerces C++.
In summary, gSOAP offers a type-safe and transparent approach to develop XML applications that has proven to be quicker to develop (by auto-coding), safer (by XML validation and type-safety), more reliable (by auto-generation of XML test messages and warnings), and higher performing (by efficient serializers and XML parsers generated in C/C++), compared to DOM and SAX libraries.
This user guide explains the gSOAP tools and libraries. This user guide and additional documentation for the growing number of gSOAP plugins can be found at https://www.genivia.com/doc. A getting-started guide for developers is available at https://www.genivia.com/dev.html with a tutorial on common topics at https://www.genivia.com/tutorials.html. Various examples ranging from simple calculator service APIs to very large protocols spanning dozens of WSDLs can be found at https://www.genivia.com/examples.html. For frequently asked questions see https://www.genivia.com/resources.html for help.
The typographical conventions used by this document are:
Courier
denotes C and C++ source code.Courier
denotes XML content, JSON content, file and path names, and URIs.Courier
denotes HTTP content, text file content, and shell commands with command line options and arguments.The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC-2119.
gsoap/samples/xml-rpc-json
folder in the gSOAP package and the XML-RPC and JSON documentation.DEBUG
mode traces their engine activity for debugging, verifies memory usage (leak detection), and saves message logs for inspection.soapcpp2 -T
generates server source code that automatically implements echo message services for testing. The testmsgr
tool generates XML messages from message templates for server-side and client-side black-box testing, see Test Messenger documentation. In addition, the soapcpp2 tool generates sample SOAP/XML input and output messages for verification and testing.The API documentation is broken down into the following functional documentation modules that drill down into the lower-level API of macros, functions, context and context variables, plugins and more:
Debugging and logging | This module defines compile-time flags and functions for run-time debugging and logging |
WITH_MACRO compile-time flags | This module defines the WITH_MACRO compile-time flags to configure the engine build |
SOAP_MACRO compile-time values | This module defines the SOAP_MACRO compile-time values to configure the engine build |
SOAP_MACRO run-time flags | This module defines the SOAP_MACRO run-time soap_mode flags to set the engine mode |
SOAP_MACRO run-time error codes | This module defines the SOAP_MACRO run-time soap_status error codes returned by functions and stored in soap::error |
Context with engine state | This module defines the soap context structure with the engine state and functions to allocate, initialize, copy and delete contexts |
Callback functions | This module defines the callback functions of the soap context to modify its behavior, as is done by plugins |
SSL/TLS context and functions | This module defines functions to set the SSL/TLS context for HTTPS and WS-Security |
HTTP and IO functions | This module defines functions for HTTP operations and functions for receiving and sending data |
HTTP cookie functions | This module defines functions to set and get HTTP cookies at the server side |
Conversion functions | This module defines conversion functions of values of various types to and from strings |
XML namespace tables | This module defines the Namespace XML namespace structure and function to activate a table |
Header structure and functions | This module defines the SOAP_ENV__Header structure and soap_header function to allocate the header |
Fault structure and functions | This module defines the SOAP_ENV__Fault structure and functions to set and get fault information |
DIME attachment functions | This module defines functions to set and get DIME attachments |
MIME attachment functions | This module defines functions to set and get MIME/MTOM attachments |
Plugins and plugin registry functions | This module defines plugin registry functions to register plugins |
Thread and mutex functions | This module defines portable thread and mutex functions |
Miscellaneous functions | This module defines other useful functions |
To start using gSOAP, you will need:
The gSOAP source code package includes:
wsdl2h
data binding tool that converts WSDLs and XSDs to generate interface header files for soapcpp2. The source code of the wsdl2h tool is located in gsoap/wsdl
.soapcpp2
code generation tool that takes an interface header file and generates the C/C++ Web service binding implementation source code. The source code of the soapcpp2 tool is located in gsoap/src
.gsoap/stdsoap2.h
and source code gsoap/stdsoap2.c
for C and gsoap/stdsoap2.cpp
for C++. These are compiled into the C libraries gsoap/libgsoap.a
(without OpenSSL/GNUTLS for SSL/TLS), gsoap/libgsoapssl.a
(with OpenSSL/GNUTLS for SSL/TLS and with gsoap/dom.c
for DOM API), and the C++ libraries gsoap/libgsoap++.a
(without OpenSSL/GNUTLS for SSL/TLS), gsoap/libgsoapssl++.a
(with OpenSSL/GNUTLS for SSL/TLS and with gsoap/dom.cpp
for DOM API). There are two more versions of these libraries with HTTP cookies enabled.gsoap/samples
.gsoap/samples/dom
, see also the XML DOM API and domcpp documentation.gsoap/samples/xml-rpc-json
, see also the XML-RPC and JSON documentation.gsoap/samples/testmsgr
, see also the Test Messenger documentation.gsoap/plugin
and gsoap/mod_gsoap
. Most but not all plugins are imported into interface header files for soapcpp2 with the #import
directive. See also API documentation Module Plugins and plugin registry functions.gsoap/custom
. Custom serializers are imported into interface header files for soapcpp2 with the #import
directive. This is usually done via a typemap.dat
file for wsdl2h that specifies bindings for XML schema types to C/C++ types, including custom serializers when desired.The wsdl2h and soapcpp2 tools and the gSOAP libraries are build with ./configure
and make
, see the download and installation page https://www.genivia.com/downloads.html for the most recent versions of gSOAP and gSOAP software installation details. The examples and other tools are build with ./configure --enable-samples
and make
.
Non-SSL-enabled (that is, not HTTPS capable) versions of the binaries of the wsdl2h and soapcpp2 tools are also included in the gSOAP package in gsoap/bin
for Windows and Mac OS platforms. The SSL-enabled and HTTPS-capable wsdl2h tool is only available for download from https://www.genivia.com/downloads.html with a commercial-use license and download key.
Although gSOAP tools are available in binary format for several platforms, the code generated by these tools is equivalent. This means that the generated source code files can be transferred between platforms and locally compiled.
The examples given in this document do not require the libraries of the engine to be build, but rather show the use of the source code: gsoap/stdsoap2.c
and gsoap/dom.c
(or gsoap/stdsoap2.cpp
and gsoap/dom.cpp
for C++). Using the source code instead of the libraries gives more control when we use the -DWITH_MACRO
and -DSOAP_MACRO
compile-time options, see also Modules WITH_MACRO compile-time flags and SOAP_MACRO compile-time values.
Introductory examples can be found online at https://www.genivia.com/dev.html. Additional examples can be found online at https://www.genivia.com/examples.html.
The gSOAP package also contains numerous examples in the gsoap/samples
directory. Run make
inside these directories to build the example applications. The examples are meant to demonstrate basic to advanced features of gSOAP. Some examples are actually development tools and libraries, such as Test Messenger located in gsoap/samples/testmsgr
to test XML Web APIs, the XML DOM API and domcpp located in gsoap/samples/dom
to generate XML DOM API source code from XML files, the JSON API and jsoncpp located in gsoap/samples/xml-rpc-json
to generate JSON API source code from JSON files.
Advanced examples include a streaming MTOM attachment server and client application demonstrate high-performance file exchanges, located in gsoap/samples/mtom-stream
. An SSL-secure Web server application demonstrates the generation of dynamic content for Web browsing and Web services functionality at the same time, located in gsoap/samples/webservice
.
This section explains the basics to develop a SOAP/XML client application in C and C++. We refer to https://www.genivia.com/dev.html for additional introductory examples of SOAP/XML, XML REST and JSON applications in C and C++.
The wsdl2h tool imports one or more WSDLs and XML schemas and generates a gSOAP interface file for soapcpp2 with familiar C/C++ header file syntax to define the Web service operations and the C/C++ data types. The soapcpp2 tool then takes this header file and generates XML serializers for the data types (soapStub.h
, soapH.h
, and soapC.cpp
), the client-side stub functions (soapClient.cpp
), and server-side skeleton functions (soapServer.cpp
).
The soapcpp2 tool can also generate WSDL definitions to implement a service from scratch, i.e. without defining a WSDL first. This "closes the loop" in that it enables Web services development from WSDL or directly from a set of C/C++ operations declared as functions in an interface header file for soapcpp2 without the need for users to be experts in WSDL and XSD.
You only need to follow a few steps to execute the tools from the command line or using a Makefile (see also MSVC++ project examples in the gsoap/samples
directory with tool integration in the MSVC++ IDE). For example, to generate code for the calculator Web service, we run the wsdl2h tool from the command line on the URL of the WSDL and use wsdl2h -o calc.h
option -o calc.h
to specify the calc.h
interface file to output:
wsdl2h -o calc.h http://www.genivia.com/calc.wsdl
This generates the calc.h
service definition interface file with service operation definitions and types to pass with the operation parameters. This interface file is then input to the soapcpp2 tool to generate the stub and skeleton source code and XML serialization functions. The calc.h
file includes documentation extracted form the WSDL and introductions to process the file with soapcpp2. You can use Doxygen (http://www.doxygen.org) to automatically generate the documentation pages for your development from the generated calc.h
interface file. To generate a markdown report for your client, use soapcpp2 -r
option -r
which has more details than the calc.h
file.
In this example we will develop a C++ API for the calculator service. By default, the wsdl2h tool generates C++ with containers and other C++ std
data types. To build without C++ containers and other std
types, use wsdl2h -s
option -s
:
wsdl2h -s -o calc.h http://www.genivia.com/calc.wsdl
.vcproj
, please set CompileAs="2"
in your .vcproj
file.We have not yet generated the stub functions and serializers for our C++ client application to invoke remote service operations. To do so, we run the soapcpp2 tool as follows:
soapcpp2 -j -C -Iimport calc.h
Option -j
(and alternatively option -i
) indicates that we want C++ proxy and server objects that include the client (and server) code, option -C
indicates client-side only files are generated (soapcpp2 generates both client stub functions and server skeleton functions by default). Option -I
is needed to import the stlvector.h
file from the gsoap/import
directory located in the gSOAP source code package to support serialization of vectors, when applicable.
We use the generated soapcalcProxy
class declared and defined in soapcalcProxy.h
and soapcalcProxy.cpp
, and calc.nsmap
XML namespace mapping table to access the Web service. The soapcalcProxy.h
file includes documentation on the proxy class. The soapcalcProxy
class is a proxy to invoke the remote service:
To complete the build, compile the code above and compile this with the generated soapC.cpp
and soapcalcProxy.cpp
files, and link the engine with -lgsoap++
:
c++ -o calcclient calcclient.cpp soapcalcProxy.cpp soapC.cpp -lgsoap++
Alternatively, compile gsoap/stdsoap2.cpp
:
c++ -o calcclient calcclient.cpp soapcalcProxy.cpp soapC.cpp stdsoap2.cpp
In both cases it is assumed that stdsoap2.h
and the soapcpp2-generated soapcalcProxy.h
, soapStub.h
, soapH.h
, and calc.nsmap
files are located in the current directory.
Then run the example:
./calcclient The sum of 1.0 and 2.0 is 3
To build a pure C application, use wsdl2h -c
option -c
and run soapcpp2 -C
to generate the client stub functions and serializers:
wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl soapcpp2 -C -Iimport calc.h
In this case our code uses a simple C function call to invoke the service and we also need to explicitly delete data and the context with soap_end
and soap_free
:
To complete the build, compile the code above and compile this with the generated soapC.c
and soapClient.c
files, and link the engine with -lgsoap
:
cc -o calcclient calclient.c soapClient.c soapC.c -lgsoap
Alternatively, compile gsoap/stdsoap2.c
:
cc -o calcclient calclient.c soapClient.c soapC.c stdsoap2.c
In both cases it is assumed that stdsoap2.h
and the soapcpp2-generated soapStub.h
, soapH.h
, and calc.nsmap
files are located in the current directory.
Then run the example:
./calcclient The sum of 1.0 and 2.0 is 3
The calculator example is fairly simple and used here to illustrate the development steps from code generation to running the application. The development steps for large-scale XML applications is similar.
See https://www.genivia.com/dev.html for additional introductory examples of SOAP/XML, XML REST and JSON applications in C and C++. See https://www.genivia.com/examples and the examples located in the gSOAP source code package in the gsoap/samples
directory.
This section explains the basics to develop a SOAP/XML service application in C and C++. We refer to https://www.genivia.com/dev.html for additional introductory examples of SOAP/XML, XML REST and JSON applications in C and C++.
Developing a service application is easy. In this example we will demonstrate a service deployed with the Common Gateway Interface (CGI) because it is a simple mechanism. This is not the preferred deployment mechanism. Because CGI is slow and stateless. FastCGI improves the speed of CGI applications, but is still stateless. Faster services can be developed as a stand-alone gSOAP HTTP/HTTPS servers as explained in this section further below.
To deploy services in a public and possibly hostile environment, we recommend the use of Apache module or IIS ISAPI extension to manage and protect services. An Apache module plugin and ISAPI extension plugin is included in the gSOAP package under gsoap/mod_gsoap
. For details, see:
To deploy gSOAP stand-alone services in a public environment make sure to protect your service application as explained in Sections Safety guards and Timeout management for non-blocking operations. See also our tutorials https://www.genivia.com/tutorials.html with instructions to protect your online gSOAP Web APIs.
Let's get started. Suppose we want to implement a simple CGI-based service that returns the time in GMT. For this example we start with an interface header file for soapcpp2, currentTime.h
which contains the service definitions. Such a file can be obtained from a WSDL using wsdl2h when a WSDL is available. When a WSDL is not available, you can define the service in C/C++ definitions in a newly created interface header file and let the soapcpp2 tool generate the source code and WSDL for you.
The currenTime
service operation of our Web service has only one output parameter, which is the current time defined in our currentTime.h
service specification:
Note that we associate an XML namespace prefix ns
and namespace name urn:currentTime
with the service WSDL and SOAP/XML messages. The gSOAP tools use a special convention for identifier names that are part of a namespace: a namespace prefix (ns
in this case) followed by a double underscore __
. This convention is used to resolve namespaces and to avoid name clashes. The ns
namespace prefix is bound to the urn:currentTime
namespace name with the //gsoap
directive. The //gsoap
directives are used to set the properties of the service, in this case the name, namespace, and location endpoint.
The service implementation for CGI simply requires a soap_serve
call on a soap
context created with soap_new
. The service operations are implemented as functions, which are called by the service skeleton functions via the service request dispatcher soap_serve
:
Note that we pass the soap
context with the engine context information to the service operation function as the first argument. The soap
context comes in handy to determine properties of the connection and to dynamically allocate data with soap_malloc
or with the generated soap_new_T
functions for serializable types T
that will be automatically deleted by calling soap_destroy
and soap_end
when the service operation is done and the service loop rolls over.
We run the soapcpp2 tool on the header file to generate the server-side code:
soapcpp2 -S currentTime.h
and then compile the CGI binary:
c++ -o currentTime.cgi currentTime.cpp soapServer.cpp soapC.cpp stdsoap2.cpp
To activate the service, copy the currentTime.cgi
binary to your bin-cgi
directory and set the proper file permissions.
The soapcpp2 tool generated the WSDL definitions currentTime.wsdl
. You can use the WSDL to advertise your service. You don't need to use this WSDL to develop a gSOAP client. You can use the currentTime.h
file with soapcpp2 -C
option -C
to generate client-side code.
Since CGI is very simple, a convenient aspect of CGI is that it exchanges messages over standard input and output. Therefore, you can run the CGI binary on the auto-generated example request XML file currentTime.currentTime.req.xml
to test your server:
./currentTime.cgi < currentTime.currentTime.req.xml
and this displays the HTTP server response:
Status: 200 OK Server: gSOAP/2.8 X-Frame-Options: SAMEORIGIN Content-Type: text/xml; charset=utf-8 Content-Length: 460 Connection: close
The above approach works also for C. Just use soapcpp2 -c -S
option -c
in addition to the -S
option to generate C code. Of course, in C we use pointers instead of references and the currentTime.h
file should be adjusted to use C syntax and types.
Run soapcpp2 -r -c -S
option -r
to generate a soapReadme.md
report. This report includes many details about the service operations and serializable C/C++ data types declared in the interface header file. This markdown file can be converted to HTML or other document formats with tools such as Doxygen.
A more elegant server implementation in C++ can be obtained by using soapcpp2 -j -S
option -j
(or option -i
) to generate C++ client-side proxy and server-side service objects as classes that you can use to build clients and services in C++. The option removes the generation of soapClient.cpp
and soapServer.cpp
, since these are no longer needed when we have classes that implement the client and server logic:
soapcpp2 -j -S currentTime.h
This generates soapcurrentTimeService.h
and soapcurrentTimeService.cpp
files, as well as auxiliary files soapStub.h
, soapH.h
, and soapC.cpp
and currentTime.nsmap
. The soapcurrentTimeService.h
file includes documentation on the service class.
Now using the currentTimeService
class we can improve the CGI service application:
We compile this with:
c++ -o currentTime.cgi currentTime.cpp soapcurrentTimeService.cpp soapC.cpp stdsoap2.cpp
and install the binary as a CGI application.
To run the server as a stand-alone iterative (i.e. non-multi-hreaded) server on port 8080 until a the accept times out or an error occurs:
To run the server as a stand-alone iterative server on port 8080 while ignoring common errors until a TCP occurs:
To implement stand-alone and multi-threaded services, see Sections How to create a stand-alone server and How to create a multi-threaded stand-alone service. These stand-alone Web Services handle multiple SOAP requests by spawning a thread for each request. Thread pooling is also an option. The use of Apache modules and ISAPI extensions to deploy gSOAP services is recommended to ensure load balancing, access control, tracing, and so on.
For more information on server-side service classes, see Section How to generate C++ server classes . For more information on client-side proxy classes, see Section How to generate C++ client proxy classes .
See https://www.genivia.com/dev.html for additional introductory examples of SOAP/XML, XML REST and JSON applications in C and C++. See https://www.genivia.com/examples and the gSOAP source code package gsoap/samples
for more examples.
This section is a basic introduction to XML data bindings in C/C++. Because gSOAP offers many options to implement XML data bindings, we wrote a separate C and C++ XML data bindings document on this topic that contains an in-depth discussion of XML schema mappings to C/C++ types, using wsdl2h with typemap.dat
to customize these bindings, memory management to allocate and release serializable types, and how to use soapcpp2 options to generate deep data structure copy and delete functions for serializable types.
Basically, the C/C++ XML data binding in gSOAP provides and automated mechanism to serialize any C and C++ data structure in XML and to deserialize XML back into C/C++ data structures. To facilitate XML data bindings, a WSDL or an XML schema (XSD file) can converted with wsdl2h into a set of serializable C or C++ data type declarations. These C/C++ type declarations can be readily incorporated into your application to manipulate XML directly as C/C++ data structures with much more ease than DOM or SAX. For example, XML schema strings are just C/C++ strings, XML schema enumerations are C/C++ enums, XML schema complex types are just structs or classes in C/C++, and so on. In this way, an automatic mapping between XML elements of the XML schema and members of a class is created. No DOM traversals and SAX events are needed.
More importantly, the XML C/C++ data binding makes XML manipulation type safe. That is, the type safety of C/C++ ensures that only valid XML documents can be parsed and generated.
The wsdl2h tool performs the mapping of WSDL and XML schemas to C and/or C++ automatically. The output of wsdl2h is a "data binding interface file" which is simply an annotated C/C++ header file with the serializable C/C++ data types that represent XML schema components. This file also includes comments and documentation of the serializable data types. For WSDLs, also functions are declared in this interface file that represent XML Web services operations.
Let's illustrate XML data bindings with an example. Suppose we have an XML document with a book record:
An example XML schema (XSD file) that defines the book element and type could be:
Now, using wsdl2h we translate this XML schema that defines the book type and root element into a C++ class definition:
Note that annotations such as @
are used to distinguish attributes from elements. These annotations are gSOAP-specific and are handled by the soapcpp2 tool that reads this generated interface file and generates the XML data binding implementation with serializers for the data types declared in the interface file.
That is, the soapcpp2 tool generates all the necessary code to parse and generate XML for book
objects. Validation constraints such as minOccurs="1"
and use="required"
are included in the generated code as checks that are enforced with the SOAP_XML_STRICT
flag.
To write the XML representation of a book object instantiated in our C++ application, we first create a soap
engine context and use it with soap_write_book
(a function generated by soapcpp2) to write the object in XML to standard output:
The soap
context holds the engine state and run-time flags, such as SOAP_XML_INDENT
, serialization options, and other I/O settings. This means that we can simply set the output file descriptor int soap::sendfd
or output stream std::ostream* soap::os
of the context to redirect the content to a file or string. Also, when serializing a graph with SOAP_XML_GRAPH
rather than an XML tree, the XML output contains id-ref attributes to reference nodes in the XML graph, similar to the way SOAP encoding with multi-reference id-ref/href works, see Section How to use XML serializers to save and load application data for details.
To read the XML representation from standard input into a book class instance:
Automatic built-in strict XML validation is enabled with SOAP_XML_STRICT
, which ensures that data members are present so we can safely print them in this example, thus ensuring consistency of data with the XML schema.
We can set the int soap::recvfd
file descriptor or the std::istream* soap::is
input stream to read from a file or string stream instead of stdin.
The soap_destroy
and soap_end
calls deallocate the deserialized data, so use these with care. Memory management is automatic in gSOAP to avoid leaks.
The above example uses a very simple example schema. The gSOAP toolkit handles all XML schema constructs defined by the XML schema standard. The toolkit is also able to serialize pointer-based C/C++ data structures, including cyclic graphs, structs/classes, unions, enums, containers, and even special data types such as struct tm
. Therefore, the toolkit works in two directions: from WSDL/schema to C/C++ and from C/C++ to WSDL/schema.
The gSOAP toolkit also handles multiple schemas defined in multiple namespaces. Normally the namespace prefixes of XML namespaces are added to the C/C++ type definitions to ensure type uniqueness. For example, if we would combine two schemas in the same application where both schemas define a book
object, we need to resolve this conflict. In gSOAP this is done using namespace prefixes, rather than C++ namespaces (research has pointed out that XML namespaces are not equivalent to C++ namespaces). Thus, the book
class might actually be bound to an XML namespace and the class would be named ns__book
, where ns
is bound to the corresponding namespace.
For example, the following run-time flags are available to control serialization as an XML tree or graph:
Other flags can be used to format XML, see Section Run-time flags .
For more details on XML databinding support for C and C++, see Section How to use XML serializers to save and load application data and the C and C++ XML data bindings document.
This section of the user guide presents a quick overview to get started with gSOAP. In principle, XML SOAP and REST clients and services can be developed in C and C++ with the soapcpp2 tool without a detailed understanding of XML, XML schema, WSDL, and the XML SOAP protocol.
The implementation of a client application that invokes remote service operations by serializing application data in XML for the remote operation request, also called XML marshalling in remote procedure calling. This requires a "stub function", also called "service proxy", for each service operation that the client invokes. The primary stub's responsibility is to serialize the parameter data in XML, send the request with the parameters to the designated SOAP service over the wire, to wait for the response, and to deserialize the parameter data of the response when it arrives. With the stub function in place, the client application invokes a remote service operation as if it would invoke a local function. To write a client stub function in C or C++ by hand is a tedious task, especially if the input and output parameters of a service operation contain elaborate data structures that must meet XML validation constraints. Fortunately, the wsdl2h tool and soapcpp2 tool automate the development of SOAP/XML Web service client and server applications.
The soapcpp2 tool generates the necessary gluing code (the client stub functions and server skeleton functions) to build web service clients and services. The input to the soapcpp2 tool consists of an interface file with familiar C/C++ header file syntax. This interface header file can be automatically generated from a WSDL (Web Service Description Language) documentation of a service with the gSOAP wsdl2h tool.
The following command:
wsdl2h -o calc.h http://www.genivia.com/calc.wsdl
generates the calc.h
interface header file for soapcpp2. The WSDL specification may consist of multiple imported WSDL files and XSD schema files. The WSDLs and XSDs are then translated to C or C++, replacing WSDL service operation by C/C++ functions and XML schema data types by C/C++ data types.
To generate C code, we use wsdl2h -c
option -c
:
wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
For more details on the wsdl2h tool and its options, see Section The wsdl2h tool .
When upgrading gSOAP to a newer version it is often not necessary to perform this first step again, since newer versions are backward compatible to previous interface header files generated by wsdl2h.
Looking into the file calc.h
we see that the SOAP service methods are specified as function prototypes. For example, the add
function to add two doubles is declared as:
The ns2__add
function uses an XML namespace prefix to distinguish it from operations defined in other namespaces, thus nicely preventing name clashes in this way. The convention to add an XML namespace prefix to the names of operations, types, and struct
and class
members is universally used by the gSOAP tools and automatically added by wsdl2h.
Next, the calc.h
header file is input to the soapcpp2 tool to generate the gluing code's logic to invoke the Web service from a client application:
soapcpp2 calc.h
The function prototypes in calc.h
are converted by the soapcpp2 tool to stub functions for remote calls:
soapStub.h
annotated copy of the header file's definitions.soapH.h
XML serializers declarationssoapC.cpp
XML serializers implementationssoapClient.cpp
the client calling stub functionsThe logic of the generated soapClient.cpp
stub functions allow client applications to seamlessly interact with existing SOAP Web services as illustrated by the client code example in the next section.
The input and output parameters of a service operation may be primitive data types or compound data types, such as containers and pointer-based linked data structures. These are defined in the interface header file, which is either generated by the wsdl2h tool or it may be specified by hand. The soapcpp2 tool automatically generates XML serializers and XML deserializers for these data types to enable the generated stub functions to serialize the contents of the parameters of the service operations in XML.
The soapcpp2 tool also generates "skeleton functions" soapServer.cpp
for each of the service operations specified in the interface header file. The skeleton functions can be readily used to implement one or more of the service operations in a new XML Web service.
To develop C++ client applications, a useful option to use with soapcpp2 is -j
to generate proxy classes to invoke services, instead of global functions:
soapcpp2 -j calc.h
The function prototypes in calc.h
are converted by the soapcpp2 tool to the following function:
soapStub.h
annotated copy of the header file's definitions.soapH.h
XML serializers declarationssoapC.cpp
XML serializers implementationssoapcalcProxy.h
the client proxy classsoapcalcProxy.cpp
the client proxy class implementationTo use the proxy class, #include "soapcalcProxy.h"
and compile and link soapcalcProxy.cpp
. See the following section.
The add
service operation declared in the calc.h
file obtained with the wsdl2h tool in the previous section, adds two doubles. The WSDL description of the service provides the endpoint to invoke the service operations and the XML namespace used by the operations:
http://example.com/service.cgi
urn:calc
Each SOAP-specific service operation also has a "SOAP action", which is an optional string to identify the operation, which is mainly used with WS-Addressing. The request and response messages for SOAP RPC-encoded services are simply represented by C functions with input and output parameters. For the add
operation, the SOAP binding details are:
This information is translated to the wsdl2h-generated interface header file with the service definitions. The calc.h
header file for C++ generated by wsdl2h contains the following directives and declarations:
The actual contents may vary depending on the release version and the options used to control the output.
The other calculator service operations are similar and were elided for clarity.
The //gsoap
directives are interpreted by the soapcpp2 tool to generate code that is compliant to the SOAP protocol. For this service the SOAP protocol with the "SOAP 1.1 RPC encoding style" is used. This produces XML messages with the familiar SOAP envelope and body in the SOAP 1.1 namespace and a SOAP-ENV:encodingStyle
attribute for SOAP RPC encoding (a simple XML serialization format) as can be seen in the XML request message:
Another style is "document/literal" which is also defined by SOAP 1.1/1.2.
To use SOAP document/literal style is indicated for each service operation as follows in the interface file specification, which also switches to the SOAP 1.2 protocol:
This produces XML messages with the familiar SOAP envelope and body with the SOAP 1.2 namespace and without the encodingStyle attribute as can be seen in the XML request message:
REST instead of SOAP is specified with HTTP
instead of SOAP
with the //gsoap <prefix> service method-protocol:
directive to carry our XML messages using the HTTP POST method without a SOAP envelope:
This produces non-SOAP XML messages with HTTP POST. For example:
Likewise you can specify POST
, PUT
, and GET
HTTP methods for direct XML messaging instead of SOAP
. However, all XML Web services protocols such as WS-Security and WS-Addressing require SOAP to include the SOAP Headers.
Note that the function declaration itself and the client-side calling stub and server-side skeleton functions are unchanged. The internals of the generated functions are changed to accommodate the protocol specified with the directives.
For more details about the //gsoap
directives, see Section Directives .
So as you can see, the Web service operations are declared as function prototypes. When the parameters of the function are structs and classes, then all of these interdependent data types are included in the wsdl2h-generated header file.
In this simple example the parameters are primitive types. The calculator add
operation takes two double floats a
and b
, and returns the sum in result
. By convention, all parameters are input parameters except the last parameter which is an output parameter or specified as void
for one-way messages. The last parameter is always a single output parameter, if not void
. A struct
or class
is used to wrap multiple output parameters, see also Section How to specify multiple output parameters . This last parameter must be a pointer or reference. By contrast, the input parameters support pass by value or by pointer, but not pass by C++ reference due to complications when generating compilable source code for the stub and skeleton functions.
The function prototype associated with a service operation always returns an int
. The return value indicates success with SOAP_OK
(zero) or failure with a nonzero value. See Section Run-time error codes for the error codes.
The role of the namespace prefix (ns2__
) in the service operation name specified as a function prototype associates an XML namespace with the service operation as a qualified name, i.e. qualified by means of a namespace prefix. This is discussed in detail in Section XML namespace considerations . Basically, the namespace prefix is added to a function name or type name with a pair of underscores, as in ns2__add
, where ns2
is the namespace prefix and add
is the service operation name. This mechanism ensures uniqueness of operations and types associated with a service.
When using wsdl2h it is strongly recommended to set the namespace prefix to a name of your choice by modifying the typemap.dat
file that is used by wsdl2h. This file can be copied from gsoap/typemap.dat
and modified in the local directory where you run wsdl2h. This avoids problems when running wsdl2h on multiple WSDLs where the sequence of prefixes ns1
, ns2
, and so on are arbitrarily assigned to the services. To choose a prefix name for all the operations and types of a service, say prefix c__
for the calculator service, add the following line to typemap.dat
:
c = "urn:calc"
and rerun wsdl2h. Moreover, the typemap.dat
configures wsdl2h to use specific bindings and data types for services. The result is that c__add
is used to uniquely identify the operation rather than the more arbitrary name ns2__add
.
A note on the use of underscores in names: a single underscore in an identifier name will be translated into a dash in XML, because dashes are more frequently used in XML compared to underscores, see Section C/C++ identifier name to XML tag name translation . Double underscores separate the namespace prefix from the unqualified part of the qualified name.
Next, the soapcpp2 tool is invoked from the command line to process the calc.h
service definitions:
soapcpp2 calc.h
The tool generates the client stub functions for the service operations. Stub functions can be invoked by a client program to invoke the remote service operations. The interface of the generated stub function is identical to the function prototype in the calc.h
service definition file, but with additional parameters to pass the engine's context soap
, an endpoint URL (or NULL for the default), and a SOAP action (or NULL for the default):
This stub function is saved in soapClient.cpp
. The file soapC.cpp
contains the serializer and deserializer functions for the data types used by the stub. You can use wsdl2h -c
option -c
to generate pure C code. Likewise, soapcpp2 -c
option -c
generates pure C code, if the input interface file is written in C of course.
The soap
parameter of the stub function shown above must be a valid pointer to a soap
context. The URL
parameter when non-NULL overrides the default endpoint address defined by the WSDL and the //gsoap <prefix> service port:
directive. The action
parameter when non-NULL overrides the default SOAP action defined by the WSDL and the //gsoap <prefix> service method-action:
directive.
The following example C/C++ client program uses the generated stub function to invoke the remote service operation:
The soap_call_c__add
call returns SOAP_OK
(zero) on success and a nonzero error on failure. When an error occurred you can print the fault message with the soap_print_fault(struct soap*, FILE*)
function. Use soap_sprint_fault(struct soap*, char *buf, size_t len)
to save the fault message to a string buffer buf[0...len-1]
. Use soap_stream_fault(struct soap*, std::ostream&)
to send the fault message to a stream.
The following functions are used to explicitly set up a soap
context and finalize it:
soap_new()
allocates, initializes, and returns a pointer to a new soap
context.soap_new1(soap_mode mode)
allocates, initializes and sets both in- and out-mode flags to the same mode, and returns a pointer to a new soap
context.soap_new2(soap_mode imode, soap_mode omode)
allocates, initializes and sets in- and out-mode flags, and returns a pointer to a new soap
context.soap_copy(struct soap*)
allocates and returns a new context by copying the given context with soap_copy_context
, such that the new context returned does not share any data with the given context.soap_init(struct soap*)
initializes a stack-allocated soap
context in C, when not using soap_new
, for C++ use the soap
constructors instead.soap_init1(struct soap*, soap_mode mode)
initializes a stack-allocated soap
context, when not using soap_new1
, and sets both in- and out-mode flags to the same mode, for C++ use the soap
constructors instead.soap_init2(struct soap*, soap_mode imode, soap_mode omode)
initializes a stack-allocated soap
context, when not using soap_new2
, and sets in- and out-mode flags, for C++ use the soap
constructors instead.soap_done(struct soap*)
finalizes a context but does not delete the specified soap
context (for example when stack-allocated). The context can be re-initialized afterwards with soap_init
. In C++, a stack-allocated context invokes this function in its destructor when the context is deleted.soap_free(struct soap*)
finalizes and deletes the given context, when created with soap_new
or soap_copy
.A soap
context can be reused as many times as necessary and does not need to be reinitialized when doing so. However, a new context is required for each thread that runs independently to guarantee exclusive access to a soap
context by each thread.
Also the use of any client calls within an active service operation implemented at the server side requires a new context, since soap_serve
is still processing with the current soap
context that must be maintained while the service operation and response has not been completed yet.
The soapcpp2 code generator tool generates a service proxy class for C++ client applications (and service objects for server applications) with the soapcpp2 -j
option -j
(or -i
option):
soapcpp2 -j calc.h
The proxy is defined in:
soapcalcProxy.h
client proxy classsoapcalcProxy.cpp
client proxy classWithout the -j
option, C-like soapClient.cpp
and soapServer.cpp
source codes are is generated. Use option -i
as an alternative to -j
to generate classes with the same functionality, but that are inherited from the soap
struct. With the -j
option, the soap
engine context is a pointer member of the generated proxy and service classes and can therefore be shared with other proxy or service class instances. The choice of option to use is application-dependent, but the choice is also important when services are chained to serve requests on the same server port, see Section How to chain C++ server classes to accept messages on the same port .
The generated C++ proxy class initializes the context and offers the service interface as a collection of methods:
The proxy constructor takes context mode parameters to initialize the context, e.g. SOAP_XML_INDENT
in this example.
The code is compiled and linked with soapcalcProxy.cpp
, soapC.cpp
, and gsoap/stdsoap2.cpp
.
The proxy class name is extracted from the WSDL content and may not always be in a short format. You can change this directive to customize the service name:
then rerun soapcpp2 to generate code that uses the new name.
When the example client application is invoked, a SOAP request is performed:
POST /~engelen/calcserver.cgi HTTP/1.1 Host: websrv.cs.fsu.edu User-Agent: gSOAP/2.8 Content-Type: text/xml; charset=utf-8 Content-Length: 464 Connection: close SOAPAction: ""
The SOAP response message is:
HTTP/1.1 200 OK Date: Wed, 05 May 2010 16:02:21 GMT Server: Apache/2.0.52 (Scientific Linux) Content-Length: 463 Connection: close Content-Type: text/xml; charset=utf-8
A client can invoke a sequence of service operations, like so:
In the example shown above, no deserialized data is deallocated until calc.destroy()
. To deallocate deserialized data between the calls we change the loop as follows:
Deallocation is safe here, since the float values were copied and saved in sum
. In other scenarios we should make sure data is copied to local data structures when the data should be preserved. There are tooling options for deep copy and delete of entire data structures to simplify this task, see Section Generating deep copy and deletion functions.
To delegate deletion to another context for later removal, use soap_delegate_deletion(struct soap *soap_from, struct soap *soap_to)
. For example:
In C we use wsdl2h -c
option -c
to generate C. The example client calculator program would be written as:
The code above is compiled and linked with the soapcpp2-generated soapClient.c
and soapC.c
files, and gsoap/stdsoap2.c
(or compile with -bgsoap
).
The declaration of the ns2__add
function prototype discussed in the previous section uses the namespace prefix ns2__
of the service operation XML namespace, which is distinguished by a pair of underscores in the function name to separate the namespace prefix from the service operation name. The purpose of a namespace prefix is to associate a service operation name with a service in order to prevent naming conflicts, e.g. to distinguish identical service operation names used by different services.
Note that the XML response of the service example uses a namespace prefix that may be different (e.g. ns
) as long as it bound to the same namespace name urn:calc
through the xmlns:ns="urn:calc"
binding. The use of namespace prefixes and namespace names is also required to enable SOAP applications to validate the content of SOAP messages. The namespace name in the service response is verified by the stub function by using the information supplied in a namespace mapping table that is required to be part of gSOAP client and service application codes. The table is accessed at run time to resolve namespace bindings, both by the generated stub's data structure serializer for encoding the client request and by the generated stub's data structure deserializer to decode and validate the service response. The namespace mapping table should not be part of the header file input to the soapcpp2 tool. Service details including namespace bindings may be provided with gSOAP directives in a header file, see Section Directives .
The namespace mapping table is:
The first four namespace entries in the table consist of the standard namespaces used by the SOAP protocol. In fact, the namespace mapping table is explicitly declared to enable a programmer to specify the SOAP encoding style and to allow the inclusion of namespace-prefix with namespace-name bindings to comply to the namespace requirements of a specific SOAP service. For example, the namespace prefix ns2
, which is bound to urn:calc
by the namespace mapping table shown above, is used by the generated stub function to encode the add
request. This is performed automatically by the soapcpp2 tool by using the ns2
prefix of the ns2__add
method name specified in the calc.h
header file. In general, if a function name of a service operation, struct
name, class
name, enum
name, or member name of a struct
or class
has a pair of underscores, the name has a namespace prefix that must be defined in the namespace mapping table.
The namespace mapping table will be output as part of the SOAP Envelope by the stub function. For example:
The namespace bindings will be used by a SOAP service to validate the SOAP request.
The incorporation of namespace prefixes into C++ identifier names is necessary to distinguish service operations that share the same name but are provided by separate Web services and/or organizations. It avoids potential name clashes, while sticking to the C syntax since C has no support for namespaces. The C++ proxy classes generated with soapcpp2 -j
option -j
(or option -i
) drop the namespace prefix from the method names.
The namespace prefix convention is also be applied to non-primitive types. For example, class
names are prefixed to avoid name clashes when the same name is used by multiple XML schemas. This ensures that the XML databinding never suffers from conflicting schema content. For example:
At this point you may ask why the gSOAP tools do no use C++ namespaces to implement XML namespaces. The answer is not too complicated. XML namespaces are semantically more rich than C++ namespaces. For example, XML schema complexTypes may reference elements in another schema and these elements may be qualified in XML. There could also be element name clashes when element names are the same but referenced in different schemas. In gSOAP this is resolved by naming struct
and class
members with the namespace prefix notation, thereby ensuring that name clashes among members cannot occur.
An instance of e__Address
is encoded by the generated serializer for this type as an Address element with namespace prefix e
:
While an instance of s__Address
is encoded by the generated serializer for this type as an Address element with namespace prefix s
:
The namespace mapping table of the client program must have entries for e
and s
that refer to the XML Schemas of the data types:
This table is automatically generated by soapcpp2 and saved as a .nsmap
file that can be included in the source code.
Proxy classes for C++ client applications are automatically generated by the soapcpp2 tool, as was shown in Section Example .
A new and improved code generation capability is implemented in soapcpp2 for C++ proxy classes by using soapcpp2 -j
option -j
(or option -i
). These new proxy classes have a cleaner interface and offer more capabilities compared to the gSOAP 2.7 proxy and service classes.
In C++ you can also use wsdl2h -q name
option -q name
to generate the proxy class and serializers in the specified C++ namespace name
. This is very useful if you want to create multiple proxies for services by repeated use of wsdl2h and then combine them in one code. Alternatively, you can run wsdl2h just once on all service WSDLs and have soapcpp2 generate multiple proxies for you. The latter approach does not use C++ namespaces and actually reduces the overall amount of source code by avoiding code duplication.
To illustrate the generation of a proxy class, the calc.h
header file example of the previous section used.
The namespace
directives declare the XML schema namespace and WSDL service namespace, which are the same in this example. The name
, type
, and port
directives declare service details, which are used by soapcpp2 to name the proxy class, the WSDL port type, and the service location port which is the endpoint URL of the service. The messaging transport
mode is HTTP.
The groups of four directives per service operation declare the operation SOAP style (RPC) and encoding (SOAP encoded), and SOAP action string, which is optional and used mostly for HTTP-based routing of messages and by WS-Addressing. In this example, the protocol is SOAP 1.1 RPC encoding. More recent uses of SOAP focus on document/literal style messaging, which is also declared with directives without affecting the rest of the interface header file. For //gsoap
directive details, see Section Directives .
Run soapcpp2 -j
on this interface header file with the calculator service specification to generate soapcalcProxy.cpp
and soapcalcProxy.h
with the proxy class declaration:
The above shows the raw source code with comments generated by soapcpp2. To obtain an annotated markdown document with documented the proxy and service classes and documented data types used by the service operations, run soapcpp2 -r
option -r
to generate a soapReadme.md
report. This markdown file can be converted to HTML or other document formats with tools such as Doxygen.
This generated proxy class can be included into a client application together with the generated namespace table as shown in this example:
The XML message sent by the client proxy:
The XML message returned by the service:
With soapcpp2 -j
option -j
, the constructor of the proxy class allocates and initializes a soap
context as a pointer member of the class. With soapcpp2 -i
option -i
the proxy class is derived from the soap
struct instead and this context is initialized when the proxy class constructor is invoked.
To place the proxy class in a C++ namespace name
, use soapcpp2 -q name
option -q name
. See Section soapcpp2 options.
XML Web services use XML schemas to define the data types of XML data structures in the XML message payloads. The default encoding assumed by soapcpp2 is SOAP 1.1 document/literal style messaging but this is easily changed using options, such as -2
(SOAP 1.2), -0
(non-SOAP XML REST), and -e
(SOAP with RPC encoding). See Section soapcpp2 options.
Primitive XSD types are mapped to C/C++ primitive types by means of typedef
declarations in the interface header file for soapcpp2 to generate the XML data binding serialization code. A typedef
binds an XML schema type name to a C/C++ type. For example:
This simple mechanism informs the soapcpp2 tool to generate serializers and deserializers that explicitly encode and decode the primitive C++ types as built-in primitive XSD types. At the same time, the use of typedef
does not force any source code rewriting of a client or Web service application because the internal types used by the application are not required to be changed by using this typedef
mechanism.
The built-in XSD types are covered by typedef
mappings and we could map XSD xsd:base64Binary
and xsd:hexBinary
to strings, but that would be cumbersome since the application should populate the strings properly. Instead, we can defined the following structs or classes to contain binary content that the generated serializers serialize in base64 and hexadecimal, respectively:
Also xsd:boolean
in C can be mapped to a enum
:
The trailing underscores are removed in XML payloads and are used here to avoid potential name clashes with C++ false
and true
keywords.
Annotations with typedef
types introduce validation constraints that are verified by the XML parser:
The soapcpp2 tool generates a schema with the following types (xsd::positiveInteger
is a built-in XSD type and therefore omitted from the generated schema):
For more details on mapping C/C++ data types with their value space constraints to XML schema and vice versa, see C and C++ XML Data Bindings documentation.
Reconsider the calculator example of the previous sections, now rewritten with an explicit XSD type for double
to illustrate the effect:
In C a pointer is used instead of a reference for the output parameter result
.
The soapcpp2 tool generates the client stub function:
This means that the client application does not need to be rewritten and can still call the client stub or use the generated C++ proxy class as before.
Likewise, typedef
can be used to declare user-defined schema types:
This lets soapcpp2 generate a WSDL and XML schema that declares the ns2:number
type:
There is no standardized convention for the response element name in a SOAP RPC encoded response message, although it is recommended that the response element name is the method name ending with "<i>`Response`</i>". For example, the response element of add
is addResponse
.
The response element name can be specified explicitly using a struct
or class
declaration in the interface header file for soapcpp2. This name should be qualified by a namespace prefix, just as the operation name should use a namespace prefix. The struct
or class
name represents the SOAP response element name used by the service. Consequently, the output parameter of the service operation must be declared as a member of the struct
or class
. The use of a struct
or a class
for the service response is fully SOAP 1.1/1.2 compliant. In fact, the absence of a struct
or class
indicates to the soapcpp2 tool to automatically generate a struct
for the response which is internally used by a stub.
Reconsider the calculator service operation specification which can be rewritten with an explicit declaration of a SOAP response element as follows:
This wraps the output parameters in a struct ns2__addResponse
. Note that in C a pointer is used instead of a reference for the output wrapper parameter r
.
In this example we just made an explicit output parameter wrapper, meaning that SOAP request and response messages will be the same as before without this wrapper:
We can use any other name with a namespace prefix for the wrapper struct or class to change the response element name.
The soapcpp2 tool uses the convention that the last parameter of the function prototype declaration of a service operation in an interface header file is the output parameter of the service operation. All other parameters are considered input parameters of the service operation.
To specify a service operation with multiple output parameters, a struct
or class
is declared to wrap the service operation response parameters, see also Section How to change the response element name . The name of the struct
or class
should have a namespace prefix, just as the service method name. The members of the struct
or class
are the output parameters of the service operation.
The order of the input parameters in the function prototype and the order of the output parameters (the members of the wrapper struct
or class
) is not significant. However, the SOAP 1.1 RPC encoding specification states that input and output parameters may be treated as anonymous parameter names, which requires a particular ordering of these parameters, see Section How to specify anonymous parameter names .
As an example, consider a hypothetical service operation getNames
with a single input parameter SSN
and two output parameters first
and last
. This can be specified as:
The soapcpp2 tool takes this header file as input and generates source code for the function soap_call_ns3__getNames
. When invoked by a client application, this stub function produces the XML request message:
The response XML message:
where first
and last
are the output parameters wrapped in the getNamesResponse
struct.
As another example, consider a service operation copy
with an input parameter and an output parameter with identical parameter names (this is not prohibited by the SOAP 1.1/1.2 protocols). This can be specified using a wrapper struct for the output parameters, thus avoiding the name clash we would run into without this wrapper:
The use of a struct
or class
for the service operation response enables the declaration of service operations that have parameters that are passed both as input and output parameters.
The soapcpp2 tool takes the copy.h
header file as input and generates the soap_call_X_rox__copy_name
stub function. When invoked by a client application, the stub function produces the XML request message:
The response XML message:
The name will be parsed and decoded by the stub function and returned as the name
member of the struct X_rox__copy_nameResponse &r
parameter.
You can use the service operation name as a wrapper for the response:
where the struct X_rox__copy_name
is generated by soapcpp2 automatically and does not need to be redeclared.
The response XML message in this case would be:
If the single output parameter of a service operation is a compound data type such as a struct
or class
it is necessary to specify the response element of the service operation as a struct
or class
at all times. Otherwise, the output parameter will be considered the response element (!), because of the response element specification convention used by gSOAP, as discussed in Section How to change the response element name .
This is best illustrated with an example. Suppose we have a Flighttracker service that provides real time flight information. It requires an airline code and flight number as parameters. The service operation name is getFlightInfo
that has two string parameters: the airline code and flight number. The method returns a getFlightResponse
response element with a return
output parameter that is of a compound data type FlightInfo
. The type FlightInfo
is represented by a class
in the header file:
The response element ns1__getFlightInfoResponse
is explicitly declared and it has one member: return_
of type ns2__FlightInfo
. Note that return_
has a trailing underscore to avoid a name clash with the return
keyword, see Section C/C++ identifier name to XML tag name translation for details on the translation of C/C++ identifiers to XML names.
The soapcpp2 tool generates the soap_call_ns1__getFlightInfo
stub function. Here is an example fragment of a client application that uses this proxy to request flight information:
When invoked by a client application, the stub function produces the XML request:
POST /soap/servlet/rpcrouter HTTP/1.1 Host: testvger.objectspace.com Content-Type: text/xml Content-Length: 634 SOAPAction: "urn:galdemo:flighttracker"
The service responds with:
HTTP/1.1 200 OK Date: Thu, 30 Aug 2011 00:34:17 GMT Server: IBM_HTTP_Server/1.3.12.3 Apache/1.3.12 (Win32) Content-Length: 861 Content-Type: text/xml; charset=utf-8
The stub function returns the service response in variable flight
of type struct ns1__getFlightInfoResponse
and this information can be displayed by the client application:
A320 flight UAL184 traveling 497 mph at 37000 ft, is located 188 mi W of Lincoln, NE
Note that the response includes xsi:type
attributes indicating the schema types of the elements in the XML message. This was common practice in earlier SOAP implementations and some SOAP implementations relied on it, but it was never mandated by the specifications. You can let soapcpp2 generate serializers that produce the xsi:type
type information in XML messages with soapcpp2 -t
option -t
. Otherwise, the serializers will not include xsi:type
attributes in the XML message payloads unless a derived type value is used in the XML payload in place of a base type, for example a derived class in place of a base class. In this way, SOAP/XML messaging implements object inheritance cleanly and efficiently because the leading xsi:type
attribute value corresponding to the serialized derived class in an XML message lets an XML parser and deserializer instantiate the derived class to populate it immediately (something that can't be claimed of JSON since JSON has no attributes and object properties are unordered).
The SOAP RPC encoding protocol allows parameter names to be anonymous. That is, the name(s) of the output parameters of a service operation are not strictly required to match a client's view of the parameters names. Also, the input parameter names of a service operation are not strictly required to match a service's view of the parameter names. The soapcpp2 tool can generate stub and skeleton functions that support anonymous parameters. Parameter names are implicitly anonymous by omitting the parameter names in the function prototype of the service operation. For example:
This enumerates the parameter names as _param_1
, _param_2
, and _param_3
, where the leading underscore makes these names anonymous, meaning that the XML parser and deserializer will accept any parameter name to extract their values, that is, even when the name of the XML element representing the parameter differs.
To make parameter names explicitly anonymous, specify parameter names that start with an underscore (_
) in the function prototype in the header file.
For example:
In this example, the _a
, _b
, and _return
are anonymous parameters.
To specify a service operation that has no input parameters, just provide a function prototype with one parameter which is the output parameter that is either a pointer or a reference, for example:
The soapcpp2 tool generates a struct for each service operation request message, which in this case is an empty struct. To prevent C compilers from throwing an error, the empty struct is patched at compile time with the compile-time flag WITH_NOEMPTYSTRUCT
.
To specify a service operation that has no output parameters, just define a function prototype with a response struct that is empty, for example:
Since the response struct is empty, no output parameters are specified. The SOAP response message has an empty response element ns:signalResponse
.
Specifying an empty response is not identical to SOAP one-way messaging, which is asynchronous and does not expect an XML response message to be transmitted at all, just an empty HTTP OK response to a HTTP POST request. See Section Asynchronous one-way message passing on one-way messaging.
To switch to RESTful Web APIs from SOAP Web services APIs is simple, just use a directive.
To declare HTTP POST as the default HTTP method to use with client-side calls for all service operations associated with the ns
namespace prefix:
To declare the HTTP POST method for a specific service operation, use:
You can specify GET
, PUT
, POST
, and DELETE
. With GET
the input parameters of the service operations should be primitive types. See Section Service directives.
The soapcpp2 tool generates skeleton functions in C or C++ source code for each of the service operations specified as function prototypes in the interface header file input to soapcpp2. The skeleton functions can be readily used to implement the service operations in a new Web service. The compound data types used by the input and output parameters of service operations must be declared in the interface header file, such as structs, classes, arrays, C++ containers, and pointer-based data structures (e.g. data structure trees and arbitrary operation. The soapcpp2 tool automatically generates serializers and deserializers for the data types to enable the generated skeleton functions to encode and decode the contents of the parameters of the service operations. The soapcpp2 tool also generates a service operation request dispatcher function soap_serve
that serves requests by calling the appropriate skeleton.
The following example specifies three service operations of a Web service:
The add
and sub
methods are intended to add and subtract two double floating point numbers stored in input parameters a
and b
and should return the result of the operation in the result
output parameter. The sqrt
method is intended to take the square root of input parameter a
and to return the result in the output parameter result
.
To generate the skeleton functions, the soapcpp2 tool is invoked from the command line with:
soapcpp2 calc.h
The soapcpp2 tool generates the skeleton functions in file soapServer.cpp
for the add
, sub
, and sqrt
service operations specified in the calc.h
header file. The skeleton functions are respectively soap_serve_ns__add
, soap_serve_ns__sub
, and soap_serve_ns__sqrt
. The generated file soapC.cpp
contains serializers and deserializers for the skeleton. The soapcpp2 tool also generates a service dispatcher: the soap_serve
function handles client requests and dispatches the service operation requests to the appropriate skeleton functions to serve the requests. The skeleton in turn calls the service operation implementation function. The function prototype of the service operation implementation function is specified in the header file that is input to the soapcpp2 tool.
Here is an example CGI service application that uses the generated soap_serve
skeleton function to handle client requests:
Note that the service operations have an extra input parameter which is a pointer to the soap
context.
The implementation of the service operations must return SOAP_OK
or a nonzero error code. The code SOAP_OK
denotes success. A nonzero error code is returned with soap_receiver_fault
and soap_sender_fault
. These functions also set up a SOAP Fault structure with the details of the fault returned. This is done by setting the soap::fault
which points to SOAP_ENV__Fault
structure. Its SOAP_ENV__Fault::faultstring
string and SOAP_ENV__Fault::detail
details are populated with the fault string (XML text) and fault detail (XML string). SOAP 1.2 requires the SOAP_ENV__Fault::SOAP_ENV__Reason
and the SOAP_ENV__Fault::SOAP_ENV__Detail
strings to be assigned instead.
This service application can be readily installed as a CGI application, which is a simple stateless way to deploy services. To deploy this service as a multi-threaded stand-alone server application see Sections How to create a stand-alone server and How to create a multi-threaded stand-alone service.
Besides generating the skeleton functions and serializers in source code, the soapcpp2 tool also generates a WSDL file for this service, see Section How to generate WSDL service descriptions for details on WSDL.
As per SOAP protocol (when applicable), "SOAP actions" are HTTP headers that are specific to the SOAP protocol and provide a means for routing service requests and for security reasons, for example firewall software can inspect SOAP action headers to grant or deny the SOAP request. Use soapcpp2 -a
option -a
or soapcpp2 -A
option -A
to let the generated skeleton functions dispatch the requests based on the SOAP action HTTP header together with (or instead) the name of the XML request element.
Note that soapcpp2 generates both clients and services based on the interface header file input. Which means that there is no need to modify the interface header file for client side or server side deployments. For example, the generated soap_call_ns__add
stub function is saved to the soapClient.cpp
file after invoking the soapcpp2 tool on the calc.h
header file.
ws2_32.lib
) To do this in Visual C++, go to Project, Properties, select Link and add ws2_32.lib
to the Object library modules entry..cpp
only. This means that you may have to rename all .c
files to .cpp
.gsoap/mod_gsoap
directory of the gSOAP package to simplify Internet access and deal with encryption, proxies, and authentication. See the gSOAP ISAPI extension documentation and the gSOAP WinInet plugin documentation.The deployment of a Web service as a CGI application is an easy means to provide your service on the Internet. However, CGI is stateless and the performance of CGI is not great. Instead, gSOAP services can be run as stand-alone services on any port by using the built-in HTTP and TCP/IP stacks of the engine. The recommended mechanism to deploy a service is through the gSOAP Apache module or ISAPI extension. These servers and modules are designed for server load balancing and access control. See the gSOAP Apache module documentation and the gSOAP ISAPI extension documentation for details.
See also the getting started page https://www.genivia.com/dev.html and tutorial page https://www.genivia.com/tutorials.html to get started with developing client and stand-alone server applications using the gSOAP tools.
To create a stand-alone service, the main
function of the service application should call soap_bind
to bind a port and then loop over soap_accept
to accept requests to serve with soap_serve
. Also call soap_ssl_accept
when HTTPS is used, which is set up with soap_ssl_server_context
.
For example:
The soap_serve
dispatcher handles one request or multiple requests when HTTP keep-alive is enabled with the SOAP_IO_KEEPALIVE
flag, which should only be used with client applications or with stand-alone multi-threaded services, see the next section and Section TCP and HTTP keep-alive.
The gSOAP functions that are frequently used for server-side coding are:
soap_bind(struct soap *soap, char *host, int port, int backlog)
binds soap::master
socket to the specified port and host name (or NULL for the current machine), using a backlog queue size of pending requests, returns master socket. We check the return value with soap_valid_socket
. The backlog queue size should be small, say 2 to 10, for iterative (not multi-threaded) stand-alone servers to ensure fairness among connecting clients. A smaller value increases fairness and defends against denial of service, but hampers performance because connection requests may be refused.soap_accept(struct soap *soap)
returns SOAP_SOCKET
socket soap::socket
when connected. We check the return value with soap_valid_socket
.soap_ssl_accept(struct soap *soap)
returns SOAP_OK
when the HTTPS handshake successfully completed.The IPv4 address is stored in soap::ip
. If IPv6 is enabled with WITH_IPV6
then soap::ip6
contains the IPv6 address.
The soap::accept_timeout
context variable of the context specifies the timeout value for a non-blocking soap_accept
call. See Section Timeout management for non-blocking operations for more details on timeout management.
The soap_serve
function parses the inbound HTTP request and dispatches the request to the skeleton functions that call the service operations implemented.
See Section Memory management for more details on memory management.
Stand-alone multi-threading a Web Service is essential when the response times for handling requests by the service are long or when HTTP keep-alive is enabled, see also Section TCP and HTTP keep-alive .
In case of long response times, the latencies introduced by the unrelated requests may become prohibitive for a successful deployment of a stand-alone service. When HTTP keep-alive is enabled, a client and server remain connected until 100 (SOAP_MAXKEEPALIVE
) request-response iterations later as specified by soap::max_keep_alive
or when a timeout occurred. Thereby preventing other clients from connecting.
The recommended mechanism to deploy a service is through the gSOAP Apache module or ISAPI extension. These servers and modules are designed for server load balancing and access control. See the gSOAP Apache module documentation and the gSOAP ISAPI extension documentation for details.
See also the getting started page https://www.genivia.com/dev.html and tutorial page https://www.genivia.com/tutorials.html to get started with developing client and stand-alone server applications using the gSOAP tools.
The following example illustrates the use of threads to improve the quality of service by handling new requests in separate threads:
For this multi-threaded application the gsoap/plugin/threads.h
and gsoap/plugin/threads.c
portable threads and mutex API is used.
The server spawns a thread per request. Each thread executes a soap_serve
using a copy of the soap
context created with soap_copy
(if soap_copy
fails due to out of memory then we can still recover as shown, recovery from errors is an important aspect of gSOAP's design and API implementation). Note that the server does not wait for threads to join the main thread upon program termination.
The soap_serve
dispatcher handles one request or multiple requests when HTTP keep-alive is set with SOAP_IO_KEEPALIVE
. The soap::max_keep_alive
value can be set to the maximum keep-alive calls allowed, which is important to avoid a client from holding a thread indefinitely. The send and receive timeouts are set to avoid (intentionally) slow clients from holding a socket connection too long. The accept timeout is used to let the server terminate automatically after a period of inactivity.
The following example limits the number of concurrent threads to reduce the machine's CPU resource utilization:
The advantage of the code shown above is that the machine cannot be overloaded with requests, since the number of active services is limited. However, threads are still started and terminated. This overhead can be eliminated using a queue of requests (a queue of accepted socket connections):
For this multi-threaded application the gsoap/plugin/threads.h
and gsoap/plugin/threads.c
portable threads and mutex API is used.
The void* soap::user
variable can be used to pass application state information to service operations and to plugins. This variable can be set before the soap_serve
call. The service method can access this variable to use the application-dependent data. The following example shows how a non-static database handle is initialized and passed to the service methods:
Another way to maintain and pass state information with the context is done with plugins, see Section Plugins, modules, and extensions .
Server object classes for C++ server applications are automatically generated by the soapcpp2 tool using soapcpp2 -j
option -j
or soapcpp2 -i
option -i
. Without these options the soapcpp2 tool generates C-based stub and skeleton functions.
We illustrate the use of server classes with the following example interface header file:
The directives provide the service name which is used to name the service class, the protocol (SOAP 1.2) and style (document/literal), service location (endpoint URL), and the schema namespace URI.
We run soapcpp2 -i calc.h
with option -i
to generate soapCalculatorService.h
which declares the C++ sever class that has the following structure:
This generated server class serve
method calls the add
, sub
, mul
, and div
methods upon receiving an XML request message. These methods should be implemented, for example as follows in a CGI-based service:
If we run soapcpp2 -j calc.h
with option -j
to generate soapCalculatorService.h
then we get the same class as with option -i
but the soap
context is not a base class but is a member of the service class:
The only difference we make to implement the service application is to use the soap
member of the class instead of this
when referring to the context, which in our example changes only one line of code in the div
method:
In fact, the service classes have soap_sender_fault
and soap_receiver_fault
methods that can be used instead.
You can declare a C++ namespace name
with soapcpp2 -q name
to create a server class in the name
namespace, see Section How to build a client or server in a C++ code namespace . For more options, see also Sections soapcpp2 options and How to create client/server libraries.
The example above serves CGI requests. The generated service classes also have bind
and accept
methods, which can be used to implement stand-alone services, see also Section How to create a stand-alone server .
A better alternative is to use soapcpp2 -j
option -j
or option -i
. With option -j
the C++ proxy and service classes have a soap
context pointer. This context pointer can be set and shared among many proxy and service classes. With option -i
the C++ proxy and server classes are derived from the soap
context, which simplifies the proxy invocation and service operation implementations.
Compilation of the above header file with soapcpp2 -i
creates new files soapCalculatorService.h
and soapCalculatorService.cpp
(rather than the C-style soapServer.cpp
).
This generated server object class can be included into a server application together with the generated namespace table as shown in this example:
Note that the service operation does not need a prefix (ns__
) and there is no soap
context passed to the service operation since the service object itself is the context (it is derived from the soap
context struct).
When combining multiple services into one application, you can run wsdl2h on multiple WSDLs to generate the single all-inclusive service definitions interface header file for soapcpp2. This header file is then processed with soapcpp2 to generate skeleton functions in C or server classes in C++ when using soapcpp2 -j
option -j
(or option -i
).
This approach works well for C and C++ too, but the problem in C++ is that we end up with multiple service classes, each for a collection of service operations that the class is supposed to implement. But what if we need to provide one endpoint port for all services and operations? In this case invoking the server object's serve
method is not sufficient, since only one service can accept requests while we want multiple services to listen to the same port.
For example, say we have three service classes soapABCService
, soapUVWService
, and soapXYZService
. We run soapcpp2 -i -S -q name
three times (on the same interface file when applicable):
soapcpp2 -i -S -qAbc file.h soapcpp2 -i -S -qUvw file.h soapcpp2 -i -S -qXyz file.h
To generate the common envH.h
file for SOAP Header and SOAP Fault definitions is done on a env.h
file that is empty or has the SOAP Header and SOAP Fault detail structures SOAP_ENV__Header
and SOAP_ENV__Detail
specified:
soapcpp2 -CSL -penv env.h
The approach is to chain the service dispatchers, as shown below:
The dispatch
method parses the SOAP/XML request and invokes the service operations, unless there is no matching operation and SOAP_NO_METHOD
is returned. The soap_copy_stream
ensures that the service object uses the currently open socket. The copied streams are freed with soap_free_stream
. Do not enable keep-alive support, as the socket may stay open indefinitely afterwards as a consequence. Also, the dispatch
method does not send a fault to the client, which has to be explicitly done with the soap_send_fault
operation when an error occurs.
In this way, multiple services can be chained to accept messages on the same port. This approach also works with SSL for HTTPS services.
However, this approach is not recommended for certain plugins, because plugins must be registered with all service objects and some plugins require state information to be used across the service objects, which will add significantly to the complexity.
Therefore, it is best to have all services share the same context. This means that soapcpp2 -j
with option -j
should be used instead of option -i
. As a result, we can make each service class instance to share the same soap
context and the same plugins.
soapcpp2 -j -S -qAbc file.h soapcpp2 -j -S -qUvw file.h soapcpp2 -j -S -qXyz file.h
Chaining the services is also simpler to implement since we use one soap
context:
However, the while loop iterates for each new connection that is established with soap_accept
and does not allow for HTTP keep-alive connections to persist. For our final improvement we want to support HTTP keep-alive connections that require looping over the service dispatches until the connection closes on either end, after which we resume the outer loop. The resulting code is very close to the soapcpp2-generated soap_serve
code and the serve
service class methods, with the addition of the chain of service dispatches in the loop body:
The soapcpp2 tool generates WSDL (Web Service Description Language) service descriptions and XML schema files (XSDs) when processing an interface header file that wasn't generated with wsdl2h. The soapcpp2 tool produces one WSDL file for a set of service operations in the header file. If the header file has no service operations (i.e. no function prototypes) then no WSDL will be generated. The names of the function prototypes of the service operations must use the same namespace prefix and the namespace prefix is used to name the WSDL file. The WSDL file and services can be named with a //gsoap <prefix> service name:
directive to specify a service name for each namespace prefix.
If multiple namespace prefixes are used to define service operations, then multiple WSDL files will be created and each file describes the set of service operations belonging to that namespace prefix.
The soapcpp2 tool also generates XML schema files (XSD files) for all serializable C/C++ types declared in the interface header file input to soapcpp2. These XSD files do not have to be published as the WSDL file already contains the appropriate XML Schema definitions.
To customize the WSDL output, use //gsoap
directives to declare the service name, the endpoint port, and namespace etc:
These are some examples and defaults will be used when directives are not specified. Recommended is to specify at least the service name and namespace URI. More details and settings for the service can be declared as well. See Section Directives for more details.
In addition to the generation of the WSDL files, a file with a namespace mapping table is generated by the gSOAP soapcpp2 tool. An example mapping table is shown below:
This file should be included in the client or service application, see Section XML namespaces and the namespace mapping table for details on namespace mapping tables.
For example, suppose the following service operations are defined in the calc.h
header file:
One WSDL file calc.wsdl
will be generated that describes the three service operations:
The above uses the default settings for the service name, port, and namespace which can be set in the header file with //gsoap
directives, see Section Directives .
Invoking a server-side client call requires the use of a new soap
context in the service operation itself, which is best illustrated with an example. The following example combines the functionality of two Web services into one new SOAP Web service. The service provides a currency-converted stock quote. To serve a request, the service in turn requests the stock quote and the currency-exchange rate from two services. The currency-converted quote is then calculated and returned.
In addition to being a client of two Web services, this service application can also be used as a client of itself to test the implementation. As a client invoked from the command-line, it will return a currency-converted stock quote by connecting to a copy of itself installed as a CGI application on the Web to retrieve the quote after which it will print the quote on the terminal.
The header file input to the soapcpp2 tool is given below. The example is for illustrative purposes only because the XMethods stock quote and currency rate services are no longer operational:
We run:
soapcpp2 quotex.h
This generates soapStub.h
, soapH.h
, soapC.cpp
(serializers), soapClient.cpp
(client stub functions), soapServer.cpp
(server skeleton functions).
The quotex.cpp
CGI service application is (for source code to create a stand-alone service, see Section How to create a stand-alone server):
When combining clients and service functionalities, it is recommended to use a single interface header file input to the soapcpp2 tool, since this header file declares both client and server functionalities. As a consequence, however, stub and skeleton functions are generated for all service operations, while the client part will only use the stub functions and the service part will use the skeleton functions. Thus, dummy implementations of the unused service operations are implemented as shown in the example above, which are in fact never used.
Three WSDL files are generated by soapcpp2: ns1.wsdl
, ns2.wsdl
, and ns3.wsdl
. Only the ns3.wsdl
file is required to be published as it contains the description of the combined service, while the others are generated as a side-effect.
To switch to RESTful Web APIs from SOAP Web services APIs is simple, just use a directive.
To declare HTTP POST as the default HTTP method to use with client-side calls for all service operations associated with the ns
namespace prefix:
To declare the HTTP POST method for a specific service operation, use:
You can specify GET
, PUT
, POST
, and DELETE
. With GET
the input parameters of the service operations should be primitive types. See Section Service directives.
SOAP messaging is typically synchronous: the client sends a HTTP POST and blocks until the server responds to the request. The gSOAP tools also support asynchronous one-way messaging over HTTP.
One-way SOAP service operations are declared as function prototypes with the output parameter specified as a void
type to indicate the absence of a return value, for example:
The soapcpp2 tool generates the following functions in soapClient.cpp
:
The soap_send_ns__event
function transmits the message to the destination URL by opening a socket and sending the SOAP encoded message. The socket will remain open after the send. To complete the HTTP POST operation we need to call soap_recv_empty_response
to accept the server's HTTP OK or Accept response message that should have an empty message body:
The generated soap_recv_ns__event
function can be used to parse a SOAP message, e.g. on the server side. But it is not used on the client side. The ns__event
structure is declared as:
The gSOAP generated soapServer.cpp
code includes a skeleton function called by soap_serve
to process the one-way request message:
This skeleton function calls the user-defined ns__event(struct soap *soap, int eventNo)
function (note the absence of the void parameter!). However, when this function returns, the skeleton function does not respond with a SOAP response message since no response data is specified. Instead, the user-defined ns__event
function should call soap_send_empty_response
to return an empty response message. For example:
The gSOAP XML databindings for C and C++ allow a seamless integration of XML in C and C++ applications. Data can be serialized in XML and vice versa. WSDL and XML schema files can be converted to C or C++ definitions. C and C++ definitions can be translated to WSDL and schemas to support legacy ANSI C applications for example.
This section explains the basics of mapping XML schema types to C/C++ types using the wsdl2h tool. A more in-depth presentation of C/C++ XML data bindings in gSOAP is documented in C and C++ XML data bindings.
The wsdl2h tool takes WSDL, WADL, and XSD files or URLs to WSDL, WADL, and XSD and generates an interface header file with the command:
wsdl2h [options] WSDL WADL and XSD files or URLs...
The WSDL 1.1 and 2.0 standards are supported and WADL. If you have any trouble with wsdl2h being able to process WSDLs and XSD files or URLs, then please contact Genivia technical support for assistance.
The gSOAP tools support the entire XML schema 1.1 standard, except XPath expressions and assertions. This covers all of the following schema components with their optional attributes shown:
The supported schema facets are:
Also supported are:
A subset of the default type mappings is shown below:
Automatic validation of xsd:pattern
-restricted content is possible with a hook to a regex pattern matching engine, see the soap::fsvalidate
and soap::fwvalidate
callback documentation in Section Function callbacks for customized I/O and HTTP handling .
User-defined mappings can be added to typemap.dat
, which is used by wsdl2h to map schema types to C/C++ types. For example, the map xsd:duration
to a custom serializer, add this line to typemap.dat
:
xsd__duration = #import "custom/duration.h" | xsd__duration
Then run wsdl2h with the typemap.dat
file in the current directory or use wsdl2h -t mapfile.dat
option -t mapfile.dat
to use mapfile.dat
instead. This requires compiling gsoap/custom/duration.c
with your build.
Another example is xsd:dateTime
which is mapped to time_t
. To expand the range and precision of xsd:dateTime
we can map xsd:dateTime
to struct tm
:
xsd__dateTime = #import "custom/struct_tm.h" | xsd__dateTime
or to struct timeval
:
xsd__dateTime = #import "custom/struct_timeval.h" | xsd__dateTime
This requires compiling gsoap/custom/struct_tm.c
or gsoap/custom/struct_timeval.c
, respectively.
Non-primitive XSD types are supported, with the default mapping shown below:
String targets are defined in the typemap.dat
file used by wsdl2h to map XSD types. This allows the use of char*
and std::string
. It is possible to map any string types to wchar_t
and std::wstring
by adding the following line to typemap.dat
:
xsd__string = | wchar_t* | wchar_t*
and
xsd__string = | std::wstring
By default strings are either char*
(for C) or std::string
(for C++) which contain ASCII or UTF-8 content enabled with the runtime flag SOAP_C_UTFSTRING
.
Note that the XSD types for unlimited numeric values such as xsd:integer
and xsd:decimal
are mapped to strings, to preserve the value in case it is too large to store in a 64-bit integer or float. The mapping can be redefined as follows in typemap.dat
:
xsd__decimal = | double xsd__integer = | LONG64 xsd__nonNegativeInteger = typedef xsd__integer xsd__nonNegativeInteger 0 : ; | xsd__nonNegativeInteger xsd__nonPositiveInteger = typedef xsd__integer xsd__nonPositiveInteger : 0 ; | xsd__nonPositiveInteger xsd__positiveInteger = typedef xsd__integer xsd__positiveInteger 1 : ; | xsd__positiveInteger xsd__negativeInteger = typedef xsd__integer xsd__negativeInteger : -1; | xsd__negativeInteger
We can also use a quadmath.h
128 bit float to store xsd:decimal
:
xsd__decimal = #import "custom/float128.h" | xsd__decimal
where xsd__decimal
is a __float128
quadmath.h
type.
There are several initialization flags to control XML serialization at run-time:
SOAP_XML_STRICT
.SOAP_XML_IGNORENS
.SOAP_XML_CANONICAL
.xmlns="..."
namespace bindings are enforced with SOAP_XML_DEFAULTNS
.SOAP_XML_INDENT
.xsi:nil
for NULL struct and class members are serialized with SOAP_XML_NIL
.char*
and std::string
with SOAP_C_UTFSTRING
.Strict validation catches all structural XML validation violations. For primitive type values it depends on the C/C++ target type that XSD types are mapped to, to catch primitive value content pattern violations. Primitive value content validation is performed on non-string types such as numerical and time values. String values are not automatically validated, unless a xsd:pattern
is given and the soap::fsvalidate
and soap::fwvalidate
callbacks are implemented by the user. Alternatively, deserialized string content can be checked at the application level.
To obtain C or C++ type definitions for XML schema components, run wsdl2h on the schemas to generate a data binding interface header file. This header file defines the C/C++ type representations of the XML schema components. The header file is then processed by the soapcpp2 tool to generate the serializers for these types. See Section Introduction to XML data bindings for an overview to use wsdl2h and soapcpp2 to map schemas to C/C++ types to obtain XML data bindings.
To generate serialization code, execute:
soapcpp2 [options] file.h
The following C/C++ types are supported in the data binding interface header file:
Additional features and C/C++ syntax requirements:
#import "file.h"
instead of #include
to import other header files. The #include
and #define
directives are fine to use, but these are moved into the generated code and then used by the C/C++ compiler._XML
strings. Otherwise, mixed content may be lost. Use soapcpp2 -d
option -d
for DOM support. See the XML DOM API documentation for details.extern
qualifier, which prevents serialization of types or struct and class members: volatile
which means that they are declared elsewhere in the project's source code base and should not be redefined in the soapcpp2-generated code nor changed by the soapcpp2 tool, for example this makes struct tm
of time.h
serializable with a selection of its members specified, where volatile
prevents soapcpp2 from declaring this struct again: mutable
means that they can be augmented with additional members using redefinitions of the struct or class: SOAP_ENV__Header
struct is mutable as well as the SOAP_ENV__Fault
, SOAP_ENV__Detail
, SOAP_ENV__Reason
, and SOAP_ENV__Code
structs. The reason is that these structures are augmented with additional members by plugins such as WS-Addressing gsoap/plugin/wsaapi.h
to support these SOAP-based protocols.SOAP_C_UTFSTRING
. When enabled, all std::string
and char*
strings contain UTF-8. In this way the deserializers populate strings with UTF-8 content and serializers will output strings as holding UTF-8 content.The soapcpp2 tool generates serializers and deserializers for all wsdl2h-generated or user-defined data structures that are specified in the header file input to the soapcpp2 tool. The serializers and deserializers can be found in the soapcpp2-generated soapC.cpp
file. These serializers and deserializers can be used separately by an application without the need to build a Web services client or service application. This is useful for applications that need to save or export their data in XML or need to import or load data stored in XML format.
The soapcpp2 tool generates the following readers and writers for each serializable data type defined in the data bindings interface file input to soapcpp2:
int soap_read_T(struct soap*, T *data)
parse XML and deserialize into C/C++ data of type T
, returns SOAP_OK
on success.int soap_write_T(struct soap* T *data)
serialize C/C++ data of type T
into XML, returns SOAP_OK
on success.Where T
is the name of the data type, such as the struct or class name. For other types, see the table further below for the naming conventions used by soapcpp2 to generate these functions.
The following soap
context variables control the destination and source for XML serialization and deserialization:
SOAP_SOCKET soap::socket
socket file descriptor for socket connection input and output (or SOAP_INVALID_SOCKET
when not set).ostream *soap::os
C++ only: output stream used for send operations when non-NULL.const char **soap::os
C only: points to a string pointer to be set with the string content produced, the saved string is allocated and managed by the soap
context.istream *soap::is
C++ only: input stream used for receive operations when non-NULL.const char *soap::is
C only: string with input to parse, this pointer advances over the string until a \0
is found.int soap::sendfd
when soap::socket
= SOAP_INVALID_SOCKET
, this fd is used for send operations, default fd is 1 (stdout).int soap::recvfd
when soap::socket
= SOAP_INVALID_SOCKET
, this fd is used for receive operations, default fd is 0 (stdin).Additional functions are generated by soapcpp2 for each serializable data type T
to dynamically allocate data of type T
on the context-managed heap and to initialize data of type T
:
T * soap_new_T(struct soap*)
allocates and initializes data of type T
in context-managed heap memory, managed data is deleted with soap_destroy
(deletes C++ objects) and soap_end
(deletes all other data), and you can also use soap_malloc
to allocate uninitialized context-managed memory.void soap_default_T(struct soap*, T*)
initializes data of type T
, but C++ classes are augmented with a soap_default(struct soap*)
method that should be called instead to (re)initialize the class instance. If the class has a soap
context pointer member then this member will be set to the first argument passed to this function.The following extra functions are generated by soapcpp2 for deep copying and deletion of entire data structures when using soapcpp2 -Ecd
options -Ec
(deep copy) and -Ed
(deep deletion):
T * soap_dup_T(struct soap*, T *dst, const T *src)
deep copy src
into dst
, replicating all deep cycles and shared pointers when a managing soap
context is provided. When dst
is NULL, allocates space for dst
and returns a pointer to the allocated copy. Deep copy results in a tree when the soap
context is NULL, but the presence of deep cycles will lead to non-termination. Use flag SOAP_XML_TREE
with managing context to copy into a tree without cycles and pointers to shared objects. Returns dst
or the allocated copy when dst
is NULL.void soap_del_T(const T*)
deletes all heap-allocated members of this object by deep deletion ONLY IF this object and all of its (deep) members are not managed by a soap context AND the deep structure is a tree (no cycles and co-referenced objects by way of multiple (non-smart) pointers pointing to the same data). Can be safely used after soap_dup(NULL)
to delete the deep copy. Does not delete the object itself.The following initializing and finalizing functions should be used before and after calling lower-level IO functions such as soap_send
, soap_send_raw
, soap_get0
, soap_get1
, and soap_http_get_body
(this is not needed when calling the soap_read_T
and soap_write_T
functions):
int soap_begin_send(struct soap*)
start a sending phase.int soap_end_send(struct soap*)
flush the send buffer.int soap_begin_recv(struct soap*)
start a receiving phase, if an HTTP header is present, parse it first.int soap_end_recv(struct soap*)
finalize receiving, read attachments if any, perform SOAP id/href consistency check on deserialized data.These operations do not setup or open or close files or connections. The application should open and close connections or files and set the soap::socket
, soap::os
or soap::sendfd
, soap::is
or soap::recvfd
streams or descriptors. When soap::socket
is SOAP_INVALID_SOCKET
and none of the streams and descriptors are set, then the standard input and output will be used.
The following options are available to control serialization:
See also Section Run-time flags to control the I/O buffering and content encoding such as compression.
To accurately and safely serialize data structures with cycles and co-referenced objects to an XML stream, two generated functions are called by soap_write_T
to serialize data of type T
: soap_serialize_T
to perform a deep analysis of pointers to detect co-referenced data and cycles, and soap_put_T
to output the data in XML with id-href (or id-ref) attributes for co-referenced data and cycles. Multi-references with id-href (and id-ref) are part of the SOAP protocol to serialize data accurately, i.e. retaining the structural integrity of the data sent and received. Flag SOAP_XML_TREE
turns id-href (id-ref) attributes off (makes soap_serialize_T
a no-op and ignores them on the receiving end). Flag SOAP_XML_GRAPH
should be used with non-SOAP XML output to accurately and safely serialize data structure graphs with co-referenced objects and cycles.
The soap_serialize_T
and soap_put_T
calls are performed by the generated soap_write_T
functions, which also call soap_begin_send
and soap_end_send
.
The following table lists the type naming conventions used by soapcpp2 to generate functions:
type | name |
---|---|
char* | string |
wchar_t* | wstring |
std::string | std__string |
std::wstring | std__wstring |
char | byte |
bool | bool |
double | double |
int | int |
float | float |
long | long |
long long | LONG64 |
short | short |
time_t | time |
unsigned char | unsignedByte |
unsigned int | unsignedInt |
unsigned long | unsignedLong |
unsigned long long | ULONG64 |
unsigned short | unsignedShort |
T [N] | ArrayN OfType where Type is the type name of T |
T* | PointerToType where Type is the type name of T |
std::vector<T> | TemplateOfType where Type is the type name of T |
struct Name | Name |
class Name | Name |
enum Name | Name |
Consider for example the following interface header file for soapcpp2 declares a struct ns__Person
:
To parse and deserialize a person variable p
from XML:
To parse and deserialize XML from a file:
To parse and deserialize XML from a C++ file stream:
Or to parse and deserialize XML from a string stream in C++:
To parse and deserialize XML from a string cs
in C:
To serialize a person variable p
in XML:
This produces:
To send the output to a file:
To send the output to a C++ file stream:
Or send the output to a C++ string stream to save XML in a string:
To save the output to a string cs
in C:
The string cs
is populated with XML when successful. This string is managed by the context and deleted with soap_end
.
As we explained, the soap_write_T
functions call soap_serialize_T
, which must be called when the data structure graph to serialize contains co-referenced data and cycles. It must be called to preserve the logical coherence of pointer-based data structures, where pointers may refer to co-referenced objects. By calling soap_serialize_T
, data structures shared through pointers are serialized only once and referenced in XML using id-refs attributes. The actual id-refs used depend on the SOAP encoding. To turn off SOAP encoding, remove or avoid using the SOAP-ENV and SOAP-ENC namespace bindings in the namespace table. In addition, the SOAP_XML_TREE
and SOAP_XML_GRAPH
flags can be used to control the output by restricting serialization to XML trees or by enabling multi-ref graph serialization with id-ref attributes.
To save the data as an XML tree (with one root) without any id-ref attributes, use the SOAP_XML_TREE
flag. The data structure must not contain pointer-based cycles. This flag also instructs the XML parser and deserializer to ignore id-ref attributes.
To preserve the exact structure of the data object graph and create XML with one root, use the SOAP_XML_GRAPH
output-mode flag (see Section Run-time flags ). Using the SOAP_XML_GRAPH
flag assures the preservation of the logical structure of the data.
Using SOAP_XML_TREE
means that no id-refs are output or parsed. With this flag the output will serialize nodes as a tree in XML, which means that nodes may be duplicated when shared by multiple pointers and cycles are broken to prevent infinite serialization. To preserve the graph structure of the nodes in the data structure, use SOAP_XML_GRAPH
or use SOAP 1.1 or 1.2 multi-reference serialization (this is the default mode with SOAP serialization).
Consider for example the following struct
:
The following fragment initializes the pointer members p
and q
to point to the value of member n
:
What is special about this data structure is that members p
and q
both point to member n
. When using SOAP 1.1 with gSOAP, the serializers strategically place id elements (also called SOAP 1.1 independent elements) after the root element to identify shared values, where the href attributes of elements p
and q
point to:
The above is not valid as plain XML, because there is no single root element, but it is valid XML when placed in a SOAP Body element as intended with SOAP 1.1 messaging.
When SOAP 1.2 is used with gSOAP, the output is more accurate, because now both elements p
and q
point to element n
:
Without using SOAP encoding but using plain XML instead with the SOAP_XML_GRAPH
flag set, the output is also accurate with both elements p
and q
pointing to element n
:
In the last two cases, the generated deserializer for this data type will be able to accurately reconstruct the instance with members p
and q
pointing to member n
.
Finally, serialization with SOAP_XML_TREE
produces XML trees, which may benefit interoperability but sacrifices the true meaning of serialization, giving three copies of the shared value 1
:
With the soapcpp2-generated serializers you can define a C++ operator that serializes a specified class instance or type as follows, assuming the ns__Person
class is declared in an interface header file for soapcpp2:
Run soapcpp2 -0
on this file to generate the serializers with non-SOAP XML namespaces, which we then use in our main program as follows:
In this example we construct an instance of ns__Person
by setting its soap
context struct pointer data member to a new valid context that is deleted by the destructor of this instance.
soap
context struct pointer member will have their soap
contexts set automatically by the deserializer's context, because soap_default_T
(or soap_default
class method) is called that sets the soap
context struct pointer of the instance. For example, soap_read_ns__Person
sets the deserialized ns__Person::soap
member to the first argument soap
of soap_read_ns__Person
, which happens to be ns__Person::soap
anyway in the example shown above. See Section Intra-class memory management .The output of this program is:
The xsi
and xsd
namespaces are used when attributes such as xsi:nil
and xsi:type
are serialized, where xsi:type
may refer to a XSD type such as xsd:string
. The xsi:nil
attribute is output when an element is nillable but its corresponding pointer member is NULL and xsi:type
is output for structs and classes with polymorphic members that are declared with int __type
member and a void*
pointer to serialize the value pointed to. Attribute xsi:type
is also output to serialize derived instances in place of base class instances. Therefore, removing these namespaces from the XML namespace table (ns.nsmap
) may cause XML parsing and validation issues.
As an example, consider the following data type declarations:
The following program uses these data types to write to standard output a data structure that contains the data of a person named "John" living at Downing st. 10 in Londen. He has a mother "Mary" and a father "Stuart". After initialization, the class instance for "John" is serialized and encoded in XML to the standard output stream using gzip compression (requires the Zlib library, compile sources with the compile-time flag WITH_GZIP
):
The person.h
interface header file is input to soapcpp2 and the generated code compiled together with person.cpp
:
soapcpp2 -0 person.h c++ -o person person.cpp soapC.cpp stdsoap2.cpp
We run the application:
./person
The output is:
Because the C++ compiler stores the constant strings "Dowling st."
and "London"
just once, references are included in the output with flag SOAP_XML_GRAPH
that preserves the original structure of the data structure serialized.
The following program decodes this content from standard input and reconstructs the original data structure on the heap:
The soapcpp2 tool generates soap_default_T
functions for serializable types T
specified in an interface header file for soapcpp2 The default values of primitive C/C++ types can be easily specified by defining any one or all of the following macros before including the gsoap/stdsoap2.h
file or by using SOAPDEFS_H
or WITH_SOAPDEFS_H
:
The absence of a data value in a receiving SOAP message will result in the assignment of a default value to a primitive type upon deserialization.
Default values can also be assigned to individual struct
and class
members of primitive type or pointers to primitive types. For example:
Default values are assigned to the members of a struct or class when parsing and deserializing XML into data when XML elements or attributes with the respective values are absent. Assigning default values to members makes these members optional elements and attributes in the corresponding XML schema.
Because service operation requests and responses are essentially structs (internally they are structs), default values can also be assigned to service operation parameters. These default parameter values do not specify optional parameters as we normally see with C/C++ function calls. Rather, the default parameter values are used in case an inbound request or response message lacks the XML elements that comprise these parameters. For example, a Web service can use default values to fill-in absent parameters in a SOAP request as follows:
When the request message lacks uid
or pwd
elements then the default values are assigned instead.
In addition, the default values will show up in the SOAP or XML request and response message examples generated by the soapcpp2 tool.
The wsdl2h tool is an advanced XML data binding tool to convert WSDLs and XML schemas (XSD files) to C or C++. The tool takes WSDL and XSD files or URLs to WSDLs and XSDs, then converts these to a C or C++ interface header file that specifies the properties of the WSDLs and XSDs in a familiar C/C++ syntax. This header file is not intended to be included in your code directly. It should be converted by soapcpp2 to generate the logic for the data bindings. It can however be safely converted by a documentation tool such as Doxygen to analyze and represent the service operations and data in a convenient layout. To this end, the generated interface header file is self-explanatory.
The wsdl2h tool can also be used without WSDLs to convert XML schemas (XSDs) to C/C++ to implement XML data bindings in C and C++. The wsdl2h tool generates the XML data binding interface header file with the C/C++ data type equivalents to the XML schema types and components.
The soapcpp2 tool then generates the XML data binding implementation source code from the data binding interface header file, meaning the serialization source code to serialize C/C++ data in XML and the client-side stub functions to invoke remote service operations and the server-side skeleton functions to implement XML Web services.
Therefore, the creation of C and C++ applications from one of more WSDLs or XSDs is a two-step process.
First, to convert a WSDL to C++ we use:
wsdl2h file.wsdl
This generates an interface header file file.h
. When using a URL to the WSDL we use wsdl2h -o file.h
option -o file.h
to save the file:
wsdl2h -ofile.h http://www.example.com/file.wsdl
Web service operations in the generated file.h
header file are converted to function prototypes. Schema types are converted to the equivalent C/C++ types, using file typemap.dat
to map XML schema types to C/C++ types.
The generated header file also contains instructions for the user and has documentation copies from the WSDL as well as various directives related to the Web service properties defined in the WSDL.
Multiple WSDL specifications can be processed at once and saved to one interface header file with wsdl2h -o file.h
option -o file.h
:
wsdl2h -o file.h file1.wsdl file2.wsdl file3.wsdl
To generate C source code, use wsdl2h -c
option -c
:
wsdl2h -c file.wsdl
The wsdl2h tool does not require WSDLs, it also works for XSDs:
wsdl2h -o file.h file1.xsd file2.xsd file3.xsd
In this case no service operations are found and therefore the interface header file generated does not contain function prototypes representing service operations.
When upgrading gSOAP to a newer version it is often not necessary to perform this first step again, since newer versions are backward compatible to previous interface header files generated by wsdl2h.
Next, the wsdl2h-generated interface header file file.h
is input to the soapcpp2 tool to generate the XML data binding implementation logic in C or C++:
soapcpp2 file.h
You can use soapcpp2 without wsdl2h, by specifying an input interface header file that is not generated by wsdl2h but written by hand for example, see The soapcpp2 tool.
There are many cases when wsdl2h generates code with #import
directives, such as #import "stlvector.h"
, that requires the soapcpp2 tool to import definitions from the gsoap/import
directory, which can be specified as follows:
soapcpp2 -I some_path_to/gsoap/import file.h
When WSDLs are converted to C++ source code, you may want to use wsdl2h -j
option -j
(or wsdl2h -j
option -i
) to generate proxy and service classes:
soapcpp2 -j file.h
This command generates a couple of C++ source files, more details will follow in Section The soapcpp2 tool.
Consider for example the following commands to implement a C++ client application:
wsdl2h -o calc.h http://www.genivia.com/calc.wsdl soapcpp2 -C -j -I path_to/gsoap/import calc.h
The first command generates calc.h
from the WSDL at the specified URL. The header file is then processed by the soapcpp2 tool to generate the proxy class declared in soapcalcProxy.h
class and defined in soapcalcProxy.cpp
. It also generates a file calc.nsmap
with a XML namespace table which should be included in our source code. The tool also generates soapStub
, soapH.h
, and soapC.cpp
. The latter is also compiled with our application together with gsoap/stdsoap2.cpp
.
The wsdl2h tool generates one XML data binding interface header file, a file that includes all of the information gathered from the WSDLs and XSDs input to the wsdl tool as command-line arguments. The default output file name of wsdl2h is the first WSDL/schema input file name but with extension .h
that replaces .wsdl
(or replaces .xsd
in case of XSD files specified). When an input file is absent or a WSDL file is loaded from a Web URL, the header output will be produced on the standard output unless wsdl2h -o file.h
option -o file.h
is used to save the output to file.h
(or any other file name specified).
The wsdl2h command-line options are:
option | result |
---|---|
-a | generate indexed struct names for local elements with anonymous types |
-b | generate bi-directional operations to serve one-way response messages (duplex) |
-c | generate C source code |
-c++ | generate C++ source code (default) |
-c++11 | generate C++11 source code |
-D | make attribute members with default/fixed values optional with pointers |
-d | generate DOM code for xsd:any and xsd:anyType elements |
-e | don't qualify enum names |
-F | add transient members to structs to simulate struct-type derivation in C |
-f | generate flat C++ class hierarchy by removing inheritance |
-g | generate global top-level element and attribute declarations |
-h | display help info and exit |
-I path | use path to locate WSDL and XSD files |
-i | don't import (advanced option) |
-j | don't generate SOAP_ENV__Header and SOAP_ENV__Detail definitions |
-k | don't generate SOAP_ENV__Header mustUnderstand qualifiers |
-L | generate less documentation by removing generic @note comments |
-l | display license information |
-M | suppress error "must understand element with wsdl:required='true'" |
-m | use xsd.h module to import primitive types |
-N name | use name for service prefixes to produce a service for each binding |
-n name | use name as the base namespace prefix name instead of ns |
-O1 | optimize by omitting duplicate choice/sequence members |
-O2 | optimize -O1 and omit unused schema types (unreachable from roots) |
-O3 | optimize -O2 and omit unused schema root attributes |
-O4 | optimize -O3 and omit unused schema root elements (use only with WSDLs) |
-Ow2 | optimize -O2 while retaining all derived types of used base types |
-Ow3 | optimize -O3 while retaining all derived types of used base types |
-Ow4 | optimize -O4 while retaining all derived types of used base types |
-o file | output to file |
-P | don't create polymorphic types inherited from xsd__anyType |
-p | create polymorphic types inherited from base xsd__anyType (automatic when the WSDL or XSD contains polymorphic definitions) |
-Q | make xsd__anySimpleType equal to xsd__anyType to use as the base type |
-q name | use name for the C++ namespace of all declarations |
-R | generate REST operations for REST bindings in the WSDL |
-r host[:port[:uid:pwd]] | connect via proxy host , port , and proxy credentials uid and pwd |
-r :uid:pwd | connect with authentication credentials uid and pwd |
-S name | use name instead of soap for the soap context included in C++ classes as a member variable or use -S "" to remove it |
-s | don't generate std code (no std::string and no std::vector) |
-t file | use type map file instead of the default file typemap.dat |
-U | map Unicode XML names to UTF-8-encoded Unicode C/C++ identifiers |
-u | don't generate unions |
-V | display the current version and exit |
-v | verbose output |
-W | suppress warnings |
-w | always wrap response parameters in a response struct |
-X | don't qualify part names to disambiguate doc/lit wrapped patterns |
-x | don't generate _XML any and _XML anyAttribute extensibility elements |
-y | generate typedef synonyms for structs and enums |
-z1 | compatibility with 2.7.6e: generate pointer-based arrays |
-z2 | compatibility with 2.7.15: (un)qualify element/attribute referenced members |
-z3 | compatibility with 2.7.16 to 2.8.7: (un)qualify element/attribute referenced members |
-z4 | compatibility up to 2.8.11: don't generate union structs in std::vector |
-z5 | compatibility up to 2.8.15: don't include minor improvements |
-z6 | compatibility up to 2.8.17: don't include minor improvements |
-z7 | compatibility up to 2.8.59: don't generate std::vector of class of union |
-z8 | compatibility up to 2.8.74: don't generate qualifiers for doc/lit wrapped patterns |
-z9 | compatibility up to 2.8.93: always qualify element/attribute referenced members, even when defined in the same namespace with default forms unqualified |
-z10 | compatibility up to 2.8.96: generate qualifiers even when defined without namespace |
-_ | don't generate _USCORE (replace with Unicode _x005f ) |
The following subsections explain the options in detail. The source code examples generated by wsdl2h are slightly simplified by removing comments and some other details without changing their meaning to improve readability.
This option generates indexed identifier names for structs, classes, unions, and enums declared for local elements with local (i.e. anonymous) types. When local elements and attributes have local types that are mapped to a struct, class, union, or enum, the generated type name is normally the outer struct/class name concatenated with the element/attribute name.
For example:
By default without this option, this schema is translated by wsdl2h to the following interface header file declaration:
By contrast, with wsdl2h -a
option -a
we obtain an indexed local class _ns__struct_1
in the generated interface header file for soapcpp2:
The next local struct or class is named _ns__struct_2
and so on. The same indexing applies to local unions and enums.
This option generates bi-directional operations (duplex operations) intended for asynchrounous server operations. The bi-directional operations for server response messages are generated in addition to the request-response operations.
For example, the wsdl2h tool generates the following declaration of a service operation ns__add
for a hypothetical calculator Web service:
By contrast, with this option -b
we obtain an additional one-way operation ns__addResponse
to send and receive one-way response messages:
Where void
as a result parameter means that the operation uses "one-way" messaging, in this case to send and receive response messages one-way asynchronously:
int soap_send_ns__addResponse(struct soap *soap, const char *endpoint, const char *action, double& result)
int soap_recv_ns__addResponse(struct soap *soap, double& result)
At the sender side use soap_send_ns__addResponse
to send the message one-way, followed by soap_recv_empty_response
to receive the HTTP acknowledgment. At the receiver side use soap_recv_ns__addResponse
. To develop a server, simply implement soap_ns__addResponse
to handle the service operation and in this function call soap_send_empty_response
to send the HTTP acknowledgment. The same applies to C++ proxy classes generated by soapcpp2.
soap_send_ns__add
to send the request and then call soap_recv_ns__add
to receive the response after polling the server connection with soap_ready
to check if the server is ready (soap_ready
returns SOAP_OK
) to send the response message as a reply message to be received by the client. Therefore, this option -b
is not required to implement asynchronous request-response messaging but rather adds one-way asynchronous response messaging as well.This option sets the source code output to C, C++, or C++11, respectively.
For C++ and C++11 you can also use wsdl2h -s
option -s
to replace std::vector
by arrays and replaces std::string
by char*
. Use a typemap.dat
file to specify further details for the source code output generated by wsdl2h.
This option makes attribute members of a struct or class with default or fixed values optional with pointers. Elements with default and fixed values are not affected by this option.
Without this option, optional attributes with default or fixed values are always output in XML, because the struct/class attribute member is not a pointer. This does not negatively affect the meaning of the XML produced, because omitted attributes are replaced by their default or fixed value.
For example:
By default without this option, this schema is translated by wsdl2h to the following interface header file declaration:
The deserializer populates the attribute value with the default or fixed value when the attribute is omitted from XML. The element is populated when the element is empty, i.e. <bar/>
or <bar></bar>
, but not when it is omitted, as per the W3C XML Schema standards.
This option forces the optional attributes to be pointer-based members, meaning that their output can be turned on or off by setting the pointer to a value or to NULL:
This option replaces literal XML strings _XML
(a char*
string with XML content) with DOM nodes that are used to store the content of xsd:any
, xsd:anyAttribute
xsd:anyType
, and mixed content values. The DOM API offers more features to manipulate XML content compared to the literal _XML
string type.
The DOM node type xsd__anyType
of the gSOAP DOM API is imported in the wsdl2h-generated interface header file with #import "dom.h"
where dom.h
is located in the gsoap/import
directory. This requires compiling gsoap/dom.c
in C and gsoap/dom.cpp
in C++.
For example:
By default without this option, this schema is translated by wsdl2h to the following interface header file declarations:
The xsd__anyType
type has _XML
simpleContent stored in __item
. Names starting with double underscores have no representation in XML as elements or attribute names, meaning that only their values matter. Therefore, _XML __any
holds the element and its content in a string.
With wsdl2h -d
option -d
we obtain:
See DOM API for details on how to use the xsd__anyType
and xsd__anyAttribute
.
This option removes the prefix qualifier from enumeration names.
Without this option all enumeration names are prefixed by their enum
name to ensure that enumeration names do not clash with other constants and enumeration names.
For example:
By default without this option, this schema is translated by wsdl2h to the following interface header file declarations:
By contrast, with wsdl2h -e
option -e
we obtain:
Where enumeration names are suffixed with underscores to make them unique.
Note that C++11 scoped enumerations can be used with wsdl2h -c++11
option -c++11
, which makes option -e
useless.
This option produces interface header files with struct/class declarations that simulate inheritance using transient pointer members to derived types. This option is particularly useful for C source code generation when derived types are required by the application. Derived type values are indicated by xsi:type
attributes in XML with the derived type name.
This option can also be used for C++ to replace class inheritance by simulated inheritance using transient pointer members in base classes that point to the value of a derived type, meaning that the base class instance is replaced by the derived class instance. This option also removes pointers from array and container item types. These pointers are normally added to ensure containers can contain derived type values, but pointers are no longer needed by the simulated approach that add pointer members to the base classes.
For example:
By default without this option, this schema is translated by wsdl2h -c
option -c
to the following interface header file declaration in C that lacks inheritance:
By contrast, with wsdl2h -c -F
option -F
we obtain an interface header file with simulated inheritance using transient pointer members of base types pointing to derived types:
Each transient pointer member name that is used to point to a derived type must match the type name as shown, but trailing underscores are allowed in the member name and type name, to prevent name clashes.
This latter form supports xsi:type
attributes in XML with the derived type name to replace base type values by derived type values at runtime by setting one of the transient pointer members to non-NULL. For example, assume ns:data
has a base type ns__base
(i.e. declared as struct ns__base data
) then the following is legal and serializable:
This is serialized XML for data.value
with data.ns__derived1
and data.ns__derived2
both set to NULL.
This is serialized XML for data.ns__derived1->value
and data.ns__derived1->name
where data.ns__derived1
is non-NULL, for example allocated and set with data.ns__derived1 = soap_new_ns__derived1(soap)
.
This is serialized XML for data.ns__derived2->value
and data.ns__derived2->x
where data.ns__derived1
is NULL and data.ns__derived2
is non-NULL, for example allocated and set with data.ns__derived2 = soap_new_ns__derived2(soap)
.
This is serialized XML for data.ns__derived1->ns__derived3->value
, data.ns__derived1->ns__derived3->name
, and data.ns__derived1->ns__derived3->x
where data.ns__derived1
and data.ns__derived1->ns__derived3
are non-NULL.
Note that C++ class inheritance achieves the same results for base and derived types, but without the use of transient pointer members. However, this requires container values to be pointers to support type derivation (class members are already pointers), as generated by wsdl2h for C++.
This option removes C++ class inheritance to produce a flat C++ class hierarchy similar to structs in C as generated by wsdl2h.
As a side effect, derived type values can no longer be serialized in place of base type values, see also wsdl2h -F
option -F
.
Basically this option removes support for xsi:type
in XML that indicates a derived type that is restricted or extended from its base type.
This option also removes pointers from array and container item types, because there are no derived types that could extend the item value types. These pointers are normally added to ensure containers can contain derived type values in addition to the base type values.
For example:
By default without this option, this schema is translated to the following interface header file declaration in C++ with base and derived classes:
By contrast, with wsdl2h -f
option -f
we obtain an interface header file without inheritance but with classes that are extended with the base class members:
This former form supports xsi:type
attributes in XML with the derived type name to replace base type values by derived type values at runtime. But this latter form does not support xsi:type
attributes in XML and only the base class can be serialized, for example ns__base data
:
This is serialized XML for data.value
.
This example can be deserialized when SOAP_XML_STRICT
is not enabled, but only the value
is retained in data.value
. However, when SOAP_XML_STRICT
is enabled, deserialization fails due to the additional element name
that is rejected.
This option adds global top-level element and attribute declarations to the interface header file generated by wsdl2h.
For example:
By default without this option, this schema is translated to the following C++ interface header file (the C interface header file is similar) that declares the ns__record
type for tns:record
but does not declare attribute tns:type
and element tns:data
:
By contrast, with wsdl2h -g
option -g
we obtain an interface header file with the attribute and element declarations:
This defines _ns__type
and _ns__data
, where the latter can be used as a root element to serialize its content with the soapcpp2-generated readers and writers:
which parses and re-writes the XML fragment:
Note that top-level element and attribute type names start with an underscore to distinguish them from types. This convention is also used by soapcpp2 to generate schemas that define top-level attributes and elements.
Note that a schema may define a global top-level element with a local type, for example:
This schema is translated to the following C++ interface header file (the C interface header file is simular) that declares the _ns__record
type and element for the tns:record
top-level element:
In this case option -g
has no effect, because tns:record
has a local type that may be used elsewhere in the schema.
This option displays help info and then exits.
This option specifies a directory path to search for WSDL and XSD files.
For example:
wsdl2h -I path file.wsdl
This searches path
for .wsdl
and .xsd
files that are imported by file.wsdl
and by other imported files.
When a WSDL or XSD file imports another file then:
http://
or by https://
is retrieved from the specified URL.file://
is retrieved from the path specified relative to the directory in which wsdl2h
is run and the -I
option can be used to change that location to import from./
) or a file name with path stating with ../
are considered files located at relative path locations with respect to the current WSDL and XSD that is importing this filewsdl2h
is run and the -I
option can be used to change that location to import from.WSDL and XSD files that import other WSDL and XSD files typically use relative paths, at least that is recommended by best practices. If absolute paths are used then wsdl2h may fail to find the imported WSDLs and XSDs. This option resolves relative paths but does not help to resolve absolute paths. In the worst case one must edit the WSDLs and XSDs to refer to proper file locations.
This option skips over schema import
and as a result none of the imported schemas and their components are imported.
There are two reasons to use this option:
#import
, andtargetNamespace
namespace names are relevant when schemas reference imported schemas by their namespace, not the schema file name.This option skips the generation of SOAP_ENV__Header
and SOAP_ENV__Detail
structure definitions, assuming that these are manually replaced in the generated interface header file for soapcpp2.
This option skips the generation of mustUnderstand
qualifiers for SOAP_ENV__Header
members. This removes the mustUnderstand="true"
XML attributes from SOAP Headers in SOAP messages. As per SOAP standard, SOAP Headers with mustUnderstand="true"
must not be ignored by receivers.
This option generates less documentation by removing generic @note
comments from the interface header file output, thereby reducing the size of the output without removing critical information.
This option displays license information.
This option suppresses the wsdl2h error message
"must understand element with wsdl:required='true'"
This error indicates that a (special) WSDL construct was used that is marked wsdl:required="true"
, meaning that must not be ignored by the WSDL processor (unless the developer knows what he or she is doing).
This option tells wsdl2h to use xsd.h
to define the primitive XSD types instead of generating them in the interface header file for soapcpp2. This option offers an alternative to the use of typemap.dat
to redefine primitive XSD types by defining them all together instead of on a type-by-type basis. The interface header file output by wsdl2h includes #import "xsd.h"
.
This option specifies a name to be used as a service namespace prefix for each WSDL binding.
By default without this option, the wsdl2h tool warns when it reads one or more WSDLs that define multiple bindings:
Warning: 3 service bindings found, but collected as one service (use option -Nname to produce a separate service for each binding)
This means that all 3 services will be collected under one name. When proxy and service classes are generated with soapcpp2 -i
option -i
or with soapcpp2 -j
option -j
then the service operations are collected into one proxy and service class. Essentially only one namespace is used. This may lead to clashes when multiple bindings define the same Web service operations (name clashes are resolved by wsdl2h by adding trailing underscores).
By contrast, with wsdl2h -N name
option -N name
we obtain an interface header file that uses the specified name as a prefix to define the service bindings and service operations.
For example:
wsdl2h -N foo file.wsdl
If file.wsdl
has multiple bindings, then the Web service operations associated with each binding are identified by their prefix foo1
, foo2
, foo3
, and so on. As a result, we obtain more than one proxy and service class generated by soapcpp2, one for each binding.
This option changes the default ns
namespace prefix to the specified prefix name.
By default without this option, the XML namespace prefix is ns
which results in the generation of prefixes ns1
, ns2
, ns3
, and so on.
For example:
wsdl2h -n foo file.wsdl
This generates namespace prefixes foo1
, foo2
, foo3
, and so on.
typemap.dat
file to prevent future runs of wsdl2h to produce namespace prefixes that are not in the same original order. For example when the order of WSDLs and XSDs changes or if new WSDLs and XSDs are added. Therefore, do not use this option unless the single WSDL processed by wsdl2h is relatively simple and does not import WSDLs and XSDs.This option optimizes the generated interface header file:
-O1
removes duplicate choice/sequence members;-O2
optimize with -O1
and remove unused schema types (types that are unreachable from top-level schema element and attribute roots);-O3
optimize with -O2
and remove unused schema top-level root attributes;-O4
optimize with -O3
and remove unused schema top-level root elements, only retain the root elements used by WSDLs. Use this option only when converting WSDLs (and their associated XSD schemas) to source code, not when solely converting XSD schemas to source code.Option -O4
is the most aggressive. When used only for one or more XSDs as input to wsdl2h, the output will be empty because removing the root elements (and attributes) results in removing all types from the schema. However, this option is safe to use with WSDLs to aggressively remove all unused schema components that are unreachable from the Web service operation parameter elements and types. Option -O3
is safe to use with one or more XSDs as input to wsdl2h instead of WSDLs, for example when developing an XML application that serializes data as XML root elements (wsdl2h -g
option -g
is recommended in this case).
Optimization by schema slicing removes unused types, which are types that are unreachable from top-level schema element and attribute roots. A type is marked as used when:
Marking proceeds recursively until no more types can be marked. All remaining unused types are removed. Top-level elements and attributes are selectively marked unused and removed depending on the level of optimization applied, with -O3
removing unused top-level attributes and -O4
removing unused top-level elements except for all elements used in the specified WSDLs.
Aggressive optimization with options -O2
, -O3
, and -O4
removes derived type extensions of a base type when the derived types are not marked as used. However, in certain messaging scenarios this may have the undesired effect that this limits the choice of derived types that can be used to replace a base type in XML messages, because a derived type may have been removed when it is not marked as used elsewhere in the WSDLs and XSD schemas. A derived type that replaces a base type in an XML message is indicated by a xsi:type
attribute with the QName value of the derived type. The wsdl2h tool generates a C++ class hierarchy to support type derivation, so assigning a derived type value instead of a base type value to a pointer member is automatically serialized in XML with the specified derived value (which is indicated by xsi:type
attribute in the XML message). For C applications, we should use wsdl2h -c -F
option -c
and option -F
to simulate inheritance in C. In both cases it is recommended to use the following options to retain all derived type extensions of a base type that is marked as used:
-Ow2
optimize with -O2
to remove unused schema types, but retain types that are derived types of base types that are marked as used. .-Ow3
optimize with -O3
to remove unused schema top-level root attributes, but retain types that are derived types of base types that are marked as used..-Ow4
optimize with -O4
to remove unused schema top-level root elements, but retain types that are derived types of base types that are marked as used.This permits a base type value (typically a struct or class member that is a pointer to a base type) to be assigned a derived type in C++, which is serialized in XML with a xsi:type
attribute to indicate the type of the derived value. Likewise, XML data with derived type values are deserialized to C/C++ data automatically. Inheritance is simulated in C, see option -F
.
This option specifies a file name for the wsdl2h interface header file output.
By default without this option, the wsdl2h tool writes the interface header file to the file named after the first file name input at the command line, but using .h
as the file name extension.
When the input to the wsdl2h tool consists of URLs, the wsdl2h tool writes its output to standard output (usually the screen). Use this option to specify a file instead.
For example:
wsdl2h calc.wsdl
This saves calc.h
because the first file specified on the command line is calc.wsdl
.
Option -o
should be used when a URL is specified on the command line:
wsdl2h -o calc.h http://www.genivia.com/calc.wsdl
This saves the interface header file calc.h
.
This option disables the generation of types inherited from the xsd__anyType
base type.
This option has effect only when wsdl2h -p
option -p
is used or when the wsdl2h tool detects that xsd:anyType
is used (thereby implicitly and automatically enabling option -p
), which means that xsd__anyType
should be a base type for all possible types defined in the schemas.
This option makes all types inherit xsd__anyType
to support full polymorphism.
This option is automatically enabled when the wsld2h tool detects that xsd:anyType
is used, which means that xsd__anyType
should be a base type for all possible types defined in the schemas. To disable, use wsdl2h -P
option -P
.
For example:
This schema is translated to the following C++ interface header file that declares the xsd__anyType
type with _XML
simpleContent (meaning that __item
contains element content as per gSOAP convention) and the ns__data
class:
The xsd__anyType
pointer values of the items of the vector can be assigned derived class instances to serialize any type of value declared in the interface header file, including the xsd__string_
wrapper class with simpleContent and the ns__data
class with complexContent.
This schema is translated to the following C interface header file with wsdl2h -c -F
option -c
and option -F
to simulate inheritance in C:
The xsd__anyType_
values of items of the dynamic array (item
points to an array of size __sizeitem
which is a special member to indicate dynamic arrays) can be assigned base xsd__anyType_
and derived types, see wsdlh2 -F
option -F
.
This option makes xsd__anySimpleType
equal to xsd__anyType
to use as the base type for derivation. This option is more effective when used with wsdl2h -p
option -p
for C++ applications and wsdl2h -F
option -F
for C applications. This option can also be used with wsdl2h -d
option -d
to make xsd__anySimpleType
equal to a DOM node.
Without option -Q
, the xsd__anySimpleType
type is just a C/C++ string generated by wsdl2h:
The reason for this choice is that some WSDLs and XSD schemas use xsd:anySimpleType
to declare XML attributes of any type (because XML attributes must be simple types xsd:anyType
is invalid to use for attributes). The values of XML attributes of type xsd:anySimpleType
can be any character data essentially. There is no mechanism to indicate the actual type of the attribute value used, unlike elements that are annotated with xsi:type
attribute with the derived type as its QName value. Therefore, by considering xsd__anySimpleType
just strings we can provide any value for XML attributes of type xsd:anySimpleType
.
However, there are other uses of xsd__anySimpleType
in XSD schemas, where essentially xsd__anySimpleType
serves the same purpose as xsd__anyType
to provide a base type for derived types, but restricts the derived types to simple types.
Unfortunately, these two cases clash: we want to use C/C++ strings for XML attributes of type xsd:anySimpleType
and also use xsd:anySimpleType
as a base class for derived types.
Option -Q
enables the latter case by making xsd__anySimpleType
equal to xsd__anyType
so that elements of type xsd:anySimpleType
can be serialized with a derived type, using inheritance in C++ and by using simulated inheritance in C using wsdl2h -F
option -F
.
For example, option -Q
changes this generated code for C++ applications:
into:
where all other classes generated by wsdl2h option -p
are derived from xsd__anyType
, meaning that value
can be assigned any one of these classes as long as the class is a simple type wrapper (wsdl2h generates comments to indicate that the polymorhpic value should be a xsd:anySimpleType
).
Similar code is generated by wsdl2h option -F
for C applications.
On the other hand this option invalidates XML attributes of type xsd:anySimpleType
. The soapcpp2 tool warns about this invalid attribute type as a result.
This option specifies a C++ namespace name. The interface header file declarations are placed in the given C++ namespace.
For example:
wsdl2h -q api file.wsdl
The generated interface header file for soapcpp2 places all declarations in the api
C++ namespace:
SOAP_ENV__Header
and SOAP_ENV__Detail
structures, which become part of the given C++ namespace. However, to use the SOAP_ENV__Header
and SOAP_ENV__Detail
structures these should be declared at the global scope. This option places these structures with the types used by their members in the given C++ namespace, making them unavailable to the global scope.See How to build a client or server in a C++ code namespace for details on using C++ namespaces to build client and server applications, which requires a env.h
file with SOAP Header and Fault definitions to be compiled with:
soapcpp2 -penv env.h
The generated envC.cpp
file holds the SOAP Header and Fault serializers and you can link this file with your client and server applications.
This option has no effect for C source code output.
This option enables the generation of REST service operations in the interface header file saved by wsdl2h for soapcpp2.
By default without this option, REST service operations defined in one or more WSDLs are ignored.
With this option, both REST and SOAP service operations are declared in the interface header file.
This option specifies a proxy host name and port number with proxy credentials to connect to web sites through a proxy server.
This option can also be used to specify credentials to access a web site that requires authentication (HTTP basic or digest authentication).
For example:
wsdl2h -r proxy.example.org:80:proxyuserid:proxypasswd -r userid:passwd
This option renames the soap
members of the generated C++ classes in the interface header file for soapcpp2.
By default without this option, wsdl2h adds struct soap *soap
members to classes and structs. This member points to the soap
context that manages the instance, when the instance was allocated by the gSOAP engine.
To remove the struct soap *soap
members use this option with an empty name:
wsdl2h -S '' file.wsdl
To rename the struct soap *soap
members, specify a name for the member, for example ctx
:
wsdl2h -S ctx file.wsdl
This option has no effect for C source code output.
This option does not generate C++ std
data types and replaces std::vector
and std::string
by C-like equivalents and is intended for systems with limited support for C++ libraries.
The std::vector
struct/class member is replaced by a dynamic array, declared with a __size
member followed by a pointer member to the array items.
The std::string
is replaced by char*
.
This option has no effect for C source code output.
This option specifies an alternate file or path for typemap.dat
. See typemap.dat
file.
For example:
wsdl2h -t $GSOAP/gsoap/typemap.dat file.wsdl
This option allows UTF-8-encoded Unicode C/C++ identifier names in the generated interface header file for soapcpp2. This assumes that the C/C++ compiler that is used to compile a gSOAP client or server application supports Unicode identifier names.
By default without this option, Unicode XML names in WSDLs and XSDs are preserved using the gSOAP convention for UCS-2 characters in identifier names with _xHHHH
where HHHH
is a hexadecimal Unicode character code point.
With this option, Unicode XML names in WSDLs and XSDs are preserved "as is" in C/C++ identifier names.
This option replaces unions with structs/classes in the generated interface header file for soapcpp2. Union members are used to represent xsd:choice
of elements. A choice of elements can also be represented by pointer members of a struct/class such that only one member is non-NULL. However, when using a struct/class instead of a union, the deserialization validator will not reject additional elements when present.
For example:
By default without this option, wsdl2h generates a tagged union
for the xsd:choice
, where the tag is a special member int __union_data
that is set to SOAP_UNION__ns__union_data_string
when the string
union member is valid or SOAP_UNION__ns__union_data_number
when the number
union member is valid:
With this option, wsdl2h removes the union
and replaces it with pointer members to produce a simpler structure:
This option displays the current wsdl2h tool version and then exits.
This option enables verbose output to assist in debugging the wsdl2h tool.
This option suppresses all warnings produced by wsdl2h. Errors are not suppressed.
This option wraps response parameters in a response struct.
The last parameter of a service operation declared as a function in the interface header file is the response parameter. When multiple response parameters are returned by the service operation or if the response parameter is a complexType (a struct or class), then the parameters should be wrapped in a special "response struct". However, if a single response parameter is a primitive type value then this parameter does not need to be wrapped in a response struct.
This option consistently wraps response parameters in a response struct, even when a single response parameter is a primitive type value.
Document/literal wrapped patterns may cause ambiguities with respect to message namespace qualification. A part
name associated with a type
is implicitly qualified by the targetNamespace of the WSDL but may also be associated with the namespace of the type. By default, the wsdl2h tool uses the namespace of the type when the type is not a primitive XSD type, otherwise the WSDL targetNamespace is used.
As an example of a document/literal wrapped pattern message, consider:
Note that message name="Message"
has two parts with both a type, which makes these part namespaces amiguous. The generated interface header file declares a wrapper for the Name
request message and the Info
response message:
Here, Name
belongs to the ns1
namespace, i.e. by the __ns1__Operation
, whereas Info
belongs to the ns2
namespace. The __ns1__Operation
is just a wrapper for the operation and is not visible in XML. Only Name
and Info
are serialized in XML as the request and response message, respectively.
With option -X
the ns2
qualifier is removed:
Now both Name
and Info
belong to the ns1
namespace, i.e. by the __ns1__Operation
.
However, best practices for document/literal messaging recommend to avoid this wrapped pattern construct in favor of using elements defined in schemas:
The elements Name
and Record
are the actual message names, qualified by the schema's targetNamespace:
See also wsdl2h option -z7
.
This option removes _XML
type members of structs and classes that are generated for xsd:any
and xsd:anyAttribute
components.
There are two options to represent xsd:any
and xsd:anyAttribute
components: the literal _XML
string type with XML content (a char*
string) or a DOM node. DOM nodes are generated for xsd:any
and xsd:anyAttribute
components with wsdl2h -d
option -d
, which also defines xsd:anyType
as the DOM node xsd__anyType
in C and C++.
This option adds typedef synonyms for structs and enums to the interface header file, which is useful for C source code. A typedef synonym for a struct is declared by typedef struct name name;
and for an enum is declared by typedef enum name name;
.
These options are for backward compatiility with older gSOAP releases:
-z1
compatibility with 2.7.6e: generate pointer-based arrays-z2
compatibility with 2.7.15: (un)qualify element/attribute referenced members-z3
compatibility with 2.7.16 to 2.8.7: (un)qualify element/attribute referenced members-z4
compatibility up to 2.8.11: don't generate union structs in std::vector-z5
compatibility up to 2.8.15: don't include minor improvements-z6
compatibility up to 2.8.17: don't include minor improvements-z7
compatibility up to 2.8.59: don't generate std::vector
of class of union-z8
compatibility up to 2.8.74: don't generate qualifiers for doc/lit wrapped patterns-z9
compatibility up to 2.8.93: always qualify element/attribute referenced members, even when defined in the same namespace with default forms unqualified-z10
compatibility up to 2.8.96: generate qualifiers even when defined without namespaceThis option replaces _USCORE
by the Unicode _x005f
character code point in identifier names in C and C++ in the generated interface header file.
The typemap.dat
file for the wsdl2h tool can be used to customize or optimize the type bindings by mapping schema types to C/C++ types. This file contains custom XML schema to C/C++ type bindings and XML namespace bindings for namespace prefixes to be generated by the wsdl2h tool. You can edit this file to enable features such as custom serializers for schema types, C++11 smart pointers to replace regular pointers, bind XML namespace prefixes to XML namespace URIs, and specify bindings for schema types.
Here is a simple example of a typemap.dat
file:
# This file contains custom definitions of the XML Schema types and # C/C++ types for your project, and XML namespace prefix definitions. # The wsdl2h WSDL importer consults this file to determine bindings. [ // This comment will be included in the generated .h file // You can include any additional declarations, includes, imports, etc. // within [ ] sections. The brackets must appear at the start of a line ] # XML namespace prefix definitions can be provided to override the # default choice of ns1, ns2, ... prefixes. For example: i = "http://www.soapinterop.org/" s = "http://www.soapinterop.org/xsd"
The i
and s
prefixes are declared such that the header file output by wsdl2h uses these prefixes instead of the default ns1
, ns2
, etc. It is strongly recommended to name the prefixes in this way, because future runs of wsdl2h may result in a different assignment of the default ns1
, ns2
, ... prefixes. Therefore, it is recommended that application code should not rely on the default prefixes.
Type bindings can be provided to bind XML schema types to C/C++ types for your project. These type bindings have four parts:
prefix__type = declaration | use | ptr-use
where prefix__type
is the C/C++ type name of the schema type (using gSOAP's type naming conventions), the declaration
part declares the C/C++ type in the generated header file which may be empty to omit, the optional use
part specifies how the type is used by other types such as by member declarations and as function parameters, and the optional ptr-use
part specifies how the type is used as a pointer type by other types and as function parameters.
# Example XML Schema and C/C++ type bindings: xsd__int = | int xsd__string = | char* | char* xsd__boolean = enum xsd__boolean { false_, true_ }; | enum xsd__boolean xsd__base64Binary = class xsd__base64Binary { unsigned char *__ptr; int __size; }; | xsd__base64Binary | xsd__base64Binary # You can extend structs and classes with member data and functions. # For example, adding a constructor to ns__myClass: ns__myClass = $ ns__myClass(); # The general form is # class_name = $ member;
XML Schema types are associated with an optional C/C++ type declaration, a use reference, and a pointer-use reference. The pointer-use reference of the xsd__byte
type for example, is int*
because char*
is reserved for strings.
For example, you can replace the std::string
that used by default for C++ with a wide string:
xsd__string = | std::wstring
Or replace the char*
strings that are used by default for C with wchar_t*
:
xsd__string = | wchar_t* | wchar_t*
When the ptr-use
part is not specified, it will be auto-generated as pointer T*
for use
type T
or std::shared_ptr<T>
when the variable $POINTER = std::shared
.
The declaration
part need not be empty, for example if a type must be declared. For example:
xsd__string = typedef std::string mystring; | mystring | std::optional<mystring>
When a type binding requires only the use
part to be changed, the declaration part can be an ellipsis ...
, as in:
prefix__type = ... | use | ptr-use
The ...
ellipsis ensures that the wsdl2h-generated type definition is preserved, while the use
and ptr-use
parts are amended as specified.
This method is useful to serialize types dynamically, when XML elements carry the xsi:type
attribute indicating the type of element content. The following illustrates an "any" type mapping for the ns:sometype
XSD type in a schema. This type will be replaced with a "any" type wrapper that supports dynamic serialization of element types indicated by the xsi:type
attribute:
[ struct __any { int __type; // set to a SOAP_TYPE_T value void *__item; // points to data of type T as serialized per SOAP_TYPE_T } ] xsd__anyType = ... | struct __any | struct __any
where __type
and __item
are used to serialize any data type in the wrapper. The __item
member points to the value (de)serialized, with the type of this value indicated by __type
which is a SOAP_TYPE_T
value for type named T
.
To match an element with content to (de)serialize, rename the __item
member to the XML element name, as usual.
Additional members can be specified to extend a generated struct or class. Class and struct extensions are of the form:
prefix__type = $ member-declaration
For example, to add getter and setter methods to class myns__record
(see also Section Get and set methods):
myns__record = $ int get(struct soap *soap) const; myns__record = $ int set(struct soap *soap);
Another way to use typemap.dat
is to remap one C/C++ type to another type:
prefix__type1 == prefix__type2
This replaces prefix__type1
by prefix__type2
in the wsdl2h output. For example:
SOAP_ENC__boolean == xsd__boolean
where SOAP_ENC__boolean
is replaced by xsd__boolean
, which in turn may be mapped to a C enum xsd__boolean
type or C++ bool
type.
The $CONTAINER
variable defines the container type to use in the wsdl2h-generated declarations for C++, which is std::vector
by default. For example, to use std::list
as the container in the wsdl2h-generated declarations we add the following line to typemap.dat
:
$CONTAINER = std::list
Also a Qt container can be used instead of the default std::vector
, for example QVector
:
[ #include <QVector> ] $CONTAINER = QVector
To remove containers, use wsdl2h -s
. This also removes std::string
, but you can re-introduce std::string
with
xsd__string = | std::string
The typemap.dat
$POINTER
variable defines the smart pointer to use in the wsdl2h-generated declarations for C++, which replaces the use of *
pointers. For example:
$POINTER = std::shared_ptr
Not all pointers in the generated output are replaced by smart pointers by wsdl2h, such as pointers as union members and pointers as struct/class members that point to arrays of values.
The variable $SIZE
defines the type of array sizes, which is int
by default. For example, to change array size types to size_t
:
$SIZE = size_t
Permissible types are int
and size_t
. This variable does not affect the size of dynamic arrays, xsd__hexBinary
and xsd__base64Binary
types, which is always int
.
When C++17 is enabled with wsdl2h and soapcpp2 option -c++17
, you can also semi-automatically enable std::optional
declarations with optional class and structure member variables. This means that std::optional
is used instead of a (smart) pointer to make a member optional.
To enable std::optional
with member variables that are primitive types, typedef
, and enum
automatically:
$OPTIONAL = std::optional
Local unnamed simpleType restrictions may not adopt the specified optional type and still use pointers instead. This limitation may be lifted in a future release.
The soapcpp2 tool is invoked from the command line and optionally takes the name of a header file as an argument or, when the file name is absent, parses the standard input:
soapcpp2 file.h
where file.h
is an interface header file generated by wsdl2h or developed manually to specify the service operations as function prototypes and C/C++ data types to serialize in XML.
The soapcpp2 tool produces the XML data binding implementation source code, client-side stub functions, and server-side skeleton functions.
The type of files generated by soapcpp2 are:
soapStub.h
a modified and annotated header file produced from the input interface header file, this file is compilable by C/C++ compilers while the input interface header file is not.soapH.h
the main header file to be included by the application source code, this file also includes soapStub.h
.soapC.cpp
(or .c
for C) the serializers for the C/C++ types specified in the interface header file.soapClient.cpp
(or .c
for C) the client-side stub functions to invoke remote service operations.soapServer.cpp
(or .c
for C) the server-side skeleton functions to dispatch service requests to user-define service functions.soapClientLib.cpp
(or .c
for C) the client-side stub functions combined with local static serializers to be integrated as one big "library".soapServerLib.cpp
(or .c
for C) the service-side skeleton functions combined with local static serializers to be integrated as one big "library"soapXYZProxy.h
the C++ proxy class declaration generated with soapcpp2 -i
or soapcpp2 -j
soapXYZProxy.cpp
the C++ proxy class implementation generated with soapcpp2 -i
or soapcpp2 -j
soapXYZService.h
the C++ service class declaration generated with soapcpp2 -i
or soapcpp2 -j
soapXYZService.cpp
the C++ service class implementation generated with soapcpp2 -i
or soapcpp2 -j
*.xsd
files are generated containing XML schemas for each namespace prefix ns
used in the interface header file input to the soapcpp2 tool, see also Section How to generate WSDL service descriptions . Not applicable when the interface header file was generated with wsdl2h.*.wsdl
files are generated containing WSDL descriptions for each namespace prefix ns
used by service operations in the interface header file input to the soapcpp2 tool, see also Section How to generate WSDL service descriptions . Not applicable when the interface header file was generated with wsdl2h.*.xml
files with SOAP or XML request and response messages are generated.*.nsmap
the XML namespace mapping table, generated for the first namespace prefix ns
found in the interface header file input to the soapcpp2 tool.If client and service applications are to be developed for the same Web services API then the same interface header file can be used to generate the source code for both the client and the service. There is no need to generate a WSDL with soapcpp2 and then use that WSDL to generate a new interface header file with wsdl2h. The new header file generated by this approach will not be identical to the original header file.
The soapClientLib.cpp
and soapServerLib.cpp
can be used to build client and server libraries. The serialization functions are declared static to avoid link symbol conflicts. For this approach to compile, we also should create a separate interface header file env.h
with SOAP Header and Fault structures with serializers that are non-static, i.e. globally declared and implemented, as described in Section How to create client/server libraries .
The following files are part of the gSOAP source code package and are required to build gSOAP applications:
gsoap/stdsoap2.h
the header file to include in your source code, but already included when including soapH.h
.gsoap/stdsoap2.c
the C source code of the entire gSOAP engine.gsoap/stdsoap2.cpp
(or .c
for C) the source code of the entire gSOAP engine.gsoap/dom.cpp
(or .c
for C) the source code of the DOM parser, which is optional and only required when using DOM such as with WS-Security.The soapcpp2 tool supports the following command-line options:
option | result |
---|---|
-0 | no SOAP, generate REST source code |
-1 | generate SOAP 1.1 source code |
-2 | generate SOAP 1.2 source code |
-A | require HTTP SOAPAction headers to invoke server-side operations |
-a | use HTTP SOAPAction headers with WS-Addressing to invoke server-side operations |
-b | serialize byte arrays char[N] as string |
-C | generate client-side source code only |
-c | generate C source code |
-c++ | generate C++ source code (default) |
-c++11 | generate C++ source code optimized for C++11 (compile with -std=c++11 ) |
-d path | use path to save files |
-Ec | generate extra functions for deep copying |
-Ed | generate extra functions for deep deletion |
-Et | generate extra functions for data traversals with callback functions |
-e | generate SOAP RPC encoding style bindings (also use -1 or -2 ) |
-f N | multiple soapC files, with N serializer definitions per file (N>=10) |
-g | generate XML sample messages in template format for testmsgr |
-h | display help info and exit |
-I path | use path (s) for #import (paths separated with : ) |
-i | generate C++ service proxies and objects inherited from soap struct |
-j | generate C++ service proxies and objects that share a soap struct |
-L | don't generate soapClientLib and soapServerLib |
-l | generate linkable modules (experimental) |
-m | generate source code for the Matlab(tm) MEX compiler (deprecated) |
-n | use service name to rename service functions and namespace table |
-p name | save files with new prefix name instead of soap |
-Q name | use name as the C++ namespace, including custom serializers |
-q name | use name as the C++ namespace, excluding custom serializers |
-r | generate soapReadme.md report |
-S | generate server-side source code only |
-s | generate stub and skeleton functions with strict XML validation checks |
-T | generate server auto-test source code |
-t | generate source code for fully xsi:type typed SOAP/XML messages |
-u | uncomment WSDL/schema output by suppressing XML comments |
-V | display the current version and exit |
-v | verbose output |
-w | don't generate WSDL and schema files |
-x | don't generate sample XML message files |
-y | include C/C++ type access information in sample XML messages |
-z1 | compatibility: generate old-style C++ service proxies and objects |
-z2 | compatibility with 2.7.x: omit XML output for NULL pointers |
-z3 | compatibility up to 2.8.30: _param_N indexing and nillable pointers |
-z4 | compatibility up to 2.8.105: char* member defaults, even when the XML element is omitted |
For example
soapcpp2 -L -c -d projects -p my -x file.h
This saves the following source code files:
projects/myH.h
serialization functions, this file should be included in projects.projects/myC.c
serialization functionsprojects/myClient.c
client call stub functionsprojects/myServer.c
server request dispatcherprojects/myStub.h
annotated copy of the source interface header fileprojects/ns.nsmap
namespace table, this file should be included or used in projects.projects/ns.wsdl
WSDL with Web service definitionsprojects/ns.xsd
XML schemaWindows users can use the usual /
for compile-time flags as well as -
, for example:
soapcpp2 -L -c /d projects /p my /x file.h
Options -A
, -a
, -c
, -c++
, -c++11
, -e
, -i
, -j
, -n
, -s
, -t
, -w
, and -x
can also be specified in the interface header file for soapcpp2 using the //gsoapopt
directive, for example:
This option generates XML REST source code by disabling SOAP bindings, essentially disabling the SOAP protocol and replacing it by direct XML REST messaging.
This option uses soap_set_version
at the client side in the generated source code to enable XML REST messaging, disabling SOAP.
In addition, the soapcpp2 tool nullifies the SOAP namespaces from the the generated namespace table file to force a server application that uses this table to use XML REST only:
-0
) with the SOAP namespaces present in the table. XML REST request messages are served and REST messages returned. Likewise, SOAP 1.1 request messages are served and SOAP 1.1 messages returned, SOAP 1.2 request messages are served and SOAP 1.2 messages returned.For example, the following example calculator service SOAP and XML REST request messages are served by a gSOAP service developed with SOAP 1.1 as the default protocol:
The server returns the following XML SOAP 1.1 and XML REST responses:
By default all XML namespaces are included with the root element, which improves messaging performance at the sending and receiving sides, because a stack of xmlns
binding scopes does not need to be maintained. Use SOAP_XML_CANONICAL
to emit xmlns
binding pairs when the XML namespace prefix is used. This is slower but may or may not reduce the message size.
This option forces SOAP 1.1 bindings globally in the generated source code, thereby overriding the SOAP protocol version used in the interface header file input.
This option uses soap_set_version
at the client to enable SOAP 1.1 request and response messages, disallowing SOAP 1.2.
In addition, the soapcpp2 tool saves the SOAP 1.1 namespaces in the second column of the generated namespace table file and the SOAP 1.2 in the third column to allow the server to accept SOAP 1.1 and SOAP 1.2 requests:
This option forces SOAP 1.2 bindings globally in the generated source code, thereby overriding the SOAP protocol version used in the interface header file input.
This option uses soap_set_version
at the client to enable SOAP 1.2 request and response messages, disallowing SOAP 1.1.
In addition, the soapcpp2 tool saves the SOAP 1.2 namespaces in the second column of the generated namespace table file and the SOAP 1.1 in the third column to allow the server to accept SOAP 1.1 and SOAP 1.2 requests:
This option generates server-side source code that requires HTTP SOAPAction headers to be present. The server invokes server-side operations based on the SOAPAction header value in request messages, instead of the SOAP/XML request message name which is ignored. This option is used with WS-Addressing, WS-ReliableMessaging, and WS-Discovery servers to relay messages based on HTTP SOAPAction headers and/or the SOAP Header wsa:Action
when present (the latter requires the [WS-Addressing plugin](wsaplugin)).
Alternatively, use soapcpp2 -a
option -a
to let the server invoke server-side operations based on the SOAPAction header value in request messages when present, otherwise when not present this lets the server invoke server-side operations based on the SOAP/XML request message name as usual.
This option can also be specified by the //gsoapopt A
directive in the interface header file.
This option generates server-side source code that uses HTTP SOAPAction headers when present to invoke server-side operations based on the SOAPAction header value in request messages, otherwise when not present lets the server invoke server-side operations based on the SOAP/XML request message name as usual. This option is used with WS-Addressing, WS-ReliableMessaging, and WS-Discovery servers to relay messages based on HTTP SOAPAction headers and/or the SOAP Header wsa:Action
when present (the latter requires the [WS-Addressing plugin](wsaplugin)).
Alternatively, use soapcpp2 -A
option -A
to require HTTP SOAPAction headers to be present in SOAP request messages to invoke server-side operations.
This option can also be specified by the //gsoapopt a
directive in the interface header file.
This option serializes byte arrays specified as char[N]
as strings. Without this option char[N]
is serialized as an array of bytes. Fixed-size arrays specified in the interface header file input are generally serialized as arrays in XML using item
elements.
For example:
By default without this option the ns__record
struct is serialized as:
With this option, the ns__record
struct is serialized as:
This option restricts soapcpp2 to generate client-side source code only. When this option is combined with soapcpp2 -CS
option -S
, no client and server source code is generated.
Option -c
generates C source code, -c++
generates C++ source code, and -c++11
generates C++11 source code.
//gsoapopt
directive in the interface header file takes priority over this option, when c
, c++
, or c++11
is declared with this directive in the interface header file.This option specifies a path to save the generated files. For example:
soapcpp2 -d source file.h
This saves files to the source/
directory located within the current directory, which should exist and should be writable.
These options generate extra functions for deep copying of serializable C/C++ data, deep deletion of serializable C/C++ data, and deep data traversals with user-defined callback functions over serializable C/C++ data.
For a serializable type T
declared in the interface header file for soapcpp2, option -Ec
generates:
virtual T * T::soap_dup(struct soap*) const
where T
is a class, returns a duplicate of this object by deep copying, replicating all deep cycles and shared pointers when a managing soap
context is provided as argument. Deep copy is a tree when argument is NULL, but the presence of deep cycles will lead to non-termination. Use flag SOAP_XML_TREE
with the managing context to copy into a tree without cycles and pointers to shared objects.T * soap_dup_T(struct soap*, T *dst, const T *src)
where T
is not a class, deep copy src
into dst
, replicating all deep cycles and shared pointers when a managing soap
context is provided as argument. When dst
is NULL, allocates space for dst
and returns a pointer to the allocated copy. Deep copy results in a tree when the soap
context is NULL, but the presence of deep cycles will lead to non-termination. Use flag SOAP_XML_TREE
with managing context to copy into a tree without cycles and pointers to shared objects. Returns dst
or allocated copy when dst
is NULL.For a serializable type T
declared in the interface header file for soapcpp2, option -Ed
generates:
virtual void T::soap_del() const
where T
is a class, deletes all heap-allocated members of this object by deep deletion ONLY IF this object and all of its (deep) members are not managed by a soap
context AND the deep structure is a tree (no cycles and co-referenced objects by way of multiple (non-smart) pointers pointing to the same data). Can be safely used after T::soap_dup(NULL)
to delete the deep copy. Does not delete the object itself.void soap_del_T(const T*)
where T
is not a class, deletes all heap-allocated members of this object by deep deletion ONLY IF this object and all of its (deep) members are not managed by a soap
context AND the deep structure is a tree (no cycles and co-referenced objects by way of multiple (non-smart) pointers pointing to the same data). Can be safely used after soap_dup_T(NULL, NULL, const T*)
to delete the deep copy returned. Does not delete the object itself.For a serializable type T
declared in the interface header file for soapcpp2, option -Et
generates:
virtual void T::soap_traverse(struct soap *soap, const char *tag, soap_walker p, soap_walker q)
where T
is a class, uses function callbacks p
and q
to traverse this object by deep ordered tree traversals over its members when non-NULL. Function p
is a pre-order function that is called before objects and data are visited recursively and function q
is a post-order function that is called after objects and data are visited recursively. Either p
or q
may be NULL. The tag
string is passed to p
and q
and should not be NULL. Cyclic graphs are treated as trees by pruning pointer back-edges, though this method does not always prevent a data node from being visited twice.void soap_traverse_T(struct soap *soap, T *data, const char *tag, soap_walker p, soap_walker q)
where T
is not a class, uses function callbacks p
and q
to traverse this data by deep ordered tree traversals over its members when present and non-NULL. Function p
is a pre-order function that is called before objects and data are visited recursively and function q
is a post-order function that is called after objects and data are visited recursively. Either p
or q
may be NULL. The tag
string is passed to p
and q
and should not be NULL. Cyclic graphs are treated as trees by pruning pointer back-edges. though this method does not always prevent a data node from being visited twice.The pre-order p
and post-order q
callback functions should be declared as a soap_walker
function, which has the following function signature:
where data
points to the data node visited which is of type soap_type
(a SOAP_TYPE_T
constant), tag
is the non-NULL element or attribute tag name (qualified or unqualified), and type
is the non-NULL C/C++ type of the data. The void* soap::user
member can be used to pass user-defined data to the callbacks.
For example:
soapcpp2 -Ecdt record.h
The main program:
The soap_read_ns__record
deserializes the following XML:
Then soap_traverse_ns__record
call displays the contenst of record
using the pre
and post
walker functions:
struct ns__record record = { char * name = { foo } int value = { 123 } struct ns__record subrecord = { char * name = { bar } int value = { 456 } } }
This option forces SOAP RPC encoding bindings globally in the generated source code, when the SOAP messaging style is not declared in the interface header file with directives.
SOAP document/literal style messaging it the default messaging style. The messaging style can be specified with the //gsoap <prefix> service style:
and //gsoap <prefix> service encoding:
directives. See also SOAP RPC encoded versus document/literal style.
This option can also be specified by the //gsoapopt e
directive in the interface header file.
This option splits the serialization source code saved to soapC.c
and soapC.cpp
files into multiple soapC_NNN
files as specified by the numeric parameter. This option alleviates compilation issues with very large source code files.
For example:
soapcpp2 -f40 file.h
This generates multiple soapC_NNN.cpp
files each with 40 serializers, with NNN
counting from 001
onward.
The value of this option must be larger or equal to 10.
This option generates XML sample messages in template format for the gSOAP Test Messenger testmsgr tool to test SOAP and REST XML clients and servers.
By default without this option, soapcpp2 generates sample XML messages with the proper XML structure but without useful data. The Test Messenger tool generates random messages directed by the template parameters included by soapcpp2 -g
option -g
.
This option only has effect when soapcpp2 -x
option -x
is not used, which skips the generation of sample messages.
This option displays help info and then exits.
This option specifies one or more directory paths to search for imported interface header files. Multiple paths are separated by a colon.
For example:
soapcpp2 -I path1:path2 file.h
This searches path1
and then path2
for files that are imported with #import
in file.h
.
This option generates C++ client-side proxy classes and server-side service classes, where the classes inherit the soap
context struct with the engine state to handle communications and manage memory independently of other class instances.
By contrast, soapcpp2 -j
option -j
allows a soap
context to be used and reused for multiple proxy and server instances.
This option can also be specified by the //gsoapopt i
directive in the interface header file.
This option has no effect for C source code output.
This option generates C++ client-side proxy classes and server-side service classes, where the classes have a pointer member soap
to a soap
context struct that handles communications and manages memory.
By contrast to soapcpp2 -i
option -i
, this option allows a soap
context to be used and reused for multiple proxy and server instances.
This option can also be specified by the //gsoapopt j
directive in the interface header file.
This option has no effect for C source code output.
This option skips the generation of the soapClientLib
and soapServerLib
files. These files are generally not needed to build client and server applications.
These files are useful to compile multiple "libraries" of client and server applications, such that all serialization source code is declared static and kept hidden from the global scope, which makes the serialization functions inaccessible to the global scope to prevent global name clashes.
Alternatively, use soapcpp2 -q name
option -q name
to develop C++ applications with C++ namespaces to prevent global name clashes.
This option is experimental and should only be used to generate source code for modules. This option is auto-enabled when a #module
directive is found in an interface header file for soapcpp2, see how to build modules and libraries with the #module directive.
This option to generate source code for the Matlab(tm) MEX compiler is deprecated.
This option renames the generated service functions soap_serve
to name_serve
and the generated namespace table namespaces
to name_namespaces
to the name
specified with the soapcpp2 -n -p name
option -p name
.
This option is useful to prevent name clashes when soapcpp2 is invoked multiple times to generate source code for different parts of an application. See also how to create client/server libraries.
This option can also be specified by the //gsoapopt n
directive in the interface header file.
This option saves source code files with the specified file name prefix name
with soapcpp2 -p name
instead of soap
as the file name prefix.
This option is useful to prevent name clashes when soapcpp2 is invoked multiple times to generate source code for different parts of an application. See also how to create client/server libraries.
For example:
soapcpp2 -p foo file.h
This saves fooStub.h
, fooH.h
, fooC.cpp
, and so on.
When the main application is build from the renamed name
-prefixed source code files, plugins and custom serializers that are compiled and linked with the application should include nameH.h
instead of soapH.h
. This can be done with the -D SOAP_H_FILE=nameH.h
option to the C/C++ compiler to rename this file to include instead of soapH.h
.
This option specifies a C++ namespace name for the generated source code, including for the custom serializers when used. See also soapcpp2 -q name
option -q name
for details on specifying C++ namespaces.
The source code files are saved with name
as prefix instead of soap
. This means that all plugins and custom serializers that are compiled and linked with the application should include nameH.h
instead of soapH.h
. This can be done with the -D SOAP_H_FILE=nameH.h
option to the C/C++ compiler to rename this file to include instead of soapH.h
.
This option has no effect for C source code output.
This option specifies a C++ namespace name for the generated source code, excluding the custom serializers when used. See also soapcpp2 -Q name
option -Q name
.
This option is the same as specifying a C++ namespace in the interface header file that encapsulates all declarations:
This interface header file format is generated with wsdl2h -q name
option -q name
.
The source code files are saved with name
as prefix instead of soap
. This means that all plugins and custom serializers that are compiled and linked with the application should include nameH.h
instead of soapH.h
. This can be done with the -D SOAP_H_FILE=nameH.h
option to the C/C++ compiler to rename this file to include instead of soapH.h
.
See How to build a client or server in a C++ code namespace for details on using C++ namespaces to build client and server applications, which requires a env.h
file with SOAP Header and Fault definitions to be compiled with:
soapcpp2 -penv env.h
The generated envC.cpp
file holds the SOAP Header and Fault serializers and you can link this file with your client and server applications.
This option has no effect for C source code output.
This option generates a soapReadme.md
markdown report. This report includes details pertaining the serializable data types and Web client and service operations, covering XML type details, serialization functions, and SOAP/REST API programming details.
The markdown report is readable as it is, but can be converted to HTML for improved readability with Doxygen or with pandoc, or can be browsed in Firefox with https://www.genivia.com/files/readmeviewer.html.zip.
This option restricts soapcpp2 to generate server-side source code only. When this option is combined with soapcpp2 -CS
option -C
, no client and server source code is generated.
This option generates client-side stub functions and proxy classes, server-side skeleton functions and service classes with strict XML validation checks enabled. This option effectively hard-codes the SOAP_XML_STRICT
run time mode flag.
This option can also be specified by the //gsoapopt s
directive in the interface header file.
This option generates server auto-test source code. The generated source code implements a test server soapTester.c
(for C) or soapTester.cpp
(for C++) that can be deployed to echo client requests, for example for testing purposes.
For example:
soapcpp2 -T file.h c++ -o tester soapTester.cpp soapServer.cpp soapC.cpp stdsoap2.cpp ./tester 8192 8080
This runs the tester
server on port 8080 with soap
context initialization mode flag 8192 = 0x2000 = SOAP_XML_INDENT
.
See generating an auto test server for client testing for more details. More advanced servers for testing are available with the gSOAP Test Messenger testmsgr tool to test SOAP and REST XML clients and servers.
This option generates source code to fully annotate SOAP/XML messages with xsi:type
attribute values. This option is useful for SOAP RPC encoded messaging with SOAP applications that require xsi:type
attributes for all XML elements in SOAP messages.
This option can also be specified by the //gsoapopt t
directive in the interface header file.
This option uncomments WSDL and XSD files generated by soapcpp2 by supressing the inclusion of `` comments to annotate WSDL and XSD files.
This option displays the current soapcpp2 tool version and then exits.
This option enables verbose output to assist in debugging the soapcpp2 tool.
This option skips the generation of WSDL and XSD files.
This option can also be specified by the //gsoapopt w
directive in the interface header file.
This option skips the generation of sample XML message files.
This option can also be specified by the //gsoapopt x
directive in the interface header file.
This option adds C/C++ type information to the sample XML message files generated by soapcpp2.
These options are for backward compatiility with older gSOAP releases:
-z1
compatibility: generate old-style C++ service proxies and objects-z2
compatibility with 2.7.x: omit XML output for NULL pointers-z3
compatibility up to 2.8.30: _param_N
indexing; nillable pointers-z4
compatibility up to 2.8.105: char*
member defaults, even when the XML element is omittedThe #import
directive is used to include interface header files into other interface header files for soapcpp2. By contrast, the #include
directive (and #define
directive for that matter) is moved by the soapcpp2 tool into the generated source code file soapStub
, see Section The #include and #define directives .
The #import
directive is used for two purposes: we use it to include the contents of one interface header file into another interface header file and to import a module, see Section How to build modules and libraries with the #module directive .
An example of the #import
directive:
where "mydefs.h"
is an interface header file that defines ns__record
:
The #include
and #define
directives are copied by the soapcpp2 tool into the generated source code. These directives are added to the top of the generated soapStub.h
before any other header file is included. Therefore, #include
and #define
directives can be used to influence the generated source code files.
The following example interface header file for soapcpp2 refers to std::ostream
:
This example also uses an #include
and a #define
directive that will be added to the top of soapStub.h
before gsoap/stdsoap2.h
is included.
#define
to override WITH_MACRO
and SOAP_MACRO
compile-time flags is not recommended because the gsoap/stdsoap2.cpp
(gsoap/stdsoap2.c
for C) is used to build the -lgsoap++
(and -lgsoap
for C) library, which is not affected by these macros whereas the soap
context is, as used by the application, leading to predictable crashes. Use SOAPDEFS_H
or WITH_SOAPDEFS_H
to define macros that are visible to all source code compiled.A service operation is specified as a function prototype in an interface header file for soapcpp2. For the function prototypes specified, the soapcpp2 tool generates client stub functions to invoke remote services and generates server skeleton functions to implement services.
The service operation specified by a function prototype should return int
, which is either SOAP_OK
for success and a soap_status
error code for failure, see Section Run-time error codes .
The general format of a service operation specification is:
where
prefix__
is the XML namespace prefix of the methodmethod_name
is the service operation nameinparam1
, ..., inparamn
are the input parameters to the service operation, which are either values or pointer types, but not referencesoutparam
is the single output parameter of the service operation, which must be a pointer or a reference type.A single output parameter is specified and multiple output parameters should be wrapped in a struct or class, see Section Service operation parameter passing . The fully qualified name of the function namespace_prefix__method_name
must be unique and cannot match the name of a struct
, class
, or enum
declared in the same header file.
The method request is send as an XML message using the qualified function name with the input parameters in XML:
where the inparam1
, ..., inparamn
elements are the XML element representations of the inparam
parameter name declarations.
The XML response by the Web service is of the form:
where the outparam
element is the XML element representation of the outparam
parameter name declaration, see Section C/C++ identifier name to XML tag name translation . By convention, the response element name is the method name ending in Response
. See Section Service operation parameter passing on how to change the declaration if the service response element name is different.
With SOAP messaging the request and response XML messages are placed in the SOAP-ENV:Envelope
and SOAP-ENV:Body
elements. SOAP 1.1 document/literal messaging is the default messaging mode in gSOAP, which are modified to SOAP or REST with //gsoap <prefix> service method-protocol:
directives, see Section Directives.
The soapcpp2 tool generates a client stub function for the service operation. This stub is of the form:
This stub is called by a client application to perform the service operation call.
The soapcpp2 tool generates a skeleton functions for the service operation. The skeleton function called by soap_serve
is:
which after deserializing the XML request message calls the prefix__method_name
service operation defined by the service application and serializes the XML response message when the service operation returns SOAP_OK
.
Alternatively, soapcpp2 -j
option -j
or option -i
generates a C++ client proxy class and a service class. These classes have methods corresponding to the service operations, which on the client side can be invoked to invoke remote service operations and on the server side are implemented by the service application to execute the service operations.
The input parameters of a service operation must be passed by value or by pointer. Input parameters cannot be passed by reference. Passing a pointer to the data is preferred when the size of the data of the parameter is non trivial such as values of primitive type.
The output parameter must be passed by pointer or by reference.
The input and output parameter types must be serializable, which means that there are some limitations on the types of data that can be passed, see Section Limitations .
If the output parameter is a pointer or reference to a struct
or class
type, it is considered a service operation response element instead of a simple output parameter value. That is, the name of the struct
or class
is the name of the response element and the struct
or class
members are the output parameters of the service operation, see also Section How to change the response element name . Therefore, if the output parameter has to be a struct
or class
, a response struct
or class
must be declared to wrap that struct
or class
type parameter. Likewise, if a service operation returns multiple output parameters then a response struct
or class
should be used to wrap the output parameters. By SOAP conventions, the response element is the service operation name ending with "<i>`Response`</i>".
The general form of a response struct or class wrapper is:
where
prefix__
is the optional namespace prefix of the response element.response_element_name
it the name of the response element.outparam1
, ..., outparamn
are the output parameters of the service operation.The general form of a service operation specification with a response element declaration is:
The choice of name for anyname
has no effect on the SOAP encoding and decoding and is only used as a place holder for the response. In C++ this parameter can be passed by reference instead of by pointer.
The request message is:
where the inparam1
, ..., inparamn
elements are the XML element representations of the inparam
parameters.
The response message is of the form:
where the outparam1
, ..., outparamn
elements are the XML element representations of the outparam
parameters.
The input and output parameters can be made anonymous, which allows the deserialization of requests/responses with different parameter names as is endorsed by the SOAP 1.1 specification, see Section How to specify anonymous parameter names .
One of the nice aspects of gSOAP is its powerful C/C++ XML data binding and the flexibility to specify names for XML, such as service operation names, class names, type identifiers, and struct or class members. The first aspect is the use of namespace prefixes with C/C++ names to qualify the names with XML namespaces, which is specified with a prefix__
or as we will see later can be specified with a colon prefix:
in the C/C++ name. A C/C++ identifier name of the form
is be encoded in XML as
The underscore pair (__
) separates the namespace prefix from the element name. Each namespace prefix has a namespace URI specified by a //gsoap <prefix> schema namespace: <URI>
directive that is saved to the soapcpp2-generated namespace mapping table, see Sections XML namespaces and the namespace mapping table and XML namespace considerations . The namespace URI is a unique identification that can be associated with the service operations and data types. The namespace URI disambiguates potentially identical service operation names and data type names used by disparate organizations.
XML element names are XSD NCNames (non-colon names) that may contain letters, digits, underscores, hyphens, dots, and other special characters except reserved characters and colon. To add non-element names of service operations, structs, classes, typedefs, and members can be A single underscore _
in a C/C++ prefix or identifier name is replaced by a hyphen -
in the XML encoding. For example, the identifier name SOAP_ENC__ur_type
is represented in XML as SOAP-ENC:ur-type
. A _DOT
is replaced by a dot .
in XML, and _USCORE
is replaced by an underscore _
in XML. For example:
is serialized in XML as:
Other special characters are added to C/C++ names as _xHHHH
where HHHH
is the hexadecimal code of a Unicode character code point.
Trailing underscores in an identifier name are stripped from the XML encoding. This is useful when an identifier name clashes with a C++ keyword. For example, return
may be used as an XML element. This return
element can be specified as return_
, for example as a struct or class member or function parameter.
By default the soapcpp2 tool generates data binding source code in which all local XML elements are and attributes are unqualified:
where the name
element and the type
attribute are unqualified in the XML content (for example to facilitate SOAP RPC encoding).
To force qualification of elements and attributes, use the "form" directive:
You can also use "elementForm" and "attributeForm" directives to (un)qualify local element and attributes, respectively.
Because the soapcpp2-generated serializers follow the qualified/unqualified forms of the schemas, there is normally no need to explicitly qualify struct/class members because automatic encoding rules will be used.
If explicit qualification is needed, this can be done using the prefix convention:
which ensures that there cannot be any name clashes between members of the same name defined in different schemas (consider for example name
and y__name
), but this can clutter the representation when clashes do not occur.
An alternative to the prefix convention is the use of "colon notation" in the interface header file for soapcpp2. This extra addition to the the C/C++ syntax allows you to bind type names and struct and class members to qualified and unqualified XML tag names explicitly, thus bypassing the default mechanism that automatically qualifies or unqualifies element and attribute tag names based on the schema element or attribute forms.
The colon notation for type names, struct and class names, and members overrides the prefix qualification rules explicitly:
where x
and y
are namespace prefixes that are declared with a directive. The xsi:type
member is an XML attribute in the xsi
namespace. The soapcpp2 tool generates data binding implementation source code with the following cleaned-up struct without the annotations:
The soapcpp2 tool also generates XML schemas with element and attribute references. That is, y:name
is referenced from the y
schema by the x:record
complexType defined in the x
schema.
The colon notation also allows you to override the element and attribute forms to unqualified for qualified schemas:
where the colon notation ensures that both type
and name
are unqualified in the XML content, which overrides the default qualified forms of the x
schema.
Note that the use of colon notation to bind namespace prefixes to type names (typedef, enum, struct, and class names) translates to code without the prefixes. This means that name clashes can occur between types with identical unqualified names:
while prefixing with double underscores never lead to clashes:
Also note that colon notation has a very different role than the C++ scope operator ::
. The scope operator cannot be used in places where we need colon notation, such as struct and class member members.
The default mechanism that associates XML tag names with the names of struct and class member members can be overridden by "re-tagging" names with the annotation of a tag placed next to the member member name. This is particularly useful to support legacy code for which the fixed naming of member members cannot be easily changed. For example:
This maps the t
member to the type
XML attribute tag and s
member to the x:name
XML element tag. Tags will be namespace qualified as per schema element and attribute forms, unless preceded by a colon.
As of gSOAP 2.8.23 and greater, Unicode characters in C/C++ identifiers are accepted by soapcpp2 when the source file is encoded in UTF-8. C/C++ Unicode names are mapped to Unicode XML tags. For C/C++ source code portability reasons, the wsdl2h tool still converts Unicode XML tag names to ASCII C/C++ identifiers using the _xHHHH
naming convention for HHHH
character code points. Use wsdl2h -U
option -U
to map Unicode letters in XML tag names to UTF-8-encoded Unicode letters in C/C++ identifiers.
After invoking the soapcpp2 tool on an interface header file description of a service to generate soapStub
, soapH.h
, and soapC.cpp
for the XML serializers, and soapClient.cpp
for the client stub functions, the client application is compiled in C++ as follows:
c++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp
For C we use soapcpp2 -c
option -c
to generate C source code that is compiled with:
cc -o myclient myclient.c stdsoap2.c soapC.c soapClient.c
Depending on your system configuration, such as with Unix, linking with -lsocket
, -lxnet
, and -lnsl
may be required.
The myclient.cpp
file should include soapH.h
and must include or define a global namespace mapping table, unless WITH_NONAMESPACES
is used.
For examples of SOAP and REST client applications, see gsoap/samples
in the gSOAP source code package. The online getting-started guide covers example client and server applications in C and C++, visit https://www.genivia.com/dev.html to read more. Various examples ranging from simple calculator service APIs to very large protocols spanning dozens of WSDLs can be found at https://www.genivia.com/examples.html
To test client applications using an auto-generated echo test server, use soapcpp2 -T
option -T
, see the next section. You can also test a client application with the gSOAP Test Messenger.
After invoking the soapcpp2 tool on an interface header file description of a service to generate soapStub
, soapH.h
, and soapC.cpp
for the XML serializers, and soapServer.cpp
for the server skeleton functions, the service application is compiled in C++ as follows:
c++ -o myserver myserver.cpp stdsoap2.cpp soapC.cpp soapServer.cpp
For C we use soapcpp2 -c
option -c
to generate C source code that is compiled with:
cc -o myserver myserver.c stdsoap2.c soapC.c soapServer.c
Depending on your system configuration, such as with Unix, linking with -lsocket
, -lxnet
, and -lnsl
may be required.
The myserver.cpp
file should include soapH.h
and should include or define a global namespace mapping table, unless WITH_NONAMESPACES
is used.
A gSOAP service can be installed as:
soap_serve
to serve requests on standard input and output.To test a service, see the gSOAP Test Messenger.
Furthermore, an echo test server application soapTester.cpp
is generated with soapcpp2 -T
option -T
, which is a stand-alone iterative test server that echos SOAP/XML requests and runs on the specified port. Compile this with:
c++ -o testserver soapTester.cpp stdsoap2.cpp soapC.cpp soapServer.cpp
Then run on a port, say 8080:
./testServer 12288 8080
The 12288 value is a combination of the SOAP_XML_INDENT
(0x2000) and SOAP_XML_STRICT
(0x1000) integer flag values (8192 + 4096 = 12288).
For examples of SOAP and REST Web service applications, see gsoap/samples
in the gSOAP source code package. The online getting-started guide covers example client and server applications in C and C++, visit https://www.genivia.com/dev.html to read more. Various examples ranging from simple calculator service APIs to very large protocols spanning dozens of WSDLs can be found at https://www.genivia.com/examples.html
The soapcpp2 -T
option -T
generates an echo test server application source code soapTester.cpp
, which is to be compiled and linked with the code generated for a server implementation soapServer.cpp
(or with the generated service class file) and soapC.cpp
. The feature also supports C source code, use the soapcpp2 -c -T
options -c
and -T
to generate a C test server.
The echo test server can be used to test a client application, by the client sending messages to the echo test server that echos responses back to the client. These responses are structurally valid but may lack sufficient details to consider the response messages useful.
The generated source code is compiled with:
c++ -o tester soapTester.cpp soapServer.cpp soapC.cpp stdsoap2.cpp
To run the tester
auto-test service on a port to test a client against, use two command-line arguments: the first argument is a combined integer of OR-ed values of the context flags such as 12288 which is a combination of SOAP_XML_INDENT
(0x1000 = 4096) and SOAP_XML_STRICT
(0x1000 = 8196) and the second argument is the port number:
./tester 12288 8080
This starts an iterative stand-alone server on port 8080. Messages can be sent to http://localhost:8080
to test a client application against the echo test server. The data in the response messages are copied from the request messages when possible, or XML default values, or empty otherwise.
More advanced servers for testing are available with the gSOAP Test Messenger testmsgr tool to test SOAP and REST XML clients and servers.
The soapcpp2 -Ec
option -Ec
generates deep copy code for each serializable type T
declared in an interface header file for soapcpp2. The soapcpp2 -Ed
option -Ed
generates deep deletion code.
For a serializable type T
declared in the interface header file for soapcpp2, option -Ec
generates:
virtual T * T::soap_dup(struct soap*) const
where T
is a class, returns a duplicate of this object by deep copying, replicating all deep cycles and shared pointers when a managing soap
context is provided as argument. Deep copy is a tree when argument is NULL, but the presence of deep cycles will lead to non-termination. Use flag SOAP_XML_TREE
with the managing context to copy into a tree without cycles and pointers to shared objects.T * soap_dup_T(struct soap*, T *dst, const T *src)
where T
is not a class, deep copy src
into dst
, replicating all deep cycles and shared pointers when a managing soap
context is provided as argument. When dst
is NULL, allocates space for dst
and returns a pointer to the allocated copy. Deep copy results in a tree when the soap
context is NULL, but the presence of deep cycles will lead to non-termination. Use flag SOAP_XML_TREE
with managing context to copy into a tree without cycles and pointers to shared objects. Returns dst
or allocated copy when dst
is NULL.For a serializable type T
declared in the interface header file for soapcpp2, option -Ed
generates:
virtual void T::soap_del() const
where T
is a class, deletes all heap-allocated members of this object by deep deletion ONLY IF this object and all of its (deep) members are not managed by a soap
context AND the deep structure is a tree (no cycles and co-referenced objects by way of multiple (non-smart) pointers pointing to the same data). Can be safely used after T::soap_dup(NULL)
to delete the deep copy. Does not delete the object itself.void soap_del_T(const T*)
where T
is not a class, deletes all heap-allocated members of this object by deep deletion ONLY IF this object and all of its (deep) members are not managed by a soap
context AND the deep structure is a tree (no cycles and co-referenced objects by way of multiple (non-smart) pointers pointing to the same data). Can be safely used after soap_dup_T(NULL, NULL, const T*)
to delete the deep copy returned. Does not delete the object itself.For example:
This section describes the serialization and deserialization of C and C++ data types in XML, and therefore by implication in SOAP 1.1 and 1.2. First, the difference between SOAP RPC encoding and document/literal style is explained and how to switch between SOAP 1.1 and 1.2 or support both in applications. Then the general XML representations of C/C++ data in XML and XML schema is explained.
To obtain more information about the code generated by soapcpp2 for the data types specified in an interface header file for soapcpp2, use soapcpp2 -r
option -r
to generate a soapReadme.md
report with all the details.
For additional details on serialization of data types in XML, see the C and C++ XML Data Bindings documentation.
The serialization and deserialization rules is almost identical for these two different styles, except for the following:
complexTypes
with maxOccurs="unbounded"
are not allowed and SOAP-encoded arrays must be used instead.choice
) are not allowed with SOAP RPC encoding.xsi:type
attributed messages although the xsi:type
attribute is not required and the gSOAP engine does not produce xsi:type
attributes unless required, e.g. to identify derived classes from base classes serialized. Use soapcpp2 -t
option -t
to force xsi:type
attributes in the XML output.The soapcpp2 tool uses SOAP 1.1 document/literal style by default. Use the //gsoap
directives to control the SOAP protocol version and messaging style, see Section Directives, or use soapcpp2
options -2
(SOAP 1.2), -e
(encoding style), and -t
(add xsi:type
attributes).
SOAP 1.1 is the default protocol. SOAP 1.2 support is automatically turned on when the appropriate SOAP 1.2 namespace is used in the WSDL input to wsdl2h, which then generates #import "soap12.h"
in the interface header file:
This interface header file when input to soapcpp2 results in a XML namespace mapping table with SOAP 1.2 namespaces:
The soapcpp2-generated default SOAP 1.1 namespace table allow for dynamic switching between SOAP 1.1 to SOAP 1.2 by providing the SOAP 1.2 namespace as a pattern in the third column of a namespace table:
where the *
in the third column of the namespace URI pattern is a wildcard for any sequence of character. This is used to match inbound xmlns
XML namespace bindings that are then associated with the prefix in the table. For example, when the inbound XML contains a xmlsn:soap="http://www.w3.org/2003/05/soap-envelope"
binding then the soap
prefix used in the inbound XML is actually equivalent to SOAP-ENV
used in gSOAP as determined by the matching pattern in the third column of the XML namespace table shown above.
In this way, gSOAP Web services can respond to both SOAP 1.1 or SOAP 1.2 requests. Moreover, the gSOAP engine will automatically return a SOAP 1.2 message response to a SOAP 1.2 message request when the XML namespace table shown above is used. This works by using the specified pattern in the third column, when it matches the namespace URI of the inbound XML request message of course. However, the use of SOAP 1.1 or 1.2 is overridden for one or more service operations with the //gsoap <prefix> service method-protocol:
directive.
A gSOAP client that sends a request message will always send it using the SOAP protocol specified by the namespace in the second column, unless this is overridden with a //gsoap <prefix> service method-protocol:
directive.
To make the XML namespace table available to the developer, the soapcpp2 tool generates a .nsmap
file with the SOAP-ENV
and SOAP-ENC
namespaces and patterns as shown in the example above.
To use SOAP 1.2 by default and accept SOAP 1.1 messages to be received, use the soapcpp2 -2
option -2
to generate SOAP 1.2 .nsmap
and .wsdl
files. Alternatively, add the following line to your interface header file (generated by wsdl2h) for soapcpp2:
The soap12.h
file is located in gsoap/import
.
__offset
member of a dynamic array is meaningless in SOAP 1.2.SOAP_ENV__Code
, SOAP_ENV__Reason
, and SOAP_ENV__Detail
members of a SOAP_ENV__Fault
fault struct, while SOAP 1.1 uses faultcode
, faultstring
, and detail
members.The default encoding rules for primitive C and C++ data types in XML are given in the table below:
C/C++ type | XSD type |
---|---|
bool | xsd:boolean |
char and int8_t | xsd:byte |
short and int16_t | xsd:short |
int , long , and int32_t | xsd:int |
LONG64 , long long and int64_t | xsd:long |
unsigned char and uint8_t | xsd:unsignedByte |
unsigned short and uint16_t | xsd:unsignedShort |
unsigned int , unsigned long and uint32_t | xsd:unsignedInt |
ULONG64 , long long , and uint64_t | xsd:unsignedLong |
float | xsd:float |
double | xsd:double |
long double | xsd:decimal with #import "custom/long_double.h" |
time_t | xsd:dateTime |
struct tm | xsd:dateTime with #import "custom/struct_tm.h" |
struct timeval | xsd:dateTime with #import "custom/struct_timeval.h" |
char* , const char* , and std::string | xsd:string |
wchar_t* , const wchar_t* , and std::wstring | xsd:string |
Enumerations and bit masks are also supported, see Section Enumeration serialization .
Custom serializers for long double
, struct tm
, and struct timeval
and many other specialized C and C++ types are available, see the C and C++ XML Data Bindings documentation for details.
The previous table shows how C/C++ primitive types are mapped to XSD types. To define and use the full range of XSD types is done with typedefs to define namespace-qualified types in C/C++ corresponding to the XSD types (or to any schema type for that matter).
XSD types such as xsd:positiveInteger
, xsd:anyURI
, and xsd:date
for which no built-in data structures in C and C++ exist can always be represented by strings and some can be represented by integers or floats. Validation constraints can be added to validate the XSD type values as explained further below.
A typedef
in an interface header file for soapcpp2 declares a schema type name. The soapcpp2 tool interprets typedef
declarations the same way as a regular C compiler interprets them. However, the soapcpp2 tool also uses the type name when generating WSDLs and XSD files and in xsi:type
attributes when present.
For example, the declaration:
creates a named type xsd__positiveInteger
represented by ulong64_t
and serialized as XSD type xsd:positiveInteger
.
The built-in primitive and derived numerical XSD types are listed below together with their recommended typedef
declarations. Note that the SOAP encoding schemas for primitive types are derived from the built-in XML Schema types, so SOAP_ENC__
can be used as a namespace prefix instead of xsd__
. However, the use of SOAP_ENC
XML types is obsolete and redundant because XSD primitive types can be used instead.
Other XSD types not mentioned in this section, such as gYearMonth
, gYear
, gMonthDay
, gDay
, xsd:gMonth
, QName
, NOTATION
, etc., can be encoded similarly using a typedef
declaration with a string type.
For additional in-depth details, see the C and C++ XML Data Bindings documentation.
xsd:anyURI
Represents a Uniform Resource Identifier Reference (URI). Each URI scheme imposes specialized syntax rules for URIs in that scheme, including restrictions on the syntax of allowed fragment identifiers. It is recommended to use strings to store xsd:anyURI
XML Schema types. The recommended type declaration is:
or
xsd:base64Binary
Represents Base64-encoded arbitrary binary data. For using the xsd:base64Binary
XSD type, the use of the base64Binary representation of a dynamic array is strongly recommended, see Section base64Binary serialization . However, the type can also be declared as a string and the encoding will be string-based:
or
However, it is the responsibility of the application to make sure the string content is according to the Base64 Content-Transfer-Encoding defined in Section 6.8 of RFC 2045. Better is to use the base64 serializer that serializes binary data as xsd:base64Binary
:
xsd:boolean
For declaring an xsd:boolean
XSD type, the use of a bool is recommended in C++. For C, see Section Boolean enumeration serialization for C . The corresponding type declaration is:
xsd:byte
Represents a byte (-128...127). The corresponding type declaration is:
xsd:dateTime
Represents a date and time. The lexical representation is according to the ISO 8601 extended format CCYY-MM-DDThh:mm:ss where "CC" represents the century, "YY" the year, "MM" the month and "DD" the day, preceded by an optional leading "-" sign to indicate a negative number. If the sign is omitted, "+" is assumed. The letter "T" is the date/time separator and "hh", "mm", "ss" represent hour, minute and second respectively. It is recommended to use the time_t
type to store xsd:dateTime
XSD types and the type declaration is:
However, note that calendar times before the year 1902 or after the year 2037 cannot be represented. Upon receiving a date outside this range, the time_t
value will be set to -1. Also strings can be used to store xsd:dateTime
types:
Best is to use a custom serializer struct tm
, struct timeval
, or std::chrono::system_clock::time_point
defined by gsoap/custom/struct_tm.h
, gsoap/custom/struct_timeval.h
, and gsoap/custom/chrono_timepoint.h
to represent xsd:dateTime
accurately.
xsd:date
Represents a date. The lexical representation for date is the reduced (right truncated) lexical representation for dateTime: CCYY-MM-DD. It is recommended to use strings (char*
) to store xsd:date
XSD types. The type declaration is:
Best is to use a custom serializer struct tm
defined by gsoap/custom/struct_tm_date.h
to represent xsd:date
accurately.
xsd:decimal
Represents arbitrary precision decimal numbers. It is recommended to use the {double} type to store xsd:decimal
XSD types and the type declaration is:
Better is to use a custom serializer gsoap/custom/long_double.h
to represent xsd:decimal
or a string to avoid losing accuracy of very large numbers.
xsd:double
Corresponds to the IEEE double-precision 64-bit floating point type. The type declaration is:
xsd:duration
Represents a duration of time. The lexical representation for duration is the ISO 8601 extended format PnYn MnDTnH nMnS, where nY represents the number of years, nM the number of months, nD the number of days, T is the date/time separator, nH the number of hours, nM the number of minutes and nS the number of seconds. The number of seconds can include decimal digits to arbitrary precision. It is recommended to use strings (char*
) to store xsd:duration
XSD types. The type declaration is:
Better is to use a custom serializer gsoap/custom/duration.h
or gsoap/custom/chrono_duration.h
to represent xsd:duration
or a string to avoid losing accuracy of very large numbers.
xsd:float
Corresponds to the IEEE single-precision 32-bit floating point type. The type declaration is:
xsd:hexBinary
Represents arbitrary hex-encoded binary data. It has a lexical representation where each binary octet is encoded as a character tuple, consisting of two hexadecimal digits ([0-9a-fA-F]) representing the octet code. For example, "0FB7" is a hex encoding for the 16-bit integer 4023 (binary representation is 111110110111. For using the xsd:hexBinary
XSD type, the use of the hexBinary representation of a dynamic array is strongly recommended, see Section hexBinary serialization . However, the type can also be declared as a string and the encoding will be string-based:
or
However, it is the responsibility of the application to make sure the string content is hex formatted. Better is to use the hex serializer that serializes binary data as xsd:hexBinary
:
xsd:int
Corresponds to a 32-bit integer in the range -2147483648 to 2147483647.
xsd:integer
Corresponds to an unbounded integer. C/C++ does not support unbounded integers as a standard feature. The recommended type declaration is:
Another possibility is to use strings to represent unbounded integers and do the translation in the application itself.
xsd:long
Corresponds to a 64-bit integer in the range -9223372036854775808 to 9223372036854775807. The type declaration is:
xsd:negativeInteger
Corresponds to a negative unbounded integer. C/C++ does not support unbounded integers as a standard feature. The recommended type declaration is:
Another possibility is to use strings to represent unbounded integers and do the translation in the application itself.
xsd:nonNegativeInteger
Corresponds to a non-negative unbounded integer. Since C++ does not support unbounded integers as a standard feature, the recommended type declaration is:
Another possibility is to use strings to represent unbounded integers and do the translation in the application itself.
xsd:nonPositiveInteger
Corresponds to a non-positive unbounded integer. Since C++ does not support unbounded integers as a standard feature, the recommended type declaration is:
Another possibility is to use strings to represent unbounded integers and do the translation in code.
xsd:normalizedString
Represents normalized character strings. Normalized character strings do not contain the carriage return (#xD), line feed (#xA) nor tab (#x9) characters. It is recommended to use strings to store xsd:normalizedString
XSD types. The type declaration is:
or
xsd:positiveInteger
Corresponds to a positive unbounded integer. C/C++ does not support unbounded integers as a standard feature. The recommended type declaration is:
Another possibility is to use strings to represent unbounded integers and do the translation in the application itself.
xsd:short
Corresponds to a 16-bit integer in the range -32768 to 32767. The type declaration is:
xsd:string
Represents character strings. The type declaration is:
or
The type declaration for wide character strings is:
or
Both types of regular and wide strings can be used at the same time, by using a typedef name with a trailing underscore as follows:
or
xsd:time
Represents a time. The lexical representation for time is the left truncated lexical representation for dateTime: hh:mm:ss.sss with optional following time zone indicator. It is recommended to use strings (char*
) to store xsd:time
XSD types. The type declaration is:
or
Better is to use a custom serializer gsoap/custom/long_time.h
to represent xsd:time
or a string to avoid losing accuracy.
xsd:token
Represents tokenized strings. Tokens are strings that do not contain the line feed (#xA) nor tab (#x9) characters, that have no leading or trailing spaces (#x20) and that have no internal sequences of two or more spaces. It is recommended to use strings to store xsd:token
XSD types. The type declaration is:
xsd:unsignedByte
Corresponds to an 8-bit unsigned integer in the range 0 to 255. The type declaration is:
xsd:unsignedInt
Corresponds to a 32-bit unsigned integer in the range 0 to 4294967295. The type declaration is:
xsd:unsignedLong
Corresponds to a 64-bit unsigned integer in the range 0 to 18446744073709551615. The type declaration is:
xsd:unsignedShort
Corresponds to a 16-bit unsigned integer in the range 0 to 65535. The type declaration is:
As explained in Section C/C++ identifier name to XML tag name translation, trailing underscores in a type name are not relevant in XML and in the XML schemas generated by soapcpp2. Therefore, we can map multiple C/C++ types to XSD types (or any XML schema type). For example, the following declaration in the interface header file for soapcpp2 permits us to use regular strings and wide strings while mapping these both to the XSD xsd:string
type:
XSD schema types form a hierarchy of types, with xsd:anyType
at the root. A container or array of xsd:anyType
may actually contain any mix of types, i.e. this container or array is polymorphic.
On the one hand, the typedef
construct provides a convenient way to associate existing C/C++ types with XML schema types and makes it easy to incorporate these types in a (legacy) C/C++ application without having to replace application types in the source code. On the other hand the typedef
declarations cannot be used to support polymorphic types.
To create a derivable primitive type T
, a wrapper class is declared as follows:
where T
is a primitive C/C++ type. The __item
member must be the first member of the wrapper class and all other members are not serialized.
For example, the a large portion of the XML type hierarchy can be implemented in C++ as follows:
Note the use of the trailing underscores for the class
names to distinguish the typedef
type names from the class
names. The char*
type of xsd__string
can be replaced with std::string
or a wide string type. We can also add the xsd:base64Binary
and xsd:hexBinary
types that serialize raw binary data in the hierarchy as follows:
See Sections base64Binary serialization and hexBinary serialization .
Methods can be added to these classes, such as constructors and getter/setter methods, see Section Get and set methods .
Wrapper structs are supported as well, similar to wrapper classes. But they cannot be used to implement polymorphism. Rather, the wrapper structs are used to represent a xsd:sequence
of elements or to add attributes to primitive types as explained in Section How to declare XML attributes .
For additional details, see the C and C++ XML Data Bindings documentation.
If more than one char
pointer points to the same string, the string is encoded as a multi-reference value, unless SOAP_XML_TREE
is used or the WITH_NOIDREF
compile-time flag.
Consider for example:
A record instance is populated as follows and then serialized:
The s
and t
variables are assigned the same string. When serialized, t
refers to the content of s
:
However, strings declared with different typedef names will never be considered multi-reference even when they point to the same string. For example:
This avoids type conflicts when a receiver considers these types incompatible.
To enable multi-references in XML use SOAP_XML_GRAPH
. To disable multi-references in SOAP 1.1 and 1.2 RPC encoded messages, use SOAP_XML_TREE
.
The implementation of string deserialization permits mixed content. When XML contains mixed text and tags when a string is expected, the text with tags are collected into the deserialized string.
For example, suppose the getInfo
service operation returns some detailed information. The service operation is declared as:
The proxy of the service is used by a client to request a piece of information and the service responds with:
HTTP/1.1 200 OK Content-Type: text/xml Content-Length: nnn
The detail
string will contain "\<picture\>Mona Lisa by \<i\>Leonardo da Vinci\</i\>\</picture\>"
.
Note that serialization of this string will not produce mixed content but rather the XML output:
To serialize XML stored in strings, use the _XML
type (a char*
) in the interface header file for soapcpp2. For example:
In C++ you can use a std::string
instead, as follows:
The _XML
and typedef XML
are literal XML strings, see also Section Serializing mixed content with literal XML strings.
The format used to output double precision floating point values in XML is by default set to "`%.17lG`", which means that at most 17 digits of precision are output. The format used by the gSOAP engine to output single precision floating point values is by default "`%.9G`".
The format of a double can be set by assigning a format string to soap::double_format
. For example:
which causes all doubles to be output in XML and JSON in scientific notation. Likewise, the encoding format of a float type can be set by assigning a format string to the soap::float_format
string variable. For example:
which causes all floats to be output in XML and JSON with four digits precision.
A new feature to specify format patterns was introduced in gSOAP 2.8.18. A format string can be used as a pattern for a typedef float or double in the interface header file for soapcpp2 to specify the representation in XML. For example:
This will output the float in XML with 5 digits total and 2 digits after the decimal point.
The soapcpp2 tool also generates an XML schema with xsd:totalDigits
and xsd:fractionDigits
for this type:
The wsdl2h tool converts WSDLs and XSDs with xsd:totalDigits
and xsd:fractionDigits
to typedefs with format patterns.
IEEE INF, -INF, and NaN values of floats are output in XML as INF
, -INF
, and NaN
, respectively, as supported by the XML schema standards.
For portability, the following macros can be used containing the float and double values INF
, -INF
, and NaN
:
To check for INF
, -INF
, and NaN
use:
Enumerations are generally useful for the declaration of named integer-valued constants.
For additional details, see the C and C++ XML Data Bindings documentation.
The soapcpp2 tool encodes the constants of enumeration-typed variables in symbolic form using the names of the constants when possible to comply to SOAP's enumeration encoding style. Consider for example the following enumeration of weekdays:
The enumeration-constant Mon
, for example, is encoded as
An XML namespace prefix can be specified as part of the enumeration-type identifier's name, with the usual namespace prefix conventions for identifiers. For example:
The ns__weekday
type with enumeration-constant Sat
, for example, is output in XML as:
The corresponding XML schema type for this enumeration type is:
C++11 scoped enumerations are supported by soapcpp2 with option -c++11
:
Enumeration constants can be initialized, for example:
The symbolic names LESS
, EQUAL
, and GREATER
will appear in the XML output.
If the value of an enumeration-typed variable has no corresponding named constant, the value is encoded as a signed integer literal. For example, the following declaration of a workday
enumeration type lacks named constants for Saturday and Sunday:
If the constant 5
(Saturday) or 6
(Sunday) is assigned to a variable of the workday
enumeration type, the variable will be encoded with the integer literals 5
and 6
, respectively. For example:
Since this is legal in C/C++ and in SOAP RPC encoding, but not XML validators, we cam transmit integer literals as well as enumeration constants with an enumeration type.
When enumeration constants are numeric, we can use the following simple trick:
The corresponding XML schema type for this enumeration type is:
A well-known deficiency of C and C++ enumeration types before C++11 scoped enumerations is the lack of a mechanism to reuse symbolic names by multiple enumerations. This issue is largely resolved with scoped enumerations in C++11, which the soapcpp2 tool supports.
In plain C and C++ we can use trailing underscores to avoid name clashes, for example:
Consider for example:
which will result in the encoding of the constants of enum ns__weekday
without the underscore, for example as Mon
.
However, the soapcpp2 tool is a bit smarter than your average C/C++ compiler and also permits the following declarations that reuse enumeration constants, because the enumeration constants have the same enumerating integer values:
The soapcpp2 tool generates soapStub.h
with amended enumeration definitions that the C/C++ compiler can handle, so you can still use the shared enumeration constants in your application code.
To avoid name clashes with enumeration constants, you can use the following convention with double underscores to add the enum name to the enum constants:
where the type name of the enumeration prefix__name
is a prefixed name, such as:
This ensures that the XML schema enumeration values are still simply Mon
, Tue
, Wed
, Thu
, Fri
, Sat
, and Sun
.
weekday
enumeration when you assume that workdays are part of weekdays, because it lacks the named constants for workday
in its enumeration list. All enumerations must be self-contained and cannot use enum constants of other enumerations.The C++ bool
type that is serialized as xsd:boolean
XSD type cannot be used in C. Instead, an enumeration type should be used to serialize true and false values as xsd:boolean
XSD type values. The xsd:boolean
XSD type is defined as an enumeration in C as:
The value false_
, for example, is output in XML as:
Peculiar of the SOAP encoding boolean type is that it only defines the values 0
and 1
, while the XSD xsd:boolean
type defines false
and true
as valid values. While SOAP encoding types are rarely used since almost all SOAP/XML Web services rely on XSD types for primitive values, we can still define the following:
A bitmask is an enumeration of power-of-two flags. The soapcpp2 tool makes it easy to define bitmasks using an annotated enum
with a *
:
This declares a regular enum
but enumerates the enumeration constants as a series of powers of 2 starting with 1. This means that the enumeration constants can be bitwise or-ed with the |
operator to form a bitvector (bitmask) which is serialized in XML as a list of symbolic values. For example:
Note that the use of the enum
name as a parameter does not require the asterisk, only the definition does. The soapcpp2 tool generates a proper C/C++ enumeration in soapStub.h
that is included by soapH.h
by your application:
The corresponding XML schema type for this enumeration type is:
The values of enum ns__machineStatus
can be or-ed, for example ON|VALVE
is output in XML as:
C++11 scoped enumerations for bitmasks are supported by soapcpp2, for example:
This section gives a brief overview of struct and class serialization.
Structs do not support inheritance when declared in an interface header file for soapcpp2. This makes serialization of structs is more efficient compared to classes. Serialization functions for structs are global functions. By contrast, soapcpp2 augments classes with serialization methods and soap_type()
method that returns the type of the class instance, which is necessary to distinguish base class instances from derived class instances for (smart) pointers to base class instances.
For additional details not covered here, see the C and C++ XML Data Bindings documentation.
A class and struct instance is serialized as an XML element with attributes and sub-elements, which is represented in XML schema as a complexType
. The class name is the XML schema type name and the member variables of the class are the type's accessors.
Consider the general declaration of an inherited class:
then
prefix__
is the optional namespace prefix associated with the class.class_name1
is the name of the complexType
for this class.class_name2
is an optional base class.field
is a member variable that is serialized when public and non-const.method
is a method declaration. Abstract methods are not allowed for serializable classes.A class name is required to be unique and cannot have the same name as a struct
, enum
, or a service operation name specified in the interface header file for soapcpp2.
Only single inheritance is supported by the soapcpp2 tool. Multiple inheritance is not supported because of the limitations of the XML schema extensibility.
If a constructor is present, there must also be a constructor declaration with an empty parameter list. If no constructors are present, then soapcpp2 generates constructors to initialize the members with the generated soap_default
method of this class.
To obtain more information about the code generated by soapcpp2 for a struct or class, use soapcpp2 -r
option -r
to generate a soapReadme.md
report with all the details.
Classes and structs may be declared volatile
if you don't want soapcpp2 to generate the class definition, see Section Serialization "as is" of volatile data types for more details.
Class templates are supported with only one template argument, see Section Containers .
Member variables of a class can be serialized as XML attributes using the @
type qualifier, if the member is a primitive type or pointer to a primitive type. See Section How to declare XML attributes for more details.
See Section C/C++ identifier name to XML tag name translation for more details on the struct/class member serialization and the resulting element and attribute qualified forms.
Arrays may be embedded within a class and a struct using a pointer member and size information, see Section Non-SOAP dynamic arrays .
Void pointers may be used in a class or a struct, but you have to add a type field so the engine can determine the type of object pointed to, see Section Void pointer serialization .
A class instance is output in XML as:
where the field
accessors have element-name representations of the class members and the basefield
accessors have element-name representations of the base class members.
If a derived class instance is used in place of a base class instance, then the serialized XML form carries a xsi:type
attribute with the derived class type to distinguish it from the base class type:
The deserialization of a class instance allows any ordering of the accessors in the XML message. However, if a base class member name is identical to a derived class member name, because the member is overloaded, the base class member name must precede the derived class member name in the XML message.
For additional details, see the C and C++ XML Data Bindings documentation.
The following example declares a base class ns__Object
and a derived class ns__Shape
:
The implementation of the class ns__Shape
methods cannot be part of the interface header file for soapcpp2 and are defined in a separate shape.cpp
C++ source code file.
An instance of class ns__Shape
with name Triangle, 3 sides, and color Green is output in XML as:
A class declaration in the interface header file for soapcpp2 may include method declarations. The method implementations must not be part of the header file but should be defined in another C++ source file, because soapcpp2 parses C/C++ type declarations but does not parse C/C++ code statements and constructor initializer lists.
If constructors are not defined, then soapcpp2 generates constructors for the class to initialize the class with default values for member variables or the initialization values for member variables given in the class declaration.
If destructors are not defined, then soapcpp2 generates destructors for the class.
To obtain more information about the code generated by soapcpp2 for a class, use soapcpp2 -r
option -r
to generate a soapReadme.md
report with all the details.
Setter and getter methods are invoked at run time upon serialization and deserialization of class instances, respectively. The use of setter and getter methods adds more flexibility to the serialization and deserialization process.
A setter method is called by the serializer. You can use setter methods to update a class instance just before it is serialized. For example, you can use setter methods to update a class instance right before serialization. Setters are methods for "set to serialize" operations.
Getter methods are immediately invoked after deserialization of a class instance. You can use them to adjust the contents of class instances right after the instance was populated by the deserializer
Getter and setter methods have the following class method signature:
These methods may be declared virtual
and may be declared const
.
The active soap
context will be passed to the get
and set
methods. The methods should return SOAP_OK
when successful. A setter method should prepare the contents of the class instance for serialization. A getter method should process the instance after deserialization.
Here is an example of a base64 binary class:
Suppose that the type and options members of the attachment should be set when the class is about to be serialized. This can be accomplished with the set
method from the information provided by the __ptr
to the data and the soap
context passed to the set
method (you can pass data via the void* soap::user
member).
The get
method is invoked after the base64 data has been processed. You can use it for post-processing purposes.
Here is another example. It defines a primitive update
type. The class is a wrapper for the time_t
type, see Section How to use C++ wrapper classes to specify polymorphic primitive types . Therefore, elements of this type contain xsd:dateType
data.
The setter method assigns the current time just before the instance is serialized:
This means that serialization in XML results in the inclusion of an up-to-date time stamp.
A get
method is invoked immediately after the instance is populated by the deserializer. The method is not invoked when the element is an xsi:nil
element or has a SOAP href
or ref
attribute referencing a value located elsewhere in the XML message or document.
soap_out
method of a class calls the setter method However, the soap_out
method is declared const
while the setter should be allowed to modify the contents of the class instance. Therefore, the soapcpp2-generated code recasts the instance and the const
is removed when invoking the setter.Getter methods enable streaming XML operations. A getter method is invoked when the object is deserialized and the rest of the XML message has not been parsed yet. For example, you can add a getter method to the SOAP Header class to implement header processing logic that is activated as soon as the SOAP Header is received. An example is shown below:
The Authentication
SOAP Header member is instantiated and decoded. After decoding, the getter method is invoked, which can be used to check the id
before the rest of the SOAP message is parsed.
Polymorphism through C++ inheritance is supported by the gSOAP tools, which means that derived XML schema types are (de)serialized when an xsi:type
attribute is present.
Because C does not support inheritance, a different approach is use for C code, see Section Polymorphism, derived types, and dynamic binding in C for details.
Base and derived C++ classes can be used anywhere, including service operation parameters and in struct and class members, provided that parameters and members are pointers to classes to allow dynamic binding at run time. Base and derived classes can also be used with containers such as std::vector
and smart pointers such as std::shared_ptr
.
The following example interface header file for soapcpp2 declares ns__Base
and ns__Derived
classes and a service operation that takes a pointer to a ns__Base
class instance and returns a ns__Base
class instance:
The service operation input parameter may point to a ns__Derived
class instance that will be serialized as ns__Derived
class instance instead of a ns__Base
class instance. Likewise, the service operation output parameter that is placed in a wrapper struct (because structs and classes are always considered wrappers to define the response message with output parameters) may point to a ns__Derived
class instance.
The ns__Base
and ns__Derived
class method implementations are:
Below is an example client application that creates a ns__Derived
class instance that is passed as the input parameter of the ns__webmethod
service operation:
The following example server application copies a class instance (ns__Base
or ns__Derived
) from the input to the output parameter:
The following messages are produced by the client and server applications:
CLIENT: created a Derived class instance SERVER: print(): Derived class instance X 3 CLIENT: created a Derived class instance CLIENT: print(): Derived class instance X 3
This shows that the Derived
class instance kept its identity as it passed through the server.
Another way to serialize polymorphic values in XML that are indicated with xsi:type
attributes is with void*
members that point to a serializable value. See Section Void pointer serialization for details.
Because C does not support object-oriented inheritance, derived types are obviously not declared as base structs or classes as in C++. Instead, we add the derived type structs to the base structs as members that point to the derived type value when the base type is dynamically overridden by one of the derived types. In this way we can (de)serialize a base type struct as usual or one of the derived structs when the base type is overridden. To serialize a derived type struct in place of the base struct, we set its corresponding member point to the derived struct value, which is serialized with the xsi:type
attribute to indicate a derived type is used in XML. Deserialization of a derived type struct is done automatically when the xsi:type
attribute is present.
This approach with additional members pointing to derived types was introduced with gSOAP 2.8.75. This approach has the benefit of type safety compared to attempts to replicate C++ inheritance by trying to overlay derived types with base types in memory, which would be fragile.
This method is fully automated for the wsdl2h tool to generate an interface header file for soapcpp2 with the type derivations in C. To use this method to generate code from WSDLs and XSDs, use wsdl2h -F
option -F
. This also works in C++, but C++ inheritance works fine without this method.
Using this method with soapcpp2 alone using a manually-specified interface header file produces the specified type inheritance in the soapcpp2-generated WSDL and XML schema files as complexType extensions.
The soapcpp2 tool warns if a derived type has multiple base types. At most one base type for a derived type may be specified.
To illustrate this method, consider the following interface header file example for soapcpp2 based on Polymorphism, derived types, and dynamic binding in C++. This example declares ns__Base
and ns__Derived
structs and a service operation that takes a pointer to a ns__Base
value and returns a ns__Base
value:
The ns__Base
struct includes the special member ns__Derived
that points to a ns__Derived
value. This special member must be:
[
and ]
, andns__Derived_
works too).To serialize the ns__Base
value make sure to set the ns__Derived
member to NULL. The soapcpp2-generated soap_default_ns__Base()
function default initializes a given ns__Base
value for you. To serialize the ns__Derived
value make sure to set the ns__Derived
member to point to the address of a ns__Derived
value. This is easy by calling soap_new_ns__Derived()
that allocates and default initializes a ns__Derived
value, whose address is returned by this function.
When multiple derived types are declared for a base type, all immediately derived struct types are added as transient pointer members to the base type. Indirectly derived types do not need to be added to the base type as members, but it is perfectly fine to do so.
To properly declare derived types, make sure to include all base type members in the derived type. In our example the ns__Derived
struct contains the ns__Base
struct members (except for the ns__Derived
member) and adds additional members as extensions.
Below is an example client application based on the example in Section Polymorphism, derived types, and dynamic binding in C++ that creates a ns__Derived
value that is passed as the input parameter of the ns__webmethod
service operation:
The following example server application copies a class instance (ns__Base
or ns__Derived
class) from the input to the output parameter:
The following messages are produced by the client and server applications:
SERVER: print(): Derived class instance X 3 CLIENT: print(): Derived class instance X 3
This shows that the Derived
class instance kept its identity as it passed through the server.
Another way to serialize polymorphic values in XML that are indicated with xsi:type
attributes is with void*
members that point to a serializable value. See Void pointer serialization for details.
Deeper levels of simulated inheritance are possible, for example:
This requires two pointer traversals from the base type ns__Base
via ns__Derived
to reach ns__Derived2
:
The gSOAP tools support the full XML schema standards, so XML attributes are nothing special. However, with respect to SOAP standards it is important to note that SOAP RPC/literal and SOAP document/literal styles support XML attributes in SOAP messages, but SOAP RPC with "Section 5" encoding does not support XML attributes other than some built-in attributes.
The idea behind SOAP RPC Section 5 encoding was to keep SOAP as simple as possible as a limited subset of XML, while offering advantages for cross-language interoperability of data types, including data structure graph serialization with multi-referenced data.
Attributes are primitive XSD types, such as strings, enumerations, boolean, and numeric types. To declare an XML attribute in a struct or class, the qualifier @
is used with the type of the attribute. The type must be primitive type or a pointer to a primitive type, including enumerations and xsd__base64Binary
and xsd__hexBinary
structures. For example:
The @
qualifier declares an XML attribute for the type
, flag
, and state
members.
Default values can be associated with any member that has a primitive type in a struct or class, as is illustrated in this example. The default values are used when the receiving message does not contain the corresponding values.
Pointers make the members optional. So type
is an optional attribute.
Because a service operation request and response message is essentially a struct, XML attributes can also be associated with method requests and responses. For example:
Attributes can also be attached to the dynamic arrays, binary types, and wrapper classes and structs of primitive types. Wrapper classes are described in Section How to use C++ wrapper classes to specify polymorphic primitive types . For example:
and
The attribute declarations must be placed after the special __item
, __ptr
, and __size
members.
For additional details, see the C and C++ XML Data Bindings documentation.
An element or attribute with type QName (Qualified Name) contains a namespace prefix and a local name. We can explicitly declare a QName as a string type with typedef char *xsd__QName
and the serializer recognizes the QName
type as a special type that requires QName normalization. A built-in QName type _QName
is recognized by soapcpp2, which is a char*
type with QName content.
QName normalization by the deserializer is applied to convert the prefix in the inbound XML message to the corresponding prefix defined in the XML namespace table, which means that the QName string is always received in normalized form.
For example:
When the elt
and att
members are serialized, their string contents are just output. When the members are deserialized however, the deserializer converts the prefix in the parsed QName to the prefix defined in the namespace table that corresponds to the same namespace URI. For example, suppose that the inbound XML message contains <elt xmlns:x="urn:example">x:def</elt>
. The prefix x
matches the namespace URI urn:example
of prefix ns
as declared by the //gsoap ns schema namespace: urn:example
directive, which populates the namespace table ns.nsmap
generated by soapcpp2. Therefore, the x:def
QName value is converted to ns:def
and saved in the elt
member of ns__myStruct
.
If the namespace URI used in the inbound XML message is not in the namespace table, for example when <elt xmlns:x="urn:x">x:def</elt>
is parsed, then x:def
is converted to "URI":def
where "URI"
is the namespace URI bound to x
, which is "urn:x"
in this case. This value "urn:x":def
is saved in the elt
member of ns__myStruct
.
For additional details, see the C and C++ XML Data Bindings documentation.
A union is only serialized if the union is used within a struct or class declaration that includes an int __union
member that acts as a selector (also called discriminant) for the union members. The selector stores run-time usage information about the union member that is activated.
A union within a struct or class with a selector member represents xsd:choice
XML schema component. For example:
The union ns__PO_or_Invoice
appears as a xsd:choice
in the generated XML schema:
The union name should be qualified, as shown in the example, to ensure correct serialization when the XML schemas is declared with elementFormDefault="qualified"
, with //gsoap ns schema elementForm: qualified
.
The int __union
member selector's values are generated by the soapcpp2 tool. Each union member name has a selector value defined by:
These selector values enumerate the union members. The special value 0 (or any negative value) can be assigned to omit the serialization of the union altogether, but only if explicitly allowed by validation rules, which requires minOccurs="0"
for the xsd:choice
:
This way we can treat the union as an optional data item by setting __union = 0
.
Since 2.7.16 it is also possible to use a '$
' as a special marker to annotate a selector member that must be of type int
and the member name can be chosen arbitrarily:
The following example shows how the struct ns__composite
instance is initialized for serialization using the above declaration:
While the gSOAP serializers are designed to be robust, failing to set the selector to a valid union member can lead to a crash of the serializer, because it will attempt to serialize an invalid union member.
The deserializer of a union type sets the selector value to the currently active union member that was deserialized. The selector will be set to a non-positive value (0 or -1) when no union member was deserialized, if permitted by the validator, where -1 indicates that a member was required by validation rules, if the validator was non-strict. Strict validation enabled with SOAP_XML_STRICT
results in a validation fault in this case.
When more than one union is used in a struct or class, the __union
selectors should use $
to identify them and named to avoid name clashes, for example:
For additional details, see the C and C++ XML Data Bindings documentation.
Basically, the serialization of a pointer amounts to the serialization of the data pointed to. However, if more than one pointer points to a node in a data structure to serialize, the node is either duplicated in the serialized output meaning the data is serialized as a tree, or the node is output only once in the serialized output meaning that the data is serialized as a graph. The latter is referred to as multi-reference encoding in SOAP 1.1/1.2 RPC encoding style. This style ensures that data structures maintain their structural integrity when transmitted, as intended by the true meaning of serialization. The SOAP_XML_GRAPH
runtime flag can be used with plain non-SOAP XML to achieve the same.
To achieve this, the gSOAP serializers for SOAP RPC encoding and the SOAP_XML_GRAPH
flag check for multi-referenced data in the data structure to serialize, i.e. the data nodes that are co-referenced by other nodes, by adding id-ref/href attributes to the XML output that refer to the co-referenced data. The soapcpp2 tool generates serializers that perform this check automatically on C/C++ pointers and smart pointers, such as std::shared_ptr
. Furthermore, the soapcpp2 tool generates serializers that prevent infinite serialization when a cyclic data structure is serialized as a tree, by breaking the cycles, when using the SOAP document/literal style or when SOAP_XML_TREE
is enabled with the SOAP RPC encoding style.
For additional details on the use of C/C++ pointers and smart pointers, see the C and C++ XML Data Bindings documentation.
A node in the data structure that is pointed to by more than one pointer is serialized as multi-reference data when the SOAP RPC encoding style is used or when SOAP_XML_GRAPH
is enabled. This means that co-referenced data is identified in XML with a unique id
attribute. References in XML are made with href
(SOAP 1.1 RPC encoding), SOAP-ENC:ref
(SOAP 1.2 RPC encoding), or ref
(SOAP_XML_GRAPH
) attributes to refer to the co-referenced data. See Section Run-time flags on options to control the serialization of multi-reference data. To turn multi-ref off, use SOAP_XML_TREE
to process plain tree-based XML. To completely eliminate multi-ref serialization use the WITH_NOIDREF
compile-time flag with all source code (including gsoap/stdsoap2.c
and gsoap/stdsoap2.cpp
) to permanently disable id-href processing.
Consider for example the following a linked list data structure:
Suppose a cyclic linked list is created. The first node contains the value "abc" and points to a node with value "def" which in turn points to the first node. This is encoded as:
In case multi-referenced data is received that "does not fit in a pointer-based structure", the data is copied. For example, the following two structs are similar, except that the first uses pointer-based members while the other uses non-pointer-based members:
Since both a
and b
members of P
point to the same integer, the serialization of P
produces a multi-reference in SOAP 1.1 RPC encoding:
The deserialization of the content in the R
data structure that does not use pointers to integers results in a copy of each multi-reference integer. Note that the two structs resemble the same XML data type because the trailing underscore will be ignored in XML encoding and decoding.
A NULL pointer is not serialized, unless the pointer member of a struct or class is declared in the interface header file as nillable with nullptr
or in the unlikely case the pointer itself is pointed to by another pointer (but see Section Run-time flags to control the serialization of NULLs), for example:
The types section of a WSDL description contains information on the "nillability" of data, which is declared as nullptr
members where the 1
indicates that the member is required (minOccurs
and maxOccurs
are 1 set with 1:1
or simply 1
).
Suppose pointer q
points to pointer p
and suppose p
and r
are NULL. In that case the X
struct is serialized with SOAP_XML_GRAPH
as:
The deserializer reconstructs the struct X
from this form of XML, thereby preserving the integrity of the data structure serialized.
When the deserializer encounters an XML element that has a xsi:nil="true"
attribute but the corresponding C/C++ data is not a pointer or reference, the deserializer will terminate with a SOAP_NULL
fault when the SOAP_XML_STRICT
flag is set.
Void pointers (void*
) cannot be serialized in XML because the type of data referred to is untyped. To enable the serialization of void pointers that are members of structs and classes, you can insert a int __type
member right before the void pointer member. The int __type
member contains run time information on the type of the data pointed to by void*
member in a struct/class to enable the serialization of this data. The int __type
member is set to a SOAP_TYPE_T
value, where T
is the name of a type. The soapcpp2 tool generates the SOAP_TYPE_T
definitions in soapH.h
and uses them internally to uniquely identify the type of each object. The type naming conventions outlined in Section Serializing C/C++ data to XML are used to determine the type name for T
. Values serialized in XML with this approach always carry the xsi:type
attribute in XML to indicate the type of content serialized.
Here is an example to illustrate the serialization of a void*
member in a struct/class:
The __type
integer can be set to 0 at run time to omit the serialization of the void pointer member.
The following example illustrates the initialization of myStruct
with a void pointer to an int:
The serialized output of S
contains the integer in its val
element:
The deserializer for ns__record
will automatically set the __type
field and void pointer when deserializing the data, provided that the XML element val
carries the xsi:type
attribute from which it can determine the type.
void*
member, the void*
pointer must directly point to the string value rather than indirectly as with all other types. For example:This is the case for all string-based types, including types defined with typedef char*
.
You may use an arbitrary suffix with the __type
members to handle multiple void pointers in structs/classes. For example:
Because service method parameters are stored within structs, you can use __type
and void*
parameters to pass polymorphic arguments without having to define a C++ class hierarchy (Section Polymorphism, derived types, and dynamic binding in C++ ), provided that xsi:type
attributes are present in the XML elements. For example:
This method has a polymorphic input parameter data
and a polymorphic output parameter return_
. The __type
parameters can be one of SOAP_TYPE_xsd__string
, SOAP_TYPE_xsd__int
, SOAP_TYPE_xsd__float
, SOAP_TYPE_ns__status
, or SOAP_TYPE_ns__widget
. The WSDL and XSD files produced by the soapcpp2 tool declare the void*
polymorphic members as xsd:anyType
elements.
To declare a wrapper struct/class for void*
pointers allows us to reuse this mechanism when we use __self
as a member name that refers to the current XML element tag name:
The following example illustrates the initialization of __ns__record
with a void pointer to an int:
The serialized output of S
contains the integer:
Fixed size arrays are serialized as repetitions of item
elements with the array values in XML. Multi-dimensional fixed size arrays are serialized as nested item
elements, where the outer elements are arrays.
The serialization of fixed-size arrays supports the SOAP RPC encoding multi-dimensional array format as well as partially transmitted and sparse array formats standardized in SOAP 1.1 and 1.2.
For example:
This specifies a fixed-size array part of the struct Example
. The serialized output of array a
is:
Any deserialized items of an array that do not fit in the fixed size array, i.e. are out of bounds, are ignored by the deserializer when the SOAP_C_NOIOB
flag is set, otherwise SOAP_IOB
errors will be generated by the deserializer.
Dynamic arrays are much more flexible than fixed-size arrays. Dynamic arrays declared in the interface header file for soapcpp2 are a special struct or class or are part of a struct or class with a member pointing to an array of elements and a member that stores the size of the array. Dynamic array allocations are easy using the soapcpp-generated soap_new_T
functions for type T
. This function is used to allocate an array of values which can then be assigned to the pointer member of the struct/class that stores the array pointer with its size.
To facilitate SOAP RPC encoding, SOAP-encoded arrays require special treatment. SOAP-encoded arrays are single- or multi-dimensional arrays with bounds that appear in XML. These arrays may also have offsets that differ from zero. The intent of SOAP-encoded arrays is to replicate multi-dimensional arrays commonly found in programming languages.
However, XML also provides a simple way to represent a sequence of values with a sequence of XML elements. This differs from SOAP-encoded arrays in that SOAP-encoded arrays are elements with nested item
elements with values, though SOAP deserializers may ignore the name of these elements when parsing XML as stated in the SOAP specifications.
Both SOAP-encoded arrays and sequences of XML elements are supported in gSOAP, using dynamic arrays and containers. The basics will be described next. For additional details, see the C and C++ XML Data Bindings documentation.
SOAP-encoded arrays use the SOAP-ENC:Array
attribute in XML to identify the array and the SOAP-ENC:arrayType
attribute to identify the array dimensionality and its size.
As a security measure to avoid denial of service attacks based on sending a huge array size value using the SOAP-ENC:arrayType
attribute, requiring the allocation of large chunks of memory, the total number of array elements set by the SOAP-ENC:arrayType
attribute cannot exceed SOAP_MAXARRAYSIZE
, which is set to 100000 by default. This limit is not a hard limit on the number of array elements, but rather to avoid pre-allocating large arrays as stated. The hard limit on the number of array elements received is soap::maxoccurs
which is set to SOAP_MAXOCCURS
by default. By contrast, the SOAP_MAXARRAYSIZE
limit only negatively affects multi-dimensional arrays because the dimensionality of the receiving array may be lost when the number of elements exceeds 100000. One-dimensional arrays are not affected and populated after this limit by simply deserializing the array elements received.
A special form of struct or class is used to define one-dimensional dynamic SOAP-encoded arrays in an interface header file for soapcpp2. Each array has a pointer variable and a member that records the number of elements the pointer points to in memory.
The general form of the struct or class declaration that contains a one-dimensional dynamic SOAP-encoded array is:
where the array_name
must be a non-qualified name and Type
is the type for the elements of the array. The __ptr
member points to the array values and __size
is the array size. The __offset
member specifies an optional array offset, when nonzero, see Section One-dimensional dynamic SOAP-encoded arrays with non-zero offsets.
If the array_name
is qualified with a namespace prefix then the array is not a SOAP-encoded array but rather represents a sequence of XML elements, see Section Non-SOAP dynamic arrays.
The soapcpp2-generated deserializer of a one-dimensional dynamic array can deserialize partially transmitted and/or SOAP-encoded sparse arrays, and even multi-dimensional arrays which will be collapsed into a one-dimensional array with row-major ordering.
__offset
member of a dynamic array is ignored.The declaration of a dynamic array as described in Section One-dimensional dynamic SOAP-encoded arrays may include an int __offset
member. When set to an integer value, the serializer of the dynamic array will use this member as the start index of the array and the SOAP-encoded array offset attribute SOAP-ENC:offset
will appear in the XML message. Note that array offsets is a SOAP 1.1 specific feature which is not supported in SOAP 1.2.
For example, the following header file declares a numeric Vector
class, which is a dynamic array of floating point values with an index that starts at 1:
The implementations of the Vector
methods are:
An example program fragment that serializes a vector of 3 elements:
The output is a partially transmitted array:
Note that xsd:float[4]
is the type and shape of the encoded array, which starts at offset 1 and therefore the element at 0 is omitted.
One-dimensional SOAP-encoded dynamic arrays may be nested. For example, using class Vector
declared in the previous section, class Matrix
is declared:
The Matrix type is essentially an array of pointers to arrays which make up the rows of a matrix. The serialization of the two-dimensional dynamic array in is nested form in XML.
A special form of struct
or class
is used to define multi-dimensional dynamic SOAP-encoded arrays. Each array has a pointer variable and a member that records the number of elements per dimension. A K
-dimensional array is declared as:
where the array_name
must be a non-qualified name and Type
is the type for the elements of the array. The __ptr
member points to the array values. The __size
array specifies the number of array elements per dimension. The __offset
array specifies an optional offset per dimension.
For example, the following declaration specifies a matrix class:
By contrast to the matrix class of Section Nested one-dimensional dynamic SOAP-encoded arrays that defines a matrix as an array of pointers to matrix rows, this class has one pointer to a matrix stored in row-major order. The size of the matrix is determined by the __size
member: __size[0]
holds the number of rows and __size[1]
holds the number of columns of the matrix. Likewise, __offset[0]
is the row offset and __offset[1]
is the columns offset.
__offset
member of a dynamic array is ignored.An array is serialized as a sequence of XML elements. By contrast, a SOAP-encoded array is serialized as an element with a sequence of sub-elements, whose tag names are irrelevant to the SOAP processor, see One-dimensional dynamic SOAP-encoded arrays.
An array is declared in an interface header file for soapcpp2 as a struct or class with a name that is qualified with a namespace prefix. There are two forms. The first form is similar to the SOAP-encoded array declaration that wraps the __ptr
and __size
members:
The second form is more generic, because the array can be declared anywhere in the struct or class and multiple arrays can be used as members, each with a __size
member (__sizeName
is also allowed) that precedes a pointer member:
The __size
member should be an int
type and cannot be a size_t
type or other integer type.
For example, we define a Map structure that contains a sequence of key-val pairs:
Since 2.7.16 it is also possible to use a '$
' as a special marker to annotate a size member instead of requiring these members to start with __size
:
The array will be serialized in XML as a sequence of pairs:
Deserialization is less efficient compared to a SOAP-encoded array, because the size of the sequence is not part of the SOAP encoding. Buffering is used by the deserializer to collect the elements in memory. When the end of the list is reached, the buffered elements are copied to a newly allocated managed space on the heap for the dynamic array.
Multiple arrays can be part of a struct or class. For example:
The XML serialization of an example ns__Contact
is:
For C++, a better alternative to arrays are containers, which are described next.
The containers std::deque
, std::list
, std::set
, and std::vector
are serializable in XML by the soapcpp2-generated serializers.
In order to use containers in an interface header file for soapcpp2, import stldeque.h
, stllist.h
, stlset.h
, or stlvector.h
to enable std::deque
, std::list
, std::set
, and std::vector
, respectively. For example:
The use of pointer members such as for name
shown above is possible, but not required. Also minOccurs : maxOccurs
and minOccurs
length constraints can be specified as shown in the example above. The XML schema that corresponds to the ns__myClass
type is:
You can also implement your own containers. The containers must be class templates and should define a forward iterator type, and provide the following methods:
void clear()
empty the container;iterator begin()
return iterator to beginning;const_iterator begin() const
return const iterator to beginning;iterator end()
return iterator to end;const_iterator end() const
return const iterator to end;size_t size()
return size;bool empty()
return true if empy;iterator insert(iterator pos, const_reference val)
insert element.The iterator
should be a forward iterator with a dereference operator to access the container's elements, it must be comparable (equal/unequal), and be pre-incrementable (++it
). The const iterator is used by its soapcpp2-generated serializer to send a sequence of XML element values. The insert
method is used to populate a container with Container::iterator i = container.insert(container.end(), val)
.
Here is in example container template class:
To enable the container, we add the following two lines to the interface header file for soapcpp2:
The container class itself should not be defined in the interface header file, only the template declaration suffices for soapcpp2 to generate serializers. Recall that the #include
directives are not executed by soapcpp2 but simply passed on to the generated source code. This include specifies in the generated source code where the container is actually defined.
Polymorphic arrays, that is, arrays of values of any type, can be serialized in XML when declared as an array of pointers to a base class. For example:
The pointers in the array can point to the ns__Object
base instances or ns__Data
derived instances, which will be serialized accordingly in XML. Derived instances are indicated by xsi:type
attribute in XML with the qualified name of the class, to distinguish derived instances from the base instances. Without this attribute the deserializer will not instantiate the derived instance but a base instance since there is no identifying information to distinguish the XML forms except for the xsi:type
attribute.
Since we cannot use dynamic binding to support polymorphism in C, another mechanism we can use is void pointers . Here is an example of a polymorphic SOAP-encoded array ArrayOfObject
and a non-SOAP dynamic array ns__Objects
that hold values of any serializable type:
This example uses an "invisible" type __wrapper
and member __array
, which start with a double underscore. These names are never visible in serialized XML. The __type
member of __wrapper
is a SOAP_TYPE_T
value that identifies the type T
that __item
points to, see Section Void pointer serialization.
The default XML element tag name for array elements is item
, which can be changed. The __ptr
member in a struct or class of a dynamic array may have an optional suffix part that specifies the name of the element tag in XML. That is, the suffix is part of the __ptr
member name:
Consider for example:
The array is serialized as:
SOAP 1.1/1.2 does not mandate a specific tag name for SOAP-encoded array elements and the soapcpp2-generated serializers will ignore the name used to itemize SOAP-encoded array values.
The base64Binary
XSD type is introduced in an interface header file for soapcpp2 using a struct or class that contains an array of unsigned char
values:
The advantage of this struct or class is the ability to serializer raw binary data from memory, since the soapcpp2-generated serializer converts the binary data to/from base64 in XML.
To introduce a new XML schema type derived from base64Binary
use the same struct or class structure, but with another name. For example:
The resulting XML schema type is:
The base64Binary
XSD type is introduced in an interface header file for soapcpp2 using a struct or class that contains an array of unsigned char
values:
The advantage of this struct or class is the ability to serializer raw binary data from memory, since the soapcpp2-generated serializer converts the binary data to/from hexadecimal in XML.
If a binary type such as xsd__base64Binary
is already defined, then we can simply use a typedef
to introduce the hex variant:
This lets soapcpp2 generate xsd:base64Binary
and xsd:hexBinary
serializers.
SOAP has several styles:
xsd:sequence maxOccurs="unbounded"
is not allowed), and xsd:choice
components are not allowed. Multi-referenced elements are used to serialize data structure graphs. Because additional SOAP-encoding specific attributes are present that are not defined in the XML schema (of the WSDL), strict XML schema validators may reject SOAP-encoded content. The SOAP Body contains at most one service operation request element or at most one service operation response element and the encoding style is indicated with the SOAP-ENV:encodingStyle="..."
attribute in the SOAP Body or one or more of its sub-elements. This style is specified for the entire service declared under namespace prefix ns
with: SOAP_XML_GRAPH
to force the use of id-ref to accurately serialize digraphs and cyclic data structures. The SOAP Body may contain any number of XML elements, as if the SOAP Body is the root of an XML document. No SOAP-ENV:encodingStyle="..."
attribute should appear in literal content. This style is specified for the entire service declared under namespace prefix ns
with: SOAP-ENV:encodingStyle="..."
attribute should appear in literal content. This style is specified for the entire service declared under namespace prefix ns
with: Besides //gsoap ns service style
and //gsoap ns service encoding
there are also the service operation specific versions //gsoap ns service method-style
, //gsoap ns service method-response-style
, //gsoap ns service method-encoding
, and //gsoap ns service method-response-encoding
that explicitly specify SOAP RPC encoded, document/literal, or RPC literal style messages for the indicated service operation methods.
To enable SOAP RPC encoding for a particular service operation, use:
To enable SOAP RPC encoding for a particular service operation response, use:
Likewise, you can specify document/literal and RPC literal messages. The default style is document/literal, unless soapcpp2 -e
option -e
is used to set SOAP RPC encoding by default.
For the style
directives you can specify rpc
or document
. For the encoding
directives you can specify literal
, encoded
, or even a custom URI that indicates some custom or proprietary encoding format in XML which will not interoperate with SOAP processors that are not compatible with the specified encoding format. See also Section Directives.
See also C and C++ XML data bindings documentation for differences in XML serialization when using the SOAP RPC encoded and document/literal messaging styles.
XML is stored in "literal" XML strings which are the built-in _XML
type that is a regular char*
string or you can declare a wide character string in an interface header file for soapcpp2 as follows:
To declare a C++ std::string
literal XML type:
Or use a wide character string:
To use both at the same time:
The differences between the use of regular 8-bit strings versus wide character strings for XML documents are:
Some XML validation constraints are not automatically verified unless explicitly set using the SOAP_XML_STRICT
flag. SOAP RPC encoding is an XML format that does not afford strict XML validation, because of the addition of SOAP-specific attributes and other small deviations that will be detected by an aggressive XML validator, leading the messaging failures. By toning XML validation down, it helps to improve SOAP RPC encoding interoperability.
Strict validation constraints are enabled with the SOAP_XML_STRICT
mode flag set, e.g. with soap_set_imode(soap, SOAP_XML_STRICT)
or soap_new(SOAP_XML_STRICT)
, see Section Run-time flags for the complete list of flags.
The next sections describe the type of constraints validated when SOAP_XML_STRICT
is enabled and validation constraints are specified in the interface header file.
Use compiler flag WITH_REPLACE_ILLEGAL_UTF8
to force strict UTF-8 text conversions, which replaces invalid UTF-8 with U+FFFD.
See also C and C++ XML data bindings documentation for more details.
Default values can be defined for optional elements and attributes, which means that the default value will be used when the element or attribute value is not present in the parsed XML. See also Section Default values for omitted XML elements and attributes and examples in subsequent subsections below.
Default values must be primitive types, integer, float, string, etc. or pointers to primitive types. Default values can be specified for struct and class members, as shown in the example below:
Upon deserialization of absent data, these members will be set accordingly. When classes are instantiated with soap_new_ClassName
the instance will be initialized with default values.
See also C and C++ XML data bindings documentation for more details.
Occurrence constraints specify the minimum and/or maximum frequency or optionality of of attributes and elements.
To force the validation of minOccurs and maxOccurs constraints the SOAP_XML_STRICT
input mode flag must be set. The minOccurs and maxOccurs constraints are specified for members of a struct and members of a class in a header file using the following syntax:
The nullptr
is optional and indicates that the member is nillable (gSOAP version 2.8.24 or greater), which means that when NULL an empty element with xsi:nil="true"
is added in the serialized XML.
The minOccurs
and maxOccurs
are optional values that must be integer literals. When maxOccurs
is not specified then the colon can be omitted. When minOccurs
is not specified it is assumed to be one (1) for non-pointer members that are elements and zero (0) for members that are pointers or are attributes (i.e. have a @
qualifier).
A default initialization value
may be provided and is optional.
A fixed initialization value can be specified with ==
(gSOAP version 2.8.48 or greater).
For example
See also C and C++ XML data bindings documentation for more details.
Similar to the minOccurs and maxOccurs annotations defined in the previous section, attributes in a struct or class can be annotated with occurrence constraints to make them optional (0), required (1), or prohibited (0:0). Default values can be assigned to optional attributes.
For example
Remember to set the SOAP_XML_STRICT
input mode flag to enable the validation of attribute occurrence constraints.
See also C and C++ XML data bindings documentation for more details.
Value constraints restrict the length of strings and the range of values of numeric types.
A schema simpleType is defined with a typedef
by taking a base primitive to defined a derived simpleType. For example:
This defines the following schema type in time.xsd
:
A complexType with simpleContent is defined with a wrapper struct/class:
This defines the following schema type in time.xsd
:
Data value length constraints of simpleTypes and complexTypes with simpleContent are defined as follows:
Set the SOAP_XML_STRICT
mode flag to enable the validation of value length constraints.
See also C and C++ XML data bindings documentation for more details.
Similar to data length constraints for string-based data, integer and floating point value range constraints on numeric simpleTypes and complexTypes with simpleContent are declared with low : high
, where low
and high
are optional.
As of gSOAP 2.8.26, floating point value ranges and integer ranges can be exclusive by adding <
on either side of the :
range operator:
range | validation check |
---|---|
1 | 1 <= x |
1 : | 1 <= x |
: 10 | x <= 10 |
1 : 10 | 1 <= x <= 10 |
1 < : < 10 | 1 < x < 10 |
1 < 10 | 1 < x < 10 |
1 : < 10 | 1 <= x < 10 |
: < 10 | x < 10 |
< 10 | x < 10 |
1 < : | 1 < x |
1 < | 1 < x |
1 < : 10 | 1 < x <= 10 |
For example:
Set the SOAP_XML_STRICT
mode flag to enable the validation of value range constraints.
See also C and C++ XML data bindings documentation for more details.
Patterns can be defined for simpleType content. However, pattern validation is not enforced unless the soap::fsvalidate
and soap::fwvalidate
callbacks are set to a regex matcher.
To associate a pattern with a simpleType, you can define a simpleType with a typedef
and a pattern string:
This defines the following schema type in time.xsd
:
The pattern string must contain a valid regular expression.
A special case for C format string patterns is introduced in gSOAP 2.8.18. When xsd:totalDigits
and xsd:fractionDigits
are given in a XSD file, then a C format string is produced to output floating point values with the proper precision and scale. For example:
produces:
The format string is used to format the output the floating point value in XML.
See also C and C++ XML data bindings documentation for more details.
Struct, class, and union members represent elements and attributes that are automatically qualified or unqualified depending on the schema element and attribute default forms specified. The engine always validates the prefixes of elements and attributes. When a namespace mismatch occurs, the element or attribute is not consumed which can lead to a validation error (unless the complexType is extensible or when SOAP_XML_STRICT
is turned off).
Consider for example:
Here, the ns__record
struct is serialized with qualified element name
and unqualified attribute type
:
The "colon notation" for struct/class/union member names is used to override element and attribute qualified or unqualified forms. To override the form for individual members that represent elements and attributes, use a namespace prefix and colon with the member name:
where name
is unqualified and type
is qualified:
The colon notation is a syntactic notation used only in the interface header file syntax, it is not translated to the C/C++ output.
The colon notation does not avoid name clashes between members. For example:
results in a redefinition error, since both members have the same name. To avoid name clashes, use a underscore suffix:
Not that the namespace prefix convention can be used instead:
which avoids the name clash. However, the resulting schema is different since the last example generates a global name
element definition that is referenced by the local element.
More specifically, the difference between the namespace prefix convention with double underscores and colon notation is that the namespace prefix convention generates schema element/attribute references to elements/attributes at the top level, while the colon notation only affects the local element/attribute namespace qualification by form overriding. This is best illustrated by an example:
which generates the following x.xsd
schema:
and the y.xsd
schema defines contains:
See also C and C++ XML data bindings documentation for more details.
A namespace mapping table should be included in the source code of client and service applications. The mapping table is used by the serializers and deserializers of the stub and skeleton functions to produce valid XML messages and to parse and validate XML messages. A typical mapping table is shown below:
Each namespace prefix used by a identifier name in the header file specification, see Section C/C++ identifier name to XML tag name translation, must have a binding to a namespace URI in the mapping table. The end of the namespace mapping table must be indicated by the NULL pair. The namespace URI matching is case insensitive. A namespace prefix is distinguished by the occurrence of a pair of underscores (__
) in an identifier or by using colon notation, see Section C/C++ identifier name to XML tag name translation.
An optional third column in the namespace mapping table may be specified that contains a namespace URI pattern. The patterns provide an alternative namespace for the validation of parsed XML messages. In this pattern, dashes (-
) are single-character wildcards and asterisks (*
) are multi-character wildcards. For example, to accept alternative versions of XML schemas with different authoring dates, four dashes can be used in place of the specific dates in the namespace mapping table pattern:
Or alternatively, asterisks can be used as wildcards for multiple characters:
A namespace mapping table is automatically generated with prefixes and URIs in the table that are declared with //gsoap <prefix> schema namespace:
directives in the interface header file, see Section Directives. If directives are not provided in the header file then default URIs of the form http://tempuri.org/prefix.xsd
for each namespace prefix
. The soapcpp2 tool also generates a WSDL and one or more XSD files, one for each XML namespace.
When parsing XML and deserializing data, namespace URIs in the XML messages are matched against the second and third column of the namespace mapping table, searching from the top to the bottom of the table. The actual prefix used in the XML message is irrelevant as the URI associated with the prefix is relevant to define the XML namespace to which a qualified element or attribute belongs. When a match is found, the namespace prefix in the first column of the table is considered semantically identical to the namespace prefix used by the qualified XML element and attribute parsed, even when the prefix names differ. This normalization of prefixes is invisible to the user of gSOAP and makes coding with XML easier. For example, when XSD QNames are parsed into strings using the built-in soapcpp2 _QName
type or a QName declared with typedef std::string xsd__QName
, then this QName string will always contain qualified names with normalized prefixes, i.e. prefixes defined in the namespace mapping table, unless the table has no entry, see Section How to use QName attributes and elements.
For example, let's say we have the following structs:
The namespace mapping table generated by soapcpp2 has the following entries:
Then, the following XML elements will match these structs:
Instead of one big namespace table that contains all XML namespace prefixes with their URIs, there are cases when it is desirable to use multiple namespace tables, one for each service. This avoids leaking namespace prefixes in XML messages that have nothing to do with the service invoked. In principle there is no harm to leak these namespace prefixes, but the messages are less compact and not as clean. To use multiple namespace tables at the client side is done as follows:
Likewise, on the server side call soap_set_namespaces
before calling soap_serve
. Changing the namespaces table in service operations has no effect.
The XML messages produced by the gSOAP engine include all xmlsn
namespace bindings in the root element, which is generally more efficient for larger XML documents in which otherwise the xmlsn
namespace bindings will be sprinkled throughout. By contrast, canonical XML requires xmlsn
namespace bindings only to be included when utilized. Therefore, the SOAP_XML_CANONICAL
context flag produces C14N exclusive XML messages and documents, which eliminates unused xmlsn
namespace bindings from XML. Unfortunately, the current C14N standard is buggy with respect to XSD QName content, because prefixes used in QName content are not considered utilized. The gSOAP engine considers QName content prefixes utilized and therefore produces corrected canonicalized XML output that prevents the loss of namespace information for QNames.
A built-in SOAP Header data structure SOAP_ENV__Header
is generated by the soapcpp2 tool for exchanging SOAP headers in SOAP messages. This structure is empty unless headers are added by plugins and headers specified by WSDL specifications (i.e. wsdl2h adds SOAP Headers).
You can create your own SOAP Header struct simply by declaring it in an interface header file for soapcpp2 and by adding members that must be qualified with namespace prefixes to conform to the SOAP Header processing requirements that SOAP Header elements must be namespace qualified.
For example, assume that transaction data should be piggy-backed with SOAP messages in SOAP Header:
The mustUnderstand
qualifier specifies that the element must be processed by the SOAP processor and cannot be ignored if the processor has no logic in place for this SOAP header, which is done by adding a SOAP-ENV:mustUnderstand="true"
attribute to the t:transaction
element. The soapcpp2-generated serializers obey this safety principle.
This declares a service operation that sends messages with an input SOAP header t__transaction
, as can be seen in the generated WSDL binding:
Likewise, you can specify that both input and output messages have the same header with //gsoap ns service method-header-part:
or the output message has a header with //gsoap ns service method-output-header-part:
. Multiple headers can be specified this way.
To set up a SOAP Header at the client side that contains the t__transaction
member:
The SOAP Web service request includes the SOAP Header with the transaction data:
At the receiving side, a SOAP Header can be inspected by checking for a non-NULL soap::header
.
soap::header
to NULL when no SOAP Header should be sent, otherwise any SOAP Headers currently present in the SOAP_ENV__Header
struct pointed to by soap::header
will be included in the message.At the client side, the soap::actor
string variable can be set to set the SOAP SOAP-ENV:actor
attribute. The SOAP-ENV:mustUnderstand="true"
attribute then indicates the requirement that the recipient corresponding to the SOAP-ENV:actor
attribute value is responsible to process the SOAP Header element. The details of which can be found in the SOAP 1.1/1.2 specifications that the gSOAP tools conform to.
The SOAP Header structure SOAP_ENV__Header
is declared mutable
, which means that re-declarations of the structures are permitted and additional members are collected into one final structure by the soapcpp2 tool.
For another example, consider:
Suppose method ns__login
uses both header parts (at most), then this is declared as:
Suppose method ns__search
uses only the first header part, then this is declared as:
Note that the method name and header part names must be namespace qualified. The headers must be present in all operations that declared the header parts.
To specify the header parts for the method input (method request message), use:
Similarly, to specify the header parts for the method output (method response message), use:
The declarations only affect the WSDL. For example:
The headers must be present in all operations that declared the header parts.
See also API documentation Module Header structure and functions.
A built-in SOAP Fault data structure SOAP_ENV__Fault
is generated by the soapcpp2 tool for exchanging exception messages. This structure has the general form:
The first four members in SOAP_ENV__Fault
are SOAP 1.1 specific. The last five members are SOAP 1.2 specific. You can redefine these structures in the interface header file for soapcpp2. For example, you can use a class
for the SOAP_ENV__Fault
and add methods for convenience.
The SOAP_ENV__Detail
structure can be changed to the needs of Web service application to communicate specific fault data structures, but this is generally not necessary because the application-specific SOAP Fault details can be serialized via the __type
and fault
members in the SOAP_ENV__Detail
member, see Section Void pointer serialization on the serialization of data referred to by __type
and fault
.
When a user-define service operation function returns an error with soap_sender_fault
or soap_receiver_fault
, then the SOAP Fault structure is populated and soap::fault
points to this SOAP Fault. The SOAP Fault is sent to the client. The client populates a SOAP Fault structure that contains the SOAP Fault message with details.
Server-side faults are raised with soap_sender_fault
or soap_receiver_fault
. The soap_sender_fault
call should be used to inform that the sender is at fault and the sender (client) should not re-send the request. The soap_receiver_fault
call should be used to indicate a temporary server-side problem, so a sender (client) can re-send the request later. For example:
In the example, the SOAP Fault details were empty (NULL). You may pass an XML fragment, which will be literally included in the SOAP Fault message. For WS-I Basic Profile compliance, you must pass an XML string with one or more namespace qualified elements, such as:
When a service operation needs to populate SOAP Fault details with a application-specific data, it does so by assigning the soap::fault
member of the current reference to the context with appropriate data associated with the exception and by returning the error SOAP_FAULT
. For example:
Here, soap_receiver_fault
allocates a fault struct then we set the SOAP Fault details as shown.
Note that SOAP 1.2 supports nested fault sub-codes. These can be set as follows:
This produces:
Service operations implementation in a Web service application can return various SOAP Faults customized in this way.
SOAP Fault structures are declared mutable
, which means that re-declarations of the structures are permitted and additional members are collected into one final structure by the soapcpp2 tool.
For an example that used the SOAP Fault detail structure:
See also API documentation Module Fault structure and functions.
The gSOAP toolkit supports MIME attachments as per SOAP with Attachments (SwA) specification http://www.w3.org/TR/SOAP-attachments.
MTOM attachments that are essentially MIME attachments that conform to the MTOM specification http://www.w3.org/TR/soap12-mtom are also supported which are the preferred way to include MIME attachments with SOAP messages, see Section MTOM attachments.
In the following discussion, MIME attachment data is assumed to be resident in memory for sending operations and MIME attachments received will be stored in memory managed by the context. MTOM and DIME attachments on the other hand can be streamed and therefore MTOM/DIME attachment data does not need to be stored in memory, see Sections DIME attachments and MTOM attachments .
Transmitting multipart/related MIME attachments with a SOAP/XML message is accomplished with two functions, soap_set_mime
and soap_set_mime_attachment
. The first function is for initialization purposes and the latter function is used to specify meta data and content data for each attachment.
See also API documentation Module MIME attachment functions.
The following functions are used to set up a collection of multipart/related MIME attachments for transmission with a SOAP or XML message.
void soap_set_mime(struct soap *soap, const char *boundary, const char *start)
This function enables sending MIME attachments. This function is generally not required when the context is initialized with SOAP_ENC_MIME
, because MIME attachments are automatically detected as xsd__base64Binary
and _xop__Include
structures in the data to serialize as an XML message with the attachments automatically added or MIME attachments can be explicitly added with soap_set_mime_attachment
. Parameter boundary
specifies a MIME boundary string or NULL to have the engine generate a MIME boundary string. Parameter start
specifies the start content ID for the first MIME body containing the SOAP or XML message. When NULL, the start ID of the SOAP message is <SOAP-ENV:Envelope>
.int soap_set_mime_attachment(struct soap *soap, char *ptr, size_t size, enum soap_mime_encoding encoding, const char *type, const char *id, const char *location, const char *description)
This function adds a MIME attachment to a SOAP/XML message to send. The specified ptr
points to the data to send of length specified by size
. The encoding
parameter is a soap_mime_encoding
value that is recommended to be specified as SOAP_MIME_NONE
to specify that the MIME data content is not encoded in any way (the MIME attachment function simply copies the raw data to the MIME block without encoding). The type
parameter is required and indicates the MIME type of the data, such as "image/jpg". The id
parameter uniquely identifies the attachment in the message, which can be omitted by specifying NULL. The location
parameter specifies a location string or NULL. The description
parameter is a string that describes the data or NULL. Returns SOAP_OK
or a soap_status
error code.void soap_clr_mime(struct soap *soap)
This function disables MIME attachments such as after sending a multipart-related message with attachments to switch back to non-multipart-related messaging, unless the data to serialize as a message contains attachments such as xsd__base64Binary
for MIME attachments and _xop__Include
for MTOM attachments.When providing a MIME boundary with soap_set_mime
, you have to make sure the boundary cannot match any parts of the message and attachments that you are sending, because the boundary delineates the attachments.
The internal list of attachments specified with soap_set_mime_attachment
is destroyed with soap_end
or when a message is received. Therefore, call soap_set_mime_attachment
to set attachments before sending a message.
The following example shows how a multipart/related HTTP message with three MIME attachments is set up and transmitted to a server. In this example we let the message body refer to the attachments using XML href
attributes. The struct claim__form
data type includes a definition of a href
attribute for this purpose.
The claim__form
struct is declared in the interface header file as:
The claim forms in the message consist of href
s to the claim forms attached. The use of href
or other attributes for referring to the MIME attachments is optional according to the SwA standard. MTOM on the other hand mandates the use of href
with XOP elements.
To associate MIME attachments with the request and response of a service operation in the generated WSDL, please see Section Generating MultipartRelated MIME attachment bindings in WSDL .
The server-side code to transmit MIME attachments back to a client:
MIME attachments are automatically parsed and stored in memory managed by the soap
context. After receiving a set of MIME/MTOM attachments, either at the client-side or the server-side, the list of MIME/MTOM attachments can be traversed to extract meta data and the attachment content. The first attachment in the collection of MIME/MTOM attachments always contains meta data about the SOAP message itself (because the SOAP message was processed the attachment does not contain any useful data).
To traverse the list of MIME attachments in C, you use a loop similar to:
C++ programmers can use an iterator instead:
Note: keep in mind that the first attachment is associated with the SOAP message and you may want to ignore it.
A call to soap_end
removes all of the received MIME data. To preserve an attachment in memory, use soap_unlink
on the ptr
member of the soap_multipart
struct. The soap_unlink
function can be used to prevent deallocation of deserialized data.
Applications developed with the gSOAP tools can transmit binary DIME attachments stored in memory or in streaming mode by fetching data from a resource or sending data to a resource using callback functions. The maximum DIME attachment size is limited to 8 MB by default as set with SOAP_MAXDIMESIZE
. This limit can be changed as needed. With streaming DIME using callback functions, data handlers are used to pass the data to and from a resource from which to fetch the data to send or data to store, such as a file or device. See Section Streaming DIME .
For details on DIME attachments, see http://msdn.microsoft.com/library/en-us/dnglobspec/html/draft-nielsen-dime-02.txt
See also API documentation Module DIME attachment functions.
The following functions can be used to explicitly set up a collection of DIME attachments for transmission with a message. These attachments can be streamed, as described in Section Streaming DIME . Without streaming, each attachment must refer to a block of data in memory.
void soap_set_dime(struct soap *soap)
This function enables sending DIME attachments. This function is generally not required because DIME attachments are automatically detected as xsd__base64Binary
and _xop__Include
structures in the data to serialize as an XML message with the attachments automatically added or DIME attachments can be explicitly added with soap_set_dime_attachment
.int soap_set_dime_attachment(struct soap *soap, char *ptr, size_t size, const char *type, const char *id, unsigned short optype, const char *option)
This function adds a DIME attachment to the XML message to send. The specified ptr
points to the data to send of length specified by size
. The type
parameter indicates the MIME type of the data or can be NULL. The id
parameter uniquely identifies the attachment in the message, which can be omitted by specifying NULL. The option
parameter is an option such as a description of the data and optype
is a user-defined option type (as per DIME option specification format). The ptr
parameter must be persistent. The ptr
parameter passed to this function must be persistent in memory until the attachment was sent. Returns SOAP_OK
or a soap_status
error code.void soap_clr_dime(struct soap *soap)
This function disables DIME attachments, unless the data to serialize as an XML message contains attachments defined by xsd__base64Binary
and _xop__Include
structures.These functions allow DIME attachments to be added to SOAP messages without requiring message body references. This is also referred to as the open DIME attachment style. The closed attachment style requires all DIME attachments to be referenced from the SOAP message body with href
(or similar) references. For the closed style, gSOAP supports an automatic binary data serialization method, see Section Serializing binary data with DIME attachments .
DIME attachments are automatically parsed and stored in memory (or passed to the streaming handlers via the DIME callback functions when defined). After receiving a set of DIME attachments, either at the client-side or the server-side, the list of DIME attachments can be traversed to extract meta data and the attachment content.
To traverse the list of DIME attachments in C, you use a loop similar to:
C++ programmers can use an iterator instead:
The options
member is available as well, but not shown in the code above. The options
content is formatted according to the DIME specification: the first two bytes are reserved for the option type, the next two bytes store the size of the option data, followed by the (binary) option data.
A call to soap_end
removes all of the received DIME data. To preserve an attachment in memory, use soap_unlink
on the ptr
member of the soap_multipart
struct. The soap_unlink
function can be used to prevent deallocation of deserialized data.
Binary data stored in extended xsd__base64Binary
and xsd__hexBinary
types can be serialized and deserialized as DIME attachments when one or more of the extra members id
, type
, and options
are non-NULL. These attachments will be automatically transmitted prior to the sequence of secondary DIME attachments defined by the user with soap_set_dime_attachment
as explained in the previous section. The serialization process is automated for SOAP encoded messages and DIME attachments will be send even when soap_set_dime
or soap_set_dime_attachment
are not used. For non-SOAP-encoded messages such as document/literal messages you must still call soap_set_dime
to enable sending messages with attachments.
To enable serialization of the data as DIME attachments instead of inline base64, we extend the xsd__base64Binary
type with three additional members:
The id
member is for attachment referencing, typically a content id (CID) or a UUID which can be obtained with soap_rand_uuid
, a type
member is used to specify the MIME type of the data, the options
member is used to piggy-back additional information with a DIME attachment. The order of the declaration of the members is significant. In addition, no other members or methods may be declared before any of these members in the struct/class, but additional members and methods may appear after the member declarations. The extended xsd__hexBinary
type is similar.
The id
and type
members contain text. The set the DIME-specific options member, you can use the soap_dime_option
function char *soap_dime_option(struct soap *soap, unsigned short type, const char *option)
.
This function returns a string with this encoding. For example
When either the id
or type
member values are non-NULL at run time, the data will be serialized as a DIME attachment.
The SOAP/XML message refers to the attachments using href
attributes. This generally works will with SOAP RPC encoded messaging, because href
attributes are permitted. However, with document/literal style the referencing mechanism must be explicitly defined in the schema of the binary type. Therefore, MTOM is the preferred attachment mechanism for document/literal style messaging.
The declaration of an extended binary type in the interface header file for soapcpp2 is:
C++ programmers can use inheritance instead of textual extension required in C:
This defines an extension of xsd:base64Binary
, such that the data can be serialized as DIME attachments using href
attributes for referencing. When a different attribute is to be used, this must be explicitly defined:
The example above uses the location
attribute defined in the content reference schema, as defined in one of the vendor's specific WSDL extensions for DIME http://www.gotdotnet.com/team/xml_wsspecs/dime/WSDL-Extension-for-DIME.htm.
When receiving DIME attachments, the DIME meta data and binary content are stored in the specified xsd__base64Binary
and xsd__hexBinary
binary data types only when the XML parts of the message uses href
attributes to refer to these attachments. If so, the binary data type __ptr
and __size
members are set to the location in memory of the attachment data and length, respectively.
Messages may contain binary data that references external resources not provided as attachments. In that case, the __ptr
member is NULL and the id
member refers to the external data source.
The dime_id_format
attribute of the current context can be set to the default format of DIME id members. The format string must contain a d
format specifier (or any other int
-based format specifier). The value of this specifier is a non-negative integer, with zero being the value of the DIME attachment id for the SOAP message. For example,
As a result, all attachments with a NULL id
member will use a auto-generated id value based on the format string.
Streaming DIME is achieved with callback functions to fetch and store data during transmission. Three function callbacks for streaming DIME output and three callbacks for streaming DIME input are available.
void *(*soap.fdimereadopen)(struct soap *soap, void *handle, const char *id, const char *type, const char *options)
This callback is called by the engine to start sending a streaming DIME attachment. This callback opens a stream to start reading the attachment data to send. The actual data stream will be read in chunks using the soap::fdimeread
callback until no more data is available and the soap::fdimereadclose
callback is called to close the stream. The handle
parameter contains the value of the __ptr
member variable of the attachment struct/class with data (e.g. xsd__base64Binary
or _xop__Include
with __ptr
, __size
, id
, type
and options
members), which should be a pointer to specific information such as a file descriptor or a pointer to a some application-specific data to be passed to this callback. Both the __ptr
and __size
members of the attachment struct/class should have been set by the application prior to the serialization of the message with attachments. If the __size
is zero and HTTP chunking is enabled (with SOAP_IO_CHUNK
), then chunked DIME attachments are sent, see soap::fdimeread
. The id
, type
and options
parameters are the id
(optional ID), type
(a MIME type) and options
(DIME options are set with soap_dime_option
) of the attachment struct/class, respectively, of which at least one member should be non-NULL. The callback should return the handle
parameter value or another pointer value, which is passed as the new handle
parameter to soap::fdimeread
and soap::fdimereadclose
callbacks. When an error occurred in this callback, the callback should return NULL and set soap::error
to an error code, e.g. using soap_receiver_fault
. The callback may return NULL and set soap::error
to SOAP_OK
when this specific DIME attachment should not to be streamed and the engine will simply skip it.size_t (*soap.fdimeread)(struct soap *soap, void *handle, char *buf, size_t len)
This callback is called by the engine to read a chunk of attachment data to transmit. The handle
parameter contains the handle returned by the soap::fdimereadopen
callback. The buf
parameter is the buffer of length len
into which a chunk of data should be written by the callback. The actual amount of data written into the buffer may be less than len
and this actual amount should be returned by the callback. A return value of zero indicates an error and soap::error
should be set. The __size
member variable of the attachment struct/class with data (e.g. xsd__base64Binary
or _xop__Include
with __ptr
, __size
, id
, type
and options
members) should be set by the application prior to the serialization of the message with attachments. The value of __size
indicates the total size of the attachment data to be transmitted. If the __size
member variable is zero and HTTP chunking is enabled (with SOAP_IO_CHUNK
), then DIME chunked transfers are activated by the engine, which is more flexible since the attachment data size does not need to be determined in advance. To use DIME chunked transfers, enable HTTP chunking with SOAP_IO_CHUNK
(also SOAP_IO_STORE
can be used, but this buffers the entire message in memory before transmission) and set the __size
member variable of the attachment struct/class to zero. When DIME attachment chunking is enabled, this callback should completely fill the buf
buffer with len
bytes unless the last data chunk is reached and fewer bytes are returned.void (*soap.fdimereadclose)(struct soap *soap, void *handle)
This callback is called by the engine to close the DIME attachment stream after reading. The handle
parameter contains the handle returned by the soap::fdimereadopen
callback.void *(*soap.fdimewriteopen)(struct soap *soap, const char *id, const char *type, const char *options)
Called by the to start receiving a streaming DIME attachment. This callback opens a stream to start writing the attachment data received. The actual data stream will be written in chunks using the soap::fdimewrite
callback until no more data is available and the soap::fdimewriteclose
callback is called to close the stream. The id
, type
and options
parameters are the id
, type
and options
of the attachment struct/class (e.g. xsd__base64Binary
or _xop__Include
with __ptr
, __size
, id
, type
and options
members), respectively. The callback should return a handle, which is passed to the soap::fdimewrite
and soap::fdimewriteclose
callbacks. The __ptr
member variable of the attachment struct/class is set by the engine to the value of this handle. The __size
member variable is set to the size of the attachment received. The maximum DIME attachment size received is limited by SOAP_MAXDIMESIZE
.int (*soap.fdimewrite)(struct soap *soap, void *handle, const char *buf, size_t len)
This callback is called by the engine to write a chunk of attachment data received. The handle
parameter contains the handle returned by the soap::fdimewriteopen
callback. The buf
parameter contains the data of length len
. Returns SOAP_OK
or a soap_status
(int) error code.void (*soap.fdimewriteclose)(struct soap *soap, void *handle)
This callback is called by the engine to close the DIME attachment stream after writing. The handle
parameter contains the handle returned by the soap::fdimewriteopen
callback.In addition, a void* soap::user
member is available to pass user-defined data to the callbacks. This way, you can set void* soap::user
to point to application data that the callbacks need such as a file name for example.
The following example illustrates the client-side initialization of an image attachment struct to stream a file into a DIME attachment:
The following example illustrates the streaming of a DIME attachment into a file by a client:
Message compression with SOAP_ENC_ZLIB
can be used with DIME to compress the entire message. However, compression requires buffering to determine the HTTP content length header, which cancels the benefits of streaming DIME. To avoid this, you should use chunked HTTP (with the output-mode SOAP_IO_CHUNK
flag) with compression and streaming DIME. At the server side, when you set SOAP_IO_CHUNK
before calling soap_serve
, the engine will automatically revert to buffering (SOAP_IO_STORE
flag is set). You can check this flag with (soap->omode & SOAP_IO) == SOAP_IO_CHUNK
to see if the client accepts chunking. More information about streaming chunked DIME can be found in Section Streaming chunked DIME .
options
member is a DIME-specific data structure, consisting of a 4 byte header containing the option type info (hi byte, lo byte), option string length (hi byte, lo byte), followed by a non-'\0' terminated string. The DIME handler recognizes one option at most.To send DIME attachments, the attachment sizes must be determined in advance to calculate HTTP message length required to stream DIME over HTTP. However, chunked DIME together with chunked HTTP can be used to omit this step. First set the SOAP_IO_CHUNK
flag. Then, to stream chunked DIME, set the __size
member of an attachment to zero and enable DIME chunking. The DIME soap::fdimeread
callback then fetches data in chunks and it is important to fill the entire buffer unless the end of the data has been reached and the last chunk is to be send. That is, soap::fdimeread
should return the value of the last len
parameter and fill the entire buffer buf
for all chunks except the last. For the last it returns 0.
You can also use the SOAP_IO_STORE
flag, but that cancels the benefits of streaming DIME.
The wsdl2h tool recognizes DIME attachments and produces an annotated header file. Both open and closed layouts are supported for transmitting DIME attachments. For closed formats, all DIME attachments must be referenced from the SOAP message, e.g. using hrefs with SOAP encoding and using the application-specific reference attribute included in the xsd__base64Binary
struct or class for document/literal messaging.
The soapcpp2 tool does not produce a WSDL with DIME extensions. DIME is an older binary format that has no WSDL protocol support, unlike MIME and MTOM.
MTOM (Message Transmission Optimization Mechanism) is a relatively new format for transmitting attachments with SOAP messages (see http://www.w3.org/TR/soap12-mtom). MTOM attachments are essentially MIME attachments with standardized mechanisms for cross referencing attachments from the SOAP body, which is absent in (plain) MIME attachments and optional with DIME attachments.
Unlike the name suggests, the speed by which attached data is transmitted is not increased compared to MIME, DIME, or even XML encoded base64 data, because the performance differences when using gSOAP will be small. The advantage of the format is the standardized attachment reference mechanism, which should improve interoperability.
The MTOM specification mandates SOAP 1.2 and the use of the XOP namespace. The XOP Include element xop:Include
is defined in the interface header file as a _xop__Include
struct or class, that is used to reference attachment(s) from the SOAP message body.
Because references from within the SOAP message body to attachments are mandatory with MTOM, the implementation of the serialization and deserialization of MTOM MIME attachments uses the extended binary type comparable to DIME support. This binary type is predefined in the import/xop.h
file:
The additional id
, type
, and option
members enable MTOM attachments for the data pointed to by __ptr
of size __size
. The process for sending and receiving MTOM XOP attachments is fully automated. The id
member references the attachment, typically a content id CID or UUID which can be obtained with soap_rand_uuid
. When set to NULL, a unique CID is automatically used. The type
field specifies the required MIME type of the binary data, and the optional options
member can be used to piggy-back descriptive text with an attachment. The order of the declaration of the members is significant.
You can import xop.h
in your interface header file to use the MTOM attachments, for example:
When an instance of x__myDataType
is serialized and either or both the id
and type
members are non-NULL, the data is transmitted as MTOM MIME attachment if the SOAP_ENC_MTOM
flag is set in the gSOAP's soap struct context:
Without this flag, the attachments will be transmitted in DIME format, which is not what we want. If your current clients and services are based on non-streaming DIME attachments using the SOAP body reference mechanism (thus, without using the soap_set_dime_attachment
function) or plain base64 binary XML data elements, it is very easy to adopt MTOM by renaming the binary types to xop__Include
and using the SOAP_ENC_MTOM
flag with the SOAP 1.2 namespace.
To enable MTOM on the fly to return MTOM attachments in the message sent:
To disable:
See also API documentation Module MIME attachment functions.
To generate multipartRelated bindings in the WSDL file indicating the use of MIME attachments, use:
This directive directive can be repeated for each attachment you want to associate with a method's request and response message. see also Section Directives .
For example:
The //gsoap x service method-mime-type:
directive indicates that this operation accepts text/xml
MIME attachments. See the SOAP-with-Attachment specification for the MIME types to use (for example, */*
is a wildcard). If the operation has more than one attachment, just repeat this directive for each attachment you want to bind to the operation.
To bind attachments only to the request message of an operation, use
Similarly, to bind attachments only to the response message of an operation, use:
The wsdl2h tool recognizes MIME attachments and produces an annotated header file.
You can repeat these directives for all multipartRelated MIME attachments you want to associate with the service operation input and output.
A receiver must be informed to recognize MTOM attachments by setting the SOAP_ENC_MTOM
flag of the soap
context. Otherwise, the regular MIME attachment mechanism (SwA) will be used to store attachments.
When using wsdl2h to build clients and/or services, you should use the typemap.dat
file included in the gSOAP source code package. The typemap.dat
file defines the XOP namespace and XML MIME namespaces as imported namespaces:
xop = <http://www.w3.org/2004/08/xop/include> xmime5 = <http://www.w3.org/2005/05/xmlmime> xmime4 = <http://www.w3.org/2004/11/xmlmime>
The wsdl2h tool uses the typemap.dat
file to convert WSDL into an interface header file. In this case we don't want the wsdl2h tool to read the XOP schema and translate it, since we have a pre-defined _xop__Include
element to handle XOP for MTOM. This _xop__Include
element is defined in xop.h
. Therefore, the bindings shown above will not translate the XOP and XML MIME schemas to code, but generates #import
statements instead in the generated interface header file:
The #import
statements are only added for those namespaces that are actually used.
Let's take a look at an example. The wsdl2h importer generates a header file with #import "xop.h"
from a WSDL that references XOP, for example:
Suppose the WSDL defines an operation:
After generating the stub functions with the soapcpp2 tool, we can invoke the stub at the client side with:
Note that the xop__Include.type
member must be set to transmit MTOM attachments, otherwise inline base64 XML will be sent.
At the server side, we show an example of an operation handler that just copies the input data to output:
The server must use the SOAP_ENC_MTOM
flag to initialize the soap
context to receive and send MTOM attachments.
Streaming MIME/MTOM is achieved with callback functions to fetch and store data during transmission. Three function callbacks for streaming MIME/MTOM output and three callbacks for streaming MIME/MTOM input are available.
void *(*soap.fmimereadopen)(struct soap *soap, void *handle, const char *id, const char *type, const char *description)
This callback is called by the engine to start sending a streaming MIME/MTOM attachment. This callback opens a stream to start reading the attachment data to send. The actual data stream will be read in chunks using the soap::fmimeread
callback until no more data is available and the soap::fmimereadclose
callback is called to close the stream. The handle
parameter contains the value of the __ptr
member variable of the attachment struct/class with data (e.g. xsd__base64Binary
or _xop__Include
with __ptr
, __size
, id
, type
and options
members), which should be a pointer to specific information such as a file descriptor or a pointer to a some application-specific data to be passed to this callback. Both the __ptr
and __size
members of the attachment struct/class should have been set by the application prior to the serialization of the message with attachments. If the __size
is zero and HTTP chunking is enabled (with SOAP_IO_CHUNK
), then chunked MIME/MTOM attachments are sent, see soap::fmimeread
. The id
, type
and options
parameters are the id
(an optional ID), type
(a MIME type) and options
(a descriptive string) of the attachment struct/class, respectively, of which at least one member should be non-NULL. The callback should return the handle
parameter value or another pointer value, which is passed as the new handle
parameter to soap::fmimeread
and soap::fmimereadclose
callbacks. When an error occurred in this callback, the callback should return NULL and set soap::error
to an error code, e.g. using soap_receiver_fault
. The callback may return NULL and set soap::error
to SOAP_OK
when this specific MIME/MTOM attachment should not to be streamed and the engine will simply skip it.size_t (*soap.fmimeread)(struct soap *soap, void *handle, char *buf, size_t len)
This callback is called by the engine to read a chunk of attachment data to transmit. The handle
parameter contains the handle returned by the soap::fmimereadopen
callback. The buf
parameter is the buffer of length len
into which a chunk of data should be written by the callback. The actual amount of data written into the buffer may be less than len
and this actual amount should be returned by the callback. A return value of zero indicates an error and soap::error
should be set. The __size
member variable of the attachment struct/class with data (e.g. xsd__base64Binary
or _xop__Include
with __ptr
, __size
, id
, type
and options
members) should be set by the application prior to the serialization of the message with attachments. The value of __size
indicates the total size of the attachment data to be transmitted. If the __size
member variable is zero and HTTP chunking is enabled (with SOAP_IO_CHUNK
), then MIME/MTOM chunked transfers are activated by the engine, which is more flexible since the attachment data size does not need to be determined in advance. To use MIME/MTOM chunked transfers, enable HTTP chunking with SOAP_IO_CHUNK
(also SOAP_IO_STORE
can be used, but this buffers the entire message in memory before transmission) and set the __size
member variable of the attachment struct/class to zero. When MIME/MTOM attachment chunking is enabled, this callback should completely fill the buf
buffer with len
bytes unless the last data chunk is reached and fewer bytes are returned.void (*soap.fmimereadclose)(struct soap *soap, void *handle)
This callback is called by the engine to close the MIME/MTOM attachment stream after reading. The handle
parameter contains the handle returned by the soap::fmimereadopen
callback.void *(*soap.fmimewriteopen)(struct soap *soap, void *handle, const char *id, const char *type, const char *description, enum soap_mime_encoding encoding)
Called by the to start receiving a streaming MIME/MTOM attachment. This callback opens a stream to start writing the attachment data received. The actual data stream will be written in chunks using the soap::fmimewrite
callback until no more data is available and the soap::fmimewriteclose
callback is called to close the stream. The id
, type
and options
parameters are the id
, type
and options
of the attachment struct/class (e.g. xsd__base64Binary
or _xop__Include
with __ptr
, __size
, id
, type
and options
members), respectively. The callback should return a handle, which is passed to the soap::fmimewrite
and soap::fmimewriteclose
callbacks. The __ptr
member variable of the attachment struct/class is set by the engine to the value of this handle. The __size
member variable is set to the size of the attachment received.int (*soap.fmimewrite)(struct soap *soap, void *handle, const char *buf, size_t len)
This callback is called by the engine to write a chunk of attachment data received. The handle
parameter contains the handle returned by the soap::fmimewriteopen
callback. The buf
parameter contains the data of length len
. Returns SOAP_OK
or a soap_status
(int) error code.void (*soap.fmimewriteclose)(struct soap *soap, void *handle)
This callback is called by the engine to close the MIME/MTOM attachment stream after writing. The handle
parameter contains the handle returned by the soap::fmimewriteopen
callback.In addition, a void* soap::user
member is available to pass user-defined data to the callbacks. This way, you can set void* soap::user
to point to application data that the callbacks need such as a file name for example.
The following example illustrates the client-side initialization of an image attachment struct to stream a file into a MTOM attachment without HTTP chunking (HTTP streaming chunked MTOM transfer is presented in Section Streaming chunked MIME/MTOM ):
The following example illustrates the streaming of a MIME/MTOM attachment into a file by a client:
Message compression with SOAP_ENC_ZLIB
can be used with MIME to compress the entire message. However, compression requires buffering to determine the HTTP content length header, which cancels the benefits of streaming MIME. To avoid this, you should use chunked HTTP (with the output-mode SOAP_IO_CHUNK
flag) with compression and streaming MIME. At the server side, when you set SOAP_IO_CHUNK
before calling soap_serve
, the engine will automatically revert to buffering (SOAP_IO_STORE
flag is set). You can check this flag with (soap->omode & SOAP_IO) == SOAP_IO_CHUNK
to see if the client accepts chunking. More information about streaming chunked MIME can be found in Section Streaming chunked MIME/MTOM ..
Note that the example above for mime_read
uses a handle that points to the open file FILE*
. The simple example above is not recommended when the platform imposes a limit on the number of open file descriptors. You can use the handle to pass along more information than just the file descriptor. So for example, when the number of open file descriptors is limited on your platform, you should let the handle point to a structure with file-related information. The C++ example below illustrates this:
To read the MTOM data for transmission:
When it is preferable or required to redirect inbound MIME/MTOM attachment streams based on SOAP message body content, where for example the names of the resources are listed in the SOAP message body, an alternative mechanism must be used to handle the attachments. This mechanism can be used at the client and server side.
Because the routing of the streams is accomplished with explicit function calls, this method should only be used when required and should not be considered optional. That is, when you enable this method, you must check for pending MIME/MTOM attachments and handle them appropriately. This is true even when you don't expect MIME/MTOM attachments in the payload, because the peer may trick you by sending attachments anyway and you should be prepared to accept or reject them.
The explicit MIME/MTOM streaming mechanism consists of three API functions:
void soap_post_check_mime_attachments(struct soap *soap)
This function enables post-processing of MIME/MTOM attachments received. This means that the presence of MIME/MTOM attachments must be explicitly checked by calling soap_check_mime_attachments
after the message was received. When this function returns nonzero (true), then the attachments can be retrieved by calling soap_recv_mime_attachment
repeatedly to retrieve each attachment until this function returns NULL. This function returns a pointer to a struct soap_multipart
attachment.int soap_check_mime_attachments(struct soap *soap)
This function checks the presence of a MIME/MTOM attachment after calling a service operation by returning nonzero when attachments are present. Returns nonzero if attachments are present. Requires soap_post_check_mime_attachments
.struct soap_multipart *soap_recv_mime_attachment(struct soap *soap, void *handle)
This function parses an attachment and invokes the MIME callbacks when set. The handle
parameter is passed to fmimewriteopen
. The handle may contain any data that is extracted from the SOAP message body to guide the redirection of the stream in the callbacks. Returns a struct with a char *ptr
member that contains the handle value returned by the fmimewriteopen
callback, and char *id
, char *type
, and char *description
member variables with the MIME id, type, and description info when present in the attachment.Example client in C:
The server-side service operations are implemented as usual, but with additional checks for MIME/MTOM attachments:
To send MIME/MTOM attachments, the attachment sizes must be determined in advance to calculate HTTP message length required to stream MIME/MTOM over HTTP. However, chunked MIME/MTOM together with chunked HTTP can be used to omit this step. First set the SOAP_IO_CHUNK
flag. Then, to stream chunked MIME/MTOM, set the __size
member of an attachment to zero and enable MIME/MTOM chunking. The MIME/MTOM soap::fmimeread
callback then fetches data in chunks and it is important to fill the entire buffer unless the end of the data has been reached and the last chunk is to be send. That is, soap::fmimeread
should return the value of the last len
parameter and fill the entire buffer buf
for all chunks except the last. For the last it returns 0.
UDP is a simple, unreliable datagram protocol: UDP sockets are connectionless. UDP address formats are identical to those used by TCP. In particular UDP provides a port identifier in addition to the normal Internet address format. The UDP port space is separate from the TCP port space (i.e. a UDP port may not be "connected" to a TCP port). In addition broadcast packets may be sent (assuming the underlying network supports this) by using a reserved "broadcast address"; this address is network interface dependent.
Client-side messages with SOAP-over-UDP endpoint URLs (soap.udp://...
) are automatically transmitted as datagrams. Server-side applications should set the SOAP_IO_UDP
mode flag to accept UDP requests, e.g. using soap_new1
, soap_init1
, or soap_set_mode
.
The maximum message length for datagram packets is restricted by the buffer size SOAP_BUFLEN
, which is 65536 by default, unless compiled with WITH_LEAN
to support small-scale embedded systems. For UDP transport SOAP_BUFLEN
must not exceed the maximum UDP packet size 65536 (the size of datagram messages is constrained by the UDP packet size 2^16=65536 as per UDP standard). You can use compression with SOAP_ENC_ZLIB
to reduce the message size, but note that compressed SOAP-over-UDP is a gSOAP-specific feature because it is not part of the SOAP-over-UDP specification.
The SOAP-over-UDP specification relies on WS-Addressing. The wsa.h
file in the import
directory defines the WS-Addressing elements for client and server applications.
The gSOAP implementation conforms to the SOAP-over-UDP requirements:
soap.udp://host:port/path
The following additional features are also available, but are not supported by the SOAP-over-UDP specification:
WITH_GZIP
).WITH_IPV6
)A SOAP-over-UDP application may use WS-Addressing to control message delivery as per SOAP-over-UDP specification.
The wsa.h
file in the import
directory defines the WS-Addressing elements. To include the WS-Addressing elements in the SOAP Header for messaging, a WS-Addressing capable SOAP_ENV__Header
struct should be defined in your header file by importing gsoap/import/wsa.h
or gsoap/import/wsa5.h
:
We also included a //gsoap wsa schema import:
directive in the wsa.h
file to enable the generation of WSDL specifications that import (instead of includes) the WS-Addressing elements. Note that the //gsoapopt w
directive (which adds option -w
to run soapcpp2 -w
) must not be present in your header file to enable WSDL generation.
One-way SOAP-over-UDP messages (see Section Asynchronous one-way message passing ) should be declared to include the wsa:MessageID
, wsa:To
, and wsa:Action
elements in the SOAP Header of the request message as follows:
Request-response SOAP-over-UDP messages should be declared to include the wsa:MessageID
, wsa:To
, wsa:Action
, and wsa:ReplyTo
elements in the SOAP Header of the request message, and the the wsa:MessageID
, wsa:To
, wsa:Action
, and wsa:RelatesTo
elements in the SOAP Header of the response message:
For the content requirements of these elements, please consult the SOAP-over-UDP specification and/or read the next sections explaining SOAP-over-UDP unicast, multicast, one-way, and request-response client and server applications.
This example assumes that the interface header file includes the SOAP Header with WS-Addressing elements, see The WS-Addressing plugin, and the ns__sendString
function discussed in Section Using WS-Addressing with SOAP-over-UDP.
This example is similar to the one-way unicast example discussed above, but uses a broadcast address and the SO_BROADCAST
socket option:
Please refer to the socket options for IPPROTO_IP
IP_MULTICAST_IF
to specify the default interface for multicast datagrams to be sent from. This is a struct in_addr
(in_addr_t
for sin6_scope_id
) interface value. Otherwise, the default interface set by the system administrator will be used (if any).
Please refer to the socket options for IPPROTO_IP
IP_MULTICAST_TTL
to limit the lifetime of the packet. Multicast datagrams are sent with a default value of 1, to prevent them to be forwarded beyond the local network. This parameter can be set between 1 to 255.
This example assumes that the interface header file for soapcpp2 includes the SOAP Header with WS-Addressing elements imported with #import "wsa.h"
and the ns__echoString
function discussed in Section Using WS-Addressing with SOAP-over-UDP .
This example is similar to the request-response unicast example discussed above, but uses a broadcast address and the SO_BROADCAST
socket option. Because we expect to receive multiple responses, we also need to use separate request-response messages to send one request and consume multiple responses. In this example we defined a bcastString
request and a bcastStringResponse
response message, which are essentially declared as one-way messages in the header file:
To obtain response one-way operations, use wsdl2h -b
option -b
.
The client code includes a loop to receive response messages until a timeout occurs:
Note that a server for the bcastString
does not need to use two-one way messages. Thus, multicast request-response message pattern can be declared and implemented as request-response operations at the server side.
The following example code illustrates a SOAP-over-UDP server for one-way sendString
and request-response echoString
messages. This example assumes that the interface header file includes the SOAP Header with WS-Addressing elements imported with #import "wsa.h"
and the ns__echoString
function discussed in Section Using WS-Addressing with SOAP-over-UDP .
The server binds to a host and port and accepts messages in a loop. Because UDP does not have the equivalent of an accept, the messages cannot be dispatched to threads. Instead the soap_serve
waits for a message and immediately accepts it. You can use a receive timeout value for soap::recv_timeout
to make soap_serve
non-blocking.
To obtain response one-way operations from a WSDL, use wsdl2h -b
option -b
. This produces additional one-way operations to support asynchronous handling of response messages in the same way requests are handled.
For UDP multicast support, follow the suggestions in Section SOAP-over-UDP server and change the initialization parts of the code to enable UDP multicast port binding by to telling the kernel which multicast groups you are interested in:
The following macros are defined in the API documentation Module WITH_MACRO compile-time flags. These macros are used to enable or disable features as specified below, by compiling source code files with compiler option -D
to set the macro:
define | result |
---|---|
SOAPDEFS_H | the header file to include, if different from soapdefs.h |
WITH_SOAPDEFS_H | includes the soapdefs.h file for custom settings, see Section Using the soapdefs.h header file |
WITH_COMPAT | removes dependency on C++ stream libraries and C++ exceptions |
WITH_LEAN | creates a small-footprint executable, see Section How to minimize application memory footprint |
WITH_LEANER | creates an even smaller footprint executable, see Section How to minimize application memory footprint |
WITH_FAST | use faster memory allocation when used with WITH_LEAN or WITH_LEANER |
WITH_COOKIES | enables HTTP cookies, see Sections Client-side cookie support and Server-side cookie support |
WITH_INSECURE_COOKIES | enables HTTP cookies and allows cookies with their Secure flag set to be sent over insecure channels |
WITH_IPV6 | enables IPv6 support |
WITH_IPV6_V6ONLY | enables IPv6 support with IPv6-only server option |
WITH_OPENSSL | enables OpenSSL, see Sections Secure clients with HTTPS and Secure Web services with HTTPS |
WITH_GNUTLS | enables GNUTLS, see Sections Secure clients with HTTPS and Secure Web services with HTTPS |
WITH_WOLFSSL | enables WolfSSL, see Sections Secure clients with HTTPS and Secure Web services with HTTPS |
WITH_GZIP | enables gzip and deflate compression, see Section Zlib compression |
WITH_ZLIB | enables deflate compression only, see Section Zlib compression |
WITH_NTLM | enables NTLM support |
WITH_C_LOCALE | force the use locale functions when available to ensure locale-independent number conversions |
WITH_NO_C_LOCALE | remove the use of locale functions to improve portability |
WITH_INCLUDE_XLOCALE_H | force the inclusion of <xlocale.h> to define locale_t and _l functions, to improve portability |
WITH_DOM | enable DOM parsing in the engine, required by the WS-Security plugin |
WITH_REPLACE_ILLEGAL_UTF8 | enable strict UTF-8, replaces UTF-8 content that is outside the allowed range with U+FFFD |
WITH_FASTCGI | enables FastCGI, see Section FastCGI |
WITH_NOIO | removes IO operations, to eliminate the use of BSD sockets, see Section How to remove the BSD socket library requirement |
WITH_NOIDREF | removes id and href/ref multi-reference data, more aggressive than using the SOAP_XML_TREE runtime flag |
WITH_NOHTTP | removes the HTTP stack to reduce code size |
WITH_NOZONE | disables and ignores the timezone in xsd:dateTime values |
WITH_NOEMPTYNAMESPACES | disables xmlns="" default empty namespaces from XML messages |
WITH_NOEMPTYSTRUCT | inserts a dummy member in empty structs to allow compilation |
WITH_NOGLOBAL | omit SOAP Header and Fault serialization code, prevents duplicate definitions with generated soapXYZLib code |
WITH_NONAMESPACES | disables dependence on global namespaces table, a table must be set explicitly with soap_set_namespaces see also Section XML namespaces and the namespace mapping table |
WITH_CDATA | retains the parsed CDATA sections in literal XML strings |
WITH_PURE_VIRTUAL | enables C++ abstract service classes with pure virtual methods, requires soapcpp2 option -i or -j |
WITH_DEFAULT_VIRTUAL | enables C++ base service classes with default virtual methods returning fault SOAP_NO_METHOD , requires soapcpp2 option -i or -j |
WITH_CASEINSENSITIVETAGS | enables case insensitive XML parsing |
WITH_SOCKET_CLOSE_ON_EXIT | prevents a server port from staying in listening mode after exit by internally setting fcntl(sock, F_SETFD, FD_CLOEXEC) |
WITH_TCPFIN | enables sending TCP FIN after sends when socket is ready to close |
#WITH_WITH_SSL_FULL_SHUTDOWN | enables second SSL_shutdown(ssl) call after close_notify before closing the socket (WITH_LEAN n/a) |
WITH_SELF_PIPE | enables a "self pipe" to enable the soap_close_connection function (gSOAP 2.8.71 or greater) |
The following subset of macros are defined in the API documentation Module SOAP_MACRO compile-time values. These macros are used to enable or disable features as specified below, by compiling source code files with compiler option -D
to set the macro:
define | result |
---|---|
SOAP_NOTHROW | expands to (std::nothrow) to prevent memory allocation exceptions (SOAP_EOM is used instead), this macro can be changed |
SOAP_BUFLEN | the length of the internal message buffer, impacts communications performance |
SOAP_HDRLEN | the maximum length of HTTP headers |
SOAP_TAGLEN | the maximum length of XML tags and URLs |
SOAP_TMPLEN | the maximum length of temporary string values, short strings and brief error messages |
SOAP_MAXALLOCSIZE | the maximum size of a block of memory that malloc can allocate |
SOAP_MAXARRAYSIZE | the maximum allocation threshold to pre-allocate SOAP arrays in memory |
SOAP_MAXDIMESIZE | the maximum DIME attachment size allowed to receive |
SOAP_MAXEINTR | maximum number of EINTR interrupts to ignore while polling a socket for pending activity |
SOAP_MAXINFLATESIZE | trusted inflated content size (1 MB by default) |
SOAP_MAXKEEPALIVE | maximum iterations in the soap_serve loop on HTTP keep-alive connections |
SOAP_MAXLENGTH | maximum string content length for strings not already constrained by XML schema validation constraints |
SOAP_MAXLEVEL | maximum XML nesting depth level permitted by the XML parser |
SOAP_MAXOCCURS | maximum number of array or container elements for containers that are not already constrained by XML schema validation constraints |
SOAP_MAXHTTPCHUNK | maximum HTTP chunk size receivable |
SOAP_MINDEFLATERATIO | trusted deflation ratio after SOAP_MAXINFLATESIZE is reached |
SOAP_PURE_VIRTUAL | set to = 0 when WITH_PURE_VIRTUAL is defined |
SOAP_SSL_RSA_BITS | length of the RSA key (2048 by default), ignored with OpenSSL v3 |
SOAP_UNKNOWN_CHAR | an 8 bit integer that represents a character that could not be converted to an ASCII char, i.e. when converting an XML Unicode character |
SOAP_UNKNOWN_UNICODE_CHAR | integer Unicode value representing a character that replaces an invalid Unicode code point |
SOAP_LONG_FORMAT | macro that represents the LONG64 printf %-format |
SOAP_ULONG_FORMAT | macro that represents the ULONG64 printf %-format |
SOAP_INVALID_SOCKET | portable invalid socket value, can also use soap_valid_socket(sock) to check if sock is valid |
gsoap/stdsoap2.cpp
, soapC.cpp
, soapClient.cpp
, soapServer.cpp
, and all application source code files that include gsoap/stdsoap2.h
or soapH.h
. If the macros are not consistently defined at compile time then the application will likely crash due to a mismatches in the declaration and use of the soap
context that is customized by these flags.The soapdefs.h
header file is included in gsoap/stdsoap2.h
when compiling with compile-time flag WITH_SOAPDEFS_H
:
c++ -D WITH_SOAPDEFS_H -c stdsoap2.cpp
The soapdefs.h
file allows users to include definitions and add includes without requiring changes to gsoap/stdsoap2.h
. You can also specify the header file name to include as a macro SOAPDEFS_H
to override the name soapdefs.h
:
c++ -D SOAPDEFS_H=mydefs.h -c stdsoap2.cpp
For example,
The following header file for soapcpp2 refers to std::ostream
without soapcpp2 throwing errors, by using extern
to declare class std::ostream
:
See also Section Transient data types , non-serializable data types.
The gSOAP engine state is stored in the soap
context that is initialized and controlled by various optional runtime flags. Most flags are applicable to either processing input or to processing output, but some are applicable to both input and output message and document processing.
Furthermore, these flags are divided into four categories: transport (IO), content encoding (ENC), XML parsing and generation (XML), and C/C++ usage (C).
The input-mode and output-mode flags for inbound (in) and outbound (out) message processing are:
mode flag | in/out | result |
---|---|---|
SOAP_IO_FLUSH | out | flush output immediately |
SOAP_IO_BUFFER | out | enable output buffering, the default mode for socket connections |
SOAP_IO_STORE | out | store the entire outbound message to calculate HTTP content length |
SOAP_IO_CHUNK | out | enable HTTP chunking |
SOAP_IO_LENGTH | out | used with two-phase serialization, first phase with this flag to calculate HTTP content length |
SOAP_IO_KEEPALIVE | in+out | keep socket connections alive, when supported by the HTTP peer |
SOAP_IO_UDP | in+out | use UDP (datagram) transport, maximum message length is SOAP_BUFLEN |
SOAP_ENC_PLAIN | in+out | use plain messages without parsing or emitting HTTP headers |
SOAP_ENC_XML | alias for SOAP_ENC_PLAIN | |
SOAP_ENC_DIME | out | use DIME encoding, automatic when DIME attachments are used |
SOAP_ENC_MIME | out | use MIME encoding instead of DIME, activated using soap_set_mime |
SOAP_ENC_MTOM | out | use MTOM XOP attachments instead of DIME and MIME |
SOAP_ENC_ZLIB | out | compress output with Zlib, using deflate or gzip format |
SOAP_ENC_SSL | in+out | use SSL/TLS, automatic when connecting "https:" endpoints |
SOAP_XML_INDENT | out | output indented XML and JSON |
SOAP_XML_CANONICAL | out | output canonical XML |
SOAP_XML_DEFAULTNS | out | output XML with default namespace bindings xmlns="..." |
SOAP_XML_IGNORENS | in | ignores XML namespaces in XML input |
SOAP_XML_STRICT | in | apply strict validation of XML input |
SOAP_XML_TREE | in+out | out: serialize data as XML trees (no multi-ref, duplicate data when necessary); in: ignore id attributes (do not resolve id-ref) |
SOAP_XML_GRAPH | out | serialize application data as an XML graph with multi-ref id/ref attributes |
SOAP_XML_NIL | out | serialize NULL data as xsi:nil attributed elements |
SOAP_XML_NOTYPE | out | disable xsi:type attributes |
SOAP_C_NOIOB | in | do not fault with SOAP_IOB |
SOAP_C_UTFSTRING | in+out | serialize 8-bit character strings "as is", meaning 8-bit strings have UTF-8 content |
SOAP_C_MBSTRING | in+out | enable multibyte character support for 8-bit character strings with wctomb and mbtowc using the current locale |
SOAP_C_NILSTRING | out | serialize empty strings as xsi:nil attributed elements |
All flags are independent and can be combined using a bitwise or (|
), except for SOAP_IO_FLUSH
, SOAP_IO_BUFFER
, SOAP_IO_STORE
, and SOAP_IO_CHUNK
which are enumerations and only one of these I/O flags can be used. Also the XML serialization flags SOAP_XML_TREE
and SOAP_XML_GRAPH
should not be mixed.
To allocate and initialize a soap
context with input and output mode flags:
To initialize a stack-allocated soap
context with input and output mode flags:
To set and clear mode flags use:
SOAP_XML_TREE
mode flag can be used to improve interoperability with SOAP implementations that are not fully SOAP 1.1/1.2 RPC encoding compliant with respect to processing id-href/ref attributes. However, tree serialization will duplicate data when this data is co-referenced. Cycles are detected and broken to avoid infinite serialization.In addition to the context mode flags, the following context flags can be used to set setsockopt
level SOL_SOCKET
options when sockets are created, though some options may not be applicable to your operating system:
context flag with setsockopt option | result |
---|---|
soap::connect_flags = SO_NOSIGPIPE | disables SIGPIPE |
soap::connect_flags = SO_DEBUG | turns on recording of debugging information in the underlying protocol modules |
soap::connect_flags = SO_BROADCAST | permits sending of broadcast messages, for example with UDP, when permitted |
soap::connect_flags = SO_LINGER | sets client-side linger time to the value of soap::linger_time |
soap::connect_flags = SO_DONTROUTE | enables routing bypass for outgoing messages |
soap::accept_flags = SO_NOSIGPIPE | disables SIGPIPE (check your OS, this is not portable) |
soap::accept_flags = SO_DEBUG | turns on recording of debugging information in the underlying protocol modules |
soap::accept_flags = SO_LINGER | sets server-side linger time to the value of soap::linger_time |
soap::accept_flags = SO_DONTROUTE | enables routing bypass for outgoing messages |
soap::bind_flags = SO_REUSEADDR | enables local address reuse immediately, use with caution |
soap::bind_flags = SO_REUSEPORT | enables duplicate address and port bindings |
For example, when soap::accept_flags
is set to (SO_NOSIGPIPE | SO_LINGER)
this disables SIGPIPE signals and set linger time value given by soap::linger_time
, which is zero by default.
The soap::socket_flags
context flag can be used to pass options to the <sys/socket.h>
send
, sendto
, recv
, and recvfrom
calls made by the engine, though some options may not be applicable to your operating system:
context flag with sent/recv flags | result |
---|---|
soap::socket_flags = MSG_NOSIGNAL | disables SIGPIPE |
soap::socket_flags = MSG_DONTROUTE | enables routing bypass for outgoing messages |
Furthermore, the setsockopt
level SOL_SOCKET
options SO_SNDBUF
and SO_RCVBUF
are set the engine when soap::sndbuf
and soap::rcvbuf
are set to a nonzero value. The default value is SOAP_BUFLEN
, which is the same size used by the internal buffer soap::buf
to send and receive messages. A zero value omits the internal setsockopt
call to set these options. Setting these values to zero activates auto-tuning with Linux 2.4 and greater.
The setsockopt
level SOL_SOCKET
option SO_KEEPALIVE
is set when keep-alive is enabled with context flag SOAP_IO_KEEPALIVE
or when soap::tcp_keep_alive
is nonzero. With soap::tcp_keep_alive
additional options can be specified with soap::tcp_keep_idle
, soap::tcp_keep_intvl
, and soap::tcp_keep_cnt
. For example:
For UDP messaging, use SOAP_IO_UDP
. See also Section SOAP/XML over UDP. The context flags that can be set at the client side for UDP messaging are soap::ipv4_multicast_if
, soap::ipv4_multicast_ttl
, and soap::ipv6_multicast_if
:
context flag | result |
---|---|
soap::ipv4_multicast_if | set setsockopt level IPPROTO_IP to IP_MULTICAST_IF with value soap::ipv4_multicast_if when non-NULL |
soap::ipv4_multicast_ttl | set setsockopt level IPPROTO_IP to IP_MULTICAST_TTL with value soap::ipv4_multicast_ttl when nonzero |
soap::ipv6_multicast_if | set sockaddr_in6::sin6_scope_id to soap::ipv6_multicast_if when nonzero, requires WITH_IPV6 |
Status error codes are integer values, which are returned by the gSOAP API functions. Error codes 200 and higher are reserved for HTTP error codes. HTTP error codes may be returned by a server to the client. HTTP codes 200, 400 and 500 are not returned when the HTTP body contains a response message, where HTTP codes 400 and 500 are reserved for SOAP Fault messages. The list of soap_status
error codes is listed below:
Error code | Description |
---|---|
SOAP_OK | No error (zero) |
SOAP_CLI_FAULT | The service returned a SOAP 1.1 client fault / SOAP 1.2 sender fault to the client |
SOAP_DATAENCODINGUNKNOWN | SOAP 1.2 DataEncodingUnknown fault |
SOAP_DEL_METHOD | An HTTP DELETE request was received by the service but the DELETE request callback soap::fdel is not implemented, see Section Function callbacks for customized I/O and HTTP handling |
SOAP_DIME_END | End of DIME attachments protocol error |
SOAP_DIME_ERROR | DIME formatting error or DIME attachment size exceeds SOAP_MAXDIMESIZE |
SOAP_DIME_HREF | DIME attachment has no href from SOAP body and no DIME callbacks were defined to save the attachment |
SOAP_DIME_MISMATCH | DIME version error |
SOAP_DUPLICATE_ID | XML element has duplicate id attribute value (applicable to SOAP multi-ref encoding and SOAP_XML_GRAPH serialization) |
SOAP_EMPTY | XML element or attribute is empty when a value is required |
SOAP_EOF | Unexpected end of file, no input, transmission interrupted or timed out, same as EOF |
SOAP_EOM | Out of memory |
SOAP_ERR | Same as EOF , but indicates an unspecified error |
SOAP_FAULT | The fault code to be returned by a service operation when calling soap_sender_fault (client is at fault) or soap_receiver_fault (server is at fault), clients receive the fault as SOAP_CLI_FAULT or SOAP_SVR_FAULT respectively |
SOAP_FD_EXCEEDED | Too many open sockets |
SOAP_FIXED | XML element or attribute value is fixed and the parsed value does not match the fixed value |
SOAP_GET_METHOD | An HTTP GET request was received by the service but the GET request callback soap::fget is not implemented, see Sections How to implement HTTP GET, PUT, and PATCH services and Function callbacks for customized I/O and HTTP handling |
SOAP_HREF | Reference to object in XML identified by its id attribute is incompatible with the object referred to by the ref or href attribute (applicable to SOAP multi-ref encoding and SOAP_XML_GRAPH serialization) |
SOAP_HTTP_ERROR | An unspecified HTTP error occurred |
SOAP_HTTP_METHOD | An HTTP request was received by the service that cannot be handled |
SOAP_IOB | SOAP array index out of bounds |
SOAP_LENGTH | XML element or attribute length validation error or SOAP_MAXLENGTH exceeded |
SOAP_LEVEL | XML nesting depth level exceeds SOAP_MAXLEVEL |
SOAP_MIME_END | End of MIME attachments protocol error |
SOAP_MIME_ERROR | MIME attachment parsing or processing error |
SOAP_MIME_HREF | MIME attachment has no href from SOAP body and no MIME callbacks were defined to save the attachment |
SOAP_MISSING_ID | An XML element with id attribute is missing that should match the element with href/ref attribute (applicable to SOAP multi-ref encoding and SOAP_XML_GRAPH serialization) |
SOAP_MOE | Memory overflow or memory corruption error (applicable in DEBUG mode only) |
SOAP_MUSTUNDERSTAND | An XML element is present with a mustUnderstand attribute which must be understood but is not deserialized |
SOAP_NAMESPACE | XML namespace name mismatch validation error |
SOAP_NO_DATA | No data in the HTTP body of the message received |
SOAP_NO_METHOD | The service request dispatcher did not find a matching service operation for a service request |
SOAP_NO_TAG | No XML element tag was found when one was expected |
SOAP_NTLM_ERROR | An NTLM authentication handshake error occurred |
SOAP_NULL | XML element has an xsi:nil attribute when the element is not nillable, causing a validation error |
SOAP_OCCURS | XML element minOccurs or maxOccurs validation error or SOAP_MAXOCCURS exceeded |
SOAP_PATCH_METHOD | An HTTP PATCH request was received by the service but the PATCH request callback soap::fpatch is not implemented, see Section Function callbacks for customized I/O and HTTP handling |
SOAP_PATTERN | XML element or attribute value pattern mismatch |
SOAP_PLUGIN_ERROR | Failed to register plugin |
SOAP_PROHIBITED | XML attribute is prohibited but present |
SOAP_PUT_METHOD | An HTTP PUT request was received by the service but the PUT request callback soap::fput is not implemented, see Section Function callbacks for customized I/O and HTTP handling |
SOAP_REQUIRED | XML attribute is required but not present |
SOAP_SSL_ERROR | An SSL error occurred |
SOAP_SVR_FAULT | The service returned a SOAP 1.1 server fault or SOAP 1.2 receiver fault to the client |
SOAP_SYNTAX_ERROR | An XML syntax error occurred while parsing the input |
SOAP_TAG_MISMATCH | XML element tag parsed does not match anything that is expected |
SOAP_TCP_ERROR | A TCP/IP connection error occurred |
SOAP_TYPE | XML element or attribute has a mismatching type or value that is causing a validation error |
SOAP_UDP_ERROR | A UDP/IP connection error occurred or the message too large to store in a UDP packet |
SOAP_USER_ERROR | soap::user not set to non-NULL |
SOAP_UTF_ERROR | An UTF-8 decoding error occurred |
SOAP_VERSIONMISMATCH | SOAP version mismatch or no SOAP message is received |
SOAP_ZLIB_ERROR | A zlib error occurred |
A status code of SOAP_OK
(zero) is returned by a gSOAP API function when the function call was successful, otherwise a non-zero error code is returned. The status error code is also stored in the current soap
context as soap::error
. For IO and socket-related errors, also the soap::errnum
variable is set to the errno
value of the system error for example when a SOAP_EOF
error occurred.
To display the error, use soap_print_fault(struct soap *soap, FILE *fd)
where the current value of soap::error
is used by the function to print the error to the specified fd
file. Alternatively, in C++ you can use soap_stream_fault(struct soap *soap, std::ostream& os)
to print the error on the specified os
output stream.
To display the location of an XML parsing and validation error, use soap_print_fault_location(struct soap *soap, FILE *fd)
or soap_stream_fault_location(struct soap *soap, std::ostream& os)
to print part of the XML with the error location marked in the XML output.
To save the error in a string buffer buf[0...len-1]
, use soap_sprint_fault(struct soap*, char *buf, size_t len)
, where buf
is populated with the fault message terminating with a \0
.
To determine the type of error that occurred, use:
soap_xml_error_check(soap_status e)
checks for XML parsing and validation errors, returns true if the specified error code is an XML error.soap_soap_error_check(soap_status e)
checks for SOAP protocol faults and errors, returns true if the specified error code is a SOAP protocol error.soap_http_error_check(soap_status e)
checks for HTTP protocol errors, returns true if the specified error code is an HTTP protocol error or a HTTP status code between 100 and 599 returned by an HTTP server.soap_tcp_error_check(soap_status e)
checks for TCP protocol errors, returns true if the specified error code is a TCP error, when true use soap::errnum
to retrieve the errno
value to determine the cause.soap_udp_error_check(soap_status e)
checks for UDP protocol errors, returns true if the specified error code is a UDP error, when true use soap::errnum
to retrieve the errno
value to determine the cause.soap_ssl_error_check(soap_status e)
checks for SSL/TLS protocol errors, returns true if the specified error code is a SSL/TLS error, when true use soap::errnum
to retrieve the errno
value to determine the cause.soap_zlib_error_check(soap_status e)
checks for zlib library errors, returns true if the specified error code is a zlib error.An HTTP status or error code is returned when the client fails to connect to an HTTP server or when the server responds with an error. A gSOAP server operation implementation may also return an HTTP error code instead of SOAP_OK
to respond to (an invalid) client request. The list of HTTP status codes is given below:
Code | Description |
---|---|
200 | OK (no error) |
201 | Created |
202 | Accepted |
203 | Non-Authoritative Information |
204 | No Content |
205 | Reset Content |
206 | Partial Content |
300 | Multiple Choices |
301 | Moved Permanently |
302 | Found |
303 | See Other |
304 | Not Modified |
305 | Use Proxy |
307 | Temporary Redirect |
400 | Bad Request |
401 | Unauthorized |
402 | Payment Required |
403 | Forbidden |
404 | Not Found |
405 | Method Not Allowed |
406 | Not Acceptable |
407 | Proxy Authentication Required |
408 | Request Time-out |
409 | Conflict |
410 | Gone |
411 | Length Required |
412 | Precondition Failed |
413 | Request Entity Too Large |
414 | Request-URI Too Large |
415 | Unsupported Media Type |
416 | Requested range not satisfiable |
417 | Expectation Failed |
500 | Internal Server Error |
501 | Not Implemented |
502 | Bad Gateway |
503 | Service Unavailable |
504 | Gateway Time-out |
505 | HTTP Version not supported |
HTTP status codes 200 to 299, 400 and 500 when received by a client are not flagged as an error, unless an HTTP message body is absent in the server's response to the client. Status codes 200, 201 and 202 are informative and should not be considered errors by the application logic.
Server-side implementations of service operations should return SOAP_OK
when the operation was successful, which returns a "200 OK" HTTP header with the XML response message. Server-side implementations of service operations in gSOAP may directly return an HTTP status code when an HTTP-related error should be returned. For example, return 404
returns "404 Not Found" to the client and the soap::error
variable is set to 404 at the client side.
To return a SOAP Fault from a server-side implementation of a service operation, use one of the following functions to populate the SOAP Fault message:
int soap_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
returns SOAP_FAULT
and populates a SOAP Fault message indicating a SOAP 1.1 client fault / SOAP 1.2 sender fault that is populated with the text faultstring
and an XML fragment faultdetail
or NULL when omitted.int soap_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
same as soap_sender_fault
with the addition of a QName-formatted string faultsubcode
.int soap_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetail)
returns SOAP_FAULT
and populates a SOAP Fault message indicating a SOAP 1.1 server fault / SOAP 1.2 receiver fault that is populated with the text faultstring
and an XML fragment faultdetail
or NULL when omitted.int soap_receiver_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
same as soap_receiver_fault
with the addition of a QName-formatted string faultsubcode
.A "receiver fault" indicates that the service could not handle the client request, but it can possibly recover from the error later, for example when resources are temporarily unavailable. A "sender fault" indicates that the client request is faulty and is rejected by the service.
See Section SOAP Fault processing for more details on how to use these functions.
Memory management with gSOAP is automatic. The engine context manages all memory allocated to serialize data and for temporary storage. Deserialized data is allocated in managed memory and data structures can be allocated in managed memory by the user when desired using soap_new_T
functions generated by soapcpp2 for each serializable type T
. All memory managed by a context is deallocated with soap_destroy
to destroy managed C++ objects and soap_end
to delete all other managed data. When a context is finalized or freed with soap_done(struct soap*)
and soap_free(struct soap*)
then managed memory is not released, so it is important to call the deallocation functions first. This was done to allow managed data to outlive the context, such as deserialized objects, but this is rarely if ever used because deleting the outlived data explicitly is prone to mistakes.
If you want to let deserialized data outlive a soap
context that you are about to free, then you can delegate management of the data to another soap
context with soap_delegate_deletion(struct soap *soap_from, struct soap *soap_to)
. This moves all deserialized and temporary data to the other soap
context soap_to
, which will delete its data and all the delegated data it is responsible for when you call soap_destroy
and soap_end
. This can be particularly useful for making client calls inside a server operation, i.e. a mixed server and client. The client call inside the server operation requires a new soap
context, e.g. copied from the server's with soap_copy
. Before destroying the client context with soap_free
, the data can be delegated to the server's context with soap_delegate_deletion
. See for example gsoap/samples/mashup/mashupserver.c
in the gSOAP source code package.
The functions related to memory management by the context are:
void * soap_malloc(struct soap *soap, size_t n)
return pointer to n
bytes of managed memory.char * soap_strdup(struct soap *soap, const char *s)
return pointer to duplicate of string s
in managed memory.char * soap_wstrdup(struct soap *soap, const wchar_t *s)
return pointer to duplicate of string s
in managed memory.T * soap_new_T(struct soap *soap)
allocates and default-initializes data of type T
, C++ only.T * soap_new_T(struct soap *soap, int n)
allocates and default-initializes and array of type T
, where n
= -1 allocates a single non-array value.T * soap_new_set_T(struct soap *soap, m1, ..., mn)
allocates a struct or class T
and initializes its members with the values m1
to mn
.T * soap_new_req_T(struct soap *soap, m1, ..., mn)
allocates a struct or class T
and initializes its required members with the values m1
to mn
, required means non-optional member as required by XML validation when this data is serialized in XML.void soap_destroy(struct soap *soap)
deletes all context-managed C++ objects and must be called before soap_end
.void soap_end(struct soap *soap)
deletes temporary data and all deserialized data except C++ objects, see above.void soap_free_temp(struct soap *soap)
deletes temporary data but leaves deserialized context-managed data intact.void soap_dealloc(struct soap *soap, void *p)
deallocates context-managed objects or data at location p
in memory.int soap_unlink(struct soap *soap, const void *p)
unlink object or data at location p
from management by the context, this object or data must be deallocated by the user.void soap_done(struct soap *soap)
finalizes the context but does not delete any managed objects or data.void soap_free(struct soap *soap)
finalizes and frees the context (contexts allocated with soap_new
or soap_copy
) but does not delete any managed objects or data.void soap_delegate_deletion(struct soap *soap_from, struct soap *soap_to)
moves all C++ objects, data, and temporary data managed by the soap_from
context to another context soap_to
, which manages the data until deleted with soap_destroy
and soap_end
.To help understand the differences between managed objects, managed data, and managed temporary data: temporary data is created by the engine to keep track of things, such as hash tables to keep pointer reference information for serialization and hash tables to keep XML id/href information for multi-reference object deserialization. Deserialized data is allocated by the context in managed memory when constructing data structures by deserializing XML and JSON messages. Data is stored in memory managed by the context using calls to soap_malloc
to allocate heap space with malloc
. A tiny bit more space is allocated to keep track of the allocations and to add a "canary" word to detect heap memory overflows. Heap memory overflows are detected when context-managed data is deallocated with soap_end
. C++ objects are allocated with new
instead of malloc
and are tracked as well. These objects are deallocated with soap_destroy
.
When the gSOAP application is compiled with -DDEBUG
using the compile-time flag DEBUG
, the engine reports memory leaks which are detected by soap_done
and soap_free
. To improve the accuracy of detection, no memory is actually freed until soap_done
or soap_free
are called to detect memory issues, so any calls to soap_destroy
and soap_end
are actually deferred to be executed when the context finalizes.
While memory management in gSOAP is automatic, it does not enforce its own memory management policy on the user. To move managed objects and data into unmanaged heap space, the soap_dup_T
deep copy functions generated by soapcpp2 -Ec
option -Ec
can be used. To delete deep copies, the soap_del_T
deep deletion functions generated by soapcpp2 -Ed
option -Ed
can be used. After copying the usual soap_destroy
and soap_end
functions remove the managed originals. See also Section Generating deep copy and deletion functions.
Furthermore, the memory allocation functions malloc
and new
used by the engine internally can be replaced with other allocators by defining SOAP_MALLOC
and SOAP_FREE
to replace malloc
and free
, and define SOAP_NEW
, SOAP_NEW_ARRAY
, SOAP_PLACEMENT_NEW
, and SOAP_DELETE
, SOAP_DELETE_ARRAY
to replace new
and delete
used by the engine to allocate managed memory. One can for example use a garbage collector with gSOAP by defining suitable replacements.
More information on memory management can be found in the C and C++ XML Data Bindings documentation that has separate sections on memory management in C and in C++.
When a class T
has a struct soap * T::soap
member declared in an interface header file for soapcpp2, then this member will be set to point to the current context by the deserializers and by the soap_default
method of the class and by the soap_default_T
and soap_new_T
functions for this class named T
. This simplifies memory management by class methods that allocate data associated with the class instance that must be managed by the context.
Consider for example the following class declaration:
Since the name
member is a character pointer to a string, where should we allocate this string? In most cases we will add a constructor that initially sets name
to NULL and a destructor that deletes name
when non-NULL, like so:
However, when instances of Class
are deserialized we have a problem with this approach because free(name)
deletes a managed string, which is managed by the context. Because the deserializer also sets the soap
member of this class, there is an easy solution to this problem:
This only frees name
if the soap
context pointer member is NULL, meaning that a managed string name
will be deleted as usual with the deserialized class using soap_destroy
and soap_end
.
The other methods are also made cognizant of the presence of a context:
Another approach is to use soap_unlink
to unlink data managed by the context and make all allocations explicitly:
The soap_unlink
call unlinks data and objects from managed memory. In this way soap_destroy
and soap_end
can be called later even when this class was deserialized.
To activate debugging and message logging compile the source code with compile-time flag DEBUG
. Or when using -lgsoap
or -lgsoap++
then reinstall gSOAP with ./configure --enable-debug
and make
.
When your gSOAP client or server applications run, they will log their activity in three separate files:
SENT.log
a concatenation of all messages sentRECV.log
a concatenation of all messages receivedTEST.log
a log of the engine's operationsYou can set macro DEBUG_STAMP
instead of DEBUG
to add time stamps to TEST.log
. This works on all operating systems supporting the gettimeofday
function.
When installing a CGI service application compiled with debugging enabled, the log files may sometimes not be created due to file access permission restrictions imposed on CGI applications. To get around this, create empty log files with universal write permissions. Be careful about the security implication of this.
You can actually test a CGI service application without deploying it on the Web. To do this, create the CGI service application and send it a request message using redirection as follows:
./service.cgi < ns.add.req.xml
this should display the service response on the terminal, where ns.add.req.xml
was generated by soapcpp2 or a modified version of this file. You can also use a SENT.log
file produced by a client application to redirect to the CGI service application. You can also use the gSOAP Test Messenger application to generate randomized messages to test your servers.
The file names of the log files and the logging activity can be controlled at the application level. This allows the creation of separate log files by separate services, clients, and threads. For example, the following service logs all messages (but no debug messages) in separate directories:
Likewise, messages can be logged for individual client-side service operation calls in a client application.
To log messages more efficiently, use the logging
plugin.
From the perspective of the C/C++ language, a few C/C++ language features are not supported by gSOAP and these features cannot be used in an interface header file for soapcpp2.
std::string
and std::wstring
and the containers std::deque
, std::list
, std::vector
, and std::set
, (see Section Containers ). Also std::shared_ptr
, std::unique_ptr
, and std::auto_ptr
are supported.begin()
, end()
, size()
, clear()
, and insert()
methods.#include
and #define
are moved to the generated soapStub.h
source code by soapcpp2. These directives are all placed at the top of that file, see The #include and #define directives. Use the #import
directive to import interface header files into other interface header files, see Section The #import directive .{
and }
. Also constructor initializers are not allowed. Class method implementations should be defined in a separate C++ source file.The following C/C++ data types require some attention to ensure they can be serialized:
void*
types: the void*
data type cannot be serialized unless run-time type information is associated with the pointer using a int __type
member in the struct or class that contains the void*
member. See Section Void pointer serialization for details.const
constant values such as const
members of a struct or class cannot be serialized except for const char*
and const wchar_t*
strings.Regular 8-bit strings cannot hold wide characters outside of the character range [1,255]. Of course you can use wide strings instead of 8-bit strings in the interface header file for soapcpp2. Alternatively, set the SOAP_C_UTFSTRING
mode flag to encode wide characters in 8-bit strings in UTF-8 format.
For example, the xsd:string
string schema type can be declared as a wide-character string and used subsequently:
To do so automatically with wsdl2h, edit typemap.dat
and add the line:
xsd__string = | wchar_t* | wchar_t*
or for C++:
xsd__string = | std::wstring | std::wstring*
Alternatively, 8-bit strings can hold UTF-8 formatted wide characters when the SOAP_C_UTFSTRING
flag is enabled, see Section Run-time flags . The application is responsible for filling regular strings with UTF-8 content.
Also the SOAP_C_MBSTRING
flag can be used to activate multibyte character support using the current locale. Multibyte support depends on the locale settings for dealing with extended natural language encodings.
Both 8-bit strings and wide-character strings can be used together within an application. For example, the following header file declaration introduces two string schema types:
Please consult the UTF-8 specification for details on the UTF-8 format when processing 8-bit strings with UTF-8 content. Note that the ASCII character set [1-127] is a subset of UTF-8. Therefore, with the SOAP_C_UTFSTRING
flag set, strings may hold ASCII character data and UTF-8 extensions.
See also C and C++ XML data bindings documentation for more details on using typemap.dat
for wsdl2h.
An interface header file for soapcpp2 may include //gsoap
directives to configure messaging protocols such as SOAP or REST, to associate SOAP Headers and Faults with messages, and to set properties of the Web service defined in the soapcpp2-generated WSDL and XSD files. Directives for soapcpp2 are specified as //gsoap
-comments that are processed by soapcpp2.
A service directive must start at a new line and is of the form:
where <prefix>
is the XML namespace prefix of a service binding. The <property>
and <value>
fields are one of the following:
property | value |
---|---|
name | name of the service, optionally followed by text describing the service |
namespace | URI of the WSDL targetNamespace |
documentation | text describing the service (see also the name property), multiple permitted |
doc | an alias for the documentation property |
style | document (default) SOAP messaging style or rpc for SOAP RPC |
encoding | literal (default), encoded for SOAP encoding, or a custom URI |
protocol | specifies SOAP or REST, see below |
port | URL of the service endpoint, usually an http or https address, to use in the WSDL definitions/service/port/address/@location |
location | an alias for the port property |
endpoint | an alias for the port property |
transport | URI declaration of the transport, usually http://schemas.xmlsoap.org/soap/http |
definitions | name of the WSDL definitions/@name |
type | name of the WSDL definitions/portType/@name (WSDL2.0 interface/@name) |
portType | an alias for the type property (portType follows SOAP 1.1 naming conventions) |
interface | an alias for the type property (interface follows SOAP 1.2 naming conventions) |
binding | name of the WSDL definitions/binding/@name |
portName | name of the WSDL definitions/service/port/@name |
executable | name of the "executable" to use in the WSDL definitions/service/port/address/@location |
The service name
and namespace
properties are required in order to generate a valid WSDL with soapcpp2. The other properties are optional.
The style
and encoding
property defaults are changed with soapcpp2 -e
option -e
to rpc
and encoded
.
You can override the port
endpoint URL at runtime in the auto-generated soap_call_prefix__func
service call (C/C++ client side) and in the C++ proxy class service call.
Protocol property values are:
protocol value | description |
---|---|
SOAP | SOAP transport, supporting both SOAP 1.1 and 1.2 |
SOAP1.1 | SOAP 1.1 transport (same as soapcpp2 -1 ) |
SOAP1.2 | SOAP 1.2 transport (same as soapcpp2 -2 ) |
SOAP-GET | one-way SOAP 1.1 or 1.2 with HTTP GET |
SOAP1.1-GET | one-way SOAP 1.1 with HTTP GET |
SOAP1.2-GET | one-way SOAP 1.2 with HTTP GET |
HTTP | an alias for POST (same as soapcpp2 -0 ) |
POST | non-SOAP REST protocol with HTTP POST |
GET | non-SOAP REST protocol with HTTP GET |
PUT | non-SOAP REST protocol with HTTP PUT |
DELETE | non-SOAP REST protocol with HTTP DELETE |
The protocol
property is SOAP
by default. The default is changed with soapcpp2 -1
option -1
to SOAP 1.1, soapcpp2 -2
option -2
to SOAP 1.2, and non-SOAP REST with soapcpp2 -0
option -0
The GET
protocols for SOAP and REST require that the service operations only use primitive types with their input parameters, because these parameters are encoded with the URL as URL query values.
To let directives take effect with service operations, you should bind the service operations to the WSDL namespace of a service by using the namespace prefix as part of the identifier name of the function that defines the service operation:
where prefix
can now be used to let directives take effect on this service operation.
Service properties are applicable to a service and to all of its operations. Service method directives are specifically applicable to a service operation.
A service method directive is of the form:
where <prefix>
is the XML namespace prefix of a service binding and <method>
is the unqualified name of a service operation. The <property>
and <value>
fields are one of the following:
method property | value |
---|---|
method-documentation | text describing the service operation |
method | same as above, shorthand form |
method-action | "" or URI SOAPAction HTTP header, or URL query string for REST protocols |
method-input-action | "" or URI SOAPAction HTTP header of service request messages |
method-output-action | "" or URI SOAPAction HTTP header of service response messages |
method-fault-action | "" or URI SOAPAction HTTP header of service fault messages |
method-header-part | member name of the SOAP_ENV__Header struct used in SOAP Header |
method-input-header-part | member name of the SOAP_ENV__Header struct used in SOAP Headers of requests |
method-output-header-part | member name of the SOAP_ENV__Header struct used in SOAP Headers of responses |
method-fault | type name of a struct or class member used in SOAP_ENV__Details struct |
method-mime-type | REST content type or SOAP MIME attachment content type(s) |
method-input-mime-type | REST content type or SOAP MIME attachment content type(s) of request message |
method-output-mime-type | REST content type or SOAP MIME attachment content type(s) of response message |
method-style | document or rpc |
method-encoding | literal , encoded , or a custom URI for encodingStyle of messages |
method-response-encoding | literal , encoded , or a custom URI for encodingStyle of response messages |
method-protocol | SOAP or REST, see Service directives |
The method-header-part
properties can be repeated for a service operation to declare multiple SOAP Header parts that the service operation requires. You can use method-input-header-part
and method-output-header-part
to differentiate between request and response messages.
The method-fault
property can be repeated for a service operation to declare multiple faults that the service operation may return.
The method-action
property serves two purposes:
?
) to complete the service endpoint URL or extends the endpoint URL with a local path (starts with a /
).Use method-input-action
and method-output-action
to differentiate the SOAPAction between SOAP request and response messages.
You can always override the port endpoint URL and action values at runtime in the auto-generated soap_call_prefix__func
service call (C/C++ client side) and in the auto-generated C++ proxy class service calls. A runtime NULL endpoint URL and/or action uses the defaults set by these directives.
The method-mime-type
property serves two purposes:
application/x-www-form-urlencoded
with REST POST and PUT protocols to send encoded form data automatically instead of XML. Only primitive type values can be transmitted with form data, such as numbers and strings, i.e. only types that are legal to use as attributes members.Use method-input-mime-type
and method-output-mime-type
to differentiate the attachment types between request and response messages.
A schema directive is of the form:
where <prefix>
is the XML namespace prefix of a schema. The <property>
and <value>
fields are one of the following:
property | value |
---|---|
namespace | URI of the XSD targetNamespace |
namespace2 | alternate URI pattern for the XSD namespace (i.e. URI is also accepted by the XML parser) |
import | URI of an imported namespace, as an alternative or in addition to namespace , adds xsd:import to the generated WSDL and XSD files |
form | unqualified (default) or qualified local element and attribute form defaults |
elementForm | unqualified (default) or qualified local element form default |
attributeForm | unqualified (default) or qualified local attribute form default |
typed | no (default) or yes for serializers to add xsi:type attributes to XML |
The namespace2
URI is a pattern with *
matching any sequence of characters and -
matching any character. This pattern instructs the XML parser and validator to also accept the URI pattern as a valid namespace for the specified <prefix>
.
The typed
property is no
by default and can be changed to yes
with soapcpp2 -t
option -t
.
A schema type directive is of the form:
where <prefix>
is the XML namespace prefix of a schema and <name>
is an unqualified name of a C/C++ type, and the optional <member>
is a class/struct members or enum constant.
You can describe a type with one of the following:
type property | value |
---|---|
type-documentation | text describing the schema type |
type | an alias for the type-documentation property |
For example, you can add a description to an enumeration:
This documented enumeration maps to a simpleType restriction of xsd:string
in the soapcpp2-generated schema:
The use of directives is best illustrated with an example. The example uses a hypothetical stock quote service and exchange rate service, actual services such as these are available for free on the web.
The quotex.h
example is a new Web Service created by combining two existing Web Services: a Stock Quote service and a Currency Exchange service.
The namespace prefix ns3
is used for the new quotex
Web Service with namespace URI urn:quotex
, service name quotex
, and endpoint port http://www.mydomain.com/quotex.cgi
.
Since the new Web Service invokes the ns1__getQuote
and ns2__getRate
service operations, the service namespaces and other details such as style and encoding of these methods are given by directives. After invoking the soapcpp2 tool on the quotex.h
header file:
soapcpp2 quotex.h
the WSDL of the new quotex
Web Service is saved as quotex.wsdl
. Since the service name, endpoint port, and namespace URI were provided in the header file, the generated WSDL file can be published together with the compiled Web Service installed as a CGI application.
The namespace mapping table for the quotex.cpp
Web Service implementation is saved as quotex.nsmap
. This file can be directly included in quotex.cpp
instead of specified by hand in the source of quotex.cpp
.
There are situations when certain types have to be used in an interface header file, but the types are not serializable and therefore have to be "invisible" to the soapcpp2 tool. These types are called transient.
This feature is useful when a library type is used in the interface header file as part of a struct or class, for example the FILE
type or std::ostream
that are clearly not serializable. If these types are introduced in an interface header file then these types must be declared transient. Otherwise, soapcpp2 will throw an error.
To declare a transient type use extern
. For example:
Even though FILE
is not a class, this declaration merely introduces the FILE
type name without specifying its details.
In C we can still use the class keyword, because no code is generated by soapcpp2 for this transient type.
We can then use this type elsewhere, for example:
Only the name
member is serialized of ns__record
.
Another example:
In other cases we do want to declare a type that soapcpp2 should copy into soapStub.h
for the application source code, but which should not be serializable. We can use extern
for this or put the declaration in [
and ]
brackets:
We can use [
and ]
brackets for parts of the code, for example to make several class members transient:
In this example, ns__myClass
has three transient members: b
, s
, and n
which will not be serialized. Member n
is transient because the type is declared within a transient block. Pointers, references, and arrays of transient types are transient. The single class method is encapsulated within [
and ]
to prevent soapcpp2 from creating serializers for the char[1024]
type.
We also use [
and ]
brackets to introduce a transient integer type transientInt
using a typedef. We cannot use extern
with typedef
because this construct is reserved for custom serializers.
Types declared volatile
in an interface header file are serializable but not copied by soapcpp2 to soapStub.h
. These types are typically library types that are included in the source code and should not be redefined in the application source code. We want to serialize these library types "as is" without redefining them.
Consider for example struct tm
, declared in time.h
. The structure may actually vary between platforms, but the tm
structure includes at least the following members as declared in the following interface header file for soapcpp2:
By declaring struct tm
volatile, soapcpp2 does not redefine it in the output source code. The #include <time.h>
is copied to the source code output. We can now serialize the tm
structure. The following example serializes the local time stored in a tm
structure to stdout:
It is also possible to serialize the tm
members as XML attributes by declaring the members as attributes with the @
qualifier, see Section How to declare XML attributes .
If you want to produce a schema file, say time.xsd
, that defines an XML schema and namespace for the tm
struct, you can add a typedef
declaration to the header file:
or simply use colon notation since we keep the tm
name:
We used the typedef name time__struct_tm
rather than time__tm
, because a schema name clash will occur for the first example above that has tm
already declared as serializable type in the schema of the generated WSDL. The second example with the colon notation avoids this altogether.
You can implement your own custom serializers for data types. A custom serializer is declared in an interface header file for soapcpp2 using the pair of keywords extern typedef
. For example:
Then provide the following functions for each extern typedef
declares type T
:
The function prototypes of these functions can be found in the soapcpp2-generated soapH.h
file.
For example, the serialization of MyData
can be done with the following code:
More information on custom serialization is available in the gSOAP source code package in the gsoap/custom
directory, where you can also find several custom serializers to use with your projects.
The following list of functions can be used for customized HTTP handling and I/O.
See also API documentation Module Callback functions.
To reset the callback functions to the internal functions of the engine, use soap_done
followed by soap_init
. This re-initializes the soap
context, removes all plugins, and resets function callbacks.
int (soap::fpost)(struct soap *soap, const char *endpoint, const char *host, int port, const char *path, const char *action, ULONG64 count)
This callback is called at the client side by the engine to send HTTP headers to the connected server. The parameters host
, port
, and path
were micro-parsed from the endpoint
prior to passing them to this callback. Parameter action
is the SOAP Action header. Parameter count
is the length of the HTTP body with the message or 0 when HTTP chunking is used. This callback sends the headers with POST by default, or when soap::status
== SOAP_POST
or soap::status
== SOAP_POST_FILE
. Alternatively, sends the HTTP headers with GET when soap::status
== SOAP_GET
, PATCH when soap::status
== SOAP_PATCH
, PUT when soap::status
== SOAP_PUT
, DELETE when soap::status
== SOAP_DEL
, CONNECT when soap::status
== SOAP_CONNECT
, HEAD when soap::status
== SOAP_HEAD
or OPTIONS when soap::status
== SOAP_OPTIONS
. Extra HTTP headers are added when soap::http_extra_header
is set to one or more header lines separated by CRLF. When redefining this callback, use function soap_send
to write the header contents. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap:fpost
is http_post
.
int (soap::fresponse)(struct soap *soap, int soap_error_code, ULONG64 count)
This callback is called at the server side by the engine to send the HTTP headers to the connected client. The parameter status
should be an HTTP status error code or SOAP_OK
(200 OK) or SOAP_HTML
or SOAP_FILE
. Using SOAP_HTML
sets the content-type header to text/html; charset=utf-8
. Using SOAP_FILE
sets the content-type header to the value of soap::http_content
. Extra HTTP headers are added when soap::http_extra_header
is set to one or more header lines separated by CRLF. When redefining this callback, use function soap_send
to write the header contents. Returns SOAP_OK
or a soap_status
error code. The built-in function assigned to soap::fresponse
is http_response
.
int (soap::fposthdr)(struct soap *soap, const char *key, const char *val)
This callback is called by soap::fpost
and soap::fresponse
to send an HTTP header with a key and an optional value. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fposthdr
is http_post_header
.
int (soap::fparse)(struct soap *soap)
This callback is called by the engine (as a client or server) to read and parse HTTP headers or MIME headers. When redefined, this function should at read or skip the entire HTTP header to reach the message body. Function soap_getline
is used by this callback to read each header line into an internal buffer soap::msgbuf
with soap_getline(soap, soap->msgbuf, sizeof(soap->msgbuf))
. Returns SOAP_OK
, or a gSOAP error code. The built-in function assigned to soap::fparse
is http_parse
.
int (soap::fparsehdr)(struct soap *soap, const char *key, const char *val)
This callback is called by soap::fparse
, consumes an HTTP header that is split in a key-value pair and updates the soap
context state accordingly. The context is updated with the HTTP header information received, but HTTP headers are not literally retained by the engine. Returns SOAP_OK
or SOAP_STOP
to prevent further reading of the HTTP body, or a soap_status
(int) error code. The built-in function assigned to soap::fparsehdr
is http_parse_header
.
int (soap::fget)(struct soap *soap)
This callback is called by the service dispatcher when an HTTP GET request is pending. Redefine this callback to respond to HTTP GET requests with content, see the http_get
HTTP GET plugin for more details. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fget
is the internal static function http_get
that returns the SOAP_GET_METHOD
error.
int (soap::fput)(struct soap *soap)
This callback is called by the service dispatcher when an HTTP PUT request is pending. Redefine this callback to respond to HTTP PUT requests, see the http_post
HTTP POST plugin for more details. Returns SOAP_OK
or a soap_status
error code. The built-in function assigned to soap::fput
is the internal static function http_put
that returns the SOAP_PUT_METHOD
error.
int (soap::fpatch)(struct soap *soap)
This callback is called by the service dispatcher when an HTTP PATCH request is pending. Redefine this callback to respond to HTTP PATCH requests, see the http_post
HTTP POST plugin for more details. Returns SOAP_OK
or a soap_status
error code. The built-in function assigned to soap::fpatch
is the internal static function http_patch
that returns the SOAP_PATCH_METHOD
error.
int (soap::fdel)(struct soap *soap)
This callback is called by the service dispatcher when an HTTP DELETE request is pending. Redefine this callback to respond to HTTP DELETE requests, see the http_post
HTTP POST plugin for more details. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fdel
is the internal static function http_del
that returns the SOAP_DEL_METHOD
error.
int (soap::fopt)(struct soap *soap)
Called by the service dispatcher when an HTTP OPTION request is pending. Redefine this callback to respond to HTTP OPTION requests, see the http_post
HTTP POST plugin for more details. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fopt
is the internal static function http_200
that returns HTTP 200 OK.
int (soap::fhead)(struct soap *soap)
This callback is called by the service dispatcher when an HTTP HEAD request is pending. Redefine this callback to respond to HTTP HEAD requests more specifically. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fhead
is the internal static function http_200
that returns HTTP 200 OK.
int (soap::fform)(struct soap *soap)
This callback is called by the HTTP FORM handler plugin to parse HTML forms received with HTTP POST and PUT requests, see the ;:http_form
HTTP FORM plugin for more details. The HTTP body with the form data should be parsed by this callback, otherwise HTTP keep-alive messages will end up out of sync as a result of the current position not being advanced to the end of the HTTP body. Returns SOAP_OK
or a soap_status
(int) error code. No built-in function is assigned to soap::fform
.
int (soap::fheader)(struct soap *soap)
This callback is called immediately after parsing a SOAP Header into the soap::header
structure. The SOAP Header structure soap::header
can be inspected by this function and verified or rejected before the rest of the message with the SOAP Body is consumed. Returns SOAP_OK
or a soap_status
(int) error code. No built-in function is assigned to soap::fheader
.
int (soap::fencoding)(struct soap *soap, const char *encoding)
This callback is called when an unrecognized XML encoding format is encountered in an XML PI. Supported encoding formats are latin (ASCII) and UTF-8. Other encoding formats can be rejected or supported by setting this callback. To reject the encoding, return a nonzero error code. To accept the encoding without further action, return SOAP_OK
. To decode the encoding, the input stream should be redictected through a decoder, for example by overriding the soap::frecv
callback with a specific handler to convert the encoding.
int (soap::fignore)(struct soap *soap, const char *tag)
This callback is called when an unrecognized XML element was encountered on the input that could be ignored depending on some specified logic. The tag
parameter is the offending XML element tag name string. The callback should return SOAP_OK
to ignore the element or return an soap_status
error code such as SOAP_TAG_MISMATCH
to trigger a validation error. This callback also overrides mustUnderstand
attributes on unrecognized SOAP Header elements that normally raise faults. It is strongly recommended that the callback returns SOAP_MUSTUNDERSTAND
when soap::mustUnderstand
!= 0
. Returns SOAP_OK
or a soap_status
(int) error code. No built-in function is assigned to soap::fignore
.
int (soap::fsvalidate)(struct soap *soap, const char *pattern, const char *string)
This callback is called to validate a string against an XML regex pattern. Patterns use XML schema regex syntax. This callback allows user-defined pattern validation that is normally disabled. Returns SOAP_OK
when the string matches the pattern or SOAP_TYPE
when the string does not match. No built-in function is assigned to soap::fsvalidate
.
int (soap::fwvalidate)(struct soap *soap, const char *pattern, const wchar_t *string)
This callback is called to validate a wide string against an XML regex pattern. Patterns use XML schema regex syntax. This callback allows user-defined pattern validation that is normally disabled. Returns SOAP_OK
when the string matches the pattern or SOAP_TYPE
when the string does not match. No built-in function is assigned to soap::fwvalidate
.
void (soap::fseterror)(struct soap *soap, const char **code, const char **string)
This callback is called by the engine when an error is raised to allow inspection or overriding of the fault code or fault string messages before the error is reported or transmitted. No built-in function is assigned to soap::fseterror
.
SOAP_SOCKET (soap::fopen)(struct soap *soap, const char *endpoint, const char *host, int port)
This callback is called by the engine at the client-side by soap_connect
or soap_connect_command
to open a TCP or UDP connection to a server specified at an endpoint. Parameters host
and port
are micro-parsed from endpoint
before being passed to soap::fopen
. Returns a valid socket or SOAP_INVALID_SOCKET
with a soap::error
set to a soap_status
(int) error code and soap::errnum
set to errno
of the connection failure. The built-in function assigned to soap::fopen
is tcp_connect
.
SOAP_SOCKET (soap::faccept)(struct soap *soap, SOAP_SOCKET s, struct sockaddr *a, int *n)
This callback is called by soap_accept
(or the C++ service class accept
method) to wait for and accept a socket connection requested by a client. Returns a valid socket or SOAP_INVALID_SOCKET
when an error occurred and sets soap::error
to a soap_status
value. The built-in function assigned to soap::faccept
is tcp_accept
.
int (soap::fclose)(struct soap *soap)
This callback is called by the engine at the client-side to close the current socket connection before a new socket connection is established. This callback may be called multiple times (e.g. by the engine and by plugins) to close the same socket soap::socket
. Checks internally if soap::socket
== SOAP_INVALID_SOCKET
before closing, which means that the socket was already closed. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fclose
is tcp_disconnect
.
int (soap::fresolve)(struct soap *soap, const char *addr, struct in_addr *inaddr)
This callback is called by soap_bind
(or the C++ service class bind
method) at the server-side and by soap_connect
or soap_connect_command
at the client-side with a host name
parameter to resolve to address inaddr
by address translation. When successful sets parameter inaddr
and returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fresolve
is tcp_gethost
.
int (soap::fconnect)(struct soap *soap, const char *endpoint, const char *host, int port)
This callback is called by the engine to optionally override client-side connecting. The parameters host
and port
were micro-parsed from the endpoint
prior to passing them to this callback. Returns SOAP_OK
or a soap_status
(int) error code. No built-in function is assigned to soap::fconnect
.
int (soap::fdisconnect)(struct soap *soap)
This callback is called by the engine soap_closesock
before the soap::fclose
callback is called to shutdown/disconnect. Returns SOAP_OK
or a soap_status
(int) error code. No built-in function is assigned to soap::fdisconnect
.
int (soap::fclosesocket)(struct soap *soap, SOAP_SOCKET sock)
This callback is called to close a socket by the engine. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fclosesocket
is tcp_closesocket
.
int (soap::fshutdownsocket)(struct soap *soap, SOAP_SOCKET sock, int how)
This callback is called to shut down a socket by the engine. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fshutdownsocket
is tcp_shutdownsocket
.
int (soap::fpoll)(struct soap *soap)
This callback is called by the engine to wait for activity on the soap::socket
or soap::master
socket using poll
or select
. Times out when soap::send_timeout
or soap::recv_timeout
are nonzero. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fpoll
is soap_poll
.
size_t (soap::frecv)(struct soap *soap, char *buf, size_t len)
This callback is called by the engine to receive (or read) data into a specified buffer buf
and len
. The source for the data to read by this callback is soap::is
when non-NULL, soap::socket
when valid, or soap::recvfd
. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::frecv
is frecv
.
int (soap::fsend)(struct soap *soap, const char *buf, size_t len)
This callback is called by the engine to send (or write) data specified by data
bytes of length len
. The sink for the data to be sent to is typically soap::socket
, soap::sendfd
or soap::os
. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fsend
is fsend
.
int (soap::fserveloop)(struct soap *soap)
This callback is called after each successful completion of a server operation in the server loop. Executes immediately after sending the response to a client and before the next keep-alive server loop iteration when enabled with SOAP_IO_KEEPALIVE
. This callback can be used to reclaim resources in the keep-alive server loop, for example managed memory can be reclaimed by calling soap_destroy
and soap_end
in that order and all deserialized and other dynamically-allocated data managed by the context will be deallocated. Returns SOAP_OK
or a soap_status
(int) error code. No built-in function is assigned to soap::fserveloop
.
void (soap::fmalloc)(struct soap *soap, size_t size)
This callback can be used to override memory allocation and management done by soap_malloc
in C. Memory allocated via this callback will not be managed and not be automatically released by the engine. Instead, the application using this callback should release allocated memory. All allocations done by soap_malloc
are replaced with a call to soap::fmalloc
. However, no other allocations, such as soap_new
and soap_new_T
for C++ classes T
are affected, because objects are allocated differently. This callback is therefore not useful for C++ applications. Returns a pointer to dynamically allocated memory or NULL on failure to allocate. No built-in function is assigned to soap::fmalloc
.
SOAP_MALLOC
and SOAP_FREE
instead.A void* soap::user
variable is available to pass user-defined data to the callbacks.
The following example uses I/O callbacks for customized serialization of data into a fixed-size buffer and deserialization back into a data structure:
A fixed-size buffer to store the outbound message sent is not flexible to handle large content. To store the message in an expanding buffer:
The following example illustrates customized I/O and HTTP header handling. The XML message is saved to a file to demonstrate I/O and HTTP callbacks. The client proxy then reads the file contents as the service response. To perform this trick, the service response has exactly the same structure as the request. This is declared by the struct ns__test
output parameter part of the service operation declaration. This struct resembles the service request (see the generated soapStub.h
file generated by soapcpp2 from the interface header file input).
The interface header file for soapcpp2 is:
The client program is:
SOAP 1.1/1.2 RPC encoding specifies that SOAP/XML elements may be ignored when present in a SOAP payload on the receiving side. However, document/literal style messaging validates XML messages and extra elements cannot just be ignored as such. With SOAP document/literal style it is recommended to enable the SOAP_XML_STRICT
mode flag. With SOAP RPC encoding, the engine ignores XML elements that are unknown by default, unless the XML attribute mustUnderstand="true"
is present in the XML element. It may be undesirable for elements to be ignored when the outcome of the omission is uncertain. The soap::fignore
callback can be set to a function that returns SOAP_OK
in case the element can be safely ignored, or SOAP_MUSTUNDERSTAND
to throw an exception, or to perform some application-specific action. For example, to throw an exception as soon as an unknown element is encountered on the input, use:
To selectively throw an exception when mustUnderstand="true"
SOAP Header element is encountered or when an unknown element is encountered except for element ns:xyz
, use:
Function soap_match_tag
compares two tags. The third parameter may be a pattern where *
is a wildcard and -
is a single character wildcard. So for example soap_match_tag(soap, tag, "ns:*")
will match any element in namespace ns
or when no namespace prefix is present in the XML message.
The callback can also be used to keep track of unknown elements in an internal data structure such as a list:
The client-side handling of HTTP 307 code "Temporary Redirect" and any of the redirect codes 301, 302, and 303 are not automated. Client application developers may want to consider adding a few lines of code to support redirects. It was decided not to automatically support redirects for the following reasons:
To implement client-side 307 redirect, add the following lines of code:
To implement HTTP GET request responses, define the soap::fget
callback function. The callback is required to produce a response to the request in textual form, such as a Web page or an XML or JSON response.
You can also use the http_get
plugin which essentially sets the soap::fget
callback and also keeps track of the number of HTTP GET and POST requests made at the server side.
The following example produces a Web page upon a HTTP GET request (e.g. from a browser):
The example below produces a WSDL file upon a HTTP GET with path ?wsdl
:
This example shows how one predetermined file is served. The gsoap/samples/webserver
demonstrates how files should be served in general, by adding the necessary logic to add media types to HTTP headers and to restrict the selection of files that should be served.
soap::path
values with a /
or a \
(soap::path
is a string with the path part of the URL, starting with a /
). If these are allowed, then we must at least check for ..
in the path to avoid request from snooping around in higher directories all the way up to the root.For a one-way SOAP/XML message, you can also return a SOAP/XML response:
where ns1__mySendMethodResponse
is a one-way message declared in a interface header file as:
The generated soapClient.cpp
includes the sending-side stub function.
The examples above are for HTTP GET. To implement HTTP PUT and PATCH set the soap::fput
and soap::fpatch
callback functions or use the http_post
plugin which is more capable.
To activate HTTP keep-alive, set the SOAP_IO_KEEPALIVE
flag for both input and output modes, see Section Run-time flags . For example
When a client or a service communicates with another client or service that supports keep alive, the soap::keep_alive
variable will be set to 1, otherwise it is reset to 0 indicating that the other party wants to close the connection. The connection maybe terminated on either end before the communication completed, for example when the server keep-alive connection has timed out. This may generate a "Broken Pipe" signal on Unix/Linux platforms. This signal can be caught with a signal handler:
where, for example:
Alternatively, broken pipes can be kept silent by setting:
This setting will not generate a SIGPIPE but read/write operations return SOAP_EOF
instead. Note that Windows does not support signals and lack the MSG_NOSIGNAL
flag.
If the client does not close the connection, the server will wait forever when no soap::recv_timeout
is specified, so be careful to set timeouts, See Section Timeout management for non-blocking operations. In addition, other clients will be denied service as long as a client keeps the connection to the server open. To prevent this from happening, the service should be multi-threaded such that each thread handles the client connection:
A client call will automatically attempt to re-establish a connection to a server when the server has terminated the connection for any reason. This way, a sequence of calls can be made to the server while keeping the connection open. Client stub functions poll the server to check if the connection is still open. When the connection was terminated by the server, the client will automatically reconnect.
A client may clear the SOAP_IO_KEEPALIVE
flag just before the last call to a server to let the server know it wants to close the connection after this last call. This will close the socket after the call and also informs the server to gracefully close the connection.
The client-side can also set the TCP keep-alive socket properties, using the soap::tcp_keep_alive
flag (set to 1 to enable), soap::tcp_keep_idle
to set the TCP_KEEPIDLE
value, soap::tcp_keep_intvl
to set the TCP_KEEPINTVL
value, and soap::tcp_keep_cnt
to set the TCP_KEEPCNT
value.
If a client is in the middle of soap call that might take a long time and the server goes away/down the caller does not get any feedback until the soap::recv_timeout
is reached. Enabling TCP keep alive on systems that support it allows for a faster connection teardown detection for applications that need it.
Outbound HTTP messages are not chunked unless the SOAP_IO_CHUNK
flag is enabled. Chunking may improve the speed of message sending with HTTP, because the message length does not need to be determined in advance for the HTTP content length header.
The entire outbound message can be stored in a buffer to determine the HTTP content length rather than the two-phase encoding used by gSOAP client-side stub functions and server-side skeleton functions generated by soapcpp2, which perform a separate pass over the data to determine the length of the outbound message. Setting the flag SOAP_IO_STORE
for the output mode will buffer the entire message. This may or may not speed up the transmission of messages, depending on the content, but may require significant storage space to hold large messages temporarily.
The following sections explain how to authenticate with HTTP bearer, basic, digest, and NTLM. Proxy authentication is also covered.
You could also use the WinInet plugin available in the gsoap/mod_gsoap
directory of the gSOAP source code package to simplify Internet access for gSOAP client applications and deal with encryption, proxies, and authentication, see the gSOAP WinInet plugin documentation.
The gSOAP CURL plugin can also be used to develop gSOAP client applications and CURL implements various HTTP authentication methods, see the gSOAP CURL plugin documentation.
HTTP bearer authentication is enabled at the client-side by setting the soap::bearer
string to the bearer token:
HTTP basic authentication is enabled at the client-side by setting the const char* soap::userid
and const char* soap::passwd
strings to a username and password, respectively. A server may request user authentication and denies access (HTTP 401 error) when the client tries to connect without HTTP authentication (or with the wrong authentication information).
Basic authentication should only be used over HTTPS, because the credentials are sent in the clear with HTTP. See Section The HTTP digest authentication plugin to use the HTTP digest plugin that is safe for authentication over HTTP.
Here is an example client code fragment to set the HTTP authentication username and password:
A client SOAP request will have the following HTTP header:
POST /XXX HTTP/1.1 Host: YYY User-Agent: gSOAP/2.8 Content-Type: text/xml; charset=utf-8 Content-Length: ZZZ Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=
A client must set the const char* soap::userid
and const char* soap::passwd
strings for each call that requires client authentication. The strings are reset after each successful or unsuccessful call.
When present, the WWW-Authenticate
HTTP header returned by the server with the authentication realm is stored in the the soap::authrealm
string. This is useful for clients to use this domain information to respond to authentication requests.
A stand-alone gSOAP Web Service application can enforce HTTP authentication on clients by checking the const char* soap::userid
and const char* soap::passwd
strings. These strings are set when a client request contains HTTP authentication headers. The strings should be checked in each service method (that requires authentication to execute).
Here is an example service method implementation that enforced client authentication:
When the authentication fails, the service response with a SOAP Fault message and a HTTP error code "401 Unauthorized". The HTTP error codes are described in Section Run-time error codes .
To return a non-SOAP error, use:
HTTP NTLM authentication is enabled at the client-side by installing libntlm
from http://www.nongnu.org/libntlm and compiling all project source codes with the compile-time flag WITH_NTLM
.
In your application code set the const char* soap::userid
and const char* soap::passwd
strings to a username and password. A server may request NTLM authentication and denies access (HTTP 401 authentication required or HTTP 407 HTTP proxy authentication required) when the client tries to connect without HTTP authentication (or with the wrong authentication information).
Here is an example client code fragment to set the NTLM authentication username and password:
The following NTLM handshake between the client C and server S is performed:
1: C --> S & POST ... & Content-Type: text/xml; charset=utf-8 2: C <-- S & 401 Unauthorized & WWW-Authenticate: NTLM 3: C --> S & GET ... & Authorization: NTLM <base64-encoded type-1-message> 4: C <-- S & 401 Unauthorized & WWW-Authenticate: NTLM <base64-encoded type-2-message> 5: C --> S & POST ... & Content-Type: text/xml; charset=utf-8 & Authorization: NTLM <base64-encoded type-3-message> 6: C <-- S & 200 OK
where stages 1 and 2 indicates a client attempting to connect without authorization information, which is the first method call in the code above. Stage 3 to 6 happen with the proper client authentication set with const char* soap::userid
and const char* soap::passwd
. Optionally, the const char* soap::authrealm
string should be set as well to indicate the domain accessed (this string is normally set when the server responds with HTTP 401 so the client receives this server domain information). NTLM authenticates connections, not requests. When the connection is kept alive, subsequent messages can be exchanged without re-authentication.
To avoid the overhead of the first rejected call, use:
When the authentication fails (stage 1 and 2), the service response with HTTP error code "401 Unauthorized" and soap::error
is set to HTTP code 401.
For HTTP 407 Proxy Authentication Required set the soap::proxy_userid
and soap::proxy_passwd
:
To avoid the overhead of the first rejected call, use:
HTTP proxy authentication (basic) is enabled at the client-side by setting the soap::proxy_userid
and soap::proxy_passwd
strings to a username and password, respectively. For example, a proxy server may request user authentication. Otherwise, access is denied by the proxy (HTTP 407 error). Example client code fragment to set proxy server, username, and password:
A client SOAP request will have the following HTTP header:
POST /XXX HTTP/1.1 Host: YYY User-Agent: gSOAP/2.8 Content-Type: text/xml; charset=utf-8 Content-Length: ZZZ Proxy-Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=
When X-Forwarded-For headers are returned by the proxy, the header can be accessed in the soap::proxy_from
string.
The CONNECT method is used for HTTP proxy authentication:
CONNECT server.example.com:80 HTTP/1.1
In some cases, you will notice that the Host HTTP header uses the CONNECT protocol:
CONNECT server.example.com:80 HTTP/1.1 Host: server.example.com:80
Here are some tips you can use to speed up gSOAP. The default settings are chosen to maximize portability and compatibility. The settings can be tweaked to optimize the performance as follows:
SOAP_BUFLEN
by changing the SOAP_BUFLEN
macro in gsoap/stdsoap2.h
. Use buffer size 2^18=262144 for example.SOAP_XML_TREE
flag to disable id-ref multi-ref object serialization. This boosts performance significantly and works with SOAP document/literal style (i.e. no id-ref graph serialization as required with SOAP encoding style). Do not use this for SOAP RPC encoded messaging.gsoap/stdsoap2.c
and gsoap/stdsoap2.cpp
and all other source codes with the compile time flag WITH_NOIDREF
to improve performance even better by permanently disabling id-ref multi-ref object serialization. Do not use this for SOAP RPC encoded messaging.The following settings are important to ensure that XML messaging is safe by defining reasonable XML message restrictions. Also messaging timeouts should be set as explained in Section Timeout management for non-blocking operations.
The XML parser is configured to restrict the XML nesting depth level to SOAP_MAXLEVEL
and restricts the repeated occurrence of elements that are deserialized into arrays and containers by SOAP_MAXOCCURS
. These macros can be changed, but you can also change the following context attributes at run-time, e.g. to enhance the safety for specific service and/or client operations:
soap::maxlevel
restricts the XML nesting depth level, where the default value is SOAP_MAXLEVEL
= 10000.soap::maxoccurs
restricts the number of repeated occurrences of elements that are deserialized into arrays and structs, where the default value is SOAP_MAXOCCURS
= 100000.soap::maxlength
restricts the length of strings deserialized from XML. A zero or negative value is unrestricted length. When restricted, the XML schema validation maxLength takes precedence over this length restriction. So setting a smaller value will not interfere with the XML validation rules. The default value is SOAP_MAXLENGTH
= 0. Note that string length is expressed in number of characters, not bytes. So UTF-8 encodings are not truncated.soap::recv_maxlength
the maximum length of messages received, 2GB by default.XML schema validation constraints are enforced with the SOAP_XML_STRICT
context flag. The schema maxLength validation constraint overrules the soap::maxlength
guard. The schema maxOccurs validation constraint does not overrule the soap::maxoccurs
guard, so arrays and containers are always restricted in length by this guard.
Other compile-time configuration settings are:
SOAP_MAXALLOCSIZE
the maximum size of a block of memory that malloc
can allocate.SOAP_MAXARRAYSIZE
the maximum allocation threshold to pre-allocate SOAP arrays in memory.SOAP_MAXDIMESIZE
the maximum DIME attachment size allowed to receive.SOAP_MAXEINTR
maximum number of EINTR interrupts to ignore while polling a socket for pending activity.Socket connect, accept, send, and receive timeout values can be set to manage socket communication timeouts. The soap::connect_timeout
, soap::accept_timeout
, soap::send_timeout
, soap::recv_timeout
and soap::transfer_timeout
context attributes of the current context soap
can be set to the appropriate user-defined socket send, receive, and accept timeout values. A positive value measures the timeout in seconds. A negative timeout value measures the timeout in microseconds (10^-6 sec).
The soap::connect_timeout
specifies the timeout for soap_call_ns__webmethod
stub function calls and for C++ proxy class calls.
The soap::accept_timeout
specifies the timeout for soap_accept
calls.
The soap::send_timeout
and soap::recv_timeout
specify the timeout for non-blocking socket I/O operations. This is the maximum delay on the socket operation permitted.
The soap::transfer_timeout
is new since 2.8.48 and limits the time a message send and a message receive operation can take. This value should be used in combination with soap::send_timeout
and soap::recv_timeout
for accurate timeout control. The soap::recv_maxlength
value when non-zero limits the length of messages that can be received in bytes in total in decompressed form (message length includes HTTP headers and HTTP chunk size fields). The value of soap::recv_maxlength
is 2GB by default.
Example:
This will result in a timeout if no data can be send in 10 seconds and no data is received within 10 seconds after initiating a send or receive operation over the socket. A value of zero disables timeout, for example:
When a timeout occurs in the send or receive operations, a SOAP_EOF
exception will be raised ("end of file or no input"). Negative timeout values measure timeouts in microseconds, for example:
connect()
. Therefore, setting soap::connect_timeout
for non-blocking soap_call_ns__webmethod
calls may not work under Linux.SOAP_MAXEINTR
in gsoap/stdsoap2.h
, which is 10 by default. Each EINTR may increase the blocking time by up to one second, up to SOAP_MAXEINTR
seconds total.To close a socket connection by force, you can use soap_force_closesock(soap)
, which closes the connection regardless if keep-alive is active. By contrast, soap_closesock(soap)
only closes the connection when keep-alive is not active.
To force-close a connection from another thread, compile stdsoap2.c or stdsoap2.cpp and your project source code with WITH_SELF_PIPE
to enable this feature. Use soap_close_connection(soap)
on the soap
context that must close. You can make this call from another thread and pass the soap
context to this function of the thread that must close connections.
Socket communications can be controlled with socket options and flags. The soap
context flags are:
soap::socket_flags
to set flags for the socket send
and recv
calls.soap::connect_flags
to set client-side setsockopt
SOL_SOCKET
socket options when connecting.soap::bind_flags
to set server-side setsockopt
SOL_SOCKET
socket options when executing soap_bind
.soap::bind_v6only
set to 1 to set setsockopt
IPPROTO_IPV6
IPV6_V6ONLY
.soap::accept_flags
to set flags to the setsockopt
socket options when executing soap_accept
.See the operating system manual pages of send
and recv
for soap::socket_flags
values and see the operating system manual pages of setsockopt
for soap::connect_flags
, soap::bind_flags
, and soap::accept_flags
(level SOL_SOCKET
) values. These SO_
socket option flags (see setsockopt
manual pages) can be bit-wise or-ed to set multiple socket options at once.
The client-side flag soap::connect_flags
= SO_LINGER
is supported with values l_onoff
= 1 and l_linger
= soap::linger_time
. The soap::linger_time
determines the wait time (the time resolution is system dependent, though according to some experts only zero and nonzero values matter). The linger option can be used to manage the number of connections that remain in TIME_WAIT
state at the server side.
For example, to disable SIGPIPE signals on Unix/Linux platforms use: soap::socket_flags
= MSG_NOSIGNAL
and/or soap::connect_flags
= SO_NOSIGPIPE
(i.e. client-side connect) depending on your platform.
Use soap::bind_flags
= SO_REUSEADDR
to enable server-side port reuse and local port sharing (but be aware of the possible security implications such as port hijacking).
Note that you have access to the soap->master
socket value returned by soap_bind
so you can set multiple socket options by calling setsockopt
as follows:
To override the host and port of the client connecting to a server, set soap::override_host
and soap::override_port
:
To enable SSL for stand-alone gSOAP Web servers, first install OpenSSL and use option the compile-time flag WITH_OPENSSL
to compile the sources with your C or C++ compiler.
c++ -DWITH_OPENSSL -o myprog myprog.cpp stdsoap2.cpp soapC.cpp soapServer.cpp -lssl -lcrypto
Or with GNUTLS use WITH_GNUTLS
and link with libgnutls and optionally libgcrypt and libgpg-error:
c++ -DWITH_GNUTLS -o myprog myprog.cpp stdsoap2.cpp soapC.cpp soapServer.cpp -lgnutls -lgcrypt -lgpg-error
Or with WolfSSL use WITH_WOLFSSL
:
c++ -DWITH_WOLFSSL -o myprog myprog.cpp stdsoap2.cpp soapC.cpp soapServer.cpp -lwolfssl
SSL support for stand-alone gSOAP Web services is enabled by calling soap_ssl_accept
to perform the SSL/TLS handshake after soap_accept
. In addition, a key file, a CA file (or path to certificates), DH file (if RSA is not used), and password need to be supplied. Instructions on how to do this can be found in the OpenSSL documentation http://www.openssl.org. See also Section SSL certificates and key files .
Let's take a look at an example SSL secure multi-threaded stand-alone SOAP Web Service:
The soap_ssl_server_context
function initializes the server-side SSL context. The server.pem
key file is the server's private key concatenated with its certificate. The cacert.pem
is used to authenticate clients and contains the client certificates. Alternatively a directory name can be specified. This directory is assumed to contain the certificates. The dh512.pem
file specifies that DH will be used for key agreement instead of RSA. A numeric value greater than 512 can be provided instead as a string constant (e.g. "512"
) to allow the engine to generate the DH parameters on the fly (this can take a while) rather than retrieving them from a file. The randfile entry can be used to seed the PRNG. The last entry enable server-side session caching to speed up TLS. A unique server name is required.
You can specify a cipher list to use with TLSv1.2 and below with SSL_CTX_set_cipher_list(soap->ctx, "...")
where soap->ctx
is the SSL context created by soap_ssl_server_context()
. Likewise, use SSL_CTX_set_ciphersuites(soap->ctx, "...")
to configure the available TLSv1.3 ciphersuites.
We refer to the OpenSSL documentation and manual pages of SSL_CTX_set_cipher_list
and SSL_CTX_set_ciphersuites
for details on the latest cipher lists and suites available to use.
The GNUTLS mutex lock setup is automatically performed in the engine, but only when POSIX threads are detected and available.
All OpenSSL versions prior to 1.1.0 require mutex locks to be explicitly set up in your code for multi-threaded applications by calling CRYPTO_thread_setup()
and CRYPTO_thread_cleanup()
as was shown in the code above. OpenSSL 1.1.0 and greater does not require these locks to be set up. If you are not sure which version of OpenSSL you may be using with your multi-threaded application, then set up the locks.
For Unix and Linux, make sure you have signal handlers set in your service and/or client applications to catch broken connections (SIGPIPE
):
where, for example:
By default, clients are not required to authenticate. To require client authentication use the SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION
flag:
This requires each client to authenticate with its certificate, in addition for the server to authenticate to the client.
Since gSOAP release version 2.8.20, SSL v3 is disabled. To enable SSL v3 together with TLS 1.0 and higher, use SOAP_SSLv3_TLSv1
with soap_ssl_server_context
. To use TLS 1.1 and 1.2 use SOAP_TLSv1_1 | SOAP_TLSv1_2
. To use TLS 1.2 only use SOAP_TLSv1_2
. To use SSL v3 only use SOAP_SSLv3
.
The cacert
file and capath
are optional. Either one can be specified when clients must run on non-trusted systems (capath
is not used with GNUTLS). We want to avoid storing trusted certificates in the default location on the file system when that is not secure. Therefore, a flat cacert.pem
file or directory can be specified to store trusted certificates.
The gSOAP package includes a cacerts.pem
file with the certificates of all certificate authorities. You can use this file to verify the authentication of servers that provide certificates issued by these CAs.
The cacert.pem
, client.pem
, and server.pem
files in the gSOAP package are examples of self-signed certificates. The client.pem
and server.pem
contain the client/server private key concatenated with the certificate. The keyfiles (client.pem
and server.pem
) are created by concatenating the private key PEM with the certificate PEM. The keyfile should not be shared with any party. With OpenSSL, you can encrypt the keyfiles with a password to offer some protection and the password is used in the client/server code to read the keyfile. GNUTLS does not support this feature and cannot encrypt or decrypt a keyfile.
WITH_OPENSSL
macro (or WITH_GNUTLS
or WITH_WOLFSSL
) is consistently defined to compile the sources gsoap/stdsoap2.cpp
, soapC.cpp
, soapClient.cpp
, soapServer.cpp
, and all application sources that include gsoap/stdsoap2.h
or soapH.h
. If the macros are not consistently used, the application will crash due to a mismatches in the declaration and access of the soap
context.See also API documentation Module SSL/TLS context and functions for more details on the SSL/TLS functions.
To utilize HTTPS at the client side, you need the OpenSSL library. Compile all the sources of your application with compile-time flag WITH_OPENSSL
c++ -DWITH_OPENSSL myclient.cpp stdsoap.cpp soapC.cpp soapClient.cpp -lssl -lcrypto
On some Unix systems you will need to link libxnet and libsocket:
c++ -DWITH_OPENSSL myclient.cpp stdsoap.cpp soapC.cpp soapClient.cpp -lxnet -lsocket -lnsl -lssl -lcrypto
Instead of the compile-time flag, you can add the following line to soapdefs.h
:
and compile with compile-time flag WITH_SOAPDEFS_H
to include soapdefs.h
in your project.
You can also use with GNUTLS instead of OpenSSL with WITH_GNUTLS
:
c++ -DWITH_GNUTLS myclient.cpp stdsoap.cpp soapC.cpp soapClient.cpp -lgnutls -lgcrypt -lgpg-error
Or WolfSSL with WITH_WOLFSSL
:
c++ -DWITH_WOLFSSL myclient.cpp stdsoap.cpp soapC.cpp soapClient.cpp -lwolfssl
A client program connects to a HTTPS server by simply using the prefix https:
instead of http:
in the endpoint URL of a service operation call to a Web Service to use encrypted transfers (if the service supports HTTPS).
To make the connction secure, you will need to specify the cacerts.pem
file with certificate authority certificates with which the server public key was signed:
By default, server authentication is enabled and the cacerts.pem
or capath
(not used with GNUTLS) must be set so that the CA certificates of the server(s) are accessible at run time. The cacerts.pem
file included in the gSOAP source code package contains the certificates of common CAs. This file must be supplied with the client, if server authentication is required. Alternatively, you can use the gsoap/plugin/cacerts.h
and gsoap/plugin/cacerts.c
code to embed CA certificates in your client code. Another alternatative is to use gsoap/samples/ssl/ssl_setup.c
or gsoap/samples/ssl/ssl_setup.cpp
for easy TLS/SSL setup. See the comments in these files.
You can specify a cipher list to use with TLSv1.2 and below with SSL_CTX_set_cipher_list(soap->ctx, "...")
where soap->ctx
is the SSL context created by soap_ssl_client_context()
. Likewise, use SSL_CTX_set_ciphersuites(soap->ctx, "...")
to configure the available TLSv1.3 ciphersuites.
Refer to the OpenSSL documentation and manual pages of SSL_CTX_set_cipher_list
and SSL_CTX_set_ciphersuites
for details on the latest cipher lists and suites available to use.
To make a connction with a server that requires the client to authenticate, you will need to specify the client-side key file and password of the keyfile:
Other client-side SSL options are SOAP_SSL_SNI_HOST_CHECK
to perform SNI only when the host address is a syntactically valid hostname and not an IP address (recommended for production systems), SOAP_SSL_SKIP_HOST_CHECK
to skip the host name verification check (for testing) and SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE
to allow connecting to a host with an expired certificate. For example:
For systems based on Microsoft windows, the WinInet module can be used instead, see mod_gsoap/gsoap_win/wininet
.
Since release version 2.8.20 SSL v3 is disabled. To enable SSL v3 together with TLS 1.0 and higher, use SOAP_SSLv3_TLSv1
with soap_ssl_server_context
. To use TLS 1.1 and 1.2 use SOAP_TLSv1_1 | SOAP_TLSv1_2
. To use TLS 1.2 only use SOAP_TLSv1_2
. To use SSL v3 only use SOAP_SSLv3
.
To disable server authentication for testing purposes, use the following:
This also assumes that the server does not require clients to authenticate (the keyfile is absent).
Make sure you have signal handlers set in your application to catch broken connections (SIGPIPE
):
where, for example:
WITH_OPENSSL
macro (or WITH_GNUTLS
or WITH_WOLFSSL
) is consistently defined to compile the sources, such as gsoap/stdsoap2.cpp
, soapC.cpp
, soapClient.cpp
, soapServer.cpp
, and all application sources that include gsoap/stdsoap2.h
or soapH.h
. If the macros are not consistently used, the application will crash due to a mismatches in the declaration and access of the soap
context. Alternatively, use library -lgsoapssl
or -lgsoapssl++
and compile everything else with WITH_OPENSSL
.soap
contexts In addition, the thread initialization code discussed in Section Secure Web services with HTTPS must be used to properly setup OpenSSL in a multi-threaded client application.See also API documentation Module SSL/TLS context and functions for more details on the SSL/TLS functions.
You can also use the WinInet interface to establish secure HTTPS connections on Windows machines, available in the gsoap/mod_gsoap
directory of the gSOAP source code package, see also Section The WinInet plugin. Or you can use the CURL plugin to use CURL to establish secure HTTPS connections, see Section The CURL plugin.
The fsslauth
callback function controls OpenSSL/GNUTLS authentication initialization:
int (soap::fsslauth)(struct soap *soap)
This callback is called to initialize the OpenSSL or GNUTLS context for HTTPS connections configured with the parameters passed to soap_ssl_client_context
and soap_ssl_server_context
. Returns SOAP_OK
or a soap_status
(int) error code. The built-in function assigned to soap::fsslauth
is ssl_auth_init
.The fsslverify
callback function controls OpenSSL peer certificate verification, via internally invoking SSL_CTX_set_verify
:
int (soap::fssverify)(int ok, X509_STORE_CTX *store
This callback is called by the engine to manage the verification of the certificate provided by a peer, such as the certificate provided by a server connected over HTTPS or to verify the certificate included with a WS-Security message. To require certificate verification of a server connected via HTTPS, use soap_ssl_client_context
with SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION
. To require certificate verification of a client connected to a server, use soap_ssl_server_context
with SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION
. The ok
parameter of this callback indicates whether the verification of the certificate in question passed (ok
== 1) or failed (ok
== 0) as determined by the OpenSSL library based on the soap_ssl_client_context
or soap_ssl_server_context
configuration. If the callback returns 1 then the handshake is continued and the connection maybe established. To return 1 when ok
== 0 requires resetting the error state with X509_STORE_CTX_set_error(store, X509_V_OK)
. If the callback returns 0 then the handshake is immediately terminated with "verification failed" and a verification failure alert is sent to the peer. The built-in function assigned to soap::fsslverify
is ssl_verify_callback
or when SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE
is used ssl_verify_callback_allow_expired_certificate
.The gSOAP package includes a cacerts.pem
file with the certificates of all certificate authorities. You can use this file to verify the authentication of servers that provide certificates issued by these CAs. Just set the cafile
parameter to the location of this file on your file system. Therefore, when you obtain a certificate signed by a trusted CA you can simply use the cacerts.pem
file to develop client applications that can verify the authenticity of your server.
Alternatively, you can use the gsoap/plugin/cacerts.h
and gsoap/plugin/cacerts.c
code to embed CA certificates in your client code.
For systems based on Microsoft windows, the WinInet module can be used instead, see the README.txt
located in the gSOAP source code package under mod_gsoap/gsoap_win/wininet
, see the gSOAP WinInet plugin documentation.
The other .pem
files in the gSOAP package are examples of self-signed certificates for testing purposes (cacert.pem
, client.pem
, server.pem
). The client.pem
and server.pem
contain the private key and certificate of the client or server, respectively. The keyfiles (client.pem
and server.pem
) are created by concatenating the private key PEM with the certificate PEM. The keyfile should not be shared with any party. With OpenSSL, you can encrypt the keyfiles with a password to offer some protection and the password is used in the client/server code to read the keyfile. GNUTLS does not support this feature and cannot encrypt or decrypt a keyfile.
You can also create your own self-signed certificates. There is more than one way to generate the necessary files for clients and servers. See http://www.openssl.org for information on OpenSSL and http://sial.org/howto/openssl/ca/ on how to setup and manage a local CA and http://sial.org/howto/openssl/self-signed on how to setup self-signed test certificates.
It is possible to convert IIS-generated certificates to PEM format with the openssl library and openssl command-line tool:
openssl x509 -in mycert.cer -inform DER -out mycert.pem -outform PEM
This converts the CRT-formatted mycert.cer to PEM-formatted mycert.pem.
Here is the simplest way to setup self-signed certificates. First you need to create a private Certificate Authority (CA). The CA is used in SSL to verify the authenticity of a given certificate. The CA acts as a trusted third party who has authenticated the user of the signed certificate as being who they say. The certificate is signed by the CA, and if the client trusts the CA, it will trust your certificate. For use within your organization, a private CA will probably serve your needs. However, if you intend use your certificates for a public service, you should probably obtain a certificate from a known CA. In addition to identification, your certificate is also used for encryption.
Creating certificates should be done through a CA to obtain signed certificates. But you can create your own certificates for testing purposes as follows.
/usr/local/ssl
by default and /System/Library/OpenSSL
on Mac OS X)gsoap/samples/ssl
directory to HOME/CAYou now have a self-signed CA root certificate cacert.pem and a server.pem (or client.pem) certificate in PEM format. The cacert.pem certificate is used in the cafile
parameter of the soap_ssl_client_context
(or soap_ssl_server_context
) at the client (or server) side to verify the authenticity of the peer. You can also provide a capath parameter to these trusted certificates. The server.pem (or client.pem) must be provided with the soap_ssl_server_context
at the server side (or soap_ssl_client_context
at the client side) together with the password you entered when generating the certificate using cert.sh to access the file. These certificates must be present to grant authentication requests by peers. In addition, the server.pem (and client.pem) include the host name of the machine on which the application runs (e.g. localhost), so you need to generate new certificates when migrating a server (or client).
Finally, you need to generate Diffie-Helmann (DH) parameters for the server if you wish to use DH instead of RSA. There are two options:
dhfile
parameter of soap_ssl_server_context
. The file should be generated beforehand. To do so with the OpenSSL command line tool, use: openssl dhparam -outform PEM -out dh.pem 512
File dh512.pem
is the output file and 512 is the number of bits used.
You can specify a hardware engine to enable hardware support for cryptographic acceleration. This can be done once in a server or client with the following statements:
The following table lists the names of the hardware and software engines:
engine | result |
---|---|
openssl | The default software engine for cryptographic operations |
openbsd_dev_crypto | OpenBSD supports kernel level cryptography |
cswift | CryptoSwift acceleration hardware |
chil | nCipher CHIL acceleration hardware |
atalla | Compaq Atalla acceleration hardware |
nuron | Nuron acceleration hardware |
ubsec | Broadcom uBSec acceleration hardware |
aep | Aep acceleration hardware |
sureware | SureWare acceleration hardware |
Set the full path to libssl.lib
and libcrypto.lib
under the MSVC++ "Projects" menu, then choose "Link": "Object/Modules". Please make sure libssl32.dll
and libeay32.dll
can be loaded by your applications, thus they must be installed properly on the target machine.
If you're using compilation settings such as /MTd
then link to the correct libeay32MTd.lib
and ssleay32MTd.lib
libraries.
Alternatively, you can use the WinInet interface for secure connections, available in the gsoap/mod_gsoap
directory of the gSOAP package, see also Section The WinInet plugin. Or you can use the CURL plugin to use CURL for secure connections, see Section The CURL plugin.
To enable deflate and gzip compression with Zlib, install Zlib from http://www.zlib.org if not already installed on your system. Compile gsoap/stdsoap2.cpp
(or gsoap/stdsoap2.c
) and all your sources that include gsoap/stdsoap2.h
or soapH.h
with compile-time flag WITH_GZIP
and link your code with the Zlib library, e.g. -lz
on Unix/Linux platforms.
The gzip compression is orthogonal to all transport encodings such as HTTP, SSL, DIME, and can be used with other transport layers. You can even save and load compressed XML data to/from files.
Two compression formats are supported by the engine: deflate and gzip. The gzip format is used by default. The gzip format has several benefits over deflate. Firstly, the engine automatically detects gzip compressed inbound messages, even without HTTP headers, by checking for the presence of a gzip header in the message content. Secondly, gzip includes a CRC32 checksum to ensure messages have been correctly received. Thirdly, gzip compressed content can be decompressed with other compression software, so you can decompress XML data saved by a gSOAP application in gzip format.
Gzip compression is enabled by compiling the sources with compile-time flag WITH_GZIP
. To transmit gzip compressed SOAP/XML data, set the output mode flags to SOAP_ENC_ZLIB
. For example:
This will send a compressed SOAP/XML request to a service, provided that Zlib is installed and linked with the application and the compile-time flag WITH_GZIP
option was used to compile the sources. Receiving compressed SOAP/XML over HTTP either in gzip or deflate formats is automatic. The SOAP_ENC_ZLIB
flag does not have to be set at the server side to accept compressed messages. Reading and receiving gzip compressed SOAP/XML without HTTP headers (e.g. with other transport protocols) is also automatic.
To control the level of compression for outbound messages, you can set the soap::z_level
to a value between 1 and 9, where 1 is the best speed and 9 is the best compression (default is 6). For example
To verify and monitor compression rates, you can use the values soap::z_ratio_in
and soap::z_ratio_out
. These two float values lie between 0.0 and 1.0 and express the ratio of the compressed message length over uncompressed message length.
Note: lower ratios mean higher compression rates.
Compressed transfers require buffering the entire output message to determine HTTP message length. This means that the SOAP_IO_STORE
flag is automatically set when the SOAP_ENC_ZLIB
flag is set to send compressed messages. The use of HTTP chunking significantly reduces memory usage and may speed up the transmission of compressed SOAP/XML messages. This is accomplished by setting the SOAP_IO_CHUNK
flag with SOAP_ENC_ZLIB
for the output mode. However, some Web servers do not accept HTTP chunked request messages (even when they return HTTP chunked messages!). Stand-alone gSOAP services always accept chunked request messages.
To restrict the compression to the deflate format only, compile the sources with the compile-time flag WITH_ZLIB
. This limits compression and decompression to the deflate format. Only plain and deflated messages can be exchanged, gzip is not supported with this option. Receiving gzip compressed content is automatic, even in the absence of HTTP headers. Receiving deflate compressed content is not automatic in the absence of HTTP headers and requires the flag SOAP_ENC_ZLIB
to be set for the input mode to decompress deflated data.
WITH_GZIP
and WITH_ZLIB
macros must be consistently defined to compile the sources, such as gsoap/stdsoap2.cpp
, soapC.cpp
, soapClient.cpp
, soapServer.cpp
, and all application sources that include gsoap/stdsoap2.h
or soapH.h
. If the macros are not consistently used, the application will crash due to a mismatches in the declaration and access of the soap
context.Client-side cookie support is optional. To enable cookie support, compile all sources with the compile-time flag WITH_COOKIES
, for example:
c++ -DWITH_COOKIES -o myclient stdsoap2.cpp soapC.cpp soapClient.cpp
or add the following line to stdsoap.h
:
Client-side cookie support is fully automatic. So just compile gsoap/stdsoap2.cpp
with the compile-time flag WITH_COOKIES
to enable cookie-based session control in your client.
A cookie store with cookies is kept and returned to the appropriate servers when the client connects to these servers. Cookies are not automatically saved to a file by a client. An example cookie file manager is included as an extras in the gSOAP package. You can remove all cookies from a soap
context by calling soap_free_cookies(soap)
, which also happens when you call soap_done(soap)
.
To avoid "cookie storms" caused by malicious servers that return an unreasonable amount of cookies, gSOAP clients/servers are limited to a cookie store size of soap::cookie_max
that the user can change, for example:
The cookie store is a linked list of soap_cookie
structures pointed to by soap::cookies
.
Since the cookie store is linked to the current soap
context, and each thread must use its own context, each thread also has its own cookie store.
This feature is not recommended to implement state in stand-alone servers. Cookies may require a fair amount of processing overhead and are not in fact needed to implement stateful services, which is typically performed with session IDs in XML/JSON messages or by passing the session IDs via the URL.
Server-side cookie support is optional. To enable cookie support, compile all sources with compile-time flag WITH_COOKIES
:
c++ -DWITH_COOKIES -o myserver ...
See API documentation Module HTTP cookie functions for the cookie API functions. See the HTTP sessions plugin for HTTP session management with cookies that is required for server-side session control. The WITH_COOKIES
flag is useless without server-side session management and control.
Here is an overview of the cookie API functions:
struct soap_cookie *soap_set_cookie(struct soap *soap, const char *name, const char *value, const char *domain, const char *path);
This function adds a cookie to the cookie store at the server side, if not already there, with the specified name
and value
. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
. Returns pointer to the cookie structure in the database or NULL when an error occurred.int soap_set_cookie_expire(struct soap *soap, const char *name, long expire, const char *domain, const char *path);
This function sets the expiration of the specified cookie name
in seconds and updates the cookie store at the server side. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
. Returns SOAP_OK
or a soap_status
error code.int soap_set_cookie_secure(struct soap *soap, const char *name, const char *domain, const char *path);
This function sets the "secure" property of the specified cookie name
and updates the cookie store at the server side. The "secure" property means that this cookie should be sent by the client to the server only when a secure HTTPS connection can be established. When HTTPS is enabled all cookies are sent by the server to the client with the "secure" property set, which means that this function is generally not needed unless the server is not HTTPS-enabled but cookies must be secure. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
. Returns SOAP_OK
or a soap_status
error code.int soap_set_cookie_session(struct soap *soap, const char *name, const char *domain, const char *path);
This function makes the specified cookie name
a "session cookie" and updates the cookie store at the server side by marking the cookie as a session cookie. This means that the cookie will be sent to clients that connect to the server. This function is not needed when a cookie is modified with soap_set_cookie_expire
, for example, because modified cookies are always sent back to the client. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
. Returns SOAP_OK
or a soap_status
error code.void soap_clr_cookie(struct soap *soap, const char *name, const char *domain, const char *path);
This function deletes the specified cookie name
from the cookie store at the server side. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
.int soap_clr_cookie_session(struct soap *soap, const char *name, const char *domain, const char *path);
This function clears the session property of the specified cookie name
and updates the cookie store at the server side. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
. Returns SOAP_OK
or a soap_status
error code.struct soap_cookie *soap_cookie(struct soap *soap, const char *name, const char *domain, const char *path);
This function returns the cookie structure of the specified cookie name
or NULL when not found by searching the cookie store at the server side. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
.const char *soap_cookie_value(struct soap *soap, const char *name, const char *domain, const char *path);
This function returns the cookie value of the specified cookie name
or NULL when not found by searching the cookie store at the server side. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
.time_t soap_cookie_expire(struct soap *soap, const char *name, const char *domain, const char *path);
This function returns the cookie expiration time time_t
of the specified cookie name
or -1 when not found by searching the cookie store at the server side. The domain
and path
parameters can be specified or can be NULL to use the current domain and path given by soap::cookie_domain
and soap::cookie_path
.int soap_getenv_cookies(struct soap *soap);
This function initializes the cookie store at the server side by reading the HTTP_COOKIE
environment variable. This provides a means for a CGI application to read cookies sent by a client. Returns SOAP_OK
or a soap_status
error code when the HTTP_COOKIE
variable was not found.void soap_free_cookies(struct soap *soap);
This function frees the cookie store and deletes all cookies.The following variables of the soap
context are used to define the current domain and path:
const char * soap::cookie_domain
should be set to the domain (host) of the serviceconst char * soap::cookie_path
may be set to the default path to the serviceint soap::cookie_max
maximum cookie database size (default=32)The soap::cookie_path
value is used to filter cookies intended for this service according to the path prefix rules outlined in RFC2109.
The following example server adopts cookies for session control:
When a client needs to connect to a Web Service through a proxy server, set the soap::proxy_host
string and soap::proxy_port
integer attributes of the current soap
context to the proxy's host name and port, respectively. For example:
The context attributes soap::proxy_host
and soap::proxy_port
keep their values through a sequence of service operation calls, so they only need to be set once.
When X-Forwarded-For headers are returned by the proxy, the header can be accessed in the soap::proxy_from
string.
See also Sections HTTP proxy basic authentication and HTTP proxy NTLM authentication.
To bind the client to a port before connect, set the soap::client_port
to a non-negative port number:
This port number is used only once and reset to -1 (disabled). Set it again for the next call.
To set a client interface address for the connection that is an IP address of the client:
This client interface address string is used only once and reset to NULL (disabled). Set it again for the next call. This feature is not available when compiling the code on windows.
To enable FastCGI support, install FastCGI and compile all soapcpp2-generated source code files and your application sources with the compile-time flag WITH_FASTCGI
or add:
to gsoap/stdsoap2.h
and recompile the project code.
gsoap/libgsoap*
libraries as these are not suitable for FastCGI. Compile gsoap/stdsoap2.c
(or gsoap/stdsoap2.cpp
) instead.The main program should contain a loop like this:
The SOAP_EOF
indicates that FastCGI no longer accepts requests. Otherwise, soap_serve
returns SOAP_OK
on successfully request-response messaging or returns an error code when a messaging or processing error occurred.
Managed Memory is released in the loop, unless the source code is compiled in DEBUG
mode.
To compile gSOAP applications intended for small memory devices, you may want to remove all non-essential features that consume precious code and data space. To do this, compile the source code files with the compile-time flag WITH_LEAN
(i.e. #define WITH_LEAN
) to remove many non-essential features. The features that will be disabled are:
SOAP_IO_CHUNK
, but chunked HTTP input is acceptedSOAP_ENC_ZLIB
, but compressed input is acceptedSOAP_XML_CANONICAL
soap::connect_timeout
, soap::send_timeout
, soap::recv_timeout
and soap::transfer_timeout
timeoutssoap::socket_flags
, soap::connect_flags
, soap::bind_flags
, soap::accept_flags
time_t
serialization with the xsd__dateTime
type, use a string to store the date and time instead.Use the compile-time flag WITH_LEANER
to make the executable even smaller by removing DIME and MIME attachment handling, LONG64
(64 bit) serialization, wchar_t*
serialization, and support for XML DOM operations. Note that DIME/MIME attachments are not essential to achieve SOAP/XML interoperability. DIME attachments are a convenient way to exchange non-text-based (i.e. binary) content, but are not required for basic SOAP/XML interoperability. Attachment requirements are predictable. That is, applications won't suddenly decide to use DIME or MIME instead of XML to exchange content.
It is safe to try to compile your application with the compile-time flag WITH_LEAN
, provided that your application does not rely on I/O timeouts. When no linkage error occurs in the compilation process, it is safe to assume that your application will run just fine.
The gsoap/stdsoap2.c
and gsoap/stdsoap2.cpp
libraries should be linked with a BSD socket library in the project build. To remove the need to link a socket library, you can compile gsoap/stdsoap2.c
(for C) and gsoap/stdsoap2.cpp
(for C++) with the the compile-time flag WITH_NOIO
macro set (i.e. #define WITH_NOIO
). This removes the dependency on the BSD socket API, IO streams, FILE
type, and errno
.
You should define callbacks to replace the missing socket stack. To do so, add to your code the following definitions:
These functions should provide a minimal input/output stack (soap::frecv
and soap::fsend
) to read/write XML and socket-like stack (the other functions) when developing client and server applications.
See Section Function callbacks for customized I/O and HTTP handling for more details on the use of these callbacks. All callback function pointers should be non-NULL, except soap::fpoll
.
You cannot use soap_print_fault
and soap_print_fault_location
to print error diagnostics. Instead, the value of soap::error
, which contains the gSOAP error code, can be used to determine the cause of a fault.
The wsdl2h tool can be used to import multiple WSDLs and schemas at once. The service definitions are combined in one header file to be parsed by soapcpp2. It is important to assign namespace prefixes to namespace URIs using the typemap.dat
file. Otherwise, wsdl2h will assign namespace prefixes ns1
, ns2
, and so on to the service operations and schema types. Thus, any change to a WSDL or schema may result in a new prefix assignment. For more details, please see Section Customizing XML data bindings with the typemap.dat file .
Another approach to combine multiple client and service applications into one executable is by using C++ namespaces to structurally separate the definitions. This is automated with wsdl2h -q name
option -q name
. Or by creating libraries in C for the client/server objects as explained in subsequent sections
Both approaches are demonstrated by examples in the gSOAP source code package, the gsoap/samples/link
(C only) and gsoap/samples/link++
(C++ with C++ namespaces) examples.
You can use a C++ code namespace of your choice in your interface header file to build a client or server in that C++ namespace. In this way, you can create multiple clients and servers that can be combined and linked together without conflicts, which is explained in more detail in the next section (which also shows an example combining two client libraries defined in two C++ code namespaces).
Use wsdl2h -q name
option -q name
to generate definitions in the C++ name
namespace. This option can also be used in combination with C++ proxy and server object generation, using soapcpp2 -j
option -j
or option -i
).
At most one namespace can be defined for the entire interface header file for soapcpp2. The C++ namespace must completely encapsulate the entire contents of the header file:
When compiling this interface header file with the soapcpp2 tool, all type definitions, the serializers for these types, and the stub and skeleton functions will be placed in this namespace. The XML namespace mapping table (saved in a .nsmap
file) will not be placed in the code namespace to allow it to be linked as a global object. You can use soapcpp2 -n
option -n
to create local XML namespace tables, see Section soapcpp2 options (but remember that you explicitly need to initialize the namespaces to point to a table at run time using soap_set_namespaces
). The generated files are prefixed with the code namespace name instead of the usual soap
file name prefix to enable multiple client/server codes to be build in the same project directory.
Because the SOAP Header and Fault serializers will also be placed in the namespace, they cannot be called from the gsoap/stdsoap2.cpp
run time library code and are therefore rendered unusable. Therefore, these serializers are not compiled at all (enforced with #define WITH_NOGLOBAL
). To add SOAP Header and Fault serializers, you must compile them separately as follows. First, create a new header file env.h
with the SOAP Header SOAP_ENV__Header
and SOAP Fault SOAP_ENV__Fault
structures, including SOAP_ENV__Detail
if this structure contains members that are serialized as fault details. You can leave this header file empty if you want to use the default SOAP Header and Fault. However, if SOAP Headers are required then you cannot leave the SOAP_ENV__Header
structure empty. For example, the WS-Addressing and WS-Security plugins require SOAP Headers which can be imported by adding #import "wsa5.h"
and #import "wsse.h"
, respectively to env.h
. Then compile this header file with:
soapcpp2 -penv env.h
The generated envC.cpp
file holds the SOAP Header and Fault serializers and you can link this file with your client and server applications.
The soapcpp2 tool produces soapClientLib.cpp
and soapServerLib.cpp
source code files that are specifically intended for building static or dynamic client and server libraries in C or C++. These files export the stub and skeleton functions, but keep all serialization code static, thus hidden to avoid link symbol conflicts when combining multiple clients and services into one executable. Note that it is far simpler to use the wsdl2h tool on multiple WSDL files to generate a header file that combines all service definitions. However, the approach presented in this section is useful when creating (dynamic) libraries for client and server objects, such as DLLs as described in Section How to create DLLs .
soap_new_T
, soap_default_T
, soap_write_T
, soap_read_T
, soap_put_T
, and soap_get_T
cannot be used any longer.Using C++ namespaces is a better alternative when building applications in C++ that combine multiple clients and services. To build multiple libraries, you can define a C++ namespace in your header file with soapcpp2 -qname
option -qname
, see Section How to build a client or server in a C++ code namespace for details.
For C, you can use soapcpp2 -c -p name
option -p name
to rename the generated soapClientLib.c
and soapServerLib.c
(and associated) files. The -p name
option specifies the file name
prefix to replace the soap
file name prefix.
The engine does not define SOAP Header and Fault serializers that the engine needs. We therefore add SOAP Header and Fault serializers, which are compiled separately as follows. First, create a new header file env.h
with the SOAP Header SOAP_ENV__Header
and SOAP Fault SOAP_ENV__Fault
structures, including SOAP_ENV__Detail
if this structure contains members that are serialized as fault details. You can leave this header file empty if you want to use the default SOAP Header and Fault. However, if SOAP Headers are required then you cannot leave the SOAP_ENV__Header
structure empty. For example, the WS-Addressing and WS-Security plugins require SOAP Headers which can be imported by adding #import "wsa5.h"
and #import "wsse.h"
, respectively to env.h
. Then compile this header file with:
soapcpp2 -penv env.h
The generated envC.cpp
file holds the SOAP Header and Fault serializers and you can create a (dynamic) library for it to link it with your client and server applications.
You should then compile the gsoap/stdsoap2.cpp
library with the compile-time WITH_NONAMESPACES
flag:
c++ -DWITH_NONAMESPACES -c stdsoap2.cpp
This omits the reference to the global namespaces table, which is nowhere to be defined since we will use XML namespaces for each client/service separately. Therefore, you must explicitly set the namespaces value of the soap
context in your code every time after initialization of the soap
context with the soap_set_namespaces(struct soap*, const struct Namespace*)
function.
For example, suppose we have two clients defined in header files client1.h
and client2.h
. We first generate the envH.h
file for the SOAP Header and Fault definitions:
soapcpp2 -c -penv env.h
Then we generate the code for client1 and client2:
soapcpp2 -c -n -pmyClient1 client1.h soapcpp2 -c -n -pmyClient2 client2.h
This generates myClient1ClientLib.c
and myClient2ClientLib.c
(among several other files). These two files should be compiled and linked with your application. The source code of your application should include the generated envH.h
, myClient1H.h
, myClient2.h
files and myClient1.nsmap
, myClient2.nsmap
files:
It is important to use soapcpp2 -n
option -n
, see Section soapcpp2 options, to rename the namespace tables so we can include them all without running into redefinitions.
As an example we will build a Delayed Stock Quote client library and a Currency Exchange Rate client library.
First, we create an empty header file env.h
, which may be empty or should contain SOAP Header and Fault definitions as explained in Section How to create client/server libraries, and compile it as follows:
soapcpp2 -penv env.h c++ -c envC.cpp
We also compile gsoap/stdsoap2.cpp
without namespaces:
c++ -c -DWITH_NONAMESPACES stdsoap2.cpp
If you do not use WITH_NONAMESPACES
then you will get an unresolved link error for the global namespaces
table. You can define a dummy table to avoid having to recompile gsoap/stdsoap2.cpp
.
Second, we create the Delayed Stock Quote header file specification, which may be obtained using the WSDL importer. If you want to use C++ namespaces then you need to manually add the namespace
declaration to the generated header file:
We then compile it as a library and we use option -n
to prefix the generated files and to rename the namespace table to avoid link conflicts later:
soapcpp2 -n quote.h c++ -c quoteClientLib.cpp
If you don't want to use a C++ code namespace, you should compile quote.h
"as is" with option -pquote
:
soapcpp2 -n -pquote quote.h c++ -c quoteClientLib.cpp
Third, we create the Currency Exchange Rate header file specification:
Similar to the Quote example above, we generate source code using option -n
to prefix the generated files and to rename the namespace table to avoid link conflicts:
soapcpp2 -n rate.h
Fourth, we use the generated source code libraries with the main program.
Compile and link this application with stdsoap2.o
, envC.o
, quoteServerProxy.o
, and rateServerProxy.o
.
Instead of the generated soap_call_webmethod
stub functions you can also use soapcpp2 -j
option -j
or option -i
to generate C++ proxy classes.
To compile server is very similar. For example, assume that we need to implement a calculator service and we want to create a library for it.
We generate code:
soapcpp2 -j -n calc.h
Here we used option -j
to generate a C++ service class calcCalcService.h
and calcCalcService.cpp
. The effect of the -n
option is that it creates local namespace tables and uses calc
to prefix the generated files.
The example above serves requests over stdin/out. Use the bind and accept calls to create a stand-alone server to service inbound requests over sockets, see Section How to create a stand-alone server .
This is the same example as above, but the clients are build in C.
We create a env.h
that contains the joint SOAP Header and SOAP Fault definitions. You may have to copy-paste these from the other header files. Then, compile it as follows:
soapcpp2 -c -penv env.h cc -c envC.c
We also compile gsoap/stdsoap2.c
without namespaces:
cc -c -DWITH_NONAMESPACES stdsoap2.c
Second, we create the Delayed Stock Quote header file specification, which may be obtained using the WSDL importer.
We compile it as a library and we use options -n
and -pquote
to prefix the generated files and to rename the namespace table to avoid link conflicts:
soapcpp2 -c -n -pquote quote.h cc -c quoteClientLib.c
Third, we create the Currency Exchange Rate header file specification:
We compile it as a library and we use options -n
and -prate
to prefix the generated files and to rename the namespace table to avoid link conflicts:
soapcpp2 -c -n -prate rate.h cc -c rateClientLib.c
The main program is:
Compile and link this application with stdsoap2.o
, envC.o
, quoteClientLib.o
, and rateClientLib.o
.
When combining multiple services into one application, you can run wsdl2h on multiple WSDLs to generate the single all-inclusive service definitions interface header file for soapcpp2. This header file is then processed with soapcpp2 to generate skeleton functions in C.
What if we generate multiple services, each from a WSDL separately, and want to deploy them on the same port? This requires listening to the same port and then chaining the service dispatches so that each service can serve a request.
First we create a env.h
that contains the joint SOAP Header and SOAP Fault definitions, for example by copy-pasting these from the other header files generated by wsdl2h. Or this file is empty if no specialized SOAP Headers and Faults are used. We compile it as follows:
soapcpp2 -c -penv env.h cc -c envC.c
We also compile gsoap/stdsoap2.c
without namespaces:
cc -c -DWITH_NONAMESPACES stdsoap2.c
Say for example that we have a service definition in quote.h
. We compile it as a library and we use options -n
and -pquote
to prefix the generated files and to rename the namespace table to avoid link conflicts:
soapcpp2 -c -n -pquote quote.h cc -c quoteClientLib.c
We do the same for a service definition in rate.h
:
soapcpp2 -c -n -prate rate.h cc -c rateClientLib.c
To serve both the quote and rate services on the same port, we chain the service dispatchers as follows:
This chaining can be arbitrarily deep. When the previous request fails with a SOAP_NO_METHOD
then next request dispatcher can be tried.
The server should also define the service operations:
However, the while loop iterates for each new connection that is established with soap_accept
and does not allow for HTTP keep-alive connections to persist. For our final improvement we want to support HTTP keep-alive connections that require looping over the service dispatches until the connection closes on either end, after which we resume the outer loop. The resulting code is very close to the soapcpp2-generated soap_serve
code and the serve
service class methods, with the addition of the chain of service dispatches in the loop body:
The engine does not define SOAP Header and Fault serializers that the engine needs when installed as a library. We therefore add SOAP Header and Fault serializers, which are compiled separately as follows. First, create a new header file env.h
with the SOAP Header SOAP_ENV__Header
and SOAP Fault SOAP_ENV__Fault
structures, including SOAP_ENV__Detail
if this structure contains members that are serialized as fault details. You can leave this header file empty if you want to use the default SOAP Header and Fault. However, if SOAP Headers are required then you cannot leave the SOAP_ENV__Header
structure empty. For example, the WS-Addressing and WS-Security plugins require SOAP Headers which can be imported by adding #import "wsa5.h"
and #import "wsse.h"
, respectively to env.h
. Then compile this header file with:
soapcpp2 -penv env.h
The generated envC.cpp
file holds the SOAP Header and Fault serializers. We can either create a separate envC.dll
DLL for this that all clients and service applications will use, or combine envC.cpp
with the stdsoap2.dll
we create, which we will explain further.
The next step is to create stdsoap2.dll
which consists of the file gsoap/stdsoap2.cpp
and envC.cpp
and optionally the plugins you want to use such as wsseapi.cpp
(we need to rename all .c
files to .cpp
files to avoid issues with MSVC++). This DLL contains all common functions needed for all other clients and servers based on gSOAP. Compile envC.cpp
and gsoap/stdsoap2.cpp
into stdsoap2.dll
using the compiler option /D
WITH_NONAMESPACES
and the MSVC Pre-Processor definitions SOAP_FMAC1=__declspec(dllexport)
, SOAP_FMAC3=__declspec(dllexport)
, and the SOAP_STD_EXPORTS
macro set as shown below from the MSVC command prompt:
C:> cl /c /I. /EHsc /DWITH_NONAMESPACES /DSOAP_FMAC1=__declspec(dllexport) /DSOAP_FMAC3=__declspec(dllexport) /DSOAP_STD_EXPORTS envC.cpp stdsoap2.cpp C:> link /LIBPATH ws2_32.lib /OUT:mygsoap.dll /DLL envC.obj stdsoap2.obj
Note: as of gSOAP 2.8.30 and later, the DLL export macros shown here are all set with one pre-processor definition SOAP_STD_EXPORTS
.
Alternatively, you can compile with /D
WITH_SOAPDEFS_H
and put the macro definitions in soapdefs.h
. This exports all functions which are preceded by the macro SOAP_FMAC1
in the soapcpp2.cpp
source file and macro SOAP_FMAC3
in the envC.cpp
source file.
Finally, note that the gSOAP source code package contains a lot of .c
source code files. Mixing C with C++ files is not recommended with Visual Studio and will lead to run-time errors when building DLLs. Therefore, always rename .c
source code files to .cpp
source code files when creating DLLs.
Compile the soapClientLib.cpp
and soapServerLib.cpp
sources as DLLs by using the MSVC Pre-Processor definitions SOAP_FMAC5=__declspec(dllexport)
and SOAP_CMAC=__declspec(dllexport)
, and by using the C++ compiler option /D
WITH_NONAMESPACES
. All of these macros are set as a shorthand with one pre-processor definition SOAP_STD_EXPORTS
(requires gSOAP 2.8.30 or later).
This DLL links to stdsoap2.dll
we created in Section Creating the base stdsoap2.dll.
To create multiple DLLs in the same project directory, you should use soapcpp2 -p name
option -p name
to rename the generated soapClientLib.cpp
and soapServerLib.cpp
(and associated) files. The -p name
option specifies a name
prefix to replace the soap
file name prefix. Another way is to use C++ namespaces with soapcpp2 -q name
option -q name
, if the interface header file input to soapcpp2 does not already declare a C++ namespace. A clean separation of libraries can also be achieved with C++ namespaces, see Section How to build a client or server in a C++ code namespace .
Unless you use the client proxy and server object classes (soapXYZProxy.h
and soapXYZService.h
), all client and server applications must explicitly set the namespaces value of the soap
context with:
where the namespaces[]
table should be defined in the client/server source. These tables are generated in the .nsmap
files. The tables are renamed for convenience using soapcpp2 -n
option -n
, see Section soapcpp2 options .
The #module
directive is used to build modules with soapcpp2. A library can be built from a module and linked with multiple Web services applications. The directive should appear at the top of the interface header file for soapcpp2 and has the following formats:
and
where the name
must be a unique short name for the module. The name is case insensitive and must not exceed 4 characters in length. The fullname
, when present, represents the full name of the module and is used to prefix the function names of the generated serializers replacing the usual soap
prefix. If absent, the short name is used to prefix the function names of the serializers.
The rest of the content of the interface header file includes type declarations and optionally the declarations of service operations and SOAP Headers and Faults that are universally used by SOAP services, when applicable. When the soapcpp2 tool processes the header file module, it will generate the source codes for a library. The Web services application that uses the library should use a header file that imports the module with the #import
directive. For example, the following defines a "test" module:
The module.h
data binding interface header file for soapcpp2 declares module-specific serializable types LONG64
, xsd__long
, char*
, and a struct ns__S
. The module name is "test", so the soapcpp2 tool produces a testC.cpp
file with the XML serializers for these types. The testC.cpp
data binding implementation source code can be separately compiled and linked with an application. If service operations are declared in the interface header file as function prototypes, we also get testClient.cpp
client stub functions and testServer.cpp
server skeleton functions.
There are some important considerations for modules and module imports:
With modules, the source code serializers for the types defined in the modules are generated with soapcpp2 separately. For example, assume that we have a module module.h
:
and a header file example.h
that uses it:
The module is compiled as follows:
soapcpp2 module1.h
This generates the files testStub.h
, testH.h
, and testC.cpp
with serializers for struct ns__S
but also for char*
and int
.
Running soapcpp2 on example.h
imports the module definitions, but does not generate serializers for struct ns__S
, char*
and int
since these are defined by module.h
:
soapcpp2 -CL example.h
An example client application that calls the client stub function:
We compile this example as follows:
c++ -o example example.cpp testC.cpp soapC.cpp soapClient.cpp stdsoap2.cpp
Modules may help to define a modular hierarchy of libraries with reusable serializable types.
Plugins offer a convenient extension mechanism for the gSOAP toolkit by extending the capabilities of its engine. When the plugin registers with the gSOAP engine, it has full access to the run-time settings and the engine's function callbacks. Upon registry, the plugin's local data is associated with the soap
context. By overriding the callbacks with the plugin's callbacks, the plugin extends or modifies the engine's capabilities. The local plugin data can be accessed through a lookup function, usually invoked within a callback function to access the plugin data. The registry and lookup functions are:
The soap_copy
function returns a new dynamically allocated soap
context that is a copy of another, such that no data is shared between the copy and the original context. The soap_copy
function invokes the copy functions of the registered plugins to copy the plugins' local data. The soap_done
and soap_free
functions de-registers all plugin.
The follow example overrides the send and receive callbacks to copy all messages that are sent and received to the terminal (stderr).
First, we write a header file plugin.h
to define the local plugin data structure(s) and we define a global name to identify the plugin:
Then, we write the plugin registry function and the callbacks:
It is the responsibility of the plugin to handle registry (init), copy, and deletion of the plugin data and reset callbacks.
The fdelete
callback of struct soap_plugin
must be set to de-register the plugin and let it delete its resources.
A plugin is copied along with its corresponding soap
context with the soap_copy
call. This function copies a soap
context and the chain of plugins. It is up to the plugin implementation to share the plugin data or not as follows:
fcopy()
callback is set by the plugin initialization, this callback will be called to allow the plugin to copy its local data upon a soap_copy
call. When soap_done
or soap_free
is called on this soap
context copy, the fdelete()
callback is called for deallocation and cleanup of the local data.fcopy()
callback is not set, then the plugin data will be shared (i.e. the data pointer points to the same address). The fdelete()
callback will not be called upon a soap_done
on a copy of the soap
context . The fdelete()
callback will be called for the original soap
context with which the plugin was registered.The example plugin should be used as follows:
To pass a void*
argument to the plugin's registry function use:
Additional documentation for the growing number of gSOAP plugins can be found at https://www.genivia.com/doc. A number of example plugins are included in the gSOAP source code package's gsoap/plugin
directory. Some of these plugins are discussed in the next sections.
See also API documentation Module Plugins and plugin registry functions .
The DOM API is not a plugin, but an extension that provides a DOM API as a separate source code file to compile and link with gSOAP applications to enabled the gSOAP DOM. XML DOM processing is optional, and enabled with wsdl2h -d
option -d
to generate DOM structures for xsd:anyType
, xsd:any
, and xsd:anyAttribute
schema components, which are enabled with #import "dom.h"
in an interface header file for soapcpp2. This imports gsoap/import/dom.h
. Then compile gsoap/dom.c
for C or gsoap/dom.cpp
for C++ with your application.
To use the DOM API with Web services, add #import "dom.h"
to the interface header file or use wsdl2h -d
option -d
:
This declares xsd__anyType
and xsd__anyAttribute
types.
A DOM element node is serialized with the xsd__anyType
serializable type. The underlying implementation type of xsd__anyType
is soap_dom_element
. One or more DOM attribute nodes are serialized with the xsd__anyAttribute
serializable type. The underlying implementation type of xsd__anyAttribute
is soap_dom_attribute
, which is a linked list.
To manipulate the DOM elements and attributes we use the DOM API functions documented in the gSOAP XML DOM API documentation.
The message logging
plugin can be used to selectively log inbound and outbound messages to a file or stream. It also keeps access statistics to log the total number of bytes sent and received.
To use the plugin, compile and link your application with logging.c
located in the gsoap/plugin
directory of the gSOAP package. To enable the plugin in your code, register the plugin and set the streams as follows:
If you use soap_copy
to copy the soap
context with the plugin, the plugin's state will be shared by the copy. The plugin is thread-safe, but does not use a lock to protect the internal statistics counters to ensure the speed of messaging is not compromised, meaning that you should not fully rely on the statistics to be 100% accurate for multi-threaded services.
See also logging
.
Server-side use of RESTful HTTP GET operations is supported with the http_get
HTTP GET plugin gsoap/plugin/httpget.c
.
The HTTP GET plugin allows your server to handle RESTful HTTP GET requests and at the same time still serve SOAP-based POST requests. The plugin provides support to client applications to issue HTTP GET operations to a server.
Note that HTTP GET requests can also be handled at the server side with the soap::fget
callback, see Section Function callbacks for customized I/O and HTTP handling . However, the HTTP GET plugin also keeps statistics on the number of successful POST and GET exchanges and failed operations (HTTP faults, SOAP Faults, etc.). It also keeps hit histograms accumulated for up to a year of running time.
To use the http_get
plugin, compile and link your application with httpget.c
located in the gsoap/plugin
directory of the gSOAP package. To enable the plugin in your code, register the plugin with your HTTP GET handler function as follows:
An HTTP GET handler can simply produce some HTML content, or any other type of content by sending data using soap_response
:
If you use soap_copy
to copy the soap
context with the plugin, the plugin's data will be shared by the copy. Therefore, the statistics are not 100% guaranteed to be accurate for multi-threaded services since race conditions on the counters may occur. Mutex is not used to update the counters to avoid introducing expensive synchronization points. If 100% server-side accuracy is required, add mutex at the points indicated in the httpget.c
code.
The client-side use of HTTP GET is provided by the soap_GET
operation. To receive a SOAP/XML (response) message ns:methodResponse
, use:
To receive any HTTP Body data into a buffer, use:
See also http_get
.
Server-side use of RESTful HTTP POST, PUT, PATCH, and DELETE operations are supported with the http_post
HTTP POST plugin gsoap/plugin/httppost.c
.
The http_post
HTTP POST plugin allows your server to handle RESTful HTTP POST requests and at the same time still serve SOAP-based POST requests. The plugin also provides support for client applications to issue HTTP POST operations to a server.
To simplify the server-side handling of POST requests, handlers can be associated with media types:
Note that *
and -
can be used as wildcards to match any text and any character, respectively. Media types may have optional parameters after ;
such as charset
and boundary
. These parameters can be matched by the media type patterns in the table. Patterns that are more specific must precede patterns that are less specific in the table. For example, "text/xml;*charset=utf-8*"
must precede "text/xml"
which must precede "text/*"
. Note that "text/xml"
also matches any parameters of the media type of the message reveived, such as "text/xml; charset=utf-8"
(only since gSOAP version 2.8.75).
The httppost plugin sets the soap::fput
, soap::fpatch
and soap::fdel
callbacks to serve HTTP PUT, PATCH and DELETE requests, respectively. The HTTP POST requests are handled differently, via soap_serve()
that invokes the soap::fform
callback that points to the handler. This callback is set by the httppost plugin upon receiving a HTTP POST request that matches the key in the table, i.e. "POST"
always matches and "application/json"
only matches when the HTTP Content-Type is application/json
. When a SOAPAction
header is present in the HTTP POST request, then the POST handler is never invoked to allow soap_serve()
to process the request.
A generic_POST_handler
, when specified with a "POST"
key entry in the table, takes priority over soap_serve()
if no SOAPAction
HTTP header is included in the message. This means that SOAP/XML messages without a SOAPAction
header will not be processed by soap_serve()
!
The handlers are functions that will be invoked when a POST request message matching media type is sent to the server.
An example image handler that checks the specific image type:
The above example returns HTTP OK. If content is supposed to be returned, as expected with POST, PATCH, and GET, use:
The soap_closesock()
call only closes the connection when it shoud not be kept alive. This function is also called automatically after the handler returns. The function returns the soap:error
value in order to pass an error code along the chain of calls. There is no harm in calling this function more than once.
HTTP POST requests with Content-Type application/json
are sent to the http_post_handler
, for example a currentTime server (this is based on gsoap/samples/xml-rpc-json/json-currentTimeServer.c):
soap_serve()
in a handler function. Instead, call soap_serve_request()
to process the XML request message and produce an XML response message for "two-way" SOAP/XML messaging with POST or PATCH. "Two-way" POST or PATCH and "one-way" SOAP/XML messaging with PUT and GET is possible and automatic when the interface header file for soapcpp2 declares protocols for XML REST for service operations ns__Method
:~~~{.cpp} //gsoap ns service method-protocol: Method1 POST int ns__Method1(...); //gsoap ns service method-protocol: Method2 PUT int ns__Method2(...); //gsoap ns service method-protocol: Method3 GET int ns__Method3(...);
The SOAP
method is "two-way" messaging with SOAP envelopes. The SOAP-PUT
and SOAP-GET
methods are "one-way" SOAP operations.
For client applications to use HTTP POST, use the soap_POST
operation:
Similarly, soap_PUT
, soap_PATCH
, and soap_DELETE
commands are provided for PUT, PATCH, and DELETE handling.
To support HTTP pipelining we use the http_pipe
plugin, which can be used at the server side to enable HTTP pipelining automatically, when registered. The plugin can also be used at the client side, though this is only necessary in scenarios that require the client to receive multiple messages without intermittend sends, i.e. multiple sends followed by multiple receives by the same thread using the same soap
context. However, clients should use multiple threads when HTTP pipelining is used to prevent blocking. See the gsoap/samples/async
folder in the gSOAP package for explanation and examples.
See also http_post
and http_pipe
.
The HTTP digest authentication plugin enables a more secure authentication scheme compared to basic authentication. HTTP basic authentication sends unencrypted userids and passwords over the net, while digest authentication does not exchange passwords but exchanges checksums of passwords (and other data such as nonces to avoid replay attacks). For more details, please see RFC 2617.
The HTTP digest authentication can be used next to the built-in basic authentication, or basic authentication can be rejected to tighten security. The server must have a database with userid's and passwords (in plain text form). The client, when challenged by the server, checks the authentication realm provided by the server and sets the userid and passwords for digest authentication. The client application can temporarily store the userid and password for a sequence of message exchanges with the server, which is faster than repeated authorization challenges and authentication responses.
At the client side, the plugin is registered and service invocations are checked for authorization challenges (HTTP error code 401). When the server challenges the client, the client should set the userid and password and retry the invocation. The client can determine the userid and password based on the authentication realm part of the server's challenge. The authentication information can be temporarily saved for multiple invocations.
Client-side example:
This code supports both basic and digest authentication.
The server can challenge a client using HTTP code 401. With the plugin, HTTP digest authentication challenges are send. Without the plugin, basic authentication challenges are send.
Each server method can implement authentication as desired and may enforce digest authentication or may also accept basic authentication responses. To verify digest authentication responses, the server should compute and compare the checksums using the plugin's http_da_verify_post
function for HTTP POST requests (and http_da_verify_get
for HTTP GET requests with the HTTP GET plugin) as follows:
For more details, including how to configure HTTP Digest authentication for proxies, see the HTTP digest authentication plugin documentation.
The plugin code is located in the gsoap/plugin
directory containing sessions.h
and sessions.c
.
For more details, see the HTTP sessions plugin documentation.
The plugin code is located in the gsoap/mod_gsoap/mod_gsoap-0.9/apache_20
directory.
For more details, see the Apache module documentation.
The plugin code is located in the gsoap/mod_gsoap/gsoap_win/isapi
directory.
For more details, see the ISAPI extension documentation.
The plugin code is located in the gsoap/plugin
directory containing curlapi.h
and curlapi.c
.
For more details, see the CURL plugin documentation.
The plugin code is located in the gsoap/mod_gsoap/gsoap_win/wininet
directory.
For more details, see the WinInet plugin documentation.
The plugin code is located in the gsoap/plugin
directory containing wsaapi.h
and wsaapi.c
(to be used in C and C++).
To enable WS-Addressing 2005 (and support for 8/2004), the service definitions header file for soapcpp2 should include the following imports:
This imports the SOAP header elements required by WS-Addressing.
For more details, see the WS-Addressing plugin documentation.
The plugin code is located in the gsoap/plugin
directory containing wsrmapi.h
and wsrmapi.c
(to be used in C and C++).
Also needed are threads.h
and threads.c
for multi-threading and locking support.
To enable WS-ReliableMessaging, the service definitions header file for soapcpp2 should include the following imports:
This imports the SOAP header elements required by WS-ReliableMessaging.
For more details, see the WS-ReliableMessaging plugin documentation.
The plugin code is located in the gsoap/plugin
directory containing wsseapi.h
and wsseapi.c
(to be used in C and C++).
Also needed are: smdevp.h
and smdevp.c
for streaming XML signature and message digest engine, mecevp.h
and mecevp.c
for the streaming XML encryption engine, threads.h
and threads.c
for multi-threading and locking support.
To enable WS-Security, the service definitions header file for soapcpp2 should include the following imports:
This imports the SOAP header elements required by WS-Security.
For more details, see the WS-Security plugin documentation.
Basically, to add WS-Discovery support the following event handlers must be defined and linked:
These event handlers will be invoked when inbound WS-Discovery messages arrive using:
which will listen for timeout
seconds to inbound WS-Discovery messages on a port and dispatches them to the event handlers. A negative timeout
value specifies the timeout in microseconds.
For more details, see the WS-Discovery plugin documentation.
Copyright (c) 2000,2024, Robert A. van Engelen, Genivia Inc.
All rights reserved.