Skip to content

Conversation

@datamweb
Copy link
Contributor

@datamweb datamweb commented Dec 20, 2025

Description
The Debug Toolbar injects HTML and JavaScript into every HTML response by default, which works for full page loads but causes issues for client-managed or partial requests (such as those from HTMX, Unpoly, or Hotwire Turbo) that expect clean HTML fragments. This can result in invalid HTML, duplicated scripts, or JavaScript errors like “Maximum call stack size exceeded.” To address this, support was added to skip Debug Toolbar HTML/JS injection for requests containing specific headers (e.g. HX-Request, X-Up-Version), while still preserving Debugbar response headers for network-level debugging.

Screenshot 2025-12-20 215637

I don’t consider this PR a new feature. I believe it could have been to the develop branch, but since it introduces the $disableOnHeaders property, I only PR’d it to the 4.7 branch.

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value (without duplication)
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@michalsn michalsn added enhancement PRs that improve existing functionalities 4.7 labels Dec 21, 2025
@datamweb datamweb marked this pull request as draft December 23, 2025 10:53
@datamweb
Copy link
Contributor Author

datamweb commented Dec 23, 2025

@samsonasik , could you please advise on the best way to fix this rector issue in ToolbarTest.php?
https://github.com/codeigniter4/CodeIgniter4/actions/runs/20474006600/job/58835031436?pr=9852

Copy link
Member

@michalsn michalsn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the Rector error, we probably will have to skip the RemoveExtraParametersRector rule for this test. But maybe there is a better way - I'm not an expert.

@datamweb datamweb marked this pull request as ready for review December 24, 2025 01:32
@datamweb
Copy link
Contributor Author

As for the Rector error, we probably will have to skip the RemoveExtraParametersRector rule for this test. But maybe there is a better way - I'm not an expert.

I agree. I’ve disabled RemoveExtraParametersRector for this specific test via the configuration, since the parameter usage is intentional and required for the test behavior.

Copy link
Member

@michalsn michalsn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates! I have a few final thoughts.

Comment on lines +143 to +144
'HX-Request', // HTMX partial requests
'X-Up-Version', // Unpoly partial requests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'HX-Request', // HTMX partial requests
'X-Up-Version', // Unpoly partial requests
'X-Requested-With' => 'xmlhttprequest', // AJAX requests
'HX-Request' => 'true', // HTMX requests
'X-Up-Version' => null, // Unpoly partial requests

Since we need to loop over these values, we can also add AJAX requests here. Additionally, we can check not only for the presence of the header but also for the value, which is important in some cases. The null value indicates that we are only interested in the header presence.

* Indicates if the current request is a custom AJAX-like request
* (HTMX, Unpoly, Turbo, etc.) that expects clean HTML fragments.
*/
protected bool $isCustomAjax = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe $isDisabled instead?

Comment on lines +417 to +420
if ($request->hasHeader($header)) {
$this->isCustomAjax = true;
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we will need more complex checks, this can be delegated to a separate method.

// then we send headers saying where to find the debug data
// for this response
if ($request->isAJAX() || ! str_contains($format, 'html')) {
if ($request->isAJAX() || ! str_contains($format, 'html') || $this->isCustomAjax) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ($request->isAJAX() || ! str_contains($format, 'html') || $this->isCustomAjax) {
if ($this->isDisabled || ! str_contains($format, 'html')) {

This way, we can make this check a bit simpler.

Comment on lines +111 to +113
RemoveExtraParametersRector::class => [
__DIR__ . '/tests/system/Debug/ToolbarTest.php',
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add above that this is required because of is_cli() mocking?

@datamweb datamweb marked this pull request as draft December 25, 2025 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.7 enhancement PRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants