Genivia - HTTP and IO functions

|  | Home | Documentation | HTTP and IO functions updated Mon Apr 22 2024 by Robert van Engelen |

- Main Page
- Modules
- Classes
- Files

Macros | Typedefs | Functions
HTTP and IO functions

This module defines functions for HTTP operations and functions for receiving and sending data. More...

## Macros
#define | SOAP_HTML
| A special `soap_status` error code to signal that a custom HTTP response is present and no HTTP response must be produced. More...
#define | SOAP_FILE
| A special `soap_status` error code to signal that a custom file-based HTTP response is present and no HTTP response must be produced. More...
#define | SOAP_POST
| HTTP POST command code. More...
#define | SOAP_POST_FILE
| HTTP POST command code with custom content type. More...
#define | SOAP_GET
| HTTP GET command code. More...
#define | SOAP_PUT
| HTTP PUT command code with custom content type. More...
#define | SOAP_DEL
| HTTP DEL command code. More...
#define | SOAP_CONNECT
| HTTP CONNECT command code. More...
#define | SOAP_HEAD
| HTTP HEAD command code. More...
#define | SOAP_OPTIONS
| HTTP OPTIONS command code. More...
#define | SOAP_PATCH
| HTTP PATCH command code with custom content type. More...

## Typedefs
typedef int | soap_http_command
| HTTP command methods for `soap_connect_command` More...
typedef int32_t | soap_wchar
| Wide char type. More...

## Functions
int | soap_GET (struct soap *soap, const char *endpoint, const char *action)
| HTTP GET content from server. More...
int | soap_PUT (struct soap *soap, const char *endpoint, const char *action, const char *type)
| HTTP PUT content to server. More...
int | soap_PATCH (struct soap *soap, const char *endpoint, const char *action, const char *type)
| HTTP PATCH content to server. More...
int | soap_POST (struct soap *soap, const char *endpoint, const char *action, const char *type)
| HTTP POST content to server. More...
int | soap_DELETE (struct soap *soap, const char *endpoint)
| HTTP DELETE content from server. More...
int | soap_connect_command (struct soap *soap, soap_http_command http_command, const char *endpoint, const char *action)
| Connect to a server. More...
int | soap_connect (struct soap *soap, const char *endpoint, const char *action)
| Connect to a server using HTTP POST. More...
SOAP_SOCKET | soap_bind (struct soap *soap, const char *host, int port, int backlog)
| Bind and listen to a port. More...
SOAP_SOCKET | soap_accept (struct soap *soap)
| Accept a connection with a client. More...
int | soap_serve (struct soap *soap)
| Serve a pending request. More...
int | soap_begin_serve (struct soap *soap)
| Initiates serving a pending client request. More...
int | soap_serve_request (struct soap *soap)
| Process a pending request. More...
int | soap_response (struct soap *soap, int status)
| Initialize the context for server-side sending and send a HTTP response header. More...
int | soap_begin_recv (struct soap *soap)
| Initialize the context for receiving. More...
int | soap_end_recv (struct soap *soap)
| Finalize the context after receiving. More...
int | soap_begin_send (struct soap *soap)
| Initialize the context for sending. More...
int | soap_end_send (struct soap *soap)
| Finalize the context after sending. More...
int | soap_begin_count (struct soap *soap)
| Initialize context to count message length for sending. More...
int | soap_end_count (struct soap *soap)
| Finalize context to count message length for sending. More...
int | soap_closesock (struct soap *soap)
| Close the socket connection. More...
int | soap_force_closesock (struct soap *soap)
| Forcibly close the socket connection. More...
void | soap_close_connection (struct soap *soap)
| Close the connection of the specified context using a self-pipe. More...
int | soap_send (struct soap *soap, const char *s)
| Send a string. More...
int | soap_send_raw (struct soap *soap, const char *s, size_t n)
| Send raw bytes. More...
int | soap_http_has_body (struct soap *soap)
| Check if HTTP body message is not empty. More...
char * | soap_http_get_body (struct soap *soap, size_t *len)
| Get the HTTP body message as a string. More...
int | soap_getline (struct soap *soap, char *buf, int len)
| Get a header line. More...
soap_wchar | soap_get0 (struct soap *soap)
| Get next byte without consuming it. More...
soap_wchar | soap_get1 (struct soap *soap)
| Get next byte. More...
int | soap_poll (struct soap *soap)
| Poll the connection. More...
int | soap_ready (struct soap *soap)
| Check if the connection is ready to receive pending data. More...
int | soap_recv_empty_response (struct soap *soap)
| Receive an HTTP response message from the server that is assumed to be empty. More...
int | soap_send_empty_response (struct soap *soap, int status)
| Return an HTTP response message with an empty HTTP body from a service back to the client or peer. More...
int | soap_envelope_begin_in (struct soap *soap)
| Parse the XML `<SOAP-ENV:Envelope>` element opening tag if present. More...
int | soap_envelope_end_in (struct soap *soap)
| Parse the XML `</SOAP-ENV:Envelope>` element closing tag if present. More...
int | soap_envelope_begin_out (struct soap *soap)
| Emit the XML `<SOAP-ENV:Envelope>` element opening tag if `soap::version` is nonzero. More...
int | soap_envelope_end_out (struct soap *soap)
| Emit the XML `</SOAP-ENV:Envelope>` element closing tag if `soap::version` is nonzero. More...
int | soap_body_begin_in (struct soap *soap)
| Parse the XML `<SOAP-ENV:Body>` element opening tag if present. More...
int | soap_body_end_in (struct soap *soap)
| Parse the XML `</SOAP-ENV:Body>` element closing tag if present. More...
int | soap_body_begin_out (struct soap *soap)
| Emit the XML `<SOAP-ENV:Body>` element opening tag if `soap::version` is nonzero. More...
int | soap_body_end_out (struct soap *soap)
| Emit the XML `</SOAP-ENV:Body>` element closing tag if `soap::version` is nonzero. More...
int | soap_recv_fault (struct soap *soap, int check)
| Parse and deserialize the SOAP Fault. More...
int | soap_send_fault (struct soap *soap)
| Return an HTTP error with a SOAP Fault message from a service. More...
int | soap_recv_header (struct soap *soap)
| Parse and deserialize the SOAP Header. More...
int | soap_putheader (struct soap *soap)
| Emit the SOAP Header pointed to by `soap::header` More...
void | soap_serializeheader (struct soap *soap)
| Serialize the SOAP Header pointed to by `soap::header` before emitting it with `soap_putheader` More...
int | http_get (struct soap *, struct soap_plugin *, void *)
| The HTTP GET plugin registration function. More...
void | soap_http_get_stats (struct soap *soap, size_t *stat_get, size_t *stat_post, size_t *stat_fail, size_t **hist_min, size_t **hist_hour, size_t **hist_day)
| Collect access statistics with the `http_get` plugin. More...
char * | soap_query (struct soap *soap)
| Extract the query string from the URL path at the server side with the `http_get` plugin. More...
char * | soap_query_key (struct soap *soap, char **query)
| Extract the next query string key at the server side with the `http_get` plugin. More...
char * | soap_query_val (struct soap *soap, char **query)
| Extract the next query string value at the server side with the `http_get` plugin. More...
int | http_post (struct soap *, struct soap_plugin *, void *)
| The HTTP POST plugin registration function. More...
int | http_form (struct soap *, struct soap_plugin *, void *)
| The HTTP POST form plugin registration function. More...
char * | soap_http_get_form (struct soap *soap)
| Get the HTTP POST application/x-www-form-urlencoded data as a string. More...
int | http_pipe (struct soap *, struct soap_plugin *, void *)
| The HTTP pipelining plugin registration function. More...

## Detailed Description

This module defines functions for HTTP operations and functions for receiving and sending data.

This module defines the following client-side functions:

- `soap_GET`
- `soap_PUT`
- `soap_PATCH`
- `soap_POST`
- `soap_DELETE`
- `soap_connect_command`
- `soap_connect`
- `soap_recv_empty_response`

This module defines the following server-side functions:

- `soap_bind`
- `soap_accept`
- `soap_ssl_accept` (defined in the SSL/TLS context and functions module)
- `soap_serve` (generated by soapcpp2)
- `soap_begin_serve`
- `soap_serve_request` (generated by soapcpp2)
- `soap_response`
- `soap_send_empty_response`

This module defines the following input/output functions:

- `soap_begin_recv`
- `soap_end_recv`
- `soap_begin_send`
- `soap_end_send`
- `soap_begin_count`
- `soap_end_count`
- `soap_closesock`
- `soap_force_closesock`
- `soap_close_connection`
- `soap_send`
- `soap_send_raw`
- `soap_http_has_body`
- `soap_http_get_body`
- `soap_getline`
- `soap_get0`
- `soap_get1`
- `soap_poll`
- `soap_ready`

This module defines the following SOAP message input/output functions:

- `soap_envelope_begin_in`
- `soap_envelope_end_in`
- `soap_envelope_begin_out`
- `soap_envelope_end_out`
- `soap_body_begin_in`
- `soap_body_end_in`
- `soap_body_begin_out`
- `soap_body_end_out`
- `soap_recv_fault`
- `soap_send_fault`
- `soap_recv_header`
- `soap_putheader`
- `soap_serializeheader`

This module defines three HTTP-related plugins;

- `http_get` HTTP GET plugin for server-side handling of HTTP GET requests by stand-alone servers as a more capable alternative to setting the `soap::fget` callback.
- `http_post` HTTP POST plugin for server-side handling of HTTP POST, PUT, PATCH, and DELETE request by stand-alone servers as a more capable alternative to setting the `soap::fput`, `soap::fpatch`, and `soap::fdel` callbacks.
- `http_form` HTTP POST form plugin for server-side handling of HTTP application/x-www-form-urlencoded data.
- `http_pipe` HTTP pipelining plugin to support server-side and client-side pipelined HTTP messages.

## Macro Definition Documentation

#define SOAP_CONNECT

HTTP CONNECT command code.

This code is to be used with `soap_connect_command`.

#define SOAP_DEL

HTTP DEL command code.

This code is to be used with `soap_connect_command`. The `soap_DELETE` performs the same operation as `soap_connect_command` with `SOAP_DEL`. `soap_DELETE` is recommended.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK or SOAP_IO_STORE
if (soap_connect_command(soap, "http://www.example.com/API/DELETE", NULL, SOAP_DEL)
|| soap_recv_empty_response(soap))
soap_print_fault(soap, stderr);
soap_closesock(soap);

#define SOAP_FILE

A special `soap_status` error code to signal that a custom file-based HTTP response is present and no HTTP response must be produced.

This code is used with `soap_response` to return a file-based response message with a HTTP content type specified by the `soap::http_content` string variable. The `soap_response` function normally returns HTTP 200 OK, but the HTTP status code can be specified as `SOAP_FILE + status` where `status` is a HTTP status code between 200 and 599.

#define SOAP_GET

HTTP GET command code.

This code is to be used with `soap_connect_command`. The `soap_GET` performs the same operation as `soap_connect_command` with `SOAP_GET`. `soap_GET` is recommended.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK or SOAP_IO_STORE
char *response = NULL;
size_t response_len;
if (soap_connect_command(soap, "http://www.example.com/API/GET", NULL, SOAP_GET)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);

#define SOAP_HEAD

HTTP HEAD command code.

This code is to be used with `soap_connect_command`.

#define SOAP_HTML

A special `soap_status` error code to signal that a custom HTTP response is present and no HTTP response must be produced.

This code is used with `soap_response` to return a HTML response message with a HTTP content type "text/html".

#define SOAP_OPTIONS

HTTP OPTIONS command code.

This code is to be used with `soap_connect_command`.

#define SOAP_PATCH

HTTP PATCH command code with custom content type.

This code is to be used with `soap_connect_command` and requires `soap::http_content` to be set to the content type of the data to be sent. The `soap_PATCH` function performs the same operation as `soap_connect_command` with `SOAP_PATCH`. `soap_PATCH` is recommended.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK or SOAP_IO_STORE
soap->http_content = "application/json; charset=utf-8";
if (soap_connect_command(soap, "http://www.example.com/API/PATCH", NULL, SOAP_PATCH)
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap)
|| soap_recv_empty_response(soap))
soap_print_fault(soap, stderr);
soap_closesock(soap);

#define SOAP_POST

HTTP POST command code.

This code is to be used with `soap_connect_command` and produces HTTP content type `text/xml; charset=utf-8`. Use code `SOAP_POST_FILE` to customize the content type by setting `soap::http_content`. Before calling `soap_connect_command`, either the HTTP content length `soap::count` must be determined with `soap_begin_count` and `soap_end_count`, or the mode of the context should be set to `SOAP_IO_CHUNK` (preferred) or `SOAP_IO_STORE`. The `soap_POST` function performs the same operation as `soap_connect_command` with `SOAP_POST_FILE` and sets the context mode to `SOAP_IO_STORE` when required. `soap_POST` is recommended.

Examples:

#include "soapH.h"
struct soap *soap = soap_new();
char *response = NULL;
size_t response_len;
// HTTP GET
if (soap_connect_command(soap, SOAP_GET, endpoint, NULL)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);
#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // must use SOAP_IO_CHUNK or SOAP_IO_STORE
char *response = NULL;
size_t response_len;
// HTTP POST request with chunked transfer
if (soap_connect_command(soap, SOAP_POST, endpoint, NULL)
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);
#include "soapH.h"
struct soap *soap = soap_new(); // no SOAP_IO_CHUNK or SOAP_IO_STORE, see below
const char *request = "<doc title=\"Example\">Some text</doc>\n";
char *response = NULL;
size_t response_len;
// HTTP POST request, here we compute the content length instead of chunked transfer with SOAP_IO_CHUNK or storing the entire message with SOAP_IO_STORE
if (soap_begin_count(soap)
|| soap_send(soap, request)
|| soap_end_count(soap)
|| soap_connect_command(soap, SOAP_POST, endpoint, NULL)
|| soap_send(soap, request)
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);

See also
  `soap_connect_command`, `soap_POST`

#define SOAP_POST_FILE

HTTP POST command code with custom content type.

This code is to be used with `soap_connect_command` and requires `soap::http_content` to be set to the content type of the data to be sent. Before calling `soap_connect_command`, either the HTTP content length `soap::count` must be determined with `soap_begin_count` and `soap_end_count`, or the mode of the context should be set to `SOAP_IO_CHUNK` (preferred) or `SOAP_IO_STORE`. The `soap_POST` function performs the same operation as `soap_connect_command` with `SOAP_POST_FILE` and sets the context mode to `SOAP_IO_STORE` when required. `soap_POST` is recommended.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK (preferred) or SOAP_IO_STORE
char *response = NULL;
size_t response_len;
soap->http_content = "application/json; charset=utf-8";
if (soap_connect_command(soap, "http://www.example.com/API/POST", NULL, SOAP_POST_FILE)
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);

#define SOAP_PUT

HTTP PUT command code with custom content type.

This code is to be used with `soap_connect_command` and requires `soap::http_content` to be set to the content type of the data to be sent. The `soap_PUT` performs the same operation as `soap_connect_command` with `SOAP_PUT` and is recommended.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK or SOAP_IO_STORE
soap->http_content = "text/xml; charset=utf-8";
if (soap_connect_command(soap, "http://www.example.com/API/PUT", NULL, SOAP_PUT)
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_send(soap)
|| soap_recv_empty_response(soap))
soap_print_fault(soap, stderr);
soap_closesock(soap);

## Typedef Documentation

typedef int soap_http_command

HTTP command methods for `soap_connect_command`

The choice of options are: `SOAP_CONNECT` `SOAP_DEL` `SOAP_GET` `SOAP_HEAD` `SOAP_OPTIONS` `SOAP_PATCH` `SOAP_POST_FILE` `SOAP_POST` `SOAP_PUT`

typedef int32_t soap_wchar

Wide char type.

## Function Documentation

int http_form | ( | struct soap * | ,
|  | struct soap_plugin * | ,
|  | void * |
| ) |  |

The HTTP POST form plugin registration function.

This function is used to register the `http_form` HTTP POST form plugin to handle application/x-www-form-urlencoded data with `soap_register_plugin_arg(soap, http_form, http_form_handler)` where the `http_form_handler` is a function to parse the application/x-www-form-urlencoded data received by the server. The HTTP POST form plugin API is declared and defined in `gsoap/plugin/httpform.h` and `gsoap/plugin/httpform.c`.

Handling multipart/related and multipart/form-data at the server side is done by iterating over the `soap_multipart` linked list containing the MIME attachments received, see the detailed description of MIME attachment functions.

Note
  This plugin requires the `http_get` plugin for the `soap_query_key` and `soap_query_val` functions.

Example:

#include "soapH.h"
#include "plugin/httpform.h"
int main()
{
struct soap *soap = soap_new();
soap_register_plugin_arg(soap, http_form, http_form_handler);
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int http_form_handler(struct soap *soap)
{
if (!strncmp(soap->path, "/API/FORM", 9))
{
// get the application/x-www-form-urlencoded data
char *form = soap_http_get_form(soap);
while (form)
{
// get next key=val pair
char *key = soap_query_key(soap, &form);
char *val = soap_query_key(soap, &form);
... // use key and val (key is non-NULL, val may be NULL)
}
// return a response message
if (soap_response(soap, SOAP_HTML)
|| soap_send(soap, "<html><body>Thank you for submitting</body></html>\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
return 404; // HTTP 404 Not Found
}

See also
  `soap_http_get_form`, `http_get`, `soap_query_key`, `soap_query_val`.

int http_get | ( | struct soap * | ,
|  | struct soap_plugin * | ,
|  | void * |
| ) |  |

The HTTP GET plugin registration function.

This function is used to register the `http_get` HTTP GET plugin with `soap_register_plugin_arg(soap, http_get, http_get_handler)` where the `http_get_handler` is a user-defined function to handle HTTP GET requests. The HTTP GET plugin API is declared and defined in `gsoap/plugin/httpget.h` and `gsoap/plugin/httpget.c`. The `soap::path` string contains the URL path, starting with a leading `/`.

Example:

#include "soapH.h"
#include "plugin/httpget.h"
int main()
{
struct soap *soap = soap_new();
soap_register_plugin_arg(soap, http_get, http_get_handler);
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int http_get_handler(struct soap *soap)
{
if (!strncmp(soap->path, "/API/GET", 8))
{
// get the query key=val pairs from soap->path
char *query = soap_query(soap);
while (query)
{
// get next key=val pair
char *key = soap_query_key(soap, &query);
char *val = soap_query_key(soap, &query);
... // use key and val (key is non-NULL, val may be NULL)
}
// return a response message
soap->http_content = "application/json; charset=utf-8";
if (soap_response(soap, SOAP_FILE)
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
return 404; // HTTP 404 Not Found
}

Warning
  When serving files as responses to requests, we need to be vary careful, because we don't want requests to snoop around in directories and serve files that should be protected from public view. Therefore, when adding logic to serve files, we must reject request that have `soap::path` values with a `/` or 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. See the `gsoap/samples/webserver/webserver.c` example for details.

See also
  `soap_http_get_stats`, `soap_query`, `soap::fget`.

int http_pipe | ( | struct soap * | ,
|  | struct soap_plugin * | ,
|  | void * |
| ) |  |

The HTTP pipelining plugin registration function.

This function is used to register the `http_pipe` HTTP pipelining plugin to support HTTP pipelining. HTTP pipelining requires `SOAP_IO_KEEPALIVE` enabled. At the server side, multiple threads should be used to serve requests, such as with a gSOAP multi-threaded stand-alone server. HTTP pipelining at the client side requires two threads, one to send request messages and one to receive the response messages, with logic to handle transmission errors and to resend failed request messages until all responses have been received.

Example:

#include "soapH.h"
#include "plugin/httppipe.h"
#include "plugin/threads.h"
int main()
{
struct soap *soap = soap_new1(SOAP_IO_KEEPALIVE); // HTTP keep-alive
soap_register_plugin(soap, http_pipe); // HTTP pipelining
soap->bind_flags = SO_REUSEADDR; // immediate port reuse
soap->accept_timeout = 3600; // exit loop when no request arrives in one hour
soap->send_timeout = soap_recv_timeout = 5; // 5 seconds max socket stall time (unlimited by default)
soap->transfer_timeout = 30; // 30 seconds max message transfer time (unlimited by default)
soap->recv_maxlength = 1048576; // limit messages received to 1MB (2GB by default)
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
if (soap_valid_socket(soap_accept(soap)))
{
THREAD_TYPE tid;
struct soap *tsoap = soap_copy(soap);
if (!tsoap)
soap_force_closesock(soap);
else
while (THREAD_CREATE(&tid, (void*(*)(void*))&process_request, (void*)tsoap))
sleep(1); // failed, try again
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
}
void *process_request(struct soap *soap)
{
THREAD_DETACH(THREAD_ID);
soap_serve(soap);
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
return NULL;
}

int http_post | ( | struct soap * | ,
|  | struct soap_plugin * | ,
|  | void * |
| ) |  |

The HTTP POST plugin registration function.

This function is used to register the `http_post` HTTP POST plugin with `soap_register_plugin_arg(soap, http_post, http_post_handler)` where the `http_post_handler` is a table of HTTP POST handler functions and generic POST, PUT, PATCH, and DELETE handler functions. The HTTP POST plugin API is declared and defined in `gsoap/plugin/httppost.h` and `gsoap/plugin/httppost.c`.

Example:

#include "soapH.h"
#include "plugin/httppost.h"
int main()
{
struct soap *soap = soap_new();
soap_register_plugin_arg(soap, http_post, http_post_handlers);
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
struct http_post_handlers http_post_handlers[] = {
{ "application/json", json_post_handler },
{ "image/*", image_post_handler },
{ "text/*", text_post_handler },
{ "POST", generic_POST_handler },
{ "PUT", generic_PUT_handler },
{ "PATCH", generic_PATCH_handler },
{ "DELETE", generic_DELETE_handler },
{ NULL }
};
// example image/* POST handler
// note: json_post_handler and text_post_handler are similar to this example
int image_post_handler(struct soap *soap)
{
const char *buf;
size_t len;
// for example, only handle /API/POST paths and content type image/gif
if (!strncmp(soap->path, "/API/POST", 9))
|| (soap->http_content && soap_tag_cmp(soap->http_content, "image/gif")))
return 404;
// get HTTP POST message body
buf = soap_http_get_body(soap, &len);
if (!buf)
return 400; // HTTP 400 Bad Request
(void)soap_end_recv(soap);
... // process image in buf[0..len-1]
// for example, send image back (HTTP POST returns a response message)
soap->http_content = "image/gif";
if (soap_response(soap, SOAP_FILE)
|| soap_send_raw(soap, buf, len)
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
// example generic PUT handler
int generic_PUT_handler(struct soap *soap)
{
const char *buf;
size_t len;
// for example, only handle /API/PUT paths and content type image/gif
if (!strncmp(soap->path, "/API/PUT", 8))
|| (soap->http_content && soap_tag_cmp(soap->http_content, "image/gif")))
return 404;
// get HTTP PUT message body
buf = soap_http_get_body(soap, &len);
if (!buf)
return 400; // HTTP 400 Bad Request
(void)soap_end_recv(soap);
... // process image in buf[0..len-1]
return soap_send_empty_response(soap, 200); // HTTP 200 OK
}

SOAP_SOCKET soap_accept | ( | struct soap * | soap | ) |

Accept a connection with a client.

This function accepts a connection requested by a client on a given port that is bound with `soap_bind` first to set `soap::master`. To accept HTTPS connections, call `soap_ssl_accept` after this function to perform the HTTPS handshake with the client. Returns the `soap::socket` connected to the client or the invalid socket handle `SOAP_INVALID_SOCKET` when an error occurred.

Examples:

#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->accept_timeout = 3600; // exit loop when no request arrives in one hour
soap->send_timeout = soap_recv_timeout = 5; // 5 seconds max socket stall time (unlimited by default)
soap->transfer_timeout = 30; // 30 seconds max message transfer time (unlimited by default)
soap->recv_maxlength = 1048576; // limit messages received to 1MB (2GB by default)
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
if (soap_valid_socket(soap_accept(soap)))
{
if (soap_serve(soap))
soap_print_fault(soap, stderr);
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
}
#include "soapH.h"
#include "plugin/threads.h"
int main()
{
struct soap *soap = soap_new();
soap->bind_flags = SO_REUSEADDR; // immediate port reuse
soap->accept_timeout = 3600; // exit loop when no request arrives in one hour
soap->send_timeout = soap_recv_timeout = 5; // 5 seconds max socket stall time (unlimited by default)
soap->transfer_timeout = 30; // 30 seconds max message transfer time (unlimited by default)
soap->recv_maxlength = 1048576; // limit messages received to 1MB (2GB by default)
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
if (soap_valid_socket(soap_accept(soap)))
{
THREAD_TYPE tid;
struct soap *tsoap = soap_copy(soap);
if (!tsoap)
soap_force_closesock(soap);
else
while (THREAD_CREATE(&tid, (void*(*)(void*))&process_request, (void*)tsoap))
sleep(1); // failed, try again
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
}
void *process_request(struct soap *soap)
{
THREAD_DETACH(THREAD_ID);
soap_serve(soap);
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
return NULL;
}
// alternative process_request function to accept HTTPS connections
void *process_request(struct soap *soap)
{
THREAD_DETACH(THREAD_ID);
if (soap_ssl_accept(soap) == SOAP_OK)
soap_serve(soap);
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
return NULL;
}

In addition, HTTP keep-alive connections with HTTP chunked messages are enabled with `struct soap *soap = soap_new1(SOAP_IO_CHUNK | SOAP_IO_KEEPALIVE)`. HTTP keep-alive should only be enabled with multi-threaded gsoap services.

See also
  `WITH_IPV6`, `WITH_IPV6_V6ONLY`, `SOAP_IO_UDP`, `SOAP_IO_CHUNK`, `SOAP_IO_STORE`, `SOAP_IO_KEEPALIVE`, `SOAP_MAXKEEPALIVE`, `soap::accept_flags`, `soap::bind_flags`, `soap::bind_inet6`, `soap::bind_v6only`, `soap::rcvbuf`, `soap::sndbuf`, `soap::master`, `soap_bind`, `soap_ssl_accept`.

Returns
  the `soap::socket` value or `SOAP_INVALID_SOCKET` when an error occurred (check the return value with `soap_valid_socket`)

Parameters

  soap | `soap` context

int soap_begin_count | ( | struct soap * | soap | ) |

Initialize context to count message length for sending.

This function is used to determine the HTTP content length. This is done by sending the message after calling this function to update `soap::count`. To activate message length counting the `SOAP_IO_LENGTH` mode is enabled, which prevents the message from being sent by not passing the data to the (internal) `soap::fsend` callback. HTTP requires either the HTTP content length header or HTTP transfer encoding chunked with `SOAP_IO_CHUNK`. Alternatively, the mode of the context can be set to `SOAP_IO_STORE` to buffer the entire message in memory to determine the message content length.

Examples:

#include "soapH.h"
struct soap *soap = soap_new();
char *response = NULL;
size_t response_len;
const char *request = "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n";
// HTTP POST request, soap_POST stores the entire message with SOAP_IO_STORE to determine HTTP content length
if (soap_POST(soap, "http://www.example.com/API/POST", NULL, "application/json; charset=utf-8")
|| soap_send(soap, request)
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);
#include "soapH.h"
struct soap *soap = soap_new();
soap->fget = my_get; // HTTP GET handler to serve HTTP GET
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
int my_get(struct soap *soap)
{
// serve HTTP GET request, here we compute the content length instead of chunked transfer with SOAP_IO_CHUNK or storing the entire message with SOAP_IO_STORE
const char *response = "<doc title=\"Example\">Some text</doc>\n";
if (soap_begin_count(soap)
|| soap_send(soap, response)
|| soap_end_count(soap)
|| soap_response(soap, SOAP_OK)
|| soap_send(soap, response)
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}

Same examples but using HTTP transfer encoding chunked:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK);
char *response = NULL;
size_t response_len;
const char *request = "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n";
if (soap_POST(soap, "http://www.example.com/API/POST", NULL, "application/json; charset=utf-8")
|| soap_send(soap, request)
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);
#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK);
soap->fget = my_get; // HTTP GET handler to serve HTTP GET
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
int my_get(struct soap *soap)
{
const char *response = "<doc title=\"Example\">Some text</doc>\n";
if (soap_response(soap, SOAP_OK)
|| soap_send(soap, response)
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}

See also
  `soap_end_count`, `SOAP_IO_LENGTH`, `SOAP_IO_CHUNK`, `SOAP_IO_STORE`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_begin_recv | ( | struct soap * | soap | ) |

Initialize the context for receiving.

This function should be called to initialize the context for receiving a message or to begin parsing a document. This function is called in the server and client-side code generated by soapcpp2, and in the generated `soap_T_read` functions to deserialize data of type `T`. For example, it is called by `soap_serve` (via `soap_begin_serve`) at the server side when a client request is pending. This function parses HTTP, DIME, MIME and SOAP headers if present and updates the context with the engine state. Therefore, this function should not be called more than once to initialize the context for receiving. The source of the data read is `soap::is` when non-NULL, or `soap::socket` when valid, or `soap::recvfd`. Returns `SOAP_OK` or a `soap_status` error code.

See also
  `soap::socket`, `soap::recvfd`, `soap::is`, `soap_end_recv`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_begin_send | ( | struct soap * | soap | ) |

Initialize the context for sending.

This function should be called to initialize the context for sending a message or to write a document. This function is called in the server and client-side code generated by soapcpp2, and in the generated `soap_T_write` functions to serialize data of type `T`. For example, it is called by `soap_connect` (via `soap_connect_command`) at the client side when a client connects to a server to send the HTTP headers and message body. The destination of the data to be send is `soap::socket` when valid, or `soap::sendfd` when nonzero or `soap::os` when non-NULL. Returns `SOAP_OK` or a `soap_status` error code.

See also
  `soap::socket`, `soap::sendfd`, `soap::os`, `soap_end_send`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_begin_serve | ( | struct soap * | soap | ) |

Initiates serving a pending client request.

This function processes the HTTP headers and XML SOAP headers if present of the pending request on `soap::socket` or on standard input/output `soap::recvfd` and `soap::sendfd`, e.g. for CGI and FastCGI services. Returns `SOAP_OK` or a `soap_status` error code.

See also
  `soap_serve`, `soap_serve_request`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

SOAP_SOCKET soap_bind | ( | struct soap * | soap,
|  | const char * | host,
|  | int | port,
|  | int | backlog
| ) |  |

Bind and listen to a port.

This function binds to the specified port and starts listening for client requests. The `host` parameter when non-NULL is the name of the host on which this service runs. The `port` parameter is the port number to bind, which must not be in use by another service. The call may also fail if the port was recently in use by this service. Use `SO_REUSEADDR` with `soap::bind_flags` to immediately reuse the port, but use this option with caution to prevent "port stealing" attacks. The `backlog` parameter is used with `listen`, which defines the maximum length for the queue of pending connections. If a connection request arrives with the queue full, the client may receive an error with an indication of `ECONNREFUSED` or a connection reset. Alternatively, if the underlying protocol supports retransmission, the request may be ignored so that retries may succeed. Returns the `soap::master` socket bound to the port or the invalid socket handle `SOAP_INVALID_SOCKET` when an error occurred.

Note
  A small `backlog` value should be used with iterative (i.e. non-multi-threaded) servers to improve fairness among connecting clients, recommended is a `backlog` value between 2 and 10. A smaller value increases fairness and defends against denial of service, but hampers performance because connection requests may be refused when the queue is full. Also short `soap::recv_timeout` and `soap::send_timeout` values of a few seconds at the most should be used to prevent clients from using connections for long by terminating unacceptably slow message exchanges that exceed the timeout thresholds. In the worst case, a connecting client may have to wait `backlog` * (`soap::recv_timeout` + `soap::send_timeout`) seconds to have the connection accepted by an iterative server when the backlog queue is full, or even longer when message sizes are very large, e.g. several MBs, requiring multiple message data packet exchanges. Larger `backlog` values can be safely used with multi-threaded servers, such as 50 to 128, where 128 is a typical maximum on most operating systems. The actual value does not matter when connections are accepted as soon as they arrive by `soap_accept` and then handled by threads executing `soap_ssl_accept` (for HTTPS) and `soap_serve`.

This function effectively deployes a stand-alone server on the specified port. There are three other alternatives for deploying services:

- CGI and FastCGI, see `WITH_FASTCGI`.
- IIS web server, see the ISAPI extension for gSOAP.
- Apache web server, see the Apache module for gSOAP.

Examples:

#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->bind_flags = SO_REUSEADDR; // immediate port reuse
soap->accept_timeout = 3600; // exit loop when no request arrives in one hour
soap->send_timeout = soap_recv_timeout = 5; // 5 seconds max socket stall time (unlimited by default)
soap->transfer_timeout = 30; // 30 seconds max message transfer time (unlimited by default)
soap->recv_maxlength = 1048576; // limit messages received to 1MB (2GB by default)
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
if (soap_valid_socket(soap_accept(soap)))
{
if (soap_serve(soap))
soap_print_fault(soap, stderr);
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
}
#include "soapH.h"
#include "plugin/threads.h"
int main()
{
struct soap *soap = soap_new();
soap->bind_flags = SO_REUSEADDR; // immediate port reuse
soap->accept_timeout = 3600; // exit loop when no request arrives in one hour
soap->send_timeout = soap_recv_timeout = 5; // 5 seconds max socket stall time (unlimited by default)
soap->transfer_timeout = 30; // 30 seconds max message transfer time (unlimited by default)
soap->recv_maxlength = 1048576; // limit messages received to 1MB (2GB by default)
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
if (soap_valid_socket(soap_accept(soap)))
{
THREAD_TYPE tid;
struct soap *tsoap = soap_copy(soap);
if (!tsoap)
soap_force_closesock(soap);
else
while (THREAD_CREATE(&tid, (void*(*)(void*))&process_request, (void*)tsoap))
sleep(1); // failed, try again
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
}
void *process_request(struct soap *soap)
{
THREAD_DETACH(THREAD_ID);
soap_serve(soap);
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
return NULL;
}

See also
  `WITH_IPV6`, `WITH_IPV6_V6ONLY`, `SOAP_IO_UDP`, `soap::bind_flags`, `soap::bind_inet6`, `soap::bind_v6only`, `soap::rcvbuf`, `soap::sndbuf`, `soap::master`, `soap_accept`, `soap_ssl_accept`.

Returns
  the `soap::master` socket value or `SOAP_INVALID_SOCKET` when an error occurred (check the return value with `soap_valid_socket`)

Parameters

  soap | `soap` context
  host | name of the host or NULL
  port | port number to bind
  backlog | maximum queue length of pending requests

int soap_body_begin_in | ( | struct soap * | soap | ) |

Parse the XML `<SOAP-ENV:Body>` element opening tag if present.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_body_begin_out | ( | struct soap * | soap | ) |

Emit the XML `<SOAP-ENV:Body>` element opening tag if `soap::version` is nonzero.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_body_end_in | ( | struct soap * | soap | ) |

Parse the XML `</SOAP-ENV:Body>` element closing tag if present.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_body_end_out | ( | struct soap * | soap | ) |

Emit the XML `</SOAP-ENV:Body>` element closing tag if `soap::version` is nonzero.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

void soap_close_connection | ( | struct soap * | soap | ) |

Close the connection of the specified context using a self-pipe.

This function closes the connection of the specified context, i.e. when it hangs on socket IO and the specified `soap::recv_timeout` and `soap::send_timeout` timeouts are not sufficient to release the blocking socket IO. This function force-closes a connection, which is typically done by another thread that detects a termination condition. Requires compilation with `WITH_SELF_PIPE` and requires `soap::recv_timeout` set to a nonzero timeout value.

Alternatively, `THREAD_CANCEL` can be used with a thread cleanup function added with `pthread_cleanup_push`. See `THREAD_CANCEL` for details.

Example:

#include "soapH.h"
#include "plugin/threads.h"
struct soap *soap = soap_new();
soap->bind_flags = SO_REUSEADDR; // immediate port reuse
soap->accept_timeout = 3600; // exit loop when no request arrives in one hour
soap->send_timeout = soap_recv_timeout = 5; // 5 seconds max socket stall time (unlimited by default)
soap->transfer_timeout = 30; // 30 seconds max message transfer time (unlimited by default)
soap->recv_maxlength = 1048576; // limit messages received to 1MB (2GB by default)
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
if (soap_valid_socket(soap_accept(soap)))
{
THREAD_TYPE tid;
struct soap *tsoap = soap_copy(soap);
if (!tsoap)
soap_force_closesock(soap);
else
while (THREAD_CREATE(&tid, (void*(*)(void*))&accept_request, (void*)tsoap))
sleep(1); // failed, try again
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
void *accept_request(struct soap *soap)
{
THREAD_TYPE tid;
struct soap *tsoap;
THREAD_DETACH(THREAD_ID);
// create a new thread that is timed to execute for max 10 seconds
tsoap = soap_copy(soap);
if (!tsoap)
{
soap_force_closesock(soap);
}
else
{
while (THREAD_CREATE(&tid, (void*(*)(void*))&process_request, (void*)tsoap))
sleep(1); // failed, try again
// allow serving the request by the new thread for up to 30 seconds max
sleep(30);
// terminate soap_serve in process_request then wait for it to join
soap_close_connection(tsoap);
THREAD_JOIN(tid);
// clean up the terminated thread context
soap_free(tsoap);
}
// clean up
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
return NULL;
}
void *process_request(struct soap *soap)
{
soap_serve(soap);
soap_destroy(soap);
soap_end(soap);
return NULL;
}

Note
  Requires gSOAP 2.8.71 or greater, compilation with `WITH_SELF_PIPE`, and nonzero `soap::recv_timeout` and `soap::send_timeout` timeout values.

See also
  `soap_closesock`, `soap_force_closesock`, `soap::recv_timeout`, `soap::send_timeout`, `soap::transfer_timeout`.

Parameters

  soap | `soap` context

int soap_closesock | ( | struct soap * | soap | ) |

Close the socket connection.

This function should be called to close `soap::socket`. The socket is closed and `soap::socket` is set to `SOAP_INVALID_SOCKET` if the socket is valid, keep-alive is not enabled and not currently active, i.e. the socket is closed when `soap::socket` != `SOAP_INVALID_SOCKET` and `soap::keep_alive` == 0. Therefore, this function keeps the socket connection open when keep-alive is currently active. This function may be called multiple times but closes the socket just once if the socket connection was open. This function is called in the server and client-side code generated by soapcpp2. Returns the current value of `soap::error` to propagate the error state when used as `return soap_closesock(soap);`.

See also
  `soap_force_closesock`, `soap_close_connection`.

Returns
  the value of `soap::error` (`SOAP_OK` or a `soap_status` error code)

Parameters

  soap | `soap` context

int soap_connect | ( | struct soap * | soap,
|  | const char * | endpoint,
|  | const char * | action
| ) |  |

Connect to a server using HTTP POST.

This function connects to the server specified by the `endpoint` URL string, using HTTP POST and the HTTP SOAP Action header specified by the `action` string (or NULL). Upon successful completion, messages can be sent to and/or received from the server.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK or SOAP_IO_STORE
char *response = NULL;
size_t response_len;
if (soap_connect(soap, endpoint, NULL)
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);

In addition, HTTP keep-alive connections can be enabled with `struct soap *soap = soap_new1(SOAP_IO_CHUNK | SOAP_IO_KEEPALIVE)`.

See also
  `WITH_IPV6`, `WITH_IPV6_V6ONLY`, `SOAP_IO_UDP`, `SOAP_IO_CHUNK`, `SOAP_IO_STORE`, `SOAP_IO_KEEPALIVE`, `soap::accept_flags`, `soap::bind_flags`, `soap::bind_inet6`, `soap::bind_v6only`, `soap::rcvbuf`, `soap::sndbuf`, `soap::master`, `soap_bind`, `soap_ssl_accept`.
  `SOAP_IO_CHUNK`, `SOAP_IO_STORE`, `SOAP_IO_KEEPALIVE`, `SOAP_MAXKEEPALIVE`, `soap::connect_flags`, `soap::connect_timeout`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  endpoint | URL string
  action | SOAP Action string or NULL

int soap_connect_command | ( | struct soap * | soap,
|  | soap_http_command | http_command,
|  | const char * | endpoint,
|  | const char * | action
| ) |  |

Connect to a server.

This function connects to the server specified by the `endpoint` URL string, using the HTTP method specified by the `http_command` with a `soap_http_command` value and using the HTTP SOAP Action header specified by the `action` string (or NULL). Before calling `soap_connect_command` with `SOAP_POST`, `SOAP_POST_FILE`, `SOAP_PATCH` or `SOAP_PUT`, either the HTTP content length `soap::count` must be determined with `soap_begin_count` and `soap_end_count`, or the mode of the context should be set to `SOAP_IO_CHUNK` (preferred) or `SOAP_IO_STORE`. ALso for HTTP methods `SOAP_POST`, `SOAP_POST_FILE`, `SOAP_PATCH` and `SOAP_PUT` the `soap::http_content` string should be set before calling `soap_connect_command`. Upon successful completion of this function, messages can be sent to and/or received from the server. Returns `SOAP_OK` or a `soap_status` error code.

Examples:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK or SOAP_IO_STORE
char *response = NULL;
size_t response_len;
soap->http_content = "application/json; charset=utf-8";
// HTTP POST request with chunked transfer
if (soap_connect_command(soap, "http://www.example.com/API/POST", NULL, SOAP_POST_FILE)
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);
#include "soapH.h"
struct soap *soap = soap_new();
const char *request = "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n";
char *response = NULL;
size_t response_len;
soap->http_content = "application/json; charset=utf-8";
// HTTP POST request, here we compute the content length instead of chunked transfer with SOAP_IO_CHUNK or storing the entire message with SOAP_IO_STORE
if (soap_begin_count(soap)
|| soap_send(soap, request)
|| soap_end_count(soap)
|| soap_connect_command(soap, "http://www.example.com/API/POST", NULL, SOAP_POST_FILE)
|| soap_send(soap, request)
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);

See also
  `SOAP_GET`, `SOAP_POST`, `SOAP_POST_FILE`, `SOAP_PATCH`, `SOAP_PUT`, `soap::connect_flags`, `soap::connect_timeout`, `soap_GET`, `soap_POST`, `soap_PUT`, `soap_PATCH`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  http_command | `soap_http_command` with HTTP method code
  endpoint | URL string
  action | SOAP Action string or NULL

int soap_DELETE | ( | struct soap * | soap,
|  | const char * | endpoint
| ) |  |

HTTP DELETE content from server.

This function connects to the server specified by the `endpoint` URL string, using HTTP DELETE. No messages are sent and received. Returns `SOAP_OK` or a `soap_status` error code.

Example:

#include "soapH.h"
struct soap *soap = soap_new();
if (soap_DELETE(soap, "http://www.example.com/API/DELETE"))
soap_print_fault(soap, stderr);

To implement server-side HTTP DELETE handling use `soap::fdel`.

See also
  `soap::connect_flags`, `soap::connect_timeout`, `soap::recv_timeout`, `soap::send_timeout`, `soap::transfer_timeout`, `soap::recv_maxlength`, `soap_GET`, `soap_PUT`, `soap_PATCH`, `soap_POST`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  endpoint | URL string

int soap_end_count | ( | struct soap * | soap | ) |

Finalize context to count message length for sending.

This function is used to determine the HTTP content length. This is done by sending the message after calling this function to update `soap::count`. HTTP requires either the HTTP content length header or HTTP transfer encoding chunked with `SOAP_IO_CHUNK`. Alternatively, the mode of the context can be set to `SOAP_IO_STORE` to buffer the entire message in memory to determine the message content length.

See also
  `soap_begin_count`, `SOAP_IO_LENGTH`, `SOAP_IO_CHUNK`, `SOAP_IO_STORE`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_end_recv | ( | struct soap * | soap | ) |

Finalize the context after receiving.

This function should be called to finalize the context after receiving a message or to end parsing a document. This function is called in the server and client-side code generated by soapcpp2, and in the generated `soap_T_read` functions to deserialize data of type `T`. Returns `SOAP_OK` or a `soap_status` error code.

See also
  `soap_begin_recv`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_end_send | ( | struct soap * | soap | ) |

Finalize the context after sending.

This function should be called to finalize the context after sending a message or to end writing a document. This function is called in the server and client-side code generated by soapcpp2, and in the generated `soap_T_write` functions to serialize data of type `T`. Returns `SOAP_OK` or a `soap_status` error code.

See also
  `soap_begin_send`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_envelope_begin_in | ( | struct soap * | soap | ) |

Parse the XML `<SOAP-ENV:Envelope>` element opening tag if present.

Parameters

  soap | `soap` context

int soap_envelope_begin_out | ( | struct soap * | soap | ) |

Emit the XML `<SOAP-ENV:Envelope>` element opening tag if `soap::version` is nonzero.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_envelope_end_in | ( | struct soap * | soap | ) |

Parse the XML `</SOAP-ENV:Envelope>` element closing tag if present.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_envelope_end_out | ( | struct soap * | soap | ) |

Emit the XML `</SOAP-ENV:Envelope>` element closing tag if `soap::version` is nonzero.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_force_closesock | ( | struct soap * | soap | ) |

Forcibly close the socket connection.

This function immediately closes `soap::socket` and should only be used when `soap_closesock` does not suffice. By contrast, `soap_closesock` gently finalizes the SSL connection, and when `soap::keep_alive` == 0 calls `shutdown` and `close` on `soap::socket`. By calling `soap_force_closesock` the socket is forcibly closed immediately and `soap::socket` is set to `SOAP_INVALID_SOCKET`, even when keep-alive is currently active. This function may be called multiple times but closes the socket just once if the socket connection was open. Returns the current value of `soap::error` to propagate the error state when used as `return soap_force_closesock(soap);`.

See also
  `soap_closesock`, `soap_close_connection`.

Returns
  the value of `soap::error` (`SOAP_OK` or a `soap_status` error code)

Parameters

  soap | `soap` context

int soap_GET | ( | struct soap * | soap,
|  | const char * | endpoint,
|  | const char * | action
| ) |  |

HTTP GET content from server.

This function connects to the server specified by the `endpoint` URL string, using HTTP GET and the HTTP SOAP Action header specified by the `action` string (or NULL). This call should be followed by `soap_end_send` to send an empty HTTP body. Upon successful completion, messages can be received from the server. Returns `SOAP_OK` or a `soap_status` error code.

This function is used by the soapcpp2-generated `soap_GET_T` functions for types `T` to HTTP GET the XML deserialized value of type `T` from a server.

To implement server-side HTTP GET handling use `soap::fget`.

Example:

#include "soapH.h"
struct soap *soap = soap_new();
char *response = NULL;
size_t response_len;
if (soap_GET(soap, "http://www.example.com/API/GET", NULL)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);

See also
  `soap::connect_flags`, `soap::connect_timeout`, `soap::recv_timeout`, `soap::send_timeout`, `soap::transfer_timeout`, `soap::recv_maxlength`, `soap_PUT`, `soap_PATCH`, `soap_POST`, `soap_DELETE`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  endpoint | URL string
  action | SOAP Action string or NULL

soap_wchar soap_get0 | ( | struct soap * | soap | ) |

Get next byte without consuming it.

This function returns the next byte on the input without consuming it, i.e. peeks one byte ahead. Reads a byte from `soap::is` when non-NULL, or from `soap::socket` when valid, or from `soap::recvfd`. Returns the next byte or EOF when an error occurred and sets `soap::error` to a `soap_status` value and `soap::errnum` to the `errno` value of the failure.

Returns
  byte read or EOF when an error occurred

Parameters

  soap | `soap` context

soap_wchar soap_get1 | ( | struct soap * | soap | ) |

Get next byte.

This function returns the next byte on the input. Reads a byte from `soap::is` when non-NULL, or from `soap::socket` when valid, or from `soap::recvfd`. Returns the next byte or EOF when an error occurred and sets `soap::error` to a `soap_status` value and `soap::errnum` to the `errno` value of the failure.

Returns
  byte read or EOF when an error occurred

Parameters

  soap | `soap` context

int soap_getline | ( | struct soap * | soap,
|  | char * | buf,
|  | int | len
| ) |  |

Get a header line.

This function stores a header line into the specified buffer `buf` of maxiumum length `len`. This function should be used to read HTTP and MIME headers, which end with CRLF or LF. The function handles header continuations (indents). This function reads input from `soap::is` when non-NULL, or from `soap::socket` when valid, or from `soap::recvfd`. Returns `SOAP_OK` or a `soap_status` error code.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  buf | buffer to fill (string)
  len | maximum size of the buffer (int)

char* soap_http_get_body | ( | struct soap * | soap,
|  | size_t * | len
| ) |  |

Get the HTTP body message as a string.

This function parses an HTTP body message into a string, whether or not an HTTP body message is present. This function should be called immediately after calling `soap_begin_recv`. Note that `soap_begin_recv` is called at the server side before a HTTP callback is called, such as `soap::fput` and `soap::fpatch`. Callbacks and the `http_post` HTTP POST plugin handlers should therefore not call `soap_begin_recv`. Also, `soap_begin_recv` is called at the client side by HTTP functions such as `soap_GET`, after which the HTTP body can then be then be checked with `soap_http_has_body` and retrieved with `soap_http_get_body`. This function reads input from from `soap::is` when non-NULL, or `soap::socket` when valid, or from `soap::recvfd`, and sets the `len` pointer parameter to the length of the string read if `len` is not NULL. After calling this function, `soap_end_recv` should be called. Returns the HTTP body as a string allocated in managed memory or returns "" (empty string, since version 2.8.71 or returns NULL for previous versions) when no HTTP message body is present or NULL when an error occurred and sets `soap::error`.

Examples:

#include "soapH.h"
int main()
{
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK or SOAP_IO_STORE
char *response = NULL;
size_t response_len;
if (soap_GET(soap, "http://www.example.com/API/GET", NULL)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
fwrite(response, 1, response_len, stdout);
soap_closesock(soap);
}
#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->fput = my_put; // HTTP PUT handler to serve HTTP PUT
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int my_put(struct soap *soap)
{
size_t len;
char *message = soap_http_get_body(soap, &len);
soap_end_recv(soap);
... // use the message data
return soap_send_empty_response(soap, 202); // HTTP 202 Accepted
}

See also
  Callback functions, `soap_begin_recv`, `soap_end_recv`, `soap_http_has_body`, `soap_GET`, `soap_POST`, `soap::fput`, `soap::fpatch`, `http_post`.

Returns
  HTTP body as a string or NULL when an error occurred

Parameters

  soap | `soap` context
  len | pointer to the length variable to assign or NULL

char* soap_http_get_form | ( | struct soap * | soap | ) |

Get the HTTP POST application/x-www-form-urlencoded data as a string.

This function parses an HTTP body with application/x-www-form-urlencoded data into a string, prepends a `?`, and returns this string allocated in managed memory or NULL when an error occurred and sets `soap::error`.

Note
  This function is declared and defined in `gsoap/plugin/httpform.h` and `gsoap/plugin/httpform.c` and requires the `http_form` plugin.

See also
  `http_form`.

Parameters

  soap | `soap` context

void soap_http_get_stats | ( | struct soap * | soap,
|  | size_t * | stat_get,
|  | size_t * | stat_post,
|  | size_t * | stat_fail,
|  | size_t ** | hist_min,
|  | size_t ** | hist_hour,
|  | size_t ** | hist_day
| ) |  |

Collect access statistics with the `http_get` plugin.

This function sets the specified minutes, hour, and day parameters to point to an array of requests per minute, an array of request per hour, and an array of requests per day of the year. The minutes array has 60 entries, the hour array has 24 entries, and the day array has 365 entries (a leap year will roll over). The plugin will collect the stats among a set of server threads if the spawned thread contexts are created with `soap_copy`.

Note
  This function is declared and defined in `gsoap/plugin/httpget.h` and `gsoap/plugin/httpget.c` and requires the `http_get` plugin.

Example:

#include "soapH.h"
#include "plugin/httpget.h"
int main()
{
struct soap *soap = soap_new();
soap_register_plugin_arg(soap, http_get, http_get_handler);
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
size_t stat_get, stat_post, stat_fail, *hist_min, *hist_hour, *hist_day;
if (soap_valid_socket(soap_accept(soap)))
{
if (soap_serve(soap))
soap_print_fault(soap, stderr);
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_http_get_stats(soap, &stat_get, &stat_post, &stat_fail, &hist_min, &hist_hour, &hist_day);
// show the number of GET, POST, and failures
printf("\n#GET = %d #POST = %d failures = %d", stat_get, stat_post, stat_fail);
// show the stats collected per hour
printf("\nBy hour: ");
for (i = 0; i < 24; i++)
printf("%8d", i);
printf("\nRequests:");
for (i = 0; i < 24; i++)
printf("%8d", hist_hour[i]);
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
}

Parameters

  soap | `soap` context
  stat_get | points to a variable to assign the number of GET requests
  stat_post | points to a variable to assign the number of POST requests
  stat_fail | points to a variable to assign the number of failed requests
  hist_min | points to a pointer to an array of 60 entries with histogram of requests per minute
  hist_hour | points to a pointer to an array of 24 entries with histogram of requests per hour
  hist_day | points to a pointer to an array of 365 entries with histogram of requests per day

int soap_http_has_body | ( | struct soap * | soap | ) |

Check if HTTP body message is not empty.

This function returns nonzero if an HTTP message body is present, zero otherwise. This function should be called immediately after calling `soap_begin_recv`. Note that `soap_begin_recv` is called at the server side before a HTTP callback is called, such as `soap::fput` and `soap::fpatch`. Callbacks and the `http_post` HTTP POST plugin handlers should therefore not call `soap_begin_recv`. Also, `soap_begin_recv` is called at the client side by HTTP functions such as `soap_GET`, after which the HTTP body can then be checked with `soap_http_has_body` and retrieved with `soap_http_get_body`.

See also
  Callback functions, `soap_begin_recv`, `soap_end_recv`, `soap_http_get_body`, `soap_GET`, `soap_POST`, `soap::fput`, `soap::fpatch`, `http_post`.

Returns
  nonzero if an HTTP body is present, zero otherwise

Parameters

  soap | `soap` context

int soap_PATCH | ( | struct soap * | soap,
|  | const char * | endpoint,
|  | const char * | action,
|  | const char * | type
| ) |  |

HTTP PATCH content to server.

This function connects to the server specified by the `endpoint` URL string, using HTTP PATCH and the HTTP SOAP Action header specified by the `action` string (or NULL). The HTTP content type of the data sent to the server is specified by `type`. If the mode is not `SOAP_IO_CHUNK` (preferred) or `SOAP_IO_STORE` then this function temporarily sets the mode of the context to `SOAP_IO_STORE` to compute the HTTP content length. Upon successful completion, messages can be sent to the server and an empty response should be received by calling `soap_recv_empty_response`. Returns `SOAP_OK` or a `soap_status` error code.

If the `soap::http_content` string is non-NULL, this string is used as the HTTP content type to be included in the HTTP header. Otherwise, the HTTP content header is `text/xml` by default. The `soap::http_content` string is automatically reset to NULL after the HTTP POST call and has to be set again for the next call.

This function is used by the soapcpp2-generated `soap_PATCH_T` functions for types `T` to HTTP PATCH the XML serialized value of type `T` to a server.

To implement server-side HTTP PATCH handling use `soap::fpatch`.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK (preferred) or SOAP_IO_STORE
if (soap_PATCH(soap, "http://www.example.com/API/PATCH", NULL, "application/json; charset=utf-8")
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap)
|| soap_recv_empty_response(soap))
soap_print_fault(soap, stderr);
soap_closesock(soap);

See also
  `soap::connect_flags`, `soap::connect_timeout`, `soap::recv_timeout`, `soap::send_timeout`, `soap::transfer_timeout`, `soap::recv_maxlength`, `soap::http_content`, `soap_GET`, `soap_PUT`, `soap_POST`, `soap_DELETE`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  endpoint | URL string
  action | SOAP Action string or NULL
  type | HTTP content type string

int soap_poll | ( | struct soap * | soap | ) |

Poll the connection.

This function returns `SOAP_OK` if the connection is ready to send and receive data, `SOAP_EOF` otherwise. Also returns `SOAP_OK` if the socket connection is closed but data can still be read or written from/to other streams.

See also
  `soap_ready`.

Returns
  `SOAP_OK` (ready), `SOAP_EOF` (not ready), or `SOAP_TCP_ERROR` (error)

Parameters

  soap | `soap` context

int soap_POST | ( | struct soap * | soap,
|  | const char * | endpoint,
|  | const char * | action,
|  | const char * | type
| ) |  |

HTTP POST content to server.

This function connects to the server specified by the `endpoint` URL string, using HTTP POST and the HTTP SOAP Action header specified by the `action` string (or NULL). The HTTP content type of the data sent to the server is specified by `type`. If the mode is not `SOAP_IO_CHUNK` (preferred) or `SOAP_IO_STORE` then this function temporarily sets the mode of the context to `SOAP_IO_STORE` to compute the HTTP content length. Upon successful completion, messages can be sent to and received from the server. Returns `SOAP_OK` or a `soap_status` error code.

If the `soap::http_content` string is non-NULL, this string is used as the HTTP content type to be included in the HTTP header. Otherwise, the HTTP content header is `text/xml` by default. The `soap::http_content` string is automatically reset to NULL after the HTTP POST call and has to be set again for the next call.

This function is used by the soapcpp2-generated `soap_POST_send_T` functions for types `T` to HTTP POST the XML serialized value of type `T` to a server. Use `soap_POST_recv_T` to receive a HTTP POST response deserialized into a value of (another) type `T`.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK (preferred) or SOAP_IO_STORE
char *response = NULL;
size_t response_len;
if (soap_POST(soap, "http://www.example.com/API/POST", NULL, "application/json; charset=utf-8")
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| (response = soap_http_get_body(soap, &response_len)) != NULL
|| soap_end_recv(soap))
soap_print_fault(soap, stderr);
else
printf("%s", response);
soap_closesock(soap);

See also
  `soap::connect_flags`, `soap::connect_timeout`, `soap::recv_timeout`, `soap::send_timeout`, `soap::transfer_timeout`, `soap::recv_maxlength`, `soap::http_content`, `soap_GET`, `soap_PUT`, `soap_PATCH`, `soap_DELETE`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  endpoint | URL string
  action | SOAP Action string or NULL
  type | HTTP content type string

int soap_PUT | ( | struct soap * | soap,
|  | const char * | endpoint,
|  | const char * | action,
|  | const char * | type
| ) |  |

HTTP PUT content to server.

This function connects to the server specified by the `endpoint` URL string, using HTTP PUT and the HTTP SOAP Action header specified by the `action` string (or NULL). The HTTP content type of the data sent to the server is specified by `type`. If the mode is not `SOAP_IO_CHUNK` (preferred) or `SOAP_IO_STORE` then this function temporarily sets the mode of the context to `SOAP_IO_STORE` to compute the HTTP content length. Upon successful completion, messages can be sent to the server and an empty response should be received by calling `soap_recv_empty_response`. Returns `SOAP_OK` or a `soap_status` error code.

If the `soap::http_content` string is non-NULL, this string is used as the HTTP content type to be included in the HTTP header. Otherwise, the HTTP content header is `text/xml` by default. The `soap::http_content` string is automatically reset to NULL after the HTTP POST call and has to be set again for the next call.

This function is used by the soapcpp2-generated `soap_PUT_T` functions for types `T` to HTTP PUT the XML serialized value of type `T` to a server.

To implement server-side HTTP PUT handling use `soap::fput`.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK); // use SOAP_IO_CHUNK (preferred) or SOAP_IO_STORE
if (soap_PUT(soap, "http://www.example.com/API/PUT", NULL, "text/xml; charset=utf-8")
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_send(soap)
|| soap_recv_empty_response(soap))
soap_print_fault(soap, stderr);
soap_closesock(soap);

See also
  `soap::connect_flags`, `soap::connect_timeout`, `soap::recv_timeout`, `soap::send_timeout`, `soap::transfer_timeout`, `soap::recv_maxlength`, `soap::http_content`, `soap_GET`, `soap_PATCH`, `soap_POST`, `soap_DELETE`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  endpoint | URL string
  action | SOAP Action string or NULL
  type | HTTP content type string

int soap_putheader | ( | struct soap * | soap | ) |

Emit the SOAP Header pointed to by `soap::header`

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

char* soap_query | ( | struct soap * | soap | ) |

Extract the query string from the URL path at the server side with the `http_get` plugin.

At the server side the value `soap::path` is set to the URL's path string which may include a query string of the form "?key=val&key=val" with a sequence of key=val pairs, where the value is optional. Returns the query string or NULL when none is present. To extract the keys and values from the string returned by this function, use `soap_query_key` and `soap_query_val`.

The `http_get` plugin sets a HTTP GET handler function to serve HTTP GET requests (or NULL to remove a handler) with `soap_register_plugin_arg(soap, http_get, http_get_handler)` and keeps track of the number of GET and POST invocations made and the number of server requests by the minute, by the hour, and by the day.

Note
  This function is declared and defined in `gsoap/plugin/httpget.h` and `gsoap/plugin/httpget.c` and requires the `http_get` plugin.

Example:

#include "soapH.h"
#include "plugin/httpget.h"
int main()
{
struct soap *soap = soap_new();
soap_register_plugin_arg(soap, http_get, http_get_handler);
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
size_t *min, *hour, *day;
if (soap_valid_socket(soap_accept(soap)))
{
if (soap_serve(soap))
soap_print_fault(soap, stderr);
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);
}
int http_get_handler(struct soap *soap)
{
if (!strncmp(soap->path, "/API/GET", 8))
{
// get the query key=val pairs from soap->path
char *query = soap_query(soap);
while (query)
{
// get next key=val pair
char *key = soap_query_key(soap, &query);
char *val = soap_query_key(soap, &query);
... // use key and val (key is non-NULL, val may be NULL)
}
// return a response message
soap->http_content = "application/json; charset=utf-8";
if (soap_response(soap, SOAP_FILE)
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
return 404; // HTTP 404 Not Found
}
int ns__webmethod(struct soap *soap, ...)
{
char *query = soap_query(soap);
while (query)
{
// get next key=val pair
char *key = soap_query_key(soap, &query);
char *val = soap_query_key(soap, &query);
... // use key and val (key is non-NULL, val may be NULL)
}
...
}

See also
  `soap_query_key`, `soap_query_val`, `soap_http_get_stats`.

Parameters

  soap | `soap` context

char* soap_query_key | ( | struct soap * | soap,
|  | char ** | query
| ) |  |

Extract the next query string key at the server side with the `http_get` plugin.

This function takes a pointer to the string variable returned by `soap_query` and updates it to point to the value (if present), then returns the query key or NULL if no more query key-value pairs are present in the query string.

Note
  This function is declared and defined in `gsoap/plugin/httpget.h` and `gsoap/plugin/httpget.c` and requires the `http_get` plugin.

Example:

// get the query key=val pairs from soap->path
char *query = soap_query(soap);
while (query)
{
// get next key=val pair
char *key = soap_query_key(soap, &query);
char *val = soap_query_key(soap, &query);
... // use key and val (key is non-NULL, val may be NULL)
}

See also
  `soap_query`, `soap_query_val`.

Returns
  query string key

Parameters

  soap | `soap` context
  query | points to the string returned by soap_query and soap_query_val

char* soap_query_val | ( | struct soap * | soap,
|  | char ** | query
| ) |  |

Extract the next query string value at the server side with the `http_get` plugin.

This function takes a pointer to the string variable returned by `soap_query` and updates it to point to the next key (if present), then returns the query value or NULL if no value is bound to the key.

Note
  This function is declared and defined in `gsoap/plugin/httpget.h` and `gsoap/plugin/httpget.c` and requires the `http_get` plugin.

Example:

// get the query key=val pairs from soap->path
char *query = soap_query(soap);
while (query)
{
// get next key=val pair
char *key = soap_query_key(soap, &query);
char *val = soap_query_key(soap, &query);
... // use key and val (key is non-NULL, val may be NULL)
}

See also
  `soap_query`, `soap_query_key`.

Returns
  query string value or NULL

Parameters

  soap | `soap` context
  query | points to the string returned by soap_query and soap_query_key

int soap_ready | ( | struct soap * | soap | ) |

Check if the connection is ready to receive pending data.

This function returns `SOAP_OK` if the connection is ready to receive pending data, `SOAP_EOF` otherwise. Also returns `SOAP_OK` if the socket connection is closed but data can still be read from other streams.

Examples:

// file.h interface header file for soapcpp2
// REST request data
struct ns__request
{
int SKU;
};
// REST response data
struct ns__response
{
char *product_name;
};
// SOAP web method response data
struct ns__webmethodResponse
{
char *string;
int number;
};
// SOAP web method
int ns__webmethod(char *string, int number, struct ns__webmethodResponse *response);

    soapcpp2 -c file.h

// SOAP client application (requires 2.8.75 or greater)
#include "soapH.h"
#include "ns.nsmap"
int main()
{
struct soap *soap = soap_new();
struct ns__webmethodResponse response;
// send the SOAP request message of ns__webmethod declared in a .h file for soapcpp2
if (soap_send_ns__webmethod(soap, endpoint, NULL, "hello", 123))
... // error
// wait on message ready to receive from server
while (soap_ready(soap) == SOAP_EOF)
{
// do some more work here (or sleep 1ms as below)
usleep(1000);
}
if (soap->error)
... // error
// receive the SOAP response message of ns__webmethod declared in a .h file for soapcpp2
if (soap_recv_ns__webmethod(soap, &response))
... // error
... // process the response
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
}
// REST POST client application
#include "soapH.h"
#include "ns.nsmap"
int main()
{
struct soap *soap = soap_new();
struct ns__request request; // serializable type declared in a .h file for soapcpp2
struct ns__response response; // serializable type declared in a .h file for soapcpp2
soap_default_ns__request(soap, &request);
... // populate request data
// POST the REST request message using the ns__request serializer
if (soap_POST_send_ns__request(soap, endpoint, &request))
... // error
// wait on message ready to receive from server
while (soap_ready(soap) == SOAP_EOF)
{
// do some more work here (or sleep 1ms as below)
usleep(1000);
}
if (soap->error)
... // error
// receive the REST response message using the ns__response serializer
if (soap_POST_recv_ns__response(soap, &response))
... // error
... // process the response data
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
}
// REST GET client application
#include "soapH.h"
#include "ns.nsmap"
int main()
{
struct soap *soap = soap_new();
struct ns__response response; // serializable type declared in a .h file for soapcpp2
// HTTP GET
if (soap_GET(soap, "http://www.exanple.org/get?SKU=123", NULL))
... // error
// wait on message ready to receive from server
while (soap_ready(soap) == SOAP_EOF)
{
// do some more work here (or sleep 1ms as below)
usleep(1000);
}
if (soap->error)
... // error
// receive the response message using the ns__response serializer
if (soap_read_ns__response(soap, &response))
{
soap_closesock(soap);
... // error
}
soap_closesock(soap);
... // process the response data
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
}

See also
  `soap_poll`.

Returns
  `SOAP_OK` (ready), `SOAP_EOF` (not ready), or `SOAP_TCP_ERROR` (error)

Parameters

  soap | `soap` context

int soap_recv_empty_response | ( | struct soap * | soap | ) |

Receive an HTTP response message from the server that is assumed to be empty.

This function receives an HTTP response message from the server and is typically used when HTTP 202 Accepted or HTTP 200 OK is expected without data. Therefore the HTTP response message body is assumed to be empty. If the message is not empty then a fault message with the HTTP body as the fault string will be produced and the `soap::error` is set to the HTTP status code received. This function reads input from `soap::is` when non-NULL, or from `soap::socket` when valid, or from `soap::recvfd`. Returns `SOAP_OK` or a `soap_status` error code such as the HTTP status code received.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_recv_fault | ( | struct soap * | soap,
|  | int | check
| ) |  |

Parse and deserialize the SOAP Fault.

This function parses and deserializes the SOAP Fault such that `soap::fault` points to a `SOAP_ENV__Fault` structure. If the specified `check` parameter is nonzero, this function attempts to parse the SOAP Fault that may be present (it checks), but if no `SOAP-ENV:Fault` element is present returns `SOAP_OK`. If the specified `check` parameter is zero, this function parses the SOAP Fault that is expected to be present, but if `SOAP-ENV:Fault` element is present returns the HTTP error code received (when between 300 and 599) or the `soap::error` code.

Returns
  a nonzero `soap_status` error code

Parameters

  soap | `soap` context
  check | flag to check or expect a SOAP Fault

int soap_recv_header | ( | struct soap * | soap | ) |

Parse and deserialize the SOAP Header.

This function parses and deserializes the SOAP Header such that `soap::header` points to a `SOAP_ENV__Header` structure.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_response | ( | struct soap * | soap,
|  | int | status
| ) |  |

Initialize the context for server-side sending and send a HTTP response header.

This function initializes the context for sending at the server side and sends a HTTP response header with the specified `status` code. The `status` code parameter controls the behavior of the HTTP header sent and how the message should be send after calling this function:

- `SOAP_OK` sends a HTTP 200 OK header with HTTP content type "text/xml" and the HTTP content length value of `soap::count` or chunked transfer encoding if the `SOAP_IO_CHUNK` mode is set, i.e. chunked transfers avoid having to compute `soap::count` such as by sending the message twice, the first time to compute the message length using `soap_begin_count` and `soap_end_count`.
- HTTP codes 200 to 599 sends the corresponding HTTP header with HTTP content type "text/xml" and the HTTP content length value of `soap::count` or chunked transfer encoding if the `SOAP_IO_CHUNK` mode is set.
- `SOAP_HTML` sends a HTTP 200 OK header with HTTP content type "text/html" and sets the context to `SOAP_IO_STORE` to accumulate the message in memory to determine the HTTP content length.
- `SOAP_FILE` sends a HTTP 200 OK header with HTTP content type `soap::http_content` and if the `SOAP_IO_CHUNK` mode is not set, sets the context to `SOAP_IO_STORE` to accumulate the message in memory to determine the HTTP content length.
- `SOAP_FILE + status` where `status` is a HTTP status code between 200 and 599, sends the corresponding HTTP header with HTTP content type `soap::http_content` and f the `SOAP_IO_CHUNK` mode is not set, sets the context to `SOAP_IO_STORE` to accumulate the message in memory to determine the HTTP content length. This function returns `SOAP_OK` or a `soap_status` error code when an error occurred.

Besides `soap_response`, other options to return a HTTP status code are:

- Return the value of `soap_send_empty_response` to produce an empty HTTP response message with the specified HTTP status code.
- Likewise, return a HTTP status code between 200 and 299 directly to produce an empty HTTP response message with the given HTTP status code.
- Return a HTTP status code between 300 and 599 directly to produce an HTTP response message with the given HTTP status code and a SOAP Fault message body.

Examples:

#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->fget = my_get; // HTTP GET handler to serve HTTP GET
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int my_get(struct soap *soap)
{
soap_set_omode(SOAP_IO_CHUNK); // make sure to chunk the transfers because we do not compute the content length
// serve HTTP GET request that has path /xml so in this example we respond with XML
if (strcmp(soap->path, "/xml") == 0)
{
if (soap_response(soap, SOAP_OK)
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
// serve HTTP GET request that has path /html so in this example we respond with HTML
if (strcmp(soap->path, "/html") == 0)
{
if (soap_response(soap, SOAP_HTML)
|| soap_send(soap, "<html><head><title>Example</title></head><body>Some text</body></html>\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
// serve HTTP GET request that has path /json so in this example we respond with JSON
if (strcmp(soap->path, "/json") == 0)
{
soap->http_content = "application/json; charset=utf-8";
if (soap_response(soap, SOAP_FILE)
|| soap_send(soap, "{ \"title\": \"Example\", \"doc\": \"Some text\" }\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
// respond with HTTP 400 Bad Request and HTML message
soap->http_content = "text/html; charset=utf-8";
if (soap_response(soap, SOAP_FILE + 400)
|| soap_send(soap, "<html><body>Bad Request</body></html>\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->fget = my_get; // HTTP GET handler to serve HTTP GET
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int my_get(struct soap *soap)
{
// serve HTTP GET request, here we compute the content length instead of chunked transfer
if (soap_begin_count(soap)
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_count(soap)
|| soap_response(soap, SOAP_OK)
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_send(soap))
return soap_closesock(soap);
return SOAP_OK;
}
#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->fget = my_get; // HTTP GET handler to serve HTTP GET
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int my_get(struct soap *soap)
{
FILE *fd = NULL;
char *s = strchr(soap->path, '?');
if (!s || strcmp(s, "?wsdl"))
return SOAP_GET_METHOD;
fd = fopen("myservice.wsdl", "rb");
if (!fd)
return 404; // return HTTP 404 Not Found
soap->http_content = "text/xml";
soap_set_omode(SOAP_IO_CHUNK);
if (soap_response(soap, SOAP_FILE) == SOAP_OK)
{
while (1)
{
size_t r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), fd);
if (!r || soap_send_raw(soap, soap->tmpbuf, r))
break;
}
}
fclose(fd);
soap_end_send(soap);
return soap_closesock(soap);
}

See also
  `soap_bind`, `soap_accept`, `soap_serve`, `soap_send_empty_response`, `soap::fget`, `soap::fput`, `soap::fpatch`, `soap::fdel`, `soap::fopt`, `soap::fhead`, `soap::http_extra_header`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  status | HTTP status code 200 to 599 or `SOAP_OK` (same as 200 OK) or `SOAP_HTML` or `SOAP_FILE`

int soap_send | ( | struct soap * | soap,
|  | const char * | s
| ) |  |

Send a string.

This function sends a 0-terminated string to `soap::os` when non-NULL, or to `soap::socket` when valid, or or to `soap::sendfd` when nonzero.

See also
  `soap_begin_count`, `soap_end_count`, `soap_begin_send`, `soap_end_send`, `soap_send_raw`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  s | 0-terminated string to send

int soap_send_empty_response | ( | struct soap * | soap,
|  | int | status
| ) |  |

Return an HTTP response message with an empty HTTP body from a service back to the client or peer.

This function sends an empty response back to the client. The response includes the specified `status` HTTP status code in the HTTP header but the HTTP body is empty. This function should be used with HTTP PUT or PATCH requests and "one-way" SOAP messaging with HTTP POST. This function sends to `soap::socket` when valid, or to `soap::os` when non-NULL, or to `soap::sendfd`. Returns `SOAP_STOP` and sets `soap::error` to `SOAP_STOP` to halt further response messaging to the client or a `soap_status` error code when the message could not be sent.

Besides `soap_send_empty_response`, other options to return an HTTP status code are:

- Use `soap_response` using `SOAP_FILE + status` to produce an HTTP response message with the specified HTTP status code.
- Return a HTTP status code between 200 and 299 directly to produce an empty HTTP response message with the given HTTP status code.
- Return a HTTP status code between 300 and 599 directly to produce an HTTP response message with the given HTTP status code and a SOAP Fault message body.

Examples:

#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->fput = my_put; // HTTP PUT handler to serve HTTP PUT
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int my_put(struct soap *soap)
{
size_t len;
char *message = soap_http_get_body(soap, &len);
soap_end_recv(soap);
... // use the message data
return soap_send_empty_response(soap, 202); // HTTP 202 Accepted
}
#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->fput = my_put; // HTTP PUT handler to serve HTTP PUT
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int my_put(struct soap *soap)
{
if (soap->http_content && soap_tag_cmp(soap->http_content, "text/xml*") == 0)
{
soap_dom_element *dom = soap_new_xsd__anyType(soap);
// get dom, don't use soap_read_xsd__anyType because we are already reading from a socket
if (soap_in_xsd__anyType(soap, "doc", dom, NULL) == SOAP_OK)
{
... // inspect the DOM using the DOM API functions
return soap_send_empty_response(soap, 202); // HTTP 202 Accepted
}
}
return soap_send_empty_response(soap, 400); // HTTP 400 Bad Request
}

See also
  `soap_bind`, `soap_accept`, `soap_serve`, `soap_response`, `soap::fget`, `soap::fput`, `soap::fpatch`, `soap::fdel`, `soap::fopt`, `soap::fhead`.

Returns
  `SOAP_STOP`

Parameters

  soap | `soap` context
  status | HTTP status code 200 to 599 or `SOAP_OK` (same as 200 OK)

int soap_send_fault | ( | struct soap * | soap | ) |

Return an HTTP error with a SOAP Fault message from a service.

This function sends an error response back to the client and is used at the server side by `soap_serve` after an error occurred to propagate the fault to the client. This function sends to `soap::socket` when valid, or to `soap::os` when non-NULL, or to `soap::sendfd`.

Returns
  the value of `soap::error`, a nonzero error code

Parameters

  soap | `soap` context

int soap_send_raw | ( | struct soap * | soap,
|  | const char * | s,
|  | size_t | n
| ) |  |

Send raw bytes.

This function sends raw bytes of data to `soap::os` when non-NULL, or to `soap::socket` when valid, or or to `soap::sendfd` when nonzero.

See also
  `soap_begin_count`, `soap_end_count`, `soap_begin_send`, `soap_end_send`, `soap_send_raw`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  s | data to send
  n | length of data to send

void soap_serializeheader | ( | struct soap * | soap | ) |

Serialize the SOAP Header pointed to by `soap::header` before emitting it with `soap_putheader`

Parameters

  soap | `soap` context

int soap_serve | ( | struct soap * | soap | ) |

Serve a pending request.

This function is auto-generated by soapcpp2 and serves the pending request on `soap::socket` or on standard input/output `soap::recvfd` and `soap::sendfd`, e.g. for CGI and FastCGI services. Returns `SOAP_OK` or a `soap_status` error code.

This auto-generated function implements the following behavior:

#include "soapH.h"
int soap_serve(struct soap *soap)
{
// keep socket open for HTTP keep-alive for maximum of soap->max_keep_alive iterations when nonzero
soap->keep_alive = soap->max_keep_alive + 1;
do
{
if (soap->keep_alive > 0 && soap->max_keep_alive > 0)
soap->keep_alive--;
// parse HTTP headers and call GET, PUT, PATCH or DELETE callback when set
if (soap_begin_serve(soap))
{
if (soap->error >= SOAP_STOP) // request was handled by plugin handler
continue; // so continue the keep-alive loop
return soap->error;
}
// call soap_serve_request generated by soapcpp2 to dispatch the SOAP/XML request
if ((soap_serve_request(soap) || (soap->fserveloop && soap->fserveloop(soap)))
&& soap->error
&& soap->error < SOAP_STOP)
return soap_send_fault(soap);
} while (soap->keep_alive);
return SOAP_OK;
}

The `soap_begin_serve` function processes the HTTP headers and XML SOAP headers if present. The `soap_serve_request` function is auto-generated by soapcpp2, when applicable, and parses the SOAP/XML request element to dispatch the SOAP/XML request to a service operation.

If soapcpp2 is not used or does not generate `soap_serve` but `soap_serve` is required to serve non-SOAP requests, for example to serve JSON or GET/PUT/PATCH/DELETE requests, then the following simplified `soap_serve` implementation works just fine:

#include "soapH.h"
int soap_serve(struct soap *ctx)
{
soap->keep_alive = soap->max_keep_alive + 1;
do
{
if (soap->keep_alive > 0 && soap->max_keep_alive > 0)
soap->keep_alive--;
// parse HTTP headers and call GET, PUT, PATCH or DELETE callback when set
if (soap_begin_serve(soap))
{
if (soap->error >= SOAP_STOP) // request was handled by plugin handler
continue; // so continue the keep-alive loop
return soap->error;
}
soap->error = 400; // Bad Request because we aren't serving anything else
return soap_send_fault(soap); // so we report an error
} while (soap->keep_alive);
return SOAP_OK;
}

Example:

#include "soapH.h"
struct soap *soap = soap_new();
soap->accept_timeout = 3600; // exit loop when no request arrives in one hour
soap->send_timeout = soap_recv_timeout = 5; // 5 seconds max socket stall time (unlimited by default)
soap->transfer_timeout = 30; // 30 seconds max message transfer time (unlimited by default)
soap->recv_maxlength = 1048576; // limit messages received to 1MB (2GB by default)
if (soap_valid_socket(soap_bind(soap, NULL, PORTNUM, BACKLOG)))
{
while (1)
{
if (soap_valid_socket(soap_accept(soap)))
{
if (soap_serve(soap))
soap_print_fault(soap, stderr);
}
else if (soap->errnum) // accept failed, try again after 1 second
{
soap_print_fault(soap, stderr);
sleep(1);
}
else // accept timed out, quit looping
{
break;
}
soap_destroy(soap);
soap_end(soap);
}
}
soap_free(soap);

See also
  `WITH_IPV6`, `WITH_IPV6_V6ONLY`, `SOAP_IO_UDP`, `soap::accept_flags`, `soap::bind_flags`, `soap::bind_inet6`, `soap::bind_v6only`, `soap::rcvbuf`, `soap::sndbuf`, `soap::master`, `soap_bind`, `soap_accept`, `soap_ssl_accept`, `soap::keep_alive`, `soap::max_keep_alive`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

int soap_serve_request | ( | struct soap * | soap | ) |

Process a pending request.

This function is auto-generated by soapcpp2 and parses the SOAP/XML request element to dispatch the SOAP/XML request to a service operation. Returns `SOAP_OK` or a `soap_status` error code.

See also
  `soap_serve`, `soap_begin_serve`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context