Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xml_to_soap.c, revision 1.1.1.2

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:                        }
1.1.1.2 ! misho     282:                        /* actor, used in conjunction with must understand. */
1.1       misho     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>