YAZ 5.37.0
soap.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
12#if HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include <yaz/soap.h>
17#include <yaz/match_glob.h>
18
19#if YAZ_HAVE_XML2
20#include <libxml/parser.h>
21#include <libxml/tree.h>
22#include <yaz/snprintf.h>
23
24static const char *soap_v1_1 = "http://schemas.xmlsoap.org/soap/envelope/";
25static const char *soap_v1_2 = "http://www.w3.org/2001/06/soap-envelope";
26
28 char **content_buf, int *content_len,
29 Z_SOAP_Handler *handlers,
30 const char *encoding,
31 const char *stylesheet)
32{
33 if (o->direction == ODR_DECODE)
34 {
35 Z_SOAP *p;
36 xmlNodePtr ptr, pptr;
37 xmlDocPtr doc;
38 int i, ret;
39
40 if (!content_buf || !*content_buf || !content_len)
41 return -1;
42
43 *pp = p = (Z_SOAP *) odr_malloc(o, sizeof(*p));
44 p->ns = soap_v1_1;
45
46 doc = xmlParseMemory(*content_buf, *content_len);
47 if (!doc)
48 return z_soap_error(o, p, "SOAP-ENV:Client",
49 "Bad XML Document", 0);
50
51 ptr = xmlDocGetRootElement(doc);
52 if (!ptr || ptr->type != XML_ELEMENT_NODE || !ptr->ns)
53 {
54 xmlFreeDoc(doc);
55 return z_soap_error(o, p, "SOAP-ENV:Client",
56 "No Envelope element", 0);
57 }
58 /* check for SRU root node match */
59 for (i = 0; handlers[i].ns; i++)
60 {
61 const char *hns = handlers[i].ns;
62 if (strchr(hns, ':'))
63 {
64 if (yaz_match_glob(hns, (const char *) ptr->ns->href))
65 break;
66 }
67 else
68 {
69 if (yaz_match_glob(hns, (const char *) ptr->name))
70 break;
71 }
72 }
73 if (handlers[i].ns)
74 {
75 void *handler_data = 0;
76 xmlNode p_top_tmp; /* pseudo parent node needed */
77
78 p_top_tmp.children = ptr;
79 ret = (*handlers[i].f)(o, &p_top_tmp, &handler_data,
80 handlers[i].client_data,
81 (const char *)ptr->ns->href);
82
83 if (ret || !handler_data)
84 z_soap_error(o, p, "SOAP-ENV:Client",
85 "SOAP Handler returned error", 0);
86 else
87 {
89 p->u.generic = (Z_SOAP_Generic *)
90 odr_malloc(o, sizeof(*p->u.generic));
91 p->u.generic->no = i;
92 p->u.generic->ns = handlers[i].ns;
93 p->u.generic->p = handler_data;
94 }
95 xmlFreeDoc(doc);
96 return ret;
97 }
98 /* OK: assume SOAP */
99 if (xmlStrcmp(ptr->name, BAD_CAST "Envelope"))
100 {
101 xmlFreeDoc(doc);
102 return z_soap_error(o, p, "SOAP-ENV:Client",
103 "No Envelope element", 0);
104 }
105 else
106 {
107 /* determine SOAP version */
108 const char * ns_envelope = (const char *) ptr->ns->href;
109 if (!strcmp(ns_envelope, soap_v1_1))
110 p->ns = soap_v1_1;
111 else if (!strcmp(ns_envelope, soap_v1_2))
112 p->ns = soap_v1_2;
113 else
114 {
115 xmlFreeDoc(doc);
116 return z_soap_error(o, p, "SOAP-ENV:Client",
117 "Bad SOAP version", 0);
118 }
119 }
120 ptr = ptr->children;
121 while(ptr && ptr->type == XML_TEXT_NODE)
122 ptr = ptr->next;
123 if (ptr && ptr->type == XML_ELEMENT_NODE &&
124 !xmlStrcmp(ptr->ns->href, BAD_CAST p->ns) &&
125 !xmlStrcmp(ptr->name, BAD_CAST "Header"))
126 {
127 ptr = ptr->next;
128 while(ptr && ptr->type == XML_TEXT_NODE)
129 ptr = ptr->next;
130 }
131 /* check that Body is present */
132 if (!ptr || ptr->type != XML_ELEMENT_NODE ||
133 xmlStrcmp(ptr->name, BAD_CAST "Body"))
134 {
135 xmlFreeDoc(doc);
136 return z_soap_error(o, p, "SOAP-ENV:Client",
137 "SOAP Body element not found", 0);
138 }
139 if (xmlStrcmp(ptr->ns->href, BAD_CAST p->ns))
140 {
141 xmlFreeDoc(doc);
142 return z_soap_error(o, p, "SOAP-ENV:Client",
143 "SOAP bad NS for Body element", 0);
144 }
145 pptr = ptr;
146 ptr = ptr->children;
147 while (ptr && ptr->type == XML_TEXT_NODE)
148 ptr = ptr->next;
149 if (!ptr || ptr->type != XML_ELEMENT_NODE)
150 {
151 xmlFreeDoc(doc);
152 return z_soap_error(o, p, "SOAP-ENV:Client",
153 "SOAP No content for Body", 0);
154 }
155 if (!ptr->ns)
156 {
157 xmlFreeDoc(doc);
158 return z_soap_error(o, p, "SOAP-ENV:Client",
159 "SOAP No namespace for content", 0);
160 }
161 /* check for fault package */
162 if (!xmlStrcmp(ptr->ns->href, BAD_CAST p->ns)
163 && !xmlStrcmp(ptr->name, BAD_CAST "Fault") && ptr->children)
164 {
165 ptr = ptr->children;
166
167 p->which = Z_SOAP_fault;
168 p->u.fault = (Z_SOAP_Fault *) odr_malloc(o, sizeof(*p->u.fault));
169 p->u.fault->fault_code = 0;
170 p->u.fault->fault_string = 0;
171 p->u.fault->details = 0;
172 while (ptr)
173 {
174 if (ptr->children && ptr->children->type == XML_TEXT_NODE)
175 {
176 if (!xmlStrcmp(ptr->name, BAD_CAST "faultcode"))
177 p->u.fault->fault_code =
178 odr_strdup(o, (const char *)
179 ptr->children->content);
180 if (!xmlStrcmp(ptr->name, BAD_CAST "faultstring"))
181 p->u.fault->fault_string =
182 odr_strdup(o, (const char *)
183 ptr->children->content);
184 if (!xmlStrcmp(ptr->name, BAD_CAST "details"))
185 p->u.fault->details =
186 odr_strdup(o, (const char *)
187 ptr->children->content);
188 }
189 ptr = ptr->next;
190 }
191 ret = 0;
192 }
193 else
194 {
195 const char *ns = (const char *) ptr->ns->href;
196 for (i = 0; handlers[i].ns; i++)
197 {
198 if (strchr(handlers[i].ns, ':') &&
199 yaz_match_glob(handlers[i].ns, ns))
200 break;
201 }
202 if (handlers[i].ns)
203 {
204 void *handler_data = 0;
205 ret = (*handlers[i].f)(o, pptr, &handler_data,
206 handlers[i].client_data, ns);
207 if (ret || !handler_data)
208 z_soap_error(o, p, "SOAP-ENV:Client",
209 "SOAP Handler returned error", 0);
210 else
211 {
213 p->u.generic = (Z_SOAP_Generic *)
214 odr_malloc(o, sizeof(*p->u.generic));
215 p->u.generic->no = i;
216 p->u.generic->ns = handlers[i].ns;
217 p->u.generic->p = handler_data;
218 }
219 }
220 else
221 {
222 ret = z_soap_error(o, p, "SOAP-ENV:Client",
223 "No handler for NS", ns);
224 }
225 }
226 xmlFreeDoc(doc);
227 return ret;
228 }
229 else if (o->direction == ODR_ENCODE)
230 {
231 Z_SOAP *p = *pp;
232 xmlNsPtr ns_env;
233 xmlNodePtr envelope_ptr, body_ptr;
234
235 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
236
237 envelope_ptr = xmlNewNode(0, BAD_CAST "Envelope");
238 ns_env = xmlNewNs(envelope_ptr, BAD_CAST p->ns,
239 BAD_CAST "SOAP-ENV");
240 xmlSetNs(envelope_ptr, ns_env);
241
242 body_ptr = xmlNewChild(envelope_ptr, ns_env, BAD_CAST "Body",
243 0);
244 xmlDocSetRootElement(doc, envelope_ptr);
245
246 if (p->which == Z_SOAP_fault || p->which == Z_SOAP_error)
247 {
248 Z_SOAP_Fault *f = p->u.fault;
249 xmlNodePtr fault_ptr = xmlNewChild(body_ptr, ns_env,
250 BAD_CAST "Fault", 0);
251 xmlNewChild(fault_ptr, ns_env, BAD_CAST "faultcode",
252 BAD_CAST f->fault_code);
253 xmlNewChild(fault_ptr, ns_env, BAD_CAST "faultstring",
254 BAD_CAST f->fault_string);
255 if (f->details)
256 xmlNewChild(fault_ptr, ns_env, BAD_CAST "details",
257 BAD_CAST f->details);
258 }
259 else if (p->which == Z_SOAP_generic)
260 {
261 int ret, no = p->u.generic->no;
262
263 ret = (*handlers[no].f)(o, body_ptr, &p->u.generic->p,
264 handlers[no].client_data,
265 handlers[no].ns);
266 if (ret)
267 {
268 xmlFreeDoc(doc);
269 return ret;
270 }
271 }
272 if (p->which == Z_SOAP_generic && !strcmp(p->ns, "SRU"))
273 {
274 xmlDocSetRootElement(doc, body_ptr->children);
275 body_ptr->children = 0;
276 xmlFreeNode(envelope_ptr);
277 }
278 if (stylesheet)
279 {
280 char *content = (char *) odr_malloc(o, strlen(stylesheet) + 40);
281 xmlNodePtr pi, ptr = xmlDocGetRootElement(doc);
282
283 yaz_snprintf(content, strlen(stylesheet) + 40,
284 "type=\"text/xsl\" href=\"%s\"", stylesheet);
285 pi = xmlNewPI(BAD_CAST "xml-stylesheet", BAD_CAST content);
286 xmlAddPrevSibling(ptr, pi);
287 }
288 if (1)
289 {
290 xmlChar *buf_out;
291 int len_out;
292 if (encoding)
293 xmlDocDumpMemoryEnc(doc, &buf_out, &len_out, encoding);
294 else
295 xmlDocDumpMemory(doc, &buf_out, &len_out);
296 *content_buf = (char *) odr_malloc(o, len_out);
297 *content_len = len_out;
298 memcpy(*content_buf, buf_out, len_out);
299 xmlFree(buf_out);
300 }
301 xmlFreeDoc(doc);
302 return 0;
303 }
304 return 0;
305}
306#else
308 char **content_buf, int *content_len,
309 Z_SOAP_Handler *handlers, const char *encoding,
310 const char *stylesheet)
311{
312 static char *err_xml =
313 "<?xml version=\"1.0\"?>\n"
314 "<SOAP-ENV:Envelope"
315 " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
316 "\t<SOAP-ENV:Body>\n"
317 "\t\t<SOAP-ENV:Fault>\n"
318 "\t\t\t<faultcode>SOAP-ENV:Server</faultcode>\n"
319 "\t\t\t<faultstring>HTTP error</faultstring>\n"
320 "\t\t\t<detail>SOAP not supported in this YAZ configuration</detail>\n"
321 "\t\t</SOAP-ENV:Fault>\n"
322 "\t</SOAP-ENV:Body>\n"
323 "</SOAP-ENV:Envelope>\n";
324 if (o->direction == ODR_ENCODE)
325 {
326 *content_buf = err_xml;
327 *content_len = strlen(err_xml);
328 }
329 return -1;
330}
331#endif
333 char **content_buf, int *content_len,
334 Z_SOAP_Handler *handlers,
335 const char *encoding)
336{
337 return z_soap_codec_enc_xsl(o, pp, content_buf, content_len, handlers,
338 encoding, 0);
339}
340
342 char **content_buf, int *content_len,
343 Z_SOAP_Handler *handlers)
344{
345 return z_soap_codec_enc(o, pp, content_buf, content_len, handlers, 0);
346}
347
349 const char *fault_code, const char *fault_string,
350 const char *details)
351{
352 p->which = Z_SOAP_error;
353 p->u.soap_error = (Z_SOAP_Fault *)
354 odr_malloc(o, sizeof(*p->u.soap_error));
355 p->u.soap_error->fault_code = odr_strdup(o, fault_code);
356 p->u.soap_error->fault_string = odr_strdup(o, fault_string);
357 if (details)
358 p->u.soap_error->details = odr_strdup(o, details);
359 else
360 p->u.soap_error->details = 0;
361 return -1;
362}
363
364/*
365 * Local variables:
366 * c-basic-offset: 4
367 * c-file-style: "Stroustrup"
368 * indent-tabs-mode: nil
369 * End:
370 * vim: shiftwidth=4 tabstop=8 expandtab
371 */
372
int yaz_match_glob(const char *glob, const char *text)
matches a glob expression against text
Definition match_glob.c:22
Glob expression matcher.
#define ODR_DECODE
Definition odr.h:95
struct odr * ODR
Definition odr.h:121
#define ODR_ENCODE
Definition odr.h:96
void * odr_malloc(ODR o, size_t size)
Definition odr_mem.c:31
char * odr_strdup(ODR o, const char *str)
Definition odr_mem.c:36
void yaz_snprintf(char *buf, size_t size, const char *fmt,...)
Definition snprintf.c:31
Header for config file reading utilities.
static const char * soap_v1_1
Definition soap.c:24
int z_soap_codec_enc_xsl(ODR o, Z_SOAP **pp, char **content_buf, int *content_len, Z_SOAP_Handler *handlers, const char *encoding, const char *stylesheet)
Definition soap.c:27
static const char * soap_v1_2
Definition soap.c:25
int z_soap_codec(ODR o, Z_SOAP **pp, char **content_buf, int *content_len, Z_SOAP_Handler *handlers)
Definition soap.c:341
int z_soap_codec_enc(ODR o, Z_SOAP **pp, char **content_buf, int *content_len, Z_SOAP_Handler *handlers, const char *encoding)
Definition soap.c:332
int z_soap_error(ODR o, Z_SOAP *p, const char *fault_code, const char *fault_string, const char *details)
Definition soap.c:348
Header for SOAP.
#define Z_SOAP_fault
Definition soap.h:52
#define Z_SOAP_error
Definition soap.h:54
#define Z_SOAP_generic
Definition soap.h:53
char * fault_code
Definition soap.h:41
char * details
Definition soap.h:43
char * fault_string
Definition soap.h:42
void * p
Definition soap.h:49
char * ns
Definition soap.h:48
char * ns
Definition soap.h:68
void * client_data
Definition soap.h:69
Z_SOAP_fun f
Definition soap.h:70
Definition soap.h:55
Z_SOAP_Fault * fault
Definition soap.h:58
union Z_SOAP::@376262347373245141365154145051227323112037301017 u
int which
Definition soap.h:56
const char * ns
Definition soap.h:62
Z_SOAP_Generic * generic
Definition soap.h:59
Z_SOAP_Fault * soap_error
Definition soap.h:60
int direction
Definition odr.h:126