Issue #1033818 by catch, Rob Loach, amateescu, sun: Move xmlrpc includes into xmlrpc.module.

8.0.x
catch 2012-06-12 11:18:51 +09:00
parent b305521ab0
commit 2f7f9c3543
13 changed files with 333 additions and 272 deletions

View File

@ -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.
*

View File

@ -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.
*

View File

@ -0,0 +1,94 @@
<?php
/**
* @file
* Definition of Drupal\xmlrpc\Tests\XmlRpcBasicTest.
*/
namespace Drupal\xmlrpc\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Perform basic XML-RPC tests that do not require addition callbacks.
*/
class XmlRpcBasicTest extends WebTestBase {
public static function getInfo() {
return array(
'name' => '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('<?xml version="1.0" encoding="ISO-8859-1"?>'),
'assertion' => t('Empty message with XML declaration correctly rejected during parsing.'),
),
array(
'message' => xmlrpc_message('<?xml version="1.0"?><params><param><value><string>value</string></value></param></params>'),
'assertion' => t('Non-empty message without a valid message type is rejected during parsing.'),
),
array(
'message' => xmlrpc_message('<methodResponse><params><param><value><string>value</string></value></param></methodResponse>'),
'assertion' => t('Non-empty malformed message is rejected during parsing.'),
),
);
foreach ($invalid_messages as $assertion) {
$this->assertFalse(xmlrpc_message_parse($assertion['message']), $assertion['assertion']);
}
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* @file
* Definition of Drupal\xmlrpc\Tests\XmlRpcMessagesTest.
*/
namespace Drupal\xmlrpc\Tests;
use Drupal\simpletest\WebTestBase;
/**
* XML-RPC message and alteration tests.
*/
class XmlRpcMessagesTest 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', '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'));
}
}

View File

@ -1,92 +1,18 @@
<?php
/**
* @file
* Definition of Drupal\xmlrpc\Tests\XmlRpcValidatorTest.
*/
namespace Drupal\xmlrpc\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Perform basic XML-RPC tests that do not require addition callbacks.
* XML-RPC validator1 specification.
*/
class XMLRPCBasicTestCase extends WebTestBase {
public static function getInfo() {
return array(
'name' => '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('<?xml version="1.0" encoding="ISO-8859-1"?>'),
'assertion' => t('Empty message with XML declaration correctly rejected during parsing.'),
),
array(
'message' => xmlrpc_message('<?xml version="1.0"?><params><param><value><string>value</string></value></param></params>'),
'assertion' => t('Non-empty message without a valid message type is rejected during parsing.'),
),
array(
'message' => xmlrpc_message('<methodResponse><params><param><value><string>value</string></value></param></methodResponse>'),
'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'));
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* @file
* Hooks provided by the XML-RPC module.
*/
/**
* 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';
}
}
}

View File

@ -0,0 +1,5 @@
name = XML-RPC
description = Provides XML-RPC functionality.
package = Core
version = VERSION
core = 8.x

View File

@ -0,0 +1,68 @@
<?php
/**
* @file
* Enables XML-RPC functionality.
*/
/**
* Implements hook_help().
*/
function xmlrpc_help($path, $args) {
switch ($path) {
case 'admin/help#xmlrpc':
$output = '';
$output .= '<p>' . 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 <a href="@xmlrpc">xmlrpc.php</a> allows this communication to take place. For more information, see the online handbook entry for <a href="@xmlrpcapi">XML-RPC API</a>.', array(
'@xmlrpc' => url('xmlrpc.php', array('absolute' => TRUE)),
'@xmlrpcapi' => 'http://drupal.org/node/44895',
)) . '</p>';
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);
}

View File

@ -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.
*

View File

@ -1,21 +0,0 @@
<?php
/**
* @file
* PHP page for handling incoming XML-RPC requests from clients.
*/
// Change the directory to the Drupal root.
chdir('..');
/**
* Root directory of Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
include_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
include_once DRUPAL_ROOT . '/core/includes/xmlrpc.inc';
include_once DRUPAL_ROOT . '/core/includes/xmlrpcs.inc';
xmlrpc_server(module_invoke_all('xmlrpc'));