Skip to content

Commit 6c41a51

Browse files
committed
feat: skip HTML/JS injection for partial requests
1 parent 08bc0f8 commit 6c41a51

2 files changed

Lines changed: 55 additions & 8 deletions

File tree

app/Config/Toolbar.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[email protected]>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
312
namespace Config;
413

514
use CodeIgniter\Config\BaseConfig;
@@ -119,4 +128,31 @@ class Toolbar extends BaseConfig
119128
public array $watchedExtensions = [
120129
'php', 'css', 'js', 'html', 'svg', 'json', 'env',
121130
];
131+
132+
/**
133+
* --------------------------------------------------------------------------
134+
* Ignored HTTP Headers
135+
* --------------------------------------------------------------------------
136+
*
137+
* CodeIgniter Debug Toolbar normally injects HTML and JavaScript into every
138+
* HTML response. This is correct for full page loads, but it breaks requests
139+
* that expect only a clean HTML fragment.
140+
*
141+
* Libraries like HTMX, Unpoly, and Hotwire (Turbo) update parts of the page or
142+
* manage navigation on the client side. Injecting the Debug Toolbar into their
143+
* responses can cause invalid HTML, duplicated scripts, or JavaScript errors
144+
* (such as infinite loops or "Maximum call stack size exceeded").
145+
*
146+
* Any request containing one of the following headers is treated as a
147+
* client-managed or partial request, and the Debug Toolbar injection is skipped.s
148+
*
149+
* @var list<string>
150+
*/
151+
public array $disableOnHeaders = [
152+
'HX-Request', // HTMX partial requests
153+
'HX-Boosted', // HTMX boosted navigation
154+
'X-Unpoly-Request', // Unpoly partial requests
155+
'Turbo-Frame', // Turbo Frames
156+
'Turbo-Visit', // Turbo Drive navigation
157+
];
122158
}

system/Debug/Toolbar.php

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ class Toolbar
4242
*/
4343
protected $config;
4444

45+
/**
46+
* Indicates if the current request is a custom AJAX-like request
47+
* (HTMX, Unpoly, Turbo, etc.) that expects clean HTML fragments.
48+
*/
49+
protected bool $isCustomAjax = false;
50+
4551
/**
4652
* Collectors to be used and displayed.
4753
*
@@ -365,10 +371,8 @@ protected function roundTo(float $number, int $increments = 5): float
365371

366372
/**
367373
* Prepare for debugging.
368-
*
369-
* @return void
370374
*/
371-
public function prepare(?RequestInterface $request = null, ?ResponseInterface $response = null)
375+
public function prepare(?RequestInterface $request = null, ?ResponseInterface $response = null): void
372376
{
373377
/**
374378
* @var IncomingRequest|null $request
@@ -385,7 +389,9 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r
385389
return;
386390
}
387391

388-
$toolbar = service('toolbar', config(ToolbarConfig::class));
392+
$config = config(ToolbarConfig::class);
393+
394+
$toolbar = service('toolbar', $config);
389395
$stats = $app->getPerformanceStats();
390396
$data = $toolbar->run(
391397
$stats['startTime'],
@@ -407,10 +413,17 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r
407413

408414
$format = $response->getHeaderLine('content-type');
409415

416+
foreach ($config->disableOnHeaders as $header) {
417+
if ($request->hasHeader($header)) {
418+
$this->isCustomAjax = true;
419+
break;
420+
}
421+
}
422+
410423
// Non-HTML formats should not include the debugbar
411424
// then we send headers saying where to find the debug data
412425
// for this response
413-
if ($request->isAJAX() || ! str_contains($format, 'html')) {
426+
if ($request->isAJAX() || ! str_contains($format, 'html') || $this->isCustomAjax) {
414427
$response->setHeader('Debugbar-Time', "{$time}")
415428
->setHeader('Debugbar-Link', site_url("?debugbar_time={$time}"));
416429

@@ -454,10 +467,8 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r
454467
* Inject debug toolbar into the response.
455468
*
456469
* @codeCoverageIgnore
457-
*
458-
* @return void
459470
*/
460-
public function respond()
471+
public function respond(): void
461472
{
462473
if (ENVIRONMENT === 'testing') {
463474
return;

0 commit comments

Comments
 (0)