summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2005-03-22 10:19:08 (GMT)
committerDmitry Stogov <dmitry@php.net>2005-03-22 10:19:08 (GMT)
commitfedbd2145a2811182414acc089b7115965c3b849 (patch)
treefd9894c763789eb893e116ba5864fce80db28370 /ext
parent5d0281d0609094bc85fc9792ea81257fc479132d (diff)
downloadphp-fedbd2145a2811182414acc089b7115965c3b849.tar.gz
Fixed bug #30106 (SOAP cannot not parse 'ref' element. Causes Uncaught SoapFault exception)
Diffstat (limited to 'ext')
-rw-r--r--ext/soap/php_encoding.c120
-rw-r--r--ext/soap/php_encoding.h4
-rw-r--r--ext/soap/php_packet_soap.c5
-rw-r--r--ext/soap/php_schema.c43
-rw-r--r--ext/soap/php_sdl.h3
-rw-r--r--ext/soap/soap.c8
-rw-r--r--ext/soap/tests/bugs/bug30106.phpt72
-rw-r--r--ext/soap/tests/bugs/bug30106.wsdl59
8 files changed, 306 insertions, 8 deletions
diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
index af78405..53f2825 100644
--- a/ext/soap/php_encoding.c
+++ b/ext/soap/php_encoding.c
@@ -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();
diff --git a/ext/soap/php_encoding.h b/ext/soap/php_encoding.h
index 1e26cdb..d291e5b 100644
--- a/ext/soap/php_encoding.h
+++ b/ext/soap/php_encoding.h
@@ -139,6 +139,8 @@
#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[];
diff --git a/ext/soap/php_packet_soap.c b/ext/soap/php_packet_soap.c
index 7b0465f..81805b4 100644
--- a/ext/soap/php_packet_soap.c
+++ b/ext/soap/php_packet_soap.c
@@ -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;
}
diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c
index 758f3bc..6aee092 100644
--- a/ext/soap/php_schema.c
+++ b/ext/soap/php_schema.c
@@ -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;
}
@@ -2156,6 +2191,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");
}
@@ -2257,6 +2294,8 @@ void delete_model(void *handle)
case XSD_CONTENT_GROUP_REF:
efree(tmp->u.group_ref);
break;
+ default:
+ break;
}
efree(tmp);
}
diff --git a/ext/soap/php_sdl.h b/ext/soap/php_sdl.h
index 5d25adc..d2c9bfd 100644
--- a/ext/soap/php_sdl.h
+++ b/ext/soap/php_sdl.h
@@ -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;
diff --git a/ext/soap/soap.c b/ext/soap/soap.c
index 41c639c..39b4a5f 100644
--- a/ext/soap/soap.c
+++ b/ext/soap/soap.c
@@ -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
index 0000000..dbc44f6
--- /dev/null
+++ b/ext/soap/tests/bugs/bug30106.phpt
@@ -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
index 0000000..db1922d
--- /dev/null
+++ b/ext/soap/tests/bugs/bug30106.wsdl
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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/">
+ <wsdl:types>
+ <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/PRWebServ/getOtherInformation">
+ <s:import namespace="http://www.w3.org/2001/XMLSchema" />
+ <s:element name="getContinentList">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="1" maxOccurs="1" name="AFFILIATE_ID" type="s:int" />
+ <s:element minOccurs="0" maxOccurs="1" name="PASSWORD" type="s:string" />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ <s:element name="getContinentListResponse">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="getContinentListResult">
+ <s:complexType>
+ <s:sequence>
+ <s:element ref="s:schema" />
+ <s:any />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ </s:schema>
+ </wsdl:types>
+ <wsdl:message name="getContinentListSoapIn">
+ <wsdl:part name="parameters" element="tns:getContinentList" />
+ </wsdl:message>
+ <wsdl:message name="getContinentListSoapOut">
+ <wsdl:part name="parameters" element="tns:getContinentListResponse" />
+ </wsdl:message>
+ <wsdl:portType name="getOtherInformationSoap">
+ <wsdl:operation name="getContinentList">
+ <wsdl:input message="tns:getContinentListSoapIn" />
+ <wsdl:output message="tns:getContinentListSoapOut" />
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="getOtherInformationSoap" type="tns:getOtherInformationSoap">
+ <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
+ <wsdl:operation name="getContinentList">
+ <soap:operation soapAction="http://tempuri.org/PRWebServ/getOtherInformation/getContinentList" style="document" />
+ <wsdl:input>
+ <soap:body use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap:body use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="getOtherInformation">
+ <wsdl:port name="getOtherInformationSoap" binding="tns:getOtherInformationSoap">
+ <soap:address location="http://www.precisionreservations.com/PRWebServ/getOtherInformation.asmx" />
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions> \ No newline at end of file