1 #define _XOPEN_SOURCE 500 /* strdup from string.h */
8 /* Private structure for write_body() call back */
15 /* CURL call back function called when chunk of HTTP reponse body is available.
16 * @buffer points to new data
17 * @size * @nmemb is length of the chunk in bytes. Zero means empty body.
18 * @userp is private structure.
19 * Must reuturn the length of the chunk, otherwise CURL will signal
20 * CURL_WRITE_ERROR. */
21 static size_t write_body(void *buffer
, size_t size
, size_t nmemb
, void *userp
) {
22 struct soap_body
*body
= (struct soap_body
*) userp
;
25 /* FIXME: Check for (size * nmemb + body->lengt) !> SIZE_T_MAX.
26 * Precompute the product then. */
28 if (!body
) return 0; /* This should never happen */
29 if (0 == (size
* nmemb
)) return 0; /* Empty body */
31 new_data
= realloc(body
->data
, body
->length
+ size
* nmemb
);
32 if (!new_data
) return 0;
34 memcpy(new_data
+ body
->length
, buffer
, size
* nmemb
);
36 body
->data
= new_data
;
37 body
->length
+= size
* nmemb
;
39 return (size
* nmemb
);
44 * @context holds the base URL,
45 * @url is a (CGI) file of SOAP URL,
46 * @request is body for POST request
47 * @request_length is length of @request in bytes
48 * @reponse is automatically reallocated() buffer to fit HTTP response with
49 * @response_length (does not need to match allocatef memory exactly). You must
50 * free() the @response.
51 * @mime_type is automatically allocated MIME type send by server (*NULL if not
52 * sent). Set NULL if you don't care.
53 * @charset is charset of the body signaled by server. The same constrains
54 * like on @mime_type apply.
55 * In case of error, the response memory, MIME type, charset and lenght will be
56 * deallocated and zerod automatically. Thus be sure they are preallocated or
57 * they points to NULL.
58 * Side effect: message buffer */
59 static isds_error
http(struct isds_ctx
*context
, const char *url
,
60 const void *request
, const size_t request_length
,
61 void **response
, size_t *response_length
,
62 char **mime_type
, char**charset
) {
65 isds_error err
= IE_SUCCESS
;
66 struct soap_body body
;
68 struct curl_slist
*headers
= NULL
;
71 if (!context
) return IE_INVALID_CONTEXT
;
72 if (!url
) return IE_INVAL
;
73 if (request_length
> 0 && !request
) return IE_INVAL
;
74 if (!response
|| !response_length
) return IE_INVAL
;
76 /* Set the body here to allow deallocataion in leave block */
77 body
.data
= *response
;
81 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_URL
, url
);
82 if (!curl_err
&& context
->username
) {
83 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_USERNAME
,
88 if (!curl_err
&& context
->password
) {
89 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_PASSWORD
,
93 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_FAILONERROR
, 1);
96 /* Set get-response function */
98 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_WRITEFUNCTION
,
102 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_WRITEDATA
, &body
);
105 /* Set MIME types and user agent identification */
107 headers
= curl_slist_append(headers
, "Accept: application/soap+xml");
112 headers
= curl_slist_append(headers
, "Content-Type: application/soap+xml");
117 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_HTTPHEADER
, headers
);
120 /* TODO: Present library version, curl etc. in User-Agent */
121 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_USERAGENT
, "libisds");
124 /* Set POST request body */
126 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_POST
, 1);
129 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_POSTFIELDS
, request
);
132 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_POSTFIELDSIZE
,
136 /* Check for errors so far */
138 isds_log_message(context
, curl_easy_strerror(curl_err
));
144 curl_err
= curl_easy_perform(context
->curl
);
147 curl_err
= curl_easy_getinfo(context
->curl
, CURLINFO_CONTENT_TYPE
,
151 isds_log_message(context
, url
);
152 isds_append_message(context
, _(": "));
153 isds_append_message(context
, curl_easy_strerror(curl_err
));
158 /* Extract MIME type and charset */
163 sep
= strchr(content_type
, ';');
164 if (sep
) offset
= (size_t) (sep
- content_type
);
165 else offset
= strlen(content_type
);
168 *mime_type
= malloc(offset
+ 1);
173 memcpy(*mime_type
, content_type
, offset
);
174 (*mime_type
)[offset
] = '\0';
181 sep
= strstr(sep
, "charset=");
185 *charset
= strdup(sep
+ 8);
212 curl_easy_cleanup(context
->curl
);
213 context
->curl
= NULL
;
216 *response
= body
.data
;
217 *response_length
= body
.length
;
224 * @context holds the base URL,
225 * @file is a (CGI) file of SOAP URL,
226 * @request is XML document with request.
227 * @request_length is lenght of @request in bytes
228 * @file and @request must be NULL rather than empty strings, if the should
229 * not be signaled in the SOAP request.
230 * @reponse is automatically reallocated() buffer to fit SOAP response with
231 * @response_length (does not need to match allocatef memory exactly). You must
232 * free() the @response. In case of error the response memory and lenght will
233 * be deallocated and zerod automatically.
234 * Side effect: message buffer */
235 _hidden isds_error
soap(struct isds_ctx
*context
, const char *file
,
236 const void *request
, const size_t request_length
,
237 void **response
, size_t *response_length
) {
240 isds_error err
= IE_SUCCESS
;
241 char *mime_type
= NULL
;
242 xmlDocPtr soap_tree
= NULL
;
243 xmlXPathContextPtr xpath_ctx
= NULL
;
244 xmlXPathObjectPtr soap_body
= NULL
;
247 if (!context
) return IE_INVALID_CONTEXT
;
248 if (request_length
> 0 && !request
) return IE_INVAL
;
249 if (!response
|| !response_length
) return IE_INVAL
;
251 url
= astrcat(context
->url
, file
);
252 if (!url
) return IE_NOMEM
;
254 /* TODO: Wrap the request into SOAP envelope */
256 err
= http(context
, url
, request
, request_length
,
257 response
, response_length
,
264 /* Check for Content-Type: application/soap+xml */
265 if (mime_type
&& strcmp(mime_type
, "application/soap+xml")
266 && strcmp(mime_type
, "application/xml")
267 && strcmp(mime_type
, "text/xml")) {
268 isds_log_message(context
, url
);
269 isds_append_message(context
, _(": bad MIME type sent by server: "));
270 isds_append_message(context
, mime_type
);
275 /* TODO: Convert returned body into XML default encoding */
277 /* TODO: Extract XML Tree with ISDS response from SOAP envelope and return
279 soap_tree
= xmlParseMemory(*response
, *response_length
);
285 xpath_ctx
= xmlXPathNewContext(soap_tree
);
291 if (register_namespaces(xpath_ctx
)) {
296 soap_body
= xmlXPathEvalExpression(BAD_CAST
"/soap:Envelope/soap:Body/*",
303 xmlXPathFreeObject(soap_body
);
304 xmlXPathFreeContext(xpath_ctx
);
305 xmlFreeDoc(soap_tree
);
311 *response_length
= 0;
321 * void xmlInitParser(void)
322 * Initialization function for the XML parser. This is not reentrant. Call
323 * once before processing in case of use in multithreaded programs.
325 * int xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
326 * Initialize a parser context
328 * xmlDocPtr xmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar * cur,
329 * const * char URL, const char * encoding, int options);
330 * Parse in-memory NULL-terminated document @cur.
332 * xmlDocPtr xmlParseMemory(const char * buffer, int size)
333 * Parse an XML in-memory block and build a tree.
335 * xmlParserCtxtPtr xmlCreateMemoryParserCtxt(const char * buffer, int
337 * Create a parser context for an XML in-memory document.
339 * xmlParserCtxtPtr xmlCreateDocParserCtxt(const xmlChar * cur)
340 * Creates a parser context for an XML in-memory document.
342 * xmlDocPtr xmlCtxtReadMemory(xmlParserCtxtPtr ctxt,
343 * const char * buffer, int size, const char * URL, const char * encoding,
345 * Parse an XML in-memory document and build a tree. This reuses the existing
346 * @ctxt parser context.
348 * void xmlCleanupParser(void)
349 * Cleanup function for the XML library. It tries to reclaim all parsing
350 * related glob document related memory. Calling this function should not
351 * prevent reusing the libr finished using the library or XML document built
354 * void xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
355 * Clear (release owned resources) and reinitialize a parser context.
357 * void xmlCtxtReset(xmlParserCtxtPtr ctxt)
358 * Reset a parser context
360 * void xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
361 * Free all the memory used by a parser context. However the parsed document
362 * in ctxt->myDoc is not freed.
364 * void xmlFreeDoc(xmlDocPtr cur)
365 * Free up all the structures used by a document, tree included.