Browse Source

More gracefully handle invalid data in Accept headers.

Some browsers have invalid accept headers, we should ignore the invalid
extension data as assuming it will be a qualifier can result in
incorrect results.

Fixes #4105
mark_story 12 years ago
parent
commit
530731ec5d

+ 18 - 8
lib/Cake/Network/CakeRequest.php

@@ -777,7 +777,10 @@ class CakeRequest implements ArrayAccess {
 	}
 
 /**
- * Parse Accept* headers with qualifier options
+ * Parse Accept* headers with qualifier options.
+ *
+ * Only qualifiers will be extracted, any other accept extensions will be
+ * discarded as they are not frequently used.
  *
  * @param string $header
  * @return array
@@ -786,14 +789,21 @@ class CakeRequest implements ArrayAccess {
 		$accept = array();
 		$header = explode(',', $header);
 		foreach (array_filter($header) as $value) {
-			$prefPos = strpos($value, ';');
-			if ($prefPos !== false) {
-				$prefValue = substr($value, strpos($value, '=') + 1);
-				$value = trim(substr($value, 0, $prefPos));
-			} else {
-				$prefValue = '1.0';
-				$value = trim($value);
+			$prefValue = '1.0';
+			$value = trim($value);
+
+			$semiPos = strpos($value, ';');
+			if ($semiPos !== false) {
+				$params = explode(';', $value);
+				$value = trim($params[0]);
+				foreach ($params as $param) {
+					$qPos = strpos($param, 'q=');
+					if ($qPos !== false) {
+						$prefValue = substr($param, $qPos + 2);
+					}
+				}
 			}
+
 			if (!isset($accept[$prefValue])) {
 				$accept[$prefValue] = array();
 			}

+ 13 - 0
lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php

@@ -280,6 +280,19 @@ class RequestHandlerComponentTest extends CakeTestCase {
 	}
 
 /**
+ * Test that the headers sent by firefox are not treated as XML requests.
+ *
+ * @return void
+ */
+	public function testInititalizeFirefoxHeaderNotXml() {
+		$_SERVER['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;image/png,image/jpeg,image/*;q=0.9,*/*;q=0.8';
+		Router::parseExtensions('xml', 'json');
+
+		$this->RequestHandler->initialize($this->Controller);
+		$this->assertNull($this->RequestHandler->ext);
+	}
+
+/**
  * Test that a type mismatch doesn't incorrectly set the ext
  *
  * @return void

+ 36 - 0
lib/Cake/Test/Case/Network/CakeRequestTest.php

@@ -1158,6 +1158,42 @@ class CakeRequestTest extends CakeTestCase {
 	}
 
 /**
+ * Test parsing accept ignores index param
+ *
+ * @return void
+ */
+	public function testParseAcceptIgnoreAcceptExtensions() {
+		$_SERVER['HTTP_ACCEPT'] = 'application/json;level=1, text/plain, */*';
+
+		$request = new CakeRequest('/', false);
+		$result = $request->parseAccept();
+		$expected = array(
+			'1.0' => array('application/json', 'text/plain', '*/*'),
+		);
+		$this->assertEquals($expected, $result);
+	}
+
+
+/**
+ * Test that parsing accept headers with invalid syntax works.
+ *
+ * The header used is missing a q value for application/xml.
+ *
+ * @return void
+ */
+	public function testParseAcceptInvalidSyntax() {
+		$_SERVER['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;image/png,image/jpeg,image/*;q=0.9,*/*;q=0.8';
+		$request = new CakeRequest('/', false);
+		$result = $request->parseAccept();
+		$expected = array(
+			'1.0' => array('text/html', 'application/xhtml+xml', 'application/xml', 'image/jpeg'),
+			'0.9' => array('image/*'),
+			'0.8' => array('*/*'),
+		);
+		$this->assertEquals($expected, $result);
+	}
+
+/**
  * Test baseUrl and webroot with ModRewrite
  *
  * @return void