Skip to content

Commit 3a3ce33

Browse files
committed
ext/soap: call userland functions directly
1 parent 13f440d commit 3a3ce33

3 files changed

Lines changed: 95 additions & 81 deletions

File tree

‎ext/soap/soap.c‎

Lines changed: 78 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,12 +1374,11 @@ PHP_METHOD(SoapServer, handle)
13741374
sdlPtr old_sdl = NULL;
13751375
soapServicePtr service;
13761376
xmlDocPtr doc_request = NULL, doc_return = NULL;
1377-
zval function_name, *params, *soap_obj, retval;
1377+
zval function_name, *params, retval;
13781378
char cont_len[30];
13791379
uint32_t num_params = 0;
1380-
int size, i, call_status = 0;
1380+
int size, i;
13811381
xmlChar *buf;
1382-
HashTable *function_table;
13831382
soapHeader *soap_headers = NULL;
13841383
sdlFunctionPtr function;
13851384
char *arg = NULL;
@@ -1554,10 +1553,10 @@ PHP_METHOD(SoapServer, handle)
15541553

15551554
service->soap_headers_ptr = &soap_headers;
15561555

1557-
soap_obj = NULL;
1556+
zval *soap_obj = NULL;
1557+
HashTable *function_table = NULL;
15581558
if (service->type == SOAP_OBJECT) {
15591559
soap_obj = &service->soap_object;
1560-
function_table = &((Z_OBJCE_P(soap_obj))->function_table);
15611560
} else if (service->type == SOAP_CLASS) {
15621561
/* If persistent then set soap_obj from the previous created session (if available) */
15631562
#ifdef SOAP_HAS_SESSION_SUPPORT
@@ -1581,7 +1580,7 @@ PHP_METHOD(SoapServer, handle)
15811580
}
15821581
#endif
15831582

1584-
/* If new session or something weird happned */
1583+
/* If new session or something weird happened */
15851584
if (soap_obj == NULL) {
15861585
if (UNEXPECTED(object_init_ex(&tmp_soap, service->soap_class.ce) != SUCCESS)) {
15871586
php_output_discard();
@@ -1619,7 +1618,6 @@ PHP_METHOD(SoapServer, handle)
16191618
soap_obj = &tmp_soap;
16201619
}
16211620
}
1622-
function_table = &((Z_OBJCE_P(soap_obj))->function_table);
16231621
} else {
16241622
if (service->soap_functions.functions_all) {
16251623
function_table = EG(function_table);
@@ -1644,52 +1642,72 @@ PHP_METHOD(SoapServer, handle)
16441642
}
16451643
}
16461644
#endif
1647-
if (zend_hash_find_ptr_lc(function_table, Z_STR(h->function_name)) != NULL ||
1648-
((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1649-
zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1650-
call_status = call_user_function(NULL, soap_obj, &h->function_name, &h->retval, h->num_params, h->parameters);
1651-
if (call_status != SUCCESS) {
1652-
php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(h->function_name));
1653-
return;
1654-
}
1655-
if (Z_TYPE(h->retval) == IS_OBJECT &&
1656-
instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
1657-
php_output_discard();
1658-
soap_server_fault_ex(function, &h->retval, h);
1659-
if (service->type == SOAP_CLASS && soap_obj) {
1660-
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1661-
zval_ptr_dtor(soap_obj);
1662-
}
1645+
1646+
if (soap_obj) {
1647+
/* This is because the object might define a __call() magic method */
1648+
zend_result method_call_result = zend_call_method_if_exists(Z_OBJ_P(soap_obj), Z_STR(h->function_name), &h->retval, h->num_params, h->parameters);
1649+
if (UNEXPECTED(method_call_result == FAILURE)) {
1650+
if (h->mustUnderstand) {
1651+
soap_server_fault_en("MustUnderstand","Header not understood");
1652+
goto fail;
16631653
}
1664-
goto fail;
1665-
} else if (EG(exception)) {
1666-
php_output_discard();
1667-
_soap_server_exception(service, function, ZEND_THIS);
1668-
if (service->type == SOAP_CLASS && soap_obj) {
1669-
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1670-
zval_ptr_dtor(soap_obj);
1671-
}
1654+
continue;
1655+
}
1656+
} else {
1657+
zend_function *header_fn = zend_hash_find_ptr_lc(function_table, Z_STR(h->function_name));
1658+
if (UNEXPECTED(header_fn == NULL)) {
1659+
if (h->mustUnderstand) {
1660+
soap_server_fault_en("MustUnderstand","Header not understood");
1661+
goto fail;
16721662
}
1673-
goto fail;
1663+
continue;
16741664
}
1675-
} else if (h->mustUnderstand) {
1676-
soap_server_fault_en("MustUnderstand","Header not understood");
1665+
zend_call_known_function(header_fn, NULL, NULL, &h->retval, h->num_params, h->parameters, NULL);
1666+
}
1667+
1668+
if (Z_TYPE(h->retval) == IS_OBJECT &&
1669+
instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
1670+
php_output_discard();
1671+
soap_server_fault_ex(function, &h->retval, h);
1672+
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1673+
goto fail;
1674+
} else if (EG(exception)) {
1675+
php_output_discard();
1676+
_soap_server_exception(service, function, ZEND_THIS);
1677+
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1678+
goto fail;
16771679
}
16781680
}
16791681
}
16801682

1681-
if (zend_hash_find_ptr_lc(function_table, Z_STR(function_name)) != NULL ||
1682-
((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1683-
zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1684-
call_status = call_user_function(NULL, soap_obj, &function_name, &retval, num_params, params);
1685-
if (service->type == SOAP_CLASS) {
1686-
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1683+
if (soap_obj) {
1684+
/* This is because the object might define a __call() magic method */
1685+
zend_result method_call_result = zend_call_method_if_exists(Z_OBJ_P(soap_obj), Z_STR(function_name), &retval, num_params, params);
1686+
if (UNEXPECTED(method_call_result == FAILURE)) {
1687+
zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(Z_OBJCE_P(soap_obj)->name), Z_STRVAL(function_name));
1688+
php_output_discard();
1689+
_soap_server_exception(service, function, ZEND_THIS);
1690+
if (service->type == SOAP_CLASS) {
16871691
zval_ptr_dtor(soap_obj);
1688-
soap_obj = NULL;
16891692
}
1693+
goto fail;
16901694
}
16911695
} else {
1692-
php_error(E_ERROR, "Function '%s' doesn't exist", Z_STRVAL(function_name));
1696+
zend_function *fn = zend_hash_find_ptr_lc(function_table, Z_STR(function_name));
1697+
if (UNEXPECTED(fn == NULL)) {
1698+
zend_throw_error(NULL, "Call to undefined function %s()", Z_STRVAL(function_name));
1699+
php_output_discard();
1700+
_soap_server_exception(service, function, ZEND_THIS);
1701+
goto fail;
1702+
}
1703+
zend_call_known_function(fn, NULL, NULL, &retval, num_params, params, NULL);
1704+
}
1705+
1706+
if (service->type == SOAP_CLASS) {
1707+
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1708+
zval_ptr_dtor(soap_obj);
1709+
soap_obj = NULL;
1710+
}
16931711
}
16941712

16951713
if (EG(exception)) {
@@ -1705,32 +1723,27 @@ PHP_METHOD(SoapServer, handle)
17051723
goto fail;
17061724
}
17071725

1708-
if (call_status == SUCCESS) {
1709-
char *response_name;
1726+
char *response_name;
17101727

1711-
if (Z_TYPE(retval) == IS_OBJECT &&
1712-
instanceof_function(Z_OBJCE(retval), soap_fault_class_entry)) {
1713-
php_output_discard();
1714-
soap_server_fault_ex(function, &retval, NULL);
1715-
goto fail;
1716-
}
1717-
1718-
bool has_response_name = function && function->responseName;
1719-
if (has_response_name) {
1720-
response_name = function->responseName;
1721-
} else {
1722-
response_name = emalloc(Z_STRLEN(function_name) + sizeof("Response"));
1723-
memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
1724-
memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
1725-
}
1726-
doc_return = serialize_response_call(function, response_name, service->uri, &retval, soap_headers, soap_version);
1728+
if (Z_TYPE(retval) == IS_OBJECT &&
1729+
instanceof_function(Z_OBJCE(retval), soap_fault_class_entry)) {
1730+
php_output_discard();
1731+
soap_server_fault_ex(function, &retval, NULL);
1732+
goto fail;
1733+
}
17271734

1728-
if (!has_response_name) {
1729-
efree(response_name);
1730-
}
1735+
bool has_response_name = function && function->responseName;
1736+
if (has_response_name) {
1737+
response_name = function->responseName;
17311738
} else {
1732-
php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(function_name));
1733-
return;
1739+
response_name = emalloc(Z_STRLEN(function_name) + sizeof("Response"));
1740+
memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
1741+
memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
1742+
}
1743+
doc_return = serialize_response_call(function, response_name, service->uri, &retval, soap_headers, soap_version);
1744+
1745+
if (!has_response_name) {
1746+
efree(response_name);
17341747
}
17351748

17361749
if (EG(exception)) {

‎ext/soap/tests/bugs/bug73037.phpt‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,42 +136,42 @@ cleanup:
136136
--EXPECT--
137137
Iteration 0
138138

139-
Function 'CATALOG' doesn't exist
139+
Call to undefined method stdClass::CATALOG()
140140

141-
Function 'CATALOG' doesn't exist
141+
Call to undefined method stdClass::CATALOG()
142142

143143
Iteration 1
144144

145-
Function 'CATALOG' doesn't exist
145+
Call to undefined method stdClass::CATALOG()
146146

147-
Function 'CATALOG' doesn't exist
147+
Call to undefined method stdClass::CATALOG()
148148

149149
Iteration 2
150150

151-
Function 'CATALOG' doesn't exist
151+
Call to undefined method stdClass::CATALOG()
152152

153-
Function 'CATALOG' doesn't exist
153+
Call to undefined method stdClass::CATALOG()
154154

155155
Iteration 3
156156

157-
Function 'CATALOG' doesn't exist
157+
Call to undefined method stdClass::CATALOG()
158158

159-
Function 'CATALOG' doesn't exist
159+
Call to undefined method stdClass::CATALOG()
160160

161161
Iteration 4
162162

163-
Function 'CATALOG' doesn't exist
163+
Call to undefined method stdClass::CATALOG()
164164

165-
Function 'CATALOG' doesn't exist
165+
Call to undefined method stdClass::CATALOG()
166166

167167
Iteration 5
168168

169-
Function 'CATALOG' doesn't exist
169+
Call to undefined method stdClass::CATALOG()
170170

171-
Function 'CATALOG' doesn't exist
171+
Call to undefined method stdClass::CATALOG()
172172

173173
Iteration 6
174174

175-
Function 'CATALOG' doesn't exist
175+
Call to undefined method stdClass::CATALOG()
176176

177-
Function 'CATALOG' doesn't exist
177+
Call to undefined method stdClass::CATALOG()

‎ext/soap/tests/gh22218.phpt‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ $_SERVER = 79;
2121
$server = new SoapServer(null, ['uri' => 'http://test-uri']);
2222
$server->handle();
2323
?>
24-
--EXPECTF--
25-
%AFunction 'test' doesn't exist%A
24+
--EXPECT--
25+
<?xml version="1.0" encoding="UTF-8"?>
26+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Call to undefined function test()</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

0 commit comments

Comments
 (0)