fix: parse multipart/form-data request bodies in LaravelHttpServer - #252
Open
Llewdur wants to merge 1 commit into
Open
fix: parse multipart/form-data request bodies in LaravelHttpServer#252Llewdur wants to merge 1 commit into
Llewdur wants to merge 1 commit into
Conversation
`handleRequest()` only understood `application/x-www-form-urlencoded` bodies, so a real file upload driven through the browser (a `<input type="file">` set via a `File`/`DataTransfer`, or any `FormData` submit) reached the in-process test server as an unparsed multipart body: no fields, no files, and `Request::create()` was always given `[]` for its files argument (the `// @todo files...`). Add `Support\MultipartFormDataParser`, a small, framework-agnostic parser that turns a raw multipart body into the `[$parameters, $files]` shape `Symfony\Component\HttpFoundation\Request::create()` expects. Uploaded parts are written to temp files and described in the same `$_FILES`-style array PHP itself produces, including for bracketed field names (`documents[]`) - `FileBag::fixPhpFilesArray()` normalizes either shape, so this doesn't need to special-case it. An empty file input (no file chosen) is reported as `UPLOAD_ERR_NO_FILE`, matching a real PHP SAPI. Verified directly against `symfony/http-foundation`'s `Request::create()` and `FileBag`: bracketed multi-file fields convert into a list of real `UploadedFile` instances with the right original names and on-disk content.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LaravelHttpServer::handleRequest()only parsesapplication/x-www-form-urlencodedbodies. A multipart request — theshape a real
<input type="file">produces when submitted through thebrowser — reaches the in-process test server with its body untouched,
and
Request::create()is always called with[]for its$filesargument (the
// @TODO files...). Concretely: any Laravel app testinga file upload through
visit()gets a 422 from its Form Request,because the file never arrives.
This PR adds
Support\MultipartFormDataParser, a small, dependency-freeparser that turns a raw
multipart/form-databody into the[$parameters, $files]shapeSymfony\Component\HttpFoundation\Request::create()expects, and wires it into
handleRequest()alongside the existingurlencoded branch.
Details
$parameters, uploaded parts are writtento a temp file and described in the same
$_FILES-style array PHP'sown SAPI produces (
name/type/tmp_name/error/size).documents[],meta[address]) are supportedvia a small recursive path-setter that mirrors how PHP itself parses
bracketed form field names — this covers both single- and
multi-file inputs.
UPLOAD_ERR_NO_FILE, matching what a real PHP SAPI does, rather thanbeing silently dropped or treated as a zero-byte file.
Symfony\Component\HttpFoundation\FileBag::fixPhpFilesArray()already normalizes either the "normal" nested shape or PHP's own
quirky flattened
$_FILESshape, so the parser only needs to buildthe straightforward nested one.
Testing
Unit tests are included at
tests/Unit/Support/MultipartFormDataParserTest.phpcovering: plain text fields (including multi-line values), a single
file upload, an empty file input, and repeated bracketed fields
(
tags[],documents[]) collecting into a list for both text and fileparts.
I wasn't able to run this repo's own suite locally (the sandbox I'm
working from is missing
ext-dom, whichpestphp/pestitself needs toboot), so I verified the parser two ways instead, both passing:
against
MultipartFormDataParser::parse().Symfony\Component\HttpFoundation\Request::create()+FileBag— confirming a bracketed multi-file field converts into alist of genuine
UploadedFileinstances with the correct originalnames and on-disk content, i.e. exactly what
handleRequest()doeswith the parser's output.
Happy to adjust anything CI flags once it runs, or to add a
visit()-level Browser test exercising an actual
<input type="file">if that'spreferred over (or in addition to) the unit tests.
Related
We hit this while trying to write a browser test for a document-upload
flow in our own app and found the
// @TODO files...— this closes thatgap for us and (hopefully) for anyone else hitting the same 422.