Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions src/Drivers/LaravelHttpServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,33 +317,33 @@ private function handleRequest(AmpRequest $request): Response
*/
private function asset(string $filepath): Response
{
$file = fopen($filepath, 'r');

if ($file === false) {
return new Response(404);
}

$mimeTypes = new MimeTypes();
$contentType = $mimeTypes->getMimeTypes(pathinfo($filepath, PATHINFO_EXTENSION));

$contentType = $contentType[0] ?? 'application/octet-stream';

if (str_ends_with($filepath, '.js')) {
$temporaryStream = fopen('php://temp', 'r+');
assert($temporaryStream !== false, 'Failed to open temporary stream.');

// @phpstan-ignore-next-line
$temporaryContent = fread($file, (int) filesize($filepath));

assert($temporaryContent !== false, 'Failed to open temporary stream.');
// ReadableResourceStream sets php://temp to non-blocking mode, causing
// AMPHP's event loop to deliver only the first 8192-byte chunk for files
// written to a php://temp stream. Using file_get_contents + a string body
// sends the full content in one shot, avoiding the truncation.
$content = file_get_contents($filepath);

if ($content === false) {
return new Response(404);
}

$content = $this->rewriteAssetUrl($temporaryContent);
$content = $this->rewriteAssetUrl($content);

fwrite($temporaryStream, $content);
return new Response(200, [
'Content-Type' => $contentType,
'Content-Length' => (string) strlen($content),
], $content);
}

rewind($temporaryStream);
$file = fopen($filepath, 'r');

$file = $temporaryStream;
if ($file === false) {
return new Response(404);
}

return new Response(200, [
Expand Down
13 changes: 13 additions & 0 deletions tests/Unit/Drivers/Laravel/LaravelHttpServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@
->assertDontSee('http://localhost');
});

it('serves JS files larger than 8192 bytes in full without truncation', function (): void {
// Create a JS file well over 8KB with a sentinel value at the very end.
// Before the fix, ReadableResourceStream on a php://temp stream would only
// deliver the first 8192-byte chunk, so the sentinel would be missing.
$padding = str_repeat('//' . str_repeat('x', 78) . PHP_EOL, 110); // ~8250 bytes of padding
@file_put_contents(
public_path('large.js'),
$padding . "console.log('END_SENTINEL');",
);

visit('/large.js')->assertSee('END_SENTINEL');
});

it('includes cookies set in the test', function (): void {
Route::get('/cookies', fn (Request $request): array => $request->cookies->all());

Expand Down