Chris@17: resourceFetcher = $resource_fetcher; Chris@17: $this->urlResolver = $url_resolver; Chris@17: $this->renderer = $renderer; Chris@17: $this->logger = $logger; Chris@17: $this->iFrameUrlHelper = $iframe_url_helper; Chris@17: } Chris@17: Chris@17: /** Chris@17: * {@inheritdoc} Chris@17: */ Chris@17: public static function create(ContainerInterface $container) { Chris@17: return new static( Chris@17: $container->get('media.oembed.resource_fetcher'), Chris@17: $container->get('media.oembed.url_resolver'), Chris@17: $container->get('renderer'), Chris@17: $container->get('logger.factory')->get('media'), Chris@17: $container->get('media.oembed.iframe_url_helper') Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * Renders an oEmbed resource. Chris@17: * Chris@17: * @param \Symfony\Component\HttpFoundation\Request $request Chris@17: * The request object. Chris@17: * Chris@17: * @return \Symfony\Component\HttpFoundation\Response Chris@17: * The response object. Chris@17: * Chris@17: * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException Chris@17: * Will be thrown if the 'hash' parameter does not match the expected hash Chris@17: * of the 'url' parameter. Chris@17: */ Chris@17: public function render(Request $request) { Chris@17: $url = $request->query->get('url'); Chris@17: $max_width = $request->query->getInt('max_width', NULL); Chris@17: $max_height = $request->query->getInt('max_height', NULL); Chris@17: Chris@17: // Hash the URL and max dimensions, and ensure it is equal to the hash Chris@17: // parameter passed in the query string. Chris@17: $hash = $this->iFrameUrlHelper->getHash($url, $max_width, $max_height); Chris@17: if (!Crypt::hashEquals($hash, $request->query->get('hash', ''))) { Chris@17: throw new AccessDeniedHttpException('This resource is not available'); Chris@17: } Chris@17: Chris@17: // Return a response instead of a render array so that the frame content Chris@17: // will not have all the blocks and page elements normally rendered by Chris@17: // Drupal. Chris@18: $response = new HtmlResponse(); Chris@17: $response->addCacheableDependency(Url::createFromRequest($request)); Chris@17: Chris@17: try { Chris@17: $resource_url = $this->urlResolver->getResourceUrl($url, $max_width, $max_height); Chris@17: $resource = $this->resourceFetcher->fetchResource($resource_url); Chris@17: Chris@18: $placeholder_token = Crypt::randomBytesBase64(55); Chris@18: Chris@17: // Render the content in a new render context so that the cacheability Chris@17: // metadata of the rendered HTML will be captured correctly. Chris@17: $element = [ Chris@17: '#theme' => 'media_oembed_iframe', Chris@17: // Even though the resource HTML is untrusted, IFrameMarkup::create() Chris@17: // will create a trusted string. The only reason this is okay is Chris@17: // because we are serving it in an iframe, which will mitigate the Chris@17: // potential dangers of displaying third-party markup. Chris@17: '#media' => IFrameMarkup::create($resource->getHtml()), Chris@17: '#cache' => [ Chris@17: // Add the 'rendered' cache tag as this response is not processed by Chris@17: // \Drupal\Core\Render\MainContent\HtmlRenderer::renderResponse(). Chris@17: 'tags' => ['rendered'], Chris@17: ], Chris@18: '#attached' => [ Chris@18: 'html_response_attachment_placeholders' => [ Chris@18: 'styles' => '', Chris@18: ], Chris@18: 'library' => [ Chris@18: 'media/oembed.frame', Chris@18: ], Chris@18: ], Chris@18: '#placeholder_token' => $placeholder_token, Chris@17: ]; Chris@17: $content = $this->renderer->executeInRenderContext(new RenderContext(), function () use ($resource, $element) { Chris@17: return $this->renderer->render($element); Chris@17: }); Chris@17: $response Chris@17: ->setContent($content) Chris@18: ->setAttachments($element['#attached']) Chris@17: ->addCacheableDependency($resource) Chris@17: ->addCacheableDependency(CacheableMetadata::createFromRenderArray($element)); Chris@17: } Chris@17: catch (ResourceException $e) { Chris@17: // Prevent the response from being cached. Chris@17: $response->setMaxAge(0); Chris@17: Chris@17: // The oEmbed system makes heavy use of exception wrapping, so log the Chris@17: // entire exception chain to help with troubleshooting. Chris@17: do { Chris@17: // @todo Log additional information from ResourceException, to help with Chris@17: // debugging, in https://www.drupal.org/project/drupal/issues/2972846. Chris@17: $this->logger->error($e->getMessage()); Chris@17: $e = $e->getPrevious(); Chris@17: } while ($e); Chris@17: } Chris@17: Chris@17: return $response; Chris@17: } Chris@17: Chris@17: }