157533cbf2b1b91d596aeb5e3477337e27fc0c54
[yaz-moved-to-github.git] / zutil / soap.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: soap.c,v 1.3 2003-02-17 14:35:42 adam Exp $
6  */
7
8 #include <yaz/soap.h>
9
10 #if HAVE_XSLT
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
13
14 static const char *soap_v1_1 = "http://schemas.xmlsoap.org/soap/envelope/";
15 static const char *soap_v1_2 = "http://www.w3.org/2001/06/soap-envelope";
16
17 int z_soap_error(ODR o, Z_SOAP *p,
18                  const char *fault_code, const char *fault_string,
19                  const char *details)
20 {
21     p->which = Z_SOAP_error;
22     p->u.soap_error = (Z_SOAP_Fault *) 
23         odr_malloc(o, sizeof(*p->u.soap_error));
24     p->u.soap_error->fault_code = odr_strdup(o, fault_code);
25     p->u.soap_error->fault_string = odr_strdup(o, fault_string);
26     if (details)
27         p->u.soap_error->details = odr_strdup(o, details);
28     else
29         p->u.soap_error->details = 0;
30     return -1;
31 }
32
33 int z_soap_codec(ODR o, Z_SOAP **pp, 
34                  char **content_buf, int *content_len,
35                  Z_SOAP_Handler *handlers)
36 {
37     if (o->direction == ODR_DECODE)
38     {
39         Z_SOAP *p;
40         xmlNodePtr ptr, pptr;
41         xmlDocPtr doc;
42         int i, ret;
43
44         if (!content_buf || !*content_buf || !content_len)
45             return -1;
46
47         *pp = p = (Z_SOAP *) odr_malloc(o, sizeof(*p));
48         p->ns = soap_v1_1;
49
50         doc = xmlParseMemory(*content_buf, *content_len);
51         if (!doc)
52             return z_soap_error(o, p, "SOAP-ENV:Client",
53                                 "Bad XML Document", 0);
54         /* check that root node is Envelope */
55         ptr = xmlDocGetRootElement(doc);
56         if (!ptr || ptr->type != XML_ELEMENT_NODE ||
57             strcmp(ptr->name, "Envelope") || !ptr->ns)
58         {
59             xmlFreeDoc(doc);
60             return z_soap_error(o, p, "SOAP-ENV:Client",
61                                 "No Envelope element", 0);
62         }
63         else
64         {
65             /* determine SOAP version */
66             const char * ns_envelope = ptr->ns->href;
67             if (!strcmp(ns_envelope, soap_v1_1))
68                 p->ns = soap_v1_1;
69             else if (!strcmp(ns_envelope, soap_v1_2))
70                 p->ns = soap_v1_2;
71             else
72             {
73                 xmlFreeDoc(doc);
74                 return z_soap_error(o, p, "SOAP-ENV:Client",
75                                     "Bad SOAP version", 0);
76             }
77         }
78         ptr = ptr->children;
79         while(ptr && ptr->type == XML_TEXT_NODE)
80             ptr = ptr->next;
81         if (ptr && ptr->type == XML_ELEMENT_NODE &&
82             !strcmp(ptr->ns->href, p->ns) &&
83             !strcmp(ptr->name, "Header"))
84         {
85             ptr = ptr->next;
86             while(ptr && ptr->type == XML_TEXT_NODE)
87                 ptr = ptr->next;
88         }
89         /* check that Body is present */
90         if (!ptr || ptr->type != XML_ELEMENT_NODE || 
91             strcmp(ptr->name, "Body"))
92         {
93             xmlFreeDoc(doc);
94             return z_soap_error(o, p, "SOAP-ENV:Client",
95                                 "SOAP Body element not found", 0);
96         }
97         if (strcmp(ptr->ns->href, p->ns))
98         {
99             xmlFreeDoc(doc);
100             return z_soap_error(o, p, "SOAP-ENV:Client",
101                                 "SOAP bad NS for Body element", 0);
102         }
103         pptr = ptr;
104         ptr = ptr->children;
105         while (ptr && ptr->type == XML_TEXT_NODE)
106             ptr = ptr->next;
107         if (!ptr || ptr->type != XML_ELEMENT_NODE)
108         {
109             xmlFreeDoc(doc);
110             return z_soap_error(o, p, "SOAP-ENV:Client",
111                                 "SOAP No content for Body", 0);
112         }
113         /* check for fault package */
114         if (!strcmp(ptr->ns->href, p->ns)
115             && !strcmp(ptr->name, "Fault") && ptr->children)
116         {
117             ptr = ptr->children;
118
119             p->which = Z_SOAP_fault;
120             p->u.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 (!strcmp(ptr->name, "faultcode"))
129                         p->u.fault->fault_code =
130                             odr_strdup(o, ptr->children->content);
131                     if (!strcmp(ptr->name, "faultstring"))
132                         p->u.fault->fault_string =
133                             odr_strdup(o, ptr->children->content);
134                     if (!strcmp(ptr->name, "details"))
135                         p->u.fault->details =
136                             odr_strdup(o, ptr->children->content);
137                 }
138                 ptr = ptr->next;
139             }
140             ret = 0;
141         }
142         else
143         {
144             for (i = 0; handlers[i].ns; i++)
145                 if (!strcmp(ptr->ns->href, handlers[i].ns))
146                     break;
147             if (handlers[i].ns)
148             {
149                 void *handler_data = 0;
150                 ret = (*handlers[i].f)(o, pptr, &handler_data,
151                                        handlers[i].client_data,
152                                        handlers[i].ns);
153                 if (ret || !handler_data)
154                     z_soap_error(o, p, "SOAP-ENV:Client",
155                                  "SOAP Handler returned error", 0);
156                 else
157                 {
158                     p->which = Z_SOAP_generic;
159                     p->u.generic = odr_malloc(o, sizeof(*p->u.generic));
160                     p->u.generic->no = i;
161                     p->u.generic->ns = handlers[i].ns;
162                     p->u.generic->p = handler_data;
163                 }
164             }
165             else
166             {
167                 ret = z_soap_error(o, p, "SOAP-ENV:Client", 
168                                    "No handler for NS", 0);
169             }
170         }
171         xmlFreeDoc(doc);
172         return ret;
173     }
174     else if (o->direction == ODR_ENCODE)
175     {
176         Z_SOAP *p = *pp;
177         xmlNsPtr ns_env;
178         xmlNodePtr envelope_ptr, body_ptr;
179         xmlChar *buf_out;
180         int len_out;
181
182         xmlDocPtr doc = xmlNewDoc("1.0");
183
184         envelope_ptr = xmlNewNode(0, "Envelope");
185         ns_env = xmlNewNs(envelope_ptr, p->ns, "SOAP-ENV");
186         xmlSetNs(envelope_ptr, ns_env);
187
188         body_ptr = xmlNewChild(envelope_ptr, ns_env, "Body", 0);
189         xmlDocSetRootElement(doc, envelope_ptr);
190
191         if (p->which == Z_SOAP_fault || p->which == Z_SOAP_error)
192         {
193             Z_SOAP_Fault *f = p->u.fault;
194             xmlNodePtr fault_ptr = xmlNewChild(body_ptr, ns_env, "Fault", 0);
195             xmlNewChild(fault_ptr, ns_env, "faultcode",  f->fault_code);
196             xmlNewChild(fault_ptr, ns_env, "faultstring", f->fault_string);
197             if (f->details)
198                 xmlNewChild(fault_ptr, ns_env, "details", f->details);
199         }
200         else if (p->which == Z_SOAP_generic)
201         {
202             int ret, no = p->u.generic->no;
203             
204             ret = (*handlers[no].f)(o, body_ptr, &p->u.generic->p,
205                                     handlers[no].client_data,
206                                     handlers[no].ns);
207             if (ret)
208                 return ret;
209         }
210         xmlDocDumpMemory(doc, &buf_out, &len_out);
211         *content_buf = (char *) odr_malloc(o, len_out);
212         *content_len = len_out;
213         memcpy(*content_buf, buf_out, len_out);
214         xmlFree(buf_out);
215         xmlFreeDoc(doc);
216         return 0;
217     }
218     return 0;
219 }
220 #endif