diff options
Diffstat (limited to 'ext/soap/php_packet_soap.c')
-rw-r--r-- | ext/soap/php_packet_soap.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/ext/soap/php_packet_soap.c b/ext/soap/php_packet_soap.c new file mode 100644 index 000000000..8ccd7d59e --- /dev/null +++ b/ext/soap/php_packet_soap.c @@ -0,0 +1,399 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Brad Lafountain <rodif_bl@yahoo.com> | + | Shane Caraveo <shane@caraveo.com> | + | Dmitry Stogov <dmitry@zend.com> | + +----------------------------------------------------------------------+ +*/ +/* $Id: php_packet_soap.c,v 1.36.2.4 2005/03/22 10:18:47 dmitry Exp $ */ + +#include "php_soap.h" + +/* SOAP client calls this function to parse response from SOAP server */ +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) +{ + char* envelope_ns = NULL; + xmlDocPtr response; + xmlNodePtr trav, env, head, body, resp, cur, fault; + xmlAttrPtr attr; + int param_count = 0; + int soap_version = SOAP_1_1; + HashTable *hdrs = NULL; + + ZVAL_NULL(return_value); + + /* Parse XML packet */ + response = soap_xmlParseMemory(buffer, buffer_size); + + if (!response) { + add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL TSRMLS_CC); + return FALSE; + } + if (xmlGetIntSubset(response) != NULL) { + add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + + /* Get <Envelope> element */ + env = NULL; + trav = response->children; + while (trav != NULL) { + if (trav->type == XML_ELEMENT_NODE) { + if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) { + env = trav; + envelope_ns = SOAP_1_1_ENV_NAMESPACE; + soap_version = SOAP_1_1; + } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) { + env = trav; + envelope_ns = SOAP_1_2_ENV_NAMESPACE; + soap_version = SOAP_1_2; + } else { + add_soap_fault(this_ptr, "VersionMismatch", "Wrong Version", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + } + trav = trav->next; + } + if (env == NULL) { + add_soap_fault(this_ptr, "Client", "looks like we got XML without \"Envelope\" element", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + + attr = env->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + add_soap_fault(this_ptr, "Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { + if (soap_version == SOAP_1_2) { + add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } else if (strcmp(attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { + add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + } + attr = attr->next; + } + + /* Get <Header> element */ + head = NULL; + trav = env->children; + while (trav != NULL && trav->type != XML_ELEMENT_NODE) { + trav = trav->next; + } + if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) { + head = trav; + trav = trav->next; + } + + /* Get <Body> element */ + body = NULL; + while (trav != NULL && trav->type != XML_ELEMENT_NODE) { + trav = trav->next; + } + if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) { + body = trav; + trav = trav->next; + } + while (trav != NULL && trav->type != XML_ELEMENT_NODE) { + trav = trav->next; + } + if (body == NULL) { + add_soap_fault(this_ptr, "Client", "Body must be present in a SOAP envelope", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + attr = body->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if (soap_version == SOAP_1_2) { + add_soap_fault(this_ptr, "Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { + if (soap_version == SOAP_1_2) { + add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Body", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } else if (strcmp(attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { + add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + } + attr = attr->next; + } + if (trav != NULL && soap_version == SOAP_1_2) { + add_soap_fault(this_ptr, "Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + + if (head != NULL) { + attr = head->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + add_soap_fault(this_ptr, "Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { + if (soap_version == SOAP_1_2) { + add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Header", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } else if (strcmp(attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { + add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; + } + } + attr = attr->next; + } + } + + /* Check if <Body> contains <Fault> element */ + fault = get_node_ex(body->children,"Fault",envelope_ns); + if (fault != NULL) { + char *faultcode = NULL, *faultstring = NULL, *faultactor = NULL; + zval *details = NULL; + xmlNodePtr tmp; + + if (soap_version == SOAP_1_1) { + tmp = get_node(fault->children,"faultcode"); + if (tmp != NULL && tmp->children != NULL) { + faultcode = tmp->children->content; + } + + tmp = get_node(fault->children,"faultstring"); + if (tmp != NULL && tmp->children != NULL) { + faultstring = tmp->children->content; + } + + tmp = get_node(fault->children,"faultactor"); + if (tmp != NULL && tmp->children != NULL) { + faultactor = tmp->children->content; + } + + tmp = get_node(fault->children,"detail"); + if (tmp != NULL) { + details = master_to_zval(NULL, tmp); + } + } else { + tmp = get_node(fault->children,"Code"); + if (tmp != NULL && tmp->children != NULL) { + tmp = get_node(tmp->children,"Value"); + if (tmp != NULL && tmp->children != NULL) { + faultcode = tmp->children->content; + } + } + + tmp = get_node(fault->children,"Reason"); + if (tmp != NULL && tmp->children != NULL) { + /* TODO: lang attribute */ + tmp = get_node(tmp->children,"Text"); + if (tmp != NULL && tmp->children != NULL) { + faultstring = tmp->children->content; + } + } + + tmp = get_node(fault->children,"Detail"); + if (tmp != NULL) { + details = master_to_zval(NULL, tmp); + } + } + add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details TSRMLS_CC); +#ifdef ZEND_ENGINE_2 + if (details) { + details->refcount--; + } +#endif + xmlFreeDoc(response); + return FALSE; + } + + /* Parse content of <Body> element */ + array_init(return_value); + resp = body->children; + while (resp != NULL && resp->type != XML_ELEMENT_NODE) { + resp = resp->next; + } + if (resp != NULL) { + if (fn != NULL && fn->binding && fn->binding->bindingType == BINDING_SOAP) { + /* Function has WSDL description */ + sdlParamPtr *h_param, param = NULL; + xmlNodePtr val = NULL; + char *name, *ns = NULL; + zval* tmp; + sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes; + int res_count; + + hdrs = fnb->output.headers; + + if (fn->responseParameters) { + res_count = zend_hash_num_elements(fn->responseParameters); + zend_hash_internal_pointer_reset(fn->responseParameters); + while (zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) == SUCCESS) { + param = (*h_param); + if (fnb->style == SOAP_DOCUMENT) { + if (param->element) { + name = param->element->name; + ns = param->element->namens; +/* + name = param->encode->details.type_str; + ns = param->encode->details.ns; +*/ + } else { + name = param->paramName; + } + } else { + name = fn->responseName; + /* ns = ? */ + } + + /* Get value of parameter */ + cur = get_node_ex(resp, name, ns); + if (!cur) { + cur = get_node(resp, name); + /* TODO: produce warning invalid ns */ + } + if (!cur && fnb->style == SOAP_RPC) { + cur = resp; + } + if (cur) { + if (fnb->style == SOAP_DOCUMENT) { + val = cur; + } else { + val = get_node(cur->children, param->paramName); + if (res_count == 1) { + if (val == NULL) { + val = get_node(cur->children, "return"); + } + if (val == NULL) { + val = get_node(cur->children, "result"); + } + if (val == NULL && cur->children && cur->children->next == NULL) { + val = cur->children; + } + } + } + } + + if (!val) { + /* TODO: may be "nil" is not OK? */ + MAKE_STD_ZVAL(tmp); + ZVAL_NULL(tmp); +/* + add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL TSRMLS_CC); + xmlFreeDoc(response); + return FALSE; +*/ + } else { + /* Decoding value of parameter */ + if (param != NULL) { + tmp = master_to_zval(param->encode, val); + } else { + tmp = master_to_zval(NULL, val); + } + } + add_assoc_zval(return_value, param->paramName, tmp); + + param_count++; + + zend_hash_move_forward(fn->responseParameters); + } + } + } else { + /* Function hasn't WSDL description */ + xmlNodePtr val; + val = resp->children; + while (val != NULL) { + while (val && val->type != XML_ELEMENT_NODE) { + val = val->next; + } + if (val != NULL) { + if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) { + zval *tmp; + + tmp = master_to_zval(NULL, val); + if (val->name) { + add_assoc_zval(return_value, (char*)val->name, tmp); + } else { + add_next_index_zval(return_value, tmp); + } + ++param_count; + } + val = val->next; + } + } + } + } + + if (Z_TYPE_P(return_value) == IS_ARRAY) { + if (param_count == 0) { + zval_dtor(return_value); + ZVAL_NULL(return_value); + } else if (param_count == 1) { + zval *tmp; + + zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value)); + zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void**)&tmp); + tmp = *(zval**)tmp; + tmp->refcount++; + zval_dtor(return_value); + *return_value = *tmp; + FREE_ZVAL(tmp); + } + } + + if (soap_headers && head) { + trav = head->children; + while (trav != NULL) { + if (trav->type == XML_ELEMENT_NODE) { + encodePtr enc = NULL; + zval* val; + + if (hdrs) { + smart_str key = {0}; + sdlSoapBindingFunctionHeaderPtr *hdr; + + if (trav->ns) { + smart_str_appends(&key,trav->ns->href); + smart_str_appendc(&key,':'); + } + smart_str_appends(&key,trav->name); + smart_str_0(&key); + if (zend_hash_find(hdrs, key.c, key.len+1, (void**)&hdr) == SUCCESS) { + enc = (*hdr)->encode; + } + smart_str_free(&key); + } + val = master_to_zval(enc, trav); + add_assoc_zval(soap_headers, (char*)trav->name, val); + } + trav = trav->next; + } + } + + xmlFreeDoc(response); + return TRUE; +} |