diff --git a/src/Drivers/LaravelHttpServer.php b/src/Drivers/LaravelHttpServer.php
index fd5a4144..ac251f10 100644
--- a/src/Drivers/LaravelHttpServer.php
+++ b/src/Drivers/LaravelHttpServer.php
@@ -369,9 +369,10 @@ private function handleRequest(AmpRequest $request): Response
ob_start();
$response->sendContent();
} finally {
- // @phpstan-ignore-next-line
- $content = mb_trim(ob_get_clean());
+ $buffer = ob_get_clean();
}
+
+ $content = $buffer === false ? '' : $buffer;
}
return new Response(
diff --git a/tests/Browser/Visit/StreamedResponseTest.php b/tests/Browser/Visit/StreamedResponseTest.php
new file mode 100644
index 00000000..6ca44f83
--- /dev/null
+++ b/tests/Browser/Visit/StreamedResponseTest.php
@@ -0,0 +1,92 @@
+ '
Home
');
+ Route::get('/binary', fn (): StreamedResponse => response()->stream(
+ function () use ($bytes): void {
+ echo $bytes;
+ },
+ 200,
+ ['Content-Type' => 'image/jpeg'],
+ ));
+
+ $page = visit('/');
+
+ $page->assertScript(
+ "async () => {
+ const response = await fetch('/binary');
+ const bytes = new Uint8Array(await response.arrayBuffer());
+
+ return Array.from(bytes).join(',');
+ }",
+ implode(',', unpack('C*', $bytes)),
+ );
+});
+
+it('may serve a binary streamed image that the browser is able to decode', function (): void {
+ $image = file_get_contents(__DIR__.'/../../Fixtures/v4.jpg');
+
+ Route::get('/', fn (): string => '
');
+ Route::get('/image', fn (): StreamedResponse => response()->stream(
+ function () use ($image): void {
+ echo $image;
+ },
+ 200,
+ ['Content-Type' => 'image/jpeg'],
+ ));
+
+ $page = visit('/');
+
+ $page->assertScript("document.getElementById('image').complete && document.getElementById('image').naturalWidth > 0");
+});
+
+it('may serve a textual streamed response without altering its whitespace', function (): void {
+ Route::get('/', fn (): string => 'Home
');
+ Route::get('/text', fn (): StreamedResponse => response()->stream(
+ function (): void {
+ echo "\n Hello World \n";
+ },
+ 200,
+ ['Content-Type' => 'text/plain'],
+ ));
+
+ $page = visit('/');
+
+ $page->assertScript(
+ "async () => JSON.stringify(await (await fetch('/text')).text())",
+ json_encode("\n Hello World \n"),
+ );
+});
+
+it('delivers every server-sent event to the browser', function (): void {
+ Route::get('/', fn (): string => '-
+ ');
+ Route::get('/events', fn (): StreamedResponse => response()->stream(
+ function (): void {
+ echo "data: first\n\n";
+ echo "data: second\n\n";
+ },
+ 200,
+ ['Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache'],
+ ));
+
+ $page = visit('/');
+
+ $page->assertSee('first');
+
+ expect($page->text('#received'))->toBe('first,second');
+});