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 7                                                        |
   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)
  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);
  47                 return FALSE;
  48         }
  49         if (xmlGetIntSubset(response) != NULL) {
  50                 add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL);
  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);
  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);
  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);
  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);
  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);
  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);
 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);
 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);
 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);
 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);
 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);
 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);
 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);
 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;
 183                 zend_string *faultstring = NULL, *faultactor = NULL;
 184                 zval details;
 185                 xmlNodePtr tmp;
 186 
 187                 ZVAL_UNDEF(&details);
 188                 if (soap_version == SOAP_1_1) {
 189                         tmp = get_node(fault->children, "faultcode");
 190                         if (tmp != NULL && tmp->children != NULL) {
 191                                 faultcode = (char*)tmp->children->content;
 192                         }
 193 
 194                         tmp = get_node(fault->children, "faultstring");
 195                         if (tmp != NULL && tmp->children != NULL) {
 196                                 zval zv;
 197                                 master_to_zval(&zv, get_conversion(IS_STRING), tmp);
 198                                 faultstring = Z_STR(zv);
 199                         }
 200 
 201                         tmp = get_node(fault->children, "faultactor");
 202                         if (tmp != NULL && tmp->children != NULL) {
 203                                 zval zv;
 204                                 master_to_zval(&zv, get_conversion(IS_STRING), tmp);
 205                                 faultactor = Z_STR(zv);
 206                         }
 207 
 208                         tmp = get_node(fault->children, "detail");
 209                         if (tmp != NULL) {
 210                                 master_to_zval(&details, NULL, tmp);
 211                         }
 212                 } else {
 213                         tmp = get_node(fault->children, "Code");
 214                         if (tmp != NULL && tmp->children != NULL) {
 215                                 tmp = get_node(tmp->children, "Value");
 216                                 if (tmp != NULL && tmp->children != NULL) {
 217                                         faultcode = (char*)tmp->children->content;
 218                                 }
 219                         }
 220 
 221                         tmp = get_node(fault->children,"Reason");
 222                         if (tmp != NULL && tmp->children != NULL) {
 223                                 /* TODO: lang attribute */
 224                                 tmp = get_node(tmp->children,"Text");
 225                                 if (tmp != NULL && tmp->children != NULL) {
 226                                         zval zv;
 227                                         master_to_zval(&zv, get_conversion(IS_STRING), tmp);
 228                                         faultstring = Z_STR(zv);
 229                                 }
 230                         }
 231 
 232                         tmp = get_node(fault->children,"Detail");
 233                         if (tmp != NULL) {
 234                                 master_to_zval(&details, NULL, tmp);
 235                         }
 236                 }
 237                 add_soap_fault(this_ptr, faultcode, faultstring ? ZSTR_VAL(faultstring) : NULL, faultactor ? ZSTR_VAL(faultactor) : NULL, &details);
 238                 if (faultstring) {
 239                         zend_string_release(faultstring);
 240                 }
 241                 if (faultactor) {
 242                         zend_string_release(faultactor);
 243                 }
 244                 if (Z_REFCOUNTED(details)) {
 245                         Z_DELREF(details);
 246                 }
 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 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_FOREACH_PTR(fn->responseParameters, 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                                                 ZVAL_NULL(&tmp);
 319 /*
 320                                                 add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL);
 321                                                 xmlFreeDoc(response);
 322                                                 return FALSE;
 323 */
 324                                         } else {
 325                                                 /* Decoding value of parameter */
 326                                                 if (param != NULL) {
 327                                                         master_to_zval(&tmp, param->encode, val);
 328                                                 } else {
 329                                                         master_to_zval(&tmp, NULL, val);
 330                                                 }
 331                                         }
 332                                         add_assoc_zval(return_value, param->paramName, &tmp);
 333 
 334                                         param_count++;
 335                                 } ZEND_HASH_FOREACH_END();
 336                         }
 337                 } else {
 338                   /* Function has no WSDL description */
 339                         xmlNodePtr val;
 340                         val = resp->children;
 341                         while (val != NULL) {
 342                                 while (val && val->type != XML_ELEMENT_NODE) {
 343                                         val = val->next;
 344                                 }
 345                                 if (val != NULL) {
 346                                         if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) {
 347                                                 zval tmp;
 348                                                 zval *arr;
 349 
 350                                                 master_to_zval(&tmp, NULL, val);
 351                                                 if (val->name) {
 352                                                         if ((arr = zend_hash_str_find(Z_ARRVAL_P(return_value), (char*)val->name, strlen((char*)val->name))) != NULL) {
 353                                                                 add_next_index_zval(arr, &tmp);
 354                                                         } else if (val->next && get_node(val->next, (char*)val->name)) {
 355                                                                 zval arr;
 356 
 357                                                                 array_init(&arr);
 358                                                                 add_next_index_zval(&arr, &tmp);
 359                                                                 add_assoc_zval(return_value, (char*)val->name, &arr);
 360                                                         } else {
 361                                                                 add_assoc_zval(return_value, (char*)val->name, &tmp);
 362                                                         }
 363                                                 } else {
 364                                                         add_next_index_zval(return_value, &tmp);
 365                                                 }
 366                                                 ++param_count;
 367                                         }
 368                                         val = val->next;
 369                                 }
 370                         }
 371                 }
 372         }
 373 
 374         if (Z_TYPE_P(return_value) == IS_ARRAY) {
 375                 if (param_count == 0) {
 376                         zval_dtor(return_value);
 377                         ZVAL_NULL(return_value);
 378                 } else if (param_count == 1) {
 379                         zval *tmp;
 380 
 381                         zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value));
 382                         tmp = zend_hash_get_current_data(Z_ARRVAL_P(return_value));
 383                         if (!Z_REFCOUNTED_P(return_value)) {
 384                                 ZVAL_COPY(return_value, tmp);
 385                         } else {
 386                                 zend_refcounted *garbage = Z_COUNTED_P(return_value);
 387                                 ZVAL_COPY(return_value, tmp);
 388                                 _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
 389                         }
 390                 }
 391         }
 392 
 393         if (soap_headers && head) {
 394                 trav = head->children;
 395                 while (trav != NULL) {
 396                         if (trav->type == XML_ELEMENT_NODE) {
 397                                 encodePtr enc = NULL;
 398                                 zval val;
 399 
 400                                 if (hdrs) {
 401                                         smart_str key = {0};
 402                                         sdlSoapBindingFunctionHeaderPtr hdr;
 403 
 404                                         if (trav->ns) {
 405                                                 smart_str_appends(&key, (char*)trav->ns->href);
 406                                                 smart_str_appendc(&key,':');
 407                                         }
 408                                         smart_str_appends(&key, (char*)trav->name);
 409                                         smart_str_0(&key);
 410                                         if ((hdr = zend_hash_find_ptr(hdrs, key.s)) != NULL) {
 411                                                 enc = hdr->encode;
 412                                         }
 413                                         smart_str_free(&key);
 414                                 }
 415                                 master_to_zval(&val, enc, trav);
 416                                 add_assoc_zval(soap_headers, (char*)trav->name, &val);
 417                         }
 418                         trav = trav->next;
 419                 }
 420         }
 421 
 422         xmlFreeDoc(response);
 423         return TRUE;
 424 }

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