diff --git a/core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php b/core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php deleted file mode 100644 index ac26bd7..0000000 --- a/core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php +++ /dev/null @@ -1,77 +0,0 @@ - "Unit tests", - 'description' => 'Test update funcionality unrelated to the database.', - 'group' => 'Update', - ); - } - - function setUp() { - parent::setUp(); - module_load_include('inc', 'update', 'update.fetch'); - } - - /** - * Tests that _update_build_fetch_url() builds the URL correctly. - */ - function testUpdateBuildFetchUrl() { - //first test that we didn't break the trivial case - $project['name'] = 'update_test'; - $project['project_type'] = ''; - $project['info']['version'] = ''; - $project['info']['project status url'] = 'http://www.example.com'; - $project['includes'] = array('module1' => 'Module 1', 'module2' => 'Module 2'); - $site_key = ''; - $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; - $url = _update_build_fetch_url($project, $site_key); - $this->assertEqual($url, $expected, "'$url' when no site_key provided should be '$expected'."); - - //For disabled projects it shouldn't add the site key either. - $site_key = 'site_key'; - $project['project_type'] = 'disabled'; - $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; - $url = _update_build_fetch_url($project, $site_key); - $this->assertEqual($url, $expected, "'$url' should be '$expected' for disabled projects."); - - //for enabled projects, adding the site key - $project['project_type'] = ''; - $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; - $expected .= '?site_key=site_key'; - $expected .= '&list=' . rawurlencode('module1,module2'); - $url = _update_build_fetch_url($project, $site_key); - $this->assertEqual($url, $expected, "When site_key provided, '$url' should be '$expected'."); - - // http://drupal.org/node/1481156 test incorrect logic when URL contains - // a question mark. - $project['info']['project status url'] = 'http://www.example.com/?project='; - $expected = 'http://www.example.com/?project=/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; - $expected .= '&site_key=site_key'; - $expected .= '&list=' . rawurlencode('module1,module2'); - $url = _update_build_fetch_url($project, $site_key); - $this->assertEqual($url, $expected, "When ? is present, '$url' should be '$expected'."); - - } -} diff --git a/core/modules/update/lib/Drupal/update/UpdateFetcher.php b/core/modules/update/lib/Drupal/update/UpdateFetcher.php new file mode 100644 index 0000000..f6177a1 --- /dev/null +++ b/core/modules/update/lib/Drupal/update/UpdateFetcher.php @@ -0,0 +1,149 @@ +fetchUrl = $config_factory->get('update.settings')->get('fetch.url'); + $this->httpClient = $http_client; + } + + /** + * Retrieves the project information. + * + * @param array $project + * The array of project information from update_get_projects(). + * @param string $site_key + * (optional) The anonymous site key hash. Defaults to an empty string. + * + * @return string + * The project information fetched as string. Empty string upon failure. + */ + public function fetchProjectData(array $project, $site_key = '') { + $url = $this->buildFetchUrl($project, $site_key); + $data = ''; + try { + $data = $this->httpClient + ->get($url, array('Accept' => 'text/xml')) + ->send() + ->getBody(TRUE); + } + catch (RequestException $exception) { + watchdog_exception('update', $exception); + } + return $data; + } + + /** + * Generates the URL to fetch information about project updates. + * + * This figures out the right URL to use, based on the project's .info.yml file + * and the global defaults. Appends optional query arguments when the site is + * configured to report usage stats. + * + * @param array $project + * The array of project information from update_get_projects(). + * @param string $site_key + * (optional) The anonymous site key hash. Defaults to an empty string. + * + * @return string + * The URL for fetching information about updates to the specified project. + * + * @see update_fetch_data() + * @see _update_process_fetch_task() + * @see update_get_projects() + */ + public function buildFetchUrl(array $project, $site_key = '') { + $name = $project['name']; + $url = $this->getFetchBaseUrl($project); + $url .= '/' . $name . '/' . DRUPAL_CORE_COMPATIBILITY; + + // Only append usage infomation if we have a site key and the project is + // enabled. We do not want to record usage statistics for disabled projects. + if (!empty($site_key) && (strpos($project['project_type'], 'disabled') === FALSE)) { + // Append the site key. + $url .= (strpos($url, '?') !== FALSE) ? '&' : '?'; + $url .= 'site_key='; + $url .= rawurlencode($site_key); + + // Append the version. + if (!empty($project['info']['version'])) { + $url .= '&version='; + $url .= rawurlencode($project['info']['version']); + } + + // Append the list of modules or themes enabled. + $list = array_keys($project['includes']); + $url .= '&list='; + $url .= rawurlencode(implode(',', $list)); + } + return $url; + } + + /** + * Returns the base of the URL to fetch available update data for a project. + * + * @param array $project + * The array of project information from update_get_projects(). + * + * @return string + * The base of the URL used for fetching available update data. This does + * not include the path elements to specify a particular project, version, + * site_key, etc. + * + * @see \Drupal\update\UpdateFetcher::getFetchBaseUrl() + */ + public function getFetchBaseUrl($project) { + if (isset($project['info']['project status url'])) { + $url = $project['info']['project status url']; + } + else { + $url = $this->fetchUrl; + if (empty($url)) { + $url = static::UPDATE_DEFAULT_URL; + } + } + return $url; + } + +} diff --git a/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php b/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php new file mode 100644 index 0000000..e43a3ae --- /dev/null +++ b/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php @@ -0,0 +1,114 @@ + 'Core update tests', + 'description' => 'Test update functionality unrelated to the database.', + 'group' => 'Update', + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + $config_factory = $this->getConfigFactoryStub(array('update.settings' => array('fetch_url' => 'http://www.example.com'))); + $this->updateFetcher = new UpdateFetcher($config_factory, $this->getMock('Guzzle\Http\Client')); + } + + /** + * Tests that buildFetchUrl() builds the URL correctly. + * + * @param array $project + * A keyed array of project information matching results from update_get_projects(). + * @param string $site_key + * A string to mimic an anonymous site key hash. + * @param string $expected + * The expected url returned from UpdateFetcher::buildFetchUrl() + * + * @dataProvider providerTestUpdateBuildFetchUrl + * + * @see \Drupal\update\UpdateFetcher::buildFetchUrl() + */ + public function testUpdateBuildFetchUrl(array $project, $site_key, $expected) { + $url = $this->updateFetcher->buildFetchUrl($project, $site_key); + $this->assertEquals($url, $expected); + } + + /** + * Provide test data for self::testUpdateBuildFetchUrl(). + * + * @return array + * An array of arrays, each containing: + * - 'project' - An array matching a project's .info file structure. + * - 'site_key' - An arbitrary site key. + * - 'expected' - The expected url from UpdateFetcher::buildFetchUrl(). + */ + public function providerTestUpdateBuildFetchUrl() { + $data = array(); + + // First test that we didn't break the trivial case. + $project['name'] = 'update_test'; + $project['project_type'] = ''; + $project['info']['version'] = ''; + $project['info']['project status url'] = 'http://www.example.com'; + $project['includes'] = array('module1' => 'Module 1', 'module2' => 'Module 2'); + $site_key = ''; + $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; + + $data[] = array($project, $site_key, $expected); + + // For disabled projects it shouldn't add the site key either. + $site_key = 'site_key'; + $project['project_type'] = 'disabled'; + $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; + + $data[] = array($project, $site_key, $expected); + + // For enabled projects, adding the site key + $project['project_type'] = ''; + $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; + $expected .= '?site_key=site_key'; + $expected .= '&list=' . rawurlencode('module1,module2'); + + $data[] = array($project, $site_key, $expected); + + // http://drupal.org/node/1481156 test incorrect logic when URL contains + // a question mark. + $project['info']['project status url'] = 'http://www.example.com/?project='; + $expected = 'http://www.example.com/?project=/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; + $expected .= '&site_key=site_key'; + $expected .= '&list=' . rawurlencode('module1,module2'); + + $data[] = array($project, $site_key, $expected); + + return $data; + } + +} diff --git a/core/modules/update/update.fetch.inc b/core/modules/update/update.fetch.inc index 13a1383..d52f66a 100644 --- a/core/modules/update/update.fetch.inc +++ b/core/modules/update/update.fetch.inc @@ -5,7 +5,6 @@ * Code required only when fetching information about available updates. */ -use Guzzle\Http\Exception\RequestException; use Drupal\Component\Utility\Crypt; /** @@ -147,20 +146,12 @@ function _update_process_fetch_task($project) { $success = FALSE; $available = array(); $site_key = Crypt::hmacBase64($base_url, drupal_get_private_key()); - $url = _update_build_fetch_url($project, $site_key); - $fetch_url_base = _update_get_fetch_url_base($project); + $update_fetcher = \Drupal::service('update_fetcher'); + $fetch_url_base = $update_fetcher->getFetchBaseUrl($project); $project_name = $project['name']; if (empty($fail[$fetch_url_base]) || $fail[$fetch_url_base] < $max_fetch_attempts) { - try { - $data = Drupal::httpClient() - ->get($url, array('Accept' => 'text/xml')) - ->send() - ->getBody(TRUE); - } - catch (RequestException $exception) { - watchdog_exception('update', $exception); - } + $data = $update_fetcher->fetchProjectData($project, $site_key); } if (!empty($data)) { @@ -274,58 +265,7 @@ function _update_create_fetch_task($project) { * @see _update_process_fetch_task() * @see update_get_projects() */ -function _update_build_fetch_url($project, $site_key = '') { - $name = $project['name']; - $url = _update_get_fetch_url_base($project); - $url .= '/' . $name . '/' . DRUPAL_CORE_COMPATIBILITY; - - // Only append usage infomation if we have a site key and the project is - // enabled. We do not want to record usage statistics for disabled projects. - if (!empty($site_key) && (strpos($project['project_type'], 'disabled') === FALSE)) { - // Append the site key. - $url .= (strpos($url, '?') !== FALSE) ? '&' : '?'; - $url .= 'site_key='; - $url .= rawurlencode($site_key); - // Append the version. - if (!empty($project['info']['version'])) { - $url .= '&version='; - $url .= rawurlencode($project['info']['version']); - } - - // Append the list of modules or themes enabled. - $list = array_keys($project['includes']); - $url .= '&list='; - $url .= rawurlencode(implode(',', $list)); - } - return $url; -} - -/** - * Returns the base of the URL to fetch available update data for a project. - * - * @param $project - * The array of project information from update_get_projects(). - * - * @return - * The base of the URL used for fetching available update data. This does - * not include the path elements to specify a particular project, version, - * site_key, etc. - * - * @see _update_build_fetch_url() - */ -function _update_get_fetch_url_base($project) { - if (isset($project['info']['project status url'])) { - $url = $project['info']['project status url']; - } - else { - $url = config('update.settings')->get('fetch.url'); - if (empty($url)) { - $url = UPDATE_DEFAULT_URL; - } - } - return $url; -} /** * Performs any notifications that should be done once cron fetches new data. diff --git a/core/modules/update/update.module b/core/modules/update/update.module index 83ba194..c2a7a71 100644 --- a/core/modules/update/update.module +++ b/core/modules/update/update.module @@ -11,11 +11,6 @@ * ability to install contributed modules and themes via an user interface. */ -/** - * URL to check for updates, if a given project doesn't define its own. - */ -const UPDATE_DEFAULT_URL = 'http://updates.drupal.org/release-history'; - // These are internally used constants for this code, do not modify. /** diff --git a/core/modules/update/update.services.yml b/core/modules/update/update.services.yml new file mode 100644 index 0000000..0c94a7a --- /dev/null +++ b/core/modules/update/update.services.yml @@ -0,0 +1,4 @@ +services: + update_fetcher: + class: Drupal\update\UpdateFetcher + arguments: ['@config.factory', '@http_default_client']