diff --git a/core/includes/common.inc b/core/includes/common.inc index 36ece809e6d..1db7699c291 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -7400,39 +7400,6 @@ function drupal_check_incompatibility($v, $current_version) { } } -/** - * Performs one or more XML-RPC request(s). - * - * Usage example: - * @code - * $result = xmlrpc('http://example.com/xmlrpc.php', array( - * 'service.methodName' => array($parameter, $second, $third), - * )); - * @endcode - * - * @param $url - * An absolute URL of the XML-RPC endpoint. - * @param $args - * An associative array whose keys are the methods to call and whose values - * are the arguments to pass to the respective method. If multiple methods - * are specified, a system.multicall is performed. - * @param $options - * (optional) An array of options to pass along to drupal_http_request(). - * - * @return - * For one request: - * Either the return value of the method on success, or FALSE. - * If FALSE is returned, see xmlrpc_errno() and xmlrpc_error_msg(). - * For multiple requests: - * An array of results. Each result will either be the result - * returned by the method called, or an xmlrpc_error object if the call - * failed. See xmlrpc_error(). - */ -function xmlrpc($url, $args, $options = array()) { - require_once DRUPAL_ROOT . '/core/includes/xmlrpc.inc'; - return _xmlrpc($url, $args, $options); -} - /** * Retrieves a list of all available archivers. * diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index ed5b7a058ef..42b5737c5da 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -1859,84 +1859,6 @@ function hook_custom_theme() { } } -/** - * Register XML-RPC callbacks. - * - * This hook lets a module register callback functions to be called when - * particular XML-RPC methods are invoked by a client. - * - * @return - * An array which maps XML-RPC methods to Drupal functions. Each array - * element is either a pair of method => function or an array with four - * entries: - * - The XML-RPC method name (for example, module.function). - * - The Drupal callback function (for example, module_function). - * - The method signature is an array of XML-RPC types. The first element - * of this array is the type of return value and then you should write a - * list of the types of the parameters. XML-RPC types are the following - * (See the types at http://www.xmlrpc.com/spec): - * - "boolean": 0 (false) or 1 (true). - * - "double": a floating point number (for example, -12.214). - * - "int": a integer number (for example, -12). - * - "array": an array without keys (for example, array(1, 2, 3)). - * - "struct": an associative array or an object (for example, - * array('one' => 1, 'two' => 2)). - * - "date": when you return a date, then you may either return a - * timestamp (time(), mktime() etc.) or an ISO8601 timestamp. When - * date is specified as an input parameter, then you get an object, - * which is described in the function xmlrpc_date - * - "base64": a string containing binary data, automatically - * encoded/decoded automatically. - * - "string": anything else, typically a string. - * - A descriptive help string, enclosed in a t() function for translation - * purposes. - * Both forms are shown in the example. - */ -function hook_xmlrpc() { - return array( - 'drupal.login' => 'drupal_login', - array( - 'drupal.site.ping', - 'drupal_directory_ping', - array('boolean', 'string', 'string', 'string', 'string', 'string'), - t('Handling ping request')) - ); -} - -/** - * Alters the definition of XML-RPC methods before they are called. - * - * 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. - * - * 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 - * An asssociative array of method callback definitions, as returned from - * hook_xmlrpc() implementations. - * - * @see hook_xmlrpc() - * @see xmlrpc_server() - */ -function hook_xmlrpc_alter(&$methods) { - // Directly change a simple method. - $methods['drupal.login'] = 'mymodule_login'; - - // 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'; - } - } -} - /** * Log an event message. * diff --git a/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcBasicTest.php b/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcBasicTest.php new file mode 100644 index 00000000000..7e949857c1e --- /dev/null +++ b/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcBasicTest.php @@ -0,0 +1,94 @@ + 'XML-RPC basic', + 'description' => 'Perform basic XML-RPC tests that do not require additional callbacks.', + 'group' => 'XML-RPC', + ); + } + + public function setUp() { + parent::setUp('xmlrpc'); + } + + /** + * Ensure that a basic XML-RPC call with no parameters works. + */ + protected function testListMethods() { + // Minimum list of methods that should be included. + $minimum = array( + 'system.multicall', + 'system.methodSignature', + 'system.getCapabilities', + 'system.listMethods', + 'system.methodHelp', + ); + + // Invoke XML-RPC call to get list of methods. + $url = url('xmlrpc.php', array('absolute' => TRUE)); + $methods = xmlrpc($url, array('system.listMethods' => array())); + + // Ensure that the minimum methods were found. + $count = 0; + foreach ($methods as $method) { + if (in_array($method, $minimum)) { + $count++; + } + } + + $this->assertEqual($count, count($minimum), 'system.listMethods returned at least the minimum listing'); + } + + /** + * Ensure that system.methodSignature returns an array of signatures. + */ + protected function testMethodSignature() { + $url = url('xmlrpc.php', array('absolute' => TRUE)); + $signature = xmlrpc($url, array('system.methodSignature' => array('system.listMethods'))); + $this->assert(is_array($signature) && !empty($signature) && is_array($signature[0]), + t('system.methodSignature returns an array of signature arrays.')); + } + + /** + * Ensure that XML-RPC correctly handles invalid messages when parsing. + */ + protected function testInvalidMessageParsing() { + $invalid_messages = array( + array( + 'message' => xmlrpc_message(''), + 'assertion' => t('Empty message correctly rejected during parsing.'), + ), + array( + 'message' => xmlrpc_message(''), + 'assertion' => t('Empty message with XML declaration correctly rejected during parsing.'), + ), + array( + 'message' => xmlrpc_message('value'), + 'assertion' => t('Non-empty message without a valid message type is rejected during parsing.'), + ), + array( + 'message' => xmlrpc_message('value'), + 'assertion' => t('Non-empty malformed message is rejected during parsing.'), + ), + ); + + foreach ($invalid_messages as $assertion) { + $this->assertFalse(xmlrpc_message_parse($assertion['message']), $assertion['assertion']); + } + } +} diff --git a/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcMessagesTest.php b/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcMessagesTest.php new file mode 100644 index 00000000000..f4823c46366 --- /dev/null +++ b/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcMessagesTest.php @@ -0,0 +1,61 @@ + 'XML-RPC message and alteration', + 'description' => 'Test large messages and method alterations.', + 'group' => 'XML-RPC', + ); + } + + function setUp() { + parent::setUp('xmlrpc', 'xmlrpc_test'); + } + + /** + * Make sure that XML-RPC can transfer large messages. + */ + function testSizedMessages() { + $xml_url = url('xmlrpc.php', array('absolute' => TRUE)); + $sizes = array(8, 80, 160); + foreach ($sizes as $size) { + $xml_message_l = xmlrpc_test_message_sized_in_kb($size); + $xml_message_r = xmlrpc($xml_url, array('messages.messageSizedInKB' => array($size))); + + $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('xmlrpc.php', array('absolute' => TRUE)); + $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/core/modules/system/tests/xmlrpc.test b/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcValidatorTest.php similarity index 50% rename from core/modules/system/tests/xmlrpc.test rename to core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcValidatorTest.php index b5c07ca87d3..f48232890e1 100644 --- a/core/modules/system/tests/xmlrpc.test +++ b/core/modules/xmlrpc/lib/Drupal/xmlrpc/Tests/XmlRpcValidatorTest.php @@ -1,92 +1,18 @@ 'XML-RPC basic', - 'description' => 'Perform basic XML-RPC tests that do not require additional callbacks.', - 'group' => 'XML-RPC', - ); - } - - /** - * Ensure that a basic XML-RPC call with no parameters works. - */ - protected function testListMethods() { - global $base_url; - - // Minimum list of methods that should be included. - $minimum = array( - 'system.multicall', - 'system.methodSignature', - 'system.getCapabilities', - 'system.listMethods', - 'system.methodHelp', - ); - - // Invoke XML-RPC call to get list of methods. - $url = $base_url . '/core/xmlrpc.php'; - $methods = xmlrpc($url, array('system.listMethods' => array())); - - // Ensure that the minimum methods were found. - $count = 0; - foreach ($methods as $method) { - if (in_array($method, $minimum)) { - $count++; - } - } - - $this->assertEqual($count, count($minimum), 'system.listMethods returned at least the minimum listing'); - } - - /** - * Ensure that system.methodSignature returns an array of signatures. - */ - protected function testMethodSignature() { - global $base_url; - - $url = $base_url . '/core/xmlrpc.php'; - $signature = xmlrpc($url, array('system.methodSignature' => array('system.listMethods'))); - $this->assert(is_array($signature) && !empty($signature) && is_array($signature[0]), - t('system.methodSignature returns an array of signature arrays.')); - } - - /** - * Ensure that XML-RPC correctly handles invalid messages when parsing. - */ - protected function testInvalidMessageParsing() { - $invalid_messages = array( - array( - 'message' => xmlrpc_message(''), - 'assertion' => t('Empty message correctly rejected during parsing.'), - ), - array( - 'message' => xmlrpc_message(''), - 'assertion' => t('Empty message with XML declaration correctly rejected during parsing.'), - ), - array( - 'message' => xmlrpc_message('value'), - 'assertion' => t('Non-empty message without a valid message type is rejected during parsing.'), - ), - array( - 'message' => xmlrpc_message('value'), - 'assertion' => t('Non-empty malformed message is rejected during parsing.'), - ), - ); - - foreach ($invalid_messages as $assertion) { - $this->assertFalse(xmlrpc_message_parse($assertion['message']), $assertion['assertion']); - } - } -} - -class XMLRPCValidator1IncTestCase extends WebTestBase { +class XmlRpcValidatorTest extends WebTestBase { public static function getInfo() { return array( 'name' => 'XML-RPC validator', @@ -96,15 +22,14 @@ class XMLRPCValidator1IncTestCase extends WebTestBase { } function setUp() { - parent::setUp('xmlrpc_test'); + parent::setUp('xmlrpc', 'xmlrpc_test'); } /** * Run validator1 tests. */ - function testValidator1() { - global $base_url; - $xml_url = $base_url . '/core/xmlrpc.php'; + function testValidator() { + $xml_url = url('xmlrpc.php', array('absolute' => TRUE)); srand(); mt_srand(); @@ -200,55 +125,3 @@ class XMLRPCValidator1IncTestCase extends WebTestBase { $this->assertEqual($a_l_res, $a_r_res); } } - -class XMLRPCMessagesTestCase extends WebTestBase { - public static function getInfo() { - return array( - 'name' => 'XML-RPC message and alteration', - 'description' => 'Test large messages and method alterations.', - 'group' => 'XML-RPC', - ); - } - - function setUp() { - parent::setUp('xmlrpc_test'); - } - - /** - * Make sure that XML-RPC can transfer large messages. - */ - function testSizedMessages() { - global $base_url; - - $xml_url = $base_url . '/core/xmlrpc.php'; - $sizes = array(8, 80, 160); - foreach ($sizes as $size) { - $xml_message_l = xmlrpc_test_message_sized_in_kb($size); - $xml_message_r = xmlrpc($xml_url, array('messages.messageSizedInKB' => array($size))); - - $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() { - global $base_url; - - // Ensure xmlrpc_test_xmlrpc_alter() is disabled and retrieve regular list of methods. - variable_set('xmlrpc_test_xmlrpc_alter', FALSE); - $url = $base_url . '/core/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/core/modules/system/tests/modules/xmlrpc_test/xmlrpc_test.info b/core/modules/xmlrpc/tests/modules/xmlrpc_test/xmlrpc_test.info similarity index 100% rename from core/modules/system/tests/modules/xmlrpc_test/xmlrpc_test.info rename to core/modules/xmlrpc/tests/modules/xmlrpc_test/xmlrpc_test.info diff --git a/core/modules/system/tests/modules/xmlrpc_test/xmlrpc_test.module b/core/modules/xmlrpc/tests/modules/xmlrpc_test/xmlrpc_test.module similarity index 100% rename from core/modules/system/tests/modules/xmlrpc_test/xmlrpc_test.module rename to core/modules/xmlrpc/tests/modules/xmlrpc_test/xmlrpc_test.module diff --git a/core/modules/xmlrpc/xmlrpc.api.php b/core/modules/xmlrpc/xmlrpc.api.php new file mode 100644 index 00000000000..fccc6a76a96 --- /dev/null +++ b/core/modules/xmlrpc/xmlrpc.api.php @@ -0,0 +1,84 @@ + function or an array with four + * entries: + * - The XML-RPC method name (for example, module.function). + * - The Drupal callback function (for example, module_function). + * - The method signature is an array of XML-RPC types. The first element + * of this array is the type of return value and then you should write a + * list of the types of the parameters. XML-RPC types are the following + * (See the types at http://www.xmlrpc.com/spec): + * - "boolean": 0 (false) or 1 (true). + * - "double": a floating point number (for example, -12.214). + * - "int": a integer number (for example, -12). + * - "array": an array without keys (for example, array(1, 2, 3)). + * - "struct": an associative array or an object (for example, + * array('one' => 1, 'two' => 2)). + * - "date": when you return a date, then you may either return a + * timestamp (time(), mktime() etc.) or an ISO8601 timestamp. When + * date is specified as an input parameter, then you get an object, + * which is described in the function xmlrpc_date + * - "base64": a string containing binary data, automatically + * encoded/decoded automatically. + * - "string": anything else, typically a string. + * - A descriptive help string, enclosed in a t() function for translation + * purposes. + * Both forms are shown in the example. + */ +function hook_xmlrpc() { + return array( + 'drupal.login' => 'drupal_login', + array( + 'drupal.site.ping', + 'drupal_directory_ping', + array('boolean', 'string', 'string', 'string', 'string', 'string'), + t('Handling ping request')) + ); +} + +/** + * Alters the definition of XML-RPC methods before they are called. + * + * 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. + * + * 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 + * An asssociative array of method callback definitions, as returned from + * hook_xmlrpc() implementations. + * + * @see hook_xmlrpc() + * @see xmlrpc_server() + */ +function hook_xmlrpc_alter(&$methods) { + // Directly change a simple method. + $methods['drupal.login'] = 'mymodule_login'; + + // 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/core/includes/xmlrpc.inc b/core/modules/xmlrpc/xmlrpc.inc similarity index 100% rename from core/includes/xmlrpc.inc rename to core/modules/xmlrpc/xmlrpc.inc diff --git a/core/modules/xmlrpc/xmlrpc.info b/core/modules/xmlrpc/xmlrpc.info new file mode 100644 index 00000000000..6e5f676bcd0 --- /dev/null +++ b/core/modules/xmlrpc/xmlrpc.info @@ -0,0 +1,5 @@ +name = XML-RPC +description = Provides XML-RPC functionality. +package = Core +version = VERSION +core = 8.x diff --git a/core/modules/xmlrpc/xmlrpc.module b/core/modules/xmlrpc/xmlrpc.module new file mode 100644 index 00000000000..f21b4871cb7 --- /dev/null +++ b/core/modules/xmlrpc/xmlrpc.module @@ -0,0 +1,68 @@ +' . t('The XML-RPC module gives external systems the opportunity to communicate with the site through the XML-RPC protocol. Pointing an XML-RPC client at xmlrpc.php allows this communication to take place. For more information, see the online handbook entry for XML-RPC API.', array( + '@xmlrpc' => url('xmlrpc.php', array('absolute' => TRUE)), + '@xmlrpcapi' => 'http://drupal.org/node/44895', + )) . '

'; + return $output; + } +} + +/** + * Implements hook_menu(). + */ +function xmlrpc_menu() { + $items['xmlrpc.php'] = array( + 'title' => 'XML-RPC', + 'page callback' => 'xmlrpc_server_page', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + 'file' => 'xmlrpc.server.inc', + ); + return $items; +} + +/** + * Performs one or more XML-RPC request(s). + * + * Usage example: + * @code + * $result = xmlrpc('http://example.com/xmlrpc.php', array( + * 'service.methodName' => array($parameter, $second, $third), + * )); + * @endcode + * + * @param $url + * An absolute URL of the XML-RPC endpoint. + * @param $args + * An associative array whose keys are the methods to call and whose values + * are the arguments to pass to the respective method. If multiple methods + * are specified, a system.multicall is performed. + * @param $options + * (optional) An array of options to pass along to drupal_http_request(). + * + * @return + * For one request: + * Either the return value of the method on success, or FALSE. + * If FALSE is returned, see xmlrpc_errno() and xmlrpc_error_msg(). + * For multiple requests: + * An array of results. Each result will either be the result + * returned by the method called, or an xmlrpc_error object if the call + * failed. See xmlrpc_error(). + */ +function xmlrpc($url, $args, $options = array()) { + module_load_include('inc', 'xmlrpc'); + return _xmlrpc($url, $args, $options); +} diff --git a/core/includes/xmlrpcs.inc b/core/modules/xmlrpc/xmlrpc.server.inc similarity index 98% rename from core/includes/xmlrpcs.inc rename to core/modules/xmlrpc/xmlrpc.server.inc index 118f652d233..e1c160bfec5 100644 --- a/core/includes/xmlrpcs.inc +++ b/core/modules/xmlrpc/xmlrpc.server.inc @@ -2,9 +2,17 @@ /** * @file - * Provides API for defining and handling XML-RPC requests. + * Page callback file for the xmlrpc module. */ +/** + * Process an XML-RPC request. + */ +function xmlrpc_server_page() { + module_load_include('inc', 'xmlrpc'); + xmlrpc_server(module_invoke_all('xmlrpc')); +} + /** * Invokes XML-RPC methods on this server. * diff --git a/core/xmlrpc.php b/core/xmlrpc.php deleted file mode 100644 index 562aa81beda..00000000000 --- a/core/xmlrpc.php +++ /dev/null @@ -1,21 +0,0 @@ -