mirror of
https://github.com/filp/whoops.git
synced 2026-10-08 13:06:10 +00:00
Merge pull request #795 from dualfroz/fix/704-non-removable-output-buffer
Stop output buffer cleanup at buffers that cannot be removed
This commit is contained in:
+4
-2
@@ -425,8 +425,10 @@ final class Run implements RunInterface
|
||||
if ($this->writeToOutput()) {
|
||||
// @todo Might be able to clean this up a bit better
|
||||
if ($willQuit) {
|
||||
// Cleanup all other output buffers before sending our output:
|
||||
while ($this->system->getOutputBufferLevel() > 0) {
|
||||
// Cleanup all other output buffers before sending our output.
|
||||
// Stop at a buffer that cannot be removed, e.g. zlib output
|
||||
// compression once it has started sending compressed output:
|
||||
while ($this->system->getOutputBufferLevel() > 0 && $this->system->isOutputBufferRemovable()) {
|
||||
$this->system->endOutputBuffering();
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,16 @@ class SystemFacade
|
||||
return ob_get_level();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isOutputBufferRemovable()
|
||||
{
|
||||
$status = ob_get_status();
|
||||
|
||||
return isset($status['flags']) && ($status['flags'] & PHP_OUTPUT_HANDLER_REMOVABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -479,6 +479,46 @@ class RunTest extends TestCase
|
||||
$this->assertEquals("", ob_get_clean());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::handleException
|
||||
*/
|
||||
public function testOutputBufferCleanupStopsAtNonRemovableBuffer()
|
||||
{
|
||||
// A removable buffer on top of one that cannot be removed, like
|
||||
// zlib.output_compression once it has sent compressed output.
|
||||
$removable = [false, true];
|
||||
$test = $this;
|
||||
|
||||
$system = m::mock('Whoops\Util\SystemFacade')->makePartial();
|
||||
$system->shouldReceive('stopExecution');
|
||||
$system->shouldReceive('getOutputBufferLevel')
|
||||
->andReturnUsing(function () use (&$removable) {
|
||||
return count($removable);
|
||||
});
|
||||
$system->shouldReceive('isOutputBufferRemovable')
|
||||
->andReturnUsing(function () use (&$removable) {
|
||||
return end($removable);
|
||||
});
|
||||
$system->shouldReceive('endOutputBuffering')
|
||||
->andReturnUsing(function () use ($test, &$removable) {
|
||||
if (!array_pop($removable)) {
|
||||
$test->fail('Tried to end an output buffer that cannot be removed');
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
$run = new Run($system);
|
||||
$run->pushHandler(function () {
|
||||
echo "hello there";
|
||||
return Handler::QUIT;
|
||||
});
|
||||
|
||||
ob_start();
|
||||
$run->handleException(new RuntimeException());
|
||||
$this->assertEquals("hello there", ob_get_clean());
|
||||
$this->assertEquals([false], $removable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::sendHttpCode
|
||||
*/
|
||||
|
||||
@@ -68,6 +68,20 @@ class SystemFacadeTest extends TestCase
|
||||
$this->facade->endOutputBuffering();
|
||||
}
|
||||
|
||||
public function test_it_reports_a_removable_output_buffer()
|
||||
{
|
||||
self::$runtime->shouldReceive('ob_get_status')->once()->andReturn(['flags' => PHP_OUTPUT_HANDLER_STDFLAGS]);
|
||||
|
||||
$this->assertTrue($this->facade->isOutputBufferRemovable());
|
||||
}
|
||||
|
||||
public function test_it_reports_a_non_removable_output_buffer()
|
||||
{
|
||||
self::$runtime->shouldReceive('ob_get_status')->once()->andReturn(['flags' => PHP_OUTPUT_HANDLER_STDFLAGS & ~PHP_OUTPUT_HANDLER_REMOVABLE]);
|
||||
|
||||
$this->assertFalse($this->facade->isOutputBufferRemovable());
|
||||
}
|
||||
|
||||
public function test_it_delegates_flushing_the_current_buffer_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('flush')->once();
|
||||
@@ -161,6 +175,11 @@ function ob_end_clean()
|
||||
return SystemFacadeTest::delegate('ob_end_clean');
|
||||
}
|
||||
|
||||
function ob_get_status()
|
||||
{
|
||||
return SystemFacadeTest::delegate('ob_get_status');
|
||||
}
|
||||
|
||||
function flush()
|
||||
{
|
||||
return SystemFacadeTest::delegate('flush');
|
||||
|
||||
Reference in New Issue
Block a user