resourceFetcher = $resource_fetcher; $this->urlResolver = $url_resolver; $this->renderer = $renderer; $this->logger = $logger; $this->iFrameUrlHelper = $iframe_url_helper; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('media.oembed.resource_fetcher'), $container->get('media.oembed.url_resolver'), $container->get('renderer'), $container->get('logger.factory')->get('media'), $container->get('media.oembed.iframe_url_helper') ); } /** * Renders an oEmbed resource. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * * @return \Symfony\Component\HttpFoundation\Response * The response object. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * Will be thrown if the 'hash' parameter does not match the expected hash * of the 'url' parameter. */ public function render(Request $request) { $url = $request->query->get('url'); $max_width = $request->query->getInt('max_width', NULL); $max_height = $request->query->getInt('max_height', NULL); // 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 (!Crypt::hashEquals($hash, $request->query->get('hash', ''))) { throw new AccessDeniedHttpException('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 CacheableResponse(); $response->addCacheableDependency(Url::createFromRequest($request)); try { $resource_url = $this->urlResolver->getResourceUrl($url, $max_width, $max_height); $resource = $this->resourceFetcher->fetchResource($resource_url); // 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', // 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'], ], ]; $content = $this->renderer->executeInRenderContext(new RenderContext(), function () use ($resource, $element) { return $this->renderer->render($element); }); $response ->setContent($content) ->addCacheableDependency($resource) ->addCacheableDependency(CacheableMetadata::createFromRenderArray($element)); } 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; } }