Browse Source

Merge pull request #1380 from ceeram/2.4-ext

Set extension with multiple accept based on order in parseExtensions.
Mark Story 12 years ago
parent
commit
94db8fbed6

+ 15 - 6
lib/Cake/Controller/Component/RequestHandlerComponent.php

@@ -144,6 +144,9 @@ class RequestHandlerComponent extends Component {
  * 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.
@@ -155,13 +158,19 @@ class RequestHandlerComponent extends Component {
 		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;
 			}
 		}
 	}

+ 24 - 1
lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php

@@ -229,7 +229,10 @@ class RequestHandlerComponentTest extends CakeTestCase {
 	}
 
 /**
- * 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
  */
@@ -239,7 +242,27 @@ class RequestHandlerComponentTest extends CakeTestCase {
 		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);
 	}
 
 /**