diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
index 79db452019ab0..0e0d4f8976233 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
@@ -162,6 +162,27 @@ public function toolbarAction(Request $request, ?string $token = null): Response
]);
}
+ /**
+ * Renders the Web Debug Toolbar stylesheet.
+ *
+ * @throws NotFoundHttpException
+ */
+ public function toolbarStylesheetAction(): Response
+ {
+ $this->denyAccessIfProfilerDisabled();
+
+ $this->cspHandler?->disableCsp();
+
+ return new Response(
+ $this->twig->render('@WebProfiler/Profiler/toolbar.css.twig'),
+ 200,
+ [
+ 'Content-Type' => 'text/css',
+ 'Cache-Control' => 'max-age=600, private',
+ ],
+ );
+ }
+
/**
* Renders the profiler search bar.
*
@@ -383,6 +404,9 @@ protected function getTemplateManager(): TemplateManager
return $this->templateManager ??= new TemplateManager($this->profiler, $this->twig, $this->templates);
}
+ /**
+ * @throws NotFoundHttpException
+ */
private function denyAccessIfProfilerDisabled(): void
{
if (null === $this->profiler) {
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/wdt.xml b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/wdt.xml
index 0f7e960cc8b91..26bbd96455adf 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/wdt.xml
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/wdt.xml
@@ -4,6 +4,10 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing https://symfony.com/schema/routing/routing-1.0.xsd">
+
+ web_profiler.controller.profiler::toolbarStylesheetAction
+
+
web_profiler.controller.profiler::toolbarAction
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig
index f6b37b37e9fb7..eaf9329aadde7 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig
@@ -9,9 +9,7 @@
}) }}
-
+
{# CAUTION: the contents of this file are processed by Twig before loading
them as JavaScript source code. Always use '/*' comments instead
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php
index 0e4e9e0d66281..3933d30e48dc4 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php
@@ -137,6 +137,33 @@ public function testToolbarActionWithEmptyToken($token)
$this->assertEquals(200, $response->getStatusCode());
}
+ public function testToolbarStylesheetActionWithProfilerDisabled()
+ {
+ $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
+ $twig = $this->createMock(Environment::class);
+
+ $controller = new ProfilerController($urlGenerator, null, $twig, []);
+
+ $this->expectException(NotFoundHttpException::class);
+ $this->expectExceptionMessage('The profiler must be enabled.');
+
+ $controller->toolbarStylesheetAction();
+ }
+
+ public function testToolbarStylesheetAction()
+ {
+ $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
+ $twig = $this->createMock(Environment::class);
+ $profiler = $this->createMock(Profiler::class);
+
+ $controller = new ProfilerController($urlGenerator, $profiler, $twig, []);
+
+ $response = $controller->toolbarStylesheetAction();
+ $this->assertSame(200, $response->getStatusCode());
+ $this->assertSame('text/css', $response->headers->get('Content-Type'));
+ $this->assertSame('max-age=600, private', $response->headers->get('Cache-Control'));
+ }
+
public static function getEmptyTokenCases()
{
return [