-
-
Notifications
You must be signed in to change notification settings - Fork 145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support parsing urlencoded request body (RequestBodyParserMiddleware) #220
Support parsing urlencoded request body (RequestBodyParserMiddleware) #220
Conversation
/** | ||
* @param bool $keepOriginalBody Keep the original body after parsing or not | ||
*/ | ||
public function __construct($keepOriginalBody = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be true
by default to replicate PHP's default behaviour (and that of most PSR-7 implementations)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree 👍 I'd also vote to completely remove this parameter for now as the motivation is a bit unclear, plus we can still add this in a follow-up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done 👍
I'd prefer a dedicated |
I'd also prefer a dedicated middleware per type but on the other |
} | ||
|
||
try { | ||
$value = $this->types[$type]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$value
might be a bit unclear here. Maybe something more readable like $request = $parser($request)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done 👍
/** @var ServerRequestInterface $request */ | ||
$request = $value($request); | ||
} catch (\Exception $e) { | ||
return $next($request); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we log somehow the parsing failure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could allow a PSR-3
logger as constructor argument and log errors to it, or emit errors as Server
does
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be interesting what PHP's behaviour is in case of invalid request bodies. I think we should probably follow that behaviour.
@jsor @christoph-kluge The thing is this set up allows us to add more types in the future, infect I already have a multipart PR ready for when this PR is merged: final class RequestBodyParserMiddleware
{
private $types = array();
public function __construct()
{
$this->addType('application/x-www-form-urlencoded', function (ServerRequestInterface $request) {
$ret = array();
parse_str((string)$request->getBody(), $ret);
return $request->withParsedBody($ret);
});
$this->addType('multipart/form-data', function (ServerRequestInterface $request) {
return MultipartParser::parseRequest($request);
});
$this->addType('multipart/mixed', function (ServerRequestInterface $request) {
return MultipartParser::parseRequest($request);
});
}
} |
@WyriHaximus That would be the |
@jsor With solid defaults, which can be extended. But I get your point will file a PRs for both |
After discussing this PR with @clue and @jsor we decided to go with a slight alteration in this middleware. or view command line instructions: removing the ability to add additional parsers for custom types and only to include parsers for body types from the HTTP 1.0/1.1/2.0 specs. I'll add documentation later today |
README.md
Outdated
|
||
```php | ||
$middlewares = new MiddlewareRunner([ | ||
new RequestBodyParserMiddleware(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably have added the RequestBodyBufferMiddleware
before to document the requirement.
{ | ||
$type = $request->getHeaderLine('Content-Type'); | ||
|
||
if ($type === 'application/x-www-form-urlencoded') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to find out since ever if header field values are case-sensitive. I'm talking only about the values, as header names are clearly defined case-insensitive. I've only found some definitions for specific header values, eg. for Connect
or Transfer Coding names.
Not sure, but it probably won't hurt to lowercase $type
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure either, but I've updated the middleware forcing it to lowercase 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the reference: This change is correct 👍 Header field values are not case-insensitive per se, but only for certain header field names, including this one:
The type, subtype, and parameter name tokens are case-insensitive.
https://tools.ietf.org/html/rfc7231#section-3.1.1.1 and https://tools.ietf.org/html/rfc1866#section-8.2.1
README.md
Outdated
@@ -725,6 +726,38 @@ $middlewares = new MiddlewareRunner([ | |||
]); | |||
``` | |||
|
|||
#### RequestBodyParserMiddleware | |||
|
|||
Another built-in middleware is `RequestBodyParserMiddleware` which takes a fully buffered request body |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should read just
The
RequestBodyParserMiddleware
takes a fully buffered request body...
Referring to previous paragraphs and repeating "built-in middleware..." might be become tedious once we add more and more middleware.
@WyriHaximus as successor of #223 this PR is now missing the multipart parts? Will multipart be another middleware or integrated here? |
@andig multipart will be filed in a follow up PR once this one is in. |
I like the direction this PR is heading and agree that it makes sense to keep "default body parsers" ("what PHP does") in a single middleware because it's unlikely a consumer would want to access individual parsers anyway. As described by @WyriHaximus, multipart handling will be added to the same code base in a separate PR. I'm currently in the process of rebasing and squashing some of these changes and will update this PR with some added tests. Other than that, this LGTM |
{ | ||
$type = strtolower($request->getHeaderLine('Content-Type')); | ||
|
||
if ($type === 'application/x-www-form-urlencoded') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to copy from here :) https://github.com/slimphp/Slim/blob/3.x/Slim/Http/Request.php#L204-L241
Great work btw :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #225 :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clue awesome 🎉 |
91d8d5c
to
a0c8de7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! 🎉 I've rebased your changes and squashed a number of related commits after adding some tests to ensure this has 100% coverage, now let's get this in!
|
||
use Psr\Http\Message\ServerRequestInterface; | ||
|
||
final class RequestBodyParserMiddleware |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to not see final in this case. There are literally a metric ton of different request body formats and this is rather limiting (from the perspective of a http framework). XML, Json, form-urlencoded are only the most popular however there are many custom encodings as well.
For framework usage it would be nice to be able extend.
Also it's possible to have a mixture of encoding types inside an application (I know it sounds weird, but it happens... a lot).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@geggleto going to provide a third party middleware that allows this as I also have a use for it 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #225 :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Body parser for #215
To be used with #216
Todo: