]> granicus.if.org Git - php/commitdiff
Fixed bug #30106 (SOAP cannot not parse 'ref' element. Causes Uncaught SoapFault...
authorDmitry Stogov <dmitry@php.net>
Tue, 22 Mar 2005 10:18:49 +0000 (10:18 +0000)
committerDmitry Stogov <dmitry@php.net>
Tue, 22 Mar 2005 10:18:49 +0000 (10:18 +0000)
NEWS
ext/soap/php_encoding.c
ext/soap/php_encoding.h
ext/soap/php_packet_soap.c
ext/soap/php_schema.c
ext/soap/php_sdl.h
ext/soap/soap.c
ext/soap/tests/bugs/bug30106.phpt [new file with mode: 0644]
ext/soap/tests/bugs/bug30106.wsdl [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index c203cdf6d783e9c90731e380aa8f29d00bbc39e5..adeded37e16a2023400cbd6a21bc20b7c97c5bfc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -147,6 +147,8 @@ PHP                                                                        NEWS
 - Fixed bug #30266 (Invalid opcode 137/1/8). (Marcus)
 - Fixed bug #30120 (imagettftext() and imagettfbbox() accept too many
   parameters). (Jani)
+- Fixed bug #30106 (SOAP cannot not parse 'ref' element. Causes Uncaught
+  SoapFault exception). (Dmitry)
 - Fixed bug #29989 (type re_registers redefined in oniguruma.h). (Moriyoshi)
 - Fixed bug #29767 (Weird behaviour of __set($name, $value)). (Dmitry)
 - Fixed bug #29733 (printf() handles repeated placeholders wrong).
index af78405581be9ac2c9aabf1abb00342f26cbdaef..53f2825ac56531005fea83a7fdfc82386e89da4b 100644 (file)
@@ -72,6 +72,9 @@ static zval *to_zval_array(encodeTypePtr type, xmlNodePtr data);
 static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
 static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
 
+static zval *to_zval_any(encodeTypePtr type, xmlNodePtr data);
+static xmlNodePtr to_xml_any(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
+
 /* Try and guess for non-wsdl clients and servers */
 static zval *guess_zval_convert(encodeTypePtr type, xmlNodePtr data);
 static xmlNodePtr guess_xml_convert(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
@@ -81,8 +84,6 @@ static void get_array_type(xmlNodePtr node, zval *array, smart_str *out_type TSR
 
 static xmlNodePtr check_and_resolve_href(xmlNodePtr data);
 
-static encodePtr get_conversion(int encode);
-
 static void get_type_str(xmlNodePtr node, const char* ns, const char* type, smart_str* ret);
 static void set_ns_and_type_ex(xmlNodePtr node, char *ns, char *type);
 
@@ -201,6 +202,8 @@ encode defaultEncoding[] = {
        {{XSD_BYTE, XSD_BYTE_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_long, to_xml_long},
        {{XSD_1999_TIMEINSTANT, XSD_1999_TIMEINSTANT_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_stringc, to_xml_string},
 
+       {{XSD_ANYXML, "<anyXML>", "<anyXML>", NULL}, to_zval_any, to_xml_any},
+
        {{END_KNOWN_TYPES, NULL, NULL, NULL}, guess_zval_convert, guess_xml_convert}
 };
 
@@ -963,17 +966,58 @@ static void model_to_zval_object(zval *ret, sdlContentModelPtr model, xmlNodePtr
                                }
                        }
                        break;
-               case XSD_CONTENT_SEQUENCE:
                case XSD_CONTENT_ALL:
+               case XSD_CONTENT_SEQUENCE:
                case XSD_CONTENT_CHOICE: {
                        sdlContentModelPtr *tmp;
                        HashPosition pos;
+                       sdlContentModelPtr any = NULL;
 
                        zend_hash_internal_pointer_reset_ex(model->u.content, &pos);
                        while (zend_hash_get_current_data_ex(model->u.content, (void**)&tmp, &pos) == SUCCESS) {
-                               model_to_zval_object(ret, *tmp, data, sdl TSRMLS_CC);
+                               if ((*tmp)->kind == XSD_CONTENT_ANY) {
+                                       any = *tmp;
+                               } else {
+                                       model_to_zval_object(ret, *tmp, data, sdl TSRMLS_CC);
+                               }
                                zend_hash_move_forward_ex(model->u.content, &pos);
                        }
+                       if (any) {
+                               xmlNodePtr node = data->children;
+                               zval* any = NULL;
+
+                               while (node != NULL) {
+                                       if (get_zval_property(ret, (char*)node->name TSRMLS_CC) == NULL) {
+                                               zval* val = master_to_zval(get_conversion(XSD_ANYXML), node);
+                                               while (node->next != NULL &&
+                                                   get_zval_property(ret, (char*)node->next->name TSRMLS_CC) == NULL) {
+                                                       zval* val2 = master_to_zval(get_conversion(XSD_ANYXML), node->next);
+                                                       add_string_to_string(val, val, val2);
+                                                       zval_ptr_dtor(&val2);
+                                                 node = node->next;
+                                               }
+                                               if (any == NULL) {
+                                                       any = val;
+                                               } else {
+                                                       if (Z_TYPE_P(any) != IS_ARRAY) {
+                                                   /* Convert into array */
+                                                   zval *arr;
+
+                                                   MAKE_STD_ZVAL(arr);
+                                                   array_init(arr);
+                                                         add_next_index_zval(arr, any);
+                                                         any = arr;
+                                                 }
+                                                 /* Add array element */
+                                                 add_next_index_zval(any, val);
+                                               }
+                                       }
+                                       node = node->next;
+                               }
+                               if (any) {
+                                       set_zval_property(ret, "any", any TSRMLS_CC);
+                               }
+                       }
                        break;
                }
                case XSD_CONTENT_GROUP:
@@ -1205,6 +1249,37 @@ static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, zval *
                        }
                        break;
                }
+               case XSD_CONTENT_ANY: {
+                       zval *data;
+                       xmlNodePtr property;
+                       encodePtr enc;
+
+                       data = get_zval_property(object, "any" TSRMLS_CC);
+                       if (data) {
+                               enc = get_conversion(XSD_ANYXML);
+                               if ((model->max_occurs == -1 || model->max_occurs > 1) && Z_TYPE_P(data) == IS_ARRAY) {
+                                       HashTable *ht = Z_ARRVAL_P(data);
+                                       zval **val;
+
+                                       zend_hash_internal_pointer_reset(ht);
+                                       while (zend_hash_get_current_data(ht,(void**)&val) == SUCCESS) {
+                                               property = master_to_xml(enc, *val, style, node);
+                                               zend_hash_move_forward(ht);
+                                       }
+                               } else {
+                                       property = master_to_xml(enc, data, style, node);
+                               }
+                               return 1;
+                       } else if (model->min_occurs == 0) {
+                               return 2;
+                       } else {
+                               if (strict) {
+                                       soap_error0(E_ERROR,  "Encoding: object hasn't 'any' property");
+                               }
+                               return 0;
+                       }
+                       break;
+               }
                case XSD_CONTENT_SEQUENCE:
                case XSD_CONTENT_ALL: {
                        sdlContentModelPtr *tmp;
@@ -2492,6 +2567,41 @@ static xmlNodePtr to_xml_union(encodeTypePtr enc, zval *data, int style, xmlNode
        return to_xml_list(enc,data,style, parent);
 }
 
+static zval *to_zval_any(encodeTypePtr type, xmlNodePtr data)
+{
+       xmlBufferPtr buf;
+       zval *ret;
+
+       buf = xmlBufferCreate();
+       xmlNodeDump(buf, NULL, data, 0, 0);
+       MAKE_STD_ZVAL(ret);
+       ZVAL_STRING(ret, (char*)xmlBufferContent(buf), 1);
+       xmlBufferFree(buf);
+       return ret;
+}
+
+extern const xmlChar xmlStringTextNoenc[];
+
+static xmlNodePtr to_xml_any(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
+{      
+       xmlNodePtr ret;
+
+       if (Z_TYPE_P(data) == IS_STRING) {
+               ret = xmlNewTextLen(Z_STRVAL_P(data), Z_STRLEN_P(data));
+       } else {
+               zval tmp = *data;
+
+               zval_copy_ctor(&tmp);
+               convert_to_string(&tmp);
+               ret = xmlNewTextLen(Z_STRVAL_P(data), Z_STRLEN_P(data));
+               zval_dtor(&tmp);
+       }
+       ret->name = xmlStringTextNoenc;
+       xmlAddChild(parent, ret);
+
+       return ret;
+}
+
 zval *sdl_guess_convert_zval(encodeTypePtr enc, xmlNodePtr data)
 {
        sdlTypePtr type;
@@ -2723,7 +2833,7 @@ void encode_reset_ns()
        SOAP_GLOBAL(cur_uniq_ns) = 0;
 }
 
-static encodePtr get_conversion(int encode)
+encodePtr get_conversion(int encode)
 {
        encodePtr *enc = NULL;
        TSRMLS_FETCH();
index 1e26cdb535ae2a9b27d50ab815a7132be6d8fb21..d291e5befe0b74318eeca41acab5d17bf29a20ce 100644 (file)
 #define XSD_UR_TYPE 146
 #define XSD_UR_TYPE_STRING "ur-type"
 
+#define XSD_ANYXML 147
+
 #define APACHE_NAMESPACE "http://xml.apache.org/xml-soap"
 #define APACHE_MAP 200
 #define APACHE_MAP_STRING "Map"
@@ -214,6 +216,8 @@ zval *sdl_guess_convert_zval(encodeTypePtr enc, xmlNodePtr data);
 void encode_reset_ns();
 xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns);
 
+encodePtr get_conversion(int encode);
+
 void delete_encoder(void *handle);
 
 extern encode defaultEncoding[];
index 7b0465f1f2ae5d90e386d6ce030b0b4230cfe5ba..81805b4b428269b8a1e6eb0914c9ad45c2b4865c 100644 (file)
@@ -222,6 +222,11 @@ int parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunction
                        }
                }
                add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details TSRMLS_CC);
+#ifdef ZEND_ENGINE_2
+               if (details) {
+                       details->refcount--;
+               }
+#endif
                xmlFreeDoc(response);
                return FALSE;
        }
index 1a7e4d413f636c4af2d468f35bc0f864b95f2235..4c71e96066bec7040f8637a3968aa053e2c91a5a 100644 (file)
@@ -1301,9 +1301,44 @@ static int schema_sequence(sdlPtr sdl, xmlAttrPtr tns, xmlNodePtr seqType, sdlTy
        return TRUE;
 }
 
-static int schema_any(sdlPtr sdl, xmlAttrPtr tns, xmlNodePtr extType, sdlTypePtr cur_type, sdlContentModelPtr model)
+/*
+<any 
+  id = ID 
+  maxOccurs = (nonNegativeInteger | unbounded)  : 1
+  minOccurs = nonNegativeInteger : 1
+  namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )  : ##any
+  processContents = (lax | skip | strict) : strict
+  {any attributes with non-schema namespace . . .}>
+  Content: (annotation?)
+</any>
+*/
+static int schema_any(sdlPtr sdl, xmlAttrPtr tns, xmlNodePtr anyType, sdlTypePtr cur_type, sdlContentModelPtr model)
 {
-       /* TODO: <any> support */
+       if (model != NULL) {
+               sdlContentModelPtr newModel;
+               xmlAttrPtr attr;
+
+               newModel = emalloc(sizeof(sdlContentModel));
+               newModel->kind = XSD_CONTENT_ANY;
+               newModel->min_occurs = 1;
+               newModel->max_occurs = 1;
+
+               attr = get_attribute(anyType->properties, "minOccurs");
+               if (attr) {
+                       newModel->min_occurs = atoi(attr->children->content);
+               }
+
+               attr = get_attribute(anyType->properties, "maxOccurs");
+               if (attr) {
+                       if (!strncmp(attr->children->content, "unbounded", sizeof("unbounded"))) {
+                               newModel->max_occurs = -1;
+                       } else {
+                               newModel->max_occurs = atoi(attr->children->content);
+                       }
+               }
+
+               zend_hash_next_index_insert(model->u.content, &newModel, sizeof(sdlContentModelPtr), NULL);
+       }
        return TRUE;
 }
 
@@ -2157,6 +2192,8 @@ static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type)
                                if ((*tmp)->def) {
                                  type->def = estrdup((*tmp)->def);
                                }
+                       } else if (strcmp(type->ref, SCHEMA_NAMESPACE ":schema") == 0) {
+                               type->encode = get_conversion(XSD_ANYXML);
                        } else {
                                soap_error0(E_ERROR, "Parsing Schema: unresolved element 'ref' attribute");
                        }
@@ -2258,6 +2295,8 @@ void delete_model(void *handle)
                case XSD_CONTENT_GROUP_REF:
                        efree(tmp->u.group_ref);
                        break;
+               default:
+                       break;
        }
        efree(tmp);
 }
index 5d25adc231657c0cce5a79c1f60bea1bcfb95d47..d2c9bfd033a55bd6c032544389d2c2768b2ac7d2 100644 (file)
@@ -152,7 +152,8 @@ typedef enum _sdlContentKind {
        XSD_CONTENT_ALL,
        XSD_CONTENT_CHOICE,
        XSD_CONTENT_GROUP_REF,
-       XSD_CONTENT_GROUP
+       XSD_CONTENT_GROUP,
+       XSD_CONTENT_ANY
 } sdlContentKind;
 
 
index 41c639c0aa304acc975c68179924ce633fa4d84b..39b4a5fc1fe1ec4a4d8beb26a9ddecc10c210275 100644 (file)
@@ -3946,11 +3946,19 @@ static void function_to_string(sdlFunctionPtr function, smart_str *buf)
 
 static void model_to_string(sdlContentModelPtr model, smart_str *buf, int level)
 {
+       int i;
+
        switch (model->kind) {
                case XSD_CONTENT_ELEMENT:
                        type_to_string(model->u.element, buf, level);
                        smart_str_appendl(buf, ";\n", 2);
                        break;
+               case XSD_CONTENT_ANY:
+                       for (i = 0;i < level;i++) {
+                               smart_str_appendc(buf, ' ');
+                       }
+                       smart_str_appendl(buf, "<anyXML> any;\n", sizeof("<anyXML> any;\n")-1);
+                       break;
                case XSD_CONTENT_SEQUENCE:
                case XSD_CONTENT_ALL:
                case XSD_CONTENT_CHOICE: {
diff --git a/ext/soap/tests/bugs/bug30106.phpt b/ext/soap/tests/bugs/bug30106.phpt
new file mode 100644 (file)
index 0000000..dbc44f6
--- /dev/null
@@ -0,0 +1,72 @@
+--TEST--
+Bug #30106 SOAP cannot not parse 'ref' element. Causes Uncaught SoapFault exception.
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+ini_set("soap.wsdl_cache_enabled", 0);
+
+function getContinentList() {
+       return array("getContinentListResult"=>array(
+         "schema"=>"<xsd:schema><element name=\"test\" type=\"xsd:string\"/></xsd:schema>",
+         "any"=>"<test>Hello World!</test><test>Bye World!</test>"));
+}
+
+class LocalSoapClient extends SoapClient {
+  function __construct($wsdl, $options=array()) {
+    parent::__construct($wsdl, $options);
+    $this->server = new SoapServer($wsdl, $options);
+               $this->server->addFunction("getContinentList"); 
+  }
+
+  function __doRequest($request, $location, $action, $version) {
+       echo $request;
+    ob_start();
+    $this->server->handle($request);
+    $response = ob_get_contents();
+    ob_end_clean();
+       echo $response;
+    return $response;
+  }
+}
+
+$client = new LocalSoapClient(dirname(__FILE__)."/bug30106.wsdl");
+var_dump($client->__getFunctions());
+var_dump($client->__getTypes());
+$x = $client->getContinentList(array("AFFILIATE_ID"=>1,"PASSWORD"=>"x"));
+var_dump($x);
+?>
+--EXPECTF--
+array(1) {
+  [0]=>
+  string(71) "getContinentListResponse getContinentList(getContinentList $parameters)"
+}
+array(3) {
+  [0]=>
+  string(64) "struct getContinentList {
+ int AFFILIATE_ID;
+ string PASSWORD;
+}"
+  [1]=>
+  string(83) "struct getContinentListResponse {
+ getContinentListResult getContinentListResult;
+}"
+  [2]=>
+  string(66) "struct getContinentListResult {
+ <anyXML> schema;
+ <anyXML> any;
+}"
+}
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/PRWebServ/getOtherInformation"><SOAP-ENV:Body><ns1:getContinentList><ns1:AFFILIATE_ID>1</ns1:AFFILIATE_ID><ns1:PASSWORD>x</ns1:PASSWORD></ns1:getContinentList></SOAP-ENV:Body></SOAP-ENV:Envelope>
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://tempuri.org/PRWebServ/getOtherInformation"><SOAP-ENV:Body><ns1:getContinentListResponse><ns1:getContinentListResult><xsd:schema><element name="test" type="xsd:string"/></xsd:schema><test>Hello World!</test><test>Bye World!</test></ns1:getContinentListResult></ns1:getContinentListResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
+object(stdClass)#%d (1) {
+  ["getContinentListResult"]=>
+  object(stdClass)#%d (2) {
+    ["schema"]=>
+    string(65) "<xsd:schema><element name="test" type="xsd:string"/></xsd:schema>"
+    ["any"]=>
+    string(48) "<test>Hello World!</test><test>Bye World!</test>"
+  }
+}
diff --git a/ext/soap/tests/bugs/bug30106.wsdl b/ext/soap/tests/bugs/bug30106.wsdl
new file mode 100644 (file)
index 0000000..db1922d
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/PRWebServ/getOtherInformation" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://tempuri.org/PRWebServ/getOtherInformation" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">\r
+  <wsdl:types>\r
+    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/PRWebServ/getOtherInformation">\r
+      <s:import namespace="http://www.w3.org/2001/XMLSchema" />\r
+      <s:element name="getContinentList">\r
+        <s:complexType>\r
+          <s:sequence>\r
+            <s:element minOccurs="1" maxOccurs="1" name="AFFILIATE_ID" type="s:int" />\r
+            <s:element minOccurs="0" maxOccurs="1" name="PASSWORD" type="s:string" />\r
+          </s:sequence>\r
+        </s:complexType>\r
+      </s:element>\r
+      <s:element name="getContinentListResponse">\r
+        <s:complexType>\r
+          <s:sequence>\r
+            <s:element minOccurs="0" maxOccurs="1" name="getContinentListResult">\r
+              <s:complexType>\r
+                <s:sequence>\r
+                  <s:element ref="s:schema" />\r
+                  <s:any />\r
+                </s:sequence>\r
+              </s:complexType>\r
+            </s:element>\r
+          </s:sequence>\r
+        </s:complexType>\r
+      </s:element>\r
+    </s:schema>\r
+  </wsdl:types>\r
+  <wsdl:message name="getContinentListSoapIn">\r
+    <wsdl:part name="parameters" element="tns:getContinentList" />\r
+  </wsdl:message>\r
+  <wsdl:message name="getContinentListSoapOut">\r
+    <wsdl:part name="parameters" element="tns:getContinentListResponse" />\r
+  </wsdl:message>\r
+  <wsdl:portType name="getOtherInformationSoap">\r
+    <wsdl:operation name="getContinentList">\r
+      <wsdl:input message="tns:getContinentListSoapIn" />\r
+      <wsdl:output message="tns:getContinentListSoapOut" />\r
+    </wsdl:operation>\r
+  </wsdl:portType>\r
+  <wsdl:binding name="getOtherInformationSoap" type="tns:getOtherInformationSoap">\r
+    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />\r
+    <wsdl:operation name="getContinentList">\r
+      <soap:operation soapAction="http://tempuri.org/PRWebServ/getOtherInformation/getContinentList" style="document" />\r
+      <wsdl:input>\r
+        <soap:body use="literal" />\r
+      </wsdl:input>\r
+      <wsdl:output>\r
+        <soap:body use="literal" />\r
+      </wsdl:output>\r
+    </wsdl:operation>\r
+  </wsdl:binding>\r
+  <wsdl:service name="getOtherInformation">\r
+    <wsdl:port name="getOtherInformationSoap" binding="tns:getOtherInformationSoap">\r
+      <soap:address location="http://www.precisionreservations.com/PRWebServ/getOtherInformation.asmx" />\r
+    </wsdl:port>\r
+  </wsdl:service>\r
+</wsdl:definitions>
\ No newline at end of file