Genivia - MIME attachment functions

|  | Home | Documentation | MIME attachment functions updated Mon Apr 22 2024 by Robert van Engelen |

- Main Page
- Modules
- Classes
- Files

Classes | Enumerations | Functions
MIME attachment functions

This module defines functions to set and get MIME/MTOM attachments. More...

## Classes
struct | soap_mime
| Stores a linked list of MIME attachments received. More...
struct | soap_multipart
| DIME/MIME/MTOM attachment data received by the engine. More...

## Enumerations
enum | soap_mime_encoding { SOAP_MIME_NONE, SOAP_MIME_7BIT, SOAP_MIME_8BIT, SOAP_MIME_BINARY, SOAP_MIME_QUOTED_PRINTABLE, SOAP_MIME_BASE64, SOAP_MIME_IETF_TOKEN, SOAP_MIME_X_TOKEN }
| RFC2045 MIME content transfer encodings. More...

## Functions
int | soap_set_mime_attachment (struct soap *soap, const char *ptr, size_t size, enum soap_mime_encoding encoding, const char *type, const char *id, const char *location, const char *description)
| Add a MIME attachment to the SOAP/XML message. More...
int | soap_set_mime (struct soap *soap, const char *boundary, const char *start)
| Enable MIME attachments. More...
void | soap_clr_mime (struct soap *soap)
| Disable MIME attachments. More...
int | soap_post_check_mime_attachments (struct soap *soap)
| Enable post-processing of MIME/MTOM attachments. More...
int | soap_check_mime_attachments (struct soap *soap)
| Check for a MIME/MTOM attachment. More...
struct soap_multipart * | soap_recv_mime_attachment (struct soap *soap, void *handle)
| Get a MIME/MTOM attachment. More...

## Detailed Description

This module defines functions to set and get MIME/MTOM attachments.

To enable MIME or MTOM, first initialize the `soap` context with `SOAP_ENC_MIME` (for MIME) or `SOAP_ENC_MTOM` (for MTOM) using `soap_new1`, `soap_init1`, `soap_set_mode`, or `soap_set_mime` to enable MIME and also to set a start id. To disable MIME use `soap_clr_mime`.

There are two ways to add MIME/MTOM attachments to SOAP/XML messages for sending:

- use `soap_set_mime_attachment` to explicitly add an attachment that contains the specified source of data;
- use `xsd__base64Binary` (MIME and MTOM) or `_xop__Include` (MTOM) structures in the serializable data of a SOAP/XML message, where the specified data is serialized in MIME/MTOM attachments automatically when one of the `id`, `type` or `options` member variables are non-NULL.

Both methods also support streaming MIME attachments to send using the `soap::fmimereadopen`, `soap::fmimeread`, and `soap::fmimereadclose` callbacks that fetch the data to send, where a user-defined handle should be specified for the `ptr` parameter of `soap_set_mime_attachment` or the `xsd__base64Binary::__ptr` member variable instead of a pointer to the actual data. This handle can be used by the callbacks to fetch the specific data to transmit.

Receiving MIME/MTOM attachments attached to SOAP/XML messages is automatic. The MIME/MTOM attachments are converted to binary data and stored in the `xsd__base64Binary` structures that reference the MIME/MTOM attachments via the `xsd__base64Binary::id` string, meaning that the `xsd__base64Binary::__ptr` (points to the data) and `xsd__base64Binary::__size` (data length) are populated automatically with the MIME/MTOM binary data. However, if the streaming MIME callbacks `soap::fmimewriteopen`, `soap::fmimewrite`, and `soap::fmimewriteclose` are defined then the attachments are streamed to these callbacks instead.

For example, to send and receive a SOAP/XML message with MIME attachments using a serializable `xsd__base64Binary` structure:

// example .h file for soapcpp2
//gsoap ns service name: example
//gsoap ns service namespace: urn:example
struct xsd__base64Binary {
unsigned char *__ptr; // pointer to binary data
int __size; // size of the binary data
char *id; // NULL to generate an id or assign this member variable a unique UUID
char *type; // MIME type of the data
char *options; // DIME options or an optional description of the MIME attachment
};
int ns__webmethod(struct xsd__base64Binary *data, struct xsd__base64Binary *result);
// example client implementation based on the above example .h file for soapcpp2
#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
struct xsd__base64Binary data, result;
data.__ptr = ...; // points to binary image data to send
data.__size = ...; // size of the image data to send
data.id = soap_strdup(soap, soap_rand_uuid(soap, NULL));
data.type = "image/jpg";
data.options = "A picture";
if (soap_call_ns__webmethod(soap, endpoint, NULL, &data, &result))
soap_print_fault(soap, stderr);
else
... // success, use the result
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
}
// example service implementation based on the above example .h file for soapcpp2
#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
... // serve requests with soap_bind, soap_accept, soap_ssl_accept, and soap_serve
}
int ns__webmethod(struct soap *soap, struct xsd__base64Binary *data, struct xsd__base64Binary *result)
{
// echo back the structure (as a MIME attachment)
result->__ptr = data->__ptr;
result->__size = data->__size;
retult->id = data->id;
retult->type = data->type;
retult->options = data->options;
return SOAP_OK;
}

To send MIME attachments without SOAP/XML (i.e. with REST methods), simply add attachments with `soap_set_mime_attachment`. The `soap_end_send` function then adds the attachments before finalizing the message transmission. To receive MIME attachments without SOAP/XML (i.e. with REST methods), simply call `soap_begin_recv` (not needed at the server side since this is already called to parse the HTTP header) and `soap_end_recv`.

For example a client-side multipart-related POST operation that sends a multipart-related message with one MIME attachment and receives a message consisting of multipart-related MIME attachments:

#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
const char *ptr = "<attached>Some attached text</attached>";
size_t size = strlen(ptr);
soap_set_mime(soap, NULL, "body");
soap_set_mime_attachment(soap, ptr, size, SOAP_MIME_NONE, "text/xml", "attach1", NULL, NULL);
if (soap_POST(soap, "http://", NULL, "text/xml")
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>")
|| soap_end_send(soap)
|| soap_begin_recv(soap)
|| soap_end_recv(soap))
{
soap_print_fault(soap, stderr);
}
else
{
int n = 0;
struct soap_multipart *attachment;
for (attachment = soap->mime.list; attachment; attachment = attachment->next)
{
++n;
printf("Part %d:\n", n);
printf("ptr =%p\n", attachment->ptr);
printf("size =%ul\n", attachment->size);
printf("id =%s\n", attachment->id ? attachment->id : "");
printf("type =%s\n", attachment->type ? attachment->type : "");
printf("location =%s\n", attachment->location ? attachment->location : "");
printf("description=%s\n", attachment->description ? attachment->description : "");
}
}
soap_clr_mime(soap);
}

In C++ you can use an iterator for the last part of this example:

struct soap *soap = soap_new();
... // call soap_POST etc
int n = 0;
for (soap_multipart::iterator i = soap->mime.begin(); i != soap->mime.end(); ++i)
{
++n;
printf("Part %d:\n", n);
printf("ptr =%p\n", i->ptr);
... // etc
}

At the server side the code to retrieve the REST message sent consisting of a set of multipart-related MIME attachments is the same. To respond with multipart-related MIME attachments use `soap_set_mime` and use `soap_set_mime_attachment` to add attachments. For example:

#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)
{
const char *ptr = "<attached>Some attached text</attached>";
size_t size = strlen(ptr);
soap_set_mime(soap, NULL, "body");
soap_set_mime_attachment(soap, ptr, size, SOAP_MIME_NONE, "text/xml", "attach1", NULL, NULL);
soap->http_content = "text/xml";
if (soap_response(soap, SOAP_FILE)
|| soap_send(soap, "<doc title=\"Example\">Some text</doc>\n")
|| soap_end_send(soap))
return soap_closesock(soap);
soap_clr_mime(soap);
return SOAP_OK;
}

To disable MIME again, use `soap_clr_mime`.

## Enumeration Type Documentation

enum soap_mime_encoding

RFC2045 MIME content transfer encodings.

These values are used by the `soap_set_mime_attachment` function parameter `encoding`.

Warning
  You are responsible to ensure that the MIME/MTOM content conforms to the encoding specified. We recommend `SOAP_MIME_NONE` to transmit any data of any type which is usually the purpose of MIME/MTOM attachments to SOAP/XML.

See also
  `soap_set_mime_attachment`.

Enumerator
SOAP_MIME_NONE | no encoding, raw data content (recommended)
SOAP_MIME_7BIT | 7 bit data content
SOAP_MIME_8BIT | 8 bit data content
SOAP_MIME_BINARY | binary raw data content
SOAP_MIME_QUOTED_PRINTABLE | data is formatted as quoted printable
SOAP_MIME_BASE64 | data is formatted in base64
SOAP_MIME_IETF_TOKEN | data is an IETF token
SOAP_MIME_X_TOKEN | data is an X-token

## Function Documentation

int soap_check_mime_attachments | ( | struct soap * | soap | ) |

Check for a MIME/MTOM attachment.

This function checks the presence of a MIME/MTOM attachment after calling a service operation by returning nonzero when attachments are present. Returns nonzero if attachments are present. Requires `soap_post_check_mime_attachments`.

See also
  `soap_post_check_mime_attachments`.

Returns
  nonzero if MIME/MTOM attachments are present

Parameters

  soap | `soap` context

void soap_clr_mime | ( | struct soap * | soap | ) |

Disable MIME attachments.

This function disables MIME attachments such as after sending a multipart-related message with attachments to switch back to non-multipart-related messaging, unless the data to serialize as a message contains attachments such as `xsd__base64Binary` for MIME attachments and `_xop__Include` for MTOM attachments.

See also
  `soap_set_mime`, `soap_set_mime_attachment`, `SOAP_ENC_MIME`, `SOAP_ENC_MTOM`.

Parameters

  soap | `soap` context

int soap_post_check_mime_attachments | ( | struct soap * | soap | ) |

Enable post-processing of MIME/MTOM attachments.

This function enables post-processing of MTOM/MIME attachments attached to a message and is useful when MIME/MTOM are streamed (asynchronously) by configuring the callbacks `::fmimewriteopen`, `soap::fmimewrite`, and `soap::fmimewriteclose` to write the attachment to memory, file or, other resources. By calling this function, the presence of MIME/MTOM attachments must be explicitly checked after each message is received by calling `soap_check_mime_attachments`. When this function returns nonzero (true), `soap_recv_mime_attachment` must be called repeatedly to retrieve each attachment until this function returns NULL indicating the end of attachments and the channel is closed, or if an error occurred with `soap::error` set to a nonzero `soap_status` error code.

If attachments are not referenced by the SOAP/XML message received, then normallly an error will be produced to indicate that attachments exist that were not converted into binary `xsd__base64Binary` or `_xop__Include` structures (i.e. deserialized from the message by resolving references to MIME/MTOM attachments). This error can be avoided by using `soap_post_check_mime_attachments` to indicate that attachments may appear that cannot be automatically resolved and should be handled explicitly by calling `soap_check_mime_attachments` and `soap_recv_mime_attachment`.

Examples:

#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap_post_check_mime_attachments(soap);
if (soap_call_ns__webmethod(soap, ...))
{
soap_print_fault(soap, stderr); // an error occurred
}
else
{
if (soap_check_mime_attachments(soap))
{
// attachments are present, channel is still open
int n = 0;
do
{
struct soap_multipart *attachment = soap_recv_mime_attachment(soap, NULL);
++n;
printf("Part %d:\n", n);
printf("ptr =%p\n", attachment->ptr);
printf("size =%ul\n", attachment->size);
printf("id =%s\n", attachment->id ? attachment->id : "");
printf("type =%s\n", attachment->type ? attachment->type : "");
printf("location =%s\n", attachment->location ? attachment->location : "");
printf("description=%s\n", attachment->description ? attachment->description : "");
} while (attachment);
if (soap->error)
soap_print_fault(soap, stderr);
}
}
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
}
#include "soapH.h"
int main()
{
struct soap *soap = soap_new();
soap->fmimewriteopen = mime_write_open;
soap->fmimewrite = mime_write;
soap->fmimewriteclose = mime_write_close;
soap_post_check_mime_attachments(soap);
if (soap_call_ns__webmethod(soap, ...))
{
soap_print_fault(soap, stderr); // an error occurred
}
else
{
if (soap_check_mime_attachments(soap))
{
// attachments are present, channel is still open
int n = 0;
do
{
handle = ...; // a 'handle' to pass to the MIME/MTOM callbacks that process the attachment content
++n;
printf("Part %d:\n", n);
printf("ptr =%p\n", attachment->ptr);
printf("size =%ul\n", attachment->size);
printf("id =%s\n", attachment->id ? attachment->id : "");
printf("type =%s\n", attachment->type ? attachment->type : "");
printf("location =%s\n", attachment->location ? attachment->location : "");
printf("description=%s\n", attachment->description ? attachment->description : "");
} while (attachment);
if (soap->error)
soap_print_fault(soap, stderr);
}
}
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
}

Warning
  When `soap_post_check_mime_attachments` is used, every message received must be followed by a call to `soap_check_mime_attachments`. When this function returns nonzero, `soap_check_mime_attachments` must be called repeatedly until this function returns NULL. This sequence of calls is necessary to properly handle messages with and without attachments. The connection is closed if HTTP keep-alive is not enabled. With HTTP keep-alive enabled, this sequence of calls allows the next message to be properly received.

See also
  `soap_check_mime_attachments`, `soap_recv_mime_attachment`, `soap::fmimewriteopen`, `soap::fmimewrite`, `soap::fmimewriteclose`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context

struct soap_multipart* soap_recv_mime_attachment | ( | struct soap * | soap,
|  | void * | handle
| ) |  |

Get a MIME/MTOM attachment.

This function parses an attachment and invokes the MIME callbacks when set. The `handle` parameter is passed to `fmimewriteopen`. The handle may contain any data that is extracted from the SOAP message body to guide the redirection of the stream in the callbacks. Returns a struct with a `char *ptr` member that contains the handle value returned by the `fmimewriteopen` callback, and `char *id`, `char *type`, and `char *description` member variables with the MIME id, type, and description info when present in the attachment.

See also
  `soap_post_check_mime_attachments`, `soap_check_mime_attachments`.

Returns
  MIME attachment data or NULL if no more attachments were found

Parameters

  soap | `soap` context
  handle | a handle to pass to the callbacks

int soap_set_mime | ( | struct soap * | soap,
|  | const char * | boundary,
|  | const char * | start
| ) |  |

Enable MIME attachments.

This function enables sending MIME attachments. This function is generally not required when the context is initialized with `SOAP_ENC_MIME`, because MIME attachments are automatically detected as `xsd__base64Binary` and `_xop__Include` structures in the data to serialize as an XML message with the attachments automatically added or MIME attachments can be explicitly added with `soap_set_mime_attachment`. Parameter `boundary` specifies a MIME boundary string or NULL to have the engine generate a MIME boundary string. Parameter `start` specifiesthe start content ID for the first MIME body containing the SOAP or XML message. When NULL, the start ID of the SOAP message is `<SOAP-ENV:Envelope>`.

See also
  `soap_set_mime_attachment`, `soap_clr_mime`, `SOAP_ENC_MIME`, `SOAP_ENC_MTOM`.

Parameters

  soap | `soap` context
  boundary | MIME boundary string to use or NULL to generate a random boundary
  start | string id of the first MIME attachment with the SOAP/XML message or NULL

int soap_set_mime_attachment | ( | struct soap * | soap,
|  | const char * | ptr,
|  | size_t | size,
|  | enum soap_mime_encoding | encoding,
|  | const char * | type,
|  | const char * | id,
|  | const char * | location,
|  | const char * | description
| ) |  |

Add a MIME attachment to the SOAP/XML message.

This function adds a MIME attachment to a SOAP/XML message to send. The specified `ptr` points to the data to send of length specified by `size`. The `encoding` parameter is a `soap_mime_encoding` value that is recommended to be specified as `SOAP_MIME_NONE` to specify that the MIME data content is not encoded in any way (the MIME attachment function simply copies the raw data to the MIME block without encoding). The `type` parameter is required and indicates the MIME type of the data, such as "image/jpg". The `id` parameter uniquely identifies the attachment in the message, which can be omitted by specifying NULL. The `location` parameter specifies a location string or NULL. The `description` parameter is a string that describes the data or NULL. Returns `SOAP_OK` or a `soap_status` error code.

There are two ways to add MIME/MTOM attachments to SOAP/XML:

- use `soap_set_mime_attachment` to explicitly add an attachment that contains the specified source of data;
- use `xsd__base64Binary` or `_xop__Include` structures in the serializable data of a SOAP/XML message, where the specified data is serialized in MIME/MTOM attachments automatically when one of the `id`, `type` or `options` member variables are non-NULL. This option requires `SOAP_ENC_MIME` or `SOAP_ENC_MTOM`.

Both methods support streaming MIME/MTOM attachments, where a user-defined handle instead of the actual data is specified for the `ptr` parameter or the `__ptr` member variable.

Example:

#include "soapH.h"
struct soap *soap = soap_new1(SOAP_IO_CHUNK);
const char *data = ...; // points to data to send
size_t size = ...; // length of the data
soap->connect_timeout = 30; // 30 seconds max connect stall time
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)
soap_set_mime_attachment(soap, data, size, SOAP_MIME_NONE, "image/jpg", NULL, NULL, "Picture");
if (soap_call_ns__webmethod(soap, endpoint, NULL, ...))
{
soap_print_fault(soap, stderr);
if (soap->errnum == 0) // timed out, exit program
exit(EXIT_FAILURE);
}
else
{
... // success
}
soap_clr_mime(soap);
soap_destroy(soap);
soap_end(soap);
soap_free(soap);

See also
  `xsd__base64Binary`, `_xop__Include`, `soap_rand_uuid`, `soap::fmimereadopen`, `soap::fmimeread`, `soap::fmimereadclose`.

Returns
  `SOAP_OK` or a `soap_status` error code

Parameters

  soap | `soap` context
  ptr | pointer to data
  size | length of the data
  encoding | encoding of the data
  type | MIME type of the data
  id | content ID of the data or NULL
  location | location of the data or NULL
  description | description of the data or NULL