Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xml_to_soap.c, revision 1.1
1.1 ! misho 1: /*
! 2: This file is part of libXMLRPC - a C library for xml-encoded function calls.
! 3:
! 4: Author: Dan Libby (dan@libby.com)
! 5: */
! 6:
! 7:
! 8: /*-**********************************************************************
! 9: * TODO: *
! 10: * - [SOAP-ENC:position] read sparse arrays (and write?) *
! 11: * - [SOAP-ENC:offset] read partially transmitted arrays (and write?) *
! 12: * - read "flattened" multi-dimensional arrays. (don't bother writing) *
! 13: * *
! 14: * BUGS: *
! 15: * - does not read schema. thus only knows soap pre-defined types. *
! 16: * - references (probably) do not work. untested. *
! 17: * - does not expose SOAP-ENV:Header to application at all. *
! 18: * - does not use namespaces correctly, thus: *
! 19: * - namespaces are hard-coded in comparison tokens *
! 20: * - if a sender uses another namespace identifer, it will break *
! 21: ************************************************************************/
! 22:
! 23:
! 24: static const char rcsid[] = "#(@) $Id:";
! 25:
! 26: #ifdef _WIN32
! 27: #include "xmlrpc_win32.h"
! 28: #endif
! 29: #include <string.h>
! 30: #include <stdlib.h>
! 31: #include "xml_to_soap.h"
! 32: #include "base64.h"
! 33:
! 34: /* list of tokens used in vocab */
! 35: #define TOKEN_ANY "xsd:ur-type"
! 36: #define TOKEN_ARRAY "SOAP-ENC:Array"
! 37: #define TOKEN_ARRAY_TYPE "SOAP-ENC:arrayType"
! 38: #define TOKEN_BASE64 "SOAP-ENC:base64"
! 39: #define TOKEN_BOOLEAN "xsd:boolean"
! 40: #define TOKEN_DATETIME "xsd:timeInstant"
! 41: #define TOKEN_DOUBLE "xsd:double"
! 42: #define TOKEN_FLOAT "xsd:float"
! 43: #define TOKEN_ID "id"
! 44: #define TOKEN_INT "xsd:int"
! 45: #define TOKEN_NULL "xsi:null"
! 46: #define TOKEN_STRING "xsd:string"
! 47: #define TOKEN_STRUCT "xsd:struct"
! 48: #define TOKEN_TYPE "xsi:type"
! 49: #define TOKEN_FAULT "SOAP-ENV:Fault"
! 50: #define TOKEN_MUSTUNDERSTAND "SOAP-ENV:mustUnderstand"
! 51: #define TOKEN_ACTOR "SOAP-ENV:actor"
! 52: #define TOKEN_ACTOR_NEXT "http://schemas.xmlsoap.org/soap/actor/next"
! 53:
! 54: #define TOKEN_XMLRPC_FAULTCODE "faultCode"
! 55: #define TOKEN_XMLRPC_FAULTSTRING "faultString"
! 56: #define TOKEN_SOAP_FAULTCODE "faultcode"
! 57: #define TOKEN_SOAP_FAULTSTRING "faultstring"
! 58: #define TOKEN_SOAP_FAULTDETAILS "details"
! 59: #define TOKEN_SOAP_FAULTACTOR "actor"
! 60:
! 61:
! 62: /* determine if a string represents a soap type, as used in element names */
! 63: static inline int is_soap_type(const char* soap_type) {
! 64: return(strstr(soap_type, "SOAP-ENC:") || strstr(soap_type, "xsd:")) ? 1 : 0;
! 65: }
! 66:
! 67: /* utility func to generate a new attribute. possibly should be in xml_element.c?? */
! 68: static xml_element_attr* new_attr(const char* key, const char* val) {
! 69: xml_element_attr* attr = malloc(sizeof(xml_element_attr));
! 70: if (attr) {
! 71: attr->key = key ? strdup(key) : NULL;
! 72: attr->val = val ? strdup(val) : NULL;
! 73: }
! 74: return attr;
! 75: }
! 76:
! 77: struct array_info {
! 78: char kids_type[128];
! 79: unsigned long size;
! 80: /* ... ? */
! 81: };
! 82:
! 83:
! 84: /* parses soap arrayType attribute to generate an array_info structure.
! 85: * TODO: should deal with sparse, flattened, & multi-dimensional arrays
! 86: */
! 87: static struct array_info* parse_array_type_info(const char* array_type) {
! 88: struct array_info* ai = NULL;
! 89: if (array_type) {
! 90: ai = (struct array_info*)calloc(1, sizeof(struct array_info));
! 91: if (ai) {
! 92: char buf[128], *p;
! 93: snprintf(buf, sizeof(buf), "%s", array_type);
! 94: p = strchr(buf, '[');
! 95: if (p) {
! 96: *p = 0;
! 97: }
! 98: strcpy(ai->kids_type, buf);
! 99: }
! 100: }
! 101: return ai;
! 102: }
! 103:
! 104: /* performs heuristics on an xmlrpc_vector_array to determine
! 105: * appropriate soap arrayType string.
! 106: */
! 107: static const char* get_array_soap_type(XMLRPC_VALUE node) {
! 108: XMLRPC_VALUE_TYPE_EASY type = xmlrpc_type_none;
! 109:
! 110: XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
! 111: int loopCount = 0;
! 112: const char* soapType = TOKEN_ANY;
! 113:
! 114: type = XMLRPC_GetValueTypeEasy(xIter);
! 115: xIter = XMLRPC_VectorNext(node);
! 116:
! 117: while (xIter) {
! 118: /* 50 seems like a decent # of loops. That will likely
! 119: * cover most cases. Any more and we start to sacrifice
! 120: * performance.
! 121: */
! 122: if ( (XMLRPC_GetValueTypeEasy(xIter) != type) || loopCount >= 50) {
! 123: type = xmlrpc_type_none;
! 124: break;
! 125: }
! 126: loopCount ++;
! 127:
! 128: xIter = XMLRPC_VectorNext(node);
! 129: }
! 130: switch (type) {
! 131: case xmlrpc_type_none:
! 132: soapType = TOKEN_ANY;
! 133: break;
! 134: case xmlrpc_type_empty:
! 135: soapType = TOKEN_NULL;
! 136: break;
! 137: case xmlrpc_type_int:
! 138: soapType = TOKEN_INT;
! 139: break;
! 140: case xmlrpc_type_double:
! 141: soapType = TOKEN_DOUBLE;
! 142: break;
! 143: case xmlrpc_type_boolean:
! 144: soapType = TOKEN_BOOLEAN;
! 145: break;
! 146: case xmlrpc_type_string:
! 147: soapType = TOKEN_STRING;
! 148: break;
! 149: case xmlrpc_type_base64:
! 150: soapType = TOKEN_BASE64;
! 151: break;
! 152: case xmlrpc_type_datetime:
! 153: soapType = TOKEN_DATETIME;
! 154: break;
! 155: case xmlrpc_type_struct:
! 156: soapType = TOKEN_STRUCT;
! 157: break;
! 158: case xmlrpc_type_array:
! 159: soapType = TOKEN_ARRAY;
! 160: break;
! 161: case xmlrpc_type_mixed:
! 162: soapType = TOKEN_STRUCT;
! 163: break;
! 164: }
! 165: return soapType;
! 166: }
! 167:
! 168: /* determines whether a node is a fault or not, and of which type:
! 169: * 0 = not a fault,
! 170: * 1 = xmlrpc style fault
! 171: * 2 = soap style fault.
! 172: */
! 173: static inline int get_fault_type(XMLRPC_VALUE node) {
! 174: if (XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTCODE) &&
! 175: XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTSTRING)) {
! 176: return 1;
! 177: }
! 178: else if (XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTCODE) &&
! 179: XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTSTRING)) {
! 180: return 2;
! 181: }
! 182: return 0;
! 183: }
! 184:
! 185: /* input: an XMLRPC_VALUE representing a fault struct in xml-rpc style.
! 186: * output: an XMLRPC_VALUE representing a fault struct in soap style,
! 187: * with xmlrpc codes mapped to soap codes, and all other values preserved.
! 188: * note that the returned value is a completely new value, and must be freed.
! 189: * the input value is untouched.
! 190: */
! 191: static XMLRPC_VALUE gen_fault_xmlrpc(XMLRPC_VALUE node, xml_element* el_target) {
! 192: XMLRPC_VALUE xDup = XMLRPC_DupValueNew(node);
! 193: XMLRPC_VALUE xCode = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTCODE);
! 194: XMLRPC_VALUE xStr = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTSTRING);
! 195:
! 196: XMLRPC_SetValueID(xCode, TOKEN_SOAP_FAULTCODE, 0);
! 197: XMLRPC_SetValueID(xStr, TOKEN_SOAP_FAULTSTRING, 0);
! 198:
! 199: /* rough mapping of xmlrpc fault codes to soap codes */
! 200: switch (XMLRPC_GetValueInt(xCode)) {
! 201: case -32700: /* "parse error. not well formed", */
! 202: case -32701: /* "parse error. unsupported encoding" */
! 203: case -32702: /* "parse error. invalid character for encoding" */
! 204: case -32600: /* "server error. invalid xml-rpc. not conforming to spec." */
! 205: case -32601: /* "server error. requested method not found" */
! 206: case -32602: /* "server error. invalid method parameters" */
! 207: XMLRPC_SetValueString(xCode, "SOAP-ENV:Client", 0);
! 208: break;
! 209: case -32603: /* "server error. internal xml-rpc error" */
! 210: case -32500: /* "application error" */
! 211: case -32400: /* "system error" */
! 212: case -32300: /* "transport error */
! 213: XMLRPC_SetValueString(xCode, "SOAP-ENV:Server", 0);
! 214: break;
! 215: }
! 216: return xDup;
! 217: }
! 218:
! 219: /* returns a new XMLRPC_VALUE representing a soap fault, comprised of a struct with four keys. */
! 220: static XMLRPC_VALUE gen_soap_fault(const char* fault_code, const char* fault_string,
! 221: const char* actor, const char* details) {
! 222: XMLRPC_VALUE xReturn = XMLRPC_CreateVector(TOKEN_FAULT, xmlrpc_vector_struct);
! 223: XMLRPC_AddValuesToVector(xReturn,
! 224: XMLRPC_CreateValueString(TOKEN_SOAP_FAULTCODE, fault_code, 0),
! 225: XMLRPC_CreateValueString(TOKEN_SOAP_FAULTSTRING, fault_string, 0),
! 226: XMLRPC_CreateValueString(TOKEN_SOAP_FAULTACTOR, actor, 0),
! 227: XMLRPC_CreateValueString(TOKEN_SOAP_FAULTDETAILS, details, 0),
! 228: NULL);
! 229: return xReturn;
! 230: }
! 231:
! 232: /* translates xml soap dom to native data structures. recursive. */
! 233: XMLRPC_VALUE xml_element_to_SOAP_REQUEST_worker(XMLRPC_REQUEST request,
! 234: XMLRPC_VALUE xParent,
! 235: struct array_info* parent_array,
! 236: XMLRPC_VALUE xCurrent,
! 237: xml_element* el,
! 238: int depth) {
! 239: XMLRPC_REQUEST_TYPE rtype = xmlrpc_request_none;
! 240:
! 241: /* no current element on first call */
! 242: if (!xCurrent) {
! 243: xCurrent = XMLRPC_CreateValueEmpty();
! 244: }
! 245:
! 246: /* increment recursion depth guage */
! 247: depth ++;
! 248:
! 249: /* safety first. must have a valid element */
! 250: if (el && el->name) {
! 251: const char* id = NULL;
! 252: const char* type = NULL, *arrayType=NULL, *actor = NULL;
! 253: xml_element_attr* attr_iter = Q_Head(&el->attrs);
! 254: int b_must_understand = 0;
! 255:
! 256: /* in soap, types may be specified in either element name -or- with xsi:type attribute. */
! 257: if (is_soap_type(el->name)) {
! 258: type = el->name;
! 259: }
! 260: /* if our parent node, by definition a vector, is not an array, then
! 261: our element name must be our key identifier. */
! 262: else if (XMLRPC_GetVectorType(xParent) != xmlrpc_vector_array) {
! 263: id = el->name;
! 264: if(!strcmp(id, "item")) {
! 265: }
! 266: }
! 267:
! 268: /* iterate through element attributes, pick out useful stuff. */
! 269: while (attr_iter) {
! 270: /* element's type */
! 271: if (!strcmp(attr_iter->key, TOKEN_TYPE)) {
! 272: type = attr_iter->val;
! 273: }
! 274: /* array type */
! 275: else if (!strcmp(attr_iter->key, TOKEN_ARRAY_TYPE)) {
! 276: arrayType = attr_iter->val;
! 277: }
! 278: /* must understand, sometimes present in headers. */
! 279: else if (!strcmp(attr_iter->key, TOKEN_MUSTUNDERSTAND)) {
! 280: b_must_understand = strchr(attr_iter->val, '1') ? 1 : 0;
! 281: }
! 282: /* actor, used in conjuction with must understand. */
! 283: else if (!strcmp(attr_iter->key, TOKEN_ACTOR)) {
! 284: actor = attr_iter->val;
! 285: }
! 286: attr_iter = Q_Next(&el->attrs);
! 287: }
! 288:
! 289: /* check if caller says we must understand something in a header. */
! 290: if (b_must_understand) {
! 291: /* is must understand actually indended for us?
! 292: BUG: spec says we should also determine if actor is our URL, but
! 293: we do not have that information. */
! 294: if (!actor || !strcmp(actor, TOKEN_ACTOR_NEXT)) {
! 295: /* TODO: implement callbacks or other mechanism for applications
! 296: to "understand" these headers. For now, we just bail if we
! 297: get a mustUnderstand header intended for us. */
! 298: XMLRPC_RequestSetError(request,
! 299: gen_soap_fault("SOAP-ENV:MustUnderstand",
! 300: "SOAP Must Understand Error",
! 301: "", ""));
! 302: return xCurrent;
! 303: }
! 304: }
! 305:
! 306: /* set id (key) if one was found. */
! 307: if (id) {
! 308: XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
! 309: }
! 310:
! 311: /* according to soap spec,
! 312: depth 1 = Envelope, 2 = Header, Body & Fault, 3 = methodcall or response. */
! 313: if (depth == 3) {
! 314: const char* methodname = el->name;
! 315: char* p = NULL;
! 316:
! 317: /* BUG: we determine request or response type using presence of "Response" in element name.
! 318: According to spec, this is only recommended, not required. Apparently, implementations
! 319: are supposed to know the type of action based on state, which strikes me as a bit lame.
! 320: Anyway, we don't have that state info, thus we use Response as a heuristic. */
! 321: rtype =
! 322: #ifdef strcasestr
! 323: strcasestr(el->name, "response") ? xmlrpc_request_response : xmlrpc_request_call;
! 324: #else
! 325: strstr(el->name, "esponse") ? xmlrpc_request_response : xmlrpc_request_call;
! 326: #endif
! 327: XMLRPC_RequestSetRequestType(request, rtype);
! 328:
! 329: /* Get methodname. strip xml namespace crap. */
! 330: p = strchr(el->name, ':');
! 331: if (p) {
! 332: methodname = p + 1;
! 333: }
! 334: if (rtype == xmlrpc_request_call) {
! 335: XMLRPC_RequestSetMethodName(request, methodname);
! 336: }
! 337: }
! 338:
! 339:
! 340: /* Next, we begin to convert actual values. if no children, then must be a scalar value. */
! 341: if (!Q_Size(&el->children)) {
! 342: if (!type && parent_array && parent_array->kids_type[0]) {
! 343: type = parent_array->kids_type;
! 344: }
! 345: if (!type || !strcmp(type, TOKEN_STRING)) {
! 346: XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
! 347: }
! 348: else if (!strcmp(type, TOKEN_INT)) {
! 349: XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
! 350: }
! 351: else if (!strcmp(type, TOKEN_BOOLEAN)) {
! 352: XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
! 353: }
! 354: else if (!strcmp(type, TOKEN_DOUBLE) ||
! 355: !strcmp(type, TOKEN_FLOAT)) {
! 356: XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
! 357: }
! 358: else if (!strcmp(type, TOKEN_NULL)) {
! 359: /* already an empty val. do nothing. */
! 360: }
! 361: else if (!strcmp(type, TOKEN_DATETIME)) {
! 362: XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
! 363: }
! 364: else if (!strcmp(type, TOKEN_BASE64)) {
! 365: struct buffer_st buf;
! 366: base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
! 367: XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
! 368: buffer_delete(&buf);
! 369: }
! 370: }
! 371: /* Element has children, thus a vector, or "compound type" in soap-speak. */
! 372: else {
! 373: struct array_info* ai = NULL;
! 374: xml_element* iter = (xml_element*)Q_Head(&el->children);
! 375:
! 376: if (!type || !strcmp(type, TOKEN_STRUCT)) {
! 377: XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
! 378: }
! 379: else if (!strcmp(type, TOKEN_ARRAY) || arrayType != NULL) {
! 380: /* determine magic associated with soap array type.
! 381: this is passed down as we recurse, so our children have access to the info. */
! 382: ai = parse_array_type_info(arrayType); /* alloc'ed ai free'd below. */
! 383: XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
! 384: }
! 385: else {
! 386: /* mixed is probably closest thing we have to compound type. */
! 387: XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
! 388: }
! 389: /* Recurse, adding values as we go. Check for error during recursion
! 390: and if found, bail. this short-circuits us out of the recursion. */
! 391: while ( iter && !XMLRPC_RequestGetError(request) ) {
! 392: XMLRPC_VALUE xNext = NULL;
! 393: /* top level elements don't actually represent values, so we just pass the
! 394: current value along until we are deep enough. */
! 395: if ( depth <= 2 ||
! 396: (rtype == xmlrpc_request_response && depth <= 3) ) {
! 397: xml_element_to_SOAP_REQUEST_worker(request, NULL, ai, xCurrent, iter, depth);
! 398: }
! 399: /* ready to do some actual de-serialization. create a new empty value and
! 400: pass that along to be init'd, then add it to our current vector. */
! 401: else {
! 402: xNext = XMLRPC_CreateValueEmpty();
! 403: xml_element_to_SOAP_REQUEST_worker(request, xCurrent, ai, xNext, iter, depth);
! 404: XMLRPC_AddValueToVector(xCurrent, xNext);
! 405: }
! 406: iter = (xml_element*)Q_Next(&el->children);
! 407: }
! 408: /* cleanup */
! 409: if (ai) {
! 410: free(ai);
! 411: }
! 412: }
! 413: }
! 414: return xCurrent;
! 415: }
! 416:
! 417: /* Convert soap xml dom to XMLRPC_VALUE, sans request info. untested. */
! 418: XMLRPC_VALUE xml_element_to_SOAP_VALUE(xml_element* el)
! 419: {
! 420: return xml_element_to_SOAP_REQUEST_worker(NULL, NULL, NULL, NULL, el, 0);
! 421: }
! 422:
! 423: /* Convert soap xml dom to XMLRPC_REQUEST */
! 424: XMLRPC_VALUE xml_element_to_SOAP_REQUEST(XMLRPC_REQUEST request, xml_element* el)
! 425: {
! 426: if (request) {
! 427: return XMLRPC_RequestSetData(request, xml_element_to_SOAP_REQUEST_worker(request, NULL, NULL, NULL, el, 0));
! 428: }
! 429: return NULL;
! 430: }
! 431:
! 432:
! 433: /* translates data structures to soap/xml. recursive */
! 434: xml_element* SOAP_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
! 435: #define BUF_SIZE 128
! 436: xml_element* elem_val = NULL;
! 437: if (node) {
! 438: int bFreeNode = 0; /* sometimes we may need to free 'node' variable */
! 439: char buf[BUF_SIZE];
! 440: XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(node);
! 441: char* pName = NULL, *pAttrType = NULL;
! 442:
! 443: /* create our return value element */
! 444: elem_val = xml_elem_new();
! 445:
! 446: switch (type) {
! 447: case xmlrpc_type_struct:
! 448: case xmlrpc_type_mixed:
! 449: case xmlrpc_type_array:
! 450: if (type == xmlrpc_type_array) {
! 451: /* array's are _very_ special in soap.
! 452: TODO: Should handle sparse/partial arrays here. */
! 453:
! 454: /* determine soap array type. */
! 455: const char* type = get_array_soap_type(node);
! 456: xml_element_attr* attr_array_type = NULL;
! 457:
! 458: /* specify array kids type and array size. */
! 459: snprintf(buf, sizeof(buf), "%s[%i]", type, XMLRPC_VectorSize(node));
! 460: attr_array_type = new_attr(TOKEN_ARRAY_TYPE, buf);
! 461:
! 462: Q_PushTail(&elem_val->attrs, attr_array_type);
! 463:
! 464: pAttrType = TOKEN_ARRAY;
! 465: }
! 466: /* check for fault, which is a rather special case.
! 467: (can't these people design anything consistent/simple/elegant?) */
! 468: else if (type == xmlrpc_type_struct) {
! 469: int fault_type = get_fault_type(node);
! 470: if (fault_type) {
! 471: if (fault_type == 1) {
! 472: /* gen fault from xmlrpc style fault codes
! 473: notice that we get a new node, which must be freed herein. */
! 474: node = gen_fault_xmlrpc(node, elem_val);
! 475: bFreeNode = 1;
! 476: }
! 477: pName = TOKEN_FAULT;
! 478: }
! 479: }
! 480:
! 481: {
! 482: /* recurse through sub-elements */
! 483: XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
! 484: while ( xIter ) {
! 485: xml_element* next_el = SOAP_to_xml_element_worker(request, xIter);
! 486: if (next_el) {
! 487: Q_PushTail(&elem_val->children, next_el);
! 488: }
! 489: xIter = XMLRPC_VectorNext(node);
! 490: }
! 491: }
! 492:
! 493: break;
! 494:
! 495: /* handle scalar types */
! 496: case xmlrpc_type_empty:
! 497: pAttrType = TOKEN_NULL;
! 498: break;
! 499: case xmlrpc_type_string:
! 500: pAttrType = TOKEN_STRING;
! 501: simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
! 502: break;
! 503: case xmlrpc_type_int:
! 504: pAttrType = TOKEN_INT;
! 505: snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
! 506: simplestring_add(&elem_val->text, buf);
! 507: break;
! 508: case xmlrpc_type_boolean:
! 509: pAttrType = TOKEN_BOOLEAN;
! 510: snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
! 511: simplestring_add(&elem_val->text, buf);
! 512: break;
! 513: case xmlrpc_type_double:
! 514: pAttrType = TOKEN_DOUBLE;
! 515: snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
! 516: simplestring_add(&elem_val->text, buf);
! 517: break;
! 518: case xmlrpc_type_datetime:
! 519: {
! 520: time_t tt = XMLRPC_GetValueDateTime(node);
! 521: struct tm *tm = localtime (&tt);
! 522: pAttrType = TOKEN_DATETIME;
! 523: if(strftime (buf, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm)) {
! 524: simplestring_add(&elem_val->text, buf);
! 525: }
! 526: }
! 527: break;
! 528: case xmlrpc_type_base64:
! 529: {
! 530: struct buffer_st buf;
! 531: pAttrType = TOKEN_BASE64;
! 532: base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
! 533: simplestring_addn(&elem_val->text, buf.data, buf.offset );
! 534: buffer_delete(&buf);
! 535: }
! 536: break;
! 537: break;
! 538: default:
! 539: break;
! 540: }
! 541:
! 542: /* determining element's name is a bit tricky, due to soap semantics. */
! 543: if (!pName) {
! 544: /* if the value's type is known... */
! 545: if (pAttrType) {
! 546: /* see if it has an id (key). If so, use that as name, and type as an attribute. */
! 547: pName = (char*)XMLRPC_GetValueID(node);
! 548: if (pName) {
! 549: Q_PushTail(&elem_val->attrs, new_attr(TOKEN_TYPE, pAttrType));
! 550: }
! 551:
! 552: /* otherwise, use the type as the name. */
! 553: else {
! 554: pName = pAttrType;
! 555: }
! 556: }
! 557: /* if the value's type is not known... (a rare case?) */
! 558: else {
! 559: /* see if it has an id (key). otherwise, default to generic "item" */
! 560: pName = (char*)XMLRPC_GetValueID(node);
! 561: if (!pName) {
! 562: pName = "item";
! 563: }
! 564: }
! 565: }
! 566: elem_val->name = strdup(pName);
! 567:
! 568: /* cleanup */
! 569: if (bFreeNode) {
! 570: XMLRPC_CleanupValue(node);
! 571: }
! 572: }
! 573: return elem_val;
! 574: }
! 575:
! 576: /* convert XMLRPC_VALUE to soap xml dom. untested. */
! 577: xml_element* SOAP_VALUE_to_xml_element(XMLRPC_VALUE node) {
! 578: return SOAP_to_xml_element_worker(NULL, node);
! 579: }
! 580:
! 581: /* convert XMLRPC_REQUEST to soap xml dom. */
! 582: xml_element* SOAP_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
! 583: xml_element* root = xml_elem_new();
! 584:
! 585: /* safety first. */
! 586: if (root) {
! 587: xml_element* body = xml_elem_new();
! 588: root->name = strdup("SOAP-ENV:Envelope");
! 589:
! 590: /* silly namespace stuff */
! 591: Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"));
! 592: Q_PushTail(&root->attrs, new_attr("xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance"));
! 593: Q_PushTail(&root->attrs, new_attr("xmlns:xsd", "http://www.w3.org/1999/XMLSchema"));
! 594: Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"));
! 595: Q_PushTail(&root->attrs, new_attr("xmlns:si", "http://soapinterop.org/xsd"));
! 596: Q_PushTail(&root->attrs, new_attr("xmlns:ns6", "http://testuri.org"));
! 597: Q_PushTail(&root->attrs, new_attr("SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"));
! 598:
! 599: /* Q_PushHead(&root->attrs, new_attr("xmlns:ks", "http://kitchen.sink.org/soap/everything/under/sun"));
! 600: JUST KIDDING!! :-) ----> ------------------------------------------------- */
! 601:
! 602: if (body) {
! 603: /* go ahead and serialize first... */
! 604: xml_element* el_serialized =
! 605: SOAP_to_xml_element_worker(request,
! 606: XMLRPC_RequestGetData(request));
! 607:
! 608: /* check for fault, in which case, there is no intermediate element */
! 609: if (el_serialized && !strcmp(el_serialized->name, TOKEN_FAULT)) {
! 610: Q_PushTail(&body->children, el_serialized);
! 611: }
! 612: /* usual case: not a fault. Add Response element in between. */
! 613: else {
! 614: xml_element* rpc = xml_elem_new();
! 615:
! 616: if (rpc) {
! 617: const char* methodname = XMLRPC_RequestGetMethodName(request);
! 618: XMLRPC_REQUEST_TYPE rtype = XMLRPC_RequestGetRequestType(request);
! 619:
! 620: /* if we are making a request, we want to use the methodname as is. */
! 621: if (rtype == xmlrpc_request_call) {
! 622: if (methodname) {
! 623: rpc->name = strdup(methodname);
! 624: }
! 625: }
! 626: /* if it's a response, we append "Response". Also, given xmlrpc-epi
! 627: API/architecture, it's likely that we don't have a methodname for
! 628: the response, so we have to check that. */
! 629: else {
! 630: char buf[128];
! 631: snprintf(buf, sizeof(buf), "%s%s",
! 632: methodname ? methodname : "",
! 633: "Response");
! 634:
! 635: rpc->name = strdup(buf);
! 636: }
! 637:
! 638: /* add serialized data to method call/response.
! 639: add method call/response to body element */
! 640: if (rpc->name) {
! 641: if(el_serialized) {
! 642: if(Q_Size(&el_serialized->children) && rtype == xmlrpc_request_call) {
! 643: xml_element* iter = (xml_element*)Q_Head(&el_serialized->children);
! 644: while(iter) {
! 645: Q_PushTail(&rpc->children, iter);
! 646: iter = (xml_element*)Q_Next(&el_serialized->children);
! 647: }
! 648: xml_elem_free_non_recurse(el_serialized);
! 649: }
! 650: else {
! 651: Q_PushTail(&rpc->children, el_serialized);
! 652: }
! 653: }
! 654:
! 655: Q_PushTail(&body->children, rpc);
! 656: }
! 657: else {
! 658: /* no method name?!
! 659: TODO: fault here...? */
! 660: }
! 661: }
! 662: }
! 663: body->name = strdup("SOAP-ENV:Body");
! 664: Q_PushTail(&root->children, body);
! 665: }
! 666: }
! 667:
! 668: return root;
! 669: }
! 670:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>