From d730acba59156884f7a04428dbe3ce956ea7d337 Mon Sep 17 00:00:00 2001
From: Ceeram <c33ram@gmail.com>
Date: Thu, 9 Aug 2012 16:11:32 +0200
Subject: [PATCH] Add onlyAllow() to CakeRequest, to check if the request
 method matches the allowed ones. Throws exception if not matched, using the
 required Allow response header.

---
 lib/Cake/Network/CakeRequest.php              | 32 +++++++++++++++++
 .../Test/Case/Network/CakeRequestTest.php     | 34 +++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/lib/Cake/Network/CakeRequest.php b/lib/Cake/Network/CakeRequest.php
index cadbbbd0c..32d7c9744 100644
--- a/lib/Cake/Network/CakeRequest.php
+++ b/lib/Cake/Network/CakeRequest.php
@@ -803,6 +803,38 @@ class CakeRequest implements ArrayAccess {
 		return $input;
 	}
 
+/**
+ * Only allow certain HTTP request methods, if the request method does not match
+ * a 405 error will be shown and the required "Allow" response header will be set.
+ *
+ * Example:
+ *
+ * $this->request->onlyAllow('post', 'delete');
+ * or
+ * $this->request->onlyAllow(array('post', 'delete'));
+ *
+ * If the request would be GET, response header "Allow: POST, DELETE" will be set
+ * and a 405 error will be returned
+ *
+ * @param string|array $methods Allowed HTTP request methods
+ * @return boolean true
+ * @throws MethodNotAllowedException
+ */
+	public function onlyAllow($methods) {
+		if (!is_array($methods)) {
+			$methods = func_get_args();
+		}
+		foreach ($methods as $method) {
+			if ($this->is($method)) {
+				return true;
+			}
+		}
+		$allowed = strtoupper(implode(', ', $methods));
+		$e = new MethodNotAllowedException();
+		$e->responseHeader('Allow', $allowed);
+		throw $e;
+	}
+
 /**
  * Read data from php://input, mocked in tests.
  *
diff --git a/lib/Cake/Test/Case/Network/CakeRequestTest.php b/lib/Cake/Test/Case/Network/CakeRequestTest.php
index 8ef0e1868..7853a048d 100644
--- a/lib/Cake/Test/Case/Network/CakeRequestTest.php
+++ b/lib/Cake/Test/Case/Network/CakeRequestTest.php
@@ -1857,6 +1857,40 @@ XML;
 		$this->assertFalse($request->isRequested());
 	}
 
+/**
+ * TestOnlyAllow
+ *
+ * @return void
+ */
+	public function testOnlyAllow() {
+		$_SERVER['REQUEST_METHOD'] = 'PUT';
+		$request = new CakeRequest('/posts/edit/1');
+
+		$this->assertTrue($request->onlyAllow(array('put')));
+
+		$_SERVER['REQUEST_METHOD'] = 'DELETE';
+		$this->assertTrue($request->onlyAllow('post', 'delete'));
+	}
+
+/**
+ * TestOnlyAllow throwing exception
+ *
+ */
+	public function testOnlyAllowException() {
+		$_SERVER['REQUEST_METHOD'] = 'PUT';
+		$request = new CakeRequest('/posts/edit/1');
+
+		try {
+			$request->onlyAllow('POST', 'DELETE');
+			$this->fail('An expected exception has not been raised.');
+		} catch (MethodNotAllowedException $e) {
+			$this->assertEquals(array('Allow' => 'POST, DELETE'), $e->responseHeader());
+		}
+
+		$this->setExpectedException('MethodNotAllowedException');
+		$request->onlyAllow('POST');
+	}
+
 /**
  * loadEnvironment method
  *