Skip to content

Commit

Permalink
Set extension with multiple accept based on order in parseExtensions,…
Browse files Browse the repository at this point in the history
… currently with multiple accepted types, no extension is set at all
  • Loading branch information
ceeram committed Jun 27, 2013
1 parent 19c94d0 commit 6a0185d
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
21 changes: 15 additions & 6 deletions lib/Cake/Controller/Component/RequestHandlerComponent.php
Expand Up @@ -144,6 +144,9 @@ public function initialize(Controller $controller) {
* Compares the accepted types and configured extensions.
* If there is one common type, that is assigned as the ext/content type
* for the response.
* Type with the highest weight will be set. If the highest weight has more
* then one type matching the extensions, the order in which extensions are specified
* determines which type will be set.
*
* If html is one of the preferred types, no content type will be set, this
* is to avoid issues with browsers that prefer html and several other content types.
Expand All @@ -155,13 +158,19 @@ protected function _setExtension() {
if (empty($accept)) {
return;
}

$accepts = $this->response->mapType($this->request->parseAccept());
$preferedTypes = current($accepts);
if (array_intersect($preferedTypes, array('html', 'xhtml'))) {
return null;
}

$extensions = Router::extensions();
$preferred = array_shift($accept);
$preferredTypes = $this->response->mapType($preferred);
if (!in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) {
$similarTypes = array_intersect($extensions, $preferredTypes);
if (count($similarTypes) === 1) {
$this->ext = array_shift($similarTypes);
foreach ($accepts as $types) {
$ext = array_intersect($extensions, $types);
if ($ext) {
$this->ext = current($ext);
break;
}
}
}
Expand Down
Expand Up @@ -229,7 +229,10 @@ public function testInitializeNoContentTypeWithSingleAccept() {
}

/**
* Test that ext is not set with multiple accepted content types.
* Test that ext is set to the first listed extension with multiple accepted
* content types.
* Having multiple types accepted with same weight, means the client lets the
* server choose the returned content type.
*
* @return void
*/
Expand All @@ -239,7 +242,27 @@ public function testInitializeNoContentTypeWithMultipleAcceptedTypes() {
Router::parseExtensions('xml', 'json');

$this->RequestHandler->initialize($this->Controller);
$this->assertEquals('xml', $this->RequestHandler->ext);

$this->RequestHandler->ext = null;
Router::setExtensions(array('json', 'xml'), false);

$this->RequestHandler->initialize($this->Controller);
$this->assertEquals('json', $this->RequestHandler->ext);
}

/**
* Test that ext is set to type with highest weight
*
* @return void
*/
public function testInitializeContentTypeWithMultipleAcceptedTypes() {
$_SERVER['HTTP_ACCEPT'] = 'text/csv;q=1.0, application/json;q=0.8, application/xml;q=0.7';
$this->assertNull($this->RequestHandler->ext);
Router::parseExtensions('xml', 'json');

$this->RequestHandler->initialize($this->Controller);
$this->assertEquals('json', $this->RequestHandler->ext);
}

/**
Expand Down

0 comments on commit 6a0185d

Please sign in to comment.