17
17
use Symfony \Component \HttpFoundation \Request ;
18
18
use Symfony \Component \HttpFoundation \Response ;
19
19
use Symfony \Component \HttpFoundation \Session \Flash \AutoExpireFlashBag ;
20
+ use Symfony \Component \HttpFoundation \StreamedResponse ;
20
21
use Symfony \Component \HttpKernel \DataCollector \DumpDataCollector ;
21
22
use Symfony \Component \HttpKernel \Event \ResponseEvent ;
22
23
use Symfony \Component \HttpKernel \KernelEvents ;
@@ -104,7 +105,6 @@ public function onKernelResponse(ResponseEvent $event): void
104
105
// keep current flashes for one more request if using AutoExpireFlashBag
105
106
$ session ->getFlashBag ()->setAll ($ session ->getFlashBag ()->peekAll ());
106
107
}
107
-
108
108
$ response ->setContent ($ this ->twig ->render ('@WebProfiler/Profiler/toolbar_redirect.html.twig ' , ['location ' => $ response ->headers ->get ('Location ' ), 'host ' => $ request ->getSchemeAndHttpHost ()]));
109
109
$ response ->setStatusCode (200 );
110
110
$ response ->headers ->remove ('Location ' );
@@ -128,26 +128,59 @@ public function onKernelResponse(ResponseEvent $event): void
128
128
*/
129
129
protected function injectToolbar (Response $ response , Request $ request , array $ nonces ): void
130
130
{
131
- $ content = $ response ->getContent ();
132
- $ pos = strripos ($ content , '</body> ' );
133
-
134
- if (false !== $ pos ) {
135
- $ toolbar = "\n" .str_replace ("\n" , '' , $ this ->twig ->render (
136
- '@WebProfiler/Profiler/toolbar_js.html.twig ' ,
137
- [
138
- 'full_stack ' => class_exists (FullStack::class),
139
- 'excluded_ajax_paths ' => $ this ->excludedAjaxPaths ,
140
- 'token ' => $ response ->headers ->get ('X-Debug-Token ' ),
141
- 'request ' => $ request ,
142
- 'csp_script_nonce ' => $ nonces ['csp_script_nonce ' ] ?? null ,
143
- 'csp_style_nonce ' => $ nonces ['csp_style_nonce ' ] ?? null ,
144
- ]
145
- ))."\n" ;
146
- $ content = substr ($ content , 0 , $ pos ).$ toolbar .substr ($ content , $ pos );
147
- $ response ->setContent ($ content );
131
+ if ($ response instanceof StreamedResponse) {
132
+ $ callback = $ response ->getCallback ();
133
+ if (false !== strripos ($ response ->headers ->get ('Content-Type ' ), 'text/html ' )) {
134
+ $ toolbarHTMLContent = $ this ->getToolbarHTML ($ request , $ response ->headers ->get ('X-Debug-Token ' ), $ nonces );
135
+ $ injectedCallback = static function () use ($ toolbarHTMLContent , $ callback ): void {
136
+ ob_start (function (string $ buffer , int $ phase ) use ($ toolbarHTMLContent ): string {
137
+ $ pos = strripos ($ buffer , '</body> ' );
138
+ if (false !== $ pos ) {
139
+ $ buffer = substr ($ buffer , 0 , $ pos ).$ toolbarHTMLContent .substr ($ buffer , $ pos );
140
+ }
141
+
142
+ return $ buffer ;
143
+ }, 8 ); // length of '</body>'
144
+
145
+ ($ callback )();
146
+ ob_end_flush ();
147
+ };
148
+ $ response ->setCallback ($ injectedCallback );
149
+ }
150
+ } else {
151
+ $ content = $ response ->getContent ();
152
+ $ pos = strripos ($ content , '</body> ' );
153
+
154
+ if (false !== $ pos ) {
155
+ $ response ->setContent (
156
+ $ this ->renderToolbarInContent ($ content , $ pos , $ response ->headers ->get ('X-Debug-Token ' ), $ request , $ nonces )
157
+ );
158
+ }
148
159
}
149
160
}
150
161
162
+ protected function renderToolbarInContent (string $ content , int $ pos , ?string $ debugToken , Request $ request , array $ nonces ): string
163
+ {
164
+ $ toolbar = "\n" .str_replace ("\n" , '' , $ this ->getToolbarHTML ($ request , $ debugToken , $ nonces ))."\n" ;
165
+
166
+ return substr ($ content , 0 , $ pos ).$ toolbar .substr ($ content , $ pos );
167
+ }
168
+
169
+ private function getToolbarHTML (Request $ request , ?string $ debugToken , array $ nonces ): string
170
+ {
171
+ return $ this ->twig ->render (
172
+ '@WebProfiler/Profiler/toolbar_js.html.twig ' ,
173
+ [
174
+ 'full_stack ' => class_exists (FullStack::class),
175
+ 'excluded_ajax_paths ' => $ this ->excludedAjaxPaths ,
176
+ 'token ' => $ debugToken ,
177
+ 'request ' => $ request ,
178
+ 'csp_script_nonce ' => $ nonces ['csp_script_nonce ' ] ?? null ,
179
+ 'csp_style_nonce ' => $ nonces ['csp_style_nonce ' ] ?? null ,
180
+ ]
181
+ );
182
+ }
183
+
151
184
public static function getSubscribedEvents (): array
152
185
{
153
186
return [
0 commit comments