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