webservice MDL-21580 remove reponse hook, add response cleaning to the method body for all Zend servers.

This commit is contained in:
jerome mouneyrac
2010-02-22 07:07:44 +00:00
parent 8300f99e09
commit d07ff72d15
6 changed files with 95 additions and 105 deletions
+1
View File
@@ -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() !';
+3
View File
@@ -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';
+71
View File
@@ -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
+16
View File
@@ -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
View File
@@ -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;
}
}
/**
-91
View File
@@ -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'));
}
}
}
/**