webservice MDL-21580 remove reponse hook, add response cleaning to the method body for all Zend servers.
This commit is contained in:
@@ -16,6 +16,7 @@ $string['fixsetting'] = 'Please fix your settings in config.php: <p>You have:</p
|
||||
$string['invalideventdata'] = 'Incorrect eventadata submitted: $a';
|
||||
$string['invalidarraysize'] = 'Incorrect size of arrays in params of $a';
|
||||
$string['invalidparameter'] = 'Invalid parameter value detected, execution can not continue.';
|
||||
$string['invalidresponse'] = 'Invalid response value detected, execution can not continue.';
|
||||
$string['missingconfigversion'] = 'Config table does not contain version, can not continue, sorry.';
|
||||
$string['mustbeoveride'] = 'Abstract $a method must be overriden.';
|
||||
$string['morethanonerecordinfetch'] = 'Found more than one record in fetch() !';
|
||||
|
||||
@@ -50,6 +50,8 @@ $string['error'] = 'Error: $a';
|
||||
$string['errorcodes'] = 'Error message';
|
||||
$string['errorinvalidparamsapi'] = 'Invalid external api parameter';
|
||||
$string['errorinvalidparamsdesc'] = 'Invalid external api description';
|
||||
$string['errorinvalidresponseapi'] = 'Invalid external api response';
|
||||
$string['errorinvalidresponsedesc'] = 'Invalid external api response description';
|
||||
$string['errormissingkey'] = 'Missing required key in single structure: $a';
|
||||
$string['erroronlyarray'] = 'Only arrays accepted.';
|
||||
$string['errorscalartype'] = 'Scalar type expected, array or object received.';
|
||||
@@ -67,6 +69,7 @@ $string['generalstructure'] = 'General structure';
|
||||
$string['httpswarning'] = 'Token strings are only displayed if your connection is secured (https)';
|
||||
$string['information'] = 'Information';
|
||||
$string['invalidextparam'] = 'Invalid external api parameter: $a';
|
||||
$string['invalidextresponse'] = 'Invalid external api response: $a';
|
||||
$string['invalidiptoken'] = 'Invalid token - your IP is not supported';
|
||||
$string['invalidtimedtoken'] = 'Invalid token - token expired';
|
||||
$string['invalidtoken'] = 'Invalid token - token not found';
|
||||
|
||||
@@ -205,6 +205,77 @@ class external_api {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean response
|
||||
* If a response attribut is unknown from the description, we just ignore the attribut.
|
||||
* If a response attribut is incorrect, invalid_response_exception is thrown.
|
||||
* Note: this function is similar to validate parameters, however it is distinct because
|
||||
* parameters validation must be distinct from cleaning return values.
|
||||
* @param external_description $description description of the return values
|
||||
* @param mixed $response the actual response
|
||||
* @return mixed response with added defaults for optional items, invalid_response_exception thrown if any problem found
|
||||
*/
|
||||
public static function clean_returnvalue(external_description $description, $response) {
|
||||
if ($description instanceof external_value) {
|
||||
if (is_array($response) or is_object($response)) {
|
||||
throw new invalid_response_exception(get_string('errorscalartype', 'webservice'));
|
||||
}
|
||||
|
||||
if ($description->type == PARAM_BOOL) {
|
||||
// special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-)
|
||||
if (is_bool($response) or $response === 0 or $response === 1 or $response === '0' or $response === '1') {
|
||||
return (bool)$response;
|
||||
}
|
||||
}
|
||||
return validate_param($response, $description->type, $description->allownull, get_string('errorinvalidresponseapi', 'webservice'));
|
||||
|
||||
} else if ($description instanceof external_single_structure) {
|
||||
if (!is_array($response)) {
|
||||
throw new invalid_response_exception(get_string('erroronlyarray', 'webservice'));
|
||||
}
|
||||
$result = array();
|
||||
foreach ($description->keys as $key=>$subdesc) {
|
||||
if (!array_key_exists($key, $response)) {
|
||||
if ($subdesc->required == VALUE_REQUIRED) {
|
||||
throw new invalid_response_exception(get_string('errormissingkey', 'webservice', $key));
|
||||
}
|
||||
if ($subdesc instanceof external_value) {
|
||||
if ($subdesc->required == VALUE_DEFAULT) {
|
||||
try {
|
||||
$result[$key] = self::clean_returnvalue($subdesc, $subdesc->default);
|
||||
} catch (invalid_response_exception $e) {
|
||||
throw new webservice_parameter_exception('invalidextresponse',$key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$result[$key] = self::clean_returnvalue($subdesc, $response[$key]);
|
||||
} catch (invalid_response_exception $e) {
|
||||
//it's ok to display debug info as here the information is useful for ws client/dev
|
||||
throw new webservice_parameter_exception('invalidextresponse',$key." (".$e->debuginfo.")");
|
||||
}
|
||||
}
|
||||
unset($response[$key]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
} else if ($description instanceof external_multiple_structure) {
|
||||
if (!is_array($response)) {
|
||||
throw new invalid_response_exception(get_string('erroronlyarray', 'webservice'));
|
||||
}
|
||||
$result = array();
|
||||
foreach ($response as $param) {
|
||||
$result[] = self::clean_returnvalue($description->content, $param);
|
||||
}
|
||||
return $result;
|
||||
|
||||
} else {
|
||||
throw new invalid_response_exception(get_string('errorinvalidresponsedesc', 'webservice'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure user may execute functions in this context.
|
||||
* @param object $context
|
||||
|
||||
@@ -154,6 +154,22 @@ class invalid_parameter_exception extends moodle_exception {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception indicating malformed response problem.
|
||||
* This exception is not supposed to be thrown when processing
|
||||
* user submitted data in forms. It is more suitable
|
||||
* for WS and other low level stuff.
|
||||
*/
|
||||
class invalid_response_exception extends moodle_exception {
|
||||
/**
|
||||
* Constructor
|
||||
* @param string $debuginfo some detailed information
|
||||
*/
|
||||
function __construct($debuginfo=null) {
|
||||
parent::__construct('invalidresponse', 'debug', '', null, $debuginfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An exception that indicates something really weird happened. For example,
|
||||
* if you do switch ($context->contextlevel), and have one case for each
|
||||
|
||||
+4
-14
@@ -261,9 +261,6 @@ abstract class webservice_zend_server extends webservice_server {
|
||||
// execute and return response, this sends some headers too
|
||||
$response = $this->zend_server->handle();
|
||||
|
||||
//hook for cleaning response (if necessary)
|
||||
$response = $this->clean_response($response);
|
||||
|
||||
// session cleanup
|
||||
$this->session_cleanup();
|
||||
|
||||
@@ -457,9 +454,11 @@ class '.$classname.' {
|
||||
* @return string body of the method for $function ie. everything within the {} of the method declaration.
|
||||
*/
|
||||
protected function service_class_method_body($function, $params){
|
||||
return ' return '.$function->classname.'::'.$function->methodname.'('.$params.');';
|
||||
$descriptionmethod = $function->methodname.'_returns()';
|
||||
$callforreturnvaluedesc = $function->classname.'::'.$descriptionmethod;
|
||||
return ' return external_api::clean_returnvalue('.$callforreturnvaluedesc.', '.$function->classname.'::'.$function->methodname.'('.$params.'));';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up zend service class
|
||||
* @return void
|
||||
@@ -547,15 +546,6 @@ class '.$classname.' {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook needed for cleaning the response (xml-rpc, soap,...).
|
||||
* @param array $response the response to clean
|
||||
* @return array $response the cleaned response
|
||||
*/
|
||||
protected function clean_response($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,97 +50,6 @@ class webservice_xmlrpc_server extends webservice_zend_server {
|
||||
Zend_XmlRpc_Server_Fault::attachFaultException('moodle_exception');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean XML-RPC reponse
|
||||
* @param array $response the response to clean
|
||||
* @return array $response the cleaned response
|
||||
*/
|
||||
protected function clean_response($response) {
|
||||
//check that the response is not an exception/server fault
|
||||
if (!($response instanceof Zend_XmlRpc_Server_Fault)) {
|
||||
$methodname = $this->zend_server->getRequest()->getMethod(); //retrieve the method name called by the client
|
||||
$function = external_function_info($methodname); //retrieve the description of the method name
|
||||
if (is_object($function)) { //if the method is not an object (no description found),
|
||||
// do not make any change on the response
|
||||
$returnvalue = $response->getReturnValue();
|
||||
$returnvalue = $this->clean_returnvalue($function->returns_desc, $returnvalue);
|
||||
$response->setReturnValue($returnvalue);
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clean response, if anything is incorrect
|
||||
* invalid_parameter_exception is thrown, if an attribut is unknow from the description,
|
||||
* just ignore it.
|
||||
* Note: this is a recursive method
|
||||
* @param external_description $description description of parameters
|
||||
* @param mixed $response the actual parameters
|
||||
* @return mixed params with added defaults for optional items, invalid_parameters_exception thrown if any problem found
|
||||
*/
|
||||
private function clean_returnvalue(external_description $description, $response) {
|
||||
if ($description instanceof external_value) {
|
||||
if (is_array($response) or is_object($response)) {
|
||||
throw new invalid_parameter_exception(get_string('errorscalartype', 'webservice'));
|
||||
}
|
||||
|
||||
if ($description->type == PARAM_BOOL) {
|
||||
// special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-)
|
||||
if (is_bool($response) or $response === 0 or $response === 1 or $response === '0' or $response === '1') {
|
||||
return (bool)$response;
|
||||
}
|
||||
}
|
||||
return validate_param($response, $description->type, $description->allownull, get_string('errorinvalidparamsapi', 'webservice'));
|
||||
|
||||
} else if ($description instanceof external_single_structure) {
|
||||
if (!is_array($response)) {
|
||||
throw new invalid_parameter_exception(get_string('erroronlyarray', 'webservice'));
|
||||
}
|
||||
$result = array();
|
||||
foreach ($description->keys as $key=>$subdesc) {
|
||||
if (!array_key_exists($key, $response)) {
|
||||
if ($subdesc->required == VALUE_REQUIRED) {
|
||||
throw new invalid_parameter_exception(get_string('errormissingkey', 'webservice', $key));
|
||||
}
|
||||
if ($subdesc instanceof external_value) {
|
||||
if ($subdesc->required == VALUE_DEFAULT) {
|
||||
try {
|
||||
$result[$key] = $this->clean_returnvalue($subdesc, $subdesc->default);
|
||||
} catch (invalid_parameter_exception $e) {
|
||||
throw new webservice_parameter_exception('invalidextparam',$key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$result[$key] = $this->clean_returnvalue($subdesc, $response[$key]);
|
||||
} catch (invalid_parameter_exception $e) {
|
||||
//it's ok to display debug info as here the information is useful for ws client/dev
|
||||
throw new webservice_parameter_exception('invalidextparam',$key." (".$e->debuginfo.")");
|
||||
}
|
||||
}
|
||||
unset($response[$key]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
} else if ($description instanceof external_multiple_structure) {
|
||||
if (!is_array($response)) {
|
||||
throw new invalid_parameter_exception(get_string('erroronlyarray', 'webservice'));
|
||||
}
|
||||
$result = array();
|
||||
foreach ($response as $param) {
|
||||
$result[] = $this->clean_returnvalue($description->content, $param);
|
||||
}
|
||||
return $result;
|
||||
|
||||
} else {
|
||||
throw new invalid_parameter_exception(get_string('errorinvalidparamsdesc', 'webservice'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user