From 03dd2f9c74534499862f5674f2f43aee9d64b41c Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Thu, 8 Jun 2006 21:15:02 +0000 Subject: - Patch #66154 by jvandyck: XML-RPC fixes and documentation improvements. --- includes/xmlrpcs.inc | 259 ++++++++++++++++++++++++++++----------------------- 1 file changed, 143 insertions(+), 116 deletions(-) (limited to 'includes/xmlrpcs.inc') diff --git a/includes/xmlrpcs.inc b/includes/xmlrpcs.inc index a2e2176b3..8fe46ce4e 100644 --- a/includes/xmlrpcs.inc +++ b/includes/xmlrpcs.inc @@ -1,34 +1,43 @@ 'xmlrpc_server_multicall', + 'system.multicall' => 'xmlrpc_server_multicall', array( 'system.methodSignature', 'xmlrpc_server_method_signature', array('array', 'string'), - 'Returns an array describing the return type and required parameters of a method' + 'Returns an array describing the return type and required parameters of a method.' ), array( 'system.getCapabilities', 'xmlrpc_server_get_capabilities', array('struct'), - 'Returns a struct describing the XML-RPC specifications supported by this server' + 'Returns a struct describing the XML-RPC specifications supported by this server.' ), array( 'system.listMethods', 'xmlrpc_server_list_methods', array('array'), - 'Returns an array of available methods on this server'), + 'Returns an array of available methods on this server.'), array( 'system.methodHelp', 'xmlrpc_server_method_help', array('string', 'string'), - 'Returns a documentation string for the specified method') + 'Returns a documentation string for the specified method.') ); - // the order matters in the next line. which is the best? + // We build an array of all method names by combining the built-ins + // with those defined by modules implementing the _xmlrpc hook. + // Built-in methods are overridable. foreach (array_merge($defaults, (array)$callbacks) as $key => $callback) { // we could check for is_array($callback) if (is_int($key)) { @@ -50,14 +59,14 @@ function xmlrpc_server($callbacks) { } $xmlrpc_server->message = xmlrpc_message($data); if (!xmlrpc_message_parse($xmlrpc_server->message)) { - xmlrpc_server_error(-32700, t('parse error. not well formed')); + xmlrpc_server_error(-32700, t('Parse error. Request not well formed.')); } if ($xmlrpc_server->message->messagetype != 'methodCall') { - xmlrpc_server_error(-32600, t('server error. invalid xml-rpc. not conforming to spec. Request must be a method_call')); + xmlrpc_server_error(-32600, t('Server error. Invalid XML-RPC. Request must be a methodCall.')); } xmlrpc_server_set($xmlrpc_server); $result = xmlrpc_server_call($xmlrpc_server, $xmlrpc_server->message->methodname, $xmlrpc_server->message->params); - // Is the result an error? + if ($result->is_error) { xmlrpc_server_error($result); } @@ -80,8 +89,15 @@ function xmlrpc_server($callbacks) { xmlrpc_server_output($xml); } +/** + * Throw an XML-RPC error. + * + * @param $error + * an error object OR integer error code + * @param $message + * description of error, used only if integer error code was passed + */ function xmlrpc_server_error($error, $message = false) { - // Accepts either an error object or an error code and message if ($message && !is_object($error)) { $error = xmlrpc_error($error, $message); } @@ -98,11 +114,12 @@ function xmlrpc_server_output($xml) { exit; } -function xmlrpc_server_list_methods() { - $xmlrpc_server = xmlrpc_server_get(); - return array_keys($xmlrpc_server->callbacks); -} - +/** + * Store a copy of the request temporarily. + * + * @param $xmlrpc_server + * Request object created by xmlrpc_server(). + */ function xmlrpc_server_set($xmlrpc_server = NULL) { static $server; if (!isset($server)) { @@ -111,77 +128,39 @@ function xmlrpc_server_set($xmlrpc_server = NULL) { return $server; } +// Retrieve the stored request. function xmlrpc_server_get() { return xmlrpc_server_set(); } -function xmlrpc_server_multicall($methodcalls) { - // See http://www.xmlrpc.com/discuss/msgReader$1208 - $return = array(); - $xmlrpc_server = xmlrpc_server_get(); - foreach ($methodcalls as $call) { - $method = $call['methodName']; - $params = $call['params']; - if ($method == 'system.multicall') { - $result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden')); - } - else { - $result = xmlrpc_server_call($xmlrpc_server, $method, $params); - } - if ($result->is_error) { - $return[] = array( - 'faultCode' => $result->code, - 'faultString' => $result->message - ); - } - else { - $return[] = $result; - } - } - return $return; -} - - -function xmlrpc_server_get_capabilities() { - return array( - 'xmlrpc' => array( - 'specUrl' => 'http://www.xmlrpc.com/spec', - 'specVersion' => 1 - ), - 'faults_interop' => array( - 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', - 'specVersion' => 20010516 - ), - 'system.multicall' => array( - 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', - 'specVersion' => 1 - ), - 'introspection' => array( - 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html', - 'specVersion' => 1 - ) - ); -} - - +/** + * Dispatch the request and any parameters to the appropriate handler. + * + * @param $xmlrpc_server + * @param $methodname + * The external XML-RPC method name, e.g. 'system.methodHelp' + * @param $args + * Array containing any parameters that were sent along with the request. + */ function xmlrpc_server_call($xmlrpc_server, $methodname, $args) { - // Make sure it's in an array + // Make sure parameters are in an array if ($args && !is_array($args)) { $args = array($args); } - // Over-rides default call method, adds signature check + // Has this method been mapped to a Drupal function by us or by modules? if (!isset($xmlrpc_server->callbacks[$methodname])) { - return xmlrpc_error(-32601, t('server error. requested method %methodname not specified.',array("%methodname" => $xmlrpc_server->message->methodname))); + return xmlrpc_error(-32601, t('Server error. Requested method %methodname not specified.', array("%methodname" => $xmlrpc_server->message->methodname))); } $method = $xmlrpc_server->callbacks[$methodname]; $signature = $xmlrpc_server->signatures[$methodname]; - $ok = true; + // If the method has a signature, validate the request against the signature if (is_array($signature)) { + $ok = true; $return_type = array_shift($signature); // Check the number of arguments if (count($args) != count($signature)) { - return xmlrpc_error(-32602, t('server error. wrong number of method parameters')); + return xmlrpc_error(-32602, t('Server error. Wrong number of method parameters.')); } // Check the argument types foreach ($signature as $key => $type) { @@ -218,74 +197,122 @@ function xmlrpc_server_call($xmlrpc_server, $methodname, $args) { break; } if (!$ok) { - return xmlrpc_error(-32602, t('server error. invalid method parameters')); + return xmlrpc_error(-32602, t('Server error. Invalid method parameters.')); } } } - // It passed the test - run the "real" method call - if (!isset($xmlrpc_server->callbacks[$methodname])) { - return xmlrpc_error(-32601, t('server error. requested method %methodname does not exist.',array("%methodname" => $methodname))); - } - - $method = $xmlrpc_server->callbacks[$methodname]; - // Perform the callback and send the response -/* + /* if (count($args) == 1) { // If only one parameter just send that instead of the whole array $args = $args[0]; } -*/ + */ if (!function_exists($method)) { - return xmlrpc_error(-32601, t('server error. requested function %method does not exist.', array("%method" => $method))); + return xmlrpc_error(-32601, t('Server error. Requested function %method does not exist.', array("%method" => $method))); } - // Call the function + // Call the mapped function return call_user_func_array($method, $args); } -function xmlrpc_server_method_signature($xmlrpc_server, $methodname) { +function xmlrpc_server_multicall($methodcalls) { + // See http://www.xmlrpc.com/discuss/msgReader$1208 + $return = array(); + $xmlrpc_server = xmlrpc_server_get(); + foreach ($methodcalls as $call) { + $ok = true; + if (!isset($call['methodName']) || !isset($call['params'])) { + $result = xmlrpc_error(3, t('Invalid syntax for system.multicall.')); + $ok = false; + } + $method = $call['methodName']; + $params = $call['params']; + if ($method == 'system.multicall') { + $result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden.')); + } + elseif ($ok) { + $result = xmlrpc_server_call($xmlrpc_server, $method, $params); + } + if ($result->is_error) { + $return[] = array( + 'faultCode' => $result->code, + 'faultString' => $result->message + ); + } + else { + $return[] = $result; + } + } + return $return; +} + + +/** + * XML-RPC method system.listMethods maps to this function. + */ +function xmlrpc_server_list_methods() { + $xmlrpc_server = xmlrpc_server_get(); + return array_keys($xmlrpc_server->callbacks); +} + +/** + * XML-RPC method system.getCapabilities maps to this function. + * See http://groups.yahoo.com/group/xml-rpc/message/2897 + */ +function xmlrpc_server_get_capabilities() { + return array( + 'xmlrpc' => array( + 'specUrl' => 'http://www.xmlrpc.com/spec', + 'specVersion' => 1 + ), + 'faults_interop' => array( + 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', + 'specVersion' => 20010516 + ), + 'system.multicall' => array( + 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', + 'specVersion' => 1 + ), + 'introspection' => array( + 'specUrl' => 'http://scripts.incutio.com/xmlrpc/introspection.html', + 'specVersion' => 1 + ) + ); +} + +/** + * XML-RPC method system.methodSignature maps to this function. + * + * @param $methodname + * Name of method for which we return a method signature. + * @return array + * An array of types representing the method signature of the + * function that the methodname maps to. The methodSignature of + * this function is 'array', 'string' because it takes an array + * and returns a string. + */ +function xmlrpc_server_method_signature($methodname) { + $xmlrpc_server = xmlrpc_server_get(); if (!isset($xmlrpc_server->callbacks[$methodname])) { - return xmlrpc_error(-32601, t('server error. requested method %methodname not specified.', array("%methodname" => $methodname))); + return xmlrpc_error(-32601, t('Server error. Requested method %methodname not specified.', array("%methodname" => $methodname))); } - if (!is_array($xmlrpc_server->signature[$methodname])) { - return xmlrpc_error(-32601, t('server error. requested method %methodname signature not specified.', array("%methodname" => $methodname))); + if (!is_array($xmlrpc_server->signatures[$methodname])) { + return xmlrpc_error(-32601, t('Server error. Requested method %methodname signature not specified.', array("%methodname" => $methodname))); } - // We should be returning an array of types + // We array of types $return = array(); foreach ($xmlrpc_server->signatures[$methodname] as $type) { - switch ($type) { - case 'string': - $return[] = 'string'; - break; - case 'int': - case 'i4': - $return[] = 42; - break; - case 'double': - $return[] = 3.1415; - break; - case 'dateTime.iso8601': - $return[] = xmlrpc_date(time()); - break; - case 'boolean': - $return[] = true; - break; - case 'base64': - $return[] =xmlrpc_base64('base64'); - break; - case 'array': - $return[] = array('array'); - break; - case 'struct': - $return[] = array('struct' => 'struct'); - break; - } + $return[] = $type; } return $return; } +/** + * XML-RPC method system.methodHelp maps to this function. + * + * @param $method + * Name of method for which we return a help string. + */ function xmlrpc_server_method_help($method) { $xmlrpc_server = xmlrpc_server_get(); return $xmlrpc_server->help[$method]; -} - - +} \ No newline at end of file -- cgit v1.2.3