1212use Drupal \Core \File \FileSystemInterface ;
1313use Drupal \Core \Lock \LockBackendInterface ;
1414use Drupal \Core \Logger \LoggerChannelInterface ;
15+ use Drupal \Core \Render \RenderContext ;
16+ use Drupal \Core \Render \RendererInterface ;
1517use Drupal \Core \Session \AccountProxyInterface ;
1618use Drupal \Core \StringTranslation \StringTranslationTrait ;
1719use Drupal \Core \Utility \Token ;
@@ -85,6 +87,13 @@ class FileUpload {
8587 */
8688 protected $ systemFileConfig ;
8789
90+ /**
91+ * The renderer service.
92+ *
93+ * @var \Drupal\Core\Render\RendererInterface
94+ */
95+ protected $ renderer ;
96+
8897 /**
8998 * Constructor.
9099 */
@@ -96,7 +105,8 @@ public function __construct(
96105 LoggerChannelInterface $ logger ,
97106 Token $ token ,
98107 LockBackendInterface $ lock ,
99- ConfigFactoryInterface $ config_factory
108+ ConfigFactoryInterface $ config_factory ,
109+ RendererInterface $ renderer
100110 ) {
101111 /** @var \Drupal\file\FileStorageInterface $file_storage */
102112 $ file_storage = $ entityTypeManager ->getStorage ('file ' );
@@ -108,6 +118,7 @@ public function __construct(
108118 $ this ->token = $ token ;
109119 $ this ->lock = $ lock ;
110120 $ this ->systemFileConfig = $ config_factory ->get ('system.file ' );
121+ $ this ->renderer = $ renderer ;
111122 }
112123
113124 /**
@@ -374,9 +385,17 @@ protected function prepareFilename(string $filename, array &$validators): string
374385 protected function getUploadLocation (array $ settings ): string {
375386 $ destination = trim ($ settings ['file_directory ' ], '/ ' );
376387
377- // Replace tokens. As the tokens might contain HTML we convert it to plain
378- // text.
379- $ destination = PlainTextOutput::renderFromHtml ($ this ->token ->replace ($ destination , []));
388+ // Replace tokens first. This might produce cacheable metadata if tokens
389+ // are used in the path. As this service is intended to be used in mutations
390+ // which are not cached at all, it's enough to just catch leaked metadata
391+ // and skip including them in current GraphQL field's context.
392+ $ context = new RenderContext ();
393+ $ destination = $ this ->renderer ->executeInRenderContext ($ context , function () use ($ destination ): string {
394+ return $ this ->token ->replace ($ destination , []);
395+ });
396+
397+ // As the tokens might contain HTML we convert it to plain text.
398+ $ destination = PlainTextOutput::renderFromHtml ($ destination );
380399 return $ settings ['uri_scheme ' ] . ':// ' . $ destination ;
381400 }
382401
0 commit comments