From 2677d79871ffcca3cd74a4d5d63d408a8497a5b1 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Sun, 1 Nov 2015 23:36:11 -0600 Subject: [PATCH] NegotiateMedia command can recognize types and subtypes now. --- system/HTTP/Message.php | 68 ++++++++++++++++++++++++++++++++------ tests/HTTP/MessageTest.php | 24 +++++++++++++- 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/system/HTTP/Message.php b/system/HTTP/Message.php index f12ad10cd6..453086e2a3 100644 --- a/system/HTTP/Message.php +++ b/system/HTTP/Message.php @@ -296,7 +296,7 @@ class Message */ public function negotiateMedia(array $supported): string { - return $this->getBestMatch($supported, $this->header('accept')); + return $this->getBestMatch($supported, $this->header('accept'), true); } //-------------------------------------------------------------------- @@ -385,12 +385,13 @@ class Message * * Portions of this code base on Aura.Accept library. * - * @param array $supported App-supported values - * @param string $header header string + * @param array $supported App-supported values + * @param string $header header string + * @param bool $enforceTypes If TRUE, will compare media types and sub-types. * * @return string Best match */ - protected function getBestMatch(array $supported, string $header=null): string + protected function getBestMatch(array $supported, string $header=null, bool $enforceTypes=false): string { if (empty($supported)) { @@ -428,14 +429,14 @@ class Message // If an acceptable value is supported, return it foreach ($supported as $available) { - if ($this->match($accept, $available)) + if ($this->match($accept, $available, $enforceTypes)) { return $available; } } } - // No matches? return the first supported type + // No matches? Return the first supported element. return $supported[0]; } @@ -533,7 +534,7 @@ class Message //-------------------------------------------------------------------- - protected function match($acceptable, $supported) + protected function match(array $acceptable, string $supported, bool $enforceTypes=false) { $supported = $this->parseHeader($supported); if (is_array($supported) && count($supported) == 1) @@ -547,15 +548,28 @@ class Message return $this->matchParameters($acceptable, $supported); } + // Do we need to compare types/sub-types? Only used + // by negotiateMedia(). + if ($enforceTypes) + { + return $this->matchTypes($acceptable, $supported); + } - -// var_dump($acceptable); -// die(var_dump($supported)); + return false; } //-------------------------------------------------------------------- - protected function matchParameters($acceptable, $supported) + /** + * Checks two Accept values with matching 'values' to see if their + * 'params' are the same. + * + * @param array $acceptable + * @param array $supported + * + * @return bool + */ + protected function matchParameters(array $acceptable, array $supported): bool { if (count($acceptable['params']) != count($supported['params'])) { @@ -576,5 +590,37 @@ class Message //-------------------------------------------------------------------- + /** + * Compares the types/subtypes of an acceptable Media type and + * the supported string. + * + * @param array $acceptable + * @param array $supported + * + * @return bool + */ + public function matchTypes(array $acceptable, array $supported): bool + { + list($aType, $aSubType) = explode('/', $acceptable['value']); + list($sType, $sSubType) = explode('/', $supported['value']); + + // If the types don't match, we're done. + if ($aType != $sType) + { + return false; + } + + // If there's an asterisk, we're cool + if ($aSubType == '*') + { + return true; + } + + // Otherwise, subtypes must match also. + return $aSubType == $sSubType; + } + + //-------------------------------------------------------------------- + } diff --git a/tests/HTTP/MessageTest.php b/tests/HTTP/MessageTest.php index 6cf1d02ede..d8f846c396 100644 --- a/tests/HTTP/MessageTest.php +++ b/tests/HTTP/MessageTest.php @@ -158,7 +158,7 @@ class MessageTest extends PHPUnit_Framework_TestCase //-------------------------------------------------------------------- - public function testNegotiateMediaDeterminesCorrectPrecedence() + public function testParseHeaderDeterminesCorrectPrecedence() { $header =$this->message->parseHeader('text/*, text/plain, text/plain;format=flowed, */*'); @@ -170,5 +170,27 @@ class MessageTest extends PHPUnit_Framework_TestCase //-------------------------------------------------------------------- + public function testNegotiateMediaReturnsSupportedMatchWhenAsterisksInAvailable() + { + $this->message->setHeader('Accept', 'image/*, text/*'); + + $this->assertEquals('text/plain', $this->message->negotiateMedia(['text/plain'])); + } + + //-------------------------------------------------------------------- + + /** + * @group single + */ + public function testNegotiateMediaRecognizesMediaTypes() + { + // Image has a higher specificity, but is the wrong type... + $this->message->setHeader('Accept', 'text/*, image/jpeg'); + + $this->assertEquals('text/plain', $this->message->negotiateMedia(['text/plain'])); + } + + //-------------------------------------------------------------------- + }