Return to php_packet_soap.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / soap |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 The PHP Group | ! 6: +----------------------------------------------------------------------+ ! 7: | This source file is subject to version 3.01 of the PHP license, | ! 8: | that is bundled with this package in the file LICENSE, and is | ! 9: | available through the world-wide-web at the following url: | ! 10: | http://www.php.net/license/3_01.txt | ! 11: | If you did not receive a copy of the PHP license and are unable to | ! 12: | obtain it through the world-wide-web, please send a note to | ! 13: | license@php.net so we can mail you a copy immediately. | ! 14: +----------------------------------------------------------------------+ ! 15: | Authors: Brad Lafountain <rodif_bl@yahoo.com> | ! 16: | Shane Caraveo <shane@caraveo.com> | ! 17: | Dmitry Stogov <dmitry@zend.com> | ! 18: +----------------------------------------------------------------------+ ! 19: */ ! 20: /* $Id: php_packet_soap.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 21: ! 22: #include "php_soap.h" ! 23: ! 24: /* SOAP client calls this function to parse response from SOAP server */ ! 25: int parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctionPtr fn, char *fn_name, zval *return_value, zval *soap_headers TSRMLS_DC) ! 26: { ! 27: char* envelope_ns = NULL; ! 28: xmlDocPtr response; ! 29: xmlNodePtr trav, env, head, body, resp, cur, fault; ! 30: xmlAttrPtr attr; ! 31: int param_count = 0; ! 32: int soap_version = SOAP_1_1; ! 33: HashTable *hdrs = NULL; ! 34: ! 35: ZVAL_NULL(return_value); ! 36: ! 37: /* Response for one-way opearation */ ! 38: if (buffer_size == 0) { ! 39: return TRUE; ! 40: } ! 41: ! 42: /* Parse XML packet */ ! 43: response = soap_xmlParseMemory(buffer, buffer_size); ! 44: ! 45: if (!response) { ! 46: add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL TSRMLS_CC); ! 47: return FALSE; ! 48: } ! 49: if (xmlGetIntSubset(response) != NULL) { ! 50: add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL TSRMLS_CC); ! 51: xmlFreeDoc(response); ! 52: return FALSE; ! 53: } ! 54: ! 55: /* Get <Envelope> element */ ! 56: env = NULL; ! 57: trav = response->children; ! 58: while (trav != NULL) { ! 59: if (trav->type == XML_ELEMENT_NODE) { ! 60: if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) { ! 61: env = trav; ! 62: envelope_ns = SOAP_1_1_ENV_NAMESPACE; ! 63: soap_version = SOAP_1_1; ! 64: } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) { ! 65: env = trav; ! 66: envelope_ns = SOAP_1_2_ENV_NAMESPACE; ! 67: soap_version = SOAP_1_2; ! 68: } else { ! 69: add_soap_fault(this_ptr, "VersionMismatch", "Wrong Version", NULL, NULL TSRMLS_CC); ! 70: xmlFreeDoc(response); ! 71: return FALSE; ! 72: } ! 73: } ! 74: trav = trav->next; ! 75: } ! 76: if (env == NULL) { ! 77: add_soap_fault(this_ptr, "Client", "looks like we got XML without \"Envelope\" element", NULL, NULL TSRMLS_CC); ! 78: xmlFreeDoc(response); ! 79: return FALSE; ! 80: } ! 81: ! 82: attr = env->properties; ! 83: while (attr != NULL) { ! 84: if (attr->ns == NULL) { ! 85: add_soap_fault(this_ptr, "Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC); ! 86: xmlFreeDoc(response); ! 87: return FALSE; ! 88: } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { ! 89: if (soap_version == SOAP_1_2) { ! 90: add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL TSRMLS_CC); ! 91: xmlFreeDoc(response); ! 92: return FALSE; ! 93: } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) { ! 94: add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC); ! 95: xmlFreeDoc(response); ! 96: return FALSE; ! 97: } ! 98: } ! 99: attr = attr->next; ! 100: } ! 101: ! 102: /* Get <Header> element */ ! 103: head = NULL; ! 104: trav = env->children; ! 105: while (trav != NULL && trav->type != XML_ELEMENT_NODE) { ! 106: trav = trav->next; ! 107: } ! 108: if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) { ! 109: head = trav; ! 110: trav = trav->next; ! 111: } ! 112: ! 113: /* Get <Body> element */ ! 114: body = NULL; ! 115: while (trav != NULL && trav->type != XML_ELEMENT_NODE) { ! 116: trav = trav->next; ! 117: } ! 118: if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) { ! 119: body = trav; ! 120: trav = trav->next; ! 121: } ! 122: while (trav != NULL && trav->type != XML_ELEMENT_NODE) { ! 123: trav = trav->next; ! 124: } ! 125: if (body == NULL) { ! 126: add_soap_fault(this_ptr, "Client", "Body must be present in a SOAP envelope", NULL, NULL TSRMLS_CC); ! 127: xmlFreeDoc(response); ! 128: return FALSE; ! 129: } ! 130: attr = body->properties; ! 131: while (attr != NULL) { ! 132: if (attr->ns == NULL) { ! 133: if (soap_version == SOAP_1_2) { ! 134: add_soap_fault(this_ptr, "Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC); ! 135: xmlFreeDoc(response); ! 136: return FALSE; ! 137: } ! 138: } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { ! 139: if (soap_version == SOAP_1_2) { ! 140: add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Body", NULL, NULL TSRMLS_CC); ! 141: xmlFreeDoc(response); ! 142: return FALSE; ! 143: } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) { ! 144: add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC); ! 145: xmlFreeDoc(response); ! 146: return FALSE; ! 147: } ! 148: } ! 149: attr = attr->next; ! 150: } ! 151: if (trav != NULL && soap_version == SOAP_1_2) { ! 152: add_soap_fault(this_ptr, "Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL TSRMLS_CC); ! 153: xmlFreeDoc(response); ! 154: return FALSE; ! 155: } ! 156: ! 157: if (head != NULL) { ! 158: attr = head->properties; ! 159: while (attr != NULL) { ! 160: if (attr->ns == NULL) { ! 161: add_soap_fault(this_ptr, "Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC); ! 162: xmlFreeDoc(response); ! 163: return FALSE; ! 164: } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { ! 165: if (soap_version == SOAP_1_2) { ! 166: add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Header", NULL, NULL TSRMLS_CC); ! 167: xmlFreeDoc(response); ! 168: return FALSE; ! 169: } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) { ! 170: add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC); ! 171: xmlFreeDoc(response); ! 172: return FALSE; ! 173: } ! 174: } ! 175: attr = attr->next; ! 176: } ! 177: } ! 178: ! 179: /* Check if <Body> contains <Fault> element */ ! 180: fault = get_node_ex(body->children,"Fault",envelope_ns); ! 181: if (fault != NULL) { ! 182: char *faultcode = NULL, *faultstring = NULL, *faultactor = NULL; ! 183: zval *details = NULL; ! 184: xmlNodePtr tmp; ! 185: ! 186: if (soap_version == SOAP_1_1) { ! 187: tmp = get_node(fault->children, "faultcode"); ! 188: if (tmp != NULL && tmp->children != NULL) { ! 189: faultcode = (char*)tmp->children->content; ! 190: } ! 191: ! 192: tmp = get_node(fault->children, "faultstring"); ! 193: if (tmp != NULL && tmp->children != NULL) { ! 194: zval *zv = master_to_zval(get_conversion(IS_STRING), tmp); ! 195: faultstring = Z_STRVAL_P(zv); ! 196: FREE_ZVAL(zv); ! 197: } ! 198: ! 199: tmp = get_node(fault->children, "faultactor"); ! 200: if (tmp != NULL && tmp->children != NULL) { ! 201: zval *zv = master_to_zval(get_conversion(IS_STRING), tmp); ! 202: faultactor = Z_STRVAL_P(zv); ! 203: FREE_ZVAL(zv); ! 204: } ! 205: ! 206: tmp = get_node(fault->children, "detail"); ! 207: if (tmp != NULL) { ! 208: details = master_to_zval(NULL, tmp); ! 209: } ! 210: } else { ! 211: tmp = get_node(fault->children, "Code"); ! 212: if (tmp != NULL && tmp->children != NULL) { ! 213: tmp = get_node(tmp->children, "Value"); ! 214: if (tmp != NULL && tmp->children != NULL) { ! 215: faultcode = (char*)tmp->children->content; ! 216: } ! 217: } ! 218: ! 219: tmp = get_node(fault->children,"Reason"); ! 220: if (tmp != NULL && tmp->children != NULL) { ! 221: /* TODO: lang attribute */ ! 222: tmp = get_node(tmp->children,"Text"); ! 223: if (tmp != NULL && tmp->children != NULL) { ! 224: zval *zv = master_to_zval(get_conversion(IS_STRING), tmp); ! 225: faultstring = Z_STRVAL_P(zv); ! 226: FREE_ZVAL(zv); ! 227: } ! 228: } ! 229: ! 230: tmp = get_node(fault->children,"Detail"); ! 231: if (tmp != NULL) { ! 232: details = master_to_zval(NULL, tmp); ! 233: } ! 234: } ! 235: add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details TSRMLS_CC); ! 236: if (faultstring) { ! 237: efree(faultstring); ! 238: } ! 239: if (faultactor) { ! 240: efree(faultactor); ! 241: } ! 242: #ifdef ZEND_ENGINE_2 ! 243: if (details) { ! 244: Z_DELREF_P(details); ! 245: } ! 246: #endif ! 247: xmlFreeDoc(response); ! 248: return FALSE; ! 249: } ! 250: ! 251: /* Parse content of <Body> element */ ! 252: array_init(return_value); ! 253: resp = body->children; ! 254: while (resp != NULL && resp->type != XML_ELEMENT_NODE) { ! 255: resp = resp->next; ! 256: } ! 257: if (resp != NULL) { ! 258: if (fn != NULL && fn->binding && fn->binding->bindingType == BINDING_SOAP) { ! 259: /* Function has WSDL description */ ! 260: sdlParamPtr *h_param, param = NULL; ! 261: xmlNodePtr val = NULL; ! 262: char *name, *ns = NULL; ! 263: zval* tmp; ! 264: sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes; ! 265: int res_count; ! 266: ! 267: hdrs = fnb->output.headers; ! 268: ! 269: if (fn->responseParameters) { ! 270: res_count = zend_hash_num_elements(fn->responseParameters); ! 271: zend_hash_internal_pointer_reset(fn->responseParameters); ! 272: while (zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) == SUCCESS) { ! 273: param = (*h_param); ! 274: if (fnb->style == SOAP_DOCUMENT) { ! 275: if (param->element) { ! 276: name = param->element->name; ! 277: ns = param->element->namens; ! 278: /* ! 279: name = param->encode->details.type_str; ! 280: ns = param->encode->details.ns; ! 281: */ ! 282: } else { ! 283: name = param->paramName; ! 284: } ! 285: } else { ! 286: name = fn->responseName; ! 287: /* ns = ? */ ! 288: } ! 289: ! 290: /* Get value of parameter */ ! 291: cur = get_node_ex(resp, name, ns); ! 292: if (!cur) { ! 293: cur = get_node(resp, name); ! 294: /* TODO: produce warning invalid ns */ ! 295: } ! 296: if (!cur && fnb->style == SOAP_RPC) { ! 297: cur = resp; ! 298: } ! 299: if (cur) { ! 300: if (fnb->style == SOAP_DOCUMENT) { ! 301: val = cur; ! 302: } else { ! 303: val = get_node(cur->children, param->paramName); ! 304: if (res_count == 1) { ! 305: if (val == NULL) { ! 306: val = get_node(cur->children, "return"); ! 307: } ! 308: if (val == NULL) { ! 309: val = get_node(cur->children, "result"); ! 310: } ! 311: if (val == NULL && cur->children && cur->children->next == NULL) { ! 312: val = cur->children; ! 313: } ! 314: } ! 315: } ! 316: } ! 317: ! 318: if (!val) { ! 319: /* TODO: may be "nil" is not OK? */ ! 320: MAKE_STD_ZVAL(tmp); ! 321: ZVAL_NULL(tmp); ! 322: /* ! 323: add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL TSRMLS_CC); ! 324: xmlFreeDoc(response); ! 325: return FALSE; ! 326: */ ! 327: } else { ! 328: /* Decoding value of parameter */ ! 329: if (param != NULL) { ! 330: tmp = master_to_zval(param->encode, val); ! 331: } else { ! 332: tmp = master_to_zval(NULL, val); ! 333: } ! 334: } ! 335: add_assoc_zval(return_value, param->paramName, tmp); ! 336: ! 337: param_count++; ! 338: ! 339: zend_hash_move_forward(fn->responseParameters); ! 340: } ! 341: } ! 342: } else { ! 343: /* Function has no WSDL description */ ! 344: xmlNodePtr val; ! 345: val = resp->children; ! 346: while (val != NULL) { ! 347: while (val && val->type != XML_ELEMENT_NODE) { ! 348: val = val->next; ! 349: } ! 350: if (val != NULL) { ! 351: if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) { ! 352: zval *tmp; ! 353: zval **arr; ! 354: ! 355: tmp = master_to_zval(NULL, val); ! 356: if (val->name) { ! 357: if (zend_hash_find(Z_ARRVAL_P(return_value), (char*)val->name, strlen((char*)val->name)+1, (void**)&arr) == SUCCESS) { ! 358: add_next_index_zval(*arr, tmp); ! 359: } else if (val->next && get_node(val->next, (char*)val->name)) { ! 360: zval *arr; ! 361: ! 362: MAKE_STD_ZVAL(arr); ! 363: array_init(arr); ! 364: add_next_index_zval(arr, tmp); ! 365: add_assoc_zval(return_value, (char*)val->name, arr); ! 366: } else { ! 367: add_assoc_zval(return_value, (char*)val->name, tmp); ! 368: } ! 369: } else { ! 370: add_next_index_zval(return_value, tmp); ! 371: } ! 372: ++param_count; ! 373: } ! 374: val = val->next; ! 375: } ! 376: } ! 377: } ! 378: } ! 379: ! 380: if (Z_TYPE_P(return_value) == IS_ARRAY) { ! 381: if (param_count == 0) { ! 382: zval_dtor(return_value); ! 383: ZVAL_NULL(return_value); ! 384: } else if (param_count == 1) { ! 385: zval *tmp; ! 386: ! 387: zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value)); ! 388: zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void**)&tmp); ! 389: tmp = *(zval**)tmp; ! 390: Z_ADDREF_P(tmp); ! 391: zval_dtor(return_value); ! 392: *return_value = *tmp; ! 393: FREE_ZVAL(tmp); ! 394: } ! 395: } ! 396: ! 397: if (soap_headers && head) { ! 398: trav = head->children; ! 399: while (trav != NULL) { ! 400: if (trav->type == XML_ELEMENT_NODE) { ! 401: encodePtr enc = NULL; ! 402: zval* val; ! 403: ! 404: if (hdrs) { ! 405: smart_str key = {0}; ! 406: sdlSoapBindingFunctionHeaderPtr *hdr; ! 407: ! 408: if (trav->ns) { ! 409: smart_str_appends(&key, (char*)trav->ns->href); ! 410: smart_str_appendc(&key,':'); ! 411: } ! 412: smart_str_appends(&key, (char*)trav->name); ! 413: smart_str_0(&key); ! 414: if (zend_hash_find(hdrs, key.c, key.len+1, (void**)&hdr) == SUCCESS) { ! 415: enc = (*hdr)->encode; ! 416: } ! 417: smart_str_free(&key); ! 418: } ! 419: val = master_to_zval(enc, trav); ! 420: add_assoc_zval(soap_headers, (char*)trav->name, val); ! 421: } ! 422: trav = trav->next; ! 423: } ! 424: } ! 425: ! 426: xmlFreeDoc(response); ! 427: return TRUE; ! 428: }