diff --git a/flight/Engine.php b/flight/Engine.php index 0af8765..0d32f0a 100644 --- a/flight/Engine.php +++ b/flight/Engine.php @@ -487,13 +487,16 @@ class Engine // If this route is to be streamed, we need to output the headers now if ($route->is_streamed === true) { - $response->status($route->streamed_headers['status'] ?? 200); - unset($route->streamed_headers['status']); + if (count($route->streamed_headers) > 0) { + $response->status($route->streamed_headers['status'] ?? 200); + unset($route->streamed_headers['status']); + foreach ($route->streamed_headers as $header => $value) { + $response->header($header, $value); + } + } + $response->header('X-Accel-Buffering', 'no'); $response->header('Connection', 'close'); - foreach ($route->streamed_headers as $header => $value) { - $response->header($header, $value); - } // We obviously don't know the content length right now. This must be false. $response->content_length = false; diff --git a/flight/net/Route.php b/flight/net/Route.php index 57ba2fc..4d005b9 100644 --- a/flight/net/Route.php +++ b/flight/net/Route.php @@ -238,6 +238,17 @@ class Route return $this; } + /** + * If the response should be streamed + * + * @return self + */ + public function stream(): self + { + $this->is_streamed = true; + return $this; + } + /** * This will allow the response for this route to be streamed. * diff --git a/tests/FlightTest.php b/tests/FlightTest.php index 042b6bb..d84336b 100644 --- a/tests/FlightTest.php +++ b/tests/FlightTest.php @@ -280,6 +280,30 @@ class FlightTest extends TestCase } public function testStreamRoute() + { + $response_mock = new class extends Response { + public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response + { + return $this; + } + }; + $mock_response_class_name = get_class($response_mock); + Flight::register('response', $mock_response_class_name); + Flight::route('/stream', function () { + echo 'stream'; + })->stream(); + Flight::request()->url = '/stream'; + $this->expectOutputString('stream'); + Flight::start(); + $this->assertEquals('', Flight::response()->getBody()); + $this->assertEquals([ + 'X-Accel-Buffering' => 'no', + 'Connection' => 'close' + ], Flight::response()->getHeaders()); + $this->assertEquals(200, Flight::response()->status()); + } + + public function testStreamRouteWithHeaders() { $response_mock = new class extends Response { public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response diff --git a/tests/server/LayoutMiddleware.php b/tests/server/LayoutMiddleware.php index b89c4e0..d23e81c 100644 --- a/tests/server/LayoutMiddleware.php +++ b/tests/server/LayoutMiddleware.php @@ -76,7 +76,8 @@ class LayoutMiddleware