function OEmbedIframeController::render

Same name and namespace in other branches
  1. 9 core/modules/media/src/Controller/OEmbedIframeController.php \Drupal\media\Controller\OEmbedIframeController::render()
  2. 8.9.x core/modules/media/src/Controller/OEmbedIframeController.php \Drupal\media\Controller\OEmbedIframeController::render()
  3. 10 core/modules/media/src/Controller/OEmbedIframeController.php \Drupal\media\Controller\OEmbedIframeController::render()

Renders an oEmbed resource.

Parameters

\Symfony\Component\HttpFoundation\Request $request: The request object.

Return value

\Symfony\Component\HttpFoundation\Response The response object.

Throws

\Symfony\Component\HttpKernel\Exception\BadRequestHttpException Will be thrown if either

  • the 'hash' parameter does not match the expected hash of the 'url' parameter;
  • the iframe_domain is set in media.settings and does not match the host in the request.
1 string reference to 'OEmbedIframeController::render'
media.routing.yml in core/modules/media/media.routing.yml
core/modules/media/media.routing.yml

File

core/modules/media/src/Controller/OEmbedIframeController.php, line 125

Class

OEmbedIframeController
Controller which renders an oEmbed resource in a bare page (without blocks).

Namespace

Drupal\media\Controller

Code

public function render(Request $request) {
    // @todo Move domain check logic to a separate method.
    $allowed_domain = \Drupal::config('media.settings')->get('iframe_domain');
    if ($allowed_domain) {
        $allowed_host = parse_url($allowed_domain, PHP_URL_HOST);
        $host = parse_url($request->getSchemeAndHttpHost(), PHP_URL_HOST);
        if ($allowed_host !== $host) {
            throw new BadRequestHttpException('This resource is not available');
        }
    }
    $url = $request->query
        ->get('url');
    $max_width = $request->query
        ->getInt('max_width');
    $max_height = $request->query
        ->getInt('max_height');
    // Hash the URL and max dimensions, and ensure it is equal to the hash
    // parameter passed in the query string.
    $hash = $this->iFrameUrlHelper
        ->getHash($url, $max_width, $max_height);
    if (!hash_equals($hash, $request->query
        ->get('hash', ''))) {
        throw new BadRequestHttpException('This resource is not available');
    }
    // Return a response instead of a render array so that the frame content
    // will not have all the blocks and page elements normally rendered by
    // Drupal.
    $response = new HtmlResponse('', HtmlResponse::HTTP_OK, [
        'Content-Type' => 'text/html; charset=UTF-8',
    ]);
    $response->addCacheableDependency(Url::createFromRequest($request));
    try {
        $resource_url = $this->urlResolver
            ->getResourceUrl($url, $max_width, $max_height);
        $resource = $this->resourceFetcher
            ->fetchResource($resource_url);
        $placeholder_token = Crypt::randomBytesBase64(55);
        // Render the content in a new render context so that the cacheability
        // metadata of the rendered HTML will be captured correctly.
        $element = [
            '#theme' => 'media_oembed_iframe',
            '#resource' => $resource,
            // Even though the resource HTML is untrusted, IFrameMarkup::create()
            // will create a trusted string. The only reason this is okay is
            // because we are serving it in an iframe, which will mitigate the
            // potential dangers of displaying third-party markup.
'#media' => IFrameMarkup::create($resource->getHtml()),
            '#cache' => [
                // Add the 'rendered' cache tag as this response is not processed by
                // \Drupal\Core\Render\MainContent\HtmlRenderer::renderResponse().
'tags' => [
                    'rendered',
                ],
            ],
            '#attached' => [
                'html_response_attachment_placeholders' => [
                    'styles' => '<css-placeholder token="' . $placeholder_token . '">',
                ],
                'library' => [
                    'media/oembed.frame',
                ],
            ],
            '#placeholder_token' => $placeholder_token,
        ];
        $context = new RenderContext();
        $content = $this->renderer
            ->executeInRenderContext($context, function () use ($element) {
            return $this->renderer
                ->render($element);
        });
        $response->setContent($content)
            ->setAttachments($element['#attached'])
            ->addCacheableDependency($resource)
            ->addCacheableDependency(CacheableMetadata::createFromRenderArray($element));
        // Modules and themes implementing hook_media_oembed_iframe_preprocess()
        // can add additional #cache and #attachments to a render array. If this
        // occurs, the render context won't be empty, and we need to ensure the
        // added metadata is bubbled up to the response.
        // @see \Drupal\Core\Theme\ThemeManager::render()
        if (!$context->isEmpty()) {
            $bubbleable_metadata = $context->pop();
            assert($bubbleable_metadata instanceof BubbleableMetadata);
            $response->addCacheableDependency($bubbleable_metadata);
            $response->addAttachments($bubbleable_metadata->getAttachments());
        }
    } catch (ResourceException $e) {
        // Prevent the response from being cached.
        $response->setMaxAge(0);
        // The oEmbed system makes heavy use of exception wrapping, so log the
        // entire exception chain to help with troubleshooting.
        do {
            // @todo Log additional information from ResourceException, to help with
            // debugging, in https://www.drupal.org/project/drupal/issues/2972846.
            $this->logger
                ->error($e->getMessage());
            $e = $e->getPrevious();
        } while ($e);
    }
    return $response;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.