diff -u b/core/modules/media/src/OEmbed.php b/core/modules/media/src/OEmbed.php --- b/core/modules/media/src/OEmbed.php +++ b/core/modules/media/src/OEmbed.php @@ -94,13 +94,15 @@ public function isProvidedUrl($url, array $providers_limit = []) { $providers = $this->oEmbedProviderDiscovery->getProviders(); if (!empty($providers_limit)) { - $providers = array_intersect_key($providers, $providers_limit); + $providers = array_intersect_key($providers, array_fill_keys($providers_limit, '')); } + // Check url against every scheme of every endpoint of every provider. foreach ($providers as $provider_name => $provider_info) { if (!empty($provider_info['endpoints'])) { foreach ($provider_info['endpoints'] as $endpoint) { if (!empty($endpoint['schemes'])) { foreach ($endpoint['schemes'] as $scheme) { + // Convert scheme into a valid RegEx pattern. $regexp = str_replace(['.', '*'], ['\.', '.*'], $scheme); if (preg_match("|$regexp|", $url)) { return TRUE; @@ -142,7 +144,7 @@ throw new OEmbedResourceException("Remote oEmbed resource returned status code $statusCode."); } - $content = $response->getBody()->getContents(); + $content = (string) $response->getBody(); $xpath = new \DOMXpath(Html::load($content)); $resultJson = $xpath->query("//link[@type='application/json+oembed']"); @@ -206,7 +208,7 @@ } $format = $response->getHeader('Content-Type'); - $content = $response->getBody()->getContents(); + $content = (string) $response->getBody(); $data = ''; if ($format[0] == 'application/json') { $data = Json::decode($content); diff -u b/core/modules/media/src/OEmbedInterface.php b/core/modules/media/src/OEmbedInterface.php --- b/core/modules/media/src/OEmbedInterface.php +++ b/core/modules/media/src/OEmbedInterface.php @@ -14,9 +14,8 @@ * The URL to be tested. * @param array $allowed_providers * (optional) A list of providers to restrict to. If present, this needs to - * be an array where keys are the provider names (codified with bin2hex()), - * and the values are irrelevant. If ommitted, all providers will be - * considered. + * be an array where the values are the provider names + * (codified with bin2hex()). If omitted, all providers will be considered. * * @return bool * If a match was found, will return TRUE, otherwise FALSE. diff -u b/core/modules/media/src/OEmbedProviderDiscovery.php b/core/modules/media/src/OEmbedProviderDiscovery.php --- b/core/modules/media/src/OEmbedProviderDiscovery.php +++ b/core/modules/media/src/OEmbedProviderDiscovery.php @@ -94,23 +94,35 @@ throw new OEmbedProviderException('Could not retrieve the providers list from the remote oEmbed database.'); } - $providers = Json::decode($response->getBody()->getContents()); + $providers = Json::decode((string) $response->getBody()); if (!is_array($providers) || empty($providers)) { $this->logger->error('Remote oEmbed providers database returned incorrect response content. Providers: @response', [ '@response' => json_encode($providers), ]); - throw new OEmbedProviderException('Remote oEmbed providers database returned empty list.', $providers); + throw new OEmbedProviderException('Remote oEmbed providers database returned empty list.', []); } \Drupal::moduleHandler()->alter('oembed_providers', $providers); - // Some provider names may contain dot chars ("."), which are not - // allowed in config keys. We store them in an array where keys are - // hex-converted names, in order to allow an easy conversion back to - // their original names when necessary. + // Some provider names, like "Wordpress.com" or "Getty Images", contain + // dot chars (".") or spaces (" "), which are not allowed in config keys. + // We store them in an array where keys are hex-converted names, in order + // to allow an easy conversion back to their original names when + // necessary. $keyed_providers = []; foreach ($providers as $provider) { + // TODO: Filter out providers without discovery and schemes until we + // know how to handle them. + $filter = TRUE; + foreach ($provider['endpoints'] as $endpoint) { + if (!empty($endpoint['discovery']) && !empty($endpoint['schemes'])) { + $filter = FALSE; + } + } + if ($filter) { + continue; + } $keyed_providers[bin2hex($provider['provider_name'])] = $provider; } diff -u b/core/modules/media/src/Plugin/Field/FieldFormatter/OEmbedFormatter.php b/core/modules/media/src/Plugin/Field/FieldFormatter/OEmbedFormatter.php --- b/core/modules/media/src/Plugin/Field/FieldFormatter/OEmbedFormatter.php +++ b/core/modules/media/src/Plugin/Field/FieldFormatter/OEmbedFormatter.php @@ -100,10 +100,2 @@ - /** - * {@inheritdoc} - */ - public static function isApplicable(FieldDefinitionInterface $field_definition) { - // This formatter is only available for fields attached to media items. - return ($field_definition->getTargetEntityTypeId() === 'media'); - } - } diff -u b/core/modules/media/src/Plugin/Validation/Constraint/OEmbedProviderConstraintValidator.php b/core/modules/media/src/Plugin/Validation/Constraint/OEmbedProviderConstraintValidator.php --- b/core/modules/media/src/Plugin/Validation/Constraint/OEmbedProviderConstraintValidator.php +++ b/core/modules/media/src/Plugin/Validation/Constraint/OEmbedProviderConstraintValidator.php @@ -59,15 +59,13 @@ * {@inheritdoc} */ public function validate($value, Constraint $constraint) { - // TODO check if resource belongs to an allowed provider. /** @var \Drupal\media\MediaInterface $media */ $media = $value->getEntity(); $source_config = $media->getSource()->getConfiguration(); if (!empty($source_config['allowed_providers'])) { - $allowed_providers = array_map('hex2bin', $source_config['allowed_providers']); $main_property = $value->getFieldDefinition()->getFieldStorageDefinition()->getMainPropertyName(); try { - if (!$this->oEmbed->isProvidedUrl($value->first()->get($main_property)->getString(), $allowed_providers)) { + if (!$this->oEmbed->isProvidedUrl($value->first()->get($main_property)->getString(), array_keys($source_config['allowed_providers']))) { $this->context->addViolation($constraint->message); } } diff -u b/core/modules/media/tests/src/Functional/OEmbedProviderDiscoveryTest.php b/core/modules/media/tests/src/Functional/OEmbedProviderDiscoveryTest.php --- b/core/modules/media/tests/src/Functional/OEmbedProviderDiscoveryTest.php +++ b/core/modules/media/tests/src/Functional/OEmbedProviderDiscoveryTest.php @@ -5,7 +5,9 @@ use Drupal\media\OEmbedProviderDiscovery; /** - * Tests Media. + * Tests the oEmbed provider discovery. + * + * @covers \Drupal\media\OEmbedProviderDiscovery * * @group media */ only in patch2: unchanged: --- /dev/null +++ b/core/modules/media/tests/src/Functional/OEmbedTest.php @@ -0,0 +1,117 @@ + + [ + 'provider_name' => 'YouTube', + 'provider_url' => 'http://www.youtube.com/', + 'endpoints' => + [ + [ + 'url' => 'http://www.youtube.com/oembed', + 'discovery' => TRUE, + 'schemes' => + [ + 0 => 'http*://*youtube.com/*', + 1 => 'http*://*youtu.be/*', + ], + ], + ], + ], + '56696d656f' => + [ + 'provider_name' => 'Vimeo', + 'provider_url' => 'https://vimeo.com/', + 'endpoints' => + [ + + [ + 'schemes' => + [ + 0 => 'https://vimeo.com/*', + 1 => 'https://vimeo.com/album/*/video/*', + 2 => 'https://vimeo.com/channels/*/*', + 3 => 'https://vimeo.com/groups/*/videos/*', + 4 => 'https://vimeo.com/ondemand/*/*', + 5 => 'https://player.vimeo.com/video/*', + ], + 'url' => 'https://vimeo.com/api/oembed.{format}', + 'discovery' => TRUE, + ], + ], + ], + ]; + + $cacheBackend = $this->container->get('cache.default'); + $logger = $this->container->get('logger.factory'); + $client = $this->container->get('http_client_factory'); + + $oEmbedProviderDiscovery = $this->getMockBuilder('Drupal\media\OEmbedProviderDiscovery') + ->disableOriginalConstructor() + ->getMock(); + $oEmbedProviderDiscovery->method('getProviders')->willReturn($providers); + + $oEmbed = new OEmbed($oEmbedProviderDiscovery, $client, $cacheBackend, $logger); + $this->assertTrue($oEmbed->isProvidedUrl('https://vimeo.com/7073899')); + $this->assertTrue($oEmbed->isProvidedUrl('https://www.youtube.com/watch?v=lZ-s3DRZJKY')); + + $this->assertFalse($oEmbed->isProvidedUrl('https://vimeo.com/7073899', ['596f7554756265'])); + $this->assertTrue($oEmbed->isProvidedUrl('https://www.youtube.com/watch?v=lZ-s3DRZJKY', ['596f7554756265'])); + + $this->assertFalse($oEmbed->isProvidedUrl('https://www.instagram.com/p/Bb-Qt2nAmu3/')); + } + + /** + * Test urlDiscovery method. + */ + public function testUrlDiscovery() { + + $cacheBackend = $this->container->get('cache.default'); + $logger = $this->container->get('logger.factory'); + $client = $this->container->get('http_client_factory'); + $oEmbedProviderDiscovery = $this->container->get('media.oembed_provider_discovery'); + + $oEmbed = new OEmbed($oEmbedProviderDiscovery, $client, $cacheBackend, $logger); + + $this->assertSame('https://vimeo.com/api/oembed.json?url=https%3A%2F%2Fvimeo.com%2F7073899', $oEmbed->urlDiscovery('https://vimeo.com/7073899')); + $this->assertFalse($oEmbed->urlDiscovery('https://twitter.com/drupaldevdays/status/935643039741202432')); + } + + /** + * Test fetchResource method. + */ + public function testFetchResource() { + + $cacheBackend = $this->container->get('cache.default'); + $logger = $this->container->get('logger.factory'); + $client = $this->container->get('http_client_factory'); + $oEmbedProviderDiscovery = $this->container->get('media.oembed_provider_discovery'); + + $oEmbed = new OEmbed($oEmbedProviderDiscovery, $client, $cacheBackend, $logger); + + $resource = $oEmbed->fetchResource('https://vimeo.com/api/oembed.json?url=https%3A%2F%2Fvimeo.com%2F7073899'); + + $this->assertSame('video', $resource['type']); + $this->assertSame('Vimeo', $resource['provider_name']); + $this->assertSame('Drupal Rap Video - Schipulcon09', $resource['title']); + } + +}