diff --git a/includes/xmlrpcs.inc b/includes/xmlrpcs.inc index 7fb4ca895e2b8b9d630b43e93e89a20f16a35907..fd5a40733f6f49f4b306b124818e2ef15ca81d60 100644 --- a/includes/xmlrpcs.inc +++ b/includes/xmlrpcs.inc @@ -45,7 +45,9 @@ function xmlrpc_server($callbacks) { // 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) { + $callbacks = array_merge($defaults, (array) $callbacks); + drupal_alter('xmlrpc', $callbacks); + foreach ($callbacks as $key => $callback) { // we could check for is_array($callback) if (is_int($key)) { $method = $callback[0]; diff --git a/modules/simpletest/tests/xmlrpc.test b/modules/simpletest/tests/xmlrpc.test index 7aad2be11a06e29ab84a0787386d91f3c0d30647..5069fe2467c5c1def15db08b4a7373afe31e393e 100644 --- a/modules/simpletest/tests/xmlrpc.test +++ b/modules/simpletest/tests/xmlrpc.test @@ -188,8 +188,8 @@ class XMLRPCValidator1IncTestCase extends DrupalWebTestCase { class XMLRPCMessagesTestCase extends DrupalWebTestCase { public static function getInfo() { return array( - 'name' => 'XML-RPC message', - 'description' => 'Test large messages.', + 'name' => 'XML-RPC message and alteration', + 'description' => 'Test large messages and method alterations.', 'group' => 'XML-RPC', ); } @@ -211,4 +211,25 @@ class XMLRPCMessagesTestCase extends DrupalWebTestCase { $this->assertEqual($xml_message_l, $xml_message_r, t('XML-RPC messages.messageSizedInKB of %s Kb size received', array('%s' => $size))); } } + + /** + * Ensure that hook_xmlrpc_alter() can hide even builtin methods. + */ + protected function testAlterListMethods() { + + // Ensure xmlrpc_test_xmlrpc_alter() is disabled and retrieve regular list of methods. + variable_set('xmlrpc_test_xmlrpc_alter', FALSE); + $url = url(NULL, array('absolute' => TRUE)) . 'xmlrpc.php'; + $methods1 = xmlrpc($url, array('system.listMethods' => array())); + + // Enable the alter hook and retrieve the list of methods again. + variable_set('xmlrpc_test_xmlrpc_alter', TRUE); + $methods2 = xmlrpc($url, array('system.listMethods' => array())); + + $diff = array_diff($methods1, $methods2); + $this->assertTrue(is_array($diff) && !empty($diff), t('Method list is altered by hook_xmlrpc_alter')); + $removed = reset($diff); + $this->assertEqual($removed, 'system.methodSignature', t('Hiding builting system.methodSignature with hook_xmlrpc_alter works')); + } + } diff --git a/modules/simpletest/tests/xmlrpc_test.module b/modules/simpletest/tests/xmlrpc_test.module index 9f06f48ae73a3b49fccd17528b7714a469b3044f..f52afe325ee58e11fa5d800e6382f1aead9785d5 100644 --- a/modules/simpletest/tests/xmlrpc_test.module +++ b/modules/simpletest/tests/xmlrpc_test.module @@ -63,6 +63,29 @@ function xmlrpc_test_xmlrpc() { ); } +/** + * Implements hook_xmlrpc_alter(). + * + * Hide (or not) the system.methodSignature() service depending on a variable. + */ +function xmlrpc_test_xmlrpc_alter(&$services) { + if (variable_get('xmlrpc_test_xmlrpc_alter', FALSE)) { + $remove = NULL; + foreach ($services as $key => $value) { + if (!is_array($value)) { + continue; + } + if ($value[0] == 'system.methodSignature') { + $remove = $key; + break; + } + } + if (isset($remove)) { + unset($services[$remove]); + } + } +} + /** * Created a message of the desired size in KB. * diff --git a/modules/system/system.api.php b/modules/system/system.api.php index c497871e5be2957723b18ddc038f999545b43b32..2e420dc6f089eb915fc9cb6c65fbb3a5b731036c 100644 --- a/modules/system/system.api.php +++ b/modules/system/system.api.php @@ -1954,37 +1954,33 @@ function hook_xmlrpc() { } /** - * Alter the definition of XML-RPC methods before they are called. + * Alters the definition of XML-RPC methods before they are called. * - * This hook lets at module modify the callback definition for already - * declared XML-RPC methods, when they are being invoked by a client. + * This hook allows modules to modify the callback definition of declared + * XML-RPC methods, right before they are invoked by a client. Methods may be + * added, or existing methods may be altered. * - * This hook is invoked by xmlrpc.php. The method definitions are - * passed in by reference. Each element of the $methods array is one - * callback definition returned by a module from hook_xmlrpc. Additional - * methods may be added, or existing items altered. - * - * Modules implementing this hook must take care of the fact that - * hook_xmlrpc allows two distinct and incompatible formats for callback - * definition, so module must be prepared to handle either format for - * each callback being altered. + * Note that hook_xmlrpc() supports two distinct and incompatible formats to + * define a callback, so care must be taken when altering other methods. * * @param $methods - * Associative array of method callback definitions returned from - * hook_xmlrpc. + * An asssociative array of method callback definitions, as returned from + * hook_xmlrpc() implementations. * * @see hook_xmlrpc() + * @see xmlrpc_server() */ function hook_xmlrpc_alter(&$methods) { - - // Direct update for methods defined the simple way + // Directly change a simple method. $methods['drupal.login'] = 'mymodule_login'; - // Lookup update for methods defined the complex way + // Alter complex definitions. foreach ($methods as $key => &$method) { + // Skip simple method definitions. if (!is_int($key)) { continue; } + // Perform the wanted manipulation. if ($method[0] == 'drupal.site.ping') { $method[1] = 'mymodule_directory_ping'; } diff --git a/xmlrpc.php b/xmlrpc.php index 5787f5b195a1074b97822d8a4e1aabad54e56582..4b6b1153fcef211b6de2243ff71d8b472970c6e7 100644 --- a/xmlrpc.php +++ b/xmlrpc.php @@ -16,6 +16,4 @@ include_once DRUPAL_ROOT . '/includes/xmlrpc.inc'; include_once DRUPAL_ROOT . '/includes/xmlrpcs.inc'; -$services = module_invoke_all('xmlrpc'); -drupal_alter('xmlrpc', $services); -xmlrpc_server($services); +xmlrpc_server(module_invoke_all('xmlrpc'));