-
Notifications
You must be signed in to change notification settings - Fork 235
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
Detect correct type on request when there are multiple media types mapped to the same content type #1335
base: 1.2
Are you sure you want to change the base?
Conversation
…Media` with the same content types, even when distinguished by `conditions`, an instance of `lithium\net\http\Request` will fail to determine the correct type to use to decode the request body. For example, if we register another type which use 'application/json' as a content type like this: ```php use lithium\net\http\Media; Media::type('json_base64', ['application/json'], [ 'encode' => function ($data) { return base64_encode(json_encode($data)); }, 'decode' => function ($data) { return json_decode(base64_decode($data), true); }, 'cast' => true, 'conditions' => [ 'http:content_transfer_encoding' => 'base64' ] ]); ``` In this case, a call to `Media::type('application/json')` will return an array like: ```php [ 'json_base64', 'json' ] ``` This case is not handled by `lithium\net\http\Message::type`, which causes `lithium\net\http\Request::$_type to be assigned as the content type of 'application/json'. Futhermore, when `Request::body` is called to decode the request body, the Media class fails to find a handler for 'application/json' (it expects a short name like 'json'). To fix this, `lithium\net\http\Message::type` must be extended by `lithium\net\http\Request`. In the case that the type is still a full content type like 'application/json', we can loop over each short name returned by `Media::type` and attempt to match the request like this: ```php public function type($type = null) { $type = parent::type($type); $media = $this->_classes['media']; if (strpos($type, '/') !== false) { $data = $media::type($type); if (is_array($data) && !isset($data['content'])) { foreach ($data as $short_type) { $conf = $media::type($short_type); if ($media::match($this, $conf)) { $type = $short_type; break; } } } } return $this->_type = $type; } ``` This will correctly determine a single short name to use for the type of the request data, and it can now correctly decode the request body.
`lithium\net\http\Media::match`, which expects the Request::get() method to be available.
…er if it is already set via configuration
@mariuswilms I don't recall, is this on the critical path for the request/response loop? If so, it should probably be benchmarked for performance impact. |
This issue also exists in this situation when attempting to find the correct type on \lithium\net\http\Response given only the Content-Type header. I only implemented this fix on the Request however, since it depended on Media::match, which in turn expects an instance of \lithium\action\Request as an argument. Ideally, this would be a part of \lithium\net\http\Message::type(), but it would require that we have the functionality of \lithium\action\Request on the Message class (e.g. is() and get()). |
In the case where multiple types are registered to
lithium\net\http\Media
with the same content type, even when distinguished byconditions
, an instance oflithium\action\Request
will fail to determine the correct type to use to decode the request body. For example, if we register another type which uses 'application/json' as a content type like this:A call to
Media::type('application/json')
will return an array like:This case is not handled by
lithium\net\http\Message::type()
, which causeslithium\action\Request::$_type
to be assigned as the content type of 'application/json'.Futhermore, when
Request::body()
is called to decode the request body, the Media class fails to find a handler for 'application/json' (it expects a short name like 'json').To fix this,
lithium\net\http\Message::type()
must be extended bylithium\action\Request
. In the case that$type
is a string and equals the result of the parent's call, we can loop over each type returned byMedia::type()
and attempt to match the request to it like this:This will correctly determine a single short name to use for the type of the request data, and it can now correctly decode the request body.