Skip to content

Commit 1bd1ca6

Browse files
committed
test: add test for native header conflict detection
1 parent 0844a47 commit 1bd1ca6

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

system/Debug/Toolbar.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,6 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r
372372
* @var IncomingRequest|null $request
373373
*/
374374
if (CI_DEBUG && ! is_cli()) {
375-
376375
if ($this->hasNativeHeaderConflict()) {
377376
return;
378377
}

tests/system/Debug/ToolbarTest.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
use PHPUnit\Framework\Attributes\BackupGlobals;
2424
use PHPUnit\Framework\Attributes\Group;
2525

26+
require_once SUPPORTPATH . 'Debug/MockNativeHeaders.php';
27+
2628
/**
2729
* @internal
2830
*/
@@ -37,6 +39,9 @@ final class ToolbarTest extends CIUnitTestCase
3739
protected function setUp(): void
3840
{
3941
parent::setUp();
42+
43+
MockNativeHeaders::reset();
44+
4045
Services::reset();
4146

4247
is_cli(false);
@@ -99,4 +104,76 @@ public function testPrepareInjectsNormallyWithoutIgnoredHeader(): void
99104
// Assertions
100105
$this->assertStringContainsString('id="debugbar_loader"', (string) $this->response->getBody());
101106
}
107+
108+
// -------------------------------------------------------------------------
109+
// Native Header Conflicts
110+
// -------------------------------------------------------------------------
111+
112+
public function testPrepareAbortsIfHeadersAlreadySent(): void
113+
{
114+
// Headers explicitly sent (e.g., echo before execution)
115+
MockNativeHeaders::$headersSent = true;
116+
117+
$this->request = service('incomingrequest', null, false);
118+
$this->response = service('response', null, false);
119+
$this->response->setBody('<html><body>Content</body></html>');
120+
121+
$toolbar = new Toolbar($this->config);
122+
$toolbar->prepare($this->request, $this->response);
123+
124+
// Must NOT inject because we can't modify the body safely
125+
$this->assertStringNotContainsString('id="debugbar_loader"', (string) $this->response->getBody());
126+
}
127+
128+
public function testPrepareAbortsIfNativeContentTypeIsNotHtml(): void
129+
{
130+
// A library (like Dompdf) set a PDF header directly
131+
MockNativeHeaders::$headers = ['Content-Type: application/pdf'];
132+
133+
$this->request = service('incomingrequest', null, false);
134+
$this->response = service('response', null, false);
135+
// Even if the body looks like HTML (before rendering), the header says PDF
136+
$this->response->setBody('<html><body>Raw PDF Data</body></html>');
137+
138+
$toolbar = new Toolbar($this->config);
139+
$toolbar->prepare($this->request, $this->response);
140+
141+
// Must NOT inject into non-HTML content
142+
$this->assertStringNotContainsString('id="debugbar_loader"', (string) $this->response->getBody());
143+
}
144+
145+
public function testPrepareAbortsIfNativeContentDispositionIsAttachment(): void
146+
{
147+
// A file download (even if it is HTML)
148+
MockNativeHeaders::$headers = [
149+
'Content-Type: text/html',
150+
'Content-Disposition: attachment; filename="report.html"',
151+
];
152+
153+
$this->request = service('incomingrequest', null, false);
154+
$this->response = service('response', null, false);
155+
$this->response->setBody('<html><body>Downloadable Report</body></html>');
156+
157+
$toolbar = new Toolbar($this->config);
158+
$toolbar->prepare($this->request, $this->response);
159+
160+
// Must NOT inject into downloads
161+
$this->assertStringNotContainsString('id="debugbar_loader"', (string) $this->response->getBody());
162+
}
163+
164+
public function testPrepareWorksWithNativeHtmlHeader(): void
165+
{
166+
// Standard scenario where PHP header is text/html
167+
MockNativeHeaders::$headers = ['Content-Type: text/html; charset=UTF-8'];
168+
169+
$this->request = service('incomingrequest', null, false);
170+
$this->response = service('response', null, false);
171+
$this->response->setBody('<html><body>Valid Page</body></html>');
172+
173+
$toolbar = new Toolbar($this->config);
174+
$toolbar->prepare($this->request, $this->response);
175+
176+
// Should inject normally
177+
$this->assertStringContainsString('id="debugbar_loader"', (string) $this->response->getBody());
178+
}
102179
}

0 commit comments

Comments
 (0)