Skip to content

Commit 4f51fe0

Browse files
committed
soap: call userland functions directly
1 parent 36c5eeb commit 4f51fe0

3 files changed

Lines changed: 94 additions & 72 deletions

File tree

‎ext/soap/soap.c‎

Lines changed: 77 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,12 +1383,11 @@ PHP_METHOD(SoapServer, handle)
13831383
sdlPtr old_sdl = NULL;
13841384
soapServicePtr service;
13851385
xmlDocPtr doc_request = NULL, doc_return = NULL;
1386-
zval function_name, *params, *soap_obj, retval;
1386+
zval function_name, *params, retval;
13871387
char cont_len[30];
13881388
uint32_t num_params = 0;
1389-
int size, i, call_status = 0;
1389+
int size, i;
13901390
xmlChar *buf;
1391-
HashTable *function_table;
13921391
soapHeader *soap_headers = NULL;
13931392
sdlFunctionPtr function;
13941393
char *arg = NULL;
@@ -1563,10 +1562,10 @@ PHP_METHOD(SoapServer, handle)
15631562

15641563
service->soap_headers_ptr = &soap_headers;
15651564

1566-
soap_obj = NULL;
1565+
zval *soap_obj = NULL;
1566+
HashTable *function_table = NULL;
15671567
if (service->type == SOAP_OBJECT) {
15681568
soap_obj = &service->soap_object;
1569-
function_table = &((Z_OBJCE_P(soap_obj))->function_table);
15701569
} else if (service->type == SOAP_CLASS) {
15711570
/* If persistent then set soap_obj from the previous created session (if available) */
15721571
#ifdef SOAP_HAS_SESSION_SUPPORT
@@ -1590,7 +1589,7 @@ PHP_METHOD(SoapServer, handle)
15901589
}
15911590
#endif
15921591

1593-
/* If new session or something weird happned */
1592+
/* If new session or something weird happened */
15941593
if (soap_obj == NULL) {
15951594
if (UNEXPECTED(object_init_ex(&tmp_soap, service->soap_class.ce) != SUCCESS)) {
15961595
php_output_discard();
@@ -1628,7 +1627,6 @@ PHP_METHOD(SoapServer, handle)
16281627
soap_obj = &tmp_soap;
16291628
}
16301629
}
1631-
function_table = &((Z_OBJCE_P(soap_obj))->function_table);
16321630
} else {
16331631
if (service->soap_functions.functions_all) {
16341632
function_table = EG(function_table);
@@ -1653,41 +1651,69 @@ PHP_METHOD(SoapServer, handle)
16531651
}
16541652
}
16551653
#endif
1656-
if (zend_hash_find_ptr_lc(function_table, Z_STR(h->function_name)) != NULL ||
1657-
((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1658-
zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1659-
call_status = call_user_function(NULL, soap_obj, &h->function_name, &h->retval, h->num_params, h->parameters);
1660-
if (call_status != SUCCESS) {
1661-
php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(h->function_name));
1662-
return;
1654+
if (soap_obj) {
1655+
/* This is because the object might define a __call() magic method */
1656+
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);
1657+
if (UNEXPECTED(method_call_result == FAILURE)) {
1658+
if (h->mustUnderstand) {
1659+
soap_server_fault_en("MustUnderstand","Header not understood");
1660+
goto fail;
1661+
}
1662+
ZVAL_NULL(&h->retval);
1663+
continue;
16631664
}
1664-
if (Z_TYPE(h->retval) == IS_OBJECT &&
1665-
instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
1666-
php_output_discard();
1667-
soap_server_fault_ex(function, &h->retval, h);
1668-
soap_free_server_object(service, soap_obj);
1669-
goto fail;
1670-
} else if (EG(exception)) {
1671-
php_output_discard();
1672-
_soap_server_exception(service, function, ZEND_THIS);
1673-
soap_free_server_object(service, soap_obj);
1674-
goto fail;
1665+
} else {
1666+
zend_function *header_fn = zend_hash_find_ptr_lc(function_table, Z_STR(h->function_name));
1667+
if (UNEXPECTED(header_fn == NULL)) {
1668+
if (h->mustUnderstand) {
1669+
soap_server_fault_en("MustUnderstand","Header not understood");
1670+
goto fail;
1671+
}
1672+
ZVAL_NULL(&h->retval);
1673+
continue;
16751674
}
1676-
} else if (h->mustUnderstand) {
1677-
soap_server_fault_en("MustUnderstand","Header not understood");
1675+
zend_call_known_function(header_fn, NULL, NULL, &h->retval, h->num_params, h->parameters, NULL);
1676+
}
1677+
1678+
if (Z_TYPE(h->retval) == IS_OBJECT &&
1679+
instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
1680+
php_output_discard();
1681+
soap_server_fault_ex(function, &h->retval, h);
1682+
soap_free_server_object(service, soap_obj);
1683+
goto fail;
1684+
} else if (EG(exception)) {
1685+
php_output_discard();
1686+
_soap_server_exception(service, function, ZEND_THIS);
1687+
soap_free_server_object(service, soap_obj);
1688+
goto fail;
16781689
}
16791690
}
16801691
}
16811692

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

1715+
soap_free_server_object(service, soap_obj);
1716+
16911717
if (EG(exception)) {
16921718
if (!zend_is_unwind_exit(EG(exception))) {
16931719
php_output_discard();
@@ -1697,32 +1723,27 @@ PHP_METHOD(SoapServer, handle)
16971723
goto fail;
16981724
}
16991725

1700-
if (call_status == SUCCESS) {
1701-
char *response_name;
1726+
char *response_name;
17021727

1703-
if (Z_TYPE(retval) == IS_OBJECT &&
1704-
instanceof_function(Z_OBJCE(retval), soap_fault_class_entry)) {
1705-
php_output_discard();
1706-
soap_server_fault_ex(function, &retval, NULL);
1707-
goto fail;
1708-
}
1709-
1710-
bool has_response_name = function && function->responseName;
1711-
if (has_response_name) {
1712-
response_name = function->responseName;
1713-
} else {
1714-
response_name = emalloc(Z_STRLEN(function_name) + sizeof("Response"));
1715-
memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
1716-
memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
1717-
}
1718-
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+
}
17191734

1720-
if (!has_response_name) {
1721-
efree(response_name);
1722-
}
1735+
bool has_response_name = function && function->responseName;
1736+
if (has_response_name) {
1737+
response_name = function->responseName;
17231738
} else {
1724-
php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(function_name));
1725-
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);
17261747
}
17271748

17281749
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)