root/ext/soap/php_packet_soap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parse_packet_soap

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 5                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 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$ */
  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 TSRMLS_CC);
 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 TSRMLS_CC);
 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 TSRMLS_CC);
 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 TSRMLS_CC);
 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 TSRMLS_CC);
 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                 if (details) {
 243                         Z_DELREF_P(details);
 244                 }
 245                 xmlFreeDoc(response);
 246                 return FALSE;
 247         }
 248 
 249         /* Parse content of <Body> element */
 250         array_init(return_value);
 251         resp = body->children;
 252         while (resp != NULL && resp->type != XML_ELEMENT_NODE) {
 253                 resp = resp->next;
 254         }
 255         if (resp != NULL) {
 256                 if (fn != NULL && fn->binding && fn->binding->bindingType == BINDING_SOAP) {
 257                   /* Function has WSDL description */
 258                         sdlParamPtr *h_param, param = NULL;
 259                         xmlNodePtr val = NULL;
 260                         char *name, *ns = NULL;
 261                         zval* tmp;
 262                         sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
 263                         int res_count;
 264 
 265                         hdrs = fnb->output.headers;
 266 
 267                         if (fn->responseParameters) {
 268                           res_count = zend_hash_num_elements(fn->responseParameters);
 269                                 zend_hash_internal_pointer_reset(fn->responseParameters);
 270                                 while (zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) == SUCCESS) {
 271                                         param = (*h_param);
 272                                         if (fnb->style == SOAP_DOCUMENT) {
 273                                                 if (param->element) {
 274                                                         name = param->element->name;
 275                                                         ns = param->element->namens;
 276 /*
 277                                                         name = param->encode->details.type_str;
 278                                                         ns = param->encode->details.ns;
 279 */
 280                                                 } else {
 281                                                         name = param->paramName;
 282                                                 }
 283                                         } else {
 284                                                 name = fn->responseName;
 285                                                 /* ns = ? */
 286                                         }
 287 
 288                                         /* Get value of parameter */
 289                                         cur = get_node_ex(resp, name, ns);
 290                                         if (!cur) {
 291                                                 cur = get_node(resp, name);
 292                                                 /* TODO: produce warning invalid ns */
 293                                         }
 294                                         if (!cur && fnb->style == SOAP_RPC) {
 295                                           cur = resp;
 296                                         }
 297                                         if (cur) {
 298                                                 if (fnb->style == SOAP_DOCUMENT) {
 299                                                         val = cur;
 300                                                 } else {
 301                                                         val = get_node(cur->children, param->paramName);
 302                                                         if (res_count == 1) {
 303                                                                 if (val == NULL) {
 304                                                                         val = get_node(cur->children, "return");
 305                                                                 }
 306                                                                 if (val == NULL) {
 307                                                                         val = get_node(cur->children, "result");
 308                                                                 }
 309                                                                 if (val == NULL && cur->children && cur->children->next == NULL) {
 310                                                                         val = cur->children;                                                              
 311                                                                 }
 312                                                         }
 313                                                 }
 314                                         }
 315 
 316                                         if (!val) {
 317                                                 /* TODO: may be "nil" is not OK? */
 318                                                 MAKE_STD_ZVAL(tmp);
 319                                                 ZVAL_NULL(tmp);
 320 /*
 321                                                 add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL TSRMLS_CC);
 322                                                 xmlFreeDoc(response);
 323                                                 return FALSE;
 324 */
 325                                         } else {
 326                                                 /* Decoding value of parameter */
 327                                                 if (param != NULL) {
 328                                                         tmp = master_to_zval(param->encode, val TSRMLS_CC);
 329                                                 } else {
 330                                                         tmp = master_to_zval(NULL, val TSRMLS_CC);
 331                                                 }
 332                                         }
 333                                         add_assoc_zval(return_value, param->paramName, tmp);
 334 
 335                                         param_count++;
 336 
 337                                         zend_hash_move_forward(fn->responseParameters);
 338                                 }
 339                         }
 340                 } else {
 341                   /* Function has no WSDL description */
 342                         xmlNodePtr val;
 343                         val = resp->children;
 344                         while (val != NULL) {
 345                                 while (val && val->type != XML_ELEMENT_NODE) {
 346                                         val = val->next;
 347                                 }
 348                                 if (val != NULL) {
 349                                         if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) {
 350                                                 zval *tmp;
 351                                                 zval **arr;
 352 
 353                                                 tmp = master_to_zval(NULL, val TSRMLS_CC);
 354                                                 if (val->name) {
 355                                                         if (zend_hash_find(Z_ARRVAL_P(return_value), (char*)val->name, strlen((char*)val->name)+1, (void**)&arr) == SUCCESS) {
 356                                                                 add_next_index_zval(*arr, tmp);
 357                                                         } else if (val->next && get_node(val->next, (char*)val->name)) {
 358                                                                 zval *arr;
 359 
 360                                                                 MAKE_STD_ZVAL(arr);
 361                                                                 array_init(arr);
 362                                                                 add_next_index_zval(arr, tmp);
 363                                                                 add_assoc_zval(return_value, (char*)val->name, arr);
 364                                                         } else {
 365                                                                 add_assoc_zval(return_value, (char*)val->name, tmp);
 366                                                         }
 367                                                 } else {
 368                                                         add_next_index_zval(return_value, tmp);
 369                                                 }
 370                                                 ++param_count;
 371                                         }
 372                                         val = val->next;
 373                                 }
 374                         }
 375                 }
 376         }
 377 
 378         if (Z_TYPE_P(return_value) == IS_ARRAY) {
 379                 if (param_count == 0) {
 380                         zval_dtor(return_value);
 381                         ZVAL_NULL(return_value);
 382                 } else if (param_count == 1) {
 383                         zval *tmp;
 384 
 385                         zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value));
 386                         zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void**)&tmp);
 387                         tmp = *(zval**)tmp;
 388                         Z_ADDREF_P(tmp);
 389                         zval_dtor(return_value);
 390                         *return_value = *tmp;
 391                         FREE_ZVAL(tmp);
 392                 }
 393         }
 394 
 395         if (soap_headers && head) {
 396                 trav = head->children;
 397                 while (trav != NULL) {
 398                         if (trav->type == XML_ELEMENT_NODE) {
 399                                 encodePtr enc = NULL;
 400                                 zval* val;
 401 
 402                                 if (hdrs) {
 403                                         smart_str key = {0};
 404                                         sdlSoapBindingFunctionHeaderPtr *hdr;
 405 
 406                                         if (trav->ns) {
 407                                                 smart_str_appends(&key, (char*)trav->ns->href);
 408                                                 smart_str_appendc(&key,':');
 409                                         }
 410                                         smart_str_appends(&key, (char*)trav->name);
 411                                         smart_str_0(&key);
 412                                         if (zend_hash_find(hdrs, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
 413                                                 enc = (*hdr)->encode;
 414                                         }
 415                                         smart_str_free(&key);
 416                                 }
 417                                 val = master_to_zval(enc, trav TSRMLS_CC);
 418                                 add_assoc_zval(soap_headers, (char*)trav->name, val);
 419                         }
 420                         trav = trav->next;
 421                 }
 422         }
 423 
 424         xmlFreeDoc(response);
 425         return TRUE;
 426 }

/* [<][>][^][v][top][bottom][index][help] */