Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xml_to_soap.c, revision 1.1.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>