summaryrefslogtreecommitdiff
path: root/ext/soap/php_packet_soap.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/soap/php_packet_soap.c')
-rw-r--r--ext/soap/php_packet_soap.c399
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;
+}