00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00065
00066
00067
00068
00069
00070
00071
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
00087
00088
00089
00090
00091
00092
00093
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
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
00274
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
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
00532 return soap_xml_get_children(body);
00533 }
00534
00535
00536
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
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];
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
00599 if (!(node = soap_xml_get_children(body)))
00600 {
00601 log_error1("No namespace found");
00602 return NULL;
00603 }
00604
00605
00606 if (node->ns)
00607 {
00608 ns = xmlSearchNs(body->doc, node, node->ns->prefix);
00609 if (ns != NULL)
00610 {
00611 return ((char *) ns->href);
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);
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 }