soap-env.c

Go to the documentation of this file.
00001 /******************************************************************
00002 *  $Id: soap-env.c,v 1.27 2006/11/26 20:13:05 m0gg Exp $
00003 *
00004 * CSOAP Project:  A SOAP client/server library in C
00005 * Copyright (C) 2003  Ferhat Ayaz
00006 *
00007 * This library is free software; you can redistribute it and/or
00008 * modify it under the terms of the GNU Library General Public
00009 * License as published by the Free Software Foundation; either
00010 * version 2 of the License, or (at your option) any later version.
00011 *
00012 * This library is distributed in the hope that it will be useful,
00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 * Library General Public License for more details.
00016 *
00017 * You should have received a copy of the GNU Library General Public
00018 * License along with this library; if not, write to the
00019 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020 * Boston, MA  02111-1307, USA.
00021 * 
00022 * Email: ayaz@jprogrammer.net
00023 ******************************************************************/
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #ifdef HAVE_SYS_TYPES_H
00029 #include <sys/types.h>
00030 #endif
00031 
00032 #ifdef HAVE_STDARG_H
00033 #include <stdarg.h>
00034 #endif
00035 
00036 #ifdef HAVE_STDIO_H
00037 #include <stdio.h>
00038 #endif
00039 
00040 #ifdef HAVE_STRING_H
00041 #include <string.h>
00042 #endif
00043 
00044 #ifdef HAVE_ERRNO_H
00045 #include <errno.h>
00046 #endif
00047 
00048 #ifdef HAVE_NETINET_IN_H
00049 #include <netinet/in.h>
00050 #endif
00051 
00052 #include <libxml/tree.h>
00053 #include <libxml/xpath.h>
00054 #include <libxml/xmlstring.h>
00055 
00056 #include <nanohttp/nanohttp-error.h>
00057 #include <nanohttp/nanohttp-logging.h>
00058 
00059 #include "soap-xml.h"
00060 #include "soap-fault.h"
00061 #include "soap-env.h"
00062 
00063 /*
00064 Parameters:
00065 1- soap_env_ns
00066 2- soap_env_enc
00067 3- xsi_ns
00068 4- xsd_ns
00069 3- method name
00070 4- uri
00071 5- method name(again)
00072 */
00073 #define _SOAP_MSG_TEMPLATE_ \
00074         "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"%s\" SOAP-ENV:encodingStyle=\"%s\"" \
00075         " xmlns:xsi=\"%s\"" \
00076         " xmlns:xsd=\"%s\">" \
00077          "<SOAP-ENV:Header />" \
00078          "<SOAP-ENV:Body>"\
00079           "<m:%s xmlns:m=\"%s\">"\
00080           "</m:%s>" \
00081          "</SOAP-ENV:Body>"\
00082         "</SOAP-ENV:Envelope>"
00083 
00084 
00085 /*
00086 Parameters:
00087 1- soap_env_ns
00088 2- soap_env_enc
00089 3- xsi_ns
00090 4- xsd_ns
00091 3- method name
00092 4- uri
00093 5- method name(again)
00094 */
00095 #define _SOAP_MSG_TEMPLATE_EMPTY_TARGET_ \
00096         "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"%s\" SOAP-ENV:encodingStyle=\"%s\"" \
00097         " xmlns:xsi=\"%s\"" \
00098         " xmlns:xsd=\"%s\">" \
00099          "<SOAP-ENV:Header />" \
00100          "<SOAP-ENV:Body>"\
00101           "<%s xmlns=\"%s\">"\
00102           "</%s>" \
00103          "</SOAP-ENV:Body>"\
00104         "</SOAP-ENV:Envelope>"
00105 
00106 
00107 /* ---------------------------------------------------------------------------- */
00108 /*     XML Serializers (implemented at the and of this document)              */
00109 /* ---------------------------------------------------------------------------- */
00110 struct XmlNodeHolder
00111 {
00112   xmlNodePtr node;
00113 };
00114 
00115 static void
00116 xmlbuilder_start_element(const xmlChar * element_name, int attr_count, xmlChar ** keys, xmlChar ** values, void *userData)
00117 {
00118   struct XmlNodeHolder *holder = (struct XmlNodeHolder *) userData;
00119   xmlNodePtr parent = NULL;
00120 
00121   if (holder == NULL)
00122     return;
00123   parent = holder->node;
00124   if (parent == NULL)
00125     return;
00126 
00127   holder->node = xmlNewChild(parent, NULL, element_name, NULL);
00128 
00129   return;
00130 }
00131 
00132 static void
00133 xmlbuilder_characters(const xmlChar * element_name, const xmlChar * chars, void *userData)
00134 {
00135   struct XmlNodeHolder *holder = (struct XmlNodeHolder *) userData;
00136   xmlNodePtr parent = NULL;
00137 
00138   if (holder == NULL)
00139     return;
00140   parent = holder->node;
00141   if (parent == NULL)
00142     return;
00143 
00144   xmlNewTextChild(parent, NULL, element_name, chars);
00145 
00146   return;
00147 }
00148 
00149 static void
00150 xmlbuilder_end_element(const xmlChar * element_name, void *userData)
00151 {
00152 
00153   struct XmlNodeHolder *holder = (struct XmlNodeHolder *) userData;
00154   xmlNodePtr parent = NULL;
00155 
00156   if (holder == NULL)
00157     return;
00158   parent = holder->node;
00159   if (parent == NULL)
00160     return;
00161 
00162   holder->node = parent->parent;
00163 
00164   return;
00165 }
00166 
00167 herror_t
00168 soap_env_new_from_doc(xmlDocPtr doc, struct SoapEnv ** out)
00169 {
00170   xmlNodePtr root;
00171   struct SoapEnv *env;
00172 
00173   if (doc == NULL)
00174   {
00175     log_error1("Cannot create XML document!");
00176     return herror_new("soap_env_new_from_doc",
00177                       GENERAL_INVALID_PARAM,
00178                       "XML Document (xmlDocPtr) is NULL");
00179   }
00180 
00181   if (!(root = xmlDocGetRootElement(doc)))
00182   {
00183     log_error1("XML document is empty!");
00184     return herror_new("soap_env_new_from_doc",
00185                       XML_ERROR_EMPTY_DOCUMENT, "XML Document is empty!");
00186   }
00187 
00188   if (!(env = (struct SoapEnv *) malloc(sizeof(struct SoapEnv))))
00189   {
00190     log_error2("malloc failed (%s)", strerror(errno));
00191     return herror_new("soap_env_from_doc", GENERAL_INVALID_PARAM, "malloc failed (%s)", strerror(errno));
00192   }
00193 
00194   env->root = root;
00195   env->header = soap_env_get_header(env);
00196   env->body = soap_env_get_body(env);
00197   env->cur = soap_env_get_method(env);
00198 
00199   *out = env;
00200 
00201   return H_OK;
00202 }
00203 
00204 herror_t
00205 soap_env_new_from_buffer(const char *buffer, struct SoapEnv **out)
00206 {
00207   xmlDocPtr doc;
00208   herror_t err;
00209 
00210   if (buffer == NULL)
00211     return herror_new("soap_env_new_from_buffer",
00212                       GENERAL_INVALID_PARAM, "buffer (first param) is NULL");
00213 
00214   if (!(doc = xmlParseDoc(BAD_CAST buffer)))
00215     return herror_new("soap_env_new_from_buffer",
00216                       XML_ERROR_PARSE, "Cannot parse XML");
00217 
00218   if ((err = soap_env_new_from_doc(doc, out)) != H_OK)
00219   {
00220     xmlFreeDoc(doc);
00221   }
00222   return err;
00223 }
00224 
00225 
00226 herror_t
00227 soap_env_new_with_fault(int faultcode, const char *faultstring, const char *faultactor, const char *detail, struct SoapEnv **out)
00228 {
00229   xmlDocPtr doc;
00230   herror_t err;
00231 
00232   if (!(doc = soap_fault_build(faultcode, faultstring, faultactor, detail)))
00233     return herror_new("soap_env_new_with_fault", XML_ERROR_PARSE, "Cannot parse fault XML");
00234 
00235   if ((err = soap_env_new_from_doc(doc, out)) != H_OK)
00236     xmlFreeDoc(doc);
00237 
00238   return err;
00239 }
00240 
00241 
00242 herror_t
00243 soap_env_new_with_response(struct SoapEnv * request, struct SoapEnv ** out)
00244 {
00245   const char *method;
00246   char *res_method;
00247   herror_t ret;
00248   const char *urn;
00249 
00250   if (request == NULL)
00251   {
00252     return herror_new("soap_env_new_with_response",
00253                       GENERAL_INVALID_PARAM, "request (first param) is NULL");
00254   }
00255 
00256   if (request->root == NULL)
00257   {
00258     return herror_new("soap_env_new_with_response",
00259                       GENERAL_INVALID_PARAM,
00260                       "request (first param) has no XML structure");
00261   }
00262 
00263   if (!(method = soap_env_find_methodname(request)))
00264   {
00265     return herror_new("soap_env_new_with_response",
00266                       GENERAL_INVALID_PARAM,
00267                       "Method name not found in request");
00268   }
00269 
00270   if (!(urn = soap_env_find_urn(request)))
00271   {
00272 
00273     /* here we have no chance to find out the namespace */
00274     /* try to continue without namespace (urn) */
00275     urn = "";
00276   }
00277 
00278   if (!(res_method = (char *)malloc(strlen(method)+9)))
00279     return herror_new("soap_env_new_with_response", GENERAL_INVALID_PARAM, "malloc failed");
00280 
00281   sprintf(res_method, "%sResponse", method);
00282 
00283   ret = soap_env_new_with_method(urn, res_method, out);
00284 
00285   free(res_method);
00286 
00287   return ret;
00288 }
00289 
00290 
00291 herror_t
00292 soap_env_new_with_method(const char *urn, const char *method, struct SoapEnv ** out)
00293 {
00294   xmlDocPtr env;
00295   xmlChar buffer[1054];
00296 
00297   log_verbose2("URN = '%s'", urn);
00298   log_verbose2("Method = '%s'", method);
00299 
00300   if (!strcmp(urn, ""))
00301   {
00302     xmlStrPrintf(buffer, 1054, BAD_CAST _SOAP_MSG_TEMPLATE_EMPTY_TARGET_,
00303                  soap_env_ns, soap_env_enc, soap_xsi_ns,
00304                  soap_xsd_ns, BAD_CAST method, BAD_CAST urn, BAD_CAST method);
00305   }
00306   else
00307   {
00308     xmlStrPrintf(buffer, 1054, BAD_CAST _SOAP_MSG_TEMPLATE_,
00309                  soap_env_ns, soap_env_enc, soap_xsi_ns,
00310                  soap_xsd_ns, BAD_CAST method, BAD_CAST urn, BAD_CAST method);
00311   }
00312 
00313   if (!(env = xmlParseDoc(buffer)))
00314     return herror_new("soap_env_new_with_method",
00315                       XML_ERROR_PARSE, "Can not parse XML");
00316 
00317   return soap_env_new_from_doc(env, out);
00318 }
00319 
00320 
00321 xmlNodePtr
00322 soap_env_add_item(struct SoapEnv * call, const char *type, const char *name, const char *value)
00323 {
00324   xmlNodePtr newNode;
00325 
00326   newNode = xmlNewTextChild(call->cur, NULL, BAD_CAST name, BAD_CAST value);
00327 
00328   if (newNode == NULL)
00329   {
00330     log_error1("Can not create new XML node");
00331     return NULL;
00332   }
00333 
00334   if (type)
00335   {
00336     if (!xmlNewProp(newNode, BAD_CAST "xsi:type", BAD_CAST type))
00337     {
00338       log_error1("Can not create new XML attribute");
00339       return NULL;
00340     }
00341   }
00342 
00343   return newNode;
00344 }
00345 
00346 
00347 xmlNodePtr
00348 soap_env_add_itemf(struct SoapEnv * call, const char *type, const char *name, const char *format, ...)
00349 {
00350 
00351   va_list ap;
00352   char buffer[1054];
00353 
00354   va_start(ap, format);
00355   vsprintf(buffer, format, ap);
00356   va_end(ap);
00357 
00358   return soap_env_add_item(call, type, name, buffer);
00359 }
00360 
00361 
00362 xmlNodePtr
00363 soap_env_add_attachment(struct SoapEnv * call, const char *name, const char *href)
00364 {
00365   xmlNodePtr newNode;
00366 
00367   newNode = xmlNewTextChild(call->cur, NULL, BAD_CAST name, BAD_CAST "");
00368 
00369   if (newNode == NULL)
00370   {
00371     log_error1("Can not create new xml node");
00372     return NULL;
00373   }
00374 
00375   if (href)
00376   {
00377     if (!xmlNewProp(newNode, BAD_CAST "href", BAD_CAST href))
00378     {
00379       log_error1("Can not create new xml attribute");
00380       return NULL;
00381     }
00382   }
00383 
00384   return newNode;
00385 }
00386 
00387 
00388 void
00389 soap_env_add_custom(struct SoapEnv * call, void *obj, XmlSerializerCallback cb, const char *type, const char *name)
00390 {
00391   struct XmlNodeHolder holder;
00392 
00393   holder.node = soap_env_get_method(call);
00394 
00395   cb(obj, BAD_CAST name,
00396      xmlbuilder_start_element,
00397      xmlbuilder_characters, xmlbuilder_end_element, &holder);
00398 
00399   return;
00400 }
00401 
00402 
00403 xmlNodePtr
00404 soap_env_push_item(struct SoapEnv * call, const char *type, const char *name)
00405 {
00406 
00407   xmlNodePtr node;
00408 
00409   if ((node = soap_env_add_item(call, type, name, "")))
00410     call->cur = node;
00411 
00412   return node;
00413 }
00414 
00415 
00416 void
00417 soap_env_pop_item(struct SoapEnv * call)
00418 {
00419   call->cur = call->cur->parent;
00420 
00421   return;
00422 }
00423 
00424 
00425 void
00426 soap_env_free(struct SoapEnv * env)
00427 {
00428   if (env)
00429   {
00430     if (env->root)
00431     {
00432       xmlFreeDoc(env->root->doc);
00433     }
00434     free(env);
00435   }
00436 
00437   return;
00438 }
00439 
00440 
00441 xmlNodePtr
00442 soap_env_get_body(struct SoapEnv * env)
00443 {
00444   xmlNodePtr node;
00445 
00446   if (env == NULL)
00447   {
00448     log_error1("SOAP envelope is NULL");
00449     return NULL;
00450   }
00451 
00452   if (env->root == NULL)
00453   {
00454     log_error1("SOAP envelope contains no XML");
00455     return NULL;
00456   }
00457 
00458   for (node = soap_xml_get_children(env->root); node; node = soap_xml_get_next(node))
00459   {
00460     if (!xmlStrcmp(node->name, BAD_CAST "Body")
00461      && !xmlStrcmp(node->ns->href, BAD_CAST soap_env_ns))
00462       return node;
00463   }
00464 
00465   log_error1("Body tag not found!");
00466   return NULL;
00467 }
00468 
00469 
00470 xmlNodePtr
00471 soap_env_get_header(struct SoapEnv *env)
00472 {
00473   xmlNodePtr node;
00474 
00475   if (!env)
00476   {
00477     log_error1("SoapEnv is NULL");
00478     return NULL;
00479   }
00480 
00481   if (!env->root)
00482   {
00483     log_error1("SoapEnv contains no document");
00484     return NULL;
00485   }
00486 
00487   for (node = soap_xml_get_children(env->root); node; node = soap_xml_get_next(node))
00488   {
00489     if (!xmlStrcmp(node->name, BAD_CAST "Header")
00490      && !xmlStrcmp(node->ns->href, BAD_CAST soap_env_ns))
00491       return node;
00492   }
00493 
00494   return NULL;
00495 }
00496 
00497 
00498 xmlNodePtr
00499 soap_env_get_fault(struct SoapEnv * env)
00500 {
00501   xmlNodePtr node;
00502 
00503   node = soap_env_get_body(env);
00504 
00505   if (!node)
00506     return NULL;
00507 
00508   while (node != NULL)
00509   {
00510     if (!xmlStrcmp(node->name, BAD_CAST "Fault"))
00511       return node;
00512     node = soap_xml_get_next(node);
00513   }
00514 
00515 /*  log_warn1 ("Node Fault tag found!");*/
00516   return NULL;
00517 }
00518 
00519 
00520 xmlNodePtr
00521 soap_env_get_method(struct SoapEnv * env)
00522 {
00523   xmlNodePtr body;
00524 
00525   if (!(body = soap_env_get_body(env)))
00526   {
00527     log_verbose1("SoapEnv contains no Body element");
00528     return NULL;
00529   }
00530 
00531   /* method is the first child */
00532   return soap_xml_get_children(body);
00533 }
00534 
00535 
00536 /* XXX: unused function? */
00537 xmlNodePtr
00538 _soap_env_get_body(struct SoapEnv * env)
00539 {
00540   xmlNodePtr body;
00541   xmlNodeSetPtr nodeset;
00542   xmlXPathObjectPtr xpathobj;
00543 
00544   if (env == NULL)
00545   {
00546     log_error1("struct SoapEnv is NULL");
00547     return NULL;
00548   }
00549 
00550   if (env->root == NULL)
00551   {
00552     log_error1("struct SoapEnv contains no XML document");
00553     return NULL;
00554   }
00555 
00556   /* 
00557      find <Body> tag find out namespace xpath: //Envelope/Body/ */
00558   xpathobj = soap_xpath_eval(env->root->doc, "//Envelope/Body");
00559 
00560   if (!xpathobj)
00561   {
00562     log_error1("No Body (xpathobj)!");
00563     return NULL;
00564   }
00565 
00566   if (!(nodeset = xpathobj->nodesetval))
00567   {
00568     log_error1("No Body (nodeset)!");
00569     xmlXPathFreeObject(xpathobj);
00570     return NULL;
00571   }
00572 
00573   if (nodeset->nodeNr < 1)
00574   {
00575     log_error1("No Body (nodeNr)!");
00576     xmlXPathFreeObject(xpathobj);
00577     return NULL;
00578   }
00579 
00580   body = nodeset->nodeTab[0];   /* body is <Body> */
00581   xmlXPathFreeObject(xpathobj);
00582   return body;
00583 }
00584 
00585 
00586 const char *
00587 soap_env_find_urn(struct SoapEnv * env)
00588 {
00589   xmlNsPtr ns;
00590   xmlNodePtr body, node;
00591 
00592   if (!(body = soap_env_get_body(env)))
00593   {
00594     log_verbose1("body is NULL");
00595     return NULL;
00596   }
00597 
00598   /* node is the first child */
00599   if (!(node = soap_xml_get_children(body)))
00600   {
00601     log_error1("No namespace found");
00602     return NULL;
00603   }
00604 
00605   /* if (node->ns && node->ns->prefix) MRC 1/25/2006 */
00606   if (node->ns)
00607   {
00608     ns = xmlSearchNs(body->doc, node, node->ns->prefix);
00609     if (ns != NULL)
00610     {
00611       return ((char *) ns->href); /* namespace found! */
00612     }
00613   }
00614   else
00615   {
00616     static char *empty = "";
00617     log_warn1("No namespace found");
00618     return(empty);
00619   }
00620 
00621   return NULL;
00622 }
00623 
00624 
00625 const char *
00626 soap_env_find_methodname(struct SoapEnv * env)
00627 {
00628   xmlNodePtr body, node;
00629 
00630   if (!(body = soap_env_get_body(env)))
00631     return NULL;
00632 
00633   node = soap_xml_get_children(body);   /* node is the first child */
00634 
00635   if (node == NULL)
00636   {
00637     log_error1("No method found");
00638     return NULL;
00639   }
00640 
00641   if (node->name == NULL)
00642   {
00643     log_error1("No methodname found");
00644     return NULL;
00645 
00646   }
00647 
00648   return ((char *) node->name);
00649 }

Generated on Thu Jan 25 23:36:03 2007 for csoap by  doxygen 1.4.6