Skip to content

Commit 28be270

Browse files
committed
Basic support for multipart and files
# Conflicts: # src/Drivers/LaravelHttpServer.php # tests/Unit/Drivers/Laravel/LaravelHttpServerTest.php
1 parent 0ed837a commit 28be270

5 files changed

Lines changed: 612 additions & 14 deletions

File tree

src/Drivers/LaravelHttpServer.php

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616
use Illuminate\Contracts\Debug\ExceptionHandler;
1717
use Illuminate\Contracts\Http\Kernel as HttpKernel;
1818
use Illuminate\Foundation\Testing\Concerns\WithoutExceptionHandlingHandler;
19+
use Illuminate\Http\Concerns\InteractsWithInput;
1920
use Illuminate\Http\Request;
21+
use Illuminate\Http\UploadedFile;
2022
use Illuminate\Routing\UrlGenerator;
2123
use Illuminate\Support\Uri;
2224
use Pest\Browser\Contracts\HttpServer;
2325
use Pest\Browser\Exceptions\ServerNotFoundException;
2426
use Pest\Browser\Execution;
2527
use Pest\Browser\GlobalState;
28+
use Pest\Browser\Http\RequestBodyParser;
2629
use Pest\Browser\Playwright\Playwright;
2730
use Psr\Log\NullLogger;
31+
use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile;
2832
use Symfony\Component\Mime\MimeTypes;
2933
use Throwable;
3034

@@ -50,14 +54,19 @@ final class LaravelHttpServer implements HttpServer
5054
*/
5155
private ?Throwable $lastThrowable = null;
5256

57+
/**
58+
* A body parser for url-encoded and multipart requests
59+
*/
60+
private RequestBodyParser $requestBodyParser;
61+
5362
/**
5463
* Creates a new laravel http server instance.
5564
*/
5665
public function __construct(
5766
public readonly string $host,
5867
public readonly int $port,
5968
) {
60-
//
69+
$this->requestBodyParser = new RequestBodyParser();
6170
}
6271

6372
/**
@@ -237,10 +246,9 @@ private function handleRequest(AmpRequest $request): Response
237246

238247
$kernel = app()->make(HttpKernel::class);
239248

240-
$contentType = $request->getHeader('content-type') ?? '';
241249
$method = mb_strtoupper($request->getMethod());
242250
$rawBody = (string) $request->getBody();
243-
$parameters = [];
251+
[$parameters, $files] = $this->requestBodyParser->parseForm($request, $rawBody);
244252
if ($method !== 'GET' && str_starts_with(mb_strtolower($contentType), 'application/x-www-form-urlencoded')) {
245253
parse_str($rawBody, $parameters);
246254
}
@@ -254,23 +262,13 @@ private function handleRequest(AmpRequest $request): Response
254262
$method,
255263
$parameters,
256264
$cookies,
257-
[], // @TODO files...
265+
$this->convertUploadedFiles($files),
258266
$serverVariables,
259267
$rawBody
260268
);
261269

262270
$symfonyRequest->headers->add($request->getHeaders());
263271

264-
// Set the Host header to match the configured host for subdomain routing
265-
$configuredHost = Playwright::host();
266-
if ($configuredHost !== null) {
267-
$hostHeader = sprintf('%s:%d', $configuredHost, $this->port);
268-
$symfonyRequest->headers->set('Host', $hostHeader);
269-
// Also set SERVER_NAME for Laravel routing
270-
$symfonyRequest->server->set('SERVER_NAME', $configuredHost);
271-
$symfonyRequest->server->set('HTTP_HOST', $hostHeader);
272-
}
273-
274272
$debug = config('app.debug');
275273

276274
try {
@@ -312,6 +310,24 @@ private function handleRequest(AmpRequest $request): Response
312310
);
313311
}
314312

313+
/**
314+
* Taken from Laravel because we can't manipulate the test flag
315+
*
316+
* @param array<SymfonyUploadedFile[]|SymfonyUploadedFile> $files
317+
* @return array<UploadedFile[]|UploadedFile>
318+
*
319+
* @see InteractsWithInput
320+
*/
321+
private function convertUploadedFiles(array $files): array
322+
{
323+
// @phpstan-ignore-next-line
324+
return array_map(function (array|SymfonyUploadedFile $file) {
325+
return is_array($file)
326+
? $this->convertUploadedFiles($file)
327+
: UploadedFile::createFromBase($file, true);
328+
}, $files);
329+
}
330+
315331
/**
316332
* Return an asset response.
317333
*/

0 commit comments

Comments
 (0)