/* This file is part of the YAZ toolkit. * Copyright (C) Index Data * See the file LICENSE for details. */ /** * \file soap.c * \brief Implements SOAP * * This implements encoding and decoding of SOAP packages using * Libxml2. */ #if HAVE_CONFIG_H #include #endif #include #include #if YAZ_HAVE_XML2 #include #include static const char *soap_v1_1 = "http://schemas.xmlsoap.org/soap/envelope/"; static const char *soap_v1_2 = "http://www.w3.org/2001/06/soap-envelope"; 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) { if (o->direction == ODR_DECODE) { Z_SOAP *p; xmlNodePtr ptr, pptr; xmlDocPtr doc; int i, ret; if (!content_buf || !*content_buf || !content_len) return -1; *pp = p = (Z_SOAP *) odr_malloc(o, sizeof(*p)); p->ns = soap_v1_1; doc = xmlParseMemory(*content_buf, *content_len); if (!doc) return z_soap_error(o, p, "SOAP-ENV:Client", "Bad XML Document", 0); ptr = xmlDocGetRootElement(doc); if (!ptr || ptr->type != XML_ELEMENT_NODE || !ptr->ns) { xmlFreeDoc(doc); return z_soap_error(o, p, "SOAP-ENV:Client", "No Envelope element", 0); } /* check for SRU root node match */ for (i = 0; handlers[i].ns; i++) { const char *hns = handlers[i].ns; if (strchr(hns, ':')) { if (yaz_match_glob(hns, (const char *) ptr->ns->href)) break; } else { if (yaz_match_glob(hns, (const char *) ptr->name)) break; } } if (handlers[i].ns) { void *handler_data = 0; xmlNode p_top_tmp; /* pseudo parent node needed */ p_top_tmp.children = ptr; ret = (*handlers[i].f)(o, &p_top_tmp, &handler_data, handlers[i].client_data, (const char *)ptr->ns->href); if (ret || !handler_data) z_soap_error(o, p, "SOAP-ENV:Client", "SOAP Handler returned error", 0); else { p->which = Z_SOAP_generic; p->u.generic = (Z_SOAP_Generic *) odr_malloc(o, sizeof(*p->u.generic)); p->u.generic->no = i; p->u.generic->ns = handlers[i].ns; p->u.generic->p = handler_data; } xmlFreeDoc(doc); return ret; } /* OK: assume SOAP */ if (xmlStrcmp(ptr->name, BAD_CAST "Envelope")) { xmlFreeDoc(doc); return z_soap_error(o, p, "SOAP-ENV:Client", "No Envelope element", 0); } else { /* determine SOAP version */ const char * ns_envelope = (const char *) ptr->ns->href; if (!strcmp(ns_envelope, soap_v1_1)) p->ns = soap_v1_1; else if (!strcmp(ns_envelope, soap_v1_2)) p->ns = soap_v1_2; else { xmlFreeDoc(doc); return z_soap_error(o, p, "SOAP-ENV:Client", "Bad SOAP version", 0); } } ptr = ptr->children; while(ptr && ptr->type == XML_TEXT_NODE) ptr = ptr->next; if (ptr && ptr->type == XML_ELEMENT_NODE && !xmlStrcmp(ptr->ns->href, BAD_CAST p->ns) && !xmlStrcmp(ptr->name, BAD_CAST "Header")) { ptr = ptr->next; while(ptr && ptr->type == XML_TEXT_NODE) ptr = ptr->next; } /* check that Body is present */ if (!ptr || ptr->type != XML_ELEMENT_NODE || xmlStrcmp(ptr->name, BAD_CAST "Body")) { xmlFreeDoc(doc); return z_soap_error(o, p, "SOAP-ENV:Client", "SOAP Body element not found", 0); } if (xmlStrcmp(ptr->ns->href, BAD_CAST p->ns)) { xmlFreeDoc(doc); return z_soap_error(o, p, "SOAP-ENV:Client", "SOAP bad NS for Body element", 0); } pptr = ptr; ptr = ptr->children; while (ptr && ptr->type == XML_TEXT_NODE) ptr = ptr->next; if (!ptr || ptr->type != XML_ELEMENT_NODE) { xmlFreeDoc(doc); return z_soap_error(o, p, "SOAP-ENV:Client", "SOAP No content for Body", 0); } if (!ptr->ns) { xmlFreeDoc(doc); return z_soap_error(o, p, "SOAP-ENV:Client", "SOAP No namespace for content", 0); } /* check for fault package */ if (!xmlStrcmp(ptr->ns->href, BAD_CAST p->ns) && !xmlStrcmp(ptr->name, BAD_CAST "Fault") && ptr->children) { ptr = ptr->children; p->which = Z_SOAP_fault; p->u.fault = (Z_SOAP_Fault *) odr_malloc(o, sizeof(*p->u.fault)); p->u.fault->fault_code = 0; p->u.fault->fault_string = 0; p->u.fault->details = 0; while (ptr) { if (ptr->children && ptr->children->type == XML_TEXT_NODE) { if (!xmlStrcmp(ptr->name, BAD_CAST "faultcode")) p->u.fault->fault_code = odr_strdup(o, (const char *) ptr->children->content); if (!xmlStrcmp(ptr->name, BAD_CAST "faultstring")) p->u.fault->fault_string = odr_strdup(o, (const char *) ptr->children->content); if (!xmlStrcmp(ptr->name, BAD_CAST "details")) p->u.fault->details = odr_strdup(o, (const char *) ptr->children->content); } ptr = ptr->next; } ret = 0; } else { const char *ns = (const char *) ptr->ns->href; for (i = 0; handlers[i].ns; i++) { if (strchr(handlers[i].ns, ':') && yaz_match_glob(handlers[i].ns, ns)) break; } if (handlers[i].ns) { void *handler_data = 0; ret = (*handlers[i].f)(o, pptr, &handler_data, handlers[i].client_data, ns); if (ret || !handler_data) z_soap_error(o, p, "SOAP-ENV:Client", "SOAP Handler returned error", 0); else { p->which = Z_SOAP_generic; p->u.generic = (Z_SOAP_Generic *) odr_malloc(o, sizeof(*p->u.generic)); p->u.generic->no = i; p->u.generic->ns = handlers[i].ns; p->u.generic->p = handler_data; } } else { ret = z_soap_error(o, p, "SOAP-ENV:Client", "No handler for NS", ns); } } xmlFreeDoc(doc); return ret; } else if (o->direction == ODR_ENCODE) { Z_SOAP *p = *pp; xmlNsPtr ns_env; xmlNodePtr envelope_ptr, body_ptr; xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); envelope_ptr = xmlNewNode(0, BAD_CAST "Envelope"); ns_env = xmlNewNs(envelope_ptr, BAD_CAST p->ns, BAD_CAST "SOAP-ENV"); xmlSetNs(envelope_ptr, ns_env); body_ptr = xmlNewChild(envelope_ptr, ns_env, BAD_CAST "Body", 0); xmlDocSetRootElement(doc, envelope_ptr); if (p->which == Z_SOAP_fault || p->which == Z_SOAP_error) { Z_SOAP_Fault *f = p->u.fault; xmlNodePtr fault_ptr = xmlNewChild(body_ptr, ns_env, BAD_CAST "Fault", 0); xmlNewChild(fault_ptr, ns_env, BAD_CAST "faultcode", BAD_CAST f->fault_code); xmlNewChild(fault_ptr, ns_env, BAD_CAST "faultstring", BAD_CAST f->fault_string); if (f->details) xmlNewChild(fault_ptr, ns_env, BAD_CAST "details", BAD_CAST f->details); } else if (p->which == Z_SOAP_generic) { int ret, no = p->u.generic->no; ret = (*handlers[no].f)(o, body_ptr, &p->u.generic->p, handlers[no].client_data, handlers[no].ns); if (ret) { xmlFreeDoc(doc); return ret; } } if (p->which == Z_SOAP_generic && !strcmp(p->ns, "SRU")) { xmlDocSetRootElement(doc, body_ptr->children); body_ptr->children = 0; xmlFreeNode(envelope_ptr); } if (stylesheet) { char *content = (char *) odr_malloc(o, strlen(stylesheet) + 40); xmlNodePtr pi, ptr = xmlDocGetRootElement(doc); sprintf(content, "type=\"text/xsl\" href=\"%s\"", stylesheet); pi = xmlNewPI(BAD_CAST "xml-stylesheet", BAD_CAST content); xmlAddPrevSibling(ptr, pi); } if (1) { xmlChar *buf_out; int len_out; if (encoding) xmlDocDumpMemoryEnc(doc, &buf_out, &len_out, encoding); else xmlDocDumpMemory(doc, &buf_out, &len_out); *content_buf = (char *) odr_malloc(o, len_out); *content_len = len_out; memcpy(*content_buf, buf_out, len_out); xmlFree(buf_out); } xmlFreeDoc(doc); return 0; } return 0; } #else 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) { static char *err_xml = "\n" "\n" "\t\n" "\t\t\n" "\t\t\tSOAP-ENV:Server\n" "\t\t\tHTTP error\n" "\t\t\tSOAP not supported in this YAZ configuration\n" "\t\t\n" "\t\n" "\n"; if (o->direction == ODR_ENCODE) { *content_buf = err_xml; *content_len = strlen(err_xml); } return -1; } #endif int z_soap_codec_enc(ODR o, Z_SOAP **pp, char **content_buf, int *content_len, Z_SOAP_Handler *handlers, const char *encoding) { return z_soap_codec_enc_xsl(o, pp, content_buf, content_len, handlers, encoding, 0); } int z_soap_codec(ODR o, Z_SOAP **pp, char **content_buf, int *content_len, Z_SOAP_Handler *handlers) { return z_soap_codec_enc(o, pp, content_buf, content_len, handlers, 0); } int z_soap_error(ODR o, Z_SOAP *p, const char *fault_code, const char *fault_string, const char *details) { p->which = Z_SOAP_error; p->u.soap_error = (Z_SOAP_Fault *) odr_malloc(o, sizeof(*p->u.soap_error)); p->u.soap_error->fault_code = odr_strdup(o, fault_code); p->u.soap_error->fault_string = odr_strdup(o, fault_string); if (details) p->u.soap_error->details = odr_strdup(o, details); else p->u.soap_error->details = 0; return -1; } /* * Local variables: * c-basic-offset: 4 * c-file-style: "Stroustrup" * indent-tabs-mode: nil * End: * vim: shiftwidth=4 tabstop=8 expandtab */