mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix #49169: SoapServer calls wrong function, although "SOAP action" header is correct
Although the original reproducer no longer exists, I was able to cook up something similar. The problem is that there are two ways ext-soap currently looks up functions: 1) By matching the exact function name; but this doesn't work if the function name is not in the body. 2) By matching the parameter names. Neither of these work when we don't have the function name in the body, and when the parameter names are not unique. That's where we can use the "SOAPAction" header to distinguish between different actions. This header should be checked first and be matched against the "soapAction" attribute in the WSDL. We keep the existing fallbacks such that the chance of a BC break is minimized. Note that since #49169 a potential target namespace is ignored right now. Closes GH-15970.
This commit is contained in:
4
NEWS
4
NEWS
@@ -15,4 +15,8 @@ PHP NEWS
|
||||
- Random:
|
||||
. Moves from /dev/urandom usage to arc4random_buf on Haiku. (David Carlier)
|
||||
|
||||
- SOAP:
|
||||
. Fixed bug #49169 (SoapServer calls wrong function, although "SOAP action"
|
||||
header is correct). (nielsdos)
|
||||
|
||||
<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
|
||||
|
||||
@@ -58,7 +58,7 @@ static sdlParamPtr get_param(sdlFunctionPtr function, const char *param_name, ze
|
||||
static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name, size_t function_name_length);
|
||||
static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr params);
|
||||
|
||||
static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, const char* actor, zval *function_name, uint32_t *num_params, zval **parameters, int *version, soapHeader **headers);
|
||||
static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, const char* actor, const char *soap_action, zval *function_name, uint32_t *num_params, zval **parameters, int *version, soapHeader **headers);
|
||||
static xmlDocPtr serialize_response_call(sdlFunctionPtr function, const char *function_name, const char *uri,zval *ret, soapHeader *headers, int version);
|
||||
static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function, const char *function_name, const char *uri, zval *arguments, uint32_t arg_count, int version, HashTable *soap_headers);
|
||||
static xmlNodePtr serialize_parameter(sdlParamPtr param,zval *param_val, uint32_t index,const char *name, int style, xmlNodePtr parent);
|
||||
@@ -1273,6 +1273,7 @@ PHP_METHOD(SoapServer, handle)
|
||||
HashTable *old_class_map, *old_typemap;
|
||||
int old_features;
|
||||
zval tmp_soap;
|
||||
const char *soap_action = NULL;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &arg, &arg_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
@@ -1341,7 +1342,7 @@ PHP_METHOD(SoapServer, handle)
|
||||
|
||||
if (!arg) {
|
||||
if (SG(request_info).request_body && 0 == php_stream_rewind(SG(request_info).request_body)) {
|
||||
zval *server_vars, *encoding;
|
||||
zval *server_vars, *encoding, *soap_action_z;
|
||||
php_stream_filter *zf = NULL;
|
||||
zend_string *server = ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER);
|
||||
|
||||
@@ -1375,6 +1376,10 @@ PHP_METHOD(SoapServer, handle)
|
||||
}
|
||||
}
|
||||
|
||||
if ((soap_action_z = zend_hash_str_find(Z_ARRVAL_P(server_vars), ZEND_STRL("HTTP_SOAPACTION"))) != NULL && Z_TYPE_P(soap_action_z) == IS_STRING) {
|
||||
soap_action = Z_STRVAL_P(soap_action_z);
|
||||
}
|
||||
|
||||
doc_request = soap_xmlParseFile("php://input");
|
||||
|
||||
if (zf) {
|
||||
@@ -1418,7 +1423,7 @@ PHP_METHOD(SoapServer, handle)
|
||||
old_soap_version = SOAP_GLOBAL(soap_version);
|
||||
|
||||
zend_try {
|
||||
function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, ¶ms, &soap_version, &soap_headers);
|
||||
function = deserialize_function_call(service->sdl, doc_request, service->actor, soap_action, &function_name, &num_params, ¶ms, &soap_version, &soap_headers);
|
||||
} zend_catch {
|
||||
/* Avoid leaking persistent memory */
|
||||
xmlFreeDoc(doc_request);
|
||||
@@ -3090,6 +3095,37 @@ static sdlFunctionPtr find_function(sdlPtr sdl, xmlNodePtr func, zval* function_
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static sdlFunctionPtr find_function_using_soap_action(const sdl *sdl, const char *soap_action, zval* function_name)
|
||||
{
|
||||
if (!sdl) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The soap action may be a http-quoted string, in which case we're removing the quotes here. */
|
||||
size_t soap_action_length = strlen(soap_action);
|
||||
if (soap_action[0] == '"') {
|
||||
if (soap_action_length < 2 || soap_action[soap_action_length - 1] != '"') {
|
||||
return NULL;
|
||||
}
|
||||
soap_action++;
|
||||
soap_action_length -= 2;
|
||||
}
|
||||
|
||||
/* TODO: This may depend on a particular target namespace, in which case this won't find a match when multiple different
|
||||
* target namespaces are used until #45282 is resolved. */
|
||||
sdlFunctionPtr function;
|
||||
ZEND_HASH_FOREACH_PTR(&sdl->functions, function) {
|
||||
if (function->binding && function->binding->bindingType == BINDING_SOAP) {
|
||||
sdlSoapBindingFunctionPtr fnb = function->bindingAttributes;
|
||||
if (fnb && fnb->soapAction && strncmp(fnb->soapAction, soap_action, soap_action_length) == 0 && fnb->soapAction[soap_action_length] == '\0') {
|
||||
ZVAL_STRING(function_name, function->functionName);
|
||||
return function;
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xmlNodePtr get_envelope(xmlNodePtr trav, int *version, char **envelope_ns) {
|
||||
while (trav != NULL) {
|
||||
if (trav->type == XML_ELEMENT_NODE) {
|
||||
@@ -3115,12 +3151,12 @@ static xmlNodePtr get_envelope(xmlNodePtr trav, int *version, char **envelope_ns
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, const char* actor, zval *function_name, uint32_t *num_params, zval **parameters, int *version, soapHeader **headers) /* {{{ */
|
||||
static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, const char* actor, const char *soap_action, zval *function_name, uint32_t *num_params, zval **parameters, int *version, soapHeader **headers) /* {{{ */
|
||||
{
|
||||
char* envelope_ns = NULL;
|
||||
xmlNodePtr trav,env,head,body,func;
|
||||
xmlAttrPtr attr;
|
||||
sdlFunctionPtr function;
|
||||
sdlFunctionPtr function = NULL;
|
||||
|
||||
encode_reset_ns();
|
||||
|
||||
@@ -3204,12 +3240,17 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c
|
||||
}
|
||||
trav = trav->next;
|
||||
}
|
||||
if (soap_action) {
|
||||
function = find_function_using_soap_action(sdl, soap_action, function_name);
|
||||
}
|
||||
if (func == NULL) {
|
||||
function = get_doc_function(sdl, NULL);
|
||||
if (function != NULL) {
|
||||
ZVAL_STRING(function_name, (char *)function->functionName);
|
||||
} else {
|
||||
soap_server_fault("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL);
|
||||
if (!function) {
|
||||
function = get_doc_function(sdl, NULL);
|
||||
if (function) {
|
||||
ZVAL_STRING(function_name, (char *)function->functionName);
|
||||
} else {
|
||||
soap_server_fault("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (*version == SOAP_1_1) {
|
||||
@@ -3223,7 +3264,9 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c
|
||||
soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
function = find_function(sdl, func, function_name);
|
||||
if (!function) {
|
||||
function = find_function(sdl, func, function_name);
|
||||
}
|
||||
if (sdl != NULL && function == NULL) {
|
||||
if (*version == SOAP_1_2) {
|
||||
soap_server_fault("rpc:ProcedureNotPresent","Procedure not present", NULL, NULL, NULL);
|
||||
|
||||
44
ext/soap/tests/bugs/bug49169.phpt
Normal file
44
ext/soap/tests/bugs/bug49169.phpt
Normal file
@@ -0,0 +1,44 @@
|
||||
--TEST--
|
||||
Bug #49169 (SoapServer calls wrong function, although "SOAP action" header is correct)
|
||||
--EXTENSIONS--
|
||||
soap
|
||||
--INI--
|
||||
soap.wsdl_cache_enabled=0
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (php_sapi_name()=='cli') echo 'skip';
|
||||
?>
|
||||
--POST--
|
||||
<SOAP-ENV:Envelope
|
||||
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
>
|
||||
<SOAP-ENV:Body>
|
||||
<testParam xsi:type="xsd:string">hello</testParam>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>
|
||||
--FILE--
|
||||
<?php
|
||||
function test($input) {
|
||||
return strrev($input);
|
||||
}
|
||||
function test2($input) {
|
||||
return strlen($input);
|
||||
}
|
||||
|
||||
$server = new soapserver(__DIR__.'/bug49169.wsdl', []);
|
||||
$server->addfunction("test");
|
||||
$server->addfunction("test2");
|
||||
$_SERVER["HTTP_SOAPACTION"] = "#test";
|
||||
$server->handle();
|
||||
$_SERVER["HTTP_SOAPACTION"] = "#test2";
|
||||
$server->handle();
|
||||
?>
|
||||
--EXPECT--
|
||||
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><testParam xsi:type="xsd:string">olleh</testParam></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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><testParam xsi:type="xsd:string">5</testParam></SOAP-ENV:Body></SOAP-ENV:Envelope>
|
||||
49
ext/soap/tests/bugs/bug49169.wsdl
Normal file
49
ext/soap/tests/bugs/bug49169.wsdl
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<definitions name="InteropTest"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
xmlns:tns="http://test-uri/"
|
||||
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
|
||||
xmlns="http://schemas.xmlsoap.org/wsdl/"
|
||||
targetNamespace="http://test-uri/">
|
||||
<message name="testMessage">
|
||||
<part name="testParam" type="xsd:string"/>
|
||||
</message>
|
||||
<portType name="testPortType">
|
||||
<operation name="test">
|
||||
<input message="testMessage"/>
|
||||
<output message="testMessage"/>
|
||||
</operation>
|
||||
<operation name="test2">
|
||||
<input message="testMessage"/>
|
||||
<output message="testMessage"/>
|
||||
</operation>
|
||||
</portType>
|
||||
<binding name="testBinding" type="testPortType">
|
||||
<soap:binding style="rcp" transport="http://schemas.xmlsoap.org/soap/http"/>
|
||||
<operation name="test">
|
||||
<soap:operation soapAction="#test" style="rcp"/>
|
||||
<input>
|
||||
<soap:body use="encoded" namespace="http://test-uri/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
|
||||
</input>
|
||||
<output>
|
||||
<soap:body use="encoded" namespace="http://test-uri/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
|
||||
</output>
|
||||
</operation>
|
||||
<operation name="test2">
|
||||
<soap:operation soapAction="#test2" style="rcp"/>
|
||||
<input>
|
||||
<soap:body use="encoded" namespace="http://test-uri/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
|
||||
</input>
|
||||
<output>
|
||||
<soap:body use="encoded" namespace="http://test-uri/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
|
||||
</output>
|
||||
</operation>
|
||||
</binding>
|
||||
<service name="testService">
|
||||
<port name="testPort" binding="tns:testBinding">
|
||||
<soap:address location="http://localhost:8080/server.php" />
|
||||
</port>
|
||||
</service>
|
||||
</definitions>
|
||||
Reference in New Issue
Block a user