diff --git a/action/Request.php b/action/Request.php index b427e0e37e..690ee7a2f3 100644 --- a/action/Request.php +++ b/action/Request.php @@ -620,9 +620,17 @@ public function is($flag) { /** * Sets/Gets the content type. If `'type'` is null, the method will attempt to determine the - * type from the params, then from the environment setting + * type from the params, then from the environment setting. * - * @param string $type a full content type i.e. `'application/json'` or simple name `'json'` + * Handle the case where a single type could not be determined by a call to + * `lithium\net\http\Media::type` in `lithium\net\nttp\Message::type`. + * In that case, the value of `$type` is returned from the parent as it + * was passed in. Attempt to use `lithium\net\http\Media::match` to + * distinguish which type to use for the request. The type is later used to + * decode the request body. Not handling this case leads to the correct + * type's decoder not being invoked on the body of the request. + * + * @param string $type A full content type i.e. `'application/json'` or simple name `'json'` * @return string A simple content type name, i.e. `'html'`, `'xml'`, `'json'`, etc., depending * on the content type of the request. */ @@ -630,7 +638,22 @@ public function type($type = null) { if (!$type && !empty($this->params['type'])) { $type = $this->params['type']; } - return parent::type($type); + $_type = parent::type($type); + if (is_string($type) && $_type === $type) { + $media = $this->_classes['media']; + $content = $media::type($type); + if (is_array($content) && !isset($content['content'])) { + foreach ($content as $short_type) { + $conf = $media::type($short_type); + $conf['name'] = $short_type; + if ($media::match($this, $conf)) { + $_type = $short_type; + break; + } + } + } + } + return ($this->_type = $_type); } /** @@ -803,4 +826,4 @@ protected function _parseFiles($data) { } } -?> \ No newline at end of file +?> diff --git a/net/http/Request.php b/net/http/Request.php index 695a1709a1..7fa35098d9 100644 --- a/net/http/Request.php +++ b/net/http/Request.php @@ -355,4 +355,4 @@ public function __toString() { } } -?> \ No newline at end of file +?> diff --git a/net/http/Response.php b/net/http/Response.php index bd2f01a288..b4f5a3e679 100644 --- a/net/http/Response.php +++ b/net/http/Response.php @@ -147,7 +147,7 @@ public function __construct(array $config = []) { $header = is_array($header) ? end($header) : $header; preg_match('/([-\w\/\.+]+)(;\s*?charset=(.+))?/i', $header, $match); - if (isset($match[1])) { + if (!$this->_type && isset($match[1])) { $this->type(trim($match[1])); } if (isset($match[3])) { @@ -437,4 +437,4 @@ public function __toString() { } } -?> \ No newline at end of file +?> diff --git a/tests/cases/action/RequestTest.php b/tests/cases/action/RequestTest.php index d9c22f6294..c1a41ee5e1 100644 --- a/tests/cases/action/RequestTest.php +++ b/tests/cases/action/RequestTest.php @@ -11,6 +11,7 @@ use lithium\core\Libraries; use lithium\action\Request; +use lithium\net\http\Media; class RequestTest extends \lithium\test\Unit { @@ -83,6 +84,7 @@ public function tearDown() { foreach ($this->_superglobals as $varname) { $GLOBALS[$varname] = $this->_env[$varname]; } + Media::reset(); } public function testInitData() { @@ -488,6 +490,34 @@ public function testContentTypeDetection() { $this->assertFalse($request->is('foo')); } + public function testContentTypeDetectionWithMultipleChoices() { + 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' + ] + ]); + $request = new Request(['env' => [ + 'CONTENT_TYPE' => 'application/json; charset=UTF-8', + 'REQUEST_METHOD' => 'POST' + ]]); + $this->assertTrue($request->is('json')); + $this->assertFalse($request->is('json_base64')); + $request = new Request(['env' => [ + 'CONTENT_TYPE' => 'application/json; charset=UTF-8', + 'REQUEST_METHOD' => 'POST', + 'HTTP_CONTENT_TRANSFER_ENCODING' => 'base64' + ]]); + $this->assertTrue($request->is('json_base64')); + $this->assertFalse($request->is('json')); + } + public function testIsMobile() { $iPhone = 'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like '; $iPhone .= 'Gecko) Version/3.0 Mobile/1A535b Safari/419.3'; @@ -1596,4 +1626,4 @@ public function testOverridingOfEnvVariables() { } } -?> \ No newline at end of file +?>