More type casts for char signed/unsigned and xmlChar. Using
[yaz-moved-to-github.git] / src / soap.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: soap.c,v 1.12 2005-08-22 20:34:21 adam Exp $
6  */
7 /**
8  * \file soap.c
9  * \brief Implements SOAP
10  *
11  * This implements encoding and decoding of SOAP packages using
12  * Libxml2.
13  */
14
15 #include <yaz/soap.h>
16
17 #if HAVE_XML2
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
20
21 static const char *soap_v1_1 = "http://schemas.xmlsoap.org/soap/envelope/";
22 static const char *soap_v1_2 = "http://www.w3.org/2001/06/soap-envelope";
23
24 int z_soap_codec_enc_xsl(ODR o, Z_SOAP **pp, 
25                          char **content_buf, int *content_len,
26                          Z_SOAP_Handler *handlers,
27                          const char *encoding,
28                          const char *stylesheet)
29 {
30     if (o->direction == ODR_DECODE)
31     {
32         Z_SOAP *p;
33         xmlNodePtr ptr, pptr;
34         xmlDocPtr doc;
35         int i, ret;
36
37         if (!content_buf || !*content_buf || !content_len)
38             return -1;
39
40         *pp = p = (Z_SOAP *) odr_malloc(o, sizeof(*p));
41         p->ns = soap_v1_1;
42
43         doc = xmlParseMemory(*content_buf, *content_len);
44         if (!doc)
45             return z_soap_error(o, p, "SOAP-ENV:Client",
46                                 "Bad XML Document", 0);
47
48         /* check that root node is Envelope */
49         ptr = xmlDocGetRootElement(doc);
50         if (!ptr || ptr->type != XML_ELEMENT_NODE ||
51             xmlStrcmp(ptr->name, BAD_CAST "Envelope") || !ptr->ns)
52         {
53             xmlFreeDoc(doc);
54             return z_soap_error(o, p, "SOAP-ENV:Client",
55                                 "No Envelope element", 0);
56         }
57         else
58         {
59             /* determine SOAP version */
60             const char * ns_envelope = (const char *) ptr->ns->href;
61             if (!strcmp(ns_envelope, soap_v1_1))
62                 p->ns = soap_v1_1;
63             else if (!strcmp(ns_envelope, soap_v1_2))
64                 p->ns = soap_v1_2;
65             else
66             {
67                 xmlFreeDoc(doc);
68                 return z_soap_error(o, p, "SOAP-ENV:Client",
69                                     "Bad SOAP version", 0);
70             }
71         }
72         ptr = ptr->children;
73         while(ptr && ptr->type == XML_TEXT_NODE)
74             ptr = ptr->next;
75         if (ptr && ptr->type == XML_ELEMENT_NODE &&
76             !xmlStrcmp(ptr->ns->href, BAD_CAST p->ns) &&
77             !xmlStrcmp(ptr->name, BAD_CAST "Header"))
78         {
79             ptr = ptr->next;
80             while(ptr && ptr->type == XML_TEXT_NODE)
81                 ptr = ptr->next;
82         }
83         /* check that Body is present */
84         if (!ptr || ptr->type != XML_ELEMENT_NODE || 
85             xmlStrcmp(ptr->name, BAD_CAST "Body"))
86         {
87             xmlFreeDoc(doc);
88             return z_soap_error(o, p, "SOAP-ENV:Client",
89                                 "SOAP Body element not found", 0);
90         }
91         if (xmlStrcmp(ptr->ns->href, BAD_CAST p->ns))
92         {
93             xmlFreeDoc(doc);
94             return z_soap_error(o, p, "SOAP-ENV:Client",
95                                 "SOAP bad NS for Body element", 0);
96         }
97         pptr = ptr;
98         ptr = ptr->children;
99         while (ptr && ptr->type == XML_TEXT_NODE)
100             ptr = ptr->next;
101         if (!ptr || ptr->type != XML_ELEMENT_NODE)
102         {
103             xmlFreeDoc(doc);
104             return z_soap_error(o, p, "SOAP-ENV:Client",
105                                 "SOAP No content for Body", 0);
106         }
107         if (!ptr->ns)
108         {
109             xmlFreeDoc(doc);
110             return z_soap_error(o, p, "SOAP-ENV:Client",
111                                 "SOAP No namespace for content", 0);
112         }
113         /* check for fault package */
114         if (!xmlStrcmp(ptr->ns->href, BAD_CAST p->ns)
115             && !xmlStrcmp(ptr->name, BAD_CAST "Fault") && ptr->children)
116         {
117             ptr = ptr->children;
118
119             p->which = Z_SOAP_fault;
120             p->u.fault = (Z_SOAP_Fault *) odr_malloc(o, sizeof(*p->u.fault));
121             p->u.fault->fault_code = 0;
122             p->u.fault->fault_string = 0;
123             p->u.fault->details = 0;
124             while (ptr)
125             {
126                 if (ptr->children && ptr->children->type == XML_TEXT_NODE)
127                 {
128                     if (!xmlStrcmp(ptr->name, BAD_CAST "faultcode"))
129                         p->u.fault->fault_code =
130                             odr_strdup(o, (const char *)
131                                        ptr->children->content);
132                     if (!xmlStrcmp(ptr->name, BAD_CAST "faultstring"))
133                         p->u.fault->fault_string =
134                             odr_strdup(o, (const char *)
135                                        ptr->children->content);
136                     if (!xmlStrcmp(ptr->name, BAD_CAST "details"))
137                         p->u.fault->details =
138                             odr_strdup(o, (const char *)
139                                        ptr->children->content);
140                 }
141                 ptr = ptr->next;
142             }
143             ret = 0;
144         }
145         else
146         {
147             for (i = 0; handlers[i].ns; i++)
148                 if (!xmlStrcmp(ptr->ns->href, BAD_CAST handlers[i].ns))
149                     break;
150             if (handlers[i].ns)
151             {
152                 void *handler_data = 0;
153                 ret = (*handlers[i].f)(o, pptr, &handler_data,
154                                        handlers[i].client_data,
155                                        handlers[i].ns);
156                 if (ret || !handler_data)
157                     z_soap_error(o, p, "SOAP-ENV:Client",
158                                  "SOAP Handler returned error", 0);
159                 else
160                 {
161                     p->which = Z_SOAP_generic;
162                     p->u.generic = (Z_SOAP_Generic *)
163                         odr_malloc(o, sizeof(*p->u.generic));
164                     p->u.generic->no = i;
165                     p->u.generic->ns = handlers[i].ns;
166                     p->u.generic->p = handler_data;
167                 }
168             }
169             else
170             {
171                 ret = z_soap_error(o, p, "SOAP-ENV:Client", 
172                                    "No handler for NS",
173                                    (const char *)ptr->ns->href);
174             }
175         }
176         xmlFreeDoc(doc);
177         return ret;
178     }
179     else if (o->direction == ODR_ENCODE)
180     {
181         Z_SOAP *p = *pp;
182         xmlNsPtr ns_env;
183         xmlNodePtr envelope_ptr, body_ptr;
184
185         xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
186
187         envelope_ptr = xmlNewNode(0, BAD_CAST "Envelope");
188         ns_env = xmlNewNs(envelope_ptr, BAD_CAST p->ns,
189                           BAD_CAST "SOAP-ENV");
190         xmlSetNs(envelope_ptr, ns_env);
191
192         body_ptr = xmlNewChild(envelope_ptr, ns_env, BAD_CAST "Body",
193                                0);
194         xmlDocSetRootElement(doc, envelope_ptr);
195
196         if (p->which == Z_SOAP_fault || p->which == Z_SOAP_error)
197         {
198             Z_SOAP_Fault *f = p->u.fault;
199             xmlNodePtr fault_ptr = xmlNewChild(body_ptr, ns_env,
200                                                BAD_CAST "Fault", 0);
201             xmlNewChild(fault_ptr, ns_env, BAD_CAST "faultcode", 
202                         BAD_CAST f->fault_code);
203             xmlNewChild(fault_ptr, ns_env, BAD_CAST "faultstring",
204                         BAD_CAST f->fault_string);
205             if (f->details)
206                 xmlNewChild(fault_ptr, ns_env, BAD_CAST "details",
207                             BAD_CAST f->details);
208         }
209         else if (p->which == Z_SOAP_generic)
210         {
211             int ret, no = p->u.generic->no;
212             
213             ret = (*handlers[no].f)(o, body_ptr, &p->u.generic->p,
214                                     handlers[no].client_data,
215                                     handlers[no].ns);
216             if (ret)
217             {
218                 xmlFreeDoc(doc);
219                 return ret;
220             }
221         }
222         if (p->which == Z_SOAP_generic && !strcmp(p->ns, "SRU"))
223         {
224             xmlDocSetRootElement(doc, body_ptr->children);
225             body_ptr->children = 0;
226             xmlFreeNode(envelope_ptr);
227         }
228         if (stylesheet)
229         {
230             char *content = odr_malloc(o, strlen(stylesheet) + 40);
231             
232             xmlNodePtr pi, ptr = xmlDocGetRootElement(doc);
233             sprintf(content, "type=\"text/xsl\" href=\"%s\"", stylesheet);
234             pi = xmlNewPI(BAD_CAST "xml-stylesheet",
235                           BAD_CAST content);
236             xmlAddPrevSibling(ptr, pi);
237         }
238         if (1)
239         {
240             xmlChar *buf_out;
241             int len_out;
242             if (encoding)
243                 xmlDocDumpMemoryEnc(doc, &buf_out, &len_out, encoding);
244             else
245                 xmlDocDumpMemory(doc, &buf_out, &len_out);
246             *content_buf = (char *) odr_malloc(o, len_out);
247             *content_len = len_out;
248             memcpy(*content_buf, buf_out, len_out);
249             xmlFree(buf_out);
250         }
251         xmlFreeDoc(doc);
252         return 0;
253     }
254     return 0;
255 }
256 #else
257 int z_soap_codec_enc_xsl(ODR o, Z_SOAP **pp, 
258                          char **content_buf, int *content_len,
259                          Z_SOAP_Handler *handlers, const char *encoding,
260                          const char *stylesheet)
261 {
262     static char *err_xml =
263         "<?xml version=\"1.0\"?>\n"
264         "<SOAP-ENV:Envelope"
265         " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
266         "\t<SOAP-ENV:Body>\n"
267         "\t\t<SOAP-ENV:Fault>\n"
268         "\t\t\t<faultcode>SOAP-ENV:Server</faultcode>\n"
269         "\t\t\t<faultstring>HTTP error</faultstring>\n"
270         "\t\t\t<detail>SOAP not supported in this YAZ configuration</detail>\n"
271         "\t\t</SOAP-ENV:Fault>\n"
272         "\t</SOAP-ENV:Body>\n"
273         "</SOAP-ENV:Envelope>\n";
274     if (o->direction == ODR_ENCODE)
275     {
276         *content_buf = err_xml;
277         *content_len = strlen(err_xml);
278     }
279     return -1;
280 }
281 #endif
282 int z_soap_codec_enc(ODR o, Z_SOAP **pp, 
283                      char **content_buf, int *content_len,
284                      Z_SOAP_Handler *handlers,
285                      const char *encoding)
286 {
287     return z_soap_codec_enc_xsl(o, pp, content_buf, content_len, handlers,
288                                 encoding, 0);
289 }
290
291 int z_soap_codec(ODR o, Z_SOAP **pp, 
292                  char **content_buf, int *content_len,
293                  Z_SOAP_Handler *handlers)
294 {
295     return z_soap_codec_enc(o, pp, content_buf, content_len, handlers, 0);
296 }
297
298 int z_soap_error(ODR o, Z_SOAP *p,
299                  const char *fault_code, const char *fault_string,
300                  const char *details)
301 {
302     p->which = Z_SOAP_error;
303     p->u.soap_error = (Z_SOAP_Fault *) 
304         odr_malloc(o, sizeof(*p->u.soap_error));
305     p->u.soap_error->fault_code = odr_strdup(o, fault_code);
306     p->u.soap_error->fault_string = odr_strdup(o, fault_string);
307     if (details)
308         p->u.soap_error->details = odr_strdup(o, details);
309     else
310         p->u.soap_error->details = 0;
311     return -1;
312 }
313
314 /*
315  * Local variables:
316  * c-basic-offset: 4
317  * indent-tabs-mode: nil
318  * End:
319  * vim: shiftwidth=4 tabstop=8 expandtab
320  */
321