From d1347ba8208a449c5aa0bf13cd7b65298c59257e Mon Sep 17 00:00:00 2001 From: William DURAND Date: Wed, 26 Feb 2014 14:55:43 +0100 Subject: [PATCH] Backport fix incorrect behavior with priorities See #24 --- src/Negotiation/FormatNegotiator.php | 21 +++++++++- .../Tests/FormatNegotiatorTest.php | 39 ++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/Negotiation/FormatNegotiator.php b/src/Negotiation/FormatNegotiator.php index 00e4d75..622ba31 100644 --- a/src/Negotiation/FormatNegotiator.php +++ b/src/Negotiation/FormatNegotiator.php @@ -28,10 +28,15 @@ public function getBest($header, array $priorities = array()) $acceptHeaders = $this->parseHeader($header); $priorities = $this->sanitize($priorities); $catchAllEnabled = $this->isCatchAllEnabled($priorities); + $catchAllHeader = null; foreach ($acceptHeaders as $accept) { $mimeType = $accept->getValue(); + if (self::CATCH_ALL_VALUE === $mimeType) { + $catchAllHeader = $accept; + } + if ('/*' !== substr($mimeType, -2)) { if (in_array($mimeType, $priorities)) { return $accept; @@ -68,7 +73,21 @@ public function getBest($header, array $priorities = array()) } } - // If $priorities is empty or contains a catch-all mime type + // if client sends `*/*` in Accept header, and nothing has been negotiated before + // then, return the first priority value if available + if (null !== $catchAllHeader) { + $value = array_shift($priorities); + + if (null !== $value && self::CATCH_ALL_VALUE !== $value) { + return new AcceptHeader( + $value, + $catchAllHeader->getQuality(), + $this->parseParameters($catchAllHeader->getValue()) + ); + } + } + + // if `$priorities` is empty or contains a catch-all mime type if ($catchAllEnabled) { return array_shift($acceptHeaders) ?: null; } diff --git a/tests/Negotiation/Tests/FormatNegotiatorTest.php b/tests/Negotiation/Tests/FormatNegotiatorTest.php index ad62a0a..5cd2502 100644 --- a/tests/Negotiation/Tests/FormatNegotiatorTest.php +++ b/tests/Negotiation/Tests/FormatNegotiatorTest.php @@ -144,7 +144,7 @@ public static function dataProviderForGetBest() 'application/rss+xml', '*/*', ), - 'text/html' + 'application/rss+xml' ), // See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html array( @@ -252,6 +252,41 @@ public static function dataProviderForGetBest() ), null ), + array( + 'text/rdf+n3; q=0.8, application/rdf+json; q=0.8, text/turtle; q=1.0, text/n3; q=0.8, application/ld+json; q=0.5, application/rdf+xml; q=0.8', + array(), + 'text/turtle' + ), + array( + 'application/rdf+xml;q=0.5,text/html;q=.3', + array(), + 'application/rdf+xml' + ), + array( + 'application/xhtml+xml;q=0.5', + array(), + 'application/xhtml+xml' + ), + array( + 'application/rdf+xml;q=0.5,text/html;q=.5', + array(), + 'application/rdf+xml' + ), + array( + 'text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c', + array(), + 'text/html', + ), + // IE8 Accept header + array( + 'image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, */*', + array( + 'text/html', + 'application/xhtml+xml', + '*/*' + ), + 'text/html', + ), ); } @@ -262,7 +297,7 @@ public static function dataProviderForGetBestFormat() array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array(), 'html'), array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array('html', 'json', '*/*'), 'html'), array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array('html', 'json', '*/*'), 'html'), - array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array('rss', '*/*'), 'html'), + array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array('rss', '*/*'), 'rss'), array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array('xml'), 'xml'), array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array('json', 'xml'), 'xml'), array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array('json'), 'json'),