From 167686b809201ac5ce6f215937bcc98c54e07f6b Mon Sep 17 00:00:00 2001
From: effulgentsia <alex.bronstein@acquia.com>
Date: Tue, 13 Jul 2021 09:26:00 -0700
Subject: [PATCH] =?UTF-8?q?Issue=20#3186415=20by=20phenaproxima,=20Charlie?=
 =?UTF-8?q?=20ChX=20Negyesi,=20walangitan,=20pianomansam,=20dan2k3k4,=20Al?=
 =?UTF-8?q?=20Munnings,=20larowlan,=20philltran,=20cilefen,=20longwave,=20?=
 =?UTF-8?q?alexpott,=20pookmish,=20kaynen,=20Lendude,=20G=C3=A1bor=20Hojts?=
 =?UTF-8?q?y,=20rlnorthcutt,=20ksenzee:=20Make=20oEmbed=20resource=20fetch?=
 =?UTF-8?q?er=20more=20tolerant=20of=20unexpected=20Content-Type=20headers?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../media/src/OEmbed/ResourceFetcher.php      | 12 ++-
 .../tests/src/Unit/ResourceFetcherTest.php    | 75 +++++++++++++++++++
 2 files changed, 83 insertions(+), 4 deletions(-)
 create mode 100644 core/modules/media/tests/src/Unit/ResourceFetcherTest.php

diff --git a/core/modules/media/src/OEmbed/ResourceFetcher.php b/core/modules/media/src/OEmbed/ResourceFetcher.php
index 4ac2efadd5e9..534102cb5921 100644
--- a/core/modules/media/src/OEmbed/ResourceFetcher.php
+++ b/core/modules/media/src/OEmbed/ResourceFetcher.php
@@ -70,12 +70,16 @@ public function fetchResource($url) {
     if (strstr($format, 'text/xml') || strstr($format, 'application/xml')) {
       $data = $this->parseResourceXml($content, $url);
     }
-    elseif (strstr($format, 'text/javascript') || strstr($format, 'application/json')) {
+    // By default, try to parse the resource data as JSON.
+    else {
       $data = Json::decode($content);
+
+      if (json_last_error() !== JSON_ERROR_NONE) {
+        throw new ResourceException('Error decoding oEmbed resource: ' . json_last_error_msg(), $url);
+      }
     }
-    // If the response is neither XML nor JSON, we are in bat country.
-    else {
-      throw new ResourceException('The fetched resource did not have a valid Content-Type header.', $url);
+    if (empty($data) || !is_array($data)) {
+      throw new ResourceException('The oEmbed resource could not be decoded.', $url);
     }
 
     $this->cacheSet($cache_id, $data);
diff --git a/core/modules/media/tests/src/Unit/ResourceFetcherTest.php b/core/modules/media/tests/src/Unit/ResourceFetcherTest.php
new file mode 100644
index 000000000000..0aef16ed5c06
--- /dev/null
+++ b/core/modules/media/tests/src/Unit/ResourceFetcherTest.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace Drupal\Tests\media\Unit;
+
+use Drupal\Component\Serialization\Json;
+use Drupal\media\OEmbed\ResourceException;
+use Drupal\media\OEmbed\ResourceFetcher;
+use Drupal\Tests\UnitTestCase;
+use GuzzleHttp\Client;
+use GuzzleHttp\Handler\MockHandler;
+use GuzzleHttp\HandlerStack;
+use GuzzleHttp\Psr7\Response;
+
+/**
+ * @group media
+ *
+ * @coversDefaultClass \Drupal\media\OEmbed\ResourceFetcher
+ */
+class ResourceFetcherTest extends UnitTestCase {
+
+  /**
+   * Tests how the resource fetcher handles unknown Content-Type headers.
+   *
+   * @covers ::fetchResource
+   */
+  public function testUnknownContentTypeHeader(): void {
+    $headers = [
+      'Content-Type' => ['text/html'],
+    ];
+    $body = Json::encode([
+      'version' => '1.0',
+      'type' => 'video',
+      'html' => 'test',
+    ]);
+    $valid_response = new Response(200, $headers, $body);
+    // Strip off the trailing '}' to produce a response that will cause a JSON
+    // parse error.
+    $invalid_response = new Response(200, $headers, rtrim($body, '}'));
+    // A response that is valid JSON, but does not decode to an array, should
+    // produce an exception as well.
+    $non_array_response = new Response(200, $headers, '"Valid JSON, but not an array..."');
+
+    $mock_handler = new MockHandler([
+      $valid_response,
+      $invalid_response,
+      $non_array_response,
+    ]);
+    $client = new Client([
+      'handler' => HandlerStack::create($mock_handler),
+    ]);
+    $providers = $this->createMock('\Drupal\media\OEmbed\ProviderRepositoryInterface');
+
+    $fetcher = new ResourceFetcher($client, $providers);
+    /** @var \Drupal\media\OEmbed\Resource $resource */
+    $resource = $fetcher->fetchResource('valid');
+    // The resource should have been successfully decoded as JSON.
+    $this->assertSame('video', $resource->getType());
+    $this->assertSame('test', $resource->getHtml());
+
+    // Invalid JSON should throw an exception.
+    try {
+      $fetcher->fetchResource('invalid');
+      $this->fail('Expected a ResourceException to be thrown for invalid JSON.');
+    }
+    catch (ResourceException $e) {
+      $this->assertSame('Error decoding oEmbed resource: Syntax error', $e->getMessage());
+    }
+
+    // Valid JSON that does not produce an array should also throw an exception.
+    $this->expectException(ResourceException::class);
+    $this->expectExceptionMessage('The oEmbed resource could not be decoded.');
+    $fetcher->fetchResource('non_array');
+  }
+
+}
-- 
GitLab