From b46b8613833cca4233d95d0ea15c326dc88e4444 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 18:54:33 -0200 Subject: [PATCH 001/125] Removed unsed variable. --- cake/libs/cake_socket.php | 1 - 1 file changed, 1 deletion(-) diff --git a/cake/libs/cake_socket.php b/cake/libs/cake_socket.php index 3bcb7ca0a..e07b9837f 100644 --- a/cake/libs/cake_socket.php +++ b/cake/libs/cake_socket.php @@ -112,7 +112,6 @@ class CakeSocket { } if ($this->config['persistent'] == true) { - $tmp = null; $this->connection = @pfsockopen($scheme.$this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']); } else { $this->connection = @fsockopen($scheme.$this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']); From fb5495fad55c6590f1673af9616ee1109c94e6da Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 18:58:29 -0200 Subject: [PATCH 002/125] Throws an exception on fail in connect. --- cake/libs/cake_socket.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cake/libs/cake_socket.php b/cake/libs/cake_socket.php index e07b9837f..612d42e21 100644 --- a/cake/libs/cake_socket.php +++ b/cake/libs/cake_socket.php @@ -100,6 +100,7 @@ class CakeSocket { * Connect the socket to the given host and port. * * @return boolean Success + * @throws Exception */ public function connect() { if ($this->connection != null) { @@ -119,6 +120,7 @@ class CakeSocket { if (!empty($errNum) || !empty($errStr)) { $this->setLastError($errStr, $errNum); + throw new Exception($errStr, $errNum); } $this->connected = is_resource($this->connection); From 8c29847c8f262406879a3483860434e9d015203d Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 19:07:29 -0200 Subject: [PATCH 003/125] Simplified the CakeSocket and fixed some phpdocs. --- cake/libs/cake_socket.php | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/cake/libs/cake_socket.php b/cake/libs/cake_socket.php index 612d42e21..531c3b43a 100644 --- a/cake/libs/cake_socket.php +++ b/cake/libs/cake_socket.php @@ -138,9 +138,8 @@ class CakeSocket { public function host() { if (Validation::ip($this->config['host'])) { return gethostbyaddr($this->config['host']); - } else { - return gethostbyaddr($this->address()); } + return gethostbyaddr($this->address()); } /** @@ -151,9 +150,8 @@ class CakeSocket { public function address() { if (Validation::ip($this->config['host'])) { return $this->config['host']; - } else { - return gethostbyname($this->config['host']); } + return gethostbyname($this->config['host']); } /** @@ -164,9 +162,8 @@ class CakeSocket { public function addresses() { if (Validation::ip($this->config['host'])) { return array($this->config['host']); - } else { - return gethostbynamel($this->config['host']); } + return gethostbynamel($this->config['host']); } /** @@ -177,9 +174,8 @@ class CakeSocket { public function lastError() { if (!empty($this->lastError)) { return $this->lastError['num'] . ': ' . $this->lastError['str']; - } else { - return null; } + return null; } /** @@ -187,6 +183,7 @@ class CakeSocket { * * @param integer $errNum Error code * @param string $errStr Error string + * @return void */ public function setLastError($errNum, $errStr) { $this->lastError = array('num' => $errNum, 'str' => $errStr); @@ -230,17 +227,8 @@ class CakeSocket { return false; } return $buffer; - } else { - return false; } - } - -/** - * Abort socket operation. - * - * @return boolean Success - */ - public function abort() { + return false; } /** @@ -273,6 +261,7 @@ class CakeSocket { /** * Resets the state of this Socket instance to it's initial state (before Object::__construct got executed) * + * @param array $state Array with key and values to reset * @return boolean True on success */ public function reset($state = null) { From 2bed6622fec146234ead490323485b256d792b6b Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 21:00:57 -0200 Subject: [PATCH 004/125] Added tests to thown in connect. --- cake/tests/cases/libs/cake_socket.test.php | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cake/tests/cases/libs/cake_socket.test.php b/cake/tests/cases/libs/cake_socket.test.php index 48b304060..c14afbff6 100644 --- a/cake/tests/cases/libs/cake_socket.test.php +++ b/cake/tests/cases/libs/cake_socket.test.php @@ -101,6 +101,30 @@ class CakeSocketTest extends CakeTestCase { $this->assertTrue($this->Socket->connected); } +/** + * data provider function for testInvalidConnection + * + * @return array + */ + public static function invalidConnections() { + return array( + array(array('host' => 'invalid.host')), + array(array('host' => '127.0.0.1', 'port' => '70000')) + ); + } + +/** + * testInvalidConnection method + * + * @dataProvider invalidConnections + * @expectedException Exception + * return void + */ + public function testInvalidConnection($data) { + $this->Socket->config = array_merge($this->Socket->config, $data); + $this->Socket->connect(); + } + /** * testSocketHost method * From c6dd77de6f778dd7b4d7e48e7f78067336f1fcba Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 21:04:52 -0200 Subject: [PATCH 005/125] Removed unsed attribute. --- cake/libs/http_socket.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 9848446c4..2a2c6333e 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -30,14 +30,6 @@ App::import('Core', array('CakeSocket', 'Set', 'Router')); */ class HttpSocket extends CakeSocket { -/** - * Object description - * - * @var string - * @access public - */ - public $description = 'HTTP-based DataSource Interface'; - /** * When one activates the $quirksMode by setting it to true, all checks meant to * enforce RFC 2616 (HTTP/1.1 specs). From 8a4faa1e6921c5853507bd0be525bf5aaa063deb Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 21:12:40 -0200 Subject: [PATCH 006/125] Updated doc to avoid E_STRICT messages. --- cake/libs/http_socket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 2a2c6333e..3dea7ad28 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -138,12 +138,12 @@ class HttpSocket extends CakeSocket { * You can use a url string to set the url and use default configurations for * all other options: * - * `$http =& new HttpSockect('http://cakephp.org/');` + * `$http = new HttpSockect('http://cakephp.org/');` * * Or use an array to configure multiple options: * * {{{ - * $http =& new HttpSocket(array( + * $http = new HttpSocket(array( * 'host' => 'cakephp.org', * 'timeout' => 20 * )); From ef2a7d4608e5f531775d4b8fc5d77403858ca833 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 21:28:11 -0200 Subject: [PATCH 007/125] Replaced trigger_error by throw Exception. --- cake/libs/http_socket.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 3dea7ad28..b25020530 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -532,6 +532,7 @@ class HttpSocket extends CakeSocket { * * @param string $body A string continaing the chunked body to decode. * @return mixed Array of response headers and body or false. + * @throws Exception */ protected function _decodeChunkedBody($body) { if (!is_string($body)) { @@ -544,8 +545,7 @@ class HttpSocket extends CakeSocket { while ($chunkLength !== 0) { if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) { if (!$this->quirksMode) { - trigger_error(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk. Activate quirks mode to do this.'), E_USER_WARNING); - return false; + throw new Exception(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk. Activate quirks mode to do this.')); } break; } @@ -794,6 +794,7 @@ class HttpSocket extends CakeSocket { * @param array $request Needs to contain a 'uri' key. Should also contain a 'method' key, otherwise defaults to GET. * @param string $versionToken The version token to use, defaults to HTTP/1.1 * @return string Request line + * @throws Exception */ protected function _buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') { $asteriskMethods = array('OPTIONS'); @@ -801,8 +802,7 @@ class HttpSocket extends CakeSocket { if (is_string($request)) { $isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match); if (!$this->quirksMode && (!$isValid || ($match[2] == '*' && !in_array($match[3], $asteriskMethods)))) { - trigger_error(__('HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.'), E_USER_WARNING); - return false; + throw new Exception(__('HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.')); } return $request; } elseif (!is_array($request)) { @@ -816,8 +816,7 @@ class HttpSocket extends CakeSocket { $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query'); if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) { - trigger_error(sprintf(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.'), join(',', $asteriskMethods)), E_USER_WARNING); - return false; + throw new Exception(sprintf(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.'), join(',', $asteriskMethods))); } return $request['method'].' '.$request['uri'].' '.$versionToken.$this->lineBreak; } From 777afb6d3ebf201b06a27b77c0ba5c594ee87f8e Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 9 Nov 2010 23:03:43 -0200 Subject: [PATCH 008/125] separeted auth from HttpSocket. Refs #880 --- cake/libs/http/basic_method.php | 42 ++++++++++++++++ cake/libs/http_socket.php | 32 +++++++++--- .../cases/libs/http/basic_method.test.php | 49 +++++++++++++++++++ cake/tests/cases/libs/http_socket.test.php | 3 ++ 4 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 cake/libs/http/basic_method.php create mode 100644 cake/tests/cases/libs/http/basic_method.test.php diff --git a/cake/libs/http/basic_method.php b/cake/libs/http/basic_method.php new file mode 100644 index 000000000..da7951c6c --- /dev/null +++ b/cake/libs/http/basic_method.php @@ -0,0 +1,42 @@ +request['auth']['user'], $http->request['auth']['pass'])) { + $http->request['header']['Authorization'] = 'Basic ' . base64_encode($http->request['auth']['user'] . ':' . $http->request['auth']['pass']); + } + } + +} diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index b25020530..3def34cea 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -236,12 +236,7 @@ class HttpSocket extends CakeSocket { $this->request['header'] = array_merge(compact('Host'), $this->request['header']); } - if (isset($this->request['auth']['user']) && isset($this->request['auth']['pass'])) { - $this->request['header']['Authorization'] = $this->request['auth']['method'] . " " . base64_encode($this->request['auth']['user'] . ":" . $this->request['auth']['pass']); - } - if (isset($this->request['uri']['user']) && isset($this->request['uri']['pass'])) { - $this->request['header']['Authorization'] = $this->request['auth']['method'] . " " . base64_encode($this->request['uri']['user'] . ":" . $this->request['uri']['pass']); - } + $this->_setAuth(); if (is_array($this->request['body'])) { $this->request['body'] = $this->_httpSerialize($this->request['body']); @@ -439,6 +434,31 @@ class HttpSocket extends CakeSocket { return $this->_buildUri($url); } +/** + * Set authentication in request + * + * @return void + * @throws Exception + */ + protected function _setAuth() { + if (empty($this->request['auth']['method'])) { + if (isset($this->request['uri']['user'], $this->request['uri']['pass'])) { + $this->request['auth'] = array( + 'method' => 'Basic', + 'user' => $this->request['uri']['user'], + 'pass' => $this->request['uri']['pass'] + ); + } else { + return; + } + } + $authClass = Inflector::camelize($this->request['auth']['method']) . 'Method'; + if (!App::import('Lib', 'http/' . $authClass)) { + throw new Exception(__('Authentication method unknown.')); + } + $authClass::authentication($this); + } + /** * Parses the given message and breaks it down in parts. * diff --git a/cake/tests/cases/libs/http/basic_method.test.php b/cake/tests/cases/libs/http/basic_method.test.php new file mode 100644 index 000000000..c9d487f70 --- /dev/null +++ b/cake/tests/cases/libs/http/basic_method.test.php @@ -0,0 +1,49 @@ + + * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests + * @package cake + * @subpackage cake.tests.cases.libs.http + * @since CakePHP(tm) v 2.0.0 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::import('Core', 'HttpSocket'); +App::import('Lib', 'http/BasicMethod'); + +/** + * BasicMethodTest class + * + * @package cake + * @subpackage cake.tests.cases.libs.http + */ +class BasicMethodTest extends CakeTestCase { + +/** + * testAuthentication method + * + * @return void + */ + public function testAuthentication() { + $http = new HttpSocket(); + $http->request['auth'] = array( + 'method' => 'Basic', + 'user' => 'mark', + 'pass' => 'secret' + ); + + BasicMethod::authentication($http); + $this->assertEqual($http->request['header']['Authorization'], 'Basic bWFyazpzZWNyZXQ='); + } + +} \ No newline at end of file diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 5b3f79e0c..beb0fc0c5 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -694,14 +694,17 @@ class HttpSocketTest extends CakeTestCase { $socket->get('http://mark:secret@example.com/test'); $this->assertEqual($socket->request['uri']['user'], 'mark'); $this->assertEqual($socket->request['uri']['pass'], 'secret'); + $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); $socket->get('/test2'); $this->assertEqual($socket->request['auth']['user'], 'mark'); $this->assertEqual($socket->request['auth']['pass'], 'secret'); + $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); $socket->get('/test3'); $this->assertEqual($socket->request['auth']['user'], 'mark'); $this->assertEqual($socket->request['auth']['pass'], 'secret'); + $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); } /** From 1dfd3ce0b17568ca351322a2b49532998532685e Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 13 Nov 2010 13:40:00 -0200 Subject: [PATCH 009/125] Changing the auth value only if auth not is setted. --- cake/libs/http_socket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 3def34cea..7a595364e 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -442,7 +442,7 @@ class HttpSocket extends CakeSocket { */ protected function _setAuth() { if (empty($this->request['auth']['method'])) { - if (isset($this->request['uri']['user'], $this->request['uri']['pass'])) { + if (isset($this->request['uri']['user'], $this->request['uri']['pass']) && !isset($this->request['auth']['user'])) { $this->request['auth'] = array( 'method' => 'Basic', 'user' => $this->request['uri']['user'], From 1d56625f3a243e90733eb864fd2f4572abf6c713 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 13 Nov 2010 17:21:52 -0200 Subject: [PATCH 010/125] If method is false, dont send the authentication. Fixed throw message. --- cake/libs/http_socket.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 7a595364e..a903aa445 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -441,6 +441,9 @@ class HttpSocket extends CakeSocket { * @throws Exception */ protected function _setAuth() { + if ($this->request['auth']['method'] === false) { + return; + } if (empty($this->request['auth']['method'])) { if (isset($this->request['uri']['user'], $this->request['uri']['pass']) && !isset($this->request['auth']['user'])) { $this->request['auth'] = array( @@ -454,7 +457,7 @@ class HttpSocket extends CakeSocket { } $authClass = Inflector::camelize($this->request['auth']['method']) . 'Method'; if (!App::import('Lib', 'http/' . $authClass)) { - throw new Exception(__('Authentication method unknown.')); + throw new Exception(__('Unknown authentication method.')); } $authClass::authentication($this); } From 44629bd673e90ab65f42b871ae73c961ebac4118 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 13 Nov 2010 20:51:09 -0200 Subject: [PATCH 011/125] Support to digest method in HttpSocket. Thanks to jmcneese and Adrien Gibrat. --- cake/libs/http/digest_method.php | 103 ++++++++++ .../cases/libs/http/digest_method.test.php | 182 ++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 cake/libs/http/digest_method.php create mode 100644 cake/tests/cases/libs/http/digest_method.test.php diff --git a/cake/libs/http/digest_method.php b/cake/libs/http/digest_method.php new file mode 100644 index 000000000..42d0c9482 --- /dev/null +++ b/cake/libs/http/digest_method.php @@ -0,0 +1,103 @@ +request['auth']['user'], $http->request['auth']['pass'])) { + if (!isset($http->config['request']['auth']['realm']) && !self::_getServerInformation($http)) { + return; + } + $http->request['header']['Authorization'] = self::_generateHeader($http); + } + } + +/** + * Retrive information about the authetication + * + * @param HttpSocket $http + * @return boolean + */ + protected static function _getServerInformation(&$http) { + $originalRequest = $http->request; + $http->request['auth'] = array('method' => false); + $http->request($http->request); + $http->request = $originalRequest; + + if (empty($http->response['header']['Www-Authenticate'])) { + return false; + } + preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $http->response['header']['Www-Authenticate'], $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $http->config['request']['auth'][$match[1]] = $match[2]; + } + if (!empty($http->config['request']['auth']['qop']) && empty($http->config['request']['auth']['nc'])) { + $http->config['request']['auth']['nc'] = 1; + } + return true; + } + +/** + * Generate the header Authorization + * + * @param HttpSocket $http + * @return string + */ + protected static function _generateHeader(&$http) { + $a1 = md5($http->request['auth']['user'] . ':' . $http->config['request']['auth']['realm'] . ':' . $http->request['auth']['pass']); + $a2 = md5($http->request['method'] . ':' . $http->request['uri']['path']); + + if (empty($http->config['request']['auth']['qop'])) { + $response = md5($a1 . ':' . $http->config['request']['auth']['nonce'] . ':' . $a2); + } else { + $http->config['request']['auth']['cnonce'] = uniqid(); + $nc = sprintf('%08x', $http->config['request']['auth']['nc']++); + $response = md5($a1 . ':' . $http->config['request']['auth']['nonce'] . ':' . $nc . ':' . $http->config['request']['auth']['cnonce'] . ':auth:' . $a2); + } + + $authHeader = 'Digest '; + $authHeader .= 'username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $http->request['auth']['user']) . '", '; + $authHeader .= 'realm="' . $http->config['request']['auth']['realm'] . '", '; + $authHeader .= 'nonce="' . $http->config['request']['auth']['nonce'] . '", '; + $authHeader .= 'uri="' . $http->request['uri']['path'] . '", '; + $authHeader .= 'response="' . $response . '"'; + if (!empty($http->config['request']['auth']['opaque'])) { + $authHeader .= ', opaque="' . $http->config['request']['auth']['opaque'] . '"'; + } + if (!empty($http->config['request']['auth']['qop'])) { + $authHeader .= ', qop="auth", nc=' . $nc . ', cnonce="' . $http->config['request']['auth']['cnonce'] . '"'; + } + return $authHeader; + } +} diff --git a/cake/tests/cases/libs/http/digest_method.test.php b/cake/tests/cases/libs/http/digest_method.test.php new file mode 100644 index 000000000..c5a67542b --- /dev/null +++ b/cake/tests/cases/libs/http/digest_method.test.php @@ -0,0 +1,182 @@ + + * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests + * @package cake + * @subpackage cake.tests.cases.libs.http + * @since CakePHP(tm) v 2.0.0 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +App::import('Core', 'HttpSocket'); +App::import('Lib', 'http/DigestMethod'); + +class DigestHttpSocket extends HttpSocket { + +/** + * nextHeader attribute + * + * @var string + */ + public $nextHeader = ''; + +/** + * request method + * + * @param mixed $request + * @return void + */ + public function request($request) { + $this->response['header']['Www-Authenticate'] = $this->nextHeader; + } + +} + +/** + * DigestMethodTest class + * + * @package cake + * @subpackage cake.tests.cases.libs.http + */ +class DigestMethodTest extends CakeTestCase { + +/** + * Socket property + * + * @var mixed null + */ + public $HttpSocket = null; + +/** + * This function sets up a HttpSocket instance we are going to use for testing + * + * @return void + */ + public function setUp() { + $this->HttpSocket = new DigestHttpSocket(); + $this->HttpSocket->request['method'] = 'GET'; + $this->HttpSocket->request['uri']['path'] = '/'; + $this->HttpSocket->request['auth'] = array( + 'method' => 'Digest', + 'user' => 'admin', + 'pass' => '1234' + ); + } + +/** + * We use this function to clean up after the test case was executed + * + * @return void + */ + function tearDown() { + unset($this->HttpSocket); + } + +/** + * testBasic method + * + * @return void + */ + public function testBasic() { + $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; + $this->HttpSocket->config['request']['auth'] = array(); + $this->assertFalse(isset($this->HttpSocket->request['header']['Authorization'])); + DigestMethod::authentication($this->HttpSocket); + $this->assertTrue(isset($this->HttpSocket->request['header']['Authorization'])); + $this->assertEqual($this->HttpSocket->config['request']['auth']['realm'], 'The batcave'); + $this->assertEqual($this->HttpSocket->config['request']['auth']['nonce'], '4cded326c6c51'); + } + +/** + * testQop method + * + * @return void + */ + public function testQop() { + $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; + $this->HttpSocket->config['request']['auth'] = array(); + DigestMethod::authentication($this->HttpSocket); + $expected = 'Digest username="admin", realm="The batcave", nonce="4cded326c6c51", uri="/", response="da7e2a46b471d77f70a9bb3698c8902b"'; + $this->assertEqual($expected, $this->HttpSocket->request['header']['Authorization']); + $this->assertFalse(isset($this->HttpSocket->config['request']['auth']['qop'])); + $this->assertFalse(isset($this->HttpSocket->config['request']['auth']['nc'])); + + $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",qop="auth"'; + $this->HttpSocket->config['request']['auth'] = array(); + DigestMethod::authentication($this->HttpSocket); + $expected = '@Digest username="admin", realm="The batcave", nonce="4cded326c6c51", uri="/", response="[a-z0-9]{32}", qop="auth", nc=00000001, cnonce="[a-z0-9]+"@'; + $this->assertPattern($expected, $this->HttpSocket->request['header']['Authorization']); + $this->assertEqual($this->HttpSocket->config['request']['auth']['qop'], 'auth'); + $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 2); + } + +/** + * testOpaque method + * + * @return void + */ + public function testOpaque() { + $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; + $this->HttpSocket->config['request']['auth'] = array(); + DigestMethod::authentication($this->HttpSocket); + $this->assertFalse(strpos($this->HttpSocket->request['header']['Authorization'], 'opaque="d8ea7aa61a1693024c4cc3a516f49b3c"')); + + $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",opaque="d8ea7aa61a1693024c4cc3a516f49b3c"'; + $this->HttpSocket->config['request']['auth'] = array(); + DigestMethod::authentication($this->HttpSocket); + $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'opaque="d8ea7aa61a1693024c4cc3a516f49b3c"') > 0); + } + +/** + * testMultipleRequest method + * + * @return void + */ + public function testMultipleRequest() { + $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",qop="auth"'; + $this->HttpSocket->config['request']['auth'] = array(); + DigestMethod::authentication($this->HttpSocket); + $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000001') > 0); + $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 2); + + DigestMethod::authentication($this->HttpSocket); + $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000002') > 0); + $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 3); + $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); + $response = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); + + $this->HttpSocket->nextHeader = ''; + DigestMethod::authentication($this->HttpSocket); + $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000003') > 0); + $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 4); + $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); + $response2 = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); + $this->assertNotEqual($response, $response2); + } + +/** + * testPathChanged method + * + * @return void + */ + public function testPathChanged() { + $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; + $this->HttpSocket->request['uri']['path'] = '/admin'; + $this->HttpSocket->config['request']['auth'] = array(); + DigestMethod::authentication($this->HttpSocket); + $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); + $response = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); + $this->assertNotEqual($response, 'da7e2a46b471d77f70a9bb3698c8902b'); + } + +} \ No newline at end of file From 85607a9963ea375dc4d01bd098f8dbdcaa051f8b Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 13 Nov 2010 21:44:11 -0200 Subject: [PATCH 012/125] Removed interference in the name of the headers. --- cake/libs/http_socket.php | 28 ++++++++++------------ cake/tests/cases/libs/http_socket.test.php | 14 +++++------ 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index a903aa445..0df3a63e1 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -864,6 +864,7 @@ class HttpSocket extends CakeSocket { * Builds the header. * * @param array $header Header to build + * @param string $mode * @return string Header built from array */ protected function _buildHeader($header, $mode = 'standard') { @@ -873,6 +874,17 @@ class HttpSocket extends CakeSocket { return false; } + $fieldsInHeader = array(); + foreach ($header as $key => $value) { + $lowKey = strtolower($key); + if (array_key_exists($lowKey, $fieldsInHeader)) { + $header[$fieldsInHeader[$lowKey]] = $value; + unset($header[$key]); + } else { + $fieldsInHeader[$lowKey] = $key; + } + } + $returnHeader = ''; foreach ($header as $field => $contents) { if (is_array($contents) && $mode == 'standard') { @@ -896,16 +908,6 @@ class HttpSocket extends CakeSocket { */ protected function _parseHeader($header) { if (is_array($header)) { - foreach ($header as $field => $value) { - unset($header[$field]); - $field = strtolower($field); - preg_match_all('/(?:^|(?<=-))[a-z]/U', $field, $offsets, PREG_OFFSET_CAPTURE); - - foreach ($offsets[0] as $offset) { - $field = substr_replace($field, strtoupper($offset[0]), $offset[1], 1); - } - $header[$field] = $value; - } return $header; } elseif (!is_string($header)) { return false; @@ -922,12 +924,6 @@ class HttpSocket extends CakeSocket { $field = $this->_unescapeToken($field); - $field = strtolower($field); - preg_match_all('/(?:^|(?<=-))[a-z]/U', $field, $offsets, PREG_OFFSET_CAPTURE); - foreach ($offsets[0] as $offset) { - $field = substr_replace($field, strtoupper($offset[0]), $offset[1], 1); - } - if (!isset($header[$field])) { $header[$field] = $value; } else { diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index beb0fc0c5..fe6ec1c70 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -529,7 +529,7 @@ class HttpSocketTest extends CakeTestCase { $expectation['request']['raw'] = $expectation['request']['line'].$expectation['request']['header']."\r\n".$raw; $r = array('config' => $this->Socket->config, 'request' => $this->Socket->request); - $v = $this->assertEquals($r, $expectation, '%s in test #'.$i.' '); + $v = $this->assertEquals($r, $expectation, 'Failed test #'.$i.' '); $expectation['request']['raw'] = $raw; } @@ -948,13 +948,13 @@ class HttpSocketTest extends CakeTestCase { $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n0\r\nfoo-header: bar\r\ncake: PHP\r\n\r\n"; $r = $this->Socket->decodeChunkedBody($encoded); $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], array('Foo-Header' => 'bar', 'Cake' => 'PHP')); + $this->assertEquals($r['header'], array('foo-header' => 'bar', 'cake' => 'PHP')); $this->Socket->quirksMode = true; $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\nfoo-header: bar\r\ncake: PHP\r\n\r\n"; $r = $this->Socket->decodeChunkedBody($encoded); $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], array('Foo-Header' => 'bar', 'Cake' => 'PHP')); + $this->assertEquals($r['header'], array('foo-header' => 'bar', 'cake' => 'PHP')); $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n"; $r = $this->Socket->decodeChunkedBody($encoded); @@ -1393,7 +1393,7 @@ class HttpSocketTest extends CakeTestCase { $this->Socket->reset(); $r = $this->Socket->parseHeader(array('foo' => 'Bar', 'fOO-bAr' => 'quux')); - $this->assertEquals($r, array('Foo' => 'Bar', 'Foo-Bar' => 'quux')); + $this->assertEquals($r, array('foo' => 'Bar', 'fOO-bAr' => 'quux')); $r = $this->Socket->parseHeader(true); $this->assertEquals($r, false); @@ -1416,9 +1416,9 @@ class HttpSocketTest extends CakeTestCase { $header = "people: Jim,John\r\nfoo-LAND: Bar\r\ncAKe-PHP: rocks\r\n"; $r = $this->Socket->parseHeader($header); $expected = array( - 'People' => 'Jim,John' - , 'Foo-Land' => 'Bar' - , 'Cake-Php' => 'rocks' + 'people' => 'Jim,John' + , 'foo-LAND' => 'Bar' + , 'cAKe-PHP' => 'rocks' ); $this->assertEquals($r, $expected); From 974161cf3a75a791571b59dc506dc71035abd2ca Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 13 Nov 2010 21:47:25 -0200 Subject: [PATCH 013/125] Changed the name of header to use in Digest method. --- cake/libs/http/digest_method.php | 4 ++-- cake/tests/cases/libs/http/digest_method.test.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cake/libs/http/digest_method.php b/cake/libs/http/digest_method.php index 42d0c9482..654dc60fb 100644 --- a/cake/libs/http/digest_method.php +++ b/cake/libs/http/digest_method.php @@ -55,10 +55,10 @@ class DigestMethod { $http->request($http->request); $http->request = $originalRequest; - if (empty($http->response['header']['Www-Authenticate'])) { + if (empty($http->response['header']['WWW-Authenticate'])) { return false; } - preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $http->response['header']['Www-Authenticate'], $matches, PREG_SET_ORDER); + preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $http->response['header']['WWW-Authenticate'], $matches, PREG_SET_ORDER); foreach ($matches as $match) { $http->config['request']['auth'][$match[1]] = $match[2]; } diff --git a/cake/tests/cases/libs/http/digest_method.test.php b/cake/tests/cases/libs/http/digest_method.test.php index c5a67542b..8b1715b7f 100644 --- a/cake/tests/cases/libs/http/digest_method.test.php +++ b/cake/tests/cases/libs/http/digest_method.test.php @@ -37,7 +37,7 @@ class DigestHttpSocket extends HttpSocket { * @return void */ public function request($request) { - $this->response['header']['Www-Authenticate'] = $this->nextHeader; + $this->response['header']['WWW-Authenticate'] = $this->nextHeader; } } From 7bea5d941070ec8f8767b7e9d6ef3fccb4dd89df Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sun, 14 Nov 2010 23:56:12 -0200 Subject: [PATCH 014/125] Added the http directory to AllSocket tests. --- cake/tests/cases/libs/all_socket.test.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cake/tests/cases/libs/all_socket.test.php b/cake/tests/cases/libs/all_socket.test.php index 60802436e..896738957 100644 --- a/cake/tests/cases/libs/all_socket.test.php +++ b/cake/tests/cases/libs/all_socket.test.php @@ -34,10 +34,11 @@ class AllSocketTest extends PHPUnit_Framework_TestSuite { * @return void */ public static function suite() { - $suite = new PHPUnit_Framework_TestSuite('All Socket related class tests'); + $suite = new CakeTestSuite('All Socket related class tests'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_socket.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'http_socket.test.php'); + $suite->addTestDirectory(CORE_TEST_CASES . DS . 'libs' . DS . 'http'); return $suite; } } \ No newline at end of file From 7e0d34903eede19eaff8efac542274d359b60e5f Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 15 Nov 2010 00:09:52 -0200 Subject: [PATCH 015/125] Removed use of reference in params of http methods. --- cake/libs/http/basic_method.php | 2 +- cake/libs/http/digest_method.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cake/libs/http/basic_method.php b/cake/libs/http/basic_method.php index da7951c6c..a0d1590c7 100644 --- a/cake/libs/http/basic_method.php +++ b/cake/libs/http/basic_method.php @@ -33,7 +33,7 @@ class BasicMethod { * @return void * @throws Exception */ - public static function authentication(&$http) { + public static function authentication(HttpSocket $http) { if (isset($http->request['auth']['user'], $http->request['auth']['pass'])) { $http->request['header']['Authorization'] = 'Basic ' . base64_encode($http->request['auth']['user'] . ':' . $http->request['auth']['pass']); } diff --git a/cake/libs/http/digest_method.php b/cake/libs/http/digest_method.php index 654dc60fb..29c068bca 100644 --- a/cake/libs/http/digest_method.php +++ b/cake/libs/http/digest_method.php @@ -34,7 +34,7 @@ class DigestMethod { * @throws Exception * @link http://www.ietf.org/rfc/rfc2617.txt */ - public static function authentication(&$http) { + public static function authentication(HttpSocket $http) { if (isset($http->request['auth']['user'], $http->request['auth']['pass'])) { if (!isset($http->config['request']['auth']['realm']) && !self::_getServerInformation($http)) { return; @@ -49,7 +49,7 @@ class DigestMethod { * @param HttpSocket $http * @return boolean */ - protected static function _getServerInformation(&$http) { + protected static function _getServerInformation(HttpSocket $http) { $originalRequest = $http->request; $http->request['auth'] = array('method' => false); $http->request($http->request); @@ -74,7 +74,7 @@ class DigestMethod { * @param HttpSocket $http * @return string */ - protected static function _generateHeader(&$http) { + protected static function _generateHeader(HttpSocket $http) { $a1 = md5($http->request['auth']['user'] . ':' . $http->config['request']['auth']['realm'] . ':' . $http->request['auth']['pass']); $a2 = md5($http->request['method'] . ':' . $http->request['uri']['path']); From 3056fbf680572fc63b2e53f7de5355fc60051c86 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 20 Nov 2010 17:47:35 -0200 Subject: [PATCH 016/125] Changing authentication classes to use suffix Authentication instead of Method. --- ...ic_method.php => basic_authentication.php} | 2 +- ...t_method.php => digest_authentication.php} | 2 +- cake/libs/http_socket.php | 2 +- ...test.php => basic_authentication.test.php} | 4 +-- ...est.php => digest_authentication.test.php} | 26 +++++++++---------- 5 files changed, 18 insertions(+), 18 deletions(-) rename cake/libs/http/{basic_method.php => basic_authentication.php} (97%) rename cake/libs/http/{digest_method.php => digest_authentication.php} (99%) rename cake/tests/cases/libs/http/{basic_method.test.php => basic_authentication.test.php} (92%) rename cake/tests/cases/libs/http/{digest_method.test.php => digest_authentication.test.php} (89%) diff --git a/cake/libs/http/basic_method.php b/cake/libs/http/basic_authentication.php similarity index 97% rename from cake/libs/http/basic_method.php rename to cake/libs/http/basic_authentication.php index a0d1590c7..7cd01b7cb 100644 --- a/cake/libs/http/basic_method.php +++ b/cake/libs/http/basic_authentication.php @@ -24,7 +24,7 @@ * @package cake * @subpackage cake.cake.libs.http */ -class BasicMethod { +class BasicAuthentication { /** * Authentication diff --git a/cake/libs/http/digest_method.php b/cake/libs/http/digest_authentication.php similarity index 99% rename from cake/libs/http/digest_method.php rename to cake/libs/http/digest_authentication.php index 29c068bca..b25c6c971 100644 --- a/cake/libs/http/digest_method.php +++ b/cake/libs/http/digest_authentication.php @@ -24,7 +24,7 @@ * @package cake * @subpackage cake.cake.libs.http */ -class DigestMethod { +class DigestAuthentication { /** * Authentication diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 0df3a63e1..da67a28ab 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -455,7 +455,7 @@ class HttpSocket extends CakeSocket { return; } } - $authClass = Inflector::camelize($this->request['auth']['method']) . 'Method'; + $authClass = Inflector::camelize($this->request['auth']['method']) . 'Authentication'; if (!App::import('Lib', 'http/' . $authClass)) { throw new Exception(__('Unknown authentication method.')); } diff --git a/cake/tests/cases/libs/http/basic_method.test.php b/cake/tests/cases/libs/http/basic_authentication.test.php similarity index 92% rename from cake/tests/cases/libs/http/basic_method.test.php rename to cake/tests/cases/libs/http/basic_authentication.test.php index c9d487f70..9843e4815 100644 --- a/cake/tests/cases/libs/http/basic_method.test.php +++ b/cake/tests/cases/libs/http/basic_authentication.test.php @@ -19,7 +19,7 @@ */ App::import('Core', 'HttpSocket'); -App::import('Lib', 'http/BasicMethod'); +App::import('Lib', 'http/BasicAuthentication'); /** * BasicMethodTest class @@ -42,7 +42,7 @@ class BasicMethodTest extends CakeTestCase { 'pass' => 'secret' ); - BasicMethod::authentication($http); + BasicAuthentication::authentication($http); $this->assertEqual($http->request['header']['Authorization'], 'Basic bWFyazpzZWNyZXQ='); } diff --git a/cake/tests/cases/libs/http/digest_method.test.php b/cake/tests/cases/libs/http/digest_authentication.test.php similarity index 89% rename from cake/tests/cases/libs/http/digest_method.test.php rename to cake/tests/cases/libs/http/digest_authentication.test.php index 8b1715b7f..7862f3147 100644 --- a/cake/tests/cases/libs/http/digest_method.test.php +++ b/cake/tests/cases/libs/http/digest_authentication.test.php @@ -1,6 +1,6 @@ HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; $this->HttpSocket->config['request']['auth'] = array(); $this->assertFalse(isset($this->HttpSocket->request['header']['Authorization'])); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $this->assertTrue(isset($this->HttpSocket->request['header']['Authorization'])); $this->assertEqual($this->HttpSocket->config['request']['auth']['realm'], 'The batcave'); $this->assertEqual($this->HttpSocket->config['request']['auth']['nonce'], '4cded326c6c51'); @@ -105,7 +105,7 @@ class DigestMethodTest extends CakeTestCase { public function testQop() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; $this->HttpSocket->config['request']['auth'] = array(); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $expected = 'Digest username="admin", realm="The batcave", nonce="4cded326c6c51", uri="/", response="da7e2a46b471d77f70a9bb3698c8902b"'; $this->assertEqual($expected, $this->HttpSocket->request['header']['Authorization']); $this->assertFalse(isset($this->HttpSocket->config['request']['auth']['qop'])); @@ -113,7 +113,7 @@ class DigestMethodTest extends CakeTestCase { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",qop="auth"'; $this->HttpSocket->config['request']['auth'] = array(); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $expected = '@Digest username="admin", realm="The batcave", nonce="4cded326c6c51", uri="/", response="[a-z0-9]{32}", qop="auth", nc=00000001, cnonce="[a-z0-9]+"@'; $this->assertPattern($expected, $this->HttpSocket->request['header']['Authorization']); $this->assertEqual($this->HttpSocket->config['request']['auth']['qop'], 'auth'); @@ -128,12 +128,12 @@ class DigestMethodTest extends CakeTestCase { public function testOpaque() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; $this->HttpSocket->config['request']['auth'] = array(); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $this->assertFalse(strpos($this->HttpSocket->request['header']['Authorization'], 'opaque="d8ea7aa61a1693024c4cc3a516f49b3c"')); $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",opaque="d8ea7aa61a1693024c4cc3a516f49b3c"'; $this->HttpSocket->config['request']['auth'] = array(); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'opaque="d8ea7aa61a1693024c4cc3a516f49b3c"') > 0); } @@ -145,18 +145,18 @@ class DigestMethodTest extends CakeTestCase { public function testMultipleRequest() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",qop="auth"'; $this->HttpSocket->config['request']['auth'] = array(); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000001') > 0); $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 2); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000002') > 0); $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 3); $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); $response = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); $this->HttpSocket->nextHeader = ''; - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000003') > 0); $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 4); $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); @@ -173,7 +173,7 @@ class DigestMethodTest extends CakeTestCase { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; $this->HttpSocket->request['uri']['path'] = '/admin'; $this->HttpSocket->config['request']['auth'] = array(); - DigestMethod::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket); $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); $response = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); $this->assertNotEqual($response, 'da7e2a46b471d77f70a9bb3698c8902b'); From ae7855692d131241f06ba78a837de536508f73f1 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 20 Nov 2010 23:42:54 -0500 Subject: [PATCH 017/125] Removing unserialize() as its dangerous. Instead using | delimited fields for locked fields. This totally avoids issues with serialize(). Removing str_rot13, as its only child proof. Tests updated. --- cake/libs/controller/components/security.php | 6 +-- .../controller/components/security.test.php | 50 ++++++++----------- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/cake/libs/controller/components/security.php b/cake/libs/controller/components/security.php index 7e5b3b28f..0de6c6ae4 100644 --- a/cake/libs/controller/components/security.php +++ b/cake/libs/controller/components/security.php @@ -618,15 +618,11 @@ class SecurityComponent extends Object { } unset($check['_Token']); - $locked = str_rot13($locked); - if (preg_match('/(\A|;|{|})O\:[0-9]+/', $locked)) { - return false; - } + $locked = explode('|', $locked); $lockedFields = array(); $fields = Set::flatten($check); $fieldList = array_keys($fields); - $locked = unserialize($locked); $multi = array(); foreach ($fieldList as $i => $key) { diff --git a/cake/tests/cases/libs/controller/components/security.test.php b/cake/tests/cases/libs/controller/components/security.test.php index bbd514100..66cff58ba 100644 --- a/cake/tests/cases/libs/controller/components/security.test.php +++ b/cake/tests/cases/libs/controller/components/security.test.php @@ -573,8 +573,7 @@ DIGEST; function testValidatePost() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3An%3A1%3A%7Bv%3A0%3B'; - $fields .= 'f%3A11%3A%22Zbqry.inyvq%22%3B%7D'; + $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid'; $this->Controller->data = array( 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'), @@ -591,8 +590,7 @@ DIGEST; function testValidatePostFormHacking() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3An%3A1%3A%7Bv%3A0%3B'; - $fields .= 'f%3A11%3A%22Zbqry.inyvq%22%3B%7D'; + $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid'; $this->Controller->data = array( 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'), @@ -641,7 +639,7 @@ DIGEST; function testValidatePostArray() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3An%3A0%3A%7B%7D'; + $fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A'; $this->Controller->data = array( 'Model' => array('multi_field' => array('1', '3')), @@ -659,7 +657,7 @@ DIGEST; function testValidatePostNoModel() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3An%3A0%3A%7B%7D'; + $fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3A'; $this->Controller->data = array( 'anything' => 'some_data', @@ -679,7 +677,7 @@ DIGEST; function testValidatePostSimple() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = '69f493434187b867ea14b901fdf58b55d27c935d%3An%3A0%3A%7B%7D'; + $fields = '69f493434187b867ea14b901fdf58b55d27c935d%3A'; $this->Controller->data = $data = array( 'Model' => array('username' => '', 'password' => ''), @@ -699,8 +697,7 @@ DIGEST; function testValidatePostComplex() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3An%3A2%3A%7Bv%3A0%3Bf%3A14%3A%'; - $fields .= '22Nqqerffrf.0.vq%22%3Bv%3A1%3Bf%3A14%3A%22Nqqerffrf.1.vq%22%3B%7D'; + $fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id'; $this->Controller->data = array( 'Addresses' => array( @@ -727,7 +724,7 @@ DIGEST; function testValidatePostMultipleSelect() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = '422cde416475abc171568be690a98cad20e66079%3An%3A0%3A%7B%7D'; + $fields = '422cde416475abc171568be690a98cad20e66079%3A'; $this->Controller->data = array( 'Tag' => array('Tag' => array(1, 2)), @@ -750,7 +747,7 @@ DIGEST; $result = $this->Controller->Security->validatePost($this->Controller); $this->assertTrue($result); - $fields = '19464422eafe977ee729c59222af07f983010c5f%3An%3A0%3A%7B%7D'; + $fields = '19464422eafe977ee729c59222af07f983010c5f%3A'; $this->Controller->data = array( 'User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1', 'Tag' => array('Tag' => array(1)), '_Token' => compact('key', 'fields'), @@ -771,8 +768,7 @@ DIGEST; function testValidatePostCheckbox() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3An%3A1%3A%7Bv%3A0%'; - $fields .= '3Bf%3A11%3A%22Zbqry.inyvq%22%3B%7D'; + $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid'; $this->Controller->data = array( 'Model' => array('username' => '', 'password' => '', 'valid' => '0'), @@ -782,7 +778,7 @@ DIGEST; $result = $this->Controller->Security->validatePost($this->Controller); $this->assertTrue($result); - $fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3An%3A0%3A%7B%7D'; + $fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3A'; $this->Controller->data = array( 'Model' => array('username' => '', 'password' => '', 'valid' => '0'), @@ -815,8 +811,8 @@ DIGEST; function testValidatePostHidden() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3An%3A2%3A%7Bv%3A0%3Bf%3A12%3A'; - $fields .= '%22Zbqry.uvqqra%22%3Bv%3A1%3Bf%3A18%3A%22Zbqry.bgure_uvqqra%22%3B%7D'; + $fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3AModel.hidden%7CModel.other_hidden'; + $fields .= ''; $this->Controller->data = array( 'Model' => array( @@ -839,8 +835,7 @@ DIGEST; $this->Controller->Security->disabledFields = array('Model.username', 'Model.password'); $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = 'ef1082968c449397bcd849f963636864383278b1%3An%3A1%3A%7Bv%'; - $fields .= '3A0%3Bf%3A12%3A%22Zbqry.uvqqra%22%3B%7D'; + $fields = 'ef1082968c449397bcd849f963636864383278b1%3AModel.hidden'; $this->Controller->data = array( 'Model' => array( @@ -862,9 +857,7 @@ DIGEST; function testValidateHiddenMultipleModel() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3An%3A3%3A%7Bv%3A0%3Bf%3A11'; - $fields .= '%3A%22Zbqry.inyvq%22%3Bv%3A1%3Bf%3A12%3A%22Zbqry2.inyvq%22%3Bv%3A2%'; - $fields .= '3Bf%3A12%3A%22Zbqry3.inyvq%22%3B%7D'; + $fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3AModel.valid%7CModel2.valid%7CModel3.valid'; $this->Controller->data = array( 'Model' => array('username' => '', 'password' => '', 'valid' => '0'), @@ -895,9 +888,8 @@ DIGEST; function testValidateHasManyModel() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3An%3A4%3A%7Bv%3A0%3Bf%3A14%3A%2'; - $fields .= '2Zbqry.0.uvqqra%22%3Bv%3A1%3Bf%3A13%3A%22Zbqry.0.inyvq%22%3Bv%3A2%3Bf%3'; - $fields .= 'A14%3A%22Zbqry.1.uvqqra%22%3Bv%3A3%3Bf%3A13%3A%22Zbqry.1.inyvq%22%3B%7D'; + $fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid'; + $fields .= '%7CModel.1.hidden%7CModel.1.valid'; $this->Controller->data = array( 'Model' => array( @@ -926,9 +918,8 @@ DIGEST; function testValidateHasManyRecordsPass() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3An%3A4%3A%7Bv%3A0%3Bf%3A12%3A%2'; - $fields .= '2Nqqerff.0.vq%22%3Bv%3A1%3Bf%3A17%3A%22Nqqerff.0.cevznel%22%3Bv%3A2%3Bf%'; - $fields .= '3A12%3A%22Nqqerff.1.vq%22%3Bv%3A3%3Bf%3A17%3A%22Nqqerff.1.cevznel%22%3B%7D'; + $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C'; + $fields .= 'Address.1.id%7CAddress.1.primary'; $this->Controller->data = array( 'Address' => array( @@ -971,9 +962,8 @@ DIGEST; function testValidateHasManyRecordsFail() { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3An%3A4%3A%7Bv%3A0%3Bf%3A12%3A%2'; - $fields .= '2Nqqerff.0.vq%22%3Bv%3A1%3Bf%3A17%3A%22Nqqerff.0.cevznel%22%3Bv%3A2%3Bf%'; - $fields .= '3A12%3A%22Nqqerff.1.vq%22%3Bv%3A3%3Bf%3A17%3A%22Nqqerff.1.cevznel%22%3B%7D'; + $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C'; + $fields .= 'Address.1.id%7CAddress.1.primary'; $this->Controller->data = array( 'Address' => array( From 79aafda6986fba23b2308050fee9bb3c955741db Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 21 Nov 2010 00:09:45 -0500 Subject: [PATCH 018/125] Removing use of serialize() for locked fields. This removes any possible exploit related to serialize()/unserialize(). Instead values are passed as | delimited. --- cake/libs/view/helpers/form.php | 2 +- .../cases/libs/view/helpers/form.test.php | 21 +++++++------------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/cake/libs/view/helpers/form.php b/cake/libs/view/helpers/form.php index 538d844e5..5ee8a6c2c 100644 --- a/cake/libs/view/helpers/form.php +++ b/cake/libs/view/helpers/form.php @@ -406,7 +406,7 @@ class FormHelper extends AppHelper { $fields += $locked; $fields = Security::hash(serialize($fields) . Configure::read('Security.salt')); - $locked = str_rot13(serialize(array_keys($locked))); + $locked = implode(array_keys($locked), '|'); $out = $this->hidden('_Token.fields', array( 'value' => urlencode($fields . ':' . $locked), diff --git a/cake/tests/cases/libs/view/helpers/form.test.php b/cake/tests/cases/libs/view/helpers/form.test.php index 0dc83aed7..3a9868c77 100644 --- a/cake/tests/cases/libs/view/helpers/form.test.php +++ b/cake/tests/cases/libs/view/helpers/form.test.php @@ -832,7 +832,7 @@ class FormHelperTest extends CakeTestCase { $result = $this->Form->secure($fields); $expected = Security::hash(serialize($fields) . Configure::read('Security.salt')); - $expected .= ':' . str_rot13(serialize(array('Model.valid'))); + $expected .= ':' . 'Model.valid'; $expected = array( 'div' => array('style' => 'display:none;'), @@ -894,9 +894,8 @@ class FormHelperTest extends CakeTestCase { $this->Form->params['_Token']['key'] = $key; $result = $this->Form->secure($fields); - $hash = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3An%3A4%3A%7Bv%3A0%3Bf%3A14%3A%22Zbqry.'; - $hash .= '0.uvqqra%22%3Bv%3A1%3Bf%3A13%3A%22Zbqry.0.inyvq%22%3Bv%3A2%3Bf%3A14%3A%22Zbqry.1'; - $hash .= '.uvqqra%22%3Bv%3A3%3Bf%3A13%3A%22Zbqry.1.inyvq%22%3B%7D'; + $hash = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid'; + $hash .= '%7CModel.1.hidden%7CModel.1.valid'; $expected = array( 'div' => array('style' => 'display:none;'), @@ -985,8 +984,7 @@ class FormHelperTest extends CakeTestCase { $result = $this->Form->secure($this->Form->fields); - $hash = 'c9118120e680a7201b543f562e5301006ccfcbe2%3An%3A2%3A%7Bv%3A0%3Bf%3A14%'; - $hash .= '3A%22Nqqerffrf.0.vq%22%3Bv%3A1%3Bf%3A14%3A%22Nqqerffrf.1.vq%22%3B%7D'; + $hash = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id'; $expected = array( 'div' => array('style' => 'display:none;'), @@ -1029,8 +1027,7 @@ class FormHelperTest extends CakeTestCase { $this->Form->input('Addresses.1.phone'); $result = $this->Form->secure($this->Form->fields); - $hash = '774df31936dc850b7d8a5277dc0b890123788b09%3An%3A2%3A%7Bv%3A0%3Bf%3A14%3A%22Nqqerf'; - $hash .= 'frf.0.vq%22%3Bv%3A1%3Bf%3A14%3A%22Nqqerffrf.1.vq%22%3B%7D'; + $hash = '774df31936dc850b7d8a5277dc0b890123788b09%3AAddresses.0.id%7CAddresses.1.id'; $expected = array( 'div' => array('style' => 'display:none;'), @@ -1074,8 +1071,7 @@ class FormHelperTest extends CakeTestCase { $result = $this->Form->secure($expected); - $hash = '449b7e889128e8e52c5e81d19df68f5346571492%3An%3A1%3A%'; - $hash .= '7Bv%3A0%3Bf%3A12%3A%22Nqqerffrf.vq%22%3B%7D'; + $hash = '449b7e889128e8e52c5e81d19df68f5346571492%3AAddresses.id'; $expected = array( 'div' => array('style' => 'display:none;'), 'input' => array( @@ -1179,8 +1175,7 @@ class FormHelperTest extends CakeTestCase { ); $this->assertEqual($result, $expected); - $hash = 'bd7c4a654e5361f9a433a43f488ff9a1065d0aaf%3An%3A2%3A%7Bv%3A0%3Bf%3A15%3'; - $hash .= 'A%22HfreSbez.uvqqra%22%3Bv%3A1%3Bf%3A14%3A%22HfreSbez.fghss%22%3B%7D'; + $hash = 'bd7c4a654e5361f9a433a43f488ff9a1065d0aaf%3AUserForm.hidden%7CUserForm.stuff'; $result = $this->Form->secure($this->Form->fields); $expected = array( @@ -3569,7 +3564,7 @@ class FormHelperTest extends CakeTestCase { $this->assertEqual($this->Form->fields, array('Model.multi_field')); $result = $this->Form->secure($this->Form->fields); - $key = 'f7d573650a295b94e0938d32b323fde775e5f32b%3An%3A0%3A%7B%7D'; + $key = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A'; $this->assertPattern('/"' . $key . '"/', $result); } From 244de1df8563dcd030245b251651d9f4a67b49eb Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 22 Nov 2010 12:58:51 -0500 Subject: [PATCH 019/125] Adding a comment about the messageId property and shells. Refs #1303 --- cake/libs/controller/components/email.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cake/libs/controller/components/email.php b/cake/libs/controller/components/email.php index 233945f53..52451fda1 100755 --- a/cake/libs/controller/components/email.php +++ b/cake/libs/controller/components/email.php @@ -261,6 +261,9 @@ class EmailComponent extends Object{ * it be handled by sendmail (or similar) or a string * to completely override the Message-ID. * + * If you are sending Email from a shell, be sure to set this value. As you + * could encounter delivery issues if you do not. + * * @var mixed * @access public */ From f48811a2ff471094462bd043dfc69792c30923f5 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 22 Nov 2010 21:15:02 -0500 Subject: [PATCH 020/125] Moving include up so its not buried deep inside the class. --- cake/libs/cake_session.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cake/libs/cake_session.php b/cake/libs/cake_session.php index bcb6459f9..0ad09de2c 100644 --- a/cake/libs/cake_session.php +++ b/cake/libs/cake_session.php @@ -22,6 +22,9 @@ * @since CakePHP(tm) v .0.10.0.1222 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +if (!class_exists('Security')) { + App::import('Core', 'Security'); +} /** * Session class for Cake. @@ -193,9 +196,6 @@ class CakeSession extends Object { } } if (isset($_SESSION) || $start === true) { - if (!class_exists('Security')) { - App::import('Core', 'Security'); - } $this->sessionTime = $this->time + (Security::inactiveMins() * Configure::read('Session.timeout')); $this->security = Configure::read('Security.level'); } From bf10723f897466a1b02149db4f45e9a279c37de8 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 22 Nov 2010 21:21:55 -0500 Subject: [PATCH 021/125] Applying patch from 'michealc' to fix duplicated comments. Fixes #1306 --- cake/libs/model/datasources/datasource.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cake/libs/model/datasources/datasource.php b/cake/libs/model/datasources/datasource.php index 2c5a0ab12..94b5d5cef 100644 --- a/cake/libs/model/datasources/datasource.php +++ b/cake/libs/model/datasources/datasource.php @@ -396,7 +396,7 @@ class DataSource extends Object { } /** - * Returns the ID generated from the previous INSERT operation. + * Returns the number of rows returned by last operation. * * @param unknown_type $source * @return integer Number of rows returned by last operation @@ -407,7 +407,7 @@ class DataSource extends Object { } /** - * Returns the ID generated from the previous INSERT operation. + * Returns the number of rows affected by last query. * * @param unknown_type $source * @return integer Number of rows affected by last query. @@ -428,6 +428,7 @@ class DataSource extends Object { function enabled() { return true; } + /** * Returns true if the DataSource supports the given interface (method) * From d0d16a7edaa9a3b26f6a64c7bbaf9f50f0f7d1f2 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 22 Nov 2010 21:29:11 -0500 Subject: [PATCH 022/125] Fixing i18n extraction errors in Scaffold. Fixes #1305 --- cake/libs/controller/scaffold.php | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cake/libs/controller/scaffold.php b/cake/libs/controller/scaffold.php index 0891616fd..ea5e9031f 100644 --- a/cake/libs/controller/scaffold.php +++ b/cake/libs/controller/scaffold.php @@ -303,7 +303,7 @@ class Scaffold extends Object { } if (!$this->ScaffoldModel->exists()) { - $message = __(sprintf("Invalid id for %s::edit()", Inflector::humanize($this->modelKey), true)); + $message = sprintf(__("Invalid id for %s::edit()", true), Inflector::humanize($this->modelKey)); if ($this->_validSession) { $this->controller->Session->setFlash($message); $this->controller->redirect($this->redirect); @@ -321,9 +321,10 @@ class Scaffold extends Object { if ($this->ScaffoldModel->save($this->controller->data)) { if ($this->controller->_afterScaffoldSave($action)) { - $message = __( - sprintf('The %1$s has been %2$s', Inflector::humanize($this->modelKey), $success), - true + $message = sprintf( + __('The %1$s has been %2$s', true), + Inflector::humanize($this->modelKey), + $success ); if ($this->_validSession) { $this->controller->Session->setFlash($message); @@ -376,8 +377,9 @@ class Scaffold extends Object { */ function __scaffoldDelete($params = array()) { if ($this->controller->_beforeScaffold('delete')) { - $message = __( - sprintf("No id set for %s::delete()", Inflector::humanize($this->modelKey)), true + $message = sprintf( + __("No id set for %s::delete()", true), + Inflector::humanize($this->modelKey) ); if (isset($params['pass'][0])) { $id = $params['pass'][0]; @@ -390,9 +392,9 @@ class Scaffold extends Object { } if ($this->ScaffoldModel->delete($id)) { - $message = __( - sprintf('The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id), - true + $message = sprintf( + __('The %1$s with id: %2$d has been deleted.', true), + Inflector::humanize($this->modelClass), $id ); if ($this->_validSession) { $this->controller->Session->setFlash($message); @@ -402,10 +404,10 @@ class Scaffold extends Object { return $this->_output(); } } else { - $message = __(sprintf( - 'There was an error deleting the %1$s with id: %2$d', + $message = sprintf( + __('There was an error deleting the %1$s with id: %2$d', true), Inflector::humanize($this->modelClass), $id - ), true); + ); if ($this->_validSession) { $this->controller->Session->setFlash($message); $this->controller->redirect($this->redirect); From d5fb0b25cb521d3b65e10d5265571ccd941b29ac Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 22 Nov 2010 22:08:46 -0500 Subject: [PATCH 023/125] Fixing issue where Date header would be missing from Emails sent by EmailComponent. Adding user configurable field for date. Test cases added. Fixes #1304 --- cake/libs/controller/components/email.php | 16 ++++++++++++ .../libs/controller/components/email.test.php | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/cake/libs/controller/components/email.php b/cake/libs/controller/components/email.php index 52451fda1..d27fd5c13 100755 --- a/cake/libs/controller/components/email.php +++ b/cake/libs/controller/components/email.php @@ -97,6 +97,15 @@ class EmailComponent extends Object{ */ var $bcc = array(); +/** + * The date to put in the Date: header. This should be a date + * conformant with the RFC2822 standard. Leave null, to have + * today's date generated. + * + * @var string + */ + var $date = null; + /** * The subject of the email * @@ -410,6 +419,7 @@ class EmailComponent extends Object{ $this->bcc = array(); $this->subject = null; $this->additionalParams = null; + $this->date = null; $this->smtpError = null; $this->attachments = array(); $this->htmlMessage = null; @@ -574,6 +584,12 @@ class EmailComponent extends Object{ } } + $date = $this->date; + if ($date == false) { + $date = date(DATE_RFC2822); + } + $headers['Date'] = $date; + $headers['X-Mailer'] = $this->xMailer; if (!empty($this->headers)) { diff --git a/cake/tests/cases/libs/controller/components/email.test.php b/cake/tests/cases/libs/controller/components/email.test.php index 8d7f588e6..8379e3e7b 100755 --- a/cake/tests/cases/libs/controller/components/email.test.php +++ b/cake/tests/cases/libs/controller/components/email.test.php @@ -493,6 +493,7 @@ TEMPDOC; $this->Controller->EmailTest->delivery = 'debug'; $this->Controller->EmailTest->messageId = false; + $date = date(DATE_RFC2822); $message = <<To: postmaster@localhost From: noreply@example.com @@ -501,6 +502,7 @@ Header: From: noreply@example.com Reply-To: noreply@example.com +Date: $date X-Mailer: CakePHP Email Component Content-Type: {CONTENTTYPE} Content-Transfer-Encoding: 7bitParameters: @@ -544,6 +546,7 @@ MSGBLOC; $this->Controller->EmailTest->delivery = 'debug'; $this->Controller->EmailTest->messageId = false; + $date = date(DATE_RFC2822); $header = <<assertPattern('/Subject: Cake Debug Test\n/', $result); $this->assertPattern('/Reply-To: noreply@example.com\n/', $result); $this->assertPattern('/From: noreply@example.com\n/', $result); + $this->assertPattern('/Date: ' . date(DATE_RFC2822) . '\n/', $result); $this->assertPattern('/X-Mailer: CakePHP Email Component\n/', $result); $this->assertPattern('/Content-Type: text\/plain; charset=UTF-8\n/', $result); $this->assertPattern('/Content-Transfer-Encoding: 7bitParameters:\n/', $result); @@ -716,6 +721,7 @@ TEXTBLOC; $this->assertPattern('/Subject: Cake Debug Test\n/', $result); $this->assertPattern('/Reply-To: noreply@example.com\n/', $result); $this->assertPattern('/From: noreply@example.com\n/', $result); + $this->assertPattern('/Date: ' . date(DATE_RFC2822) . '\n/', $result); $this->assertPattern('/X-Mailer: CakePHP Email Component\n/', $result); $this->assertPattern('/Content-Type: text\/plain; charset=UTF-8\n/', $result); $this->assertPattern('/Content-Transfer-Encoding: 7bitParameters:\n/', $result); @@ -849,7 +855,24 @@ HTMLBLOC; $this->assertPattern('/First line\n/', $result); $this->assertPattern('/Second line\n/', $result); $this->assertPattern('/Third line\n/', $result); + } +/** + * test setting a custom date. + * + * @return void + */ + function testDateProperty() { + $this->Controller->EmailTest->to = 'postmaster@localhost'; + $this->Controller->EmailTest->from = 'noreply@example.com'; + $this->Controller->EmailTest->subject = 'Cake Debug Test'; + $this->Controller->EmailTest->date = 'Today!'; + $this->Controller->EmailTest->template = null; + $this->Controller->EmailTest->delivery = 'debug'; + + $this->assertTrue($this->Controller->EmailTest->send('test message')); + $result = $this->Controller->Session->read('Message.email.message'); + $this->assertPattern('/Date: Today!\n/', $result); } /** @@ -1043,6 +1066,7 @@ HTMLBLOC; $this->Controller->EmailTest->return = 'test.return@example.com'; $this->Controller->EmailTest->cc = array('cc1@example.com', 'cc2@example.com'); $this->Controller->EmailTest->bcc = array('bcc1@example.com', 'bcc2@example.com'); + $this->Controller->EmailTest->date = 'Today!'; $this->Controller->EmailTest->subject = 'Test subject'; $this->Controller->EmailTest->additionalParams = 'X-additional-header'; $this->Controller->EmailTest->delivery = 'smtp'; @@ -1064,6 +1088,7 @@ HTMLBLOC; $this->assertNull($this->Controller->EmailTest->return); $this->assertIdentical($this->Controller->EmailTest->cc, array()); $this->assertIdentical($this->Controller->EmailTest->bcc, array()); + $this->assertNull($this->Controller->EmailTest->date); $this->assertNull($this->Controller->EmailTest->subject); $this->assertNull($this->Controller->EmailTest->additionalParams); $this->assertIdentical($this->Controller->EmailTest->getHeaders(), array()); From b567de977e6d1e570095f26ae1eb1eaccbb6cb78 Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 24 Nov 2010 01:43:10 +0530 Subject: [PATCH 024/125] Fixed bug where Dispatcher::getUrl() returned incorrect URL if $base appeared in a $uri besides at start of $uri. --- cake/dispatcher.php | 8 ++++---- cake/tests/cases/dispatcher.test.php | 21 ++++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/cake/dispatcher.php b/cake/dispatcher.php index 1597c666f..e95771b2c 100644 --- a/cake/dispatcher.php +++ b/cake/dispatcher.php @@ -82,7 +82,7 @@ class Dispatcher extends Object { } /** - * Dispatches and invokes given URL, handing over control to the involved controllers, and then renders the + * Dispatches and invokes given URL, handing over control to the involved controllers, and then renders the * results (if autoRender is set). * * If no controller of given name can be found, invoke() shows error messages in @@ -483,8 +483,8 @@ class Dispatcher extends Object { if ($tmpUri === '/' || $tmpUri == $baseDir || $tmpUri == $base) { $url = $_GET['url'] = '/'; } else { - if ($base && strpos($uri, $base) !== false) { - $elements = explode($base, $uri); + if ($base && strpos($uri, $base) === 0) { + $elements = explode($base, $uri, 2); } elseif (preg_match('/^[\/\?\/|\/\?|\?\/]/', $uri)) { $elements = array(1 => preg_replace('/^[\/\?\/|\/\?|\?\/]/', '', $uri)); } else { @@ -560,7 +560,7 @@ class Dispatcher extends Object { } $filters = Configure::read('Asset.filter'); $isCss = ( - strpos($url, 'ccss/') === 0 || + strpos($url, 'ccss/') === 0 || preg_match('#^(theme/([^/]+)/ccss/)|(([^/]+)(?assertEqual($expected, $result); + $_GET['url'] = array(); + $Dispatcher =& new Dispatcher(); + $Dispatcher->base = '/shop'; + $uri = '/shop/fr/pages/shop'; + $result = $Dispatcher->getUrl($uri); + $expected = 'fr/pages/shop'; + $this->assertEqual($expected, $result); } /** @@ -1367,11 +1374,11 @@ class DispatcherTest extends CakeTestCase { $url = 'test_dispatch_pages/camelCased'; $controller = $Dispatcher->dispatch($url, array('return' => 1)); $this->assertEqual('TestDispatchPages', $controller->name); - + $url = 'test_dispatch_pages/camelCased/something. .'; $controller = $Dispatcher->dispatch($url, array('return' => 1)); $this->assertEqual($controller->params['pass'][0], 'something. .', 'Period was chopped off. %s'); - + } /** @@ -1395,7 +1402,7 @@ class DispatcherTest extends CakeTestCase { $expected = array('0' => 'home', 'param' => 'value', 'param2' => 'value2'); $this->assertIdentical($expected, $controller->passedArgs); - + $this->assertEqual($Dispatcher->base . '/pages/display/home/param:value/param2:value2', $Dispatcher->here); } @@ -1441,7 +1448,7 @@ class DispatcherTest extends CakeTestCase { Router::reload(); $Dispatcher =& new TestDispatcher(); Router::connect( - '/my_plugin/:controller/*', + '/my_plugin/:controller/*', array('plugin' => 'my_plugin', 'controller' => 'pages', 'action' => 'display') ); @@ -1598,7 +1605,7 @@ class DispatcherTest extends CakeTestCase { 'action' => 'admin_index', 'prefix' => 'admin', 'admin' => true, - 'form' => array(), + 'form' => array(), 'url' => array('url' => 'admin/articles_test'), 'return' => 1 ); @@ -1980,7 +1987,7 @@ class DispatcherTest extends CakeTestCase { } /** - * test that asset filters work for theme and plugin assets + * test that asset filters work for theme and plugin assets * * @return void */ @@ -2008,7 +2015,7 @@ class DispatcherTest extends CakeTestCase { $Dispatcher->stopped = false; $Dispatcher->asset('css/ccss/debug_kit.css'); $this->assertFalse($Dispatcher->stopped); - + $Dispatcher->stopped = false; $Dispatcher->asset('js/cjs/debug_kit.js'); $this->assertFalse($Dispatcher->stopped); From af06b8f1791e658a0299095a6cea062afd0cc847 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 24 Nov 2010 21:14:52 -0200 Subject: [PATCH 025/125] Added test to a request that server dont response WWW-Authenticate. --- .../libs/http/digest_authentication.test.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cake/tests/cases/libs/http/digest_authentication.test.php b/cake/tests/cases/libs/http/digest_authentication.test.php index 7862f3147..75e98595e 100644 --- a/cake/tests/cases/libs/http/digest_authentication.test.php +++ b/cake/tests/cases/libs/http/digest_authentication.test.php @@ -37,6 +37,12 @@ class DigestHttpSocket extends HttpSocket { * @return void */ public function request($request) { + if ($request === false) { + if (isset($this->response['header']['WWW-Authenticate'])) { + unset($this->response['header']['WWW-Authenticate']); + } + return; + } $this->response['header']['WWW-Authenticate'] = $this->nextHeader; } @@ -179,4 +185,17 @@ class DigestAuthenticationTest extends CakeTestCase { $this->assertNotEqual($response, 'da7e2a46b471d77f70a9bb3698c8902b'); } +/** + * testNoDigestResponse method + * + * @return void + */ + public function testNoDigestResponse() { + $this->HttpSocket->nextHeader = false; + $this->HttpSocket->request['uri']['path'] = '/admin'; + $this->HttpSocket->config['request']['auth'] = array(); + DigestAuthentication::authentication($this->HttpSocket); + $this->assertFalse(isset($this->HttpSocket->request['header']['Authorization'])); + } + } \ No newline at end of file From 0e29567f8d8110948140b6445be4812750181ba8 Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 24 Nov 2010 22:09:08 -0500 Subject: [PATCH 026/125] Adding an array cast to fix issues where users could modify cookie values causing iteration errors. Fixes #1309 --- cake/libs/controller/components/cookie.php | 2 +- .../libs/controller/components/cookie.test.php | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cake/libs/controller/components/cookie.php b/cake/libs/controller/components/cookie.php index 67c3fe4db..38c5f00ae 100644 --- a/cake/libs/controller/components/cookie.php +++ b/cake/libs/controller/components/cookie.php @@ -411,7 +411,7 @@ class CookieComponent extends Object { $decrypted = array(); $type = $this->__type; - foreach ($values as $name => $value) { + foreach ((array)$values as $name => $value) { if (is_array($value)) { foreach ($value as $key => $val) { $pos = strpos($val, 'Q2FrZQ==.'); diff --git a/cake/tests/cases/libs/controller/components/cookie.test.php b/cake/tests/cases/libs/controller/components/cookie.test.php index 86e7789b5..5e3751f8b 100644 --- a/cake/tests/cases/libs/controller/components/cookie.test.php +++ b/cake/tests/cases/libs/controller/components/cookie.test.php @@ -437,6 +437,19 @@ class CookieComponentTest extends CakeTestCase { unset($_COOKIE['CakeTestCookie']); } + +/** + * test that no error is issued for non array data. + * + * @return void + */ + function testNoErrorOnNonArrayData() { + $this->Controller->Cookie->destroy(); + $_COOKIE['CakeTestCookie'] = 'kaboom'; + + $this->assertNull($this->Controller->Cookie->read('value')); + } + /** * encrypt method * From 4214242efd05645db042524aa85a953acda152f8 Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 24 Nov 2010 22:44:12 -0500 Subject: [PATCH 027/125] Adding test for correct merge order for $uses. Fixing incorrect merge ordering for $uses, so it matches historical behaviour. Fixes #1309 --- cake/libs/controller/controller.php | 8 ++------ cake/tests/cases/libs/controller/controller.test.php | 4 ++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cake/libs/controller/controller.php b/cake/libs/controller/controller.php index 4a9827975..799d93f62 100644 --- a/cake/libs/controller/controller.php +++ b/cake/libs/controller/controller.php @@ -437,9 +437,7 @@ class Controller extends Object { $this->{$var} = Set::merge($app, $normal); } } else { - $this->{$var} = Set::merge( - array_diff($appVars[$var], $this->{$var}), $this->{$var} - ); + $this->{$var} = array_merge($this->{$var}, array_diff($appVars[$var], $this->{$var})); } } } @@ -463,9 +461,7 @@ class Controller extends Object { $this->{$var} = Set::merge($app, $normal); } } else { - $this->{$var} = Set::merge( - array_diff($appVars[$var], $this->{$var}), $this->{$var} - ); + $this->{$var} = array_merge($this->{$var}, array_diff($appVars[$var], $this->{$var})); } } } diff --git a/cake/tests/cases/libs/controller/controller.test.php b/cake/tests/cases/libs/controller/controller.test.php index d73672814..55a9e53cd 100644 --- a/cake/tests/cases/libs/controller/controller.test.php +++ b/cake/tests/cases/libs/controller/controller.test.php @@ -1153,6 +1153,10 @@ class ControllerTest extends CakeTestCase { $this->assertEqual(count(array_diff($TestController->uses, $uses)), 0); $this->assertEqual(count(array_diff_assoc(Set::normalize($TestController->components), Set::normalize($components))), 0); + $expected = array('ControllerComment', 'ControllerAlias', 'ControllerPost'); + $this->assertEqual($expected, $TestController->uses, '$uses was merged incorrectly, AppController models should be last.'); + + $TestController =& new AnotherTestController(); $TestController->constructClasses(); From 7d158e8d1f8ea6a156e169c021b831740d8ca838 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 25 Nov 2010 06:39:08 -0500 Subject: [PATCH 028/125] Fixing Set::sort() for arrays with out of sequence, or missing keys. Tests added. Fixes #1312 --- cake/libs/set.php | 5 ++++- cake/tests/cases/libs/set.test.php | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/cake/libs/set.php b/cake/libs/set.php index 69706e8c9..3d4e89f02 100644 --- a/cake/libs/set.php +++ b/cake/libs/set.php @@ -1092,6 +1092,10 @@ class Set { * @static */ function sort($data, $path, $dir) { + $originalKeys = array_keys($data); + if (is_numeric(implode('', $originalKeys))) { + $data = array_values($data); + } $result = Set::__flatten(Set::extract($data, $path)); list($keys, $values) = array(Set::extract($result, '{n}.id'), Set::extract($result, '{n}.value')); @@ -1103,7 +1107,6 @@ class Set { } array_multisort($values, $dir, $keys, $dir); $sorted = array(); - $keys = array_unique($keys); foreach ($keys as $k) { diff --git a/cake/tests/cases/libs/set.test.php b/cake/tests/cases/libs/set.test.php index ee75ba1a9..3018c351a 100644 --- a/cake/tests/cases/libs/set.test.php +++ b/cake/tests/cases/libs/set.test.php @@ -354,6 +354,33 @@ class SetTest extends CakeTestCase { $this->assertEqual($result, $expected); } +/** + * test sorting with out of order keys. + * + * @return void + */ + function testSortWithOutOfOrderKeys() { + $data = array( + 9 => array('class' => 510, 'test2' => 2), + 1 => array('class' => 500, 'test2' => 1), + 2 => array('class' => 600, 'test2' => 2), + 5 => array('class' => 625, 'test2' => 4), + 0 => array('class' => 605, 'test2' => 3), + ); + $expected = array( + array('class' => 500, 'test2' => 1), + array('class' => 510, 'test2' => 2), + array('class' => 600, 'test2' => 2), + array('class' => 605, 'test2' => 3), + array('class' => 625, 'test2' => 4), + ); + $result = Set::sort($data, '{n}.class', 'asc'); + $this->assertEqual($expected, $result); + + $result = Set::sort($data, '{n}.test2', 'asc'); + $this->assertEqual($expected, $result); + } + /** * testExtract method * From 15ca2400bc546a42cdea462f6609cc65e0db6a8f Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 25 Nov 2010 06:52:23 -0500 Subject: [PATCH 029/125] Fixing issue in DboSource::name() where special characters in column names would not be correctly quoted. Tests added. Fixes #1264 --- cake/libs/model/datasources/dbo_source.php | 2 +- cake/tests/cases/libs/model/datasources/dbo_source.test.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cake/libs/model/datasources/dbo_source.php b/cake/libs/model/datasources/dbo_source.php index 3f82a09d9..42d7db354 100755 --- a/cake/libs/model/datasources/dbo_source.php +++ b/cake/libs/model/datasources/dbo_source.php @@ -542,7 +542,7 @@ class DboSource extends DataSource { return $return; } $data = trim($data); - if (preg_match('/^[\w-]+(\.[\w-]+)*$/', $data)) { // string, string.string + if (preg_match('/^[\w-]+(?:\.[^ \*]*)*$/', $data)) { // string, string.string if (strpos($data, '.') === false) { // string return $this->cacheMethod(__FUNCTION__, $cacheKey, $this->startQuote . $data . $this->endQuote); } diff --git a/cake/tests/cases/libs/model/datasources/dbo_source.test.php b/cake/tests/cases/libs/model/datasources/dbo_source.test.php index bcb11045d..d60898dab 100644 --- a/cake/tests/cases/libs/model/datasources/dbo_source.test.php +++ b/cake/tests/cases/libs/model/datasources/dbo_source.test.php @@ -4077,6 +4077,10 @@ class DboSourceTest extends CakeTestCase { $result = $this->testDb->name(array('my-name', 'Foo-Model.*')); $expected = array('`my-name`', '`Foo-Model`.*'); $this->assertEqual($result, $expected); + + $result = $this->testDb->name(array('Team.P%', 'Team.G/G')); + $expected = array('`Team`.`P%`', '`Team`.`G/G`'); + $this->assertEqual($result, $expected); } /** From 70ae66edf7a0dccae40b1e004d190cf0a1a73170 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 27 Nov 2010 01:21:19 +0530 Subject: [PATCH 030/125] Fixing test cases for EmailComponent --- .../tests/cases/libs/controller/components/email.test.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cake/tests/cases/libs/controller/components/email.test.php b/cake/tests/cases/libs/controller/components/email.test.php index 8379e3e7b..3a0472877 100755 --- a/cake/tests/cases/libs/controller/components/email.test.php +++ b/cake/tests/cases/libs/controller/components/email.test.php @@ -693,7 +693,7 @@ TEXTBLOC; $this->assertPattern('/Subject: Cake Debug Test\n/', $result); $this->assertPattern('/Reply-To: noreply@example.com\n/', $result); $this->assertPattern('/From: noreply@example.com\n/', $result); - $this->assertPattern('/Date: ' . date(DATE_RFC2822) . '\n/', $result); + $this->assertPattern('/Date: ' . preg_quote(date(DATE_RFC2822)) . '\n/', $result); $this->assertPattern('/X-Mailer: CakePHP Email Component\n/', $result); $this->assertPattern('/Content-Type: text\/plain; charset=UTF-8\n/', $result); $this->assertPattern('/Content-Transfer-Encoding: 7bitParameters:\n/', $result); @@ -721,7 +721,7 @@ TEXTBLOC; $this->assertPattern('/Subject: Cake Debug Test\n/', $result); $this->assertPattern('/Reply-To: noreply@example.com\n/', $result); $this->assertPattern('/From: noreply@example.com\n/', $result); - $this->assertPattern('/Date: ' . date(DATE_RFC2822) . '\n/', $result); + $this->assertPattern('/Date: ' . preg_quote(date(DATE_RFC2822)) . '\n/', $result); $this->assertPattern('/X-Mailer: CakePHP Email Component\n/', $result); $this->assertPattern('/Content-Type: text\/plain; charset=UTF-8\n/', $result); $this->assertPattern('/Content-Transfer-Encoding: 7bitParameters:\n/', $result); @@ -1217,10 +1217,10 @@ HTMLBLOC; $result = $this->Controller->EmailTest->formatAddress('email@example.com', true); $this->assertEqual($result, ''); - + $result = $this->Controller->EmailTest->formatAddress('', true); $this->assertEqual($result, ''); - + $result = $this->Controller->EmailTest->formatAddress('alias name ', true); $this->assertEqual($result, ''); } From 1186bc56f194defe827dd0802ea17cc243b5b836 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 27 Nov 2010 02:11:43 +0530 Subject: [PATCH 031/125] Adding EmailCompnent::lineFeed property toallow overriding the default line feed string when using mail() function to send mail. Closes #1320 --- cake/libs/controller/components/email.php | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/cake/libs/controller/components/email.php b/cake/libs/controller/components/email.php index d27fd5c13..2aa96c3e0 100755 --- a/cake/libs/controller/components/email.php +++ b/cake/libs/controller/components/email.php @@ -98,7 +98,7 @@ class EmailComponent extends Object{ var $bcc = array(); /** - * The date to put in the Date: header. This should be a date + * The date to put in the Date: header. This should be a date * conformant with the RFC2822 standard. Leave null, to have * today's date generated. * @@ -157,6 +157,18 @@ class EmailComponent extends Object{ */ var $lineLength = 70; +/** + * Line feed character(s) to be used when sending using mail() function + * If null PHP_EOL is used. + * RFC2822 requires it to be CRLF but some Unix + * mail transfer agents replace LF by CRLF automatically + * (which leads to doubling CR if CRLF is used). + * + * @var string + * @access public + */ + var $lineFeed = null; + /** * @deprecated see lineLength */ @@ -804,8 +816,13 @@ class EmailComponent extends Object{ * @access private */ function _mail() { - $header = implode("\r\n", $this->__header); - $message = implode("\r\n", $this->__message); + if ($this->lineFeed === null) { + $lineFeed = PHP_EOL; + } else { + $lineFeed = $this->lineFeed; + } + $header = implode($lineFeed, $this->__header); + $message = implode($lineFeed, $this->__message); if (is_array($this->to)) { $to = implode(', ', array_map(array($this, '_formatAddress'), $this->to)); } else { From 547f48fb03ca6a0247028fcf8453e6431b4f25a2 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 26 Nov 2010 23:00:26 -0200 Subject: [PATCH 032/125] Changing to be compatible with PHP 5.2+ --- cake/libs/http_socket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index da67a28ab..8ae54948c 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -459,7 +459,7 @@ class HttpSocket extends CakeSocket { if (!App::import('Lib', 'http/' . $authClass)) { throw new Exception(__('Unknown authentication method.')); } - $authClass::authentication($this); + call_user_func("$authClass::authentication", $this); } /** From c55a57927c0ec3b20cae7515de1ebb972bfe3c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Markovi=C4=87?= Date: Tue, 30 Nov 2010 18:35:43 +0100 Subject: [PATCH 033/125] Typos in documentation: reguired -> required --- cake/libs/controller/components/cookie.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cake/libs/controller/components/cookie.php b/cake/libs/controller/components/cookie.php index 38c5f00ae..002395b7b 100644 --- a/cake/libs/controller/components/cookie.php +++ b/cake/libs/controller/components/cookie.php @@ -184,7 +184,7 @@ class CookieComponent extends Object { /** * Write a value to the $_COOKIE[$key]; * - * Optional [Name.], reguired key, optional $value, optional $encrypt, optional $expires + * Optional [Name.], required key, optional $value, optional $encrypt, optional $expires * $this->Cookie->write('[Name.]key, $value); * * By default all values are encrypted. @@ -205,7 +205,7 @@ class CookieComponent extends Object { } $this->__encrypted = $encrypt; $this->__expire($expires); - + if (!is_array($key)) { $key = array($key => $value); } @@ -214,7 +214,7 @@ class CookieComponent extends Object { if (strpos($name, '.') === false) { $this->__values[$name] = $value; $this->__write("[$name]", $value); - + } else { $names = explode('.', $name, 2); if (!isset($this->__values[$names[0]])) { @@ -230,7 +230,7 @@ class CookieComponent extends Object { /** * Read the value of the $_COOKIE[$key]; * - * Optional [Name.], reguired key + * Optional [Name.], required key * $this->Cookie->read(Name.key); * * @param mixed $key Key of the value to be obtained. If none specified, obtain map key => values @@ -245,7 +245,7 @@ class CookieComponent extends Object { if (is_null($key)) { return $this->__values; } - + if (strpos($key, '.') !== false) { $names = explode('.', $key, 2); $key = $names[0]; @@ -263,7 +263,7 @@ class CookieComponent extends Object { /** * Delete a cookie value * - * Optional [Name.], reguired key + * Optional [Name.], required key * $this->Cookie->read('Name.key); * * You must use this method before any output is sent to the browser. @@ -344,11 +344,11 @@ class CookieComponent extends Object { return $this->__expires; } $this->__reset = $this->__expires; - + if ($expires == 0) { return $this->__expires = 0; } - + if (is_integer($expires) || is_numeric($expires)) { return $this->__expires = $now + intval($expires); } From b9010b05f2f272c3ba2c7632223f6f1f2837090a Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 1 Dec 2010 13:46:13 -0200 Subject: [PATCH 034/125] Support to proxy in HttpSocket. --- cake/libs/http_socket.php | 43 +++++++++- cake/tests/cases/libs/http_socket.test.php | 99 ++++++++++++++++++++++ 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 1297c122f..ad943bbcb 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -64,6 +64,13 @@ class HttpSocket extends CakeSocket { 'user' => null, 'pass' => null ), + 'proxy' => array( + 'method' => 'Basic', + 'host' => null, + 'port' => 3128, + 'user' => null, + 'pass' => null + ), 'version' => '1.1', 'body' => '', 'line' => null, @@ -121,6 +128,13 @@ class HttpSocket extends CakeSocket { 'user' => null, 'pass' => null ), + 'proxy' => array( + 'method' => 'Basic', + 'host' => null, + 'port' => 3128, + 'user' => null, + 'pass' => null + ), 'cookies' => array() ) ); @@ -238,6 +252,7 @@ class HttpSocket extends CakeSocket { } $this->_setAuth(); + $this->_setProxyConfig(); if (is_array($this->request['body'])) { $this->request['body'] = $this->_httpSerialize($this->request['body']); @@ -463,6 +478,28 @@ class HttpSocket extends CakeSocket { call_user_func("$authClass::authentication", $this); } +/** + * Set the proxy configuration and authentication + * + * @return void + */ + protected function _setProxyConfig() { + if (empty($this->request['proxy']['host'])) { + return; + } + $this->config['host'] = $this->request['proxy']['host']; + $this->config['port'] = $this->request['proxy']['port']; + + if (empty($this->request['proxy']['method']) || !isset($this->request['proxy']['user'], $this->request['proxy']['pass'])) { + return; + } + $authClass = Inflector::camelize($this->request['proxy']['method']) . 'Authentication'; + if (!App::import('Lib', 'http/' . $authClass)) { + throw new Exception(__('Unknown authentication method for proxy.')); + } + call_user_func("$authClass::proxyAuthentication", $this); + } + /** * Parses the given message and breaks it down in parts. * @@ -837,7 +874,11 @@ class HttpSocket extends CakeSocket { $request['uri'] = $this->_parseUri($request['uri']); $request = array_merge(array('method' => 'GET'), $request); - $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query'); + if (!empty($request['proxy']['host'])) { + $request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query'); + } else { + $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query'); + } if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) { throw new Exception(sprintf(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.'), join(',', $asteriskMethods))); diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index fe6ec1c70..877d52ac1 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -19,6 +19,36 @@ */ App::import('Core', 'HttpSocket'); +/** + * TestAuthentication class + * + * @package cake + * @subpackage cake.tests.cases.libs + */ +class TestAuthentication { + +/** + * authentication method + * + * @param HttpSocket $http + * @return void + */ + public static function authentication(HttpSocket $http) { + $http->request['header']['Authorization'] = 'Test ' . $http->request['auth']['user'] . '.' . $http->request['auth']['pass']; + } + +/** + * proxyAuthentication method + * + * @param HttpSocket $http + * @return void + */ + public static function proxyAuthentication(HttpSocket $http) { + $http->request['header']['Proxy-Authorization'] = 'Test ' . $http->request['proxy']['user'] . '.' . $http->request['proxy']['pass']; + } + +} + class TestHttpSocket extends HttpSocket { /** @@ -261,6 +291,13 @@ class HttpSocketTest extends CakeTestCase { , 'user' => 'bob' , 'pass' => 'secret' ), + 'proxy' => array( + 'method' => 'Basic', + 'host' => null, + 'port' => 3128, + 'user' => null, + 'pass' => null + ), 'cookies' => array(), ) ); @@ -290,6 +327,13 @@ class HttpSocketTest extends CakeTestCase { , 'user' => null , 'pass' => null ), + 'proxy' => array( + 'method' => 'Basic', + 'host' => null, + 'port' => 3128, + 'user' => null, + 'pass' => null + ), 'cookies' => array() ) ); @@ -336,6 +380,13 @@ class HttpSocketTest extends CakeTestCase { ,'user' => null ,'pass' => null ), + 'proxy' => array( + 'method' => 'Basic', + 'host' => null, + 'port' => 3128, + 'user' => null, + 'pass' => null + ), 'cookies' => array(), ), ) @@ -355,6 +406,13 @@ class HttpSocketTest extends CakeTestCase { 'method' => 'Basic' , 'user' => null , 'pass' => null + ), + 'proxy' => array( + 'method' => 'Basic', + 'host' => null, + 'port' => 3128, + 'user' => null, + 'pass' => null ) , 'version' => '1.1' , 'body' => '' @@ -588,6 +646,47 @@ class HttpSocketTest extends CakeTestCase { $this->assertFalse($this->Socket->connected); } +/** + * testProxy method + * + * @return void + */ + function testProxy() { + $this->Socket->reset(); + $this->Socket->expects($this->any())->method('connect')->will($this->returnValue(true)); + $this->Socket->expects($this->any())->method('read')->will($this->returnValue(false)); + $request = array( + 'uri' => 'http://www.cakephp.org/', + 'proxy' => array( + 'host' => 'proxy.server', + 'port' => 123 + ) + ); + $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n\r\n"; + $this->Socket->request($request); + $this->assertEqual($this->Socket->request['raw'], $expected); + $this->assertEqual($this->Socket->config['host'], 'proxy.server'); + $this->assertEqual($this->Socket->config['port'], 123); + + $request['proxy']['method'] = 'Test'; + $request['proxy']['user'] = 'mark'; + $request['proxy']['pass'] = 'secret'; + $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; + $this->Socket->request($request); + $this->assertEqual($this->Socket->request['raw'], $expected); + $this->assertEqual($this->Socket->config['host'], 'proxy.server'); + $this->assertEqual($this->Socket->config['port'], 123); + + $request['auth'] = array( + 'method' => 'Test', + 'user' => 'login', + 'pass' => 'passwd' + ); + $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nAuthorization: Test login.passwd\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; + $this->Socket->request($request); + $this->assertEqual($this->Socket->request['raw'], $expected); + } + /** * testUrl method * From 64dcca61ef2479e1d92226feba6d12c23291ff9d Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 1 Dec 2010 13:49:03 -0200 Subject: [PATCH 035/125] Throw exception when authentication class dont support authentication/proxyAuthentication method. --- cake/libs/http_socket.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index ad943bbcb..70a86c582 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -475,6 +475,9 @@ class HttpSocket extends CakeSocket { if (!App::import('Lib', 'http/' . $authClass)) { throw new Exception(__('Unknown authentication method.')); } + if (!method_exists($authClass, 'authentication')) { + throw new Exception(sprintf(__('The %s do not support authentication.'), $authClass)); + } call_user_func("$authClass::authentication", $this); } @@ -497,6 +500,9 @@ class HttpSocket extends CakeSocket { if (!App::import('Lib', 'http/' . $authClass)) { throw new Exception(__('Unknown authentication method for proxy.')); } + if (!method_exists($authClass, 'proxyAuthentication')) { + throw new Exception(sprintf(__('The %s do not support proxy authentication.'), $authClass)); + } call_user_func("$authClass::proxyAuthentication", $this); } From e1e802639252a231d9c8faf3aa37c91043492d9c Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 1 Dec 2010 14:00:10 -0200 Subject: [PATCH 036/125] Support to proxy authentication in basic authentication. --- cake/libs/http/basic_authentication.php | 28 +++++++++++++++++-- .../libs/http/basic_authentication.test.php | 17 +++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/cake/libs/http/basic_authentication.php b/cake/libs/http/basic_authentication.php index 7cd01b7cb..4a857e68e 100644 --- a/cake/libs/http/basic_authentication.php +++ b/cake/libs/http/basic_authentication.php @@ -31,12 +31,36 @@ class BasicAuthentication { * * @param HttpSocket $http * @return void - * @throws Exception + * @see http://www.ietf.org/rfc/rfc2617.txt */ public static function authentication(HttpSocket $http) { if (isset($http->request['auth']['user'], $http->request['auth']['pass'])) { - $http->request['header']['Authorization'] = 'Basic ' . base64_encode($http->request['auth']['user'] . ':' . $http->request['auth']['pass']); + $http->request['header']['Authorization'] = self::_generateHeader($http->request['auth']['user'], $http->request['auth']['pass']); } } +/** + * Proxy Authentication + * + * @param HttpSocket $http + * @return void + * @see http://www.ietf.org/rfc/rfc2617.txt + */ + public static function proxyAuthentication(HttpSocket $http) { + if (isset($http->request['proxy']['user'], $http->request['proxy']['pass'])) { + $http->request['header']['Proxy-Authorization'] = self::_generateHeader($http->request['proxy']['user'], $http->request['proxy']['pass']); + } + } + +/** + * Generate basic [proxy] authentication header + * + * @param string $user + * @param string $pass + * @return string + */ + protected static function _generateHeader($user, $pass) { + return 'Basic ' . base64_encode($user . ':' . $pass); + } + } diff --git a/cake/tests/cases/libs/http/basic_authentication.test.php b/cake/tests/cases/libs/http/basic_authentication.test.php index 9843e4815..3df447b55 100644 --- a/cake/tests/cases/libs/http/basic_authentication.test.php +++ b/cake/tests/cases/libs/http/basic_authentication.test.php @@ -46,4 +46,21 @@ class BasicMethodTest extends CakeTestCase { $this->assertEqual($http->request['header']['Authorization'], 'Basic bWFyazpzZWNyZXQ='); } +/** + * testProxyAuthentication method + * + * @return void + */ + public function testProxyAuthentication() { + $http = new HttpSocket(); + $http->request['proxy'] = array( + 'method' => 'Basic', + 'user' => 'mark', + 'pass' => 'secret' + ); + + BasicAuthentication::proxyAuthentication($http); + $this->assertEqual($http->request['header']['Proxy-Authorization'], 'Basic bWFyazpzZWNyZXQ='); + } + } \ No newline at end of file From 96b30f0547dd9e85d768e05da83a2dd702b5812b Mon Sep 17 00:00:00 2001 From: dogmatic69 Date: Wed, 1 Dec 2010 17:07:45 +0000 Subject: [PATCH 037/125] adding tests for places that will leave a trailing 0 because of the way phps number_format() method works Signed-off-by: mark_story --- cake/tests/cases/libs/view/helpers/number.test.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cake/tests/cases/libs/view/helpers/number.test.php b/cake/tests/cases/libs/view/helpers/number.test.php index d5f88aa61..0e2a53f5b 100644 --- a/cake/tests/cases/libs/view/helpers/number.test.php +++ b/cake/tests/cases/libs/view/helpers/number.test.php @@ -321,6 +321,14 @@ class NumberHelperTest extends CakeTestCase { $expected = '£1,234,568'; $this->assertEqual($expected, $result); + $result = $this->Number->currency('1234567.8912345', null, array('before' => 'GBP', 'places' => 3)); + $expected = 'GBP1,234,567.891'; + $this->assertEqual($expected, $result); + + $result = $this->Number->currency('650.120001', null, array('before' => 'GBP', 'places' => 4)); + $expected = 'GBP650.1200'; + $this->assertEqual($expected, $result); + $result = $this->Number->currency($value, 'GBP', array('escape' => true)); $expected = '&#163;1,234,567.89'; $this->assertEqual($expected, $result); From 44b09171ef9d9910778c8b8adf7891b05a2c60b0 Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 1 Dec 2010 23:47:30 -0500 Subject: [PATCH 038/125] Adding unicode letters and numbers to url path segment regex. Test case added. Fixes #1284 --- cake/libs/validation.php | 4 ++-- cake/tests/cases/libs/validation.test.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cake/libs/validation.php b/cake/libs/validation.php index 51572e75e..71d178933 100644 --- a/cake/libs/validation.php +++ b/cake/libs/validation.php @@ -874,13 +874,13 @@ class Validation extends Object { $_this =& Validation::getInstance(); $_this->__populateIp(); $_this->check = $check; - $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~') . '\/0-9a-z]|(%[0-9a-f]{2}))'; + $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~') . '\/0-9a-z\p{L}\p{N}]|(%[0-9a-f]{2}))'; $_this->regex = '/^(?:(?:https?|ftps?|file|news|gopher):\/\/)' . (!empty($strict) ? '' : '?') . '(?:' . $_this->__pattern['IPv4'] . '|\[' . $_this->__pattern['IPv6'] . '\]|' . $_this->__pattern['hostname'] . ')' . '(?::[1-9][0-9]{0,4})?' . '(?:\/?|\/' . $validChars . '*)?' . '(?:\?' . $validChars . '*)?' . - '(?:#' . $validChars . '*)?$/i'; + '(?:#' . $validChars . '*)?$/iu'; return $_this->_check(); } diff --git a/cake/tests/cases/libs/validation.test.php b/cake/tests/cases/libs/validation.test.php index 5c51b1bad..3ac9d97a2 100644 --- a/cake/tests/cases/libs/validation.test.php +++ b/cake/tests/cases/libs/validation.test.php @@ -1879,6 +1879,7 @@ class ValidationTest extends CakeTestCase { $this->assertTrue(Validation::url('http://example.com/~userdir/subdir/index.html')); $this->assertTrue(Validation::url('http://www.zwischenraume.de')); $this->assertTrue(Validation::url('http://www.zwischenraume.cz')); + $this->assertTrue(Validation::url('http://www.last.fm/music/浜崎あゆみ'), 'utf8 path failed'); $this->assertTrue(Validation::url('http://cakephp.org:80')); $this->assertTrue(Validation::url('http://cakephp.org:443')); From cd24aca39d9262fa43410566b6ddbe29eae7c9ef Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 3 Dec 2010 00:46:11 -0200 Subject: [PATCH 039/125] Removing auth key from request and putting this as attribute. --- cake/libs/http/basic_authentication.php | 7 +- cake/libs/http_socket.php | 70 ++++++++++--------- .../libs/http/basic_authentication.test.php | 4 +- cake/tests/cases/libs/http_socket.test.php | 40 ++--------- 4 files changed, 46 insertions(+), 75 deletions(-) diff --git a/cake/libs/http/basic_authentication.php b/cake/libs/http/basic_authentication.php index 4a857e68e..393f4a867 100644 --- a/cake/libs/http/basic_authentication.php +++ b/cake/libs/http/basic_authentication.php @@ -30,12 +30,13 @@ class BasicAuthentication { * Authentication * * @param HttpSocket $http + * @param array $authInfo * @return void * @see http://www.ietf.org/rfc/rfc2617.txt */ - public static function authentication(HttpSocket $http) { - if (isset($http->request['auth']['user'], $http->request['auth']['pass'])) { - $http->request['header']['Authorization'] = self::_generateHeader($http->request['auth']['user'], $http->request['auth']['pass']); + public static function authentication(HttpSocket $http, &$authInfo) { + if (isset($authInfo['user'], $authInfo['pass'])) { + $http->request['header']['Authorization'] = self::_generateHeader($authInfo['user'], $authInfo['pass']); } } diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 70a86c582..45abaa079 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -59,11 +59,6 @@ class HttpSocket extends CakeSocket { 'query' => null, 'fragment' => null ), - 'auth' => array( - 'method' => 'Basic', - 'user' => null, - 'pass' => null - ), 'proxy' => array( 'method' => 'Basic', 'host' => null, @@ -123,11 +118,6 @@ class HttpSocket extends CakeSocket { 'host' => 'localhost', 'port' => 80 ), - 'auth' => array( - 'method' => 'Basic', - 'user' => null, - 'pass' => null - ), 'proxy' => array( 'method' => 'Basic', 'host' => null, @@ -147,6 +137,14 @@ class HttpSocket extends CakeSocket { */ public $lineBreak = "\r\n"; +/** + * Authentication settings + * + * @var array + * @access protected + */ + protected $_auth = array(); + /** * Build an HTTP Socket using the specified configuration. * @@ -181,6 +179,26 @@ class HttpSocket extends CakeSocket { parent::__construct($this->config); } +/** + * Set authentication settings + * + * @param string $method Authentication method (ex. Basic, Digest). If empty, disable authentication + * @param mixed $user Username for authentication. Can be an array with settings to authentication class + * @param string $pass Password for authentication + * @return void + */ + public function setAuthConfig($method, $user, $pass = null) { + if (empty($method)) { + $this->_auth = array(); + return; + } + if (is_array($user)) { + $this->_auth = array($method => $user); + return; + } + $this->_auth = array($method => compact('user', 'pass')); + } + /** * Issue the specified request. HttpSocket::get() and HttpSocket::post() wrap this * method and provide a more granular interface. @@ -201,10 +219,6 @@ class HttpSocket extends CakeSocket { $request['uri'] = null; } $uri = $this->_parseUri($request['uri']); - $hadAuth = false; - if (is_array($uri) && array_key_exists('user', $uri)) { - $hadAuth = true; - } if (!isset($uri['host'])) { $host = $this->config['host']; } @@ -216,10 +230,6 @@ class HttpSocket extends CakeSocket { $request['uri'] = $this->_parseUri($request['uri'], true); $this->request = Set::merge($this->request, $this->config['request'], $request); - if (!$hadAuth && !empty($this->config['request']['auth']['user'])) { - $this->request['uri']['user'] = $this->config['request']['auth']['user']; - $this->request['uri']['pass'] = $this->config['request']['auth']['pass']; - } $this->_configUri($this->request['uri']); if (isset($host)) { @@ -251,6 +261,9 @@ class HttpSocket extends CakeSocket { $this->request['header'] = array_merge(compact('Host'), $this->request['header']); } + if (isset($this->request['uri']['user'], $this->request['uri']['pass'])) { + $this->setAuthConfig('Basic', $this->request['uri']['user'], $this->request['uri']['pass']); + } $this->_setAuth(); $this->_setProxyConfig(); @@ -457,28 +470,18 @@ class HttpSocket extends CakeSocket { * @throws Exception */ protected function _setAuth() { - if ($this->request['auth']['method'] === false) { + if (empty($this->_auth)) { return; } - if (empty($this->request['auth']['method'])) { - if (isset($this->request['uri']['user'], $this->request['uri']['pass']) && !isset($this->request['auth']['user'])) { - $this->request['auth'] = array( - 'method' => 'Basic', - 'user' => $this->request['uri']['user'], - 'pass' => $this->request['uri']['pass'] - ); - } else { - return; - } - } - $authClass = Inflector::camelize($this->request['auth']['method']) . 'Authentication'; + $method = key($this->_auth); + $authClass = Inflector::camelize($method) . 'Authentication'; if (!App::import('Lib', 'http/' . $authClass)) { throw new Exception(__('Unknown authentication method.')); } if (!method_exists($authClass, 'authentication')) { throw new Exception(sprintf(__('The %s do not support authentication.'), $authClass)); } - call_user_func("$authClass::authentication", $this); + call_user_func("$authClass::authentication", $this, &$this->_auth[$method]); } /** @@ -677,8 +680,7 @@ class HttpSocket extends CakeSocket { } $config = array( 'request' => array( - 'uri' => array_intersect_key($uri, $this->config['request']['uri']), - 'auth' => array_intersect_key($uri, $this->config['request']['auth']) + 'uri' => array_intersect_key($uri, $this->config['request']['uri']) ) ); $this->config = Set::merge($this->config, $config); diff --git a/cake/tests/cases/libs/http/basic_authentication.test.php b/cake/tests/cases/libs/http/basic_authentication.test.php index 3df447b55..7ba642b64 100644 --- a/cake/tests/cases/libs/http/basic_authentication.test.php +++ b/cake/tests/cases/libs/http/basic_authentication.test.php @@ -36,13 +36,13 @@ class BasicMethodTest extends CakeTestCase { */ public function testAuthentication() { $http = new HttpSocket(); - $http->request['auth'] = array( + $auth = array( 'method' => 'Basic', 'user' => 'mark', 'pass' => 'secret' ); - BasicAuthentication::authentication($http); + BasicAuthentication::authentication($http, $auth); $this->assertEqual($http->request['header']['Authorization'], 'Basic bWFyazpzZWNyZXQ='); } diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 877d52ac1..99f3f0cdb 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -31,10 +31,11 @@ class TestAuthentication { * authentication method * * @param HttpSocket $http + * @param array $authInfo * @return void */ - public static function authentication(HttpSocket $http) { - $http->request['header']['Authorization'] = 'Test ' . $http->request['auth']['user'] . '.' . $http->request['auth']['pass']; + public static function authentication(HttpSocket $http, &$authInfo) { + $http->request['header']['Authorization'] = 'Test ' . $authInfo['user'] . '.' . $authInfo['pass']; } /** @@ -286,11 +287,6 @@ class HttpSocketTest extends CakeTestCase { , 'host' => 'www.cakephp.org' , 'port' => 23 ), - 'auth' => array( - 'method' => 'Basic' - , 'user' => 'bob' - , 'pass' => 'secret' - ), 'proxy' => array( 'method' => 'Basic', 'host' => null, @@ -322,11 +318,6 @@ class HttpSocketTest extends CakeTestCase { , 'host' => 'www.foo.com' , 'port' => 80 ), - 'auth' => array( - 'method' => 'Basic' - , 'user' => null - , 'pass' => null - ), 'proxy' => array( 'method' => 'Basic', 'host' => null, @@ -374,11 +365,6 @@ class HttpSocketTest extends CakeTestCase { 'scheme' => 'http' , 'host' => 'www.cakephp.org' , 'port' => 80, - ) - , 'auth' => array( - 'method' => 'Basic' - ,'user' => null - ,'pass' => null ), 'proxy' => array( 'method' => 'Basic', @@ -401,11 +387,6 @@ class HttpSocketTest extends CakeTestCase { , 'path' => '/' , 'query' => array('foo' => 'bar') , 'fragment' => null - ) - , 'auth' => array( - 'method' => 'Basic' - , 'user' => null - , 'pass' => null ), 'proxy' => array( 'method' => 'Basic', @@ -677,11 +658,7 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($this->Socket->config['host'], 'proxy.server'); $this->assertEqual($this->Socket->config['port'], 123); - $request['auth'] = array( - 'method' => 'Test', - 'user' => 'login', - 'pass' => 'passwd' - ); + $this->Socket->setAuthConfig('Test', 'login', 'passwd'); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nAuthorization: Test login.passwd\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; $this->Socket->request($request); $this->assertEqual($this->Socket->request['raw'], $expected); @@ -785,24 +762,15 @@ class HttpSocketTest extends CakeTestCase { */ function testConsecutiveGetResetsAuthCredentials() { $socket = new MockHttpSocket(); - $socket->config['request']['auth'] = array( - 'method' => 'Basic', - 'user' => 'mark', - 'pass' => 'secret' - ); $socket->get('http://mark:secret@example.com/test'); $this->assertEqual($socket->request['uri']['user'], 'mark'); $this->assertEqual($socket->request['uri']['pass'], 'secret'); $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); $socket->get('/test2'); - $this->assertEqual($socket->request['auth']['user'], 'mark'); - $this->assertEqual($socket->request['auth']['pass'], 'secret'); $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); $socket->get('/test3'); - $this->assertEqual($socket->request['auth']['user'], 'mark'); - $this->assertEqual($socket->request['auth']['pass'], 'secret'); $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); } From 4325e671630a30bb8313d2364c990718a0e2ffcc Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 3 Dec 2010 01:30:03 -0200 Subject: [PATCH 040/125] Fixing setAuthConfig to accept false as param to remove auth config. Tests added. --- cake/libs/http_socket.php | 2 +- cake/tests/cases/libs/http_socket.test.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 45abaa079..d5ed518ad 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -187,7 +187,7 @@ class HttpSocket extends CakeSocket { * @param string $pass Password for authentication * @return void */ - public function setAuthConfig($method, $user, $pass = null) { + public function setAuthConfig($method, $user = null, $pass = null) { if (empty($method)) { $this->_auth = array(); return; diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 99f3f0cdb..06b055928 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -755,6 +755,25 @@ class HttpSocketTest extends CakeTestCase { $this->RequestSocket->get('http://www.google.com/', null, array('auth' => array('user' => 'foo', 'pass' => 'bar'))); } +/** + * Test authentication + * + * @return void + */ + public function testAuth() { + $socket = new MockHttpSocket(); + $socket->get('http://mark:secret@example.com/test'); + $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); + + $socket->setAuthConfig(false); + $socket->get('http://example.com/test'); + $this->assertFalse(strpos($socket->request['header'], 'Authorization:')); + + $socket->setAuthConfig('Test', 'mark', 'passwd'); + $socket->get('http://example.com/test'); + $this->assertTrue(strpos($socket->request['header'], 'Authorization: Test mark.passwd') !== false); + } + /** * test that two consecutive get() calls reset the authentication credentials. * From f004bef74fac8db830fe8e7e8f86a303b4dafdaf Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 3 Dec 2010 21:57:15 -0200 Subject: [PATCH 041/125] DigestAuthentication adapted to new auth in HttpSocket. --- cake/libs/http/digest_authentication.php | 50 +++++++++------- .../libs/http/digest_authentication.test.php | 60 +++++++++---------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/cake/libs/http/digest_authentication.php b/cake/libs/http/digest_authentication.php index b25c6c971..ba146e2fc 100644 --- a/cake/libs/http/digest_authentication.php +++ b/cake/libs/http/digest_authentication.php @@ -30,16 +30,17 @@ class DigestAuthentication { * Authentication * * @param HttpSocket $http + * @param array $authInfo * @return void * @throws Exception * @link http://www.ietf.org/rfc/rfc2617.txt */ - public static function authentication(HttpSocket $http) { - if (isset($http->request['auth']['user'], $http->request['auth']['pass'])) { - if (!isset($http->config['request']['auth']['realm']) && !self::_getServerInformation($http)) { + public static function authentication(HttpSocket $http, &$authInfo) { + if (isset($authInfo['user'], $authInfo['pass'])) { + if (!isset($authInfo['realm']) && !self::_getServerInformation($http, $authInfo)) { return; } - $http->request['header']['Authorization'] = self::_generateHeader($http); + $http->request['header']['Authorization'] = self::_generateHeader($http, $authInfo); } } @@ -47,23 +48,25 @@ class DigestAuthentication { * Retrive information about the authetication * * @param HttpSocket $http + * @parma array $authInfo * @return boolean */ - protected static function _getServerInformation(HttpSocket $http) { + protected static function _getServerInformation(HttpSocket $http, &$authInfo) { $originalRequest = $http->request; - $http->request['auth'] = array('method' => false); + $http->setAuthConfig(false); $http->request($http->request); $http->request = $originalRequest; + $http->setAuthConfig('Digest', $authInfo); if (empty($http->response['header']['WWW-Authenticate'])) { return false; } preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $http->response['header']['WWW-Authenticate'], $matches, PREG_SET_ORDER); foreach ($matches as $match) { - $http->config['request']['auth'][$match[1]] = $match[2]; + $authInfo[$match[1]] = $match[2]; } - if (!empty($http->config['request']['auth']['qop']) && empty($http->config['request']['auth']['nc'])) { - $http->config['request']['auth']['nc'] = 1; + if (!empty($authInfo['qop']) && empty($authInfo['nc'])) { + $authInfo['nc'] = 1; } return true; } @@ -72,31 +75,32 @@ class DigestAuthentication { * Generate the header Authorization * * @param HttpSocket $http + * @param array $authInfo * @return string */ - protected static function _generateHeader(HttpSocket $http) { - $a1 = md5($http->request['auth']['user'] . ':' . $http->config['request']['auth']['realm'] . ':' . $http->request['auth']['pass']); + protected static function _generateHeader(HttpSocket $http, &$authInfo) { + $a1 = md5($authInfo['user'] . ':' . $authInfo['realm'] . ':' . $authInfo['pass']); $a2 = md5($http->request['method'] . ':' . $http->request['uri']['path']); - if (empty($http->config['request']['auth']['qop'])) { - $response = md5($a1 . ':' . $http->config['request']['auth']['nonce'] . ':' . $a2); + if (empty($authInfo['qop'])) { + $response = md5($a1 . ':' . $authInfo['nonce'] . ':' . $a2); } else { - $http->config['request']['auth']['cnonce'] = uniqid(); - $nc = sprintf('%08x', $http->config['request']['auth']['nc']++); - $response = md5($a1 . ':' . $http->config['request']['auth']['nonce'] . ':' . $nc . ':' . $http->config['request']['auth']['cnonce'] . ':auth:' . $a2); + $authInfo['cnonce'] = uniqid(); + $nc = sprintf('%08x', $authInfo['nc']++); + $response = md5($a1 . ':' . $authInfo['nonce'] . ':' . $nc . ':' . $authInfo['cnonce'] . ':auth:' . $a2); } $authHeader = 'Digest '; - $authHeader .= 'username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $http->request['auth']['user']) . '", '; - $authHeader .= 'realm="' . $http->config['request']['auth']['realm'] . '", '; - $authHeader .= 'nonce="' . $http->config['request']['auth']['nonce'] . '", '; + $authHeader .= 'username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $authInfo['user']) . '", '; + $authHeader .= 'realm="' . $authInfo['realm'] . '", '; + $authHeader .= 'nonce="' . $authInfo['nonce'] . '", '; $authHeader .= 'uri="' . $http->request['uri']['path'] . '", '; $authHeader .= 'response="' . $response . '"'; - if (!empty($http->config['request']['auth']['opaque'])) { - $authHeader .= ', opaque="' . $http->config['request']['auth']['opaque'] . '"'; + if (!empty($authInfo['opaque'])) { + $authHeader .= ', opaque="' . $authInfo['opaque'] . '"'; } - if (!empty($http->config['request']['auth']['qop'])) { - $authHeader .= ', qop="auth", nc=' . $nc . ', cnonce="' . $http->config['request']['auth']['cnonce'] . '"'; + if (!empty($authInfo['qop'])) { + $authHeader .= ', qop="auth", nc=' . $nc . ', cnonce="' . $authInfo['cnonce'] . '"'; } return $authHeader; } diff --git a/cake/tests/cases/libs/http/digest_authentication.test.php b/cake/tests/cases/libs/http/digest_authentication.test.php index 75e98595e..2166aee24 100644 --- a/cake/tests/cases/libs/http/digest_authentication.test.php +++ b/cake/tests/cases/libs/http/digest_authentication.test.php @@ -72,11 +72,6 @@ class DigestAuthenticationTest extends CakeTestCase { $this->HttpSocket = new DigestHttpSocket(); $this->HttpSocket->request['method'] = 'GET'; $this->HttpSocket->request['uri']['path'] = '/'; - $this->HttpSocket->request['auth'] = array( - 'method' => 'Digest', - 'user' => 'admin', - 'pass' => '1234' - ); } /** @@ -95,12 +90,13 @@ class DigestAuthenticationTest extends CakeTestCase { */ public function testBasic() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; - $this->HttpSocket->config['request']['auth'] = array(); $this->assertFalse(isset($this->HttpSocket->request['header']['Authorization'])); - DigestAuthentication::authentication($this->HttpSocket); + + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $this->assertTrue(isset($this->HttpSocket->request['header']['Authorization'])); - $this->assertEqual($this->HttpSocket->config['request']['auth']['realm'], 'The batcave'); - $this->assertEqual($this->HttpSocket->config['request']['auth']['nonce'], '4cded326c6c51'); + $this->assertEqual($auth['realm'], 'The batcave'); + $this->assertEqual($auth['nonce'], '4cded326c6c51'); } /** @@ -110,20 +106,20 @@ class DigestAuthenticationTest extends CakeTestCase { */ public function testQop() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; - $this->HttpSocket->config['request']['auth'] = array(); - DigestAuthentication::authentication($this->HttpSocket); + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $expected = 'Digest username="admin", realm="The batcave", nonce="4cded326c6c51", uri="/", response="da7e2a46b471d77f70a9bb3698c8902b"'; $this->assertEqual($expected, $this->HttpSocket->request['header']['Authorization']); - $this->assertFalse(isset($this->HttpSocket->config['request']['auth']['qop'])); - $this->assertFalse(isset($this->HttpSocket->config['request']['auth']['nc'])); + $this->assertFalse(isset($auth['qop'])); + $this->assertFalse(isset($auth['nc'])); $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",qop="auth"'; - $this->HttpSocket->config['request']['auth'] = array(); - DigestAuthentication::authentication($this->HttpSocket); + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $expected = '@Digest username="admin", realm="The batcave", nonce="4cded326c6c51", uri="/", response="[a-z0-9]{32}", qop="auth", nc=00000001, cnonce="[a-z0-9]+"@'; $this->assertPattern($expected, $this->HttpSocket->request['header']['Authorization']); - $this->assertEqual($this->HttpSocket->config['request']['auth']['qop'], 'auth'); - $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 2); + $this->assertEqual($auth['qop'], 'auth'); + $this->assertEqual($auth['nc'], 2); } /** @@ -133,13 +129,13 @@ class DigestAuthenticationTest extends CakeTestCase { */ public function testOpaque() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; - $this->HttpSocket->config['request']['auth'] = array(); - DigestAuthentication::authentication($this->HttpSocket); + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $this->assertFalse(strpos($this->HttpSocket->request['header']['Authorization'], 'opaque="d8ea7aa61a1693024c4cc3a516f49b3c"')); $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",opaque="d8ea7aa61a1693024c4cc3a516f49b3c"'; - $this->HttpSocket->config['request']['auth'] = array(); - DigestAuthentication::authentication($this->HttpSocket); + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'opaque="d8ea7aa61a1693024c4cc3a516f49b3c"') > 0); } @@ -150,21 +146,21 @@ class DigestAuthenticationTest extends CakeTestCase { */ public function testMultipleRequest() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51",qop="auth"'; - $this->HttpSocket->config['request']['auth'] = array(); - DigestAuthentication::authentication($this->HttpSocket); + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000001') > 0); - $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 2); + $this->assertEqual($auth['nc'], 2); - DigestAuthentication::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket, $auth); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000002') > 0); - $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 3); + $this->assertEqual($auth['nc'], 3); $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); $response = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); $this->HttpSocket->nextHeader = ''; - DigestAuthentication::authentication($this->HttpSocket); + DigestAuthentication::authentication($this->HttpSocket, $auth); $this->assertTrue(strpos($this->HttpSocket->request['header']['Authorization'], 'nc=00000003') > 0); - $this->assertEqual($this->HttpSocket->config['request']['auth']['nc'], 4); + $this->assertEqual($auth['nc'], 4); $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); $response2 = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); $this->assertNotEqual($response, $response2); @@ -178,8 +174,8 @@ class DigestAuthenticationTest extends CakeTestCase { public function testPathChanged() { $this->HttpSocket->nextHeader = 'Digest realm="The batcave",nonce="4cded326c6c51"'; $this->HttpSocket->request['uri']['path'] = '/admin'; - $this->HttpSocket->config['request']['auth'] = array(); - DigestAuthentication::authentication($this->HttpSocket); + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $responsePos = strpos($this->HttpSocket->request['header']['Authorization'], 'response='); $response = substr($this->HttpSocket->request['header']['Authorization'], $responsePos + 10, 32); $this->assertNotEqual($response, 'da7e2a46b471d77f70a9bb3698c8902b'); @@ -193,8 +189,8 @@ class DigestAuthenticationTest extends CakeTestCase { public function testNoDigestResponse() { $this->HttpSocket->nextHeader = false; $this->HttpSocket->request['uri']['path'] = '/admin'; - $this->HttpSocket->config['request']['auth'] = array(); - DigestAuthentication::authentication($this->HttpSocket); + $auth = array('user' => 'admin', 'pass' => '1234'); + DigestAuthentication::authentication($this->HttpSocket, $auth); $this->assertFalse(isset($this->HttpSocket->request['header']['Authorization'])); } From 075bdebebe7c04ffa6d5d00b9a9cba4bc9809da3 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 3 Dec 2010 23:10:07 -0200 Subject: [PATCH 042/125] Moved the proxy configuration from request to class attribute. --- cake/libs/http/basic_authentication.php | 7 +-- cake/libs/http_socket.php | 60 ++++++++++++++-------- cake/tests/cases/libs/http_socket.test.php | 52 ++++--------------- 3 files changed, 51 insertions(+), 68 deletions(-) diff --git a/cake/libs/http/basic_authentication.php b/cake/libs/http/basic_authentication.php index 393f4a867..111246210 100644 --- a/cake/libs/http/basic_authentication.php +++ b/cake/libs/http/basic_authentication.php @@ -44,12 +44,13 @@ class BasicAuthentication { * Proxy Authentication * * @param HttpSocket $http + * @param array $proxyInfo * @return void * @see http://www.ietf.org/rfc/rfc2617.txt */ - public static function proxyAuthentication(HttpSocket $http) { - if (isset($http->request['proxy']['user'], $http->request['proxy']['pass'])) { - $http->request['header']['Proxy-Authorization'] = self::_generateHeader($http->request['proxy']['user'], $http->request['proxy']['pass']); + public static function proxyAuthentication(HttpSocket $http, &$proxyInfo) { + if (isset($proxyInfo['user'], $proxyInfo['pass'])) { + $http->request['header']['Proxy-Authorization'] = self::_generateHeader($proxyInfo['user'], $proxyInfo['pass']); } } diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index d5ed518ad..06df4ad1f 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -59,13 +59,6 @@ class HttpSocket extends CakeSocket { 'query' => null, 'fragment' => null ), - 'proxy' => array( - 'method' => 'Basic', - 'host' => null, - 'port' => 3128, - 'user' => null, - 'pass' => null - ), 'version' => '1.1', 'body' => '', 'line' => null, @@ -118,13 +111,6 @@ class HttpSocket extends CakeSocket { 'host' => 'localhost', 'port' => 80 ), - 'proxy' => array( - 'method' => 'Basic', - 'host' => null, - 'port' => 3128, - 'user' => null, - 'pass' => null - ), 'cookies' => array() ) ); @@ -145,6 +131,14 @@ class HttpSocket extends CakeSocket { */ protected $_auth = array(); +/** + * Proxy settings + * + * @var array + * @access protected + */ + protected $_proxy = array(); + /** * Build an HTTP Socket using the specified configuration. * @@ -182,7 +176,7 @@ class HttpSocket extends CakeSocket { /** * Set authentication settings * - * @param string $method Authentication method (ex. Basic, Digest). If empty, disable authentication + * @param string $method Authentication method (ie. Basic, Digest). If empty, disable authentication * @param mixed $user Username for authentication. Can be an array with settings to authentication class * @param string $pass Password for authentication * @return void @@ -199,6 +193,28 @@ class HttpSocket extends CakeSocket { $this->_auth = array($method => compact('user', 'pass')); } +/** + * Set proxy settings + * + * @param mixed $host Proxy host. Can be an array with settings to authentication class + * @param integer $port Port. Default 3128. + * @param string $method Proxy method (ie, Basic, Digest). If empty, disable proxy authentication + * @param string $user Username if your proxy need authentication + * @param string $pass Password to proxy authentication + * @return void + */ + public function setProxyConfig($host, $port = 3128, $method = null, $user = null, $pass = null) { + if (empty($host)) { + $this->_proxy = array(); + return; + } + if (is_array($host)) { + $this->_proxy = $host + array('host' => null); + return; + } + $this->_proxy = compact('host', 'port', 'method', 'user', 'pass'); + } + /** * Issue the specified request. HttpSocket::get() and HttpSocket::post() wrap this * method and provide a more granular interface. @@ -490,23 +506,23 @@ class HttpSocket extends CakeSocket { * @return void */ protected function _setProxyConfig() { - if (empty($this->request['proxy']['host'])) { + if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) { return; } - $this->config['host'] = $this->request['proxy']['host']; - $this->config['port'] = $this->request['proxy']['port']; + $this->config['host'] = $this->_proxy['host']; + $this->config['port'] = $this->_proxy['port']; - if (empty($this->request['proxy']['method']) || !isset($this->request['proxy']['user'], $this->request['proxy']['pass'])) { + if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) { return; } - $authClass = Inflector::camelize($this->request['proxy']['method']) . 'Authentication'; + $authClass = Inflector::camelize($this->_proxy['method']) . 'Authentication'; if (!App::import('Lib', 'http/' . $authClass)) { throw new Exception(__('Unknown authentication method for proxy.')); } if (!method_exists($authClass, 'proxyAuthentication')) { throw new Exception(sprintf(__('The %s do not support proxy authentication.'), $authClass)); } - call_user_func("$authClass::proxyAuthentication", $this); + call_user_func("$authClass::proxyAuthentication", $this, &$this->_proxy); } /** @@ -882,7 +898,7 @@ class HttpSocket extends CakeSocket { $request['uri'] = $this->_parseUri($request['uri']); $request = array_merge(array('method' => 'GET'), $request); - if (!empty($request['proxy']['host'])) { + if (!empty($this->_proxy['host'])) { $request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query'); } else { $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query'); diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 06b055928..834237934 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -42,10 +42,11 @@ class TestAuthentication { * proxyAuthentication method * * @param HttpSocket $http + * @param array $proxyInfo * @return void */ - public static function proxyAuthentication(HttpSocket $http) { - $http->request['header']['Proxy-Authorization'] = 'Test ' . $http->request['proxy']['user'] . '.' . $http->request['proxy']['pass']; + public static function proxyAuthentication(HttpSocket $http, &$proxyInfo) { + $http->request['header']['Proxy-Authorization'] = 'Test ' . $proxyInfo['user'] . '.' . $proxyInfo['pass']; } } @@ -287,13 +288,6 @@ class HttpSocketTest extends CakeTestCase { , 'host' => 'www.cakephp.org' , 'port' => 23 ), - 'proxy' => array( - 'method' => 'Basic', - 'host' => null, - 'port' => 3128, - 'user' => null, - 'pass' => null - ), 'cookies' => array(), ) ); @@ -318,13 +312,6 @@ class HttpSocketTest extends CakeTestCase { , 'host' => 'www.foo.com' , 'port' => 80 ), - 'proxy' => array( - 'method' => 'Basic', - 'host' => null, - 'port' => 3128, - 'user' => null, - 'pass' => null - ), 'cookies' => array() ) ); @@ -366,13 +353,6 @@ class HttpSocketTest extends CakeTestCase { , 'host' => 'www.cakephp.org' , 'port' => 80, ), - 'proxy' => array( - 'method' => 'Basic', - 'host' => null, - 'port' => 3128, - 'user' => null, - 'pass' => null - ), 'cookies' => array(), ), ) @@ -387,13 +367,6 @@ class HttpSocketTest extends CakeTestCase { , 'path' => '/' , 'query' => array('foo' => 'bar') , 'fragment' => null - ), - 'proxy' => array( - 'method' => 'Basic', - 'host' => null, - 'port' => 3128, - 'user' => null, - 'pass' => null ) , 'version' => '1.1' , 'body' => '' @@ -636,31 +609,24 @@ class HttpSocketTest extends CakeTestCase { $this->Socket->reset(); $this->Socket->expects($this->any())->method('connect')->will($this->returnValue(true)); $this->Socket->expects($this->any())->method('read')->will($this->returnValue(false)); - $request = array( - 'uri' => 'http://www.cakephp.org/', - 'proxy' => array( - 'host' => 'proxy.server', - 'port' => 123 - ) - ); + + $this->Socket->setProxyConfig('proxy.server', 123); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n\r\n"; - $this->Socket->request($request); + $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); $this->assertEqual($this->Socket->config['host'], 'proxy.server'); $this->assertEqual($this->Socket->config['port'], 123); - $request['proxy']['method'] = 'Test'; - $request['proxy']['user'] = 'mark'; - $request['proxy']['pass'] = 'secret'; $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; - $this->Socket->request($request); + $this->Socket->setProxyConfig('proxy.server', 123, 'Test', 'mark', 'secret'); + $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); $this->assertEqual($this->Socket->config['host'], 'proxy.server'); $this->assertEqual($this->Socket->config['port'], 123); $this->Socket->setAuthConfig('Test', 'login', 'passwd'); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nAuthorization: Test login.passwd\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; - $this->Socket->request($request); + $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); } From 874a1172a1b118d9a8d89569d7e6f9b2c1868698 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 3 Dec 2010 23:13:49 -0200 Subject: [PATCH 043/125] Cleaning auth and proxy configuration in full reset. --- cake/libs/http_socket.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 06df4ad1f..22fdf45d4 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -1132,6 +1132,8 @@ class HttpSocket extends CakeSocket { $this->response = $initalState['response']; return true; } + $this->_auth = array(); + $this->_proxy = array(); parent::reset($initalState); return true; } From 3f910dc6c1581594131cad74bf70414390400226 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 4 Dec 2010 00:58:49 -0200 Subject: [PATCH 044/125] Formatting --- cake/libs/http_socket.php | 69 +++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 22fdf45d4..1738c4076 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -37,7 +37,6 @@ class HttpSocket extends CakeSocket { * will be disabled and additional measures to deal with non-standard responses will be enabled. * * @var boolean - * @access public */ public $quirksMode = false; @@ -45,7 +44,6 @@ class HttpSocket extends CakeSocket { * The default values to use for a request * * @var array - * @access public */ public $request = array( 'method' => 'GET', @@ -71,11 +69,10 @@ class HttpSocket extends CakeSocket { ); /** -* The default structure for storing the response -* -* @var array -* @access public -*/ + * The default structure for storing the response + * + * @var array + */ public $response = array( 'raw' => array( 'status-line' => null, @@ -97,7 +94,6 @@ class HttpSocket extends CakeSocket { * Default configuration settings for the HttpSocket * * @var array - * @access public */ public $config = array( 'persistent' => false, @@ -119,7 +115,6 @@ class HttpSocket extends CakeSocket { * String that represents a line break. * * @var string - * @access public */ public $lineBreak = "\r\n"; @@ -127,7 +122,6 @@ class HttpSocket extends CakeSocket { * Authentication settings * * @var array - * @access protected */ protected $_auth = array(); @@ -135,7 +129,6 @@ class HttpSocket extends CakeSocket { * Proxy settings * * @var array - * @access protected */ protected $_proxy = array(); @@ -425,7 +418,7 @@ class HttpSocket extends CakeSocket { } /** - * Normalizes urls into a $uriTemplate. If no template is provided + * Normalizes urls into a $uriTemplate. If no template is provided * a default one will be used. Will generate the url using the * current config information. * @@ -457,10 +450,10 @@ class HttpSocket extends CakeSocket { } if (is_string($url)) { if ($url{0} == '/') { - $url = $this->config['request']['uri']['host'].':'.$this->config['request']['uri']['port'] . $url; + $url = $this->config['request']['uri']['host'] . ':' . $this->config['request']['uri']['port'] . $url; } if (!preg_match('/^.+:\/\/|\*|^\//', $url)) { - $url = $this->config['request']['uri']['scheme'].'://'.$url; + $url = $this->config['request']['uri']['scheme'] . '://' . $url; } } elseif (!is_array($url) && !empty($url)) { return false; @@ -504,6 +497,7 @@ class HttpSocket extends CakeSocket { * Set the proxy configuration and authentication * * @return void + * @throws Exception */ protected function _setProxyConfig() { if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) { @@ -570,7 +564,7 @@ class HttpSocket extends CakeSocket { $response['body'] = $decoded['body']; if (!empty($decoded['header'])) { - $response['header'] = $this->_parseHeader($this->_buildHeader($response['header']).$this->_buildHeader($decoded['header'])); + $response['header'] = $this->_parseHeader($this->_buildHeader($response['header']) . $this->_buildHeader($decoded['header'])); } if (!empty($response['header'])) { @@ -601,7 +595,7 @@ class HttpSocket extends CakeSocket { if (empty($encoding)) { return array('body' => $body, 'header' => false); } - $decodeMethod = '_decode'.Inflector::camelize(str_replace('-', '_', $encoding)).'Body'; + $decodeMethod = '_decode'.Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body'; if (!is_callable(array(&$this, $decodeMethod))) { if (!$this->quirksMode) { @@ -663,7 +657,7 @@ class HttpSocket extends CakeSocket { } $decodedBody .= $chunk; if ($chunkLength !== 0) { - $body = substr($body, $chunkLength+strlen("\r\n")); + $body = substr($body, $chunkLength + strlen("\r\n")); } } @@ -707,7 +701,7 @@ class HttpSocket extends CakeSocket { /** * Takes a $uri array and turns it into a fully qualified URL string * - * @param mixed $uri Either A $uri array, or a request string. Will use $this->config if left empty. + * @param mixed $uri Either A $uri array, or a request string. Will use $this->config if left empty. * @param string $uriTemplate The Uri template/format to use. * @return mixed A fully qualified URL formated according to $uriTemplate, or false on failure */ @@ -741,7 +735,7 @@ class HttpSocket extends CakeSocket { $uriTemplate = str_replace(':%port', null, $uriTemplate); } foreach ($uri as $property => $value) { - $uriTemplate = str_replace('%'.$property, $value, $uriTemplate); + $uriTemplate = str_replace('%' . $property, $value, $uriTemplate); } if ($uriTemplate === '/*') { @@ -816,7 +810,7 @@ class HttpSocket extends CakeSocket { * - ?key[subKey]=value * - ?key[]=value1&key[]=value2 * - * A leading '?' mark in $query is optional and does not effect the outcome of this function. + * A leading '?' mark in $query is optional and does not effect the outcome of this function. * For the complete capabilities of this implementation take a look at HttpSocketTest::testparseQuery() * * @param mixed $query A query string to parse into an array or an array to return directly "as is" @@ -907,7 +901,7 @@ class HttpSocket extends CakeSocket { if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) { throw new Exception(sprintf(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.'), join(',', $asteriskMethods))); } - return $request['method'].' '.$request['uri'].' '.$versionToken.$this->lineBreak; + return $request['method'] . ' ' . $request['uri'] . ' ' . $versionToken . $this->lineBreak; } /** @@ -960,7 +954,7 @@ class HttpSocket extends CakeSocket { $contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content); $field = $this->_escapeToken($field); - $returnHeader .= $field.': '.$contents.$this->lineBreak; + $returnHeader .= $field . ': ' . $contents . $this->lineBreak; } } return $returnHeader; @@ -1004,10 +998,9 @@ class HttpSocket extends CakeSocket { * * @param array $header Header array containing one ore more 'Set-Cookie' headers. * @return mixed Either false on no cookies, or an array of cookies recieved. - * @access public * @todo Make this 100% RFC 2965 confirm */ - function parseCookies($header) { + public function parseCookies($header) { if (!isset($header['Set-Cookie'])) { return false; } @@ -1016,7 +1009,7 @@ class HttpSocket extends CakeSocket { foreach ((array)$header['Set-Cookie'] as $cookie) { if (strpos($cookie, '";"') !== false) { $cookie = str_replace('";"', "{__cookie_replace__}", $cookie); - $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie)); + $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie)); } else { $parts = preg_split('/\;[ \t]*/', $cookie); } @@ -1046,28 +1039,26 @@ class HttpSocket extends CakeSocket { * * @param array $cookies Array of cookies to send with the request. * @return string Cookie header string to be sent with the request. - * @access public * @todo Refactor token escape mechanism to be configurable */ - function buildCookies($cookies) { + public function buildCookies($cookies) { $header = array(); foreach ($cookies as $name => $cookie) { - $header[] = $name.'='.$this->_escapeToken($cookie['value'], array(';')); + $header[] = $name . '=' . $this->_escapeToken($cookie['value'], array(';')); } - $header = $this->_buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic'); - return $header; + return $this->_buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic'); } /** * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs) * * @param string $token Token to unescape + * @param array $chars * @return string Unescaped token - * @access protected * @todo Test $chars parameter */ - function _unescapeToken($token, $chars = null) { - $regex = '/"(['.join('', $this->_tokenEscapeChars(true, $chars)).'])"/'; + protected function _unescapeToken($token, $chars = null) { + $regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/'; $token = preg_replace($regex, '\\1', $token); return $token; } @@ -1076,12 +1067,12 @@ class HttpSocket extends CakeSocket { * Escapes a given $token according to RFC 2616 (HTTP 1.1 specs) * * @param string $token Token to escape + * @param array $chars * @return string Escaped token - * @access protected * @todo Test $chars parameter */ - function _escapeToken($token, $chars = null) { - $regex = '/(['.join('', $this->_tokenEscapeChars(true, $chars)).'])/'; + protected function _escapeToken($token, $chars = null) { + $regex = '/([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])/'; $token = preg_replace($regex, '"\\1"', $token); return $token; } @@ -1090,11 +1081,11 @@ class HttpSocket extends CakeSocket { * Gets escape chars according to RFC 2616 (HTTP 1.1 specs). * * @param boolean $hex true to get them as HEX values, false otherwise + * @param array $chars * @return array Escape chars - * @access protected * @todo Test $chars parameter */ - function _tokenEscapeChars($hex = true, $chars = null) { + protected function _tokenEscapeChars($hex = true, $chars = null) { if (!empty($chars)) { $escape = $chars; } else { @@ -1110,7 +1101,7 @@ class HttpSocket extends CakeSocket { } $regexChars = ''; foreach ($escape as $key => $char) { - $escape[$key] = '\\x'.str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT); + $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT); } return $escape; } From 123b2256c5ff5936a03fe5e47463cd5e35f6194b Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 4 Dec 2010 01:23:07 -0200 Subject: [PATCH 045/125] Formatting --- cake/tests/cases/libs/http_socket.test.php | 502 +++++++++++---------- 1 file changed, 255 insertions(+), 247 deletions(-) diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 834237934..9bfa3bf96 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -51,6 +51,10 @@ class TestAuthentication { } +/** + * TestHttpSocket + * + */ class TestHttpSocket extends HttpSocket { /** @@ -59,7 +63,7 @@ class TestHttpSocket extends HttpSocket { * @param mixed $uri URI (see {@link _parseUri()}) * @return array Current configuration settings */ - function configUri($uri = null) { + public function configUri($uri = null) { return parent::_configUri($uri); } @@ -70,7 +74,7 @@ class TestHttpSocket extends HttpSocket { * @param mixed $base If true use default URI config, otherwise indexed array to set 'scheme', 'host', 'port', etc. * @return array Parsed URI */ - function parseUri($uri = null, $base = array()) { + public function parseUri($uri = null, $base = array()) { return parent::_parseUri($uri, $base); } @@ -81,7 +85,7 @@ class TestHttpSocket extends HttpSocket { * @param string $uriTemplate The Uri template/format to use * @return string A fully qualified URL formated according to $uriTemplate */ - function buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') { + public function buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') { return parent::_buildUri($uri, $uriTemplate); } @@ -91,7 +95,7 @@ class TestHttpSocket extends HttpSocket { * @param array $header Header to build * @return string Header built from array */ - function buildHeader($header, $mode = 'standard') { + public function buildHeader($header, $mode = 'standard') { return parent::_buildHeader($header, $mode); } @@ -101,7 +105,7 @@ class TestHttpSocket extends HttpSocket { * @param string $message Message to parse * @return array Parsed message (with indexed elements such as raw, status, header, body) */ - function parseResponse($message) { + public function parseResponse($message) { return parent::_parseResponse($message); } @@ -111,7 +115,7 @@ class TestHttpSocket extends HttpSocket { * @param array $header Header as an indexed array (field => value) * @return array Parsed header */ - function parseHeader($header) { + public function parseHeader($header) { return parent::_parseHeader($header); } @@ -121,7 +125,7 @@ class TestHttpSocket extends HttpSocket { * @param mixed $query A query string to parse into an array or an array to return directly "as is" * @return array The $query parsed into a possibly multi-level array. If an empty $query is given, an empty array is returned. */ - function parseQuery($query) { + public function parseQuery($query) { return parent::_parseQuery($query); } @@ -132,7 +136,7 @@ class TestHttpSocket extends HttpSocket { * @param mixed $encoding Can be false in case no encoding is being used, or a string representing the encoding * @return mixed Array or false */ - function decodeBody($body, $encoding = 'chunked') { + public function decodeBody($body, $encoding = 'chunked') { return parent::_decodeBody($body, $encoding); } @@ -142,7 +146,7 @@ class TestHttpSocket extends HttpSocket { * @param string $body A string continaing the chunked body to decode * @return mixed Array or false */ - function decodeChunkedBody($body) { + public function decodeChunkedBody($body) { return parent::_decodeChunkedBody($body); } @@ -153,7 +157,7 @@ class TestHttpSocket extends HttpSocket { * @param string $versionToken The version token to use, defaults to HTTP/1.1 * @return string Request line */ - function buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') { + public function buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') { return parent::_buildRequestLine($request, $versionToken); } @@ -163,7 +167,7 @@ class TestHttpSocket extends HttpSocket { * @param boolean $hex true to get them as HEX values, false otherwise * @return array Escape chars */ - function tokenEscapeChars($hex = true, $chars = null) { + public function tokenEscapeChars($hex = true, $chars = null) { return parent::_tokenEscapeChars($hex, $chars); } @@ -173,7 +177,7 @@ class TestHttpSocket extends HttpSocket { * @param string $token Token to escape * @return string Escaped token */ - function EscapeToken($token, $chars = null) { + public function EscapeToken($token, $chars = null) { return parent::_escapeToken($token, $chars); } @@ -183,7 +187,7 @@ class TestHttpSocket extends HttpSocket { * @param string $token Token to unescape * @return string Unescaped token */ - function unescapeToken($token, $chars = null) { + public function unescapeToken($token, $chars = null) { return parent::_unescapeToken($token, $chars); } } @@ -200,7 +204,6 @@ class HttpSocketTest extends CakeTestCase { * Socket property * * @var mixed null - * @access public */ public $Socket = null; @@ -208,17 +211,15 @@ class HttpSocketTest extends CakeTestCase { * RequestSocket property * * @var mixed null - * @access public */ public $RequestSocket = null; /** * This function sets up a TestHttpSocket instance we are going to use for testing * - * @access public * @return void */ - function setUp() { + public function setUp() { if (!class_exists('MockHttpSocket')) { $this->getMock('TestHttpSocket', array('read', 'write', 'connect'), array(), 'MockHttpSocket'); $this->getMock('TestHttpSocket', array('read', 'write', 'connect', 'request'), array(), 'MockHttpSocketRequests'); @@ -231,20 +232,18 @@ class HttpSocketTest extends CakeTestCase { /** * We use this function to clean up after the test case was executed * - * @access public * @return void */ - function tearDown() { + public function tearDown() { unset($this->Socket, $this->RequestSocket); } /** * Test that HttpSocket::__construct does what one would expect it to do * - * @access public * @return void */ - function testConstruct() { + public function testConstruct() { $this->Socket->reset(); $baseConfig = $this->Socket->config; $this->Socket->expects($this->never())->method('connect'); @@ -270,25 +269,24 @@ class HttpSocketTest extends CakeTestCase { /** * Test that HttpSocket::configUri works properly with different types of arguments * - * @access public * @return void */ - function testConfigUri() { + public function testConfigUri() { $this->Socket->reset(); $r = $this->Socket->configUri('https://bob:secret@www.cakephp.org:23/?query=foo'); $expected = array( 'persistent' => false, - 'host' => 'www.cakephp.org', - 'protocol' => 'tcp', - 'port' => 23, - 'timeout' => 30, + 'host' => 'www.cakephp.org', + 'protocol' => 'tcp', + 'port' => 23, + 'timeout' => 30, 'request' => array( 'uri' => array( - 'scheme' => 'https' - , 'host' => 'www.cakephp.org' - , 'port' => 23 + 'scheme' => 'https', + 'host' => 'www.cakephp.org', + 'port' => 23 ), - 'cookies' => array(), + 'cookies' => array() ) ); $this->assertEquals($this->Socket->config, $expected); @@ -302,15 +300,15 @@ class HttpSocketTest extends CakeTestCase { $r = $this->Socket->configUri('http://www.foo.com'); $expected = array( 'persistent' => false, - 'host' => 'www.foo.com', - 'protocol' => 'tcp', - 'port' => 80, - 'timeout' => 30, + 'host' => 'www.foo.com', + 'protocol' => 'tcp', + 'port' => 80, + 'timeout' => 30, 'request' => array( 'uri' => array( - 'scheme' => 'http' - , 'host' => 'www.foo.com' - , 'port' => 80 + 'scheme' => 'http', + 'host' => 'www.foo.com', + 'port' => 80 ), 'cookies' => array() ) @@ -328,191 +326,216 @@ class HttpSocketTest extends CakeTestCase { /** * Tests that HttpSocket::request (the heart of the HttpSocket) is working properly. * - * @access public * @return void */ - function testRequest() { + public function testRequest() { $this->Socket->reset(); $response = $this->Socket->request(true); $this->assertFalse($response); $tests = array( - 0 => array( - 'request' => 'http://www.cakephp.org/?foo=bar' - , 'expectation' => array( + array( + 'request' => 'http://www.cakephp.org/?foo=bar', + 'expectation' => array( 'config' => array( - 'persistent' => false - , 'host' => 'www.cakephp.org' - , 'protocol' => 'tcp' - , 'port' => 80 - , 'timeout' => 30 - , 'request' => array( + 'persistent' => false, + 'host' => 'www.cakephp.org', + 'protocol' => 'tcp', + 'port' => 80, + 'timeout' => 30, + 'request' => array( 'uri' => array ( - 'scheme' => 'http' - , 'host' => 'www.cakephp.org' - , 'port' => 80, + 'scheme' => 'http', + 'host' => 'www.cakephp.org', + 'port' => 80 ), - 'cookies' => array(), - ), - ) - , 'request' => array( - 'method' => 'GET' - , 'uri' => array( - 'scheme' => 'http' - , 'host' => 'www.cakephp.org' - , 'port' => 80 - , 'user' => null - , 'pass' => null - , 'path' => '/' - , 'query' => array('foo' => 'bar') - , 'fragment' => null + 'cookies' => array() ) - , 'version' => '1.1' - , 'body' => '' - , 'line' => "GET /?foo=bar HTTP/1.1\r\n" - , 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n" - , 'raw' => "" - , 'cookies' => array(), + ), + 'request' => array( + 'method' => 'GET', + 'uri' => array( + 'scheme' => 'http', + 'host' => 'www.cakephp.org', + 'port' => 80, + 'user' => null, + 'pass' => null, + 'path' => '/', + 'query' => array('foo' => 'bar'), + 'fragment' => null + ), + 'version' => '1.1', + 'body' => '', + 'line' => "GET /?foo=bar HTTP/1.1\r\n", + 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n", + 'raw' => "", + 'cookies' => array() ) ) - ) - , 1 => array( + ), + array( 'request' => array( 'uri' => array( - 'host' => 'www.cakephp.org' - , 'query' => '?foo=bar' + 'host' => 'www.cakephp.org', + 'query' => '?foo=bar' ) ) - ) - , 2 => array( + ), + array( 'request' => 'www.cakephp.org/?foo=bar' - ) - , 3 => array( - 'request' => array('host' => '192.168.0.1', 'uri' => 'http://www.cakephp.org/?foo=bar') - , 'expectation' => array( + ), + array( + 'request' => array( + 'host' => '192.168.0.1', + 'uri' => 'http://www.cakephp.org/?foo=bar' + ), + 'expectation' => array( 'request' => array( 'uri' => array('host' => 'www.cakephp.org') - ) - , 'config' => array( + ), + 'config' => array( 'request' => array( 'uri' => array('host' => 'www.cakephp.org') - ) - , 'host' => '192.168.0.1' + ), + 'host' => '192.168.0.1' ) ) - ) - , 'reset4' => array( + ), + 'reset4' => array( 'request.uri.query' => array() - ) - , 4 => array( - 'request' => array('header' => array('Foo@woo' => 'bar-value')) - , 'expectation' => array( + ), + array( + 'request' => array( + 'header' => array('Foo@woo' => 'bar-value') + ), + 'expectation' => array( 'request' => array( - 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nFoo\"@\"woo: bar-value\r\n" - , 'line' => "GET / HTTP/1.1\r\n" + 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nFoo\"@\"woo: bar-value\r\n", + 'line' => "GET / HTTP/1.1\r\n" ) ) - ) - , 5 => array( - 'request' => array('header' => array('Foo@woo' => 'bar-value', 'host' => 'foo.com'), 'uri' => 'http://www.cakephp.org/') - , 'expectation' => array( + ), + array( + 'request' => array('header' => array('Foo@woo' => 'bar-value', 'host' => 'foo.com'), 'uri' => 'http://www.cakephp.org/'), + 'expectation' => array( 'request' => array( 'header' => "Host: foo.com\r\nConnection: close\r\nUser-Agent: CakePHP\r\nFoo\"@\"woo: bar-value\r\n" - ) - , 'config' => array( + ), + 'config' => array( 'host' => 'www.cakephp.org' ) ) - ) - , 6 => array( - 'request' => array('header' => "Foo: bar\r\n") - , 'expectation' => array( + ), + array( + 'request' => array('header' => "Foo: bar\r\n"), + 'expectation' => array( 'request' => array( 'header' => "Foo: bar\r\n" ) ) - ) - , 7 => array( - 'request' => array('header' => "Foo: bar\r\n", 'uri' => 'http://www.cakephp.org/search?q=http_socket#ignore-me') - , 'expectation' => array( + ), + array( + 'request' => array('header' => "Foo: bar\r\n", 'uri' => 'http://www.cakephp.org/search?q=http_socket#ignore-me'), + 'expectation' => array( 'request' => array( 'uri' => array( - 'path' => '/search' - , 'query' => array('q' => 'http_socket') - , 'fragment' => 'ignore-me' - ) - , 'line' => "GET /search?q=http_socket HTTP/1.1\r\n" + 'path' => '/search', + 'query' => array('q' => 'http_socket'), + 'fragment' => 'ignore-me' + ), + 'line' => "GET /search?q=http_socket HTTP/1.1\r\n" ) ) - ) - , 'reset8' => array( + ), + 'reset8' => array( 'request.uri.query' => array() - ) - , 8 => array( - 'request' => array('method' => 'POST', 'uri' => 'http://www.cakephp.org/posts/add', 'body' => array('name' => 'HttpSocket-is-released', 'date' => 'today')) - , 'expectation' => array( + ), + array( + 'request' => array( + 'method' => 'POST', + 'uri' => 'http://www.cakephp.org/posts/add', + 'body' => array( + 'name' => 'HttpSocket-is-released', + 'date' => 'today' + ) + ), + 'expectation' => array( 'request' => array( - 'method' => 'POST' - , 'uri' => array( - 'path' => '/posts/add' - , 'fragment' => null - ) - , 'body' => "name=HttpSocket-is-released&date=today" - , 'line' => "POST /posts/add HTTP/1.1\r\n" - , 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 38\r\n" - , 'raw' => "name=HttpSocket-is-released&date=today" + 'method' => 'POST', + 'uri' => array( + 'path' => '/posts/add', + 'fragment' => null + ), + 'body' => "name=HttpSocket-is-released&date=today", + 'line' => "POST /posts/add HTTP/1.1\r\n", + 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 38\r\n", + 'raw' => "name=HttpSocket-is-released&date=today" ) ) - ) - , 9 => array( - 'request' => array('method' => 'POST', 'uri' => 'http://www.cakephp.org:8080/posts/add', 'body' => array('name' => 'HttpSocket-is-released', 'date' => 'today')) - , 'expectation' => array( + ), + array( + 'request' => array( + 'method' => 'POST', + 'uri' => 'http://www.cakephp.org:8080/posts/add', + 'body' => array( + 'name' => 'HttpSocket-is-released', + 'date' => 'today' + ) + ), + 'expectation' => array( 'config' => array( - 'port' => 8080 - , 'request' => array( + 'port' => 8080, + 'request' => array( 'uri' => array( 'port' => 8080 ) ) - ) - , 'request' => array( + ), + 'request' => array( 'uri' => array( 'port' => 8080 - ) - , 'header' => "Host: www.cakephp.org:8080\r\nConnection: close\r\nUser-Agent: CakePHP\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 38\r\n" + ), + 'header' => "Host: www.cakephp.org:8080\r\nConnection: close\r\nUser-Agent: CakePHP\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 38\r\n" ) ) - ) - , 10 => array( - 'request' => array('method' => 'POST', 'uri' => 'https://www.cakephp.org/posts/add', 'body' => array('name' => 'HttpSocket-is-released', 'date' => 'today')) - , 'expectation' => array( + ), + array( + 'request' => array( + 'method' => 'POST', + 'uri' => 'https://www.cakephp.org/posts/add', + 'body' => array( + 'name' => 'HttpSocket-is-released', + 'date' => 'today' + ) + ), + 'expectation' => array( 'config' => array( - 'port' => 443 - , 'request' => array( + 'port' => 443, + 'request' => array( 'uri' => array( - 'scheme' => 'https' - , 'port' => 443 + 'scheme' => 'https', + 'port' => 443 ) ) - ) - , 'request' => array( + ), + 'request' => array( 'uri' => array( - 'scheme' => 'https' - , 'port' => 443 - ) - , 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 38\r\n" + 'scheme' => 'https', + 'port' => 443 + ), + 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 38\r\n" ) ) - ) - , 11 => array( + ), + array( 'request' => array( - 'method' => 'POST', - 'uri' => 'https://www.cakephp.org/posts/add', - 'body' => array('name' => 'HttpSocket-is-released', 'date' => 'today'), - 'cookies' => array('foo' => array('value' => 'bar')) - ) - , 'expectation' => array( + 'method' => 'POST', + 'uri' => 'https://www.cakephp.org/posts/add', + 'body' => array('name' => 'HttpSocket-is-released', 'date' => 'today'), + 'cookies' => array('foo' => array('value' => 'bar')) + ), + 'expectation' => array( 'request' => array( 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 38\r\nCookie: foo=bar\r\n", 'cookies' => array( @@ -538,10 +561,10 @@ class HttpSocketTest extends CakeTestCase { $this->Socket->request($test['request']); $raw = $expectation['request']['raw']; - $expectation['request']['raw'] = $expectation['request']['line'].$expectation['request']['header']."\r\n".$raw; + $expectation['request']['raw'] = $expectation['request']['line'] . $expectation['request']['header'] . "\r\n" . $raw; $r = array('config' => $this->Socket->config, 'request' => $this->Socket->request); - $v = $this->assertEquals($r, $expectation, 'Failed test #'.$i.' '); + $v = $this->assertEquals($r, $expectation, 'Failed test #' . $i . ' '); $expectation['request']['raw'] = $raw; } @@ -560,10 +583,9 @@ class HttpSocketTest extends CakeTestCase { /** * testRequest2 method * - * @access public * @return void */ - function testRequest2() { + public function testRequest2() { $this->Socket->reset(); $request = array('uri' => 'htpp://www.cakephp.org/'); $number = mt_rand(0, 9999999); @@ -580,10 +602,9 @@ class HttpSocketTest extends CakeTestCase { /** * testRequest3 method * - * @access public * @return void */ - function testRequest3() { + public function testRequest3() { $request = array('uri' => 'htpp://www.cakephp.org/'); $serverResponse = "HTTP/1.x 200 OK\r\nSet-Cookie: foo=bar\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a cookie test!

"; $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); @@ -605,7 +626,7 @@ class HttpSocketTest extends CakeTestCase { * * @return void */ - function testProxy() { + public function testProxy() { $this->Socket->reset(); $this->Socket->expects($this->any())->method('connect')->will($this->returnValue(true)); $this->Socket->expects($this->any())->method('read')->will($this->returnValue(false)); @@ -633,10 +654,9 @@ class HttpSocketTest extends CakeTestCase { /** * testUrl method * - * @access public * @return void */ - function testUrl() { + public function testUrl() { $this->Socket->reset(true); $this->assertEquals($this->Socket->url(true), false); @@ -688,10 +708,9 @@ class HttpSocketTest extends CakeTestCase { /** * testGet method * - * @access public * @return void */ - function testGet() { + public function testGet() { $this->RequestSocket->reset(); $this->RequestSocket->expects($this->at(0)) @@ -701,7 +720,7 @@ class HttpSocketTest extends CakeTestCase { $this->RequestSocket->expects($this->at(1)) ->method('request') ->with(array('method' => 'GET', 'uri' => 'http://www.google.com/?foo=bar')); - + $this->RequestSocket->expects($this->at(2)) ->method('request') ->with(array('method' => 'GET', 'uri' => 'http://www.google.com/?foo=bar')); @@ -745,7 +764,7 @@ class HttpSocketTest extends CakeTestCase { * * @return void */ - function testConsecutiveGetResetsAuthCredentials() { + public function testConsecutiveGetResetsAuthCredentials() { $socket = new MockHttpSocket(); $socket->get('http://mark:secret@example.com/test'); $this->assertEqual($socket->request['uri']['user'], 'mark'); @@ -762,10 +781,9 @@ class HttpSocketTest extends CakeTestCase { /** * testPostPutDelete method * - * @access public * @return void */ - function testPost() { + public function testPost() { $this->RequestSocket->reset(); $this->RequestSocket->expects($this->at(0)) ->method('request') @@ -784,7 +802,12 @@ class HttpSocketTest extends CakeTestCase { $this->RequestSocket->post('http://www.google.com/', null, array('line' => 'Hey Server')); } - function testPut() { +/** + * testPut + * + * @return void + */ + public function testPut() { $this->RequestSocket->reset(); $this->RequestSocket->expects($this->at(0)) ->method('request') @@ -803,7 +826,12 @@ class HttpSocketTest extends CakeTestCase { $this->RequestSocket->put('http://www.google.com/', null, array('line' => 'Hey Server')); } - function testDelete() { +/** + * testDelete + * + * @return void + */ + public function testDelete() { $this->RequestSocket->reset(); $this->RequestSocket->expects($this->at(0)) ->method('request') @@ -825,10 +853,9 @@ class HttpSocketTest extends CakeTestCase { /** * testParseResponse method * - * @access public * @return void */ - function testParseResponse() { + public function testParseResponse() { $this->Socket->reset(); $r = $this->Socket->parseResponse(array('foo' => 'bar')); @@ -846,8 +873,8 @@ class HttpSocketTest extends CakeTestCase { 'status-line' => "HTTP/1.x 200 OK\r\n", 'header' => "Date: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\n", 'body' => "

Hello World

\r\n

It's good to be html

" - ) - , 'expectations' => array( + ), + 'expectations' => array( 'status.http-version' => 'HTTP/1.x', 'status.code' => 200, 'status.reason-phrase' => 'OK', @@ -858,9 +885,9 @@ class HttpSocketTest extends CakeTestCase { 'no-header' => array( 'response' => array( 'status-line' => "HTTP/1.x 404 OK\r\n", - 'header' => null, - ) - , 'expectations' => array( + 'header' => null + ), + 'expectations' => array( 'status.code' => 404, 'header' => array() ) @@ -897,19 +924,18 @@ class HttpSocketTest extends CakeTestCase { $expectations = array(); foreach ($tests as $name => $test) { - $testResponse = array_merge($testResponse, $test['response']); - $testResponse['response'] = $testResponse['status-line'].$testResponse['header']."\r\n".$testResponse['body']; + $testResponse['response'] = $testResponse['status-line'] . $testResponse['header'] . "\r\n" . $testResponse['body']; $r = $this->Socket->parseResponse($testResponse['response']); $expectations = array_merge($expectations, $test['expectations']); foreach ($expectations as $property => $expectedVal) { $val = Set::extract($r, $property); - $this->assertEquals($val, $expectedVal, 'Test "'.$name.'": response.'.$property.' - %s'); + $this->assertEquals($val, $expectedVal, 'Test "' . $name . '": response.' . $property . ' - %s'); } foreach (array('status-line', 'header', 'body', 'response') as $field) { - $this->assertEquals($r['raw'][$field], $testResponse[$field], 'Test response.raw.'.$field.': %s'); + $this->assertEquals($r['raw'][$field], $testResponse[$field], 'Test response.raw.' . $field . ': %s'); } } } @@ -917,10 +943,9 @@ class HttpSocketTest extends CakeTestCase { /** * testDecodeBody method * - * @access public * @return void */ - function testDecodeBody() { + public function testDecodeBody() { $this->Socket->reset(); $r = $this->Socket->decodeBody(true); @@ -939,7 +964,12 @@ class HttpSocketTest extends CakeTestCase { $this->assertEquals($r, $sample['decoded']); } - function testDecodeFooCoded() { +/** + * testDecodeFooCoded + * + * @return void + */ + public function testDecodeFooCoded() { $this->Socket->reset(); $r = $this->Socket->decodeBody(true); @@ -967,10 +997,9 @@ class HttpSocketTest extends CakeTestCase { /** * testDecodeChunkedBody method * - * @access public * @return void */ - function testDecodeChunkedBody() { + public function testDecodeChunkedBody() { $this->Socket->reset(); $r = $this->Socket->decodeChunkedBody(true); @@ -1023,10 +1052,9 @@ class HttpSocketTest extends CakeTestCase { /** * testBuildRequestLine method * - * @access public * @return void */ - function testBuildRequestLine() { + public function testBuildRequestLine() { $this->Socket->reset(); $this->Socket->quirksMode = true; @@ -1067,7 +1095,7 @@ class HttpSocketTest extends CakeTestCase { $request['method'] = 'GET'; $this->Socket->quirksMode = true; $r = $this->Socket->buildRequestLine($request); - $this->assertEquals($r, "GET * HTTP/1.1\r\n"); + $this->assertEquals($r, "GET * HTTP/1.1\r\n"); $r = $this->Socket->buildRequestLine("GET * HTTP/1.1\r\n"); $this->assertEquals($r, "GET * HTTP/1.1\r\n"); @@ -1076,10 +1104,9 @@ class HttpSocketTest extends CakeTestCase { /** * testBadBuildRequestLine method * - * @access public * @return void */ - function testBadBuildRequestLine() { + public function testBadBuildRequestLine() { $this->expectError(); $r = $this->Socket->buildRequestLine('Foo'); } @@ -1087,10 +1114,9 @@ class HttpSocketTest extends CakeTestCase { /** * testBadBuildRequestLine2 method * - * @access public * @return void */ - function testBadBuildRequestLine2() { + public function testBadBuildRequestLine2() { $this->expectError(); $r = $this->Socket->buildRequestLine("GET * HTTP/1.1\r\n"); } @@ -1098,10 +1124,9 @@ class HttpSocketTest extends CakeTestCase { /** * Asserts that HttpSocket::parseUri is working properly * - * @access public * @return void */ - function testParseUri() { + public function testParseUri() { $this->Socket->reset(); $uri = $this->Socket->parseUri(array('invalid' => 'uri-string')); @@ -1132,7 +1157,7 @@ class HttpSocketTest extends CakeTestCase { $this->assertEquals($uri, array( 'scheme' => 'http', 'host' => 'www.cakephp.org', - 'path' => '/', + 'path' => '/' )); $uri = $this->Socket->parseUri('http://www.cakephp.org', true); @@ -1197,7 +1222,7 @@ class HttpSocketTest extends CakeTestCase { $this->assertEquals($uri, array( 'scheme' => 'http', 'host' => 'www.google.com', - 'port' => 8080, + 'port' => 8080 )); $uri = $this->Socket->parseUri('http://www.cakephp.org/?param1=value1¶m2=value2%3Dvalue3'); @@ -1226,10 +1251,9 @@ class HttpSocketTest extends CakeTestCase { /** * Tests that HttpSocket::buildUri can turn all kinds of uri arrays (and strings) into fully or partially qualified URI's * - * @access public * @return void */ - function testBuildUri() { + public function testBuildUri() { $this->Socket->reset(); $r = $this->Socket->buildUri(true); @@ -1293,10 +1317,9 @@ class HttpSocketTest extends CakeTestCase { /** * Asserts that HttpSocket::parseQuery is working properly * - * @access public * @return void */ - function testParseQuery() { + public function testParseQuery() { $this->Socket->reset(); $query = $this->Socket->parseQuery(array('framework' => 'cakephp')); @@ -1345,16 +1368,10 @@ class HttpSocketTest extends CakeTestCase { $query = $this->Socket->parseQuery('a[][]=foo&a[bar]=php&a[][]=bar&a[][]=cake'); $expectedQuery = array( 'a' => array( - 0 => array( - 0 => 'foo' - ), + array('foo'), 'bar' => 'php', - 1 => array( - 0 => 'bar' - ), - array( - 0 => 'cake' - ) + array('bar'), + array('cake') ) ); $this->assertEquals($query, $expectedQuery); @@ -1400,10 +1417,9 @@ class HttpSocketTest extends CakeTestCase { * Tests that HttpSocket::buildHeader can turn a given $header array into a proper header string according to * HTTP 1.1 specs. * - * @access public * @return void */ - function testBuildHeader() { + public function testBuildHeader() { $this->Socket->reset(); $r = $this->Socket->buildHeader(true); @@ -1438,10 +1454,9 @@ class HttpSocketTest extends CakeTestCase { /** * Test that HttpSocket::parseHeader can take apart a given (and valid) $header string and turn it into an array. * - * @access public * @return void */ - function testParseHeader() { + public function testParseHeader() { $this->Socket->reset(); $r = $this->Socket->parseHeader(array('foo' => 'Bar', 'fOO-bAr' => 'quux')); @@ -1460,32 +1475,32 @@ class HttpSocketTest extends CakeTestCase { $header = "Date:Sat, 07 Apr 2007 10:10:25 GMT\r\nX-Powered-By: PHP/5.1.2\r\n"; $r = $this->Socket->parseHeader($header); $expected = array( - 'Date' => 'Sat, 07 Apr 2007 10:10:25 GMT' - , 'X-Powered-By' => 'PHP/5.1.2' + 'Date' => 'Sat, 07 Apr 2007 10:10:25 GMT', + 'X-Powered-By' => 'PHP/5.1.2' ); $this->assertEquals($r, $expected); $header = "people: Jim,John\r\nfoo-LAND: Bar\r\ncAKe-PHP: rocks\r\n"; $r = $this->Socket->parseHeader($header); $expected = array( - 'people' => 'Jim,John' - , 'foo-LAND' => 'Bar' - , 'cAKe-PHP' => 'rocks' + 'people' => 'Jim,John', + 'foo-LAND' => 'Bar', + 'cAKe-PHP' => 'rocks' ); $this->assertEquals($r, $expected); $header = "People: Jim,John,Tim\r\nPeople: Lisa,Tina,Chelsea\r\n"; $r = $this->Socket->parseHeader($header); $expected = array( - 'People' => array('Jim,John,Tim', 'Lisa,Tina,Chelsea') + 'People' => array('Jim,John,Tim', 'Lisa,Tina,Chelsea') ); $this->assertEquals($r, $expected); $header = "Multi-Line: I am a \r\nmulti line\t\r\nfield value.\r\nSingle-Line: I am not\r\n"; $r = $this->Socket->parseHeader($header); $expected = array( - 'Multi-Line' => "I am a\r\nmulti line\r\nfield value." - , 'Single-Line' => 'I am not' + 'Multi-Line' => "I am a\r\nmulti line\r\nfield value.", + 'Single-Line' => 'I am not' ); $this->assertEquals($r, $expected); @@ -1500,10 +1515,9 @@ class HttpSocketTest extends CakeTestCase { /** * testParseCookies method * - * @access public * @return void */ - function testParseCookies() { + public function testParseCookies() { $header = array( 'Set-Cookie' => array( 'foo=bar', @@ -1543,10 +1557,9 @@ class HttpSocketTest extends CakeTestCase { * testBuildCookies method * * @return void - * @access public * @todo Test more scenarios */ - function testBuildCookies() { + public function testBuildCookies() { $cookies = array( 'foo' => array( 'value' => 'bar' @@ -1564,10 +1577,9 @@ class HttpSocketTest extends CakeTestCase { /** * Tests that HttpSocket::_tokenEscapeChars() returns the right characters. * - * @access public * @return void */ - function testTokenEscapeChars() { + public function testTokenEscapeChars() { $this->Socket->reset(); $expected = array( @@ -1590,19 +1602,18 @@ class HttpSocketTest extends CakeTestCase { /** * Test that HttpSocket::escapeToken is escaping all characters as descriped in RFC 2616 (HTTP 1.1 specs) * - * @access public * @return void */ - function testEscapeToken() { + public function testEscapeToken() { $this->Socket->reset(); $this->assertEquals($this->Socket->escapeToken('Foo'), 'Foo'); $escape = $this->Socket->tokenEscapeChars(false); foreach ($escape as $char) { - $token = 'My-special-'.$char.'-Token'; + $token = 'My-special-' . $char . '-Token'; $escapedToken = $this->Socket->escapeToken($token); - $expectedToken = 'My-special-"'.$char.'"-Token'; + $expectedToken = 'My-special-"' . $char . '"-Token'; $this->assertEquals($escapedToken, $expectedToken, 'Test token escaping for ASCII '.ord($char)); } @@ -1616,19 +1627,18 @@ class HttpSocketTest extends CakeTestCase { /** * Test that escaped token strings are properly unescaped by HttpSocket::unescapeToken * - * @access public * @return void */ - function testUnescapeToken() { + public function testUnescapeToken() { $this->Socket->reset(); $this->assertEquals($this->Socket->unescapeToken('Foo'), 'Foo'); $escape = $this->Socket->tokenEscapeChars(false); foreach ($escape as $char) { - $token = 'My-special-"'.$char.'"-Token'; + $token = 'My-special-"' . $char . '"-Token'; $unescapedToken = $this->Socket->unescapeToken($token); - $expectedToken = 'My-special-'.$char.'-Token'; + $expectedToken = 'My-special-' . $char . '-Token'; $this->assertEquals($unescapedToken, $expectedToken, 'Test token unescaping for ASCII '.ord($char)); } @@ -1643,10 +1653,9 @@ class HttpSocketTest extends CakeTestCase { * This tests asserts HttpSocket::reset() resets a HttpSocket instance to it's initial state (before Object::__construct * got executed) * - * @access public * @return void */ - function testReset() { + public function testReset() { $this->Socket->reset(); $initialState = get_class_vars('HttpSocket'); @@ -1667,10 +1676,9 @@ class HttpSocketTest extends CakeTestCase { * This tests asserts HttpSocket::reset(false) resets certain HttpSocket properties to their initial state (before * Object::__construct got executed). * - * @access public * @return void */ - function testPartialReset() { + public function testPartialReset() { $this->Socket->reset(); $partialResetProperties = array('request', 'response'); From c4743a24388ccca519e223fea5fc810dc1f03ca1 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 4 Dec 2010 01:41:45 -0200 Subject: [PATCH 046/125] Changing the test with get to use version instead auth. --- cake/tests/cases/libs/http_socket.test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 9bfa3bf96..858a5df10 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -731,13 +731,13 @@ class HttpSocketTest extends CakeTestCase { $this->RequestSocket->expects($this->at(4)) ->method('request') - ->with(array('method' => 'GET', 'uri' => 'http://www.google.com/', 'auth' => array('user' => 'foo', 'pass' => 'bar'))); + ->with(array('method' => 'GET', 'uri' => 'http://www.google.com/', 'version' => '1.0')); $this->RequestSocket->get('http://www.google.com/'); $this->RequestSocket->get('http://www.google.com/', array('foo' => 'bar')); $this->RequestSocket->get('http://www.google.com/', 'foo=bar'); $this->RequestSocket->get('http://www.google.com/?foo=bar', array('foobar' => '42', 'foo' => '23')); - $this->RequestSocket->get('http://www.google.com/', null, array('auth' => array('user' => 'foo', 'pass' => 'bar'))); + $this->RequestSocket->get('http://www.google.com/', null, array('version' => '1.0')); } /** From 1dbed85979a46a5508b3386d595b8ffd827e0a9a Mon Sep 17 00:00:00 2001 From: Graham Weldon Date: Sat, 4 Dec 2010 22:14:33 +1100 Subject: [PATCH 047/125] Append Controller to error class name for isAuthorized() not implemented. --- cake/libs/controller/controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/libs/controller/controller.php b/cake/libs/controller/controller.php index 799d93f62..0bfe924f0 100644 --- a/cake/libs/controller/controller.php +++ b/cake/libs/controller/controller.php @@ -800,7 +800,7 @@ class Controller extends Object { */ function isAuthorized() { trigger_error(sprintf( - __('%s::isAuthorized() is not defined.', true), $this->name + __('%sController::isAuthorized() is not defined.', true), $this->name ), E_USER_WARNING); return false; } From 7024d14c748a312af19ca2f8546db3248b844ec2 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 5 Dec 2010 18:41:26 -0500 Subject: [PATCH 048/125] Removing private annotations for File::__construct() and File::__destruct() as its just not true. This also prevents them from being included in the API docs. --- cake/libs/file.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/cake/libs/file.php b/cake/libs/file.php index cc69c2122..86755a513 100644 --- a/cake/libs/file.php +++ b/cake/libs/file.php @@ -93,7 +93,6 @@ class File extends Object { * @param string $path Path to file * @param boolean $create Create file if it does not exist (if true) * @param integer $mode Mode to apply to the folder holding the file - * @access private */ function __construct($path, $create = false, $mode = 0755) { parent::__construct(); @@ -108,7 +107,6 @@ class File extends Object { /** * Closes the current file if it is opened * - * @access private */ function __destruct() { $this->close(); From 97fe32f87c16a6a3e909389e58bac44de5a4960d Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sun, 5 Dec 2010 23:36:28 -0200 Subject: [PATCH 049/125] Request return a pointer to body. It will reduce the memory usage in big responses. --- cake/libs/http_socket.php | 15 ++++++++------- cake/tests/cases/libs/http_socket.test.php | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 1738c4076..c467393c9 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -213,15 +213,16 @@ class HttpSocket extends CakeSocket { * method and provide a more granular interface. * * @param mixed $request Either an URI string, or an array defining host/uri - * @return mixed false on error, request body on success + * @return mixed null on error, reference to request body on success */ - public function request($request = array()) { + public function &request($request = array()) { $this->reset(false); if (is_string($request)) { $request = array('uri' => $request); } elseif (!is_array($request)) { - return false; + $return = false; + return $return; } if (!isset($request['uri'])) { @@ -354,7 +355,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request, either false on failure or the response to the request. */ - public function get($uri = null, $query = array(), $request = array()) { + public function &get($uri = null, $query = array(), $request = array()) { if (!empty($query)) { $uri = $this->_parseUri($uri); if (isset($uri['query'])) { @@ -386,7 +387,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request, either false on failure or the response to the request. */ - public function post($uri = null, $data = array(), $request = array()) { + public function &post($uri = null, $data = array(), $request = array()) { $request = Set::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request); return $this->request($request); } @@ -399,7 +400,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request */ - public function put($uri = null, $data = array(), $request = array()) { + public function &put($uri = null, $data = array(), $request = array()) { $request = Set::merge(array('method' => 'PUT', 'uri' => $uri, 'body' => $data), $request); return $this->request($request); } @@ -412,7 +413,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request */ - public function delete($uri = null, $data = array(), $request = array()) { + public function &delete($uri = null, $data = array(), $request = array()) { $request = Set::merge(array('method' => 'DELETE', 'uri' => $uri, 'body' => $data), $request); return $this->request($request); } diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 858a5df10..df4914ec3 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -621,6 +621,22 @@ class HttpSocketTest extends CakeTestCase { $this->assertFalse($this->Socket->connected); } +/** + * testRequestResultAsPointer method + * + * @return void + */ + public function testRequestResultAsPointer() { + $request = array('uri' => 'htpp://www.cakephp.org/'); + $serverResponse = "HTTP/1.x 200 OK\r\nSet-Cookie: foo=bar\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a cookie test!

"; + $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->connected = true; + $data =& $this->Socket->request($request); + $this->assertEqual($data, $this->Socket->response['body']); + $data = 'new data'; + $this->assertEqual($data, $this->Socket->response['body']); + } + /** * testProxy method * From 151ea2804f64531207e2452a07c80fd03758edb6 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 6 Dec 2010 03:23:09 -0200 Subject: [PATCH 050/125] Default value to raw key, avoiding warnings if line is false. --- cake/libs/http_socket.php | 1 + 1 file changed, 1 insertion(+) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index c467393c9..99bd71014 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -303,6 +303,7 @@ class HttpSocket extends CakeSocket { return $this->response = false; } + $this->request['raw'] = ''; if ($this->request['line'] !== false) { $this->request['raw'] = $this->request['line']; } From 33bb253dfa5c8d10a0774110ed72b8964b2e80b8 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 6 Dec 2010 03:56:16 -0200 Subject: [PATCH 051/125] Minor optimization in HttpSocket::reset(). --- cake/libs/http_socket.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 99bd71014..f88a16e67 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -1120,13 +1120,11 @@ class HttpSocket extends CakeSocket { if (empty($initalState)) { $initalState = get_class_vars(__CLASS__); } - if ($full == false) { + if (!$full) { $this->request = $initalState['request']; $this->response = $initalState['response']; return true; } - $this->_auth = array(); - $this->_proxy = array(); parent::reset($initalState); return true; } From 30a70b700bb0967c1f726bab809a6a2cf4834546 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 6 Dec 2010 04:02:23 -0200 Subject: [PATCH 052/125] HttpSocket::_configUri() always change config attribute and it is public. This function dont need return it. --- cake/libs/http_socket.php | 4 ++-- cake/tests/cases/libs/http_socket.test.php | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index f88a16e67..263dcb585 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -674,7 +674,7 @@ class HttpSocket extends CakeSocket { * Parses and sets the specified URI into current request configuration. * * @param mixed $uri URI, See HttpSocket::_parseUri() - * @return array Current configuration settings + * @return boolean If uri has merged in config */ protected function _configUri($uri = null) { if (empty($uri)) { @@ -697,7 +697,7 @@ class HttpSocket extends CakeSocket { ); $this->config = Set::merge($this->config, $config); $this->config = Set::merge($this->config, array_intersect_key($this->config['request']['uri'], $this->config)); - return $this->config; + return true; } /** diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index df4914ec3..d589f11a3 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -290,12 +290,12 @@ class HttpSocketTest extends CakeTestCase { ) ); $this->assertEquals($this->Socket->config, $expected); - $this->assertEquals($r, $expected); + $this->assertTrue($r); $r = $this->Socket->configUri(array('host' => 'www.foo-bar.org')); $expected['host'] = 'www.foo-bar.org'; $expected['request']['uri']['host'] = 'www.foo-bar.org'; $this->assertEquals($this->Socket->config, $expected); - $this->assertEquals($r, $expected); + $this->assertTrue($r); $r = $this->Socket->configUri('http://www.foo.com'); $expected = array( @@ -314,13 +314,13 @@ class HttpSocketTest extends CakeTestCase { ) ); $this->assertEquals($this->Socket->config, $expected); - $this->assertEquals($r, $expected); + $this->assertTrue($r); $r = $this->Socket->configUri('/this-is-broken'); $this->assertEquals($this->Socket->config, $expected); - $this->assertEquals($r, false); + $this->assertFalse($r); $r = $this->Socket->configUri(false); $this->assertEquals($this->Socket->config, $expected); - $this->assertEquals($r, false); + $this->assertFalse($r); } /** From d656bdae3b3c622f03a8eabab9dd8c09e194a71d Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 6 Dec 2010 11:28:40 -0200 Subject: [PATCH 053/125] Renamed proxy method and calling togheter from host config. --- cake/libs/http_socket.php | 4 ++-- cake/tests/cases/libs/http_socket.test.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 263dcb585..84742fddd 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -245,6 +245,7 @@ class HttpSocket extends CakeSocket { if (isset($host)) { $this->config['host'] = $host; } + $this->_setProxy(); $cookies = null; if (is_array($this->request['header'])) { @@ -275,7 +276,6 @@ class HttpSocket extends CakeSocket { $this->setAuthConfig('Basic', $this->request['uri']['user'], $this->request['uri']['pass']); } $this->_setAuth(); - $this->_setProxyConfig(); if (is_array($this->request['body'])) { $this->request['body'] = $this->_httpSerialize($this->request['body']); @@ -501,7 +501,7 @@ class HttpSocket extends CakeSocket { * @return void * @throws Exception */ - protected function _setProxyConfig() { + protected function _setProxy() { if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) { return; } diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index d589f11a3..156dc9816 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -662,7 +662,7 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($this->Socket->config['port'], 123); $this->Socket->setAuthConfig('Test', 'login', 'passwd'); - $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nAuthorization: Test login.passwd\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; + $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nProxy-Authorization: Test mark.secret\r\nAuthorization: Test login.passwd\r\n\r\n"; $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); } From 7c23d289e0945f0af53ef2e219ca5c4aa95c6aea Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 6 Dec 2010 12:03:22 -0200 Subject: [PATCH 054/125] Minor optimizations. --- cake/libs/http_socket.php | 2 +- cake/tests/cases/libs/http_socket.test.php | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 84742fddd..545762b75 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -321,7 +321,7 @@ class HttpSocket extends CakeSocket { $response .= $data; } - if ($connectionType == 'close') { + if ($connectionType === 'close') { $this->disconnect(); } diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 156dc9816..a7410231f 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -251,13 +251,12 @@ class HttpSocketTest extends CakeTestCase { $baseConfig['host'] = 'foo-bar'; $baseConfig['protocol'] = getprotobyname($baseConfig['protocol']); $this->assertEquals($this->Socket->config, $baseConfig); + $this->Socket->reset(); $baseConfig = $this->Socket->config; $this->Socket->__construct('http://www.cakephp.org:23/'); - $baseConfig['host'] = 'www.cakephp.org'; - $baseConfig['request']['uri']['host'] = 'www.cakephp.org'; - $baseConfig['port'] = 23; - $baseConfig['request']['uri']['port'] = 23; + $baseConfig['host'] = $baseConfig['request']['uri']['host'] = 'www.cakephp.org'; + $baseConfig['port'] = $baseConfig['request']['uri']['port'] = 23; $baseConfig['protocol'] = getprotobyname($baseConfig['protocol']); $this->assertEquals($this->Socket->config, $baseConfig); From bcacace061106e8c04b02c670992b1bf8c678d9a Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 6 Dec 2010 12:04:00 -0200 Subject: [PATCH 055/125] Updating docs. --- cake/libs/http_socket.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 545762b75..a128e96ad 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -41,7 +41,7 @@ class HttpSocket extends CakeSocket { public $quirksMode = false; /** - * The default values to use for a request + * Contain information about the last request (read only) * * @var array */ @@ -69,7 +69,7 @@ class HttpSocket extends CakeSocket { ); /** - * The default structure for storing the response + * Contain information about the last response (read only) * * @var array */ @@ -91,7 +91,7 @@ class HttpSocket extends CakeSocket { ); /** - * Default configuration settings for the HttpSocket + * Configuration settings for the HttpSocket and the requests * * @var array */ From 8681399fc29443281107a0788e65056f44e72598 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 6 Dec 2010 21:29:11 -0500 Subject: [PATCH 056/125] Forcing the plugin list to use a fresh directory listing in the web runner. Fixes #1338 --- cake/tests/lib/reporter/cake_html_reporter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/tests/lib/reporter/cake_html_reporter.php b/cake/tests/lib/reporter/cake_html_reporter.php index 7074b844a..b1ef7ac9f 100755 --- a/cake/tests/lib/reporter/cake_html_reporter.php +++ b/cake/tests/lib/reporter/cake_html_reporter.php @@ -74,7 +74,7 @@ class CakeHtmlReporter extends CakeBaseReporter { function paintTestMenu() { $groups = $this->baseUrl() . '?show=groups'; $cases = $this->baseUrl() . '?show=cases'; - $plugins = App::objects('plugin'); + $plugins = App::objects('plugin', null, false); sort($plugins); include CAKE_TESTS_LIB . 'templates' . DS . 'menu.php'; } From 48f32a11e03b7af923aea601e17fb93f77df5cee Mon Sep 17 00:00:00 2001 From: jblotus Date: Wed, 8 Dec 2010 09:41:28 -0800 Subject: [PATCH 057/125] Fixed incorrect docblock. Fixes #1350 Signed-off-by: mark_story --- cake/libs/view/helpers/html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/libs/view/helpers/html.php b/cake/libs/view/helpers/html.php index 3dedaccbc..dee7cc309 100644 --- a/cake/libs/view/helpers/html.php +++ b/cake/libs/view/helpers/html.php @@ -806,7 +806,7 @@ class HtmlHelper extends AppHelper { /** * Internal function to build a nested list (UL/OL) out of an associative array. * - * @param array $list Set of elements to list + * @param array $items Set of elements to list * @param array $options Additional HTML attributes of the list (ol/ul) tag * @param array $itemOptions Additional HTML attributes of the list item (LI) tag * @param string $tag Type of list tag to use (ol/ul) From a8306320717feb75f870b0c68eeeb5e708dae64f Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 9 Dec 2010 22:06:23 -0500 Subject: [PATCH 058/125] Changing View::element() to not overwrite viewVars with helpers that have the same name. Test added. Fixes #1354 --- cake/libs/view/view.php | 9 +++++++-- cake/tests/cases/libs/view/view.test.php | 18 ++++++++++++++++++ .../test_app/views/elements/type_check.ctp | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 cake/tests/test_app/views/elements/type_check.ctp diff --git a/cake/libs/view/view.php b/cake/libs/view/view.php index ad7600b1f..fd1999e9a 100644 --- a/cake/libs/view/view.php +++ b/cake/libs/view/view.php @@ -381,8 +381,13 @@ class View extends Object { } if (is_file($file)) { - $params = array_merge_recursive($params, $this->loaded); - $element = $this->_render($file, array_merge($this->viewVars, $params), $loadHelpers); + $vars = array_merge($this->viewVars, $params); + foreach ($this->loaded as $name => $helper) { + if (!isset($vars[$name])) { + $vars[$name] =& $this->loaded[$name]; + } + } + $element = $this->_render($file, $vars, $loadHelpers); if (isset($params['cache']) && isset($cacheFile) && isset($expires)) { cache('views' . DS . $cacheFile, $element, $expires); } diff --git a/cake/tests/cases/libs/view/view.test.php b/cake/tests/cases/libs/view/view.test.php index 4905cad20..8ffb0837a 100644 --- a/cake/tests/cases/libs/view/view.test.php +++ b/cake/tests/cases/libs/view/view.test.php @@ -487,6 +487,24 @@ class ViewTest extends CakeTestCase { $this->assertPattern('/non_existant_element/', $result); } +/** + * test that additional element viewVars don't get overwritten with helpers. + * + * @return void + */ + function testElementParamsDontOverwriteHelpers() { + $Controller = new ViewPostsController(); + $Controller->helpers = array('Form'); + + $View = new View($Controller); + $result = $View->element('type_check', array('form' => 'string'), true); + $this->assertEqual('string', $result); + + $View->set('form', 'string'); + $result = $View->element('type_check', array(), true); + $this->assertEqual('string', $result); + } + /** * testElementCacheHelperNoCache method * diff --git a/cake/tests/test_app/views/elements/type_check.ctp b/cake/tests/test_app/views/elements/type_check.ctp new file mode 100644 index 000000000..a863c2b48 --- /dev/null +++ b/cake/tests/test_app/views/elements/type_check.ctp @@ -0,0 +1 @@ + \ No newline at end of file From d7e62b88bc889921040dc256987e51a2241fd373 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 9 Dec 2010 22:34:20 -0500 Subject: [PATCH 059/125] Adding test cases for using helpers in nested elements from email templates. Closes #1355 --- .../libs/controller/components/email.test.php | 34 ++++++++++++------- .../elements/email/html/nested_element.ctp | 3 ++ .../test_app/views/elements/html_call.ctp | 3 ++ 3 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 cake/tests/test_app/views/elements/email/html/nested_element.ctp create mode 100644 cake/tests/test_app/views/elements/html_call.ctp diff --git a/cake/tests/cases/libs/controller/components/email.test.php b/cake/tests/cases/libs/controller/components/email.test.php index 3a0472877..ed80c1b2b 100755 --- a/cake/tests/cases/libs/controller/components/email.test.php +++ b/cake/tests/cases/libs/controller/components/email.test.php @@ -629,22 +629,30 @@ HTMLBLOC; $expect = '
' . str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $header) . $html . '
'; $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message', 'default', 'thin')); $this->assertEqual($this->Controller->Session->read('Message.email.message'), $this->__osFix($expect)); + } - return; +/** + * test that elements used in email templates get helpers. + * + * @return void + */ + function testTemplateNestedElements() { + $this->Controller->EmailTest->to = 'postmaster@localhost'; + $this->Controller->EmailTest->from = 'noreply@example.com'; + $this->Controller->EmailTest->subject = 'Cake SMTP test'; + $this->Controller->EmailTest->replyTo = 'noreply@example.com'; - $text = <<Controller->EmailTest->delivery = 'debug'; + $this->Controller->EmailTest->messageId = false; + $this->Controller->EmailTest->layout = 'default'; + $this->Controller->EmailTest->template = 'nested_element'; + $this->Controller->EmailTest->sendAs = 'html'; + $this->Controller->helpers = array('Html'); -This element has some text that is just too wide to comply with email -standards. -This is the body of the message - -This email was sent using the CakePHP Framework, http://cakephp.org. -TEXTBLOC; - - $this->Controller->EmailTest->sendAs = 'text'; - $expect = '
' . str_replace('{CONTENTTYPE}', 'text/plain; charset=UTF-8', $header) . $text . "\n" . '
'; - $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message', 'wide', 'default')); - $this->assertEqual($this->Controller->Session->read('Message.email.message'), $this->__osFix($expect)); + $this->Controller->EmailTest->send(); + $result = $this->Controller->Session->read('Message.email.message'); + $this->assertPattern('/Test/', $result); + $this->assertPattern('/http\:\/\/example\.com/', $result); } /** diff --git a/cake/tests/test_app/views/elements/email/html/nested_element.ctp b/cake/tests/test_app/views/elements/email/html/nested_element.ctp new file mode 100644 index 000000000..49858200e --- /dev/null +++ b/cake/tests/test_app/views/elements/email/html/nested_element.ctp @@ -0,0 +1,3 @@ +Before the element. +element('html_call'); ?> +After the element. \ No newline at end of file diff --git a/cake/tests/test_app/views/elements/html_call.ctp b/cake/tests/test_app/views/elements/html_call.ctp new file mode 100644 index 000000000..8c2c08978 --- /dev/null +++ b/cake/tests/test_app/views/elements/html_call.ctp @@ -0,0 +1,3 @@ +Html->link('Test', 'http://example.com'); +?> \ No newline at end of file From 453c5364c28dc86841582912a72a50608f68f12c Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 10 Dec 2010 10:38:49 -0200 Subject: [PATCH 060/125] Putting the auth and proxy data in request attribute after request. --- cake/libs/http_socket.php | 3 ++ cake/tests/cases/libs/http_socket.test.php | 55 ++++++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index a128e96ad..53e010874 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -246,6 +246,8 @@ class HttpSocket extends CakeSocket { $this->config['host'] = $host; } $this->_setProxy(); + $this->request['proxy'] = $this->_proxy; + $cookies = null; if (is_array($this->request['header'])) { @@ -276,6 +278,7 @@ class HttpSocket extends CakeSocket { $this->setAuthConfig('Basic', $this->request['uri']['user'], $this->request['uri']['pass']); } $this->_setAuth(); + $this->request['auth'] = $this->_auth; if (is_array($this->request['body'])) { $this->request['body'] = $this->_httpSerialize($this->request['body']); diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index a7410231f..aac957c0d 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -349,7 +349,7 @@ class HttpSocketTest extends CakeTestCase { 'host' => 'www.cakephp.org', 'port' => 80 ), - 'cookies' => array() + 'cookies' => array(), ) ), 'request' => array( @@ -369,7 +369,9 @@ class HttpSocketTest extends CakeTestCase { 'line' => "GET /?foo=bar HTTP/1.1\r\n", 'header' => "Host: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n", 'raw' => "", - 'cookies' => array() + 'cookies' => array(), + 'proxy' => array(), + 'auth' => array() ) ) ), @@ -621,11 +623,11 @@ class HttpSocketTest extends CakeTestCase { } /** - * testRequestResultAsPointer method + * testRequestResultAsReference method * * @return void */ - public function testRequestResultAsPointer() { + public function testRequestResultAsReference() { $request = array('uri' => 'htpp://www.cakephp.org/'); $serverResponse = "HTTP/1.x 200 OK\r\nSet-Cookie: foo=bar\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a cookie test!

"; $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); @@ -652,6 +654,28 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($this->Socket->request['raw'], $expected); $this->assertEqual($this->Socket->config['host'], 'proxy.server'); $this->assertEqual($this->Socket->config['port'], 123); + $expected = array( + 'host' => 'proxy.server', + 'port' => 123, + 'method' => null, + 'user' => null, + 'pass' => null + ); + $this->assertEqual($this->Socket->request['proxy'], $expected); + + $expected = "GET http://www.cakephp.org/bakery HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n\r\n"; + $this->Socket->request('/bakery'); + $this->assertEqual($this->Socket->request['raw'], $expected); + $this->assertEqual($this->Socket->config['host'], 'proxy.server'); + $this->assertEqual($this->Socket->config['port'], 123); + $expected = array( + 'host' => 'proxy.server', + 'port' => 123, + 'method' => null, + 'user' => null, + 'pass' => null + ); + $this->assertEqual($this->Socket->request['proxy'], $expected); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; $this->Socket->setProxyConfig('proxy.server', 123, 'Test', 'mark', 'secret'); @@ -659,11 +683,34 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($this->Socket->request['raw'], $expected); $this->assertEqual($this->Socket->config['host'], 'proxy.server'); $this->assertEqual($this->Socket->config['port'], 123); + $expected = array( + 'host' => 'proxy.server', + 'port' => 123, + 'method' => 'Test', + 'user' => 'mark', + 'pass' => 'secret' + ); + $this->assertEqual($this->Socket->request['proxy'], $expected); $this->Socket->setAuthConfig('Test', 'login', 'passwd'); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nProxy-Authorization: Test mark.secret\r\nAuthorization: Test login.passwd\r\n\r\n"; $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); + $expected = array( + 'host' => 'proxy.server', + 'port' => 123, + 'method' => 'Test', + 'user' => 'mark', + 'pass' => 'secret' + ); + $this->assertEqual($this->Socket->request['proxy'], $expected); + $expected = array( + 'Test' => array( + 'user' => 'login', + 'pass' => 'passwd' + ) + ); + $this->assertEqual($this->Socket->request['auth'], $expected); } /** From 1e108748e923b6daa5698fe98836c7483552e96b Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 10 Dec 2010 22:51:42 -0500 Subject: [PATCH 061/125] Fixing validation methods + features lost in [f51ce734] due to a bad merge. Fixing additional tests to reflect changes in 2.0 --- cake/libs/cake_session.php | 2 +- cake/libs/controller/scaffold.php | 4 ++-- cake/libs/validation.php | 16 ++++++++++++++-- .../libs/controller/components/cookie.test.php | 4 ++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/cake/libs/cake_session.php b/cake/libs/cake_session.php index 34c293fe7..f90b27b3d 100644 --- a/cake/libs/cake_session.php +++ b/cake/libs/cake_session.php @@ -455,7 +455,7 @@ class CakeSession { } foreach ($write as $key => $val) { if (in_array($key, self::$watchKeys)) { - trigger_error(__('Writing session key {%s}: %s', $key, Debugger::exportVar($val)), E_USER_NOTICE); + trigger_error(__('Writing session key {%s}: %s', $key, var_export($val, true)), E_USER_NOTICE); } self::__overwrite($_SESSION, Set::insert($_SESSION, $key, $val)); if (Set::classicExtract($_SESSION, $key) !== $val) { diff --git a/cake/libs/controller/scaffold.php b/cake/libs/controller/scaffold.php index 492ddeba9..34eb22c6d 100644 --- a/cake/libs/controller/scaffold.php +++ b/cake/libs/controller/scaffold.php @@ -260,7 +260,7 @@ class Scaffold { if ($this->ScaffoldModel->save($request->data)) { if ($this->controller->_afterScaffoldSave($action)) { $message = sprintf( - __('The %1$s has been %2$s', true), + __('The %1$s has been %2$s'), Inflector::humanize($this->modelKey), $success ); @@ -328,7 +328,7 @@ class Scaffold { $message = sprintf( __('There was an error deleting the %1$s with id: %2$d', true), Inflector::humanize($this->modelClass), $id - )); + ); return $this->_sendMessage($message); } } elseif ($this->controller->_scaffoldError('delete') === false) { diff --git a/cake/libs/validation.php b/cake/libs/validation.php index 15f4af042..5af6db748 100644 --- a/cake/libs/validation.php +++ b/cake/libs/validation.php @@ -670,10 +670,10 @@ class Validation { self::__populateIp(); $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~') . '\/0-9a-z\p{L}\p{N}]|(%[0-9a-f]{2}))'; $regex = '/^(?:(?:https?|ftps?|file|news|gopher):\/\/)' . (!empty($strict) ? '' : '?') . - '(?:' . self::$__pattern['IPv4'] . '|' . self::$__pattern['hostname'] . ')(?::[1-9][0-9]{0,3})?' . + '(?:' . self::$__pattern['IPv4'] . '|\[' . self::$__pattern['IPv6'] . '\]|' . self::$__pattern['hostname'] . ')(?::[1-9][0-9]{0,4})?' . '(?:\/?|\/' . $validChars . '*)?' . '(?:\?' . $validChars . '*)?' . - '(?:#' . $validChars . '*)?$/i'; + '(?:#' . $validChars . '*)?$/iu'; return self::_check($check, $regex); } @@ -701,6 +701,18 @@ class Validation { return call_user_func_array(array($object, $method), array($check, $args)); } +/** + * Checks that a value is a valid uuid - http://tools.ietf.org/html/rfc4122 + * + * @param string $check Value to check + * @return boolean Success + * @access public + */ + public static function uuid($check) { + $regex = '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i'; + return self::_check($check, $regex); + } + /** * Attempts to pass unhandled Validation locales to a class starting with $classPrefix * and ending with Validation. For example $classPrefix = 'nl', the class would be diff --git a/cake/tests/cases/libs/controller/components/cookie.test.php b/cake/tests/cases/libs/controller/components/cookie.test.php index c223034ff..84a852c6d 100644 --- a/cake/tests/cases/libs/controller/components/cookie.test.php +++ b/cake/tests/cases/libs/controller/components/cookie.test.php @@ -465,10 +465,10 @@ class CookieComponentTest extends CakeTestCase { * @return void */ function testNoErrorOnNonArrayData() { - $this->Controller->Cookie->destroy(); + $this->Cookie->destroy(); $_COOKIE['CakeTestCookie'] = 'kaboom'; - $this->assertNull($this->Controller->Cookie->read('value')); + $this->assertNull($this->Cookie->read('value')); } /** From ceca1791846a4925a503ee6b6093560b936c5633 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 10 Dec 2010 23:17:42 -0500 Subject: [PATCH 062/125] Fixing more tests that were failing post merge. --- cake/libs/controller/controller.php | 17 ++++++++++++----- .../cases/libs/controller/controller.test.php | 7 ++++--- .../cases/libs/view/helpers/number.test.php | 1 + 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/cake/libs/controller/controller.php b/cake/libs/controller/controller.php index 22b5fe881..7bc58f024 100644 --- a/cake/libs/controller/controller.php +++ b/cake/libs/controller/controller.php @@ -440,17 +440,24 @@ class Controller extends Object { $this->uses = array_flip($this->uses); array_unshift($this->uses, $plugin . $this->modelClass); } - } elseif ($this->uses !== null || $this->uses !== false) { - $this->_mergeVars(array('uses'), 'AppController', false); + } elseif ( + ($this->uses !== null || $this->uses !== false) && + is_array($this->uses) && !empty($appVars['uses']) + ) { + $this->uses = array_merge($this->uses, array_diff($appVars['uses'], $this->uses)); + var_dump($this->uses); } $this->_mergeVars($merge, 'AppController', true); } if ($pluginController && $pluginName != null) { $merge = array('components', 'helpers'); - - if ($this->uses !== null || $this->uses !== false) { - $this->_mergeVars(array('uses'), $pluginController, false); + $appVars = get_class_vars($pluginController); + if ( + ($this->uses !== null || $this->uses !== false) && + is_array($this->uses) && !empty($appVars['uses']) + ) { + $this->uses = array_merge($this->uses, array_diff($appVars['uses'], $this->uses)); } $this->_mergeVars($merge, $pluginController); } diff --git a/cake/tests/cases/libs/controller/controller.test.php b/cake/tests/cases/libs/controller/controller.test.php index a1d06b779..089955373 100644 --- a/cake/tests/cases/libs/controller/controller.test.php +++ b/cake/tests/cases/libs/controller/controller.test.php @@ -1283,13 +1283,14 @@ class ControllerTest extends CakeTestCase { ? array_merge($appVars['uses'], $testVars['uses']) : $testVars['uses']; - $this->assertEqual(count(array_diff($TestController->helpers, $helpers)), 0); + $this->assertEqual(count(array_diff_key($TestController->helpers, array_flip($helpers))), 0); $this->assertEqual(count(array_diff($TestController->uses, $uses)), 0); $this->assertEqual(count(array_diff_assoc(Set::normalize($TestController->components), Set::normalize($components))), 0); - $TestController = new AnotherTestController($request); $expected = array('ControllerComment', 'ControllerAlias', 'ControllerPost'); - $this->assertEqual($expected, $TestController->uses, '$uses was merged incorrectly, AppController models should be last.'); + $this->assertEquals($expected, $TestController->uses, '$uses was merged incorrectly, AppController models should be last.'); + + $TestController = new AnotherTestController($request); $TestController->constructClasses(); $appVars = get_class_vars('AppController'); diff --git a/cake/tests/cases/libs/view/helpers/number.test.php b/cake/tests/cases/libs/view/helpers/number.test.php index d34eb65c0..30022d2cd 100644 --- a/cake/tests/cases/libs/view/helpers/number.test.php +++ b/cake/tests/cases/libs/view/helpers/number.test.php @@ -18,6 +18,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ App::import('Helper', 'Number'); +App::import('View', 'View'); /** * NumberHelperTest class From 9bfd170443c249a10b31b8a6cac972d6ef9b1b9a Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 10 Dec 2010 23:35:22 -0500 Subject: [PATCH 063/125] Making behaviour of debug() consistent between cli and web. --- cake/basics.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cake/basics.php b/cake/basics.php index b80b1b645..b88e14a9e 100644 --- a/cake/basics.php +++ b/cake/basics.php @@ -116,10 +116,9 @@ TEXT; $template = $html; if (php_sapi_name() == 'cli') { $template = $text; - } else { - if ($showHtml === null) { - $showHtml = true; - } + } + if ($showHtml === null) { + $showHtml = true; } $var = print_r($var, true); if ($showHtml) { From eeafb55d314f3a03508d7067b8d3c46bd3a7ea40 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Fri, 10 Dec 2010 12:08:49 -0200 Subject: [PATCH 064/125] Support to download requests. --- cake/libs/http_socket.php | 46 +++++++++++++++++++++- cake/tests/cases/libs/http_socket.test.php | 28 +++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 53e010874..0ecc1a60b 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -132,6 +132,13 @@ class HttpSocket extends CakeSocket { */ protected $_proxy = array(); +/** + * Resource to receive the content of request + * + * @var mixed + */ + protected $_contentResource = null; + /** * Build an HTTP Socket using the specified configuration. * @@ -208,6 +215,24 @@ class HttpSocket extends CakeSocket { $this->_proxy = compact('host', 'port', 'method', 'user', 'pass'); } +/** + * Set the resource to receive the request content. This resource must support fwrite. + * + * @param mixed $resource Resource or false to disable the resource use + * @return void + * @throw Exception + */ + public function setContentResource($resource) { + if ($resource === false) { + $this->_contentResource = null; + return; + } + if (!is_resource($resource)) { + throw new Exception(__('Invalid resource.')); + } + $this->_contentResource = $resource; + } + /** * Issue the specified request. HttpSocket::get() and HttpSocket::post() wrap this * method and provide a more granular interface. @@ -320,8 +345,27 @@ class HttpSocket extends CakeSocket { $this->write($this->request['raw']); $response = null; + $inHeader = true; while ($data = $this->read()) { - $response .= $data; + if ($this->_contentResource) { + if ($inHeader) { + $response .= $data; + $pos = strpos($response, "\r\n\r\n"); + if ($pos !== false) { + $pos += 4; + $data = substr($response, $pos); + fwrite($this->_contentResource, $data); + + $response = substr($response, 0, $pos); + $inHeader = false; + } + } else { + fwrite($this->_contentResource, $data); + fflush($this->_contentResource); + } + } else { + $response .= $data; + } } if ($connectionType === 'close') { diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index aac957c0d..32be35f7b 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -638,6 +638,34 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($data, $this->Socket->response['body']); } +/** + * testRequestWithResource + * + * @return void + */ + public function testRequestWithResource() { + $serverResponse = "HTTP/1.x 200 OK\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a test!

"; + $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->expects($this->at(2))->method('read')->will($this->returnValue(false)); + $this->Socket->expects($this->at(4))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->connected = true; + + $f = fopen(TMP . 'download.txt', 'w'); + $this->skipUnless($f, 'Can not write in TMP directory.'); + + $this->Socket->setContentResource($f); + $result = $this->Socket->request('http://www.cakephp.org/'); + $this->assertEqual($result, ''); + $this->assertEqual($this->Socket->response['header']['Server'], 'CakeHttp Server'); + fclose($f); + $this->assertEqual(file_get_contents(TMP . 'download.txt'), '

This is a test!

'); + unlink(TMP . 'download.txt'); + + $this->Socket->setContentResource(false); + $result = $this->Socket->request('http://www.cakephp.org/'); + $this->assertEqual($result, '

This is a test!

'); + } + /** * testProxy method * From 504b4d495f72cd34f581813029775c2488350ddf Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 11 Dec 2010 12:47:16 -0500 Subject: [PATCH 065/125] Adding stack traces to logged exceptions, as I forgot them last time around. --- cake/libs/error/error_handler.php | 7 ++++++- cake/tests/cases/libs/error/error_handler.test.php | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cake/libs/error/error_handler.php b/cake/libs/error/error_handler.php index 85cea7ec4..b25582fac 100644 --- a/cake/libs/error/error_handler.php +++ b/cake/libs/error/error_handler.php @@ -110,7 +110,12 @@ class ErrorHandler { if (!class_exists('CakeLog')) { require LIBS . 'cake_log.php'; } - CakeLog::write(LOG_ERR, '[' . get_class($exception) . '] ' . $exception->getMessage()); + $message = sprintf("[%s] %s\n%s", + get_class($exception), + $exception->getMessage(), + $exception->getTraceAsString() + ); + CakeLog::write(LOG_ERR, $message); } if ($config['renderer'] !== 'ExceptionRenderer') { App::import('Lib', $config['renderer']); diff --git a/cake/tests/cases/libs/error/error_handler.test.php b/cake/tests/cases/libs/error/error_handler.test.php index 736524251..c6f33d600 100644 --- a/cake/tests/cases/libs/error/error_handler.test.php +++ b/cake/tests/cases/libs/error/error_handler.test.php @@ -220,6 +220,7 @@ class ErrorHandlerTest extends CakeTestCase { $log = file(LOGS . 'error.log'); $this->assertPattern('/\[NotFoundException\] Kaboom!/', $log[0], 'message missing.'); + $this->assertPattern('/\#0.*ErrorHandlerTest->testHandleExceptionLog/', $log[1], 'Stack trace missing.'); } } From 60ada4432a1a52839f2f6a4cafdb0d6594a410e0 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 11 Dec 2010 13:30:29 -0500 Subject: [PATCH 066/125] Making unknown errors with codes higher than 500 render as error500. Test added. --- cake/libs/error/exception_renderer.php | 2 +- .../libs/error/exception_renderer.test.php | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cake/libs/error/exception_renderer.php b/cake/libs/error/exception_renderer.php index 0d6c71b83..6666f4414 100644 --- a/cake/libs/error/exception_renderer.php +++ b/cake/libs/error/exception_renderer.php @@ -107,7 +107,7 @@ class ExceptionRenderer { } } elseif (!$methodExists) { $method = 'error500'; - if ($code >= 400) { + if ($code >= 400 && $code < 500) { $method = 'error400'; } } diff --git a/cake/tests/cases/libs/error/exception_renderer.test.php b/cake/tests/cases/libs/error/exception_renderer.test.php index c99c6b118..91efdf608 100644 --- a/cake/tests/cases/libs/error/exception_renderer.test.php +++ b/cake/tests/cases/libs/error/exception_renderer.test.php @@ -322,6 +322,24 @@ class ExceptionRendererTest extends CakeTestCase { $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.'); } +/** + * test that unknown exception types with valid status codes are treated correctly. + * + * @return void + */ + function testUnknownExceptionTypeWithCodeHigherThan500() { + $exception = new OutOfBoundsException('foul ball.', 501); + $ExceptionRenderer = new ExceptionRenderer($exception); + $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader')); + $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(501); + + ob_start(); + $ExceptionRenderer->render(); + $results = ob_get_clean(); + + $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.'); + } + /** * testerror400 method * From 6c0efb62e729ea5e8658c1561f630a1b5fff37f4 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 11 Dec 2010 13:38:09 -0500 Subject: [PATCH 067/125] Adding a base HttpException for all the various HttpExceptions that cake provides, this should make it easier to write concise catch blocks. --- cake/libs/error/exceptions.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/cake/libs/error/exceptions.php b/cake/libs/error/exceptions.php index 473b2dbee..961b39c7d 100644 --- a/cake/libs/error/exceptions.php +++ b/cake/libs/error/exceptions.php @@ -19,12 +19,21 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +/** + * Parent class for all of the HTTP related exceptions in CakePHP. + * All HTTP status/error related exceptions should extend this class so + * catch blocks can be specifically typed. + * + * @package cake.libs + */ +class HttpException extends RuntimeException { } + /** * Represents an HTTP 400 error. * * @package cake.libs */ -class BadRequestException extends RuntimeException { +class BadRequestException extends HttpException { /** * Constructor * @@ -44,7 +53,7 @@ class BadRequestException extends RuntimeException { * * @package cake.libs */ -class UnauthorizedException extends RuntimeException { +class UnauthorizedException extends HttpException { /** * Constructor * @@ -64,7 +73,7 @@ class UnauthorizedException extends RuntimeException { * * @package cake.libs */ -class ForbiddenException extends RuntimeException { +class ForbiddenException extends HttpException { /** * Constructor * @@ -84,7 +93,7 @@ class ForbiddenException extends RuntimeException { * * @package cake.libs */ -class NotFoundException extends RuntimeException { +class NotFoundException extends HttpException { /** * Constructor * @@ -104,7 +113,7 @@ class NotFoundException extends RuntimeException { * * @package cake.libs */ -class MethodNotAllowedException extends RuntimeException { +class MethodNotAllowedException extends HttpException { /** * Constructor * @@ -124,7 +133,7 @@ class MethodNotAllowedException extends RuntimeException { * * @package cake.libs */ -class InternalErrorException extends CakeException { +class InternalErrorException extends HttpException { /** * Constructor * From d332f0624fbe91afe5524b55d4fa0826b239d710 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 11 Dec 2010 16:49:19 -0200 Subject: [PATCH 068/125] Making the cookies independent for each host. --- cake/libs/http_socket.php | 19 ++++++++-- cake/tests/cases/libs/http_socket.test.php | 41 +++++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 0ecc1a60b..0af827f44 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -263,10 +263,21 @@ class HttpSocket extends CakeSocket { } $request['uri'] = $this->url($request['uri']); $request['uri'] = $this->_parseUri($request['uri'], true); - $this->request = Set::merge($this->request, $this->config['request'], $request); + $this->request = Set::merge($this->request, array_diff_key($this->config['request'], array('cookies' => true)), $request); $this->_configUri($this->request['uri']); + $Host = $this->request['uri']['host']; + if (!empty($this->config['request']['cookies'][$Host])) { + if (!isset($this->request['cookies'])) { + $this->request['cookies'] = array(); + } + if (!isset($request['cookies'])) { + $request['cookies'] = array(); + } + $this->request['cookies'] = array_merge($this->request['cookies'], $this->config['request']['cookies'][$Host], $request['cookies']); + } + if (isset($host)) { $this->config['host'] = $host; } @@ -280,7 +291,6 @@ class HttpSocket extends CakeSocket { if (!empty($this->request['cookies'])) { $cookies = $this->buildCookies($this->request['cookies']); } - $Host = $this->request['uri']['host']; $schema = ''; $port = 0; if (isset($this->request['uri']['schema'])) { @@ -374,7 +384,10 @@ class HttpSocket extends CakeSocket { $this->response = $this->_parseResponse($response); if (!empty($this->response['cookies'])) { - $this->config['request']['cookies'] = array_merge($this->config['request']['cookies'], $this->response['cookies']); + if (!isset($this->config['request']['cookies'][$Host])) { + $this->config['request']['cookies'][$Host] = array(); + } + $this->config['request']['cookies'][$Host] = array_merge($this->config['request']['cookies'][$Host], $this->response['cookies']); } return $this->response['body']; diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 32be35f7b..895b62e08 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -618,7 +618,7 @@ class HttpSocketTest extends CakeTestCase { ) ); $this->assertEqual($result, $expect); - $this->assertEqual($this->Socket->config['request']['cookies'], $expect); + $this->assertEqual($this->Socket->config['request']['cookies']['www.cakephp.org'], $expect); $this->assertFalse($this->Socket->connected); } @@ -666,6 +666,45 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($result, '

This is a test!

'); } +/** + * testRequestWithCrossCookie + * + * @return void + */ + public function testRequestWithCrossCookie() { + $this->Socket->connected = true; + $this->Socket->config['request']['cookies'] = array(); + + $serverResponse = "HTTP/1.x 200 OK\r\nSet-Cookie: foo=bar\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a test!

"; + $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->expects($this->at(2))->method('read')->will($this->returnValue(false)); + $expected = array('www.cakephp.org' => array('foo' => array('value' => 'bar'))); + $this->Socket->request('http://www.cakephp.org/'); + $this->assertEqual($this->Socket->config['request']['cookies'], $expected); + + $serverResponse = "HTTP/1.x 200 OK\r\nSet-Cookie: bar=foo\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a test!

"; + $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->expects($this->at(2))->method('read')->will($this->returnValue(false)); + $this->Socket->request('http://www.cakephp.org/other'); + $this->assertEqual($this->Socket->request['cookies'], array('foo' => array('value' => 'bar'))); + $expected['www.cakephp.org'] += array('bar' => array('value' => 'foo')); + $this->assertEqual($this->Socket->config['request']['cookies'], $expected); + + $serverResponse = "HTTP/1.x 200 OK\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a test!

"; + $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->expects($this->at(2))->method('read')->will($this->returnValue(false)); + $this->Socket->request('/other2'); + $this->assertEqual($this->Socket->config['request']['cookies'], $expected); + + $serverResponse = "HTTP/1.x 200 OK\r\nSet-Cookie: foobar=ok\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

This is a test!

"; + $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->expects($this->at(2))->method('read')->will($this->returnValue(false)); + $this->Socket->request('http://www.cake.com'); + $this->assertTrue(empty($this->Socket->request['cookies'])); + $expected['www.cake.com'] = array('foobar' => array('value' => 'ok')); + $this->assertEqual($this->Socket->config['request']['cookies'], $expected); + } + /** * testProxy method * From b3f55bfd29de80d2cee560db0bdc7466e7a4734d Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 11 Dec 2010 13:23:23 -0800 Subject: [PATCH 069/125] Added shorter timeout to fsockopen checks --- .../libs/controller/components/email.test.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cake/tests/cases/libs/controller/components/email.test.php b/cake/tests/cases/libs/controller/components/email.test.php index f8fd2e4a5..1dafc9b42 100755 --- a/cake/tests/cases/libs/controller/components/email.test.php +++ b/cake/tests/cases/libs/controller/components/email.test.php @@ -268,7 +268,7 @@ class EmailComponentTest extends CakeTestCase { * @return void */ function testSmtpConfig() { - if ($this->skipIf(!@fsockopen('localhost', 25), '%s No SMTP server running on localhost')) { + if ($this->skipIf(!@fsockopen('localhost', 25, $err, $errstr, .01), '%s No SMTP server running on localhost')) { return; } $this->Controller->EmailTest->delivery = 'smtp'; @@ -295,7 +295,7 @@ class EmailComponentTest extends CakeTestCase { * @return void */ function testBadSmtpSend() { - if ($this->skipIf(!@fsockopen('localhost', 25), '%s No SMTP server running on localhost')) { + if ($this->skipIf(!@fsockopen('localhost', 25, $err, $errstr, .01), '%s No SMTP server running on localhost')) { return; } $this->Controller->EmailTest->smtpOptions['host'] = 'blah'; @@ -310,7 +310,7 @@ class EmailComponentTest extends CakeTestCase { * @return void */ function testSmtpSend() { - if ($this->skipIf(!@fsockopen('localhost', 25), '%s No SMTP server running on localhost')) { + if ($this->skipIf(!@fsockopen('localhost', 25, $err, $errstr, .01), '%s No SMTP server running on localhost')) { return; } @@ -359,7 +359,7 @@ TEMPDOC; * @return void */ function testSmtpEhlo() { - if ($this->skipIf(!@fsockopen('localhost', 25), '%s No SMTP server running on localhost')) { + if ($this->skipIf(!@fsockopen('localhost', 25, $err, $errstr, .01), '%s No SMTP server running on localhost')) { return; } @@ -416,7 +416,7 @@ TEMPDOC; * @return void */ function testSmtpSendMultipleTo() { - if ($this->skipIf(!@fsockopen('localhost', 25), '%s No SMTP server running on localhost')) { + if ($this->skipIf(!@fsockopen('localhost', 25, $err, $errstr, .01), '%s No SMTP server running on localhost')) { return; } $this->Controller->EmailTest->reset(); @@ -465,7 +465,7 @@ TEMPDOC; * @return void */ function testAuthenticatedSmtpSend() { - if ($this->skipIf(!@fsockopen('localhost', 25), '%s No SMTP server running on localhost')) { + if ($this->skipIf(!@fsockopen('localhost', 25, $err, $errstr, .01), '%s No SMTP server running on localhost')) { return; } @@ -658,7 +658,7 @@ TEXTBLOC; * @return void */ function testSmtpSendSocket() { - if ($this->skipIf(!@fsockopen('localhost', 25), '%s No SMTP server running on localhost')) { + if ($this->skipIf(!@fsockopen('localhost', 25, $err, $errstr, .01), '%s No SMTP server running on localhost')) { return; } From 7ed19eae88043e72c737144b077d3a8e1dcc50fc Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 11 Dec 2010 15:11:54 -0800 Subject: [PATCH 070/125] Allowed comma-delimited list in smtp $to var to be consistent with standard mail delivery. Fixes #1353 --- cake/libs/controller/components/email.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/libs/controller/components/email.php b/cake/libs/controller/components/email.php index a4cb6dd02..76fbee04e 100755 --- a/cake/libs/controller/components/email.php +++ b/cake/libs/controller/components/email.php @@ -861,7 +861,7 @@ class EmailComponent extends Component { } if (!is_array($this->to)) { - $tos = array($this->to); + $tos = array_map('trim', explode(',', $this->to)); } else { $tos = $this->to; } From 44c080d5ad0ef977d187b7887ccc748a836b7af5 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 11 Dec 2010 19:01:07 -0500 Subject: [PATCH 071/125] Making all core classes throw CakeException subclasses, this allows developers to catch framework exceptions with one catch. Adding package specific exceptions. Replacing generic exceptions in the codebase with CakeException + package exceptions. --- cake/console/libs/console_input_argument.php | 2 +- cake/console/libs/console_input_option.php | 2 +- cake/console/libs/console_option_parser.php | 6 +- cake/console/shell_dispatcher.php | 4 +- cake/libs/cache.php | 8 +-- cake/libs/cache/file.php | 8 +-- cake/libs/cache/memcache.php | 8 +-- cake/libs/cake_log.php | 8 +-- cake/libs/cake_request.php | 2 +- cake/libs/cake_response.php | 3 +- cake/libs/cake_session.php | 13 ++-- cake/libs/config/php_reader.php | 10 ++-- cake/libs/configure.php | 2 +- cake/libs/controller/components/acl.php | 8 +-- cake/libs/error/exceptions.php | 60 ++++++++++++++++++- cake/libs/router.php | 11 ++-- cake/libs/view/helpers/form.php | 5 +- cake/libs/view/helpers/paginator.php | 4 +- cake/libs/view/view.php | 6 +- cake/libs/xml.php | 18 +++--- .../libs/console_option_parser.test.php | 10 ++-- cake/tests/cases/libs/cake_log.test.php | 6 +- cake/tests/cases/libs/cake_request.test.php | 6 +- cake/tests/cases/libs/cake_response.test.php | 2 +- cake/tests/cases/libs/cake_session.test.php | 10 ++-- .../cases/libs/config/php_reader.test.php | 4 +- .../libs/controller/components/acl.test.php | 4 +- .../cases/libs/view/helpers/form.test.php | 2 +- 28 files changed, 146 insertions(+), 86 deletions(-) diff --git a/cake/console/libs/console_input_argument.php b/cake/console/libs/console_input_argument.php index c0ed84fc0..200582353 100644 --- a/cake/console/libs/console_input_argument.php +++ b/cake/console/libs/console_input_argument.php @@ -116,7 +116,7 @@ class ConsoleInputArgument { return true; } if (!in_array($value, $this->_choices)) { - throw new InvalidArgumentException(sprintf( + throw new ConsoleException(sprintf( __('"%s" is not a valid value for %s. Please use one of "%s"'), $value, $this->_name, implode(', ', $this->_choices) )); diff --git a/cake/console/libs/console_input_option.php b/cake/console/libs/console_input_option.php index d4d831aa1..56b01d448 100644 --- a/cake/console/libs/console_input_option.php +++ b/cake/console/libs/console_input_option.php @@ -142,7 +142,7 @@ class ConsoleInputOption { return true; } if (!in_array($value, $this->_choices)) { - throw new InvalidArgumentException(sprintf( + throw new ConsoleException(sprintf( __('"%s" is not a valid value for --%s. Please use one of "%s"'), $value, $this->_name, implode(', ', $this->_choices) )); diff --git a/cake/console/libs/console_option_parser.php b/cake/console/libs/console_option_parser.php index 8a9f8af65..5af733e2d 100644 --- a/cake/console/libs/console_option_parser.php +++ b/cake/console/libs/console_option_parser.php @@ -457,7 +457,7 @@ class ConsoleOptionParser { } foreach ($this->_args as $i => $arg) { if ($arg->isRequired() && !isset($args[$i]) && empty($params['help'])) { - throw new RuntimeException( + throw new ConsoleException( __('Missing required arguments. %s is required.', $arg->name()) ); } @@ -552,7 +552,7 @@ class ConsoleOptionParser { */ protected function _parseOption($name, $params) { if (!isset($this->_options[$name])) { - throw new InvalidArgumentException(__('Unknown option `%s`', $name)); + throw new ConsoleException(__('Unknown option `%s`', $name)); } $option = $this->_options[$name]; $isBoolean = $option->isBoolean(); @@ -586,7 +586,7 @@ class ConsoleOptionParser { } $next = count($args); if (!isset($this->_args[$next])) { - throw new InvalidArgumentException(__('Too many arguments.')); + throw new ConsoleException(__('Too many arguments.')); } if ($this->_args[$next]->validChoice($argument)) { diff --git a/cake/console/shell_dispatcher.php b/cake/console/shell_dispatcher.php index a80407613..029a91442 100644 --- a/cake/console/shell_dispatcher.php +++ b/cake/console/shell_dispatcher.php @@ -102,7 +102,7 @@ class ShellDispatcher { protected function _initEnvironment() { if (!$this->__bootstrap()) { $message = "Unable to load CakePHP core.\nMake sure " . DS . 'cake' . DS . 'libs exists in ' . CAKE_CORE_INCLUDE_PATH; - throw new RuntimeException($message); + throw new CakeException($message); } if (!isset($this->args[0]) || !isset($this->params['working'])) { @@ -110,7 +110,7 @@ class ShellDispatcher { "Please make sure that " . DIRECTORY_SEPARATOR . "cake" . DIRECTORY_SEPARATOR . "console is in your system path,\n" . "and check the cookbook for the correct usage of this command.\n" . "(http://book.cakephp.org/)"; - throw new RuntimeException($message); + throw new CakeException($message); } $this->shiftArgs(); diff --git a/cake/libs/cache.php b/cake/libs/cache.php index e211d20f9..17ba3f8d7 100644 --- a/cake/libs/cache.php +++ b/cake/libs/cache.php @@ -67,7 +67,7 @@ class Cache { * @param string $name Name of the configuration * @param array $settings Optional associative array of settings passed to the engine * @return array(engine, settings) on success, false on failure - * @throws Exception + * @throws CacheException */ public static function config($name = null, $settings = array()) { if (is_array($name)) { @@ -113,10 +113,10 @@ class Cache { return false; } $cacheClass = $class . 'Engine'; - self::$_engines[$name] = new $cacheClass(); - if (!self::$_engines[$name] instanceof CacheEngine) { - throw new Exception(__('Cache engines must use CacheEngine as a base class.')); + if (!is_subclass_of($cacheClass, 'CacheEngine')) { + throw new CacheException(__('Cache engines must use CacheEngine as a base class.')); } + self::$_engines[$name] = new $cacheClass(); if (self::$_engines[$name]->init($config)) { if (time() % self::$_engines[$name]->settings['probability'] === 0) { self::$_engines[$name]->gc(); diff --git a/cake/libs/cache/file.php b/cake/libs/cache/file.php index 687a74f72..7560d8113 100644 --- a/cake/libs/cache/file.php +++ b/cake/libs/cache/file.php @@ -249,20 +249,20 @@ class FileEngine extends CacheEngine { * Not implemented * * @return void - * @throws BadMethodCallException + * @throws CacheException */ public function decrement($key, $offset = 1) { - throw new BadMethodCallException(__('Files cannot be atomically decremented.')); + throw new CacheException(__('Files cannot be atomically decremented.')); } /** * Not implemented * * @return void - * @throws BadMethodCallException + * @throws CacheException */ public function increment($key, $offset = 1) { - throw new BadMethodCallException(__('Files cannot be atomically incremented.')); + throw new CacheException(__('Files cannot be atomically incremented.')); } /** diff --git a/cake/libs/cache/memcache.php b/cake/libs/cache/memcache.php index 9b121e89f..d4a1dbfa8 100644 --- a/cake/libs/cache/memcache.php +++ b/cake/libs/cache/memcache.php @@ -148,11 +148,11 @@ class MemcacheEngine extends CacheEngine { * @param integer $offset How much to increment * @param integer $duration How long to cache the data, in seconds * @return New incremented value, false otherwise - * @throws RuntimeException when you try to increment with compress = true + * @throws CacheException when you try to increment with compress = true */ public function increment($key, $offset = 1) { if ($this->settings['compress']) { - throw new RuntimeException( + throw new CacheException( __('Method increment() not implemented for compressed cache in %s', __CLASS__) ); } @@ -166,11 +166,11 @@ class MemcacheEngine extends CacheEngine { * @param integer $offset How much to substract * @param integer $duration How long to cache the data, in seconds * @return New decremented value, false otherwise - * @throws RuntimeException when you try to decrement with compress = true + * @throws CacheException when you try to decrement with compress = true */ public function decrement($key, $offset = 1) { if ($this->settings['compress']) { - throw new RuntimeException( + throw new CacheException( __('Method decrement() not implemented for compressed cache in %s', __CLASS__) ); } diff --git a/cake/libs/cake_log.php b/cake/libs/cake_log.php index 5e8887c65..afc8df033 100644 --- a/cake/libs/cake_log.php +++ b/cake/libs/cake_log.php @@ -97,18 +97,18 @@ class CakeLog { * @param string $key The keyname for this logger, used to remove the logger later. * @param array $config Array of configuration information for the logger * @return boolean success of configuration. - * @throws Exception + * @throws CakeLogException */ public static function config($key, $config) { if (empty($config['engine'])) { - throw new Exception(__('Missing logger classname')); + throw new CakeLogException(__('Missing logger classname')); } $loggerName = $config['engine']; unset($config['engine']); $className = self::_getLogger($loggerName); $logger = new $className($config); if (!$logger instanceof CakeLogInterface) { - throw new Exception(sprintf( + throw new CakeLogException(sprintf( __('logger class %s does not implement a write method.'), $loggerName )); } @@ -134,7 +134,7 @@ class CakeLog { } } if (!class_exists($loggerName)) { - throw new Exception(__('Could not load class %s', $loggerName)); + throw new CakeLogException(__('Could not load class %s', $loggerName)); } return $loggerName; } diff --git a/cake/libs/cake_request.php b/cake/libs/cake_request.php index ec05c55d2..580f51296 100644 --- a/cake/libs/cake_request.php +++ b/cake/libs/cake_request.php @@ -426,7 +426,7 @@ class CakeRequest implements ArrayAccess { $type = strtolower(substr($name, 2)); return $this->is($type); } - throw new BadMethodCallException(sprintf('Method %s does not exist', $name)); + throw new CakeException(__('Method %s does not exist', $name)); } /** diff --git a/cake/libs/cake_response.php b/cake/libs/cake_response.php index d2217efbd..6c3d751c2 100644 --- a/cake/libs/cake_response.php +++ b/cake/libs/cake_response.php @@ -448,13 +448,14 @@ class CakeResponse { * * @param integer $code * @return integer current status code + * @throws CakeException When an unknown status code is reached. */ public function statusCode($code = null) { if (is_null($code)) { return $this->_status; } if (!isset($this->_statusCodes[$code])) { - throw new OutOfRangeException(__('Unknown status code')); + throw new CakeException(__('Unknown status code')); } return $this->_status = $code; } diff --git a/cake/libs/cake_session.php b/cake/libs/cake_session.php index f90b27b3d..c590f2881 100644 --- a/cake/libs/cake_session.php +++ b/cake/libs/cake_session.php @@ -265,7 +265,7 @@ class CakeSession { public static function delete($name) { if (self::check($name)) { if (in_array($name, self::$watchKeys)) { - trigger_error(__('Deleting session key {%s}', $name), E_USER_NOTICE); + throw new CakeSessionException(__('Deleting session key {%s}', $name)); } self::__overwrite($_SESSION, Set::remove($_SESSION, $name)); return (self::check($name) == false); @@ -426,7 +426,6 @@ class CakeSession { */ public static function ignore($var) { if (!in_array($var, self::$watchKeys)) { - debug("NOT"); return; } foreach (self::$watchKeys as $i => $key) { @@ -455,7 +454,7 @@ class CakeSession { } foreach ($write as $key => $val) { if (in_array($key, self::$watchKeys)) { - trigger_error(__('Writing session key {%s}: %s', $key, var_export($val, true)), E_USER_NOTICE); + throw new CakeSessionException(__('Writing session key {%s}: %s', $key, var_export($val, true))); } self::__overwrite($_SESSION, Set::insert($_SESSION, $key, $val)); if (Set::classicExtract($_SESSION, $key) !== $val) { @@ -495,7 +494,7 @@ class CakeSession { * Sessions can be configured with a few shortcut names as well as have any number of ini settings declared. * * @return void - * @throws Exception Throws exceptions when ini_set() fails. + * @throws CakeSessionException Throws exceptions when ini_set() fails. */ protected static function _configureSession() { $sessionConfig = Configure::read('Session'); @@ -527,7 +526,7 @@ class CakeSession { if (!empty($sessionConfig['ini']) && is_array($sessionConfig['ini'])) { foreach ($sessionConfig['ini'] as $setting => $value) { if (ini_set($setting, $value) === false) { - throw new Exception(sprintf( + throw new CakeSessionException(sprintf( __('Unable to configure the session, setting %s failed.'), $setting )); @@ -565,13 +564,13 @@ class CakeSession { App::import('Core', 'session/' . $class); } if (!class_exists($class)) { - throw new Exception(__('Could not load %s to handle the session.', $class)); + throw new CakeSessionException(__('Could not load %s to handle the session.', $class)); } $handler = new $class(); if ($handler instanceof CakeSessionHandlerInterface) { return $handler; } - throw new Exception(__('Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); + throw new CakeSessionException(__('Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); } /** diff --git a/cake/libs/config/php_reader.php b/cake/libs/config/php_reader.php index 169b44df6..1e2734d12 100644 --- a/cake/libs/config/php_reader.php +++ b/cake/libs/config/php_reader.php @@ -51,12 +51,12 @@ class PhpReader implements ConfigReaderInterface { * @param string $key The identifier to read from. If the key has a . it will be treated * as a plugin prefix. * @return array Parsed configuration values. - * @throws RuntimeException when files don't exist or they don't contain `$config`. - * InvalidArgumentException when files contain '..' as this could lead to abusive reads. + * @throws ConfigureException when files don't exist or they don't contain `$config`. + * Or when files contain '..' as this could lead to abusive reads. */ public function read($key) { if (strpos($key, '..') !== false) { - throw new InvalidArgumentException(__('Cannot load configuration files with ../ in them.')); + throw new ConfigureException(__('Cannot load configuration files with ../ in them.')); } list($plugin, $key) = pluginSplit($key); @@ -66,11 +66,11 @@ class PhpReader implements ConfigReaderInterface { $file = $this->_path . $key . '.php'; } if (!file_exists($file)) { - throw new RuntimeException(__('Could not load configuration file: ') . $file); + throw new ConfigureException(__('Could not load configuration file: ') . $file); } include $file; if (!isset($config)) { - throw new RuntimeException( + throw new ConfigureException( sprintf(__('No variable $config found in %s.php'), $file) ); } diff --git a/cake/libs/configure.php b/cake/libs/configure.php index fca858832..ce05b018e 100644 --- a/cake/libs/configure.php +++ b/cake/libs/configure.php @@ -325,7 +325,7 @@ class Configure { * @param string $key name of configuration resource to load. * @param string $config Name of the configured reader to use to read the resource identfied by $key. * @return mixed false if file not found, void if load successful. - * @throws Exception Will throw any exceptions the reader raises. + * @throws ConfigureException Will throw any exceptions the reader raises. */ public static function load($key, $config = 'default') { if (!isset(self::$_readers[$config])) { diff --git a/cake/libs/controller/components/acl.php b/cake/libs/controller/components/acl.php index 3a09c590b..1b7b31486 100644 --- a/cake/libs/controller/components/acl.php +++ b/cake/libs/controller/components/acl.php @@ -58,7 +58,7 @@ class AclComponent extends Component { /** * Constructor. Will return an instance of the correct ACL class as defined in `Configure::read('Acl.classname')` * - * @throws Exception when Acl.classname could not be loaded. + * @throws CakeException when Acl.classname could not be loaded. */ public function __construct(ComponentCollection $collection, $settings = array()) { parent::__construct($collection, $settings); @@ -68,7 +68,7 @@ class AclComponent extends Component { list($plugin, $name) = pluginSplit($name); $name .= 'Component'; } else { - throw new Exception(__('Could not find %s.', $name)); + throw new CakeException(__('Could not find %s.', $name)); } } $this->adapter($name); @@ -84,7 +84,7 @@ class AclComponent extends Component { * * @param mixed $adapter Instance of AclBase or a string name of the class to use. (optional) * @return mixed either null, or instance of AclBase - * @throws Exception when the given class is not an AclBase + * @throws CakeException when the given class is not an AclBase */ public function adapter($adapter = null) { if ($adapter) { @@ -92,7 +92,7 @@ class AclComponent extends Component { $adapter = new $adapter(); } if (!$adapter instanceof AclInterface) { - throw new Exception(__('AclComponent adapters must implement AclInterface')); + throw new CakeException(__('AclComponent adapters must implement AclInterface')); } $this->_Instance = $adapter; $this->_Instance->initialize($this); diff --git a/cake/libs/error/exceptions.php b/cake/libs/error/exceptions.php index 961b39c7d..b6d49061d 100644 --- a/cake/libs/error/exceptions.php +++ b/cake/libs/error/exceptions.php @@ -387,4 +387,62 @@ class MissingTableException extends CakeException { */ class MissingModelException extends CakeException { protected $_messageTemplate = 'Model %s could not be found.'; -} \ No newline at end of file +} + + +/** + * Exception class for Cache. This exception will be thrown from Cache when it + * encounters an error. + * + * @package cake.libs + */ +class CacheException extends CakeException { } + +/** + * Exception class for Router. This exception will be thrown from Router when it + * encounters an error. + * + * @package cake.libs + */ +class RouterException extends CakeException { } + +/** + * Exception class for CakeLog. This exception will be thrown from CakeLog when it + * encounters an error. + * + * @package cake.libs + */ +class CakeLogException extends CakeException { } + +/** + * Exception class for CakeSession. This exception will be thrown from CakeSession when it + * encounters an error. + * + * @package cake.libs + */ +class CakeSessionException extends CakeException { } + +/** + * Exception class for Configure. This exception will be thrown from Configure when it + * encounters an error. + * + * @package cake.libs + */ +class ConfigureException extends CakeException { } + +/** + * Exception class for Xml. This exception will be thrown from Xml when it + * encounters an error. + * + * @package cake.libs + */ +class XmlException extends CakeException { } + +/** + * Exception class for Console libraries. This exception will be thrown from Console library + * classes when they encounter an error. + * + * @package cake.libs + */ +class ConsoleException extends CakeException { } + diff --git a/cake/libs/router.php b/cake/libs/router.php index b51f02134..010511cb2 100644 --- a/cake/libs/router.php +++ b/cake/libs/router.php @@ -226,7 +226,7 @@ class Router { * shifted into the passed arguments. As well as supplying patterns for routing parameters. * @see routes * @return array Array of routes - * @throws Exception + * @throws RouterException */ public static function connect($route, $defaults = array(), $options = array()) { foreach (self::$_prefixes as $prefix) { @@ -246,13 +246,12 @@ class Router { $routeClass = 'CakeRoute'; if (isset($options['routeClass'])) { $routeClass = $options['routeClass']; + if (!is_subclass_of($routeClass, 'CakeRoute')) { + throw new RouterException(__('Route classes must extend CakeRoute')); + } unset($options['routeClass']); } - $Route = new $routeClass($route, $defaults, $options); - if (!$Route instanceof CakeRoute) { - throw new Exception(__('Route classes must extend CakeRoute')); - } - self::$routes[] =& $Route; + self::$routes[] = new $routeClass($route, $defaults, $options); return self::$routes; } diff --git a/cake/libs/view/helpers/form.php b/cake/libs/view/helpers/form.php index e57e12a68..a92b3fd41 100644 --- a/cake/libs/view/helpers/form.php +++ b/cake/libs/view/helpers/form.php @@ -1133,14 +1133,15 @@ class FormHelper extends AppHelper { * The first argument to an input type should always be the fieldname, in `Model.field` format. * The second argument should always be an array of attributes for the input. * - * @param string $method Method name / input type to make. + * @param string $method Method name / input type to make. * @param array $params Parameters for the method call * @return string Formatted input method. + * @throws CakeException When there are no params for the method call. */ public function __call($method, $params) { $options = array(); if (empty($params)) { - throw new Exception(__('Missing field name for FormHelper::%s', $method)); + throw new CakeException(__('Missing field name for FormHelper::%s', $method)); } if (isset($params[1])) { $options = $params[1]; diff --git a/cake/libs/view/helpers/paginator.php b/cake/libs/view/helpers/paginator.php index 5816c6b6a..11b897226 100644 --- a/cake/libs/view/helpers/paginator.php +++ b/cake/libs/view/helpers/paginator.php @@ -87,7 +87,7 @@ class PaginatorHelper extends AppHelper { * * @param View $View the view object the helper is attached to. * @param array $settings Array of settings. - * @return void + * @throws CakeException When the AjaxProvider helper does not implement a link method. */ function __construct(View $View, $settings = array()) { parent::__construct($View, $settings); @@ -99,7 +99,7 @@ class PaginatorHelper extends AppHelper { } $classname = $ajaxProvider . 'Helper'; if (!method_exists($classname, 'link')) { - throw new Exception(sprintf( + throw new CakeException(sprintf( __('%s does not implement a link() method, it is incompatible with PaginatorHelper'), $classname )); } diff --git a/cake/libs/view/view.php b/cake/libs/view/view.php index a3221c761..af035292f 100644 --- a/cake/libs/view/view.php +++ b/cake/libs/view/view.php @@ -385,6 +385,7 @@ class View extends Object { * @param string $layout Layout to use * @param string $file Custom filename for view * @return string Rendered Element + * @throws CakeException if there is an error in the view. */ public function render($action = null, $layout = null, $file = null) { if ($this->hasRendered) { @@ -409,7 +410,7 @@ class View extends Object { $layout = $this->layout; } if ($this->output === false) { - throw new RuntimeException(__("Error in view %s, got no content.", $viewFileName)); + throw new CakeException(__("Error in view %s, got no content.", $viewFileName)); } if ($layout && $this->autoLayout) { $this->output = $this->renderLayout($this->output, $layout); @@ -428,6 +429,7 @@ class View extends Object { * * @param string $content_for_layout Content to render in a view, wrapped by the surrounding layout. * @return mixed Rendered output, or false on error + * @throws CakeException if there is an error in the view. */ public function renderLayout($content_for_layout, $layout = null) { $layoutFileName = $this->_getLayoutFileName($layout); @@ -451,7 +453,7 @@ class View extends Object { $this->output = $this->_render($layoutFileName); if ($this->output === false) { - throw new RuntimeException(__("Error in layout %s, got no content.", $layoutFileName)); + throw new CakeException(__("Error in layout %s, got no content.", $layoutFileName)); } $this->Helpers->trigger('afterLayout', array($layoutFileName)); diff --git a/cake/libs/xml.php b/cake/libs/xml.php index 42097597a..160572b95 100644 --- a/cake/libs/xml.php +++ b/cake/libs/xml.php @@ -73,7 +73,7 @@ class Xml { * @param mixed $input XML string, a path to a file, an URL or an array * @param array $options The options to use * @return object SimpleXMLElement or DOMDocument - * @throws Exception + * @throws XmlException */ public static function build($input, $options = array()) { if (!is_array($options)) { @@ -101,9 +101,9 @@ class Xml { $dom->load($input); return $dom; } elseif (!is_string($input)) { - throw new Exception(__('Invalid input.')); + throw new XmlException(__('Invalid input.')); } - throw new Exception(__('XML cannot be read.')); + throw new XmlException(__('XML cannot be read.')); } /** @@ -141,14 +141,15 @@ class Xml { * @param array $input Array with data * @param array $options The options to use * @return object SimpleXMLElement or DOMDocument + * @throws XmlException */ public static function fromArray($input, $options = array()) { if (!is_array($input) || count($input) !== 1) { - throw new Exception(__('Invalid input.')); + throw new XmlException(__('Invalid input.')); } $key = key($input); if (is_integer($key)) { - throw new Exception(__('The key of input must be alphanumeric')); + throw new XmlException(__('The key of input must be alphanumeric')); } if (!is_array($options)) { @@ -212,7 +213,7 @@ class Xml { } } else { if ($key[0] === '@') { - throw new Exception(__('Invalid array')); + throw new XmlException(__('Invalid array')); } if (array_keys($value) === range(0, count($value) - 1)) { // List foreach ($value as $item) { @@ -225,7 +226,7 @@ class Xml { } } } else { - throw new Exception(__('Invalid array')); + throw new XmlException(__('Invalid array')); } } } @@ -270,13 +271,14 @@ class Xml { * * @param object $obj SimpleXMLElement, DOMDocument or DOMNode instance * @return array Array representation of the XML structure. + * @throws XmlException */ public static function toArray($obj) { if ($obj instanceof DOMNode) { $obj = simplexml_import_dom($obj); } if (!($obj instanceof SimpleXMLElement)) { - throw new Exception(__('The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.')); + throw new XmlException(__('The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.')); } $result = array(); $namespaces = array_merge(array('' => ''), $obj->getNamespaces(true)); diff --git a/cake/tests/cases/console/libs/console_option_parser.test.php b/cake/tests/cases/console/libs/console_option_parser.test.php index 656f3317a..e010bbaf4 100644 --- a/cake/tests/cases/console/libs/console_option_parser.test.php +++ b/cake/tests/cases/console/libs/console_option_parser.test.php @@ -230,7 +230,7 @@ class ConsoleOptionParserTest extends CakeTestCase { /** * test parsing options that do not exist. * - * @expectedException InvalidArgumentException + * @expectedException ConsoleException */ function testOptionThatDoesNotExist() { $parser = new ConsoleOptionParser('test', false); @@ -242,7 +242,7 @@ class ConsoleOptionParserTest extends CakeTestCase { /** * test that options with choices enforce them. * - * @expectedException InvalidArgumentException + * @expectedException ConsoleException * @return void */ function testOptionWithChoices() { @@ -297,7 +297,7 @@ class ConsoleOptionParserTest extends CakeTestCase { /** * test parsing arguments. * - * @expectedException InvalidArgumentException + * @expectedException ConsoleException * @return void */ function testParseArgumentTooMany() { @@ -315,7 +315,7 @@ class ConsoleOptionParserTest extends CakeTestCase { /** * test that when there are not enough arguments an exception is raised * - * @expectedException RuntimeException + * @expectedException ConsoleException * @return void */ function testPositionalArgNotEnough() { @@ -329,7 +329,7 @@ class ConsoleOptionParserTest extends CakeTestCase { /** * test that arguments with choices enforce them. * - * @expectedException InvalidArgumentException + * @expectedException ConsoleException * @return void */ function testPositionalArgWithChoices() { diff --git a/cake/tests/cases/libs/cake_log.test.php b/cake/tests/cases/libs/cake_log.test.php index 52c5c5abc..72fe1e8e8 100644 --- a/cake/tests/cases/libs/cake_log.test.php +++ b/cake/tests/cases/libs/cake_log.test.php @@ -17,7 +17,7 @@ * @since CakePHP(tm) v 1.2.0.5432 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Log'); +App::import('Core', 'CakeLog'); App::import('Core', 'log/FileLog'); /** @@ -70,7 +70,7 @@ class CakeLogTest extends CakeTestCase { /** * test all the errors from failed logger imports * - * @expectedException Exception + * @expectedException CakeLogException * @return void */ function testImportingLoggerFailure() { @@ -80,7 +80,7 @@ class CakeLogTest extends CakeTestCase { /** * test that loggers have to implement the correct interface. * - * @expectedException Exception + * @expectedException CakeLogException * @return void */ function testNotImplementingInterface() { diff --git a/cake/tests/cases/libs/cake_request.test.php b/cake/tests/cases/libs/cake_request.test.php index af4ad93cb..f423ac19d 100644 --- a/cake/tests/cases/libs/cake_request.test.php +++ b/cake/tests/cases/libs/cake_request.test.php @@ -17,9 +17,7 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -if (!class_exists('dispatcher')) { - require CAKE . 'dispatcher.php'; -} +App::import('Core', 'Dispatcher'); App::import('Core', 'CakeRequest'); class CakeRequestTestCase extends CakeTestCase { @@ -614,7 +612,7 @@ class CakeRequestTestCase extends CakeTestCase { /** * test __call expcetions * - * @expectedException Exception + * @expectedException CakeException * @return void */ function test__callExceptionOnUnknownMethod() { diff --git a/cake/tests/cases/libs/cake_response.test.php b/cake/tests/cases/libs/cake_response.test.php index eee0cfc69..d0d2a9e58 100644 --- a/cake/tests/cases/libs/cake_response.test.php +++ b/cake/tests/cases/libs/cake_response.test.php @@ -55,7 +55,7 @@ class CakeResponseTestCase extends CakeTestCase { /** * Tests the statusCode method * -* @expectedException OutOfRangeException +* @expectedException CakeException */ public function testStatusCode() { $response = new CakeResponse(); diff --git a/cake/tests/cases/libs/cake_session.test.php b/cake/tests/cases/libs/cake_session.test.php index 51d37dc14..02fda57e7 100644 --- a/cake/tests/cases/libs/cake_session.test.php +++ b/cake/tests/cases/libs/cake_session.test.php @@ -367,7 +367,7 @@ class CakeSessionTest extends CakeTestCase { /** * testWatchVar method * - * @expectedException Exception + * @expectedException CakeSessionException * @access public * @return void */ @@ -380,16 +380,16 @@ class CakeSessionTest extends CakeTestCase { } /** - * undocumented function + * Test that deleting watched vars causes exceptions * - * @expectedException Exception + * @expectedException CakeSessionException * @return void */ function testWatchVarDelete() { + TestCakeSession::write('Watching', 'I am watching you.'); + TestCakeSession::watch('Watching'); TestCakeSession::delete('Watching'); - - $this->assertFalse(TestCakeSession::watch('Invalid.key')); } /** diff --git a/cake/tests/cases/libs/config/php_reader.test.php b/cake/tests/cases/libs/config/php_reader.test.php index 53898f97f..539f56666 100644 --- a/cake/tests/cases/libs/config/php_reader.test.php +++ b/cake/tests/cases/libs/config/php_reader.test.php @@ -44,7 +44,7 @@ class PhpReaderTest extends CakeTestCase { /** * Test an exception is thrown by reading files that don't exist. * - * @expectedException RuntimeException + * @expectedException ConfigureException * @return void */ function testReadWithNonExistantFile() { @@ -66,7 +66,7 @@ class PhpReaderTest extends CakeTestCase { /** * test reading keys with ../ doesn't work * - * @expectedException InvalidArgumentException + * @expectedException ConfigureException * @return void */ function testReadWithDots() { diff --git a/cake/tests/cases/libs/controller/components/acl.test.php b/cake/tests/cases/libs/controller/components/acl.test.php index 600b69069..544ff44b1 100644 --- a/cake/tests/cases/libs/controller/components/acl.test.php +++ b/cake/tests/cases/libs/controller/components/acl.test.php @@ -218,7 +218,7 @@ class AclComponentTest extends CakeTestCase { * test that construtor throws an exception when Acl.classname is a * non-existant class * - * @expectedException Exception + * @expectedException CakeException * @return void */ function testConstrutorException() { @@ -243,7 +243,7 @@ class AclComponentTest extends CakeTestCase { /** * test that adapter() whines when the class is not an AclBase * - * @expectedException Exception + * @expectedException CakeException * @return void */ function testAdapterException() { diff --git a/cake/tests/cases/libs/view/helpers/form.test.php b/cake/tests/cases/libs/view/helpers/form.test.php index a5a37bb7e..143570711 100644 --- a/cake/tests/cases/libs/view/helpers/form.test.php +++ b/cake/tests/cases/libs/view/helpers/form.test.php @@ -6700,7 +6700,7 @@ class FormHelperTest extends CakeTestCase { /** * - * @expectedException Exception + * @expectedException CakeException * @return void */ function testHtml5InputException() { From daffe3adb27260c2e8b80d09ecc184c219d2fe99 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 12:37:02 -0500 Subject: [PATCH 072/125] Making baked code throw 404 errors when you try to edit, delete, or view records that do not exist. Updated tests. --- .../default/actions/controller_actions.ctp | 35 ++++++------------- .../console/shells/tasks/controller.test.php | 8 ++--- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/cake/console/templates/default/actions/controller_actions.ctp b/cake/console/templates/default/actions/controller_actions.ctp index 370879e66..b02ad7647 100644 --- a/cake/console/templates/default/actions/controller_actions.ctp +++ b/cake/console/templates/default/actions/controller_actions.ctp @@ -25,13 +25,9 @@ } public function view($id = null) { - if (!$id) { - - $this->Session->setFlash(__('Invalid ')); - $this->redirect(array('action' => 'index')); - - $this->flash(__('Invalid '), array('action' => 'index')); - + $this->->id = $id; + if (!$this->->exists()) { + throw new NotFoundException(__('Invalid ')); } $this->set('', $this->->read(null, $id)); } @@ -72,13 +68,9 @@ public function edit($id = null) { - if (!$id && empty($this->request->data)) { - - $this->Session->setFlash(__('Invalid ')); - $this->redirect(array('action' => 'index')); - - $this->flash(__('Invalid '), array('action' => 'index')); - + $this->->id = $id; + if (!$this->->exists()) { + throw new NotFoundException(__('Invalid ')); } if ($this->request->is('post')) { if ($this->->save($this->request->data)) { @@ -93,8 +85,7 @@ $this->Session->setFlash(__('The could not be saved. Please, try again.')); } - } - if (!$this->request->is('post')) { + } else { $this->data = $this->->read(null, $id); } request->is('post')) { throw new MethodNotAllowedException(); } - if (!$id) { - - $this->Session->setFlash(__('Invalid id for ')); - $this->redirect(array('action'=>'index')); - - $this->flash(__('Invalid '), array('action' => 'index')); - + $this->->id = $id; + if (!$this->->exists()) { + throw new NotFoundException(__('Invalid ')); } - if ($this->->delete($id)) { + if ($this->->delete()) { $this->Session->setFlash(__(' deleted')); $this->redirect(array('action'=>'index')); diff --git a/cake/tests/cases/console/shells/tasks/controller.test.php b/cake/tests/cases/console/shells/tasks/controller.test.php index f3601376e..86ff8fb77 100644 --- a/cake/tests/cases/console/shells/tasks/controller.test.php +++ b/cake/tests/cases/console/shells/tasks/controller.test.php @@ -340,7 +340,7 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set('bakeArticles', \$this->paginate());", $result); $this->assertContains('function view($id = null)', $result); - $this->assertContains("\$this->Session->setFlash(__('Invalid bake article'));", $result); + $this->assertContains("throw new NotFoundException(__('Invalid bake article'));", $result); $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result); $this->assertContains('function add()', $result); @@ -352,7 +352,7 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->Session->setFlash(__('The bake article could not be saved. Please, try again.'));", $result); $this->assertContains('function delete($id = null)', $result); - $this->assertContains('if ($this->BakeArticle->delete($id))', $result); + $this->assertContains('if ($this->BakeArticle->delete())', $result); $this->assertContains("\$this->Session->setFlash(__('Bake article deleted'));", $result); $result = $this->Task->bakeActions('BakeArticles', 'admin_', true); @@ -382,7 +382,7 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set('bakeArticles', \$this->paginate());", $result); $this->assertContains('function view($id = null)', $result); - $this->assertContains("\$this->flash(__('Invalid bake article'), array('action' => 'index'))", $result); + $this->assertContains("throw new NotFoundException(__('Invalid bake article'));", $result); $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result); $this->assertContains('function add()', $result); @@ -396,7 +396,7 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set(compact('bakeTags'))", $result); $this->assertContains('function delete($id = null)', $result); - $this->assertContains('if ($this->BakeArticle->delete($id))', $result); + $this->assertContains('if ($this->BakeArticle->delete())', $result); $this->assertContains("\$this->flash(__('Bake article deleted'), array('action' => 'index'))", $result); } From 661195db6ca6944f1013c2c7682b7977437e0482 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 12:44:48 -0500 Subject: [PATCH 073/125] Updating __() use in scaffold to take advantage of sprintf() being built into __() now. --- cake/libs/controller/scaffold.php | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/cake/libs/controller/scaffold.php b/cake/libs/controller/scaffold.php index 34eb22c6d..68883be52 100644 --- a/cake/libs/controller/scaffold.php +++ b/cake/libs/controller/scaffold.php @@ -173,7 +173,7 @@ class Scaffold { protected function _scaffoldView(CakeRequest $request) { if ($this->controller->_beforeScaffold('view')) { - $message = __(sprintf("No id set for %s::view()", Inflector::humanize($this->modelKey))); + $message = __("No id set for %s::view()", Inflector::humanize($this->modelKey)); if (isset($request->params['pass'][0])) { $this->ScaffoldModel->id = $request->params['pass'][0]; } else { @@ -247,7 +247,7 @@ class Scaffold { } if (!$this->ScaffoldModel->exists()) { - $message = sprintf(__("Invalid id for %s::edit()", true), Inflector::humanize($this->modelKey)); + $message = __("Invalid id for %s::edit()", Inflector::humanize($this->modelKey)); return $this->_sendMessage($message); } } @@ -259,8 +259,8 @@ class Scaffold { if ($this->ScaffoldModel->save($request->data)) { if ($this->controller->_afterScaffoldSave($action)) { - $message = sprintf( - __('The %1$s has been %2$s'), + $message = __( + 'The %1$s has been %2$s', Inflector::humanize($this->modelKey), $success ); @@ -308,10 +308,7 @@ class Scaffold { */ protected function _scaffoldDelete(CakeRequest $request) { if ($this->controller->_beforeScaffold('delete')) { - $message = sprintf( - __("No id set for %s::delete()", true), - Inflector::humanize($this->modelKey) - ); + $message = __("No id set for %s::delete()", Inflector::humanize($this->modelKey)); if (isset($request->params['pass'][0])) { $id = $request->params['pass'][0]; } else { @@ -319,15 +316,13 @@ class Scaffold { } if ($this->ScaffoldModel->delete($id)) { - $message = sprintf( - __('The %1$s with id: %2$d has been deleted.', true), - Inflector::humanize($this->modelClass), $id - ); + $message = __('The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id); return $this->_sendMessage($message); } else { - $message = sprintf( - __('There was an error deleting the %1$s with id: %2$d', true), - Inflector::humanize($this->modelClass), $id + $message = __( + 'There was an error deleting the %1$s with id: %2$d', + Inflector::humanize($this->modelClass), + $id ); return $this->_sendMessage($message); } From 495061537fd1e776fe3436f89ba28a87004130e4 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 12:59:25 -0500 Subject: [PATCH 074/125] Changing Scaffold to use exceptions to indicate error states. Starting to convert record deletion to POST only. --- cake/libs/controller/scaffold.php | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cake/libs/controller/scaffold.php b/cake/libs/controller/scaffold.php index 68883be52..c58fba7d1 100644 --- a/cake/libs/controller/scaffold.php +++ b/cake/libs/controller/scaffold.php @@ -172,15 +172,14 @@ class Scaffold { */ protected function _scaffoldView(CakeRequest $request) { if ($this->controller->_beforeScaffold('view')) { - - $message = __("No id set for %s::view()", Inflector::humanize($this->modelKey)); if (isset($request->params['pass'][0])) { $this->ScaffoldModel->id = $request->params['pass'][0]; - } else { - return $this->_sendMessage($message); + } + if (!$this->ScaffoldModel->exists()) { + throw new NotFoundException(__('Invalid %s', Inflector::humanize($this->modelKey))); } $this->ScaffoldModel->recursive = 1; - $this->controller->request->data = $this->controller->data = $this->ScaffoldModel->read(); + $this->controller->request->data = $this->ScaffoldModel->read(); $this->controller->set( Inflector::variable($this->controller->modelClass), $this->request->data ); @@ -245,10 +244,8 @@ class Scaffold { if (isset($request->params['pass'][0])) { $this->ScaffoldModel->id = $request['pass'][0]; } - if (!$this->ScaffoldModel->exists()) { - $message = __("Invalid id for %s::edit()", Inflector::humanize($this->modelKey)); - return $this->_sendMessage($message); + throw new NotFoundException(__('Invalid %s', Inflector::humanize($this->modelKey))); } } @@ -308,14 +305,18 @@ class Scaffold { */ protected function _scaffoldDelete(CakeRequest $request) { if ($this->controller->_beforeScaffold('delete')) { - $message = __("No id set for %s::delete()", Inflector::humanize($this->modelKey)); + if (!$request->is('post')) { + throw new MethodNotAllowedException(); + } + $id = false; if (isset($request->params['pass'][0])) { $id = $request->params['pass'][0]; - } else { - return $this->_sendMessage($message); } - - if ($this->ScaffoldModel->delete($id)) { + $this->ScaffoldModel->id = $id; + if (!$this->ScaffoldModel->exists()) { + throw new NotFoundException(__('Invalid %s', Inflector::humanize($this->modelClass))); + } + if ($this->ScaffoldModel->delete()) { $message = __('The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id); return $this->_sendMessage($message); } else { From 11df32148f9d0cd7f620b9ee829eea8373e37558 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 13:13:00 -0500 Subject: [PATCH 075/125] Updating scaffold templates to use post forms for delete buttons. Updating test case. --- cake/libs/view/scaffolds/edit.ctp | 11 ++++-- cake/libs/view/scaffolds/index.ctp | 36 ++++++++++--------- .../cases/libs/controller/scaffold.test.php | 2 +- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/cake/libs/view/scaffolds/edit.ctp b/cake/libs/view/scaffolds/edit.ctp index 3e59682b5..7fb2c4c8b 100644 --- a/cake/libs/view/scaffolds/edit.ctp +++ b/cake/libs/view/scaffolds/edit.ctp @@ -27,10 +27,15 @@

    -action != 'add'):?> -
  • Html->link(__('Delete'), array('action' => 'delete', $this->Form->value($modelClass.'.'.$primaryKey)), null, __('Are you sure you want to delete').' #' . $this->Form->value($modelClass.'.'.$primaryKey)); ?>
  • +request->action != 'add'): ?> +
  • Form->postLink( + __('Delete'), + array('action' => 'delete', $this->Form->value($modelClass . '.' . $primaryKey)), + null, + __('Are you sure you want to delete # %s?', $this->Form->value($modelClass . '.' . $primaryKey))); + ?>
  • -
  • Html->link(__('List').' '.$pluralHumanName, array('action' => 'index'));?>
  • +
  • Html->link(__('List') . ' ' . $pluralHumanName, array('action' => 'index'));?>
  • $_data) { diff --git a/cake/libs/view/scaffolds/index.ctp b/cake/libs/view/scaffolds/index.ctp index 7a4f49aef..d92b88320 100644 --- a/cake/libs/view/scaffolds/index.ctp +++ b/cake/libs/view/scaffolds/index.ctp @@ -33,33 +33,37 @@ foreach (${$pluralVar} as ${$singularVar}): if ($i++ % 2 == 0) { $class = ' class="altrow"'; } -echo "\n"; - echo "\t\n"; + echo ""; foreach ($scaffoldFields as $_field) { $isKey = false; if (!empty($associations['belongsTo'])) { foreach ($associations['belongsTo'] as $_alias => $_details) { if ($_field === $_details['foreignKey']) { $isKey = true; - echo "\t\t\n\t\t\t" . $this->Html->link(${$singularVar}[$_alias][$_details['displayField']], array('controller' => $_details['controller'], 'action' => 'view', ${$singularVar}[$_alias][$_details['primaryKey']])) . "\n\t\t\n"; + echo "" . $this->Html->link(${$singularVar}[$_alias][$_details['displayField']], array('controller' => $_details['controller'], 'action' => 'view', ${$singularVar}[$_alias][$_details['primaryKey']])) . ""; break; } } } if ($isKey !== true) { - echo "\t\t" . h(${$singularVar}[$modelClass][$_field]) . "\n"; + echo "" . h(${$singularVar}[$modelClass][$_field]) . ""; } } - echo "\t\t\n"; - echo "\t\t\t" . $this->Html->link(__('View'), array('action' => 'view', ${$singularVar}[$modelClass][$primaryKey])) . "\n"; - echo "\t\t\t" . $this->Html->link(__('Edit'), array('action' => 'edit', ${$singularVar}[$modelClass][$primaryKey])) . "\n"; - echo "\t\t\t" . $this->Html->link(__('Delete'), array('action' => 'delete', ${$singularVar}[$modelClass][$primaryKey]), null, __('Are you sure you want to delete').' #' . ${$singularVar}[$modelClass][$primaryKey]) . "\n"; - echo "\t\t\n"; - echo "\t\n"; + echo ''; + echo $this->Html->link(__('View'), array('action' => 'view', ${$singularVar}[$modelClass][$primaryKey])); + echo $this->Html->link(__('Edit'), array('action' => 'edit', ${$singularVar}[$modelClass][$primaryKey])); + echo $this->Form->postLink( + __('Delete'), + array('action' => 'delete', ${$singularVar}[$modelClass][$primaryKey]), + null, + __('Are you sure you want to delete').' #' . ${$singularVar}[$modelClass][$primaryKey] + ); + echo ''; + echo ''; endforeach; -echo "\n"; + ?>

    - Paginator->prev('<< ' . __('previous'), array(), null, array('class' => 'disabled')) . "\n";?> - | Paginator->numbers() . "\n"?> - Paginator->next(__('next') .' >>', array(), null, array('class' => 'disabled')) . "\n";?> + Paginator->prev('<< ' . __('previous'), array(), null, array('class' => 'disabled')); ?> + | Paginator->numbers(); ?> + Paginator->next(__('next') .' >>', array(), null, array('class' => 'disabled')); ?>
@@ -82,8 +86,8 @@ echo "\n"; foreach ($associations as $_type => $_data) { foreach ($_data as $_alias => $_details) { if ($_details['controller'] != $this->name && !in_array($_details['controller'], $done)) { - echo "\t\t
  • " . $this->Html->link(__('List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' => 'index')) . "
  • \n"; - echo "\t\t
  • " . $this->Html->link(__('New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' => 'add')) . "
  • \n"; + echo "
  • " . $this->Html->link(__('List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' => 'index')) . "
  • "; + echo "
  • " . $this->Html->link(__('New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' => 'add')) . "
  • "; $done[] = $_details['controller']; } } diff --git a/cake/tests/cases/libs/controller/scaffold.test.php b/cake/tests/cases/libs/controller/scaffold.test.php index 2ebd3f5e3..17e755047 100644 --- a/cake/tests/cases/libs/controller/scaffold.test.php +++ b/cake/tests/cases/libs/controller/scaffold.test.php @@ -524,7 +524,7 @@ class ScaffoldViewTest extends CakeTestCase { $this->assertContains('input name="data[ScaffoldMock][title]" maxlength="255" type="text" value="First Article" id="ScaffoldMockTitle"', $result); $this->assertContains('input name="data[ScaffoldMock][published]" maxlength="1" type="text" value="Y" id="ScaffoldMockPublished"', $result); $this->assertContains('textarea name="data[ScaffoldMock][body]" cols="30" rows="6" id="ScaffoldMockBody"', $result); - $this->assertPattern('/
  • ]*>Delete<\/a>\s*<\/li>/', $result); + $this->assertPattern('/useDbConfig); if (!$db->connected) { trigger_error( @@ -73,7 +73,7 @@ class TranslateBehavior extends ModelBehavior { * @param Model $model Model being detached. * @return void */ - public function cleanup(&$model) { + public function cleanup($model) { $this->unbindTranslation($model); unset($this->settings[$model->alias]); unset($this->runtime[$model->alias]); @@ -86,7 +86,7 @@ class TranslateBehavior extends ModelBehavior { * @param array $query Array of Query parameters. * @return array Modified query */ - public function beforeFind(&$model, $query) { + public function beforeFind($model, $query) { $this->runtime[$model->alias]['virtualFields'] = $model->virtualFields; $locale = $this->_getLocale($model); if (empty($locale)) { @@ -196,7 +196,7 @@ class TranslateBehavior extends ModelBehavior { * @param boolean $primary Did the find originate on $model. * @return array Modified results */ - public function afterFind(&$model, $results, $primary) { + public function afterFind($model, $results, $primary) { $model->virtualFields = $this->runtime[$model->alias]['virtualFields']; $this->runtime[$model->alias]['virtualFields'] = $this->runtime[$model->alias]['fields'] = array(); $locale = $this->_getLocale($model); @@ -242,7 +242,7 @@ class TranslateBehavior extends ModelBehavior { * @param Model $model Model invalidFields was called on. * @return boolean */ - public function beforeValidate(&$model) { + public function beforeValidate($model) { $locale = $this->_getLocale($model); if (empty($locale)) { return true; @@ -276,7 +276,7 @@ class TranslateBehavior extends ModelBehavior { * @param boolean $created Whether or not the save created a record. * @return void */ - public function afterSave(&$model, $created) { + public function afterSave($model, $created) { if (!isset($this->runtime[$model->alias]['beforeSave'])) { return true; } @@ -284,7 +284,7 @@ class TranslateBehavior extends ModelBehavior { $tempData = $this->runtime[$model->alias]['beforeSave']; unset($this->runtime[$model->alias]['beforeSave']); $conditions = array('model' => $model->alias, 'foreign_key' => $model->id); - $RuntimeModel =& $this->translateModel($model); + $RuntimeModel = $this->translateModel($model); foreach ($tempData as $field => $value) { unset($conditions['content']); @@ -319,8 +319,8 @@ class TranslateBehavior extends ModelBehavior { * @param Model $model Model the callback was run on. * @return void */ - public function afterDelete(&$model) { - $RuntimeModel =& $this->translateModel($model); + public function afterDelete($model) { + $RuntimeModel = $this->translateModel($model); $conditions = array('model' => $model->alias, 'foreign_key' => $model->id); $RuntimeModel->deleteAll($conditions); } @@ -331,12 +331,12 @@ class TranslateBehavior extends ModelBehavior { * @param Model $model Model the locale needs to be set/get on. * @return mixed string or false */ - protected function _getLocale(&$model) { + protected function _getLocale($model) { if (!isset($model->locale) || is_null($model->locale)) { if (!class_exists('I18n')) { App::import('Core', 'i18n'); } - $I18n =& I18n::getInstance(); + $I18n = I18n::getInstance(); $I18n->l10n->get(Configure::read('Config.language')); $model->locale = $I18n->l10n->locale; } @@ -353,7 +353,7 @@ class TranslateBehavior extends ModelBehavior { * @param Model $model Model to get a translatemodel for. * @return object */ - public function &translateModel(&$model) { + public function translateModel($model) { if (!isset($this->runtime[$model->alias]['model'])) { if (!isset($model->translateModel) || empty($model->translateModel)) { $className = 'I18nModel'; @@ -380,12 +380,12 @@ class TranslateBehavior extends ModelBehavior { * @param boolean $reset * @return bool */ - function bindTranslation(&$model, $fields, $reset = true) { + function bindTranslation($model, $fields, $reset = true) { if (is_string($fields)) { $fields = array($fields); } $associations = array(); - $RuntimeModel =& $this->translateModel($model); + $RuntimeModel = $this->translateModel($model); $default = array('className' => $RuntimeModel->alias, 'foreignKey' => 'foreign_key'); foreach ($fields as $key => $value) { @@ -453,7 +453,7 @@ class TranslateBehavior extends ModelBehavior { * unbind all original translations * @return bool */ - function unbindTranslation(&$model, $fields = null) { + function unbindTranslation($model, $fields = null) { if (empty($fields) && empty($this->settings[$model->alias])) { return false; } @@ -464,7 +464,7 @@ class TranslateBehavior extends ModelBehavior { if (is_string($fields)) { $fields = array($fields); } - $RuntimeModel =& $this->translateModel($model); + $RuntimeModel = $this->translateModel($model); $associations = array(); foreach ($fields as $key => $value) { @@ -499,15 +499,13 @@ class TranslateBehavior extends ModelBehavior { return true; } } -if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) { /** * @package cake * @subpackage cake.cake.libs.model.behaviors */ - class I18nModel extends AppModel { - public $name = 'I18nModel'; - public $useTable = 'i18n'; - public $displayField = 'field'; - } +class I18nModel extends AppModel { + public $name = 'I18nModel'; + public $useTable = 'i18n'; + public $displayField = 'field'; } diff --git a/cake/tests/cases/libs/model/models.php b/cake/tests/cases/libs/model/models.php index 33a566edf..b116962b0 100644 --- a/cake/tests/cases/libs/model/models.php +++ b/cake/tests/cases/libs/model/models.php @@ -2591,38 +2591,6 @@ class MyCategoriesMyProduct extends CakeTestModel { public $name = 'MyCategoriesMyProduct'; } -/** - * I18nModel class - * - * @package cake - * @subpackage cake.tests.cases.libs.model - */ -class I18nModel extends CakeTestModel { - -/** - * name property - * - * @var string 'I18nModel' - * @access public - */ - public $name = 'I18nModel'; - -/** - * useTable property - * - * @var string 'i18n' - * @access public - */ - public $useTable = 'i18n'; - -/** - * displayField property - * - * @var string 'field' - * @access public - */ - public $displayField = 'field'; -} /** * NumberTree class @@ -2662,7 +2630,7 @@ class NumberTree extends CakeTestModel { */ function initialize($levelLimit = 3, $childLimit = 3, $currentLevel = null, $parent_id = null, $prefix = '1', $hierachial = true) { if (!$parent_id) { - $db =& ConnectionManager::getDataSource($this->useDbConfig); + $db = ConnectionManager::getDataSource($this->useDbConfig); $db->truncate($this->table); $this->save(array($this->name => array('name' => '1. Root'))); $this->initialize($levelLimit, $childLimit, 1, $this->id, '1', $hierachial); From 3c69d9b13841610bc10be707224c10244a02d1f8 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 17:40:13 -0500 Subject: [PATCH 086/125] Making ModelBehavior beforeX callbacks default to returning true. Returning null or false from a Behavior::before method will abort the operation. It felt illogical to have null continue, but false stop. --- cake/libs/model/model.php | 10 +++++----- cake/libs/model/model_behavior.php | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/cake/libs/model/model.php b/cake/libs/model/model.php index 7f757a79c..7c8b5f2e6 100644 --- a/cake/libs/model/model.php +++ b/cake/libs/model/model.php @@ -1322,7 +1322,7 @@ class Model extends Object { if ($options['callbacks'] === true || $options['callbacks'] === 'before') { $result = $this->Behaviors->trigger('beforeSave', array(&$this, $options), array( - 'break' => true, 'breakOn' => false + 'break' => true, 'breakOn' => array(false, null) )); if (!$result || !$this->beforeSave($options)) { $this->whitelist = $_whitelist; @@ -1854,7 +1854,7 @@ class Model extends Object { $filters = $this->Behaviors->trigger( 'beforeDelete', array(&$this, $cascade), - array('break' => true, 'breakOn' => false) + array('break' => true, 'breakOn' => array(false, null)) ); if (!$filters || !$this->exists()) { return false; @@ -1876,7 +1876,7 @@ class Model extends Object { if (!empty($this->belongsTo)) { $this->updateCounterCache($keys[$this->alias]); } - $this->Behaviors->trigger($this, 'afterDelete'); + $this->Behaviors->trigger('afterDelete', array(&$this)); $this->afterDelete(); $this->_clearCache(); $this->id = false; @@ -2142,8 +2142,8 @@ class Model extends Object { if ($query['callbacks'] === true || $query['callbacks'] === 'before') { $return = $this->Behaviors->trigger( 'beforeFind', - array(&$this, $query), - array('break' => true, 'breakOn' => false, 'modParams' => 1) + array(&$this, $query), + array('break' => true, 'breakOn' => array(false, null), 'modParams' => 1) ); $query = (is_array($return)) ? $return : $query; diff --git a/cake/libs/model/model_behavior.php b/cake/libs/model/model_behavior.php index 192b21b72..46ad69165 100644 --- a/cake/libs/model/model_behavior.php +++ b/cake/libs/model/model_behavior.php @@ -80,7 +80,7 @@ class ModelBehavior extends Object { * * @param object $model Model using this behavior * @param array $queryData Data used to execute this query, i.e. conditions, order, etc. - * @return mixed False if the operation should abort. An array will replace the value of $query. + * @return mixed False or null will abort the operation. You should array will replace the value of $query. * @access public */ public function beforeFind($model, $query) { } @@ -100,10 +100,12 @@ class ModelBehavior extends Object { * Before validate callback * * @param object $model Model using this behavior - * @return mixed False if the operation should abort. Any other result will continue. + * @return mixed False or null will abort the operation. Any other result will continue. * @access public */ - public function beforeValidate($model) { } + public function beforeValidate($model) { + return true; + } /** * Before save callback @@ -112,7 +114,9 @@ class ModelBehavior extends Object { * @return mixed False if the operation should abort. Any other result will continue. * @access public */ - public function beforeSave($model) { } + public function beforeSave($model) { + return true; + } /** * After save callback @@ -120,7 +124,9 @@ class ModelBehavior extends Object { * @param object $model Model using this behavior * @param boolean $created True if this save created a new record */ - public function afterSave($model, $created) { } + public function afterSave($model, $created) { + return true; + } /** * Before delete callback @@ -130,7 +136,9 @@ class ModelBehavior extends Object { * @return mixed False if the operation should abort. Any other result will continue. * @access public */ - public function beforeDelete($model, $cascade = true) { } + public function beforeDelete($model, $cascade = true) { + return true; + } /** * After delete callback From ce2e6053e4eda2b95ba95bc126ac5a0bae7181a0 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 17:40:41 -0500 Subject: [PATCH 087/125] Adding containable to the AllBehaviors test as it now runs. --- cake/tests/cases/libs/all_behaviors.test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/tests/cases/libs/all_behaviors.test.php b/cake/tests/cases/libs/all_behaviors.test.php index 625e4065a..b27a1cfe4 100644 --- a/cake/tests/cases/libs/all_behaviors.test.php +++ b/cake/tests/cases/libs/all_behaviors.test.php @@ -39,7 +39,7 @@ class AllBehaviorsTest extends PHPUnit_Framework_TestSuite { $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'model' . DS . 'behavior_collection.test.php'); $suite->addTestFile($path . 'acl.test.php'); - // $suite->addTestFile($path . 'containable.test.php'); + $suite->addTestFile($path . 'containable.test.php'); $suite->addTestFile($path . 'translate.test.php'); $suite->addTestFile($path . 'tree.test.php'); return $suite; From bf22af6b7f9a463043dd1b51534e3641f0a492ab Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 17:41:57 -0500 Subject: [PATCH 088/125] Fixing more strict errors and usage errors in BehaviorCollection test. Making modParams only work if the result is an array. This is for compatibility with previous behaviour. --- cake/libs/object_collection.php | 7 +-- .../libs/model/behavior_collection.test.php | 59 ++++++++----------- .../cases/libs/object_collection.test.php | 2 +- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/cake/libs/object_collection.php b/cake/libs/object_collection.php index 831dd555b..d91f62cc9 100644 --- a/cake/libs/object_collection.php +++ b/cake/libs/object_collection.php @@ -107,18 +107,17 @@ abstract class ObjectCollection { if ($options['modParams'] !== false && !isset($params[$options['modParams']])) { throw new CakeException(__('Cannot use modParams with indexes that do not exist.')); } - foreach ($list as $name) { $result = call_user_func_array(array($this->_loaded[$name], $callback), $params); if ($options['collectReturn'] === true) { $collected[] = $result; } if ( - $options['break'] && ($result === $options['breakOn'] || + $options['break'] && ($result === $options['breakOn'] || (is_array($options['breakOn']) && in_array($result, $options['breakOn'], true))) ) { - break; - } elseif ($options['modParams'] !== false && $result !== null) { + return $result; + } elseif ($options['modParams'] !== false && is_array($result)) { $params[$options['modParams']] = $result; } } diff --git a/cake/tests/cases/libs/model/behavior_collection.test.php b/cake/tests/cases/libs/model/behavior_collection.test.php index 12ce1dd4f..27c71e2f9 100644 --- a/cake/tests/cases/libs/model/behavior_collection.test.php +++ b/cake/tests/cases/libs/model/behavior_collection.test.php @@ -46,7 +46,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function setup(&$model, $config = array()) { + function setup($model, $config = array()) { parent::setup($model, $config); if (isset($config['mangle'])) { $config['mangle'] .= ' mangled'; @@ -62,7 +62,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function beforeFind(&$model, $query) { + function beforeFind($model, $query) { $settings = $this->settings[$model->alias]; if (!isset($settings['beforeFind']) || $settings['beforeFind'] == 'off') { return parent::beforeFind($model, $query); @@ -91,7 +91,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function afterFind(&$model, $results, $primary) { + function afterFind($model, $results, $primary) { $settings = $this->settings[$model->alias]; if (!isset($settings['afterFind']) || $settings['afterFind'] == 'off') { return parent::afterFind($model, $results, $primary); @@ -119,7 +119,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function beforeSave(&$model) { + function beforeSave($model) { $settings = $this->settings[$model->alias]; if (!isset($settings['beforeSave']) || $settings['beforeSave'] == 'off') { return parent::beforeSave($model); @@ -129,7 +129,7 @@ class TestBehavior extends ModelBehavior { return false; break; case 'test': - return null; + return true; break; case 'modify': $model->data[$model->alias]['name'] .= ' modified before'; @@ -146,7 +146,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function afterSave(&$model, $created) { + function afterSave($model, $created) { $settings = $this->settings[$model->alias]; if (!isset($settings['afterSave']) || $settings['afterSave'] == 'off') { return parent::afterSave($model, $created); @@ -178,7 +178,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function beforeValidate(&$model) { + function beforeValidate($model) { $settings = $this->settings[$model->alias]; if (!isset($settings['validate']) || $settings['validate'] == 'off') { return parent::beforeValidate($model); @@ -210,7 +210,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function beforeDelete(&$model, $cascade = true) { + function beforeDelete($model, $cascade = true) { $settings = $this->settings[$model->alias]; if (!isset($settings['beforeDelete']) || $settings['beforeDelete'] == 'off') { return parent::beforeDelete($model, $cascade); @@ -227,6 +227,7 @@ class TestBehavior extends ModelBehavior { if ($cascade) { echo ' (cascading) '; } + return true; break; } } @@ -238,7 +239,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function afterDelete(&$model) { + function afterDelete($model) { $settings = $this->settings[$model->alias]; if (!isset($settings['afterDelete']) || $settings['afterDelete'] == 'off') { return parent::afterDelete($model); @@ -257,10 +258,10 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function onError(&$model) { + function onError($model, $error) { $settings = $this->settings[$model->alias]; if (!isset($settings['onError']) || $settings['onError'] == 'off') { - return parent::onError($model, $cascade); + return parent::onError($model, $error); } echo "onError trigger success"; } @@ -271,7 +272,7 @@ class TestBehavior extends ModelBehavior { * @access public * @return void */ - function beforeTest(&$model) { + function beforeTest($model) { if (!isset($model->beforeTestResult)) { $model->beforeTestResult = array(); } @@ -361,7 +362,7 @@ class Test3Behavior extends TestBehavior{ * @subpackage cake.tests.cases.libs.model */ class Test4Behavior extends ModelBehavior{ - function setup(&$model, $config = null) { + function setup($model, $config = null) { $model->bindModel( array('hasMany' => array('Comment')) ); @@ -375,7 +376,7 @@ class Test4Behavior extends ModelBehavior{ * @subpackage cake.tests.cases.libs.model */ class Test5Behavior extends ModelBehavior{ - function setup(&$model, $config = null) { + function setup($model, $config = null) { $model->bindModel( array('belongsTo' => array('User')) ); @@ -389,7 +390,7 @@ class Test5Behavior extends ModelBehavior{ * @subpackage cake.tests.cases.libs.model */ class Test6Behavior extends ModelBehavior{ - function setup(&$model, $config = null) { + function setup($model, $config = null) { $model->bindModel( array('hasAndBelongsToMany' => array('Tag')) ); @@ -403,7 +404,7 @@ class Test6Behavior extends ModelBehavior{ * @subpackage cake.tests.cases.libs.model */ class Test7Behavior extends ModelBehavior{ - function setup(&$model, $config = null) { + function setup($model, $config = null) { $model->bindModel( array('hasOne' => array('Attachment')) ); @@ -429,16 +430,6 @@ class BehaviorCollectionTest extends CakeTestCase { 'core.attachment', 'core.tag', 'core.articles_tag' ); -/** - * tearDown method - * - * @access public - * @return void - */ - function endTest() { - ClassRegistry::flush(); - } - /** * testBehaviorBinding method * @@ -937,7 +928,8 @@ class BehaviorCollectionTest extends CakeTestCase { $this->assertIdentical(trim(ob_get_clean()), 'afterDelete success'); $this->assertIdentical($results, true); } - /** + +/** * testBehaviorOnErrorCallback method * * @access public @@ -948,10 +940,11 @@ class BehaviorCollectionTest extends CakeTestCase { $Apple->Behaviors->attach('Test', array('beforeFind' => 'off', 'onError' => 'on')); ob_start(); - $Apple->Behaviors->Test->onError($Apple); + $Apple->Behaviors->Test->onError($Apple, ''); $this->assertIdentical(trim(ob_get_clean()), 'onError trigger success'); } - /** + +/** * testBehaviorValidateCallback method * * @access public @@ -1055,17 +1048,17 @@ class BehaviorCollectionTest extends CakeTestCase { $Apple->Behaviors->attach('Test3'); $Apple->beforeTestResult = array(); - $Apple->Behaviors->trigger($Apple, 'beforeTest'); + $Apple->Behaviors->trigger('beforeTest', array(&$Apple)); $expected = array('testbehavior', 'test2behavior', 'test3behavior'); $this->assertIdentical($Apple->beforeTestResult, $expected); $Apple->beforeTestResult = array(); - $Apple->Behaviors->trigger($Apple, 'beforeTest', array(), array('break' => true, 'breakOn' => 'test2behavior')); + $Apple->Behaviors->trigger('beforeTest', array(&$Apple), array('break' => true, 'breakOn' => 'test2behavior')); $expected = array('testbehavior', 'test2behavior'); $this->assertIdentical($Apple->beforeTestResult, $expected); $Apple->beforeTestResult = array(); - $Apple->Behaviors->trigger($Apple, 'beforeTest', array(), array('break' => true, 'breakOn' => array('test2behavior', 'test3behavior'))); + $Apple->Behaviors->trigger('beforeTest', array($Apple), array('break' => true, 'breakOn' => array('test2behavior', 'test3behavior'))); $expected = array('testbehavior', 'test2behavior'); $this->assertIdentical($Apple->beforeTestResult, $expected); } @@ -1130,6 +1123,6 @@ class BehaviorCollectionTest extends CakeTestCase { $Sample->Behaviors->attach('Test2'); $Sample->Behaviors->detach('Test3'); - $Sample->Behaviors->trigger($Sample, 'beforeTest'); + $Sample->Behaviors->trigger('beforeTest', array(&$Sample)); } } diff --git a/cake/tests/cases/libs/object_collection.test.php b/cake/tests/cases/libs/object_collection.test.php index 91f7080e1..fd51cbecd 100644 --- a/cake/tests/cases/libs/object_collection.test.php +++ b/cake/tests/cases/libs/object_collection.test.php @@ -334,7 +334,7 @@ class ObjectCollectionTest extends CakeTestCase { $this->Objects->TriggerMockSecond->expects($this->once()) ->method('callback') ->with(array('value')) - ->will($this->returnValue('new value')); + ->will($this->returnValue(array('new value'))); $result = $this->Objects->trigger( 'callback', From dc7ff8911dfbcb6442e1905cb90406abd9b0ac67 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 18:02:45 -0500 Subject: [PATCH 089/125] Fixing tests in ComponentCollection and HelperCollection as return of trigger now depends on the triggered objects. Removing annoying test that broke anytime something changed in Model. --- .../libs/controller/component_collection.test.php | 6 +++--- cake/tests/cases/libs/set.test.php | 14 -------------- .../cases/libs/view/helper_collection.test.php | 4 ++-- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/cake/tests/cases/libs/controller/component_collection.test.php b/cake/tests/cases/libs/controller/component_collection.test.php index d41f74095..ff96199b1 100644 --- a/cake/tests/cases/libs/controller/component_collection.test.php +++ b/cake/tests/cases/libs/controller/component_collection.test.php @@ -150,7 +150,7 @@ class ComponentCollectionTest extends CakeTestCase { $this->mockObjects[] = $this->Components->TriggerMockCookie; $this->mockObjects[] = $this->Components->TriggerMockSecurity; - $this->assertTrue($this->Components->trigger('startup', array(&$controller))); + $this->assertNull($this->Components->trigger('startup', array(&$controller))); } /** @@ -174,7 +174,7 @@ class ComponentCollectionTest extends CakeTestCase { $this->mockObjects[] = $this->Components->TriggerMockSecurity; $result = $this->Components->trigger('initialize', array(&$controller), array('triggerDisabled' => true)); - $this->assertTrue($result); + $this->assertNull($result); } /** @@ -197,7 +197,7 @@ class ComponentCollectionTest extends CakeTestCase { $this->Components->disable('TriggerMockSecurity'); - $this->assertTrue($this->Components->trigger('startup', array(&$controller))); + $this->assertNull($this->Components->trigger('startup', array(&$controller))); } /** diff --git a/cake/tests/cases/libs/set.test.php b/cake/tests/cases/libs/set.test.php index 01fb97663..1075b6cf7 100644 --- a/cake/tests/cases/libs/set.test.php +++ b/cake/tests/cases/libs/set.test.php @@ -2115,20 +2115,6 @@ class SetTest extends CakeTestCase { $result = Set::reverse($class); $this->assertEquals($result, $expected); - $model = new Model(array('id' => false, 'name' => 'Model', 'table' => false)); - $expected = array( - 'Behaviors' => array('modelName' => 'Model'), - 'useDbConfig' => 'default', 'useTable' => false, 'displayField' => null, 'id' => false, 'data' => array(), 'table' => 'models', 'primaryKey' => 'id', 'validate' => array(), - 'validationErrors' => array(), 'tablePrefix' => null, 'name' => 'Model', 'alias' => 'Model', 'tableToModel' => array(), 'logTransactions' => false, 'cacheQueries' => false, - 'belongsTo' => array(), 'hasOne' => array(), 'hasMany' => array(), 'hasAndBelongsToMany' => array(), 'actsAs' => null, 'whitelist' => array(), 'cacheSources' => true, - 'findQueryType' => null, 'recursive' => 1, 'order' => null, 'virtualFields' => array(), -); - $result = Set::reverse($model); - - ksort($result); - ksort($expected); - $this->assertEquals($result, $expected); - $class = new stdClass; $class->User = new stdClass; $class->User->id = 100; diff --git a/cake/tests/cases/libs/view/helper_collection.test.php b/cake/tests/cases/libs/view/helper_collection.test.php index 8d60f0109..403bbc8e7 100644 --- a/cake/tests/cases/libs/view/helper_collection.test.php +++ b/cake/tests/cases/libs/view/helper_collection.test.php @@ -137,7 +137,7 @@ class HelperCollectionTest extends CakeTestCase { $this->mockObjects[] = $this->Helpers->TriggerMockForm; - $this->assertTrue($this->Helpers->trigger('beforeRender', array('one', 'two'))); + $this->assertNull($this->Helpers->trigger('beforeRender', array('one', 'two'))); } /** @@ -163,7 +163,7 @@ class HelperCollectionTest extends CakeTestCase { $this->Helpers->disable('TriggerMockForm'); - $this->assertTrue($this->Helpers->trigger('beforeRender', array('one', 'two'))); + $this->assertNull($this->Helpers->trigger('beforeRender', array('one', 'two'))); } /** From f3445cd94152c478fc30700307a8c824815574ca Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 18:04:47 -0500 Subject: [PATCH 090/125] Making ModelBehavior::beforeFind() return true by default. Since returning null causes the find to abort, behaviors should return true if they are not going to return a query array. --- cake/libs/model/model_behavior.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cake/libs/model/model_behavior.php b/cake/libs/model/model_behavior.php index 46ad69165..d0093e95e 100644 --- a/cake/libs/model/model_behavior.php +++ b/cake/libs/model/model_behavior.php @@ -80,10 +80,13 @@ class ModelBehavior extends Object { * * @param object $model Model using this behavior * @param array $queryData Data used to execute this query, i.e. conditions, order, etc. - * @return mixed False or null will abort the operation. You should array will replace the value of $query. + * @return mixed False or null will abort the operation. You can return an array to replace the + * $query that will be eventually run. * @access public */ - public function beforeFind($model, $query) { } + public function beforeFind($model, $query) { + return true; + } /** * After find callback. Can be used to modify any results returned by find and findAll. From 017385d61c6059f3e546a2da6cb6957a2b34461d Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 20:21:14 -0500 Subject: [PATCH 091/125] Fixing most of the strict errors in the helper test suite. --- cake/libs/view/helpers/form.php | 3 ++- cake/libs/view/helpers/js.php | 15 --------------- cake/tests/cases/libs/view/helper.test.php | 8 ++++---- cake/tests/cases/libs/view/helpers/form.test.php | 10 +++++----- cake/tests/cases/libs/view/helpers/rss.test.php | 4 ++-- 5 files changed, 13 insertions(+), 27 deletions(-) diff --git a/cake/libs/view/helpers/form.php b/cake/libs/view/helpers/form.php index a92b3fd41..06a465e84 100644 --- a/cake/libs/view/helpers/form.php +++ b/cake/libs/view/helpers/form.php @@ -540,7 +540,8 @@ class FormHelper extends AppHelper { if ($text === null) { if (strpos($fieldName, '.') !== false) { - $text = array_pop(explode('.', $fieldName)); + $fieldElements = explode('.', $fieldName); + $text = array_pop($fieldElements); } else { $text = $fieldName; } diff --git a/cake/libs/view/helpers/js.php b/cake/libs/view/helpers/js.php index 9fcecaab9..41f0ffbd5 100644 --- a/cake/libs/view/helpers/js.php +++ b/cake/libs/view/helpers/js.php @@ -155,20 +155,6 @@ class JsHelper extends AppHelper { trigger_error(__('JsHelper:: Missing Method %s is undefined', $method), E_USER_WARNING); } -/** - * Workaround for Object::Object() existing. Since Object::object exists, it does not - * fall into call__ and is not passed onto the engine helper. See JsBaseEngineHelper::object() for - * more information on this method. - * - * @param mixed $data Data to convert into JSON - * @param array $options Options to use for encoding JSON. See JsBaseEngineHelper::object() for more details. - * @return string encoded JSON - * @deprecated Remove when support for PHP4 and Object::object are removed. - */ - public function object($data = array(), $options = array()) { - return $this->{$this->__engineName}->object($data, $options); - } - /** * Overwrite inherited Helper::value() * See JsBaseEngineHelper::value() for more information on this method. @@ -203,7 +189,6 @@ class JsHelper extends AppHelper { */ public function writeBuffer($options = array()) { $domReady = $this->request->is('ajax'); - // $domReady = isset($this->params['isAjax']) ? !$this->params['isAjax'] : true; $defaults = array( 'onDomReady' => $domReady, 'inline' => true, 'cache' => false, 'clear' => true, 'safe' => true diff --git a/cake/tests/cases/libs/view/helper.test.php b/cake/tests/cases/libs/view/helper.test.php index ba401fe6e..4ef761091 100644 --- a/cake/tests/cases/libs/view/helper.test.php +++ b/cake/tests/cases/libs/view/helper.test.php @@ -41,7 +41,7 @@ class HelperTestPost extends Model { * @access public * @return void */ - function schema() { + function schema($field = false) { $this->_schema = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'), 'title' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'), @@ -85,7 +85,7 @@ class HelperTestComment extends Model { * @access public * @return void */ - function schema() { + function schema($field = false) { $this->_schema = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'), 'author_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'), @@ -120,7 +120,7 @@ class HelperTestTag extends Model { * @access public * @return void */ - function schema() { + function schema($field = false) { $this->_schema = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'), 'name' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'), @@ -153,7 +153,7 @@ class HelperTestPostsTag extends Model { * @access public * @return void */ - function schema() { + function schema($field = false) { $this->_schema = array( 'helper_test_post_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'), 'helper_test_tag_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'), diff --git a/cake/tests/cases/libs/view/helpers/form.test.php b/cake/tests/cases/libs/view/helpers/form.test.php index 143570711..8c01f95eb 100644 --- a/cake/tests/cases/libs/view/helpers/form.test.php +++ b/cake/tests/cases/libs/view/helpers/form.test.php @@ -221,7 +221,7 @@ class ContactNonStandardPk extends Contact { * @access public * @return void */ - function schema() { + function schema($field = false) { $this->_schema = parent::schema(); $this->_schema['pk'] = $this->_schema['id']; unset($this->_schema['id']); @@ -389,7 +389,7 @@ class OpenidUrl extends CakeTestModel { * @access public * @return void */ - function beforeValidate() { + function beforeValidate($options = array()) { $this->invalidate('openid_not_registered'); return true; } @@ -458,7 +458,7 @@ class ValidateUser extends CakeTestModel { * @access public * @return void */ - function beforeValidate() { + function beforeValidate($options = array()) { $this->invalidate('email'); return false; } @@ -537,7 +537,7 @@ class ValidateProfile extends CakeTestModel { * @access public * @return void */ - function beforeValidate() { + function beforeValidate($options = array()) { $this->invalidate('full_name'); $this->invalidate('city'); return false; @@ -607,7 +607,7 @@ class ValidateItem extends CakeTestModel { * @access public * @return void */ - function beforeValidate() { + function beforeValidate($options = array()) { $this->invalidate('description'); return false; } diff --git a/cake/tests/cases/libs/view/helpers/rss.test.php b/cake/tests/cases/libs/view/helpers/rss.test.php index afc3e54e9..f836d890f 100644 --- a/cake/tests/cases/libs/view/helpers/rss.test.php +++ b/cake/tests/cases/libs/view/helpers/rss.test.php @@ -108,7 +108,7 @@ class RssHelperTest extends CakeTestCase { 'title', '/title', 'Rss->url('/', true), '/link', ' array('url' => RssHelper::url('/test.flv', true)), + 'enclosure' => array('url' => $this->Rss->url('/test.flv', true)), ' Date: Sun, 12 Dec 2010 23:48:04 -0200 Subject: [PATCH 092/125] Renamed setAuthConfig to configAuth, and setProxyConfig to configProxy. --- cake/libs/http_socket.php | 6 +++--- cake/tests/cases/libs/http_socket.test.php | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 0af827f44..5c58745c6 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -181,7 +181,7 @@ class HttpSocket extends CakeSocket { * @param string $pass Password for authentication * @return void */ - public function setAuthConfig($method, $user = null, $pass = null) { + public function configAuth($method, $user = null, $pass = null) { if (empty($method)) { $this->_auth = array(); return; @@ -203,7 +203,7 @@ class HttpSocket extends CakeSocket { * @param string $pass Password to proxy authentication * @return void */ - public function setProxyConfig($host, $port = 3128, $method = null, $user = null, $pass = null) { + public function configProxy($host, $port = 3128, $method = null, $user = null, $pass = null) { if (empty($host)) { $this->_proxy = array(); return; @@ -310,7 +310,7 @@ class HttpSocket extends CakeSocket { } if (isset($this->request['uri']['user'], $this->request['uri']['pass'])) { - $this->setAuthConfig('Basic', $this->request['uri']['user'], $this->request['uri']['pass']); + $this->configAuth('Basic', $this->request['uri']['user'], $this->request['uri']['pass']); } $this->_setAuth(); $this->request['auth'] = $this->_auth; diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 895b62e08..73c44fe62 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -715,7 +715,7 @@ class HttpSocketTest extends CakeTestCase { $this->Socket->expects($this->any())->method('connect')->will($this->returnValue(true)); $this->Socket->expects($this->any())->method('read')->will($this->returnValue(false)); - $this->Socket->setProxyConfig('proxy.server', 123); + $this->Socket->configProxy('proxy.server', 123); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n\r\n"; $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); @@ -745,7 +745,7 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($this->Socket->request['proxy'], $expected); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nProxy-Authorization: Test mark.secret\r\n\r\n"; - $this->Socket->setProxyConfig('proxy.server', 123, 'Test', 'mark', 'secret'); + $this->Socket->configProxy('proxy.server', 123, 'Test', 'mark', 'secret'); $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); $this->assertEqual($this->Socket->config['host'], 'proxy.server'); @@ -759,7 +759,7 @@ class HttpSocketTest extends CakeTestCase { ); $this->assertEqual($this->Socket->request['proxy'], $expected); - $this->Socket->setAuthConfig('Test', 'login', 'passwd'); + $this->Socket->configAuth('Test', 'login', 'passwd'); $expected = "GET http://www.cakephp.org/ HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\nProxy-Authorization: Test mark.secret\r\nAuthorization: Test login.passwd\r\n\r\n"; $this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($this->Socket->request['raw'], $expected); @@ -879,11 +879,11 @@ class HttpSocketTest extends CakeTestCase { $socket->get('http://mark:secret@example.com/test'); $this->assertTrue(strpos($socket->request['header'], 'Authorization: Basic bWFyazpzZWNyZXQ=') !== false); - $socket->setAuthConfig(false); + $socket->configAuth(false); $socket->get('http://example.com/test'); $this->assertFalse(strpos($socket->request['header'], 'Authorization:')); - $socket->setAuthConfig('Test', 'mark', 'passwd'); + $socket->configAuth('Test', 'mark', 'passwd'); $socket->get('http://example.com/test'); $this->assertTrue(strpos($socket->request['header'], 'Authorization: Test mark.passwd') !== false); } From f84871ae47a4298f419a31d108ca7366519306c6 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 20:55:33 -0500 Subject: [PATCH 093/125] Fixing strict errors that were causing shell tests to fail. Fixing test case for bake test that has been getting skipped. --- cake/console/shells/bake.php | 2 +- cake/console/shells/tasks/model.php | 2 +- cake/libs/folder.php | 28 +++++-------------- cake/tests/cases/console/shells/bake.test.php | 13 ++++----- 4 files changed, 15 insertions(+), 30 deletions(-) diff --git a/cake/console/shells/bake.php b/cake/console/shells/bake.php index 77dd36201..7e4dbb016 100644 --- a/cake/console/shells/bake.php +++ b/cake/console/shells/bake.php @@ -186,7 +186,7 @@ class BakeShell extends Shell { } else { $this->error(__('Bake All could not continue without a valid model')); } - $this->_stop(); + return $this->_stop(); } /** diff --git a/cake/console/shells/tasks/model.php b/cake/console/shells/tasks/model.php index 7616ef14c..ffa06640a 100644 --- a/cake/console/shells/tasks/model.php +++ b/cake/console/shells/tasks/model.php @@ -701,7 +701,7 @@ class ModelTask extends BakeTask { protected function _generatePossibleKeys() { $possible = array(); foreach ($this->_tables as $otherTable) { - $tempOtherModel = & new Model(array('table' => $otherTable, 'ds' => $this->connection)); + $tempOtherModel = new Model(array('table' => $otherTable, 'ds' => $this->connection)); $modelFieldsTemp = $tempOtherModel->schema(true); foreach ($modelFieldsTemp as $fieldName => $field) { if ($field['type'] == 'integer' || $field['type'] == 'string') { diff --git a/cake/libs/folder.php b/cake/libs/folder.php index 551e05876..733315a1a 100644 --- a/cake/libs/folder.php +++ b/cake/libs/folder.php @@ -240,10 +240,8 @@ class Folder { * * @param string $path Path to check * @return boolean true if windows path, false otherwise - * @access public - * @static */ - function isWindowsPath($path) { + public static function isWindowsPath($path) { return (preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) == '\\\\'); } @@ -252,10 +250,8 @@ class Folder { * * @param string $path Path to check * @return bool true if path is absolute. - * @access public - * @static */ - function isAbsolute($path) { + public static function isAbsolute($path) { return !empty($path) && ($path[0] === '/' || preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) == '\\\\'); } @@ -264,10 +260,8 @@ class Folder { * * @param string $path Path to check * @return string Set of slashes ("\\" or "/") - * @access public - * @static */ - function normalizePath($path) { + public static function normalizePath($path) { return Folder::correctSlashFor($path); } @@ -276,10 +270,8 @@ class Folder { * * @param string $path Path to check * @return string Set of slashes ("\\" or "/") - * @access public - * @static */ - function correctSlashFor($path) { + public static function correctSlashFor($path) { return (Folder::isWindowsPath($path)) ? '\\' : '/'; } @@ -288,10 +280,8 @@ class Folder { * * @param string $path Path to check * @return string Path with ending slash - * @access public - * @static */ - function slashTerm($path) { + public static function slashTerm($path) { if (Folder::isSlashTerm($path)) { return $path; } @@ -304,10 +294,8 @@ class Folder { * @param string $path Path * @param string $element Element to and at end of path * @return string Combined path - * @access public - * @static */ - function addPathElement($path, $element) { + public static function addPathElement($path, $element) { return rtrim($path, DS) . DS . $element; } @@ -755,10 +743,8 @@ class Folder { * * @param string $path Path to check * @return boolean true if path ends with slash, false otherwise - * @access public - * @static */ - function isSlashTerm($path) { + public static function isSlashTerm($path) { $lastChar = $path[strlen($path) - 1]; return $lastChar === '/' || $lastChar === '\\'; } diff --git a/cake/tests/cases/console/shells/bake.test.php b/cake/tests/cases/console/shells/bake.test.php index 6f68e8bb3..89383b1ff 100644 --- a/cake/tests/cases/console/shells/bake.test.php +++ b/cake/tests/cases/console/shells/bake.test.php @@ -20,9 +20,9 @@ */ App::import('Shell', 'Shell', false); App::import('Shell', 'Bake', false); -App::import('Shell', 'tasks/model', false); -App::import('Shell', 'tasks/controller', false); -App::import('Shell', 'tasks/db_config', false); +App::import('Shell', 'tasks/model'); +App::import('Shell', 'tasks/controller'); +App::import('Shell', 'tasks/db_config'); App::import('Core', 'Controller'); require_once CAKE . 'console' . DS . 'shell_dispatcher.php'; @@ -94,12 +94,11 @@ class BakeShellTest extends CakeTestCase { $this->Shell->Controller->expects($this->once())->method('bake')->will($this->returnValue(true)); $this->Shell->View->expects($this->once())->method('execute'); - $this->Shell->expects($this->at(1))->method('out')->with('Bake All'); - $this->Shell->expects($this->at(3))->method('out')->with('User Model was baked.'); + $this->Shell->expects($this->once())->method('_stop'); + $this->Shell->expects($this->at(0))->method('out')->with('Bake All'); $this->Shell->expects($this->at(5))->method('out')->with('Bake All complete'); - $this->Shell->expects($this->at(7))->method('out')->with('User Views were baked.'); - $this->Shell->expects($this->at(8))->method('out')->with('Bake All complete'); + $this->Shell->connection = ''; $this->Shell->params = array(); $this->Shell->args = array('User'); $this->Shell->all(); From 0ac8d042417899c51316ec499c70b9c74bb4eb5b Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 21:02:42 -0500 Subject: [PATCH 094/125] Fixing more strict warnings. --- cake/libs/dispatcher.php | 3 ++- cake/libs/file.php | 2 +- cake/tests/cases/libs/dispatcher.test.php | 9 ++++----- cake/tests/cases/libs/folder.test.php | 4 ++-- cake/tests/cases/libs/router.test.php | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cake/libs/dispatcher.php b/cake/libs/dispatcher.php index cb14d18ba..4f35138c8 100644 --- a/cake/libs/dispatcher.php +++ b/cake/libs/dispatcher.php @@ -315,7 +315,8 @@ class Dispatcher { $this->_stop(); } $controller = null; - $ext = array_pop(explode('.', $url)); + $pathSegments = explode('.', $url); + $ext = array_pop($pathSegments); $parts = explode('/', $url); $assetFile = null; diff --git a/cake/libs/file.php b/cake/libs/file.php index 0151181f5..47f922d9d 100644 --- a/cake/libs/file.php +++ b/cake/libs/file.php @@ -212,7 +212,7 @@ class File { * @param string $data Data to prepare for writing. * @return string The with converted line endings. */ - public function prepare($data, $forceWindows = false) { + public static function prepare($data, $forceWindows = false) { $lineBreak = "\n"; if (DIRECTORY_SEPARATOR == '\\' || $forceWindows === true) { $lineBreak = "\r\n"; diff --git a/cake/tests/cases/libs/dispatcher.test.php b/cake/tests/cases/libs/dispatcher.test.php index 35f161e7a..0192e6740 100644 --- a/cake/tests/cases/libs/dispatcher.test.php +++ b/cake/tests/cases/libs/dispatcher.test.php @@ -49,12 +49,11 @@ class TestDispatcher extends Dispatcher { * invoke method * * @param mixed $controller - * @param mixed $params - * @param mixed $missingAction + * @param mixed $request * @return void */ - protected function _invoke(&$controller, $params) { - if ($result = parent::_invoke($controller, $params)) { + protected function _invoke(Controller $controller, CakeRequest $request) { + if ($result = parent::_invoke($controller, $request)) { if ($result[0] === 'missingAction') { return $result; } @@ -192,7 +191,7 @@ class SomePagesController extends AppController { * * @return void */ - public function redirect() { + public function redirect($url, $status = null, $exit = true) { echo 'this should not be accessible'; } } diff --git a/cake/tests/cases/libs/folder.test.php b/cake/tests/cases/libs/folder.test.php index 428520610..472385243 100644 --- a/cake/tests/cases/libs/folder.test.php +++ b/cake/tests/cases/libs/folder.test.php @@ -195,8 +195,8 @@ class FolderTest extends CakeTestCase { $this->assertFalse($result); $expected = $new . ' is a file'; - $result = array_pop($Folder->errors()); - $this->assertEqual($result, $expected); + $result = $Folder->errors(); + $this->assertEqual($result[0], $expected); $new = TMP . 'test_folder_new'; $result = $Folder->create($new); diff --git a/cake/tests/cases/libs/router.test.php b/cake/tests/cases/libs/router.test.php index 92c3f0971..ffe168ac8 100644 --- a/cake/tests/cases/libs/router.test.php +++ b/cake/tests/cases/libs/router.test.php @@ -2273,7 +2273,7 @@ class RouterTest extends CakeTestCase { * @return void */ function testPatternOnAction() { - $route =& new CakeRoute( + $route = new CakeRoute( '/blog/:action/*', array('controller' => 'blog_posts'), array('action' => 'other|actions') From 2fe60142f53381d91b2000261447a5dd3f4673d5 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 12 Dec 2010 21:09:56 -0500 Subject: [PATCH 095/125] Fixing more strict warnings. --- cake/libs/cake_session.php | 3 +-- cake/libs/controller/cake_error_controller.php | 2 +- cake/libs/debugger.php | 2 +- cake/libs/validation.php | 5 +++-- cake/libs/xml.php | 4 ++-- cake/tests/cases/libs/set.test.php | 3 +-- cake/tests/cases/libs/validation.test.php | 8 ++++---- 7 files changed, 13 insertions(+), 14 deletions(-) diff --git a/cake/libs/cake_session.php b/cake/libs/cake_session.php index c590f2881..91ed52f02 100644 --- a/cake/libs/cake_session.php +++ b/cake/libs/cake_session.php @@ -393,9 +393,8 @@ class CakeSession { * Returns all session variables. * * @return mixed Full $_SESSION array, or false on error. - * @access private */ - function __returnSessionVars() { + private static function __returnSessionVars() { if (!empty($_SESSION)) { return $_SESSION; } diff --git a/cake/libs/controller/cake_error_controller.php b/cake/libs/controller/cake_error_controller.php index 765e79f30..443024840 100644 --- a/cake/libs/controller/cake_error_controller.php +++ b/cake/libs/controller/cake_error_controller.php @@ -26,7 +26,7 @@ class CakeErrorController extends AppController { function __construct() { parent::__construct(); $this->_set(Router::getPaths()); - $this->request = $this->params = Router::getRequest(false); + $this->request = Router::getRequest(false); $this->constructClasses(); $this->Components->trigger('initialize', array(&$this)); $this->_set(array('cacheAction' => false, 'viewPath' => 'errors')); diff --git a/cake/libs/debugger.php b/cake/libs/debugger.php index f07ab78c6..33f665a2c 100644 --- a/cake/libs/debugger.php +++ b/cake/libs/debugger.php @@ -236,7 +236,7 @@ class Debugger { * @param array $context Context * @return boolean true if error was handled */ - public function showError($code, $description, $file = null, $line = null, $context = null) { + public static function showError($code, $description, $file = null, $line = null, $context = null) { $_this = Debugger::getInstance(); if (empty($file)) { diff --git a/cake/libs/validation.php b/cake/libs/validation.php index 5af6db748..adda137c0 100644 --- a/cake/libs/validation.php +++ b/cake/libs/validation.php @@ -415,7 +415,8 @@ class Validation { if (is_array($check)) { return self::extension(array_shift($check), $extensions); } - $extension = strtolower(array_pop(explode('.', $check))); + $pathSegments = explode('.', $check); + $extension = strtolower(array_pop($pathSegments)); foreach ($extensions as $value) { if ($extension == strtolower($value)) { return true; @@ -431,7 +432,7 @@ class Validation { * @param string $ipVersion The IP Protocol version to validate against * @return boolean Success */ - public function ip($check, $type = 'both') { + public static function ip($check, $type = 'both') { $type = strtolower($type); $flags = array(); if ($type === 'ipv4' || $type === 'both') { diff --git a/cake/libs/xml.php b/cake/libs/xml.php index 160572b95..0027d1631 100644 --- a/cake/libs/xml.php +++ b/cake/libs/xml.php @@ -182,7 +182,7 @@ class Xml { * @param string $format Either 'attribute' or 'tags'. This determines where nested keys go. * @return void */ - protected function _fromArray(&$dom, &$node, &$data, $format) { + protected static function _fromArray(&$dom, &$node, &$data, $format) { if (empty($data) || !is_array($data)) { return; } @@ -237,7 +237,7 @@ class Xml { * @param array $data Array with informations to create childs * @return void */ - private function __createChild($data) { + private static function __createChild($data) { extract($data); $childNS = $childValue = null; if (is_array($value)) { diff --git a/cake/tests/cases/libs/set.test.php b/cake/tests/cases/libs/set.test.php index 1075b6cf7..a4d6a5427 100644 --- a/cake/tests/cases/libs/set.test.php +++ b/cake/tests/cases/libs/set.test.php @@ -2706,10 +2706,9 @@ class SetTest extends CakeTestCase { /** * Helper method to test Set::apply() * - * @access protected * @return void */ - function _method($val1, $val2) { + static function _method($val1, $val2) { $val1 += $val2; return $val1; } diff --git a/cake/tests/cases/libs/validation.test.php b/cake/tests/cases/libs/validation.test.php index a794453d8..002902a9d 100644 --- a/cake/tests/cases/libs/validation.test.php +++ b/cake/tests/cases/libs/validation.test.php @@ -34,7 +34,7 @@ class CustomValidator { * @return boolean * @access public */ - function customValidate($check) { + static function customValidate($check) { return (bool)preg_match('/^[0-9]{3}$/', $check); } } @@ -53,7 +53,7 @@ class TestNlValidation { * @param string $check * @return void */ - function postal($check) { + static function postal($check) { return true; } /** @@ -61,7 +61,7 @@ class TestNlValidation { * * @return void */ - function ssn($check) { + static function ssn($check) { return true; } } @@ -80,7 +80,7 @@ class TestDeValidation { * @param string $check * @return void */ - function phone($check) { + static function phone($check) { return true; } } From dfb76d67da6e14b4c3b01ebfe371518ca9a62ed1 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 00:16:45 -0200 Subject: [PATCH 096/125] Created the HttpResponse to get HttpSocket responses. --- cake/libs/http_response.php | 180 +++++++++++++++++++ cake/tests/cases/libs/all_socket.test.php | 1 + cake/tests/cases/libs/http_response.test.php | 157 ++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 cake/libs/http_response.php create mode 100644 cake/tests/cases/libs/http_response.test.php diff --git a/cake/libs/http_response.php b/cake/libs/http_response.php new file mode 100644 index 000000000..ef54423ab --- /dev/null +++ b/cake/libs/http_response.php @@ -0,0 +1,180 @@ +body; + } + +/** + * Get header in case insensitive + * + * @param string $name Header name + * @return mixed String if header exists or null + */ + public function getHeader($name) { + if (isset($this->headers[$name])) { + return $this->headers[$name]; + } + foreach ($this->headers as $key => $value) { + if (strcasecmp($key, $name) == 0) { + return $value; + } + } + return null; + } + +/** + * If return is 200 (OK) + * + * @return boolean + */ + public function isOk() { + return $this->code == 200; + } + +/** + * ArrayAccess - Offset Exists + * + * @param mixed $offset + * @return boolean + */ + public function offsetExists($offset) { + return in_array($offset, array('raw', 'status', 'header', 'body', 'cookies')); + } + +/** + * ArrayAccess - Offset Get + * + * @param mixed $offset + * @return mixed + */ + public function offsetGet($offset) { + switch ($offset) { + case 'raw': + $firstLineLength = strpos($this->raw, "\r\n") + 2; + return array( + 'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase, + 'header' => substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength), + 'body' => $this->body, + 'response' => $this->raw + ); + case 'status': + return array( + 'http-version' => $this->httpVersion, + 'code' => $this->code, + 'reason-phrase' => $this->reasonPhrase + ); + case 'header': + return $this->headers; + case 'body': + return $this->body; + case 'cookies': + return $this->cookies; + } + return null; + } + +/** + * ArrayAccess - 0ffset Set + * + * @param mixed $offset + * @param mixed $value + * @return void + */ + public function offsetSet($offset, $value) { + return; + } + +/** + * ArrayAccess - Offset Unset + * + * @param mixed @offset + * @return void + */ + public function offsetUnset($offset) { + return; + } + +/** + * Instance as string + * + * @return string + */ + public function __toString() { + return $this->body(); + } + +} diff --git a/cake/tests/cases/libs/all_socket.test.php b/cake/tests/cases/libs/all_socket.test.php index 896738957..ec276f580 100644 --- a/cake/tests/cases/libs/all_socket.test.php +++ b/cake/tests/cases/libs/all_socket.test.php @@ -38,6 +38,7 @@ class AllSocketTest extends PHPUnit_Framework_TestSuite { $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_socket.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'http_socket.test.php'); + $suite->addTestFile(CAKE_TEST_CASES . DS . 'libs' . DS . 'http_response.test.php'); $suite->addTestDirectory(CORE_TEST_CASES . DS . 'libs' . DS . 'http'); return $suite; } diff --git a/cake/tests/cases/libs/http_response.test.php b/cake/tests/cases/libs/http_response.test.php new file mode 100644 index 000000000..debac0735 --- /dev/null +++ b/cake/tests/cases/libs/http_response.test.php @@ -0,0 +1,157 @@ + + * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests + * @package cake + * @subpackage cake.tests.cases.libs + * @since CakePHP(tm) v 1.2.0.4206 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ +App::import('Core', 'HttpResponse'); + +/** + * HttpResponseTest class + * + * @package cake + * @subpackage cake.tests.cases.libs + */ +class HttpResponseTest extends CakeTestCase { +/** + * This function sets up a HttpResponse + * + * @return void + */ + public function setUp() { + $this->HttpResponse = new HttpResponse(); + } + +/** + * testBody + * + * @return void + */ + public function testBody() { + $this->HttpResponse->body = 'testing'; + $this->assertEqual($this->HttpResponse->body(), 'testing'); + + $this->HttpResponse->body = null; + $this->assertIdentical($this->HttpResponse->body(), ''); + } + +/** + * testToString + * + * @return void + */ + public function testToString() { + $this->HttpResponse->body = 'other test'; + $this->assertEqual($this->HttpResponse->body(), 'other test'); + $this->assertEqual((string)$this->HttpResponse, 'other test'); + $this->assertTrue(strpos($this->HttpResponse, 'test') > 0); + + $this->HttpResponse->body = null; + $this->assertEqual((string)$this->HttpResponse, ''); + } + +/** + * testGetHeadr + * + * @return void + */ + public function testGetHeader() { + $this->HttpResponse->headers = array( + 'foo' => 'Bar', + 'Some' => 'ok', + 'HeAdEr' => 'value', + 'content-Type' => 'text/plain' + ); + + $this->assertEqual($this->HttpResponse->getHeader('foo'), 'Bar'); + $this->assertEqual($this->HttpResponse->getHeader('Foo'), 'Bar'); + $this->assertEqual($this->HttpResponse->getHeader('FOO'), 'Bar'); + $this->assertEqual($this->HttpResponse->getHeader('header'), 'value'); + $this->assertEqual($this->HttpResponse->getHeader('Content-Type'), 'text/plain'); + $this->assertIdentical($this->HttpResponse->getHeader(0), null); + } + +/** + * testIsOk + * + * @return void + */ + public function testIsOk() { + $this->HttpResponse->code = 0; + $this->assertFalse($this->HttpResponse->isOk()); + $this->HttpResponse->code = -1; + $this->assertFalse($this->HttpResponse->isOk()); + $this->HttpResponse->code = 201; + $this->assertFalse($this->HttpResponse->isOk()); + $this->HttpResponse->code = 'what?'; + $this->assertFalse($this->HttpResponse->isOk()); + $this->HttpResponse->code = 200; + $this->assertTrue($this->HttpResponse->isOk()); + } + +/** + * testArrayAccess + * + * @return void + */ + public function testArrayAccess() { + $this->HttpResponse->httpVersion = 'HTTP/1.1'; + $this->HttpResponse->code = 200; + $this->HttpResponse->reasonPhrase = 'OK'; + $this->HttpResponse->headers = array( + 'Server' => 'CakePHP', + 'ContEnt-Type' => 'text/plain' + ); + $this->HttpResponse->cookies = array( + 'foo' => array('value' => 'bar'), + 'bar' => array('value' => 'foo') + ); + $this->HttpResponse->body = 'This is a test!'; + $this->HttpResponse->raw = "HTTP/1.1 200 OK\r\nServer: CakePHP\r\nContEnt-Type: text/plain\r\n\r\nThis is a test!"; + + $expected1 = 'HTTP/1.1 200 OK'; + $this->assertEqual($this->HttpResponse['raw']['status-line'], $expected1); + $expected2 = "Server: CakePHP\r\nContEnt-Type: text/plain"; + $this->assertEqual($this->HttpResponse['raw']['header'], $expected2); + $expected3 = 'This is a test!'; + $this->assertEqual($this->HttpResponse['raw']['body'], $expected3); + $expected = $expected1 . "\r\n" . $expected2 . "\r\n\r\n" . $expected3; + $this->assertEqual($this->HttpResponse['raw']['response'], $expected); + + $expected = 'HTTP/1.1'; + $this->assertEqual($this->HttpResponse['status']['http-version'], $expected); + $expected = 200; + $this->assertEqual($this->HttpResponse['status']['code'], $expected); + $expected = 'OK'; + $this->assertEqual($this->HttpResponse['status']['reason-phrase'], $expected); + + $expected = array( + 'Server' => 'CakePHP', + 'ContEnt-Type' => 'text/plain' + ); + $this->assertEqual($this->HttpResponse['header'], $expected); + + $expected = 'This is a test!'; + $this->assertEqual($this->HttpResponse['body'], $expected); + + $expected = array( + 'foo' => array('value' => 'bar'), + 'bar' => array('value' => 'foo') + ); + $this->assertEqual($this->HttpResponse['cookies'], $expected); + } + +} \ No newline at end of file From f45027ecd87041be3a8f257664b661650a315bd7 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 01:06:57 -0200 Subject: [PATCH 097/125] Adjusting HttpResponse responses in array to be more compatible. --- cake/libs/http_response.php | 9 +++++++-- cake/tests/cases/libs/http_response.test.php | 9 ++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cake/libs/http_response.php b/cake/libs/http_response.php index ef54423ab..f0cc637c8 100644 --- a/cake/libs/http_response.php +++ b/cake/libs/http_response.php @@ -125,9 +125,14 @@ class HttpResponse implements ArrayAccess { switch ($offset) { case 'raw': $firstLineLength = strpos($this->raw, "\r\n") + 2; + if ($this->raw[$firstLineLength] === "\r") { + $header = null; + } else { + $header = substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength) . "\r\n"; + } return array( - 'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase, - 'header' => substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength), + 'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase . "\r\n", + 'header' => $header, 'body' => $this->body, 'response' => $this->raw ); diff --git a/cake/tests/cases/libs/http_response.test.php b/cake/tests/cases/libs/http_response.test.php index debac0735..6c3967a89 100644 --- a/cake/tests/cases/libs/http_response.test.php +++ b/cake/tests/cases/libs/http_response.test.php @@ -122,13 +122,13 @@ class HttpResponseTest extends CakeTestCase { $this->HttpResponse->body = 'This is a test!'; $this->HttpResponse->raw = "HTTP/1.1 200 OK\r\nServer: CakePHP\r\nContEnt-Type: text/plain\r\n\r\nThis is a test!"; - $expected1 = 'HTTP/1.1 200 OK'; + $expected1 = "HTTP/1.1 200 OK\r\n"; $this->assertEqual($this->HttpResponse['raw']['status-line'], $expected1); - $expected2 = "Server: CakePHP\r\nContEnt-Type: text/plain"; + $expected2 = "Server: CakePHP\r\nContEnt-Type: text/plain\r\n"; $this->assertEqual($this->HttpResponse['raw']['header'], $expected2); $expected3 = 'This is a test!'; $this->assertEqual($this->HttpResponse['raw']['body'], $expected3); - $expected = $expected1 . "\r\n" . $expected2 . "\r\n\r\n" . $expected3; + $expected = $expected1 . $expected2 . "\r\n" . $expected3; $this->assertEqual($this->HttpResponse['raw']['response'], $expected); $expected = 'HTTP/1.1'; @@ -152,6 +152,9 @@ class HttpResponseTest extends CakeTestCase { 'bar' => array('value' => 'foo') ); $this->assertEqual($this->HttpResponse['cookies'], $expected); + + $this->HttpResponse->raw = "HTTP/1.1 200 OK\r\n\r\nThis is a test!"; + $this->assertIdentical($this->HttpResponse['raw']['header'], null); } } \ No newline at end of file From 60a9d34027d9ab1d822fb75bcefe2c87bac7e4cf Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 01:07:25 -0200 Subject: [PATCH 098/125] Updated the HttpSocket to use the new HttpResponse. --- cake/libs/http_socket.php | 99 +++++++------------ cake/tests/cases/libs/http_socket.test.php | 110 +++++++++------------ 2 files changed, 81 insertions(+), 128 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index 5c58745c6..aa4769319 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -19,6 +19,7 @@ */ App::import('Core', 'CakeSocket'); App::import('Core', 'Router'); +App::import('Lib', 'HttpResponse'); /** * Cake network socket connection class. @@ -73,22 +74,7 @@ class HttpSocket extends CakeSocket { * * @var array */ - public $response = array( - 'raw' => array( - 'status-line' => null, - 'header' => null, - 'body' => null, - 'response' => null - ), - 'status' => array( - 'http-version' => null, - 'code' => null, - 'reason-phrase' => null - ), - 'header' => array(), - 'body' => '', - 'cookies' => array() - ); + public $response = null; /** * Configuration settings for the HttpSocket and the requests @@ -238,16 +224,15 @@ class HttpSocket extends CakeSocket { * method and provide a more granular interface. * * @param mixed $request Either an URI string, or an array defining host/uri - * @return mixed null on error, reference to request body on success + * @return mixed false on error, HttpResponse on success */ - public function &request($request = array()) { + public function request($request = array()) { $this->reset(false); if (is_string($request)) { $request = array('uri' => $request); } elseif (!is_array($request)) { - $return = false; - return $return; + return false; } if (!isset($request['uri'])) { @@ -338,7 +323,7 @@ class HttpSocket extends CakeSocket { } if ($this->quirksMode === false && $this->request['line'] === false) { - return $this->response = false; + return false; } $this->request['raw'] = ''; @@ -383,14 +368,14 @@ class HttpSocket extends CakeSocket { } $this->response = $this->_parseResponse($response); - if (!empty($this->response['cookies'])) { + if (!empty($this->response->cookies)) { if (!isset($this->config['request']['cookies'][$Host])) { $this->config['request']['cookies'][$Host] = array(); } - $this->config['request']['cookies'][$Host] = array_merge($this->config['request']['cookies'][$Host], $this->response['cookies']); + $this->config['request']['cookies'][$Host] = array_merge($this->config['request']['cookies'][$Host], $this->response->cookies); } - return $this->response['body']; + return $this->response; } /** @@ -416,7 +401,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request, either false on failure or the response to the request. */ - public function &get($uri = null, $query = array(), $request = array()) { + public function get($uri = null, $query = array(), $request = array()) { if (!empty($query)) { $uri = $this->_parseUri($uri); if (isset($uri['query'])) { @@ -448,7 +433,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request, either false on failure or the response to the request. */ - public function &post($uri = null, $data = array(), $request = array()) { + public function post($uri = null, $data = array(), $request = array()) { $request = Set::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request); return $this->request($request); } @@ -461,7 +446,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request */ - public function &put($uri = null, $data = array(), $request = array()) { + public function put($uri = null, $data = array(), $request = array()) { $request = Set::merge(array('method' => 'PUT', 'uri' => $uri, 'body' => $data), $request); return $this->request($request); } @@ -474,7 +459,7 @@ class HttpSocket extends CakeSocket { * @param array $request An indexed array with indexes such as 'method' or uri * @return mixed Result of request */ - public function &delete($uri = null, $data = array(), $request = array()) { + public function delete($uri = null, $data = array(), $request = array()) { $request = Set::merge(array('method' => 'DELETE', 'uri' => $uri, 'body' => $data), $request); return $this->request($request); } @@ -585,58 +570,40 @@ class HttpSocket extends CakeSocket { * Parses the given message and breaks it down in parts. * * @param string $message Message to parse - * @return array Parsed message (with indexed elements such as raw, status, header, body) + * @return object Parsed message as HttpResponse */ protected function _parseResponse($message) { - if (is_array($message)) { - return $message; - } elseif (!is_string($message)) { - return false; + if (!is_string($message)) { + throw new Exception(__('Invalid response.')); } - static $responseTemplate; - - if (empty($responseTemplate)) { - $classVars = get_class_vars(__CLASS__); - $responseTemplate = $classVars['response']; - } - - $response = $responseTemplate; - if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) { - return false; + throw new Exception(__('Invalid HTTP response.')); } - list($null, $response['raw']['status-line'], $response['raw']['header']) = $match; - $response['raw']['response'] = $message; - $response['raw']['body'] = substr($message, strlen($match[0])); + $response = new HttpResponse(); - if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $response['raw']['status-line'], $match)) { - $response['status']['http-version'] = $match[1]; - $response['status']['code'] = (int)$match[2]; - $response['status']['reason-phrase'] = $match[3]; + list(, $statusLine, $header) = $match; + $response->raw = $message; + $response->body = (string)substr($message, strlen($match[0])); + + if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) { + $response->httpVersion = $match[1]; + $response->code = $match[2]; + $response->reasonPhrase = $match[3]; } - $response['header'] = $this->_parseHeader($response['raw']['header']); - $transferEncoding = null; - if (isset($response['header']['Transfer-Encoding'])) { - $transferEncoding = $response['header']['Transfer-Encoding']; - } - $decoded = $this->_decodeBody($response['raw']['body'], $transferEncoding); - $response['body'] = $decoded['body']; + $response->headers = $this->_parseHeader($header); + $transferEncoding = $response->getHeader('Transfer-Encoding'); + $decoded = $this->_decodeBody($response->body, $transferEncoding); + $response->body = $decoded['body']; if (!empty($decoded['header'])) { - $response['header'] = $this->_parseHeader($this->_buildHeader($response['header']) . $this->_buildHeader($decoded['header'])); + $response->headers = $this->_parseHeader($this->_buildHeader($response->headers) . $this->_buildHeader($decoded['header'])); } - if (!empty($response['header'])) { - $response['cookies'] = $this->parseCookies($response['header']); - } - - foreach ($response['raw'] as $field => $val) { - if ($val === '') { - $response['raw'][$field] = null; - } + if (!empty($response->headers)) { + $response->cookies = $this->parseCookies($response->headers); } return $response; diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 73c44fe62..9dff42b8f 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -190,6 +190,19 @@ class TestHttpSocket extends HttpSocket { public function unescapeToken($token, $chars = null) { return parent::_unescapeToken($token, $chars); } + +/** + * Convenience method for testing protected method + * + * @param string $message + * @return object HttpResponse + */ + protected function _parseResponse($message) { + if (!is_string($message)) { + return false; + } + return parent::_parseResponse($message); + } } /** @@ -596,7 +609,7 @@ class HttpSocketTest extends CakeTestCase { $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); $this->Socket->expects($this->once())->method('write') ->with("GET / HTTP/1.1\r\nHost: www.cakephp.org\r\nConnection: close\r\nUser-Agent: CakePHP\r\n\r\n"); - $response = $this->Socket->request($request); + $response = (string)$this->Socket->request($request); $this->assertEquals($response, "

    Hello, your lucky number is " . $number . "

    "); } @@ -622,22 +635,6 @@ class HttpSocketTest extends CakeTestCase { $this->assertFalse($this->Socket->connected); } -/** - * testRequestResultAsReference method - * - * @return void - */ - public function testRequestResultAsReference() { - $request = array('uri' => 'htpp://www.cakephp.org/'); - $serverResponse = "HTTP/1.x 200 OK\r\nSet-Cookie: foo=bar\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

    This is a cookie test!

    "; - $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); - $this->Socket->connected = true; - $data =& $this->Socket->request($request); - $this->assertEqual($data, $this->Socket->response['body']); - $data = 'new data'; - $this->assertEqual($data, $this->Socket->response['body']); - } - /** * testRequestWithResource * @@ -654,7 +651,7 @@ class HttpSocketTest extends CakeTestCase { $this->skipUnless($f, 'Can not write in TMP directory.'); $this->Socket->setContentResource($f); - $result = $this->Socket->request('http://www.cakephp.org/'); + $result = (string)$this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($result, ''); $this->assertEqual($this->Socket->response['header']['Server'], 'CakeHttp Server'); fclose($f); @@ -662,7 +659,7 @@ class HttpSocketTest extends CakeTestCase { unlink(TMP . 'download.txt'); $this->Socket->setContentResource(false); - $result = $this->Socket->request('http://www.cakephp.org/'); + $result = (string)$this->Socket->request('http://www.cakephp.org/'); $this->assertEqual($result, '

    This is a test!

    '); } @@ -987,15 +984,6 @@ class HttpSocketTest extends CakeTestCase { public function testParseResponse() { $this->Socket->reset(); - $r = $this->Socket->parseResponse(array('foo' => 'bar')); - $this->assertEquals($r, array('foo' => 'bar')); - - $r = $this->Socket->parseResponse(true); - $this->assertEquals($r, false); - - $r = $this->Socket->parseResponse("HTTP Foo\r\nBar: La"); - $this->assertEquals($r, false); - $tests = array( 'simple-request' => array( 'response' => array( @@ -1004,10 +992,10 @@ class HttpSocketTest extends CakeTestCase { 'body' => "

    Hello World

    \r\n

    It's good to be html

    " ), 'expectations' => array( - 'status.http-version' => 'HTTP/1.x', - 'status.code' => 200, - 'status.reason-phrase' => 'OK', - 'header' => $this->Socket->parseHeader("Date: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\n"), + 'httpVersion' => 'HTTP/1.x', + 'code' => 200, + 'reasonPhrase' => 'OK', + 'headers' => array('Date' => 'Mon, 16 Apr 2007 04:14:16 GMT', 'Server' => 'CakeHttp Server'), 'body' => "

    Hello World

    \r\n

    It's good to be html

    " ) ), @@ -1017,34 +1005,8 @@ class HttpSocketTest extends CakeTestCase { 'header' => null ), 'expectations' => array( - 'status.code' => 404, - 'header' => array() - ) - ), - 'chunked' => array( - 'response' => array( - 'header' => "Transfer-Encoding: chunked\r\n", - 'body' => "19\r\nThis is a chunked message\r\n0\r\n" - ), - 'expectations' => array( - 'body' => "This is a chunked message", - 'header' => $this->Socket->parseHeader("Transfer-Encoding: chunked\r\n") - ) - ), - 'enitity-header' => array( - 'response' => array( - 'body' => "19\r\nThis is a chunked message\r\n0\r\nFoo: Bar\r\n" - ), - 'expectations' => array( - 'header' => $this->Socket->parseHeader("Transfer-Encoding: chunked\r\nFoo: Bar\r\n") - ) - ), - 'enitity-header-combine' => array( - 'response' => array( - 'header' => "Transfer-Encoding: chunked\r\nFoo: Foobar\r\n" - ), - 'expectations' => array( - 'header' => $this->Socket->parseHeader("Transfer-Encoding: chunked\r\nFoo: Foobar\r\nFoo: Bar\r\n") + 'code' => 404, + 'headers' => array() ) ) ); @@ -1059,8 +1021,7 @@ class HttpSocketTest extends CakeTestCase { $expectations = array_merge($expectations, $test['expectations']); foreach ($expectations as $property => $expectedVal) { - $val = Set::extract($r, $property); - $this->assertEquals($val, $expectedVal, 'Test "' . $name . '": response.' . $property . ' - %s'); + $this->assertEquals($r->{$property}, $expectedVal, 'Test "' . $name . '": response.' . $property . ' - %s'); } foreach (array('status-line', 'header', 'body', 'response') as $field) { @@ -1069,6 +1030,31 @@ class HttpSocketTest extends CakeTestCase { } } +/** + * data provider function for testInvalidParseResponseData + * + * @return array + */ + public static function invalidParseResponseDataProvider() { + return array( + array(array('foo' => 'bar')), + array(true), + array("HTTP Foo\r\nBar: La"), + array('HTTP/1.1 TEST ERROR') + ); + } + +/** + * testInvalidParseResponseData + * + * @dataProvider invalidParseResponseDataProvider + * @expectedException Exception + * return void + */ + public function testInvalidParseResponseData($value) { + $this->Socket->parseResponse($value); + } + /** * testDecodeBody method * From 176da154172c9d7670086ad4dc25733e03912bec Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 02:22:30 -0200 Subject: [PATCH 099/125] Moved the response methods from HttpSocket to HttpResponse. --- cake/libs/http_response.php | 249 +++++++++++++++++ cake/libs/http_socket.php | 176 +----------- cake/tests/cases/libs/http_response.test.php | 236 +++++++++++++++- cake/tests/cases/libs/http_socket.test.php | 272 ------------------- 4 files changed, 486 insertions(+), 447 deletions(-) diff --git a/cake/libs/http_response.php b/cake/libs/http_response.php index f0cc637c8..aea0133ae 100644 --- a/cake/libs/http_response.php +++ b/cake/libs/http_response.php @@ -69,6 +69,16 @@ class HttpResponse implements ArrayAccess { */ public $raw = ''; +/** + * Contructor + * + */ + public function __construct($message = null) { + if ($message !== null) { + $this->parseResponse($message); + } + } + /** * Body content * @@ -105,6 +115,245 @@ class HttpResponse implements ArrayAccess { return $this->code == 200; } +/** + * Parses the given message and breaks it down in parts. + * + * @param string $message Message to parse + * @return void + * @throw Exception + */ + public function parseResponse($message) { + if (!is_string($message)) { + throw new Exception(__('Invalid response.')); + } + + if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) { + throw new Exception(__('Invalid HTTP response.')); + } + + list(, $statusLine, $header) = $match; + $this->raw = $message; + $this->body = (string)substr($message, strlen($match[0])); + + if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) { + $this->httpVersion = $match[1]; + $this->code = $match[2]; + $this->reasonPhrase = $match[3]; + } + + $this->headers = $this->_parseHeader($header); + $transferEncoding = $this->getHeader('Transfer-Encoding'); + $decoded = $this->_decodeBody($this->body, $transferEncoding); + $this->body = $decoded['body']; + + if (!empty($decoded['header'])) { + $this->headers = $this->_parseHeader($this->_buildHeader($this->headers) . $this->_buildHeader($decoded['header'])); + } + + if (!empty($this->headers)) { + $this->cookies = $this->parseCookies($this->headers); + } + } + +/** + * Generic function to decode a $body with a given $encoding. Returns either an array with the keys + * 'body' and 'header' or false on failure. + * + * @param string $body A string continaing the body to decode. + * @param mixed $encoding Can be false in case no encoding is being used, or a string representing the encoding. + * @return mixed Array of response headers and body or false. + */ + protected function _decodeBody($body, $encoding = 'chunked') { + if (!is_string($body)) { + return false; + } + if (empty($encoding)) { + return array('body' => $body, 'header' => false); + } + $decodeMethod = '_decode' . Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body'; + + if (!is_callable(array(&$this, $decodeMethod))) { + return array('body' => $body, 'header' => false); + } + return $this->{$decodeMethod}($body); + } + +/** + * Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as + * a result. + * + * @param string $body A string continaing the chunked body to decode. + * @return mixed Array of response headers and body or false. + * @throws Exception + */ + protected function _decodeChunkedBody($body) { + if (!is_string($body)) { + return false; + } + + $decodedBody = null; + $chunkLength = null; + + while ($chunkLength !== 0) { + if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) { + throw new Exception(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.')); + } + + $chunkSize = 0; + $hexLength = 0; + $chunkExtensionName = ''; + $chunkExtensionValue = ''; + if (isset($match[0])) { + $chunkSize = $match[0]; + } + if (isset($match[1])) { + $hexLength = $match[1]; + } + if (isset($match[2])) { + $chunkExtensionName = $match[2]; + } + if (isset($match[3])) { + $chunkExtensionValue = $match[3]; + } + + $body = substr($body, strlen($chunkSize)); + $chunkLength = hexdec($hexLength); + $chunk = substr($body, 0, $chunkLength); + if (!empty($chunkExtensionName)) { + /** + * @todo See if there are popular chunk extensions we should implement + */ + } + $decodedBody .= $chunk; + if ($chunkLength !== 0) { + $body = substr($body, $chunkLength + strlen("\r\n")); + } + } + + $entityHeader = false; + if (!empty($body)) { + $entityHeader = $this->_parseHeader($body); + } + return array('body' => $decodedBody, 'header' => $entityHeader); + } + +/** + * Parses an array based header. + * + * @param array $header Header as an indexed array (field => value) + * @return array Parsed header + */ + protected function _parseHeader($header) { + if (is_array($header)) { + return $header; + } elseif (!is_string($header)) { + return false; + } + + preg_match_all("/(.+):(.+)(?:(?_unescapeToken($field); + + if (!isset($header[$field])) { + $header[$field] = $value; + } else { + $header[$field] = array_merge((array)$header[$field], (array)$value); + } + } + return $header; + } + +/** + * Parses cookies in response headers. + * + * @param array $header Header array containing one ore more 'Set-Cookie' headers. + * @return mixed Either false on no cookies, or an array of cookies recieved. + * @todo Make this 100% RFC 2965 confirm + */ + public function parseCookies($header) { + if (!isset($header['Set-Cookie'])) { + return false; + } + + $cookies = array(); + foreach ((array)$header['Set-Cookie'] as $cookie) { + if (strpos($cookie, '";"') !== false) { + $cookie = str_replace('";"', "{__cookie_replace__}", $cookie); + $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie)); + } else { + $parts = preg_split('/\;[ \t]*/', $cookie); + } + + list($name, $value) = explode('=', array_shift($parts), 2); + $cookies[$name] = compact('value'); + + foreach ($parts as $part) { + if (strpos($part, '=') !== false) { + list($key, $value) = explode('=', $part); + } else { + $key = $part; + $value = true; + } + + $key = strtolower($key); + if (!isset($cookies[$name][$key])) { + $cookies[$name][$key] = $value; + } + } + } + return $cookies; + } + +/** + * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs) + * + * @param string $token Token to unescape + * @param array $chars + * @return string Unescaped token + * @todo Test $chars parameter + */ + protected function _unescapeToken($token, $chars = null) { + $regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/'; + $token = preg_replace($regex, '\\1', $token); + return $token; + } + +/** + * Gets escape chars according to RFC 2616 (HTTP 1.1 specs). + * + * @param boolean $hex true to get them as HEX values, false otherwise + * @param array $chars + * @return array Escape chars + * @todo Test $chars parameter + */ + protected function _tokenEscapeChars($hex = true, $chars = null) { + if (!empty($chars)) { + $escape = $chars; + } else { + $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " "); + for ($i = 0; $i <= 31; $i++) { + $escape[] = chr($i); + } + $escape[] = chr(127); + } + + if ($hex == false) { + return $escape; + } + $regexChars = ''; + foreach ($escape as $key => $char) { + $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT); + } + return $escape; + } + /** * ArrayAccess - Offset Exists * diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index aa4769319..c226b574f 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -367,7 +367,7 @@ class HttpSocket extends CakeSocket { $this->disconnect(); } - $this->response = $this->_parseResponse($response); + $this->response = new HttpResponse($response); if (!empty($this->response->cookies)) { if (!isset($this->config['request']['cookies'][$Host])) { $this->config['request']['cookies'][$Host] = array(); @@ -566,137 +566,6 @@ class HttpSocket extends CakeSocket { call_user_func("$authClass::proxyAuthentication", $this, &$this->_proxy); } -/** - * Parses the given message and breaks it down in parts. - * - * @param string $message Message to parse - * @return object Parsed message as HttpResponse - */ - protected function _parseResponse($message) { - if (!is_string($message)) { - throw new Exception(__('Invalid response.')); - } - - if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) { - throw new Exception(__('Invalid HTTP response.')); - } - - $response = new HttpResponse(); - - list(, $statusLine, $header) = $match; - $response->raw = $message; - $response->body = (string)substr($message, strlen($match[0])); - - if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) { - $response->httpVersion = $match[1]; - $response->code = $match[2]; - $response->reasonPhrase = $match[3]; - } - - $response->headers = $this->_parseHeader($header); - $transferEncoding = $response->getHeader('Transfer-Encoding'); - $decoded = $this->_decodeBody($response->body, $transferEncoding); - $response->body = $decoded['body']; - - if (!empty($decoded['header'])) { - $response->headers = $this->_parseHeader($this->_buildHeader($response->headers) . $this->_buildHeader($decoded['header'])); - } - - if (!empty($response->headers)) { - $response->cookies = $this->parseCookies($response->headers); - } - - return $response; - } - -/** - * Generic function to decode a $body with a given $encoding. Returns either an array with the keys - * 'body' and 'header' or false on failure. - * - * @param string $body A string continaing the body to decode. - * @param mixed $encoding Can be false in case no encoding is being used, or a string representing the encoding. - * @return mixed Array of response headers and body or false. - */ - protected function _decodeBody($body, $encoding = 'chunked') { - if (!is_string($body)) { - return false; - } - if (empty($encoding)) { - return array('body' => $body, 'header' => false); - } - $decodeMethod = '_decode'.Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body'; - - if (!is_callable(array(&$this, $decodeMethod))) { - if (!$this->quirksMode) { - trigger_error(sprintf(__('HttpSocket::_decodeBody - Unknown encoding: %s. Activate quirks mode to surpress error.'), h($encoding)), E_USER_WARNING); - } - return array('body' => $body, 'header' => false); - } - return $this->{$decodeMethod}($body); - } - -/** - * Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as - * a result. - * - * @param string $body A string continaing the chunked body to decode. - * @return mixed Array of response headers and body or false. - * @throws Exception - */ - protected function _decodeChunkedBody($body) { - if (!is_string($body)) { - return false; - } - - $decodedBody = null; - $chunkLength = null; - - while ($chunkLength !== 0) { - if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) { - if (!$this->quirksMode) { - throw new Exception(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk. Activate quirks mode to do this.')); - } - break; - } - - $chunkSize = 0; - $hexLength = 0; - $chunkExtensionName = ''; - $chunkExtensionValue = ''; - if (isset($match[0])) { - $chunkSize = $match[0]; - } - if (isset($match[1])) { - $hexLength = $match[1]; - } - if (isset($match[2])) { - $chunkExtensionName = $match[2]; - } - if (isset($match[3])) { - $chunkExtensionValue = $match[3]; - } - - $body = substr($body, strlen($chunkSize)); - $chunkLength = hexdec($hexLength); - $chunk = substr($body, 0, $chunkLength); - if (!empty($chunkExtensionName)) { - /** - * @todo See if there are popular chunk extensions we should implement - */ - } - $decodedBody .= $chunk; - if ($chunkLength !== 0) { - $body = substr($body, $chunkLength + strlen("\r\n")); - } - } - - $entityHeader = false; - if (!empty($body)) { - $entityHeader = $this->_parseHeader($body); - } - return array('body' => $decodedBody, 'header' => $entityHeader); - } - /** * Parses and sets the specified URI into current request configuration. * @@ -1002,7 +871,7 @@ class HttpSocket extends CakeSocket { return false; } - preg_match_all("/(.+):(.+)(?:(?lineBreak . "|\$)/Uis", $header, $matches, PREG_SET_ORDER); + preg_match_all("/(.+):(.+)(?:(?HttpResponse = new HttpResponse(); + $this->HttpResponse = new TestHttpResponse(); } /** @@ -102,6 +133,209 @@ class HttpResponseTest extends CakeTestCase { $this->assertTrue($this->HttpResponse->isOk()); } +/** + * testParseResponse method + * + * @return void + */ + public function testParseResponse() { + $tests = array( + 'simple-request' => array( + 'response' => array( + 'status-line' => "HTTP/1.x 200 OK\r\n", + 'header' => "Date: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\n", + 'body' => "

    Hello World

    \r\n

    It's good to be html

    " + ), + 'expectations' => array( + 'httpVersion' => 'HTTP/1.x', + 'code' => 200, + 'reasonPhrase' => 'OK', + 'headers' => array('Date' => 'Mon, 16 Apr 2007 04:14:16 GMT', 'Server' => 'CakeHttp Server'), + 'body' => "

    Hello World

    \r\n

    It's good to be html

    " + ) + ), + 'no-header' => array( + 'response' => array( + 'status-line' => "HTTP/1.x 404 OK\r\n", + 'header' => null + ), + 'expectations' => array( + 'code' => 404, + 'headers' => array() + ) + ) + ); + + $testResponse = array(); + $expectations = array(); + + foreach ($tests as $name => $test) { + $testResponse = array_merge($testResponse, $test['response']); + $testResponse['response'] = $testResponse['status-line'] . $testResponse['header'] . "\r\n" . $testResponse['body']; + $this->HttpResponse->parseResponse($testResponse['response']); + $expectations = array_merge($expectations, $test['expectations']); + + foreach ($expectations as $property => $expectedVal) { + $this->assertEquals($this->HttpResponse->{$property}, $expectedVal, 'Test "' . $name . '": response.' . $property . ' - %s'); + } + + foreach (array('status-line', 'header', 'body', 'response') as $field) { + $this->assertEquals($this->HttpResponse['raw'][$field], $testResponse[$field], 'Test response.raw.' . $field . ': %s'); + } + } + } + +/** + * data provider function for testInvalidParseResponseData + * + * @return array + */ + public static function invalidParseResponseDataProvider() { + return array( + array(array('foo' => 'bar')), + array(true), + array("HTTP Foo\r\nBar: La"), + array('HTTP/1.1 TEST ERROR') + ); + } + +/** + * testInvalidParseResponseData + * + * @dataProvider invalidParseResponseDataProvider + * @expectedException Exception + * return void + */ + public function testInvalidParseResponseData($value) { + $this->HttpResponse->parseResponse($value); + } + +/** + * testDecodeBody method + * + * @return void + */ + public function testDecodeBody() { + $r = $this->HttpResponse->decodeBody(true); + $this->assertEquals($r, false); + + $r = $this->HttpResponse->decodeBody('Foobar', false); + $this->assertEquals($r, array('body' => 'Foobar', 'header' => false)); + + $encoding = 'chunked'; + $sample = array( + 'encoded' => "19\r\nThis is a chunked message\r\n0\r\n", + 'decoded' => array('body' => "This is a chunked message", 'header' => false) + ); + + $r = $this->HttpResponse->decodeBody($sample['encoded'], $encoding); + $this->assertEquals($r, $sample['decoded']); + } + +/** + * testDecodeFooCoded + * + * @return void + */ + public function testDecodeFooCoded() { + $r = $this->HttpResponse->decodeBody(true); + $this->assertEquals($r, false); + + $r = $this->HttpResponse->decodeBody('Foobar', false); + $this->assertEquals($r, array('body' => 'Foobar', 'header' => false)); + + $encoding = 'foo-bar'; + $sample = array( + 'encoded' => '!Foobar!', + 'decoded' => array('body' => '!Foobar!', 'header' => false), + ); + + $r = $this->HttpResponse->decodeBody($sample['encoded'], $encoding); + $this->assertEquals($r, $sample['decoded']); + } + +/** + * testDecodeChunkedBody method + * + * @return void + */ + public function testDecodeChunkedBody() { + $r = $this->HttpResponse->decodeChunkedBody(true); + $this->assertEquals($r, false); + + $encoded = "19\r\nThis is a chunked message\r\n0\r\n"; + $decoded = "This is a chunked message"; + $r = $this->HttpResponse->decodeChunkedBody($encoded); + $this->assertEquals($r['body'], $decoded); + $this->assertEquals($r['header'], false); + + $encoded = "19 \r\nThis is a chunked message\r\n0\r\n"; + $r = $this->HttpResponse->decodeChunkedBody($encoded); + $this->assertEquals($r['body'], $decoded); + + $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n0\r\n"; + $decoded = "This is a chunked message\nThat is cool\n"; + $r = $this->HttpResponse->decodeChunkedBody($encoded); + $this->assertEquals($r['body'], $decoded); + $this->assertEquals($r['header'], false); + + $encoded = "19\r\nThis is a chunked message\r\nE;foo-chunk=5\r\n\nThat is cool\n\r\n0\r\n"; + $r = $this->HttpResponse->decodeChunkedBody($encoded); + $this->assertEquals($r['body'], $decoded); + $this->assertEquals($r['header'], false); + + $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n0\r\nfoo-header: bar\r\ncake: PHP\r\n\r\n"; + $r = $this->HttpResponse->decodeChunkedBody($encoded); + $this->assertEquals($r['body'], $decoded); + $this->assertEquals($r['header'], array('foo-header' => 'bar', 'cake' => 'PHP')); + + $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n"; + $this->expectError(); + $r = $this->HttpResponse->decodeChunkedBody($encoded); + $this->assertEquals($r, false); + } + +/** + * testParseCookies method + * + * @return void + */ + public function testParseCookies() { + $header = array( + 'Set-Cookie' => array( + 'foo=bar', + 'people=jim,jack,johnny";";Path=/accounts', + 'google=not=nice' + ), + 'Transfer-Encoding' => 'chunked', + 'Date' => 'Sun, 18 Nov 2007 18:57:42 GMT', + ); + $cookies = $this->HttpResponse->parseCookies($header); + $expected = array( + 'foo' => array( + 'value' => 'bar' + ), + 'people' => array( + 'value' => 'jim,jack,johnny";"', + 'path' => '/accounts', + ), + 'google' => array( + 'value' => 'not=nice', + ) + ); + $this->assertEqual($cookies, $expected); + + $header['Set-Cookie'][] = 'cakephp=great; Secure'; + $expected['cakephp'] = array('value' => 'great', 'secure' => true); + $cookies = $this->HttpResponse->parseCookies($header); + $this->assertEqual($cookies, $expected); + + $header['Set-Cookie'] = 'foo=bar'; + unset($expected['people'], $expected['cakephp'], $expected['google']); + $cookies = $this->HttpResponse->parseCookies($header); + $this->assertEqual($cookies, $expected); + } + /** * testArrayAccess * diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 9dff42b8f..b6a540759 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -99,16 +99,6 @@ class TestHttpSocket extends HttpSocket { return parent::_buildHeader($header, $mode); } -/** - * Convenience method for testing protected method - * - * @param string $message Message to parse - * @return array Parsed message (with indexed elements such as raw, status, header, body) - */ - public function parseResponse($message) { - return parent::_parseResponse($message); - } - /** * Convenience method for testing protected method * @@ -129,27 +119,6 @@ class TestHttpSocket extends HttpSocket { return parent::_parseQuery($query); } -/** - * Convenience method for testing protected method - * - * @param string $body A string continaing the body to decode - * @param mixed $encoding Can be false in case no encoding is being used, or a string representing the encoding - * @return mixed Array or false - */ - public function decodeBody($body, $encoding = 'chunked') { - return parent::_decodeBody($body, $encoding); - } - -/** - * Convenience method for testing protected method - * - * @param string $body A string continaing the chunked body to decode - * @return mixed Array or false - */ - public function decodeChunkedBody($body) { - return parent::_decodeChunkedBody($body); - } - /** * Convenience method for testing protected method * @@ -191,18 +160,6 @@ class TestHttpSocket extends HttpSocket { return parent::_unescapeToken($token, $chars); } -/** - * Convenience method for testing protected method - * - * @param string $message - * @return object HttpResponse - */ - protected function _parseResponse($message) { - if (!is_string($message)) { - return false; - } - return parent::_parseResponse($message); - } } /** @@ -976,194 +933,6 @@ class HttpSocketTest extends CakeTestCase { $this->RequestSocket->delete('http://www.google.com/', null, array('line' => 'Hey Server')); } -/** - * testParseResponse method - * - * @return void - */ - public function testParseResponse() { - $this->Socket->reset(); - - $tests = array( - 'simple-request' => array( - 'response' => array( - 'status-line' => "HTTP/1.x 200 OK\r\n", - 'header' => "Date: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\n", - 'body' => "

    Hello World

    \r\n

    It's good to be html

    " - ), - 'expectations' => array( - 'httpVersion' => 'HTTP/1.x', - 'code' => 200, - 'reasonPhrase' => 'OK', - 'headers' => array('Date' => 'Mon, 16 Apr 2007 04:14:16 GMT', 'Server' => 'CakeHttp Server'), - 'body' => "

    Hello World

    \r\n

    It's good to be html

    " - ) - ), - 'no-header' => array( - 'response' => array( - 'status-line' => "HTTP/1.x 404 OK\r\n", - 'header' => null - ), - 'expectations' => array( - 'code' => 404, - 'headers' => array() - ) - ) - ); - - $testResponse = array(); - $expectations = array(); - - foreach ($tests as $name => $test) { - $testResponse = array_merge($testResponse, $test['response']); - $testResponse['response'] = $testResponse['status-line'] . $testResponse['header'] . "\r\n" . $testResponse['body']; - $r = $this->Socket->parseResponse($testResponse['response']); - $expectations = array_merge($expectations, $test['expectations']); - - foreach ($expectations as $property => $expectedVal) { - $this->assertEquals($r->{$property}, $expectedVal, 'Test "' . $name . '": response.' . $property . ' - %s'); - } - - foreach (array('status-line', 'header', 'body', 'response') as $field) { - $this->assertEquals($r['raw'][$field], $testResponse[$field], 'Test response.raw.' . $field . ': %s'); - } - } - } - -/** - * data provider function for testInvalidParseResponseData - * - * @return array - */ - public static function invalidParseResponseDataProvider() { - return array( - array(array('foo' => 'bar')), - array(true), - array("HTTP Foo\r\nBar: La"), - array('HTTP/1.1 TEST ERROR') - ); - } - -/** - * testInvalidParseResponseData - * - * @dataProvider invalidParseResponseDataProvider - * @expectedException Exception - * return void - */ - public function testInvalidParseResponseData($value) { - $this->Socket->parseResponse($value); - } - -/** - * testDecodeBody method - * - * @return void - */ - public function testDecodeBody() { - $this->Socket->reset(); - - $r = $this->Socket->decodeBody(true); - $this->assertEquals($r, false); - - $r = $this->Socket->decodeBody('Foobar', false); - $this->assertEquals($r, array('body' => 'Foobar', 'header' => false)); - - $encoding = 'chunked'; - $sample = array( - 'encoded' => "19\r\nThis is a chunked message\r\n0\r\n", - 'decoded' => array('body' => "This is a chunked message", 'header' => false) - ); - - $r = $this->Socket->decodeBody($sample['encoded'], $encoding); - $this->assertEquals($r, $sample['decoded']); - } - -/** - * testDecodeFooCoded - * - * @return void - */ - public function testDecodeFooCoded() { - $this->Socket->reset(); - - $r = $this->Socket->decodeBody(true); - $this->assertEquals($r, false); - - $r = $this->Socket->decodeBody('Foobar', false); - $this->assertEquals($r, array('body' => 'Foobar', 'header' => false)); - - $encoding = 'foo-bar'; - $sample = array( - 'encoded' => '!Foobar!', - 'decoded' => array('body' => '!Foobar!', 'header' => false), - ); - - $this->Socket->quirksMode = true; - $r = $this->Socket->decodeBody($sample['encoded'], $encoding); - $this->assertEquals($r, $sample['decoded']); - $this->Socket->quirksMode = false; - - $this->expectError(); - $r = $this->Socket->decodeBody($sample['encoded'], $encoding); - $this->assertEquals($r, $sample['decoded']); - } - -/** - * testDecodeChunkedBody method - * - * @return void - */ - public function testDecodeChunkedBody() { - $this->Socket->reset(); - - $r = $this->Socket->decodeChunkedBody(true); - $this->assertEquals($r, false); - - $encoded = "19\r\nThis is a chunked message\r\n0\r\n"; - $decoded = "This is a chunked message"; - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], false); - - $encoded = "19 \r\nThis is a chunked message\r\n0\r\n"; - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r['body'], $decoded); - - $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n0\r\n"; - $decoded = "This is a chunked message\nThat is cool\n"; - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], false); - - $encoded = "19\r\nThis is a chunked message\r\nE;foo-chunk=5\r\n\nThat is cool\n\r\n0\r\n"; - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], false); - - $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n0\r\nfoo-header: bar\r\ncake: PHP\r\n\r\n"; - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], array('foo-header' => 'bar', 'cake' => 'PHP')); - - $this->Socket->quirksMode = true; - $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\nfoo-header: bar\r\ncake: PHP\r\n\r\n"; - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], array('foo-header' => 'bar', 'cake' => 'PHP')); - - $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n"; - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r['body'], $decoded); - $this->assertEquals($r['header'], false); - - $this->Socket->quirksMode = false; - $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n"; - $this->expectError(); - $r = $this->Socket->decodeChunkedBody($encoded); - $this->assertEquals($r, false); - } - /** * testBuildRequestLine method * @@ -1627,47 +1396,6 @@ class HttpSocketTest extends CakeTestCase { $this->assertEquals($r, $expected); } -/** - * testParseCookies method - * - * @return void - */ - public function testParseCookies() { - $header = array( - 'Set-Cookie' => array( - 'foo=bar', - 'people=jim,jack,johnny";";Path=/accounts', - 'google=not=nice' - ), - 'Transfer-Encoding' => 'chunked', - 'Date' => 'Sun, 18 Nov 2007 18:57:42 GMT', - ); - $cookies = $this->Socket->parseCookies($header); - $expected = array( - 'foo' => array( - 'value' => 'bar' - ), - 'people' => array( - 'value' => 'jim,jack,johnny";"', - 'path' => '/accounts', - ), - 'google' => array( - 'value' => 'not=nice', - ) - ); - $this->assertEqual($cookies, $expected); - - $header['Set-Cookie'][] = 'cakephp=great; Secure'; - $expected['cakephp'] = array('value' => 'great', 'secure' => true); - $cookies = $this->Socket->parseCookies($header); - $this->assertEqual($cookies, $expected); - - $header['Set-Cookie'] = 'foo=bar'; - unset($expected['people'], $expected['cakephp'], $expected['google']); - $cookies = $this->Socket->parseCookies($header); - $this->assertEqual($cookies, $expected); - } - /** * testBuildCookies method * From 2f64afe44e888a897ad7ea12f6b54f780af7b776 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 02:46:31 -0200 Subject: [PATCH 100/125] Allowing the user change the response class. --- cake/libs/http_socket.php | 13 ++++++- cake/tests/cases/libs/http_socket.test.php | 40 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index c226b574f..a4fea03f3 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -76,6 +76,13 @@ class HttpSocket extends CakeSocket { */ public $response = null; +/** + * Response classname + * + * @var string + */ + public $responseClass = 'HttpResponse'; + /** * Configuration settings for the HttpSocket and the requests * @@ -367,7 +374,11 @@ class HttpSocket extends CakeSocket { $this->disconnect(); } - $this->response = new HttpResponse($response); + if (!App::import('Lib', $this->responseClass)) { + throw new Exception(__('Class %s not found.', $this->responseClass)); + } + $responseClass = $this->responseClass; + $this->response = new $responseClass($response); if (!empty($this->response->cookies)) { if (!isset($this->config['request']['cookies'][$Host])) { $this->config['request']['cookies'][$Host] = array(); diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index b6a540759..45f0350c6 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -51,6 +51,29 @@ class TestAuthentication { } +/** + * CustomResponse + * + */ +class CustomResponse { + +/** + * First 10 chars + * + * @var string + */ + public $first10; + +/** + * Constructor + * + */ + public function __construct($message) { + $this->first10 = substr($message, 0, 10); + } + +} + /** * TestHttpSocket * @@ -659,6 +682,23 @@ class HttpSocketTest extends CakeTestCase { $this->assertEqual($this->Socket->config['request']['cookies'], $expected); } +/** + * testRequestCustomResponse + * + * @return void + */ + public function testRequestCustomResponse() { + $this->Socket->connected = true; + $serverResponse = "HTTP/1.x 200 OK\r\nDate: Mon, 16 Apr 2007 04:14:16 GMT\r\nServer: CakeHttp Server\r\nContent-Type: text/html\r\n\r\n

    This is a test!

    "; + $this->Socket->expects($this->at(1))->method('read')->will($this->returnValue($serverResponse)); + $this->Socket->expects($this->at(2))->method('read')->will($this->returnValue(false)); + + $this->Socket->responseClass = 'CustomResponse'; + $response = $this->Socket->request('http://www.cakephp.org/'); + $this->assertIsA($response, 'CustomResponse'); + $this->assertEqual($response->first10, 'HTTP/1.x 2'); + } + /** * testProxy method * From 37303d9c37abe86fe2d8eeea75b3e9d2fcf5316d Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 02:52:40 -0200 Subject: [PATCH 101/125] HttpResponse::getHeader() is more flexible to accept a custom header list. --- cake/libs/http_response.php | 16 ++++++++++------ cake/tests/cases/libs/http_response.test.php | 3 +++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cake/libs/http_response.php b/cake/libs/http_response.php index aea0133ae..77b7feb02 100644 --- a/cake/libs/http_response.php +++ b/cake/libs/http_response.php @@ -94,11 +94,14 @@ class HttpResponse implements ArrayAccess { * @param string $name Header name * @return mixed String if header exists or null */ - public function getHeader($name) { - if (isset($this->headers[$name])) { - return $this->headers[$name]; + public function getHeader($name, $headers = null) { + if (!is_array($headers)) { + $headers =& $this->headers; } - foreach ($this->headers as $key => $value) { + if (isset($headers[$name])) { + return $headers[$name]; + } + foreach ($headers as $key => $value) { if (strcasecmp($key, $name) == 0) { return $value; } @@ -278,12 +281,13 @@ class HttpResponse implements ArrayAccess { * @todo Make this 100% RFC 2965 confirm */ public function parseCookies($header) { - if (!isset($header['Set-Cookie'])) { + $cookieHeader = $this->getHeader('Set-Cookie', $header); + if (!$cookieHeader) { return false; } $cookies = array(); - foreach ((array)$header['Set-Cookie'] as $cookie) { + foreach ((array)$cookieHeader as $cookie) { if (strpos($cookie, '";"') !== false) { $cookie = str_replace('";"', "{__cookie_replace__}", $cookie); $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie)); diff --git a/cake/tests/cases/libs/http_response.test.php b/cake/tests/cases/libs/http_response.test.php index 54a92e1a4..4f54dc3f7 100644 --- a/cake/tests/cases/libs/http_response.test.php +++ b/cake/tests/cases/libs/http_response.test.php @@ -113,6 +113,9 @@ class HttpResponseTest extends CakeTestCase { $this->assertEqual($this->HttpResponse->getHeader('header'), 'value'); $this->assertEqual($this->HttpResponse->getHeader('Content-Type'), 'text/plain'); $this->assertIdentical($this->HttpResponse->getHeader(0), null); + + $this->assertEqual($this->HttpResponse->getHeader('foo', false), 'Bar'); + $this->assertEqual($this->HttpResponse->getHeader('foo', array('foo' => 'not from class')), 'not from class'); } /** From 9e1c85e627392bae6574962df5502f847d452548 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 9 Dec 2010 23:41:07 -0500 Subject: [PATCH 102/125] Removing auto-start from CakeSession. Lazy starting will be more performant in most cases. --- cake/libs/cake_session.php | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/cake/libs/cake_session.php b/cake/libs/cake_session.php index 91ed52f02..e38f3f243 100644 --- a/cake/libs/cake_session.php +++ b/cake/libs/cake_session.php @@ -151,14 +151,8 @@ class CakeSession { if (($checkAgent === true || $checkAgent === null) && env('HTTP_USER_AGENT') != null) { self::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt')); } - - if ($start === true) { - self::_setPath($base); - self::_setHost(env('HTTP_HOST')); - } - if (isset($_SESSION) || $start === true) { - self::start(); - } + self::_setPath($base); + self::_setHost(env('HTTP_HOST')); } /** @@ -374,12 +368,12 @@ class CakeSession { * @return mixed The value of the session variable */ public static function read($name = null) { - if (is_null($name)) { - return self::__returnSessionVars(); - } if (empty($name)) { return false; } + if (is_null($name)) { + return self::__returnSessionVars(); + } $result = Set::classicExtract($_SESSION, $name); if (!is_null($result)) { From 8eebdffcbb41faba84aa20019b61ea34fcbb4217 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 9 Dec 2010 23:55:38 -0500 Subject: [PATCH 103/125] Updating session to lazy start after the first time an operation has been performed. This should make controllers that only use sessions on some actions perform better. --- cake/libs/cake_session.php | 21 ++++++++++++++++++++- cake/tests/cases/libs/cake_session.test.php | 5 ++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/cake/libs/cake_session.php b/cake/libs/cake_session.php index e38f3f243..a0b44b9cb 100644 --- a/cake/libs/cake_session.php +++ b/cake/libs/cake_session.php @@ -226,6 +226,9 @@ class CakeSession { * @return boolean True if variable is there */ public static function check($name = null) { + if (!self::started() && !self::start()) { + return false; + } if (empty($name)) { return false; } @@ -368,12 +371,15 @@ class CakeSession { * @return mixed The value of the session variable */ public static function read($name = null) { - if (empty($name)) { + if (!self::started() && !self::start()) { return false; } if (is_null($name)) { return self::__returnSessionVars(); } + if (empty($name)) { + return false; + } $result = Set::classicExtract($_SESSION, $name); if (!is_null($result)) { @@ -403,6 +409,9 @@ class CakeSession { * @return void */ public static function watch($var) { + if (!self::started() && !self::start()) { + return false; + } if (empty($var)) { return false; } @@ -418,6 +427,9 @@ class CakeSession { * @return void */ public static function ignore($var) { + if (!self::started() && !self::start()) { + return false; + } if (!in_array($var, self::$watchKeys)) { return; } @@ -438,6 +450,9 @@ class CakeSession { * @return boolean True if the write was successful, false if the write failed */ public static function write($name, $value = null) { + if (!self::started() && !self::start()) { + return false; + } if (empty($name)) { return false; } @@ -666,6 +681,10 @@ class CakeSession { * @return void */ protected static function _checkValid() { + if (!self::started() && !self::start()) { + self::$valid = false; + return false; + } if (self::read('Config')) { $sessionConfig = Configure::read('Session'); diff --git a/cake/tests/cases/libs/cake_session.test.php b/cake/tests/cases/libs/cake_session.test.php index 02fda57e7..889053817 100644 --- a/cake/tests/cases/libs/cake_session.test.php +++ b/cake/tests/cases/libs/cake_session.test.php @@ -305,8 +305,8 @@ class CakeSessionTest extends CakeTestCase { * @return void */ function testId() { - $expected = session_id(); $result = TestCakeSession::id(); + $expected = session_id(); $this->assertEqual($result, $expected); TestCakeSession::id('MySessionId'); @@ -321,10 +321,9 @@ class CakeSessionTest extends CakeTestCase { * @return void */ function testStarted() { - $this->assertTrue(TestCakeSession::started()); - unset($_SESSION); $_SESSION = null; + $this->assertFalse(TestCakeSession::started()); $this->assertTrue(TestCakeSession::start()); $this->assertTrue(TestCakeSession::started()); From 106c1185b4618b5d6fe39226c549d1cc052b3d93 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 10 Dec 2010 22:00:44 -0500 Subject: [PATCH 104/125] Making the id() test pass. --- cake/tests/cases/libs/cake_session.test.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cake/tests/cases/libs/cake_session.test.php b/cake/tests/cases/libs/cake_session.test.php index 889053817..231b74ec9 100644 --- a/cake/tests/cases/libs/cake_session.test.php +++ b/cake/tests/cases/libs/cake_session.test.php @@ -305,13 +305,15 @@ class CakeSessionTest extends CakeTestCase { * @return void */ function testId() { + TestCakeSession::destroy(); + $result = TestCakeSession::id(); $expected = session_id(); - $this->assertEqual($result, $expected); + $this->assertEquals($expected, $result); TestCakeSession::id('MySessionId'); $result = TestCakeSession::id(); - $this->assertEqual($result, 'MySessionId'); + $this->assertEquals('MySessionId', $result); } /** From daf6084cccba6cc4129407c2c5e596191444b4e9 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 10 Dec 2010 22:03:53 -0500 Subject: [PATCH 105/125] Converting assertions to not use compatibility wrappers. --- cake/tests/cases/libs/cake_session.test.php | 84 ++++++++++----------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/cake/tests/cases/libs/cake_session.test.php b/cake/tests/cases/libs/cake_session.test.php index 231b74ec9..2c84254dd 100644 --- a/cake/tests/cases/libs/cake_session.test.php +++ b/cake/tests/cases/libs/cake_session.test.php @@ -136,10 +136,10 @@ class CakeSessionTest extends CakeTestCase { */ function testSessionPath() { TestCakeSession::init('/index.php'); - $this->assertEqual('/', TestCakeSession::$path); + $this->assertEquals(TestCakeSession::$path, '/'); TestCakeSession::init('/sub_dir/index.php'); - $this->assertEqual('/sub_dir/', TestCakeSession::$path); + $this->assertEquals(TestCakeSession::$path, '/sub_dir/'); } /** @@ -150,7 +150,7 @@ class CakeSessionTest extends CakeTestCase { */ function testCakeSessionPathEmpty() { TestCakeSession::init(''); - $this->assertEqual('/', TestCakeSession::$path, 'Session path is empty, with "" as $base needs to be / %s'); + $this->assertEquals(TestCakeSession::$path, '/', 'Session path is empty, with "" as $base needs to be /'); } /** @@ -161,7 +161,7 @@ class CakeSessionTest extends CakeTestCase { */ function testCakeSessionPathContainsQuestion() { TestCakeSession::init('/index.php?'); - $this->assertEqual('/', TestCakeSession::$path); + $this->assertEquals(TestCakeSession::$path, '/'); } /** @@ -173,7 +173,7 @@ class CakeSessionTest extends CakeTestCase { function testSetHost() { TestCakeSession::init(); TestCakeSession::setHost('cakephp.org'); - $this->assertEqual('cakephp.org', TestCakeSession::$host); + $this->assertEquals(TestCakeSession::$host, 'cakephp.org'); } /** @@ -185,7 +185,7 @@ class CakeSessionTest extends CakeTestCase { function testSetHostWithPort() { TestCakeSession::init(); TestCakeSession::setHost('cakephp.org:443'); - $this->assertEqual('cakephp.org', TestCakeSession::$host); + $this->assertEquals(TestCakeSession::$host, 'cakephp.org'); } /** @@ -238,14 +238,14 @@ class CakeSessionTest extends CakeTestCase { function testSimpleRead() { TestCakeSession::write('testing', '1,2,3'); $result = TestCakeSession::read('testing'); - $this->assertEqual($result, '1,2,3'); + $this->assertEquals('1,2,3', $result); TestCakeSession::write('testing', array('1' => 'one', '2' => 'two','3' => 'three')); $result = TestCakeSession::read('testing.1'); - $this->assertEqual($result, 'one'); + $this->assertEquals('one', $result); $result = TestCakeSession::read('testing'); - $this->assertEqual($result, array('1' => 'one', '2' => 'two', '3' => 'three')); + $this->assertEquals(array('1' => 'one', '2' => 'two', '3' => 'three'), $result); $result = TestCakeSession::read(); $this->assertTrue(isset($result['testing'])); @@ -254,7 +254,7 @@ class CakeSessionTest extends CakeTestCase { TestCakeSession::write('This.is.a.deep.array.my.friend', 'value'); $result = TestCakeSession::read('This.is.a.deep.array.my.friend'); - $this->assertEqual('value', $result); + $this->assertEquals($result, 'value'); } /** @@ -340,11 +340,11 @@ class CakeSessionTest extends CakeTestCase { function testError() { TestCakeSession::read('Does.not.exist'); $result = TestCakeSession::error(); - $this->assertEqual($result, "Does.not.exist doesn't exist"); + $this->assertEquals("Does.not.exist doesn't exist", $result); TestCakeSession::delete('Failing.delete'); $result = TestCakeSession::error(); - $this->assertEqual($result, "Failing.delete doesn't exist"); + $this->assertEquals("Failing.delete doesn't exist", $result); } /** @@ -449,7 +449,7 @@ class CakeSessionTest extends CakeTestCase { */ function testCheckKeyWithSpaces() { $this->assertTrue(TestCakeSession::write('Session Test', "test")); - $this->assertEqual(TestCakeSession::check('Session Test'), 'test'); + $this->assertEquals('test', TestCakeSession::check('Session Test')); TestCakeSession::delete('Session Test'); $this->assertTrue(TestCakeSession::write('Session Test.Test Case', "test")); @@ -477,7 +477,7 @@ class CakeSessionTest extends CakeTestCase { $this->assertTrue($result); $result = TestCakeSession::read($key); - $this->assertEqual($result, 'haxored'); + $this->assertEquals('haxored', $result); } /** @@ -488,17 +488,17 @@ class CakeSessionTest extends CakeTestCase { */ function testReadingSavedEmpty() { TestCakeSession::write('SessionTestCase', 0); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 0); + $this->assertEquals(0, TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', '0'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), '0'); + $this->assertEquals('0', TestCakeSession::read('SessionTestCase')); $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0); TestCakeSession::write('SessionTestCase', false); $this->assertFalse(TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', null); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), null); + $this->assertEquals(null, TestCakeSession::read('SessionTestCase')); } /** @@ -542,24 +542,24 @@ class CakeSessionTest extends CakeTestCase { TestCakeSession::start(); TestCakeSession::write('SessionTestCase', 0); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 0); + $this->assertEquals(0, TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', '0'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), '0'); + $this->assertEquals('0', TestCakeSession::read('SessionTestCase')); $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0); TestCakeSession::write('SessionTestCase', false); $this->assertFalse(TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', null); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), null); + $this->assertEquals(null, TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', 'This is a Test'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 'This is a Test'); + $this->assertEquals('This is a Test', TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', 'This is a Test'); TestCakeSession::write('SessionTestCase', 'This was updated'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 'This was updated'); + $this->assertEquals('This was updated', TestCakeSession::read('SessionTestCase')); TestCakeSession::destroy(); $this->assertNull(TestCakeSession::read('SessionTestCase')); @@ -624,24 +624,24 @@ class CakeSessionTest extends CakeTestCase { TestCakeSession::destroy(); TestCakeSession::write('SessionTestCase', 0); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 0); + $this->assertEquals(0, TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', '0'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), '0'); + $this->assertEquals('0', TestCakeSession::read('SessionTestCase')); $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0); TestCakeSession::write('SessionTestCase', false); $this->assertFalse(TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', null); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), null); + $this->assertEquals(null, TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', 'This is a Test'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 'This is a Test'); + $this->assertEquals('This is a Test', TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', 'This is a Test'); TestCakeSession::write('SessionTestCase', 'This was updated'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 'This was updated'); + $this->assertEquals('This was updated', TestCakeSession::read('SessionTestCase')); TestCakeSession::destroy(); $this->assertNull(TestCakeSession::read('SessionTestCase')); @@ -687,23 +687,23 @@ class CakeSessionTest extends CakeTestCase { TestCakeSession::start(); TestCakeSession::write('SessionTestCase', 0); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 0); + $this->assertEquals(0, TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', '0'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), '0'); + $this->assertEquals('0', TestCakeSession::read('SessionTestCase')); $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0); TestCakeSession::write('SessionTestCase', false); $this->assertFalse(TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', null); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), null); + $this->assertEquals(null, TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', 'This is a Test'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 'This is a Test'); + $this->assertEquals('This is a Test', TestCakeSession::read('SessionTestCase')); TestCakeSession::write('SessionTestCase', 'Some additional data'); - $this->assertEqual(TestCakeSession::read('SessionTestCase'), 'Some additional data'); + $this->assertEquals('Some additional data', TestCakeSession::read('SessionTestCase')); TestCakeSession::destroy(); $this->assertNull(TestCakeSession::read('SessionTestCase')); @@ -729,21 +729,21 @@ class CakeSessionTest extends CakeTestCase { TestCakeSession::destroy(); TestCakeSession::write('Test', 'some value'); - $this->assertEqual(CakeSession::$sessionTime, time() + $timeoutSeconds); - $this->assertEqual($_SESSION['Config']['countdown'], 10); - $this->assertEqual($_SESSION['Config']['time'], CakeSession::$sessionTime); - $this->assertEqual(CakeSession::$time, time()); - $this->assertEqual($_SESSION['Config']['time'], time() + $timeoutSeconds); + $this->assertEquals(time() + $timeoutSeconds, CakeSession::$sessionTime); + $this->assertEquals(10, $_SESSION['Config']['countdown']); + $this->assertEquals(CakeSession::$sessionTime, $_SESSION['Config']['time']); + $this->assertEquals(time(), CakeSession::$time); + $this->assertEquals(time() + $timeoutSeconds, $_SESSION['Config']['time']); Configure::write('Session.harden', true); TestCakeSession::destroy(); TestCakeSession::write('Test', 'some value'); - $this->assertEqual(CakeSession::$sessionTime, time() + $timeoutSeconds); - $this->assertEqual($_SESSION['Config']['countdown'], 10); - $this->assertEqual($_SESSION['Config']['time'], CakeSession::$sessionTime); - $this->assertEqual(CakeSession::$time, time()); - $this->assertEqual($_SESSION['Config']['time'], CakeSession::$time + $timeoutSeconds); + $this->assertEquals(time() + $timeoutSeconds, CakeSession::$sessionTime); + $this->assertEquals(10, $_SESSION['Config']['countdown']); + $this->assertEquals(CakeSession::$sessionTime, $_SESSION['Config']['time']); + $this->assertEquals(time(), CakeSession::$time); + $this->assertEquals(CakeSession::$time + $timeoutSeconds, $_SESSION['Config']['time']); } } From bd951791f4429c91502fcfe184039534257f3c9b Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 13 Dec 2010 23:58:42 -0500 Subject: [PATCH 106/125] Removing forced start of sessions now that they are lazily started. --- cake/libs/controller/components/session.php | 11 ----------- cake/libs/view/helpers/session.php | 13 ------------- 2 files changed, 24 deletions(-) diff --git a/cake/libs/controller/components/session.php b/cake/libs/controller/components/session.php index 77ab43a4d..af4474c6c 100644 --- a/cake/libs/controller/components/session.php +++ b/cake/libs/controller/components/session.php @@ -33,17 +33,6 @@ if (!class_exists('cakesession')) { */ class SessionComponent extends Component { -/** - * Constructor automatically starts the session. - * - * @param ComponentCollection $collection A ComponentCollection this component can use to lazy load its components - * @param array $settings Array of configuration settings. - */ - public function __construct(ComponentCollection $collection, $settings = array()) { - parent::__construct($collection, $settings); - CakeSession::start(); - } - /** * Get / Set the userAgent * diff --git a/cake/libs/view/helpers/session.php b/cake/libs/view/helpers/session.php index 0f6aa002d..b12fa3190 100644 --- a/cake/libs/view/helpers/session.php +++ b/cake/libs/view/helpers/session.php @@ -31,19 +31,6 @@ if (!class_exists('CakeSession')) { */ class SessionHelper extends AppHelper { -/** - * Constructor. Starts the session if it has not already been started - * - * @param View $view View instance for this helper - * @param array $settings Settings for the helper. - * @return void - */ - public function __construct(View $view, $settings = array()) { - parent::__construct($view, $settings); - if (!CakeSession::started()) { - CakeSession::start(); - } - } /** * Used to read a session values set in a controller for a key or return values for all keys. * From cf7aae791132a3ca418edad5894f52f14cb86826 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 11:05:37 -0200 Subject: [PATCH 107/125] Removed parseHeader from HttpSocket (it was not used). Moved the tests of parseHeader to HttpResponse. --- cake/libs/http_socket.php | 48 -------- cake/tests/cases/libs/http_response.test.php | 112 +++++++++++++++++++ cake/tests/cases/libs/http_socket.test.php | 106 ------------------ 3 files changed, 112 insertions(+), 154 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index a4fea03f3..cc28ae5fd 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -279,7 +279,6 @@ class HttpSocket extends CakeSocket { $cookies = null; if (is_array($this->request['header'])) { - $this->request['header'] = $this->_parseHeader($this->request['header']); if (!empty($this->request['cookies'])) { $cookies = $this->buildCookies($this->request['cookies']); } @@ -869,39 +868,6 @@ class HttpSocket extends CakeSocket { return $returnHeader; } -/** - * Parses an array based header. - * - * @param array $header Header as an indexed array (field => value) - * @return array Parsed header - */ - protected function _parseHeader($header) { - if (is_array($header)) { - return $header; - } elseif (!is_string($header)) { - return false; - } - - preg_match_all("/(.+):(.+)(?:(?_unescapeToken($field); - - if (!isset($header[$field])) { - $header[$field] = $value; - } else { - $header[$field] = array_merge((array)$header[$field], (array)$value); - } - } - return $header; - } - /** * Builds cookie headers for a request. * @@ -917,20 +883,6 @@ class HttpSocket extends CakeSocket { return $this->_buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic'); } -/** - * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs) - * - * @param string $token Token to unescape - * @param array $chars - * @return string Unescaped token - * @todo Test $chars parameter - */ - protected function _unescapeToken($token, $chars = null) { - $regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/'; - $token = preg_replace($regex, '\\1', $token); - return $token; - } - /** * Escapes a given $token according to RFC 2616 (HTTP 1.1 specs) * diff --git a/cake/tests/cases/libs/http_response.test.php b/cake/tests/cases/libs/http_response.test.php index 4f54dc3f7..63892535c 100644 --- a/cake/tests/cases/libs/http_response.test.php +++ b/cake/tests/cases/libs/http_response.test.php @@ -27,6 +27,16 @@ App::import('Core', 'HttpResponse'); */ class TestHttpResponse extends HttpResponse { +/** + * Convenience method for testing protected method + * + * @param array $header Header as an indexed array (field => value) + * @return array Parsed header + */ + public function parseHeader($header) { + return parent::_parseHeader($header); + } + /** * Convenience method for testing protected method * @@ -48,6 +58,26 @@ class TestHttpResponse extends HttpResponse { return parent::_decodeChunkedBody($body); } +/** + * Convenience method for testing protected method + * + * @param string $token Token to unescape + * @return string Unescaped token + */ + public function unescapeToken($token, $chars = null) { + return parent::_unescapeToken($token, $chars); + } + +/** + * Convenience method for testing protected method + * + * @param boolean $hex true to get them as HEX values, false otherwise + * @return array Escape chars + */ + public function tokenEscapeChars($hex = true, $chars = null) { + return parent::_tokenEscapeChars($hex, $chars); + } + } /** @@ -136,6 +166,65 @@ class HttpResponseTest extends CakeTestCase { $this->assertTrue($this->HttpResponse->isOk()); } +/** + * Test that HttpSocket::parseHeader can take apart a given (and valid) $header string and turn it into an array. + * + * @return void + */ + public function testParseHeader() { + $r = $this->HttpResponse->parseHeader(array('foo' => 'Bar', 'fOO-bAr' => 'quux')); + $this->assertEquals($r, array('foo' => 'Bar', 'fOO-bAr' => 'quux')); + + $r = $this->HttpResponse->parseHeader(true); + $this->assertEquals($r, false); + + $header = "Host: cakephp.org\t\r\n"; + $r = $this->HttpResponse->parseHeader($header); + $expected = array( + 'Host' => 'cakephp.org' + ); + $this->assertEquals($r, $expected); + + $header = "Date:Sat, 07 Apr 2007 10:10:25 GMT\r\nX-Powered-By: PHP/5.1.2\r\n"; + $r = $this->HttpResponse->parseHeader($header); + $expected = array( + 'Date' => 'Sat, 07 Apr 2007 10:10:25 GMT', + 'X-Powered-By' => 'PHP/5.1.2' + ); + $this->assertEquals($r, $expected); + + $header = "people: Jim,John\r\nfoo-LAND: Bar\r\ncAKe-PHP: rocks\r\n"; + $r = $this->HttpResponse->parseHeader($header); + $expected = array( + 'people' => 'Jim,John', + 'foo-LAND' => 'Bar', + 'cAKe-PHP' => 'rocks' + ); + $this->assertEquals($r, $expected); + + $header = "People: Jim,John,Tim\r\nPeople: Lisa,Tina,Chelsea\r\n"; + $r = $this->HttpResponse->parseHeader($header); + $expected = array( + 'People' => array('Jim,John,Tim', 'Lisa,Tina,Chelsea') + ); + $this->assertEquals($r, $expected); + + $header = "Multi-Line: I am a \r\nmulti line\t\r\nfield value.\r\nSingle-Line: I am not\r\n"; + $r = $this->HttpResponse->parseHeader($header); + $expected = array( + 'Multi-Line' => "I am a\r\nmulti line\r\nfield value.", + 'Single-Line' => 'I am not' + ); + $this->assertEquals($r, $expected); + + $header = "Esc\"@\"ped: value\r\n"; + $r = $this->HttpResponse->parseHeader($header); + $expected = array( + 'Esc@ped' => 'value' + ); + $this->assertEquals($r, $expected); + } + /** * testParseResponse method * @@ -339,6 +428,29 @@ class HttpResponseTest extends CakeTestCase { $this->assertEqual($cookies, $expected); } +/** + * Test that escaped token strings are properly unescaped by HttpSocket::unescapeToken + * + * @return void + */ + public function testUnescapeToken() { + $this->assertEquals($this->HttpResponse->unescapeToken('Foo'), 'Foo'); + + $escape = $this->HttpResponse->tokenEscapeChars(false); + foreach ($escape as $char) { + $token = 'My-special-"' . $char . '"-Token'; + $unescapedToken = $this->HttpResponse->unescapeToken($token); + $expectedToken = 'My-special-' . $char . '-Token'; + + $this->assertEquals($unescapedToken, $expectedToken, 'Test token unescaping for ASCII '.ord($char)); + } + + $token = 'Extreme-":"Token-" "-""""@"-test'; + $escapedToken = $this->HttpResponse->unescapeToken($token); + $expectedToken = 'Extreme-:Token- -"@-test'; + $this->assertEquals($expectedToken, $escapedToken); + } + /** * testArrayAccess * diff --git a/cake/tests/cases/libs/http_socket.test.php b/cake/tests/cases/libs/http_socket.test.php index 45f0350c6..cefd649e2 100644 --- a/cake/tests/cases/libs/http_socket.test.php +++ b/cake/tests/cases/libs/http_socket.test.php @@ -122,16 +122,6 @@ class TestHttpSocket extends HttpSocket { return parent::_buildHeader($header, $mode); } -/** - * Convenience method for testing protected method - * - * @param array $header Header as an indexed array (field => value) - * @return array Parsed header - */ - public function parseHeader($header) { - return parent::_parseHeader($header); - } - /** * Convenience method for testing protected method * @@ -173,16 +163,6 @@ class TestHttpSocket extends HttpSocket { return parent::_escapeToken($token, $chars); } -/** - * Convenience method for testing protected method - * - * @param string $token Token to unescape - * @return string Unescaped token - */ - public function unescapeToken($token, $chars = null) { - return parent::_unescapeToken($token, $chars); - } - } /** @@ -1375,67 +1355,6 @@ class HttpSocketTest extends CakeTestCase { } -/** - * Test that HttpSocket::parseHeader can take apart a given (and valid) $header string and turn it into an array. - * - * @return void - */ - public function testParseHeader() { - $this->Socket->reset(); - - $r = $this->Socket->parseHeader(array('foo' => 'Bar', 'fOO-bAr' => 'quux')); - $this->assertEquals($r, array('foo' => 'Bar', 'fOO-bAr' => 'quux')); - - $r = $this->Socket->parseHeader(true); - $this->assertEquals($r, false); - - $header = "Host: cakephp.org\t\r\n"; - $r = $this->Socket->parseHeader($header); - $expected = array( - 'Host' => 'cakephp.org' - ); - $this->assertEquals($r, $expected); - - $header = "Date:Sat, 07 Apr 2007 10:10:25 GMT\r\nX-Powered-By: PHP/5.1.2\r\n"; - $r = $this->Socket->parseHeader($header); - $expected = array( - 'Date' => 'Sat, 07 Apr 2007 10:10:25 GMT', - 'X-Powered-By' => 'PHP/5.1.2' - ); - $this->assertEquals($r, $expected); - - $header = "people: Jim,John\r\nfoo-LAND: Bar\r\ncAKe-PHP: rocks\r\n"; - $r = $this->Socket->parseHeader($header); - $expected = array( - 'people' => 'Jim,John', - 'foo-LAND' => 'Bar', - 'cAKe-PHP' => 'rocks' - ); - $this->assertEquals($r, $expected); - - $header = "People: Jim,John,Tim\r\nPeople: Lisa,Tina,Chelsea\r\n"; - $r = $this->Socket->parseHeader($header); - $expected = array( - 'People' => array('Jim,John,Tim', 'Lisa,Tina,Chelsea') - ); - $this->assertEquals($r, $expected); - - $header = "Multi-Line: I am a \r\nmulti line\t\r\nfield value.\r\nSingle-Line: I am not\r\n"; - $r = $this->Socket->parseHeader($header); - $expected = array( - 'Multi-Line' => "I am a\r\nmulti line\r\nfield value.", - 'Single-Line' => 'I am not' - ); - $this->assertEquals($r, $expected); - - $header = "Esc\"@\"ped: value\r\n"; - $r = $this->Socket->parseHeader($header); - $expected = array( - 'Esc@ped' => 'value' - ); - $this->assertEquals($r, $expected); - } - /** * testBuildCookies method * @@ -1507,31 +1426,6 @@ class HttpSocketTest extends CakeTestCase { $this->assertEquals($expectedToken, $escapedToken); } -/** - * Test that escaped token strings are properly unescaped by HttpSocket::unescapeToken - * - * @return void - */ - public function testUnescapeToken() { - $this->Socket->reset(); - - $this->assertEquals($this->Socket->unescapeToken('Foo'), 'Foo'); - - $escape = $this->Socket->tokenEscapeChars(false); - foreach ($escape as $char) { - $token = 'My-special-"' . $char . '"-Token'; - $unescapedToken = $this->Socket->unescapeToken($token); - $expectedToken = 'My-special-' . $char . '-Token'; - - $this->assertEquals($unescapedToken, $expectedToken, 'Test token unescaping for ASCII '.ord($char)); - } - - $token = 'Extreme-":"Token-" "-""""@"-test'; - $escapedToken = $this->Socket->unescapeToken($token); - $expectedToken = 'Extreme-:Token- -"@-test'; - $this->assertEquals($expectedToken, $escapedToken); - } - /** * This tests asserts HttpSocket::reset() resets a HttpSocket instance to it's initial state (before Object::__construct * got executed) From 2cbece678495273aa5504b1362b5f252309dc7e9 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 11:11:36 -0200 Subject: [PATCH 108/125] Removed the lineBreak attribute, this is fixed in RFC. --- cake/libs/http_socket.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index cc28ae5fd..a521ea9c5 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -104,13 +104,6 @@ class HttpSocket extends CakeSocket { ) ); -/** - * String that represents a line break. - * - * @var string - */ - public $lineBreak = "\r\n"; - /** * Authentication settings * @@ -809,7 +802,7 @@ class HttpSocket extends CakeSocket { if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) { throw new Exception(sprintf(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.'), join(',', $asteriskMethods))); } - return $request['method'] . ' ' . $request['uri'] . ' ' . $versionToken . $this->lineBreak; + return $request['method'] . ' ' . $request['uri'] . ' ' . $versionToken . "\r\n"; } /** @@ -862,7 +855,7 @@ class HttpSocket extends CakeSocket { $contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content); $field = $this->_escapeToken($field); - $returnHeader .= $field . ': ' . $contents . $this->lineBreak; + $returnHeader .= $field . ': ' . $contents . "\r\n"; } } return $returnHeader; From 296aef2c112ff8c6d6783d282e22895ef86e125d Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 14 Dec 2010 11:13:44 -0200 Subject: [PATCH 109/125] Removed the import. It is called in request. --- cake/libs/http_socket.php | 1 - 1 file changed, 1 deletion(-) diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index a521ea9c5..a5e66964a 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -19,7 +19,6 @@ */ App::import('Core', 'CakeSocket'); App::import('Core', 'Router'); -App::import('Lib', 'HttpResponse'); /** * Cake network socket connection class. From 9fa1bec0cb4605ffdc00002b4d9e7fe4b039ae67 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 14 Dec 2010 18:21:39 -0800 Subject: [PATCH 110/125] Move Controller::paginate() into PaginatorComponent --- cake/libs/controller/components/paginator.php | 251 +++++++++ cake/libs/controller/controller.php | 219 +------- cake/libs/route/cake_route.php | 8 +- cake/libs/router.php | 28 +- .../controller/components/paginator.test.php | 485 ++++++++++++++++++ .../cases/libs/controller/controller.test.php | 373 ++------------ cake/tests/cases/libs/router.test.php | 107 ++++ 7 files changed, 910 insertions(+), 561 deletions(-) create mode 100644 cake/libs/controller/components/paginator.php create mode 100644 cake/tests/cases/libs/controller/components/paginator.test.php diff --git a/cake/libs/controller/components/paginator.php b/cake/libs/controller/components/paginator.php new file mode 100644 index 000000000..cb1bf7f0e --- /dev/null +++ b/cake/libs/controller/components/paginator.php @@ -0,0 +1,251 @@ + 1, 'limit' => 20), (array)$settings); + $this->Controller = $collection->getController(); + parent::__construct($collection, $settings); + } + +/** + * Handles automatic pagination of model records. + * + * @param mixed $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel') + * @param mixed $scope Conditions to use while paginating + * @param array $whitelist List of allowed options for paging + * @return array Model query results + */ + public function paginate($object = null, $scope = array(), $whitelist = array()) { + if (is_array($object)) { + $whitelist = $scope; + $scope = $object; + $object = null; + } + $assoc = null; + + if (is_string($object)) { + $assoc = null; + if (strpos($object, '.') !== false) { + list($object, $assoc) = pluginSplit($object); + } + + if ($assoc && isset($this->Controller->{$object}->{$assoc})) { + $object = $this->Controller->{$object}->{$assoc}; + } elseif ( + $assoc && isset($this->Controller->{$this->Controller->modelClass}) && + isset($this->Controller->{$this->Controller->modelClass}->{$assoc} + )) { + $object = $this->Controller->{$this->Controller->modelClass}->{$assoc}; + } elseif (isset($this->Controller->{$object})) { + $object = $this->Controller->{$object}; + } elseif ( + isset($this->Controller->{$this->Controller->modelClass}) && isset($this->Controller->{$this->Controller->modelClass}->{$object} + )) { + $object = $this->Controller->{$this->Controller->modelClass}->{$object}; + } + } elseif (empty($object) || $object === null) { + if (isset($this->Controller->{$this->Controller->modelClass})) { + $object = $this->Controller->{$this->Controller->modelClass}; + } else { + $className = null; + $name = $this->Controller->uses[0]; + if (strpos($this->Controller->uses[0], '.') !== false) { + list($name, $className) = explode('.', $this->Controller->uses[0]); + } + if ($className) { + $object = $this->Controller->{$className}; + } else { + $object = $this->Controller->{$name}; + } + } + } + + if (!is_object($object)) { + throw new MissingModelException($object); + } + $options = array_merge($this->Controller->request->params, $this->Controller->params['url'], $this->Controller->passedArgs); + + if (isset($this->settings[$object->alias])) { + $defaults = $this->settings[$object->alias]; + } else { + $defaults = $this->settings; + } + + if (isset($options['show'])) { + $options['limit'] = $options['show']; + } + + if (isset($options['sort'])) { + $direction = null; + if (isset($options['direction'])) { + $direction = strtolower($options['direction']); + } + if ($direction != 'asc' && $direction != 'desc') { + $direction = 'asc'; + } + $options['order'] = array($options['sort'] => $direction); + } + + if (!empty($options['order']) && is_array($options['order'])) { + $alias = $object->alias ; + $key = $field = key($options['order']); + + if (strpos($key, '.') !== false) { + list($alias, $field) = explode('.', $key); + } + $value = $options['order'][$key]; + unset($options['order'][$key]); + + if ($object->hasField($field)) { + $options['order'][$alias . '.' . $field] = $value; + } elseif ($object->hasField($field, true)) { + $options['order'][$field] = $value; + } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field)) { + $options['order'][$alias . '.' . $field] = $value; + } + } + $vars = array('fields', 'order', 'limit', 'page', 'recursive'); + $keys = array_keys($options); + $count = count($keys); + + for ($i = 0; $i < $count; $i++) { + if (!in_array($keys[$i], $vars, true)) { + unset($options[$keys[$i]]); + } + if (empty($whitelist) && ($keys[$i] === 'fields' || $keys[$i] === 'recursive')) { + unset($options[$keys[$i]]); + } elseif (!empty($whitelist) && !in_array($keys[$i], $whitelist)) { + unset($options[$keys[$i]]); + } + } + $conditions = $fields = $order = $limit = $page = $recursive = null; + + if (!isset($defaults['conditions'])) { + $defaults['conditions'] = array(); + } + + $type = 'all'; + + if (isset($defaults[0])) { + $type = $defaults[0]; + unset($defaults[0]); + } + + $options = array_merge(array('page' => 1, 'limit' => 20), $defaults, $options); + $options['limit'] = (int) $options['limit']; + if (empty($options['limit']) || $options['limit'] < 1) { + $options['limit'] = 1; + } + + extract($options); + + if (is_array($scope) && !empty($scope)) { + $conditions = array_merge($conditions, $scope); + } elseif (is_string($scope)) { + $conditions = array($conditions, $scope); + } + if ($recursive === null) { + $recursive = $object->recursive; + } + + $extra = array_diff_key($defaults, compact( + 'conditions', 'fields', 'order', 'limit', 'page', 'recursive' + )); + if ($type !== 'all') { + $extra['type'] = $type; + } + + if (method_exists($object, 'paginateCount')) { + $count = $object->paginateCount($conditions, $recursive, $extra); + } else { + $parameters = compact('conditions'); + if ($recursive != $object->recursive) { + $parameters['recursive'] = $recursive; + } + $count = $object->find('count', array_merge($parameters, $extra)); + } + $pageCount = intval(ceil($count / $limit)); + + if ($page === 'last' || $page >= $pageCount) { + $options['page'] = $page = $pageCount; + } elseif (intval($page) < 1) { + $options['page'] = $page = 1; + } + $page = $options['page'] = (integer)$page; + + if (method_exists($object, 'paginate')) { + $results = $object->paginate( + $conditions, $fields, $order, $limit, $page, $recursive, $extra + ); + } else { + $parameters = compact('conditions', 'fields', 'order', 'limit', 'page'); + if ($recursive != $object->recursive) { + $parameters['recursive'] = $recursive; + } + $results = $object->find($type, array_merge($parameters, $extra)); + } + $paging = array( + 'page' => $page, + 'current' => count($results), + 'count' => $count, + 'prevPage' => ($page > 1), + 'nextPage' => ($count > ($page * $limit)), + 'pageCount' => $pageCount, + 'defaults' => array_merge(array('limit' => 20, 'step' => 1), $defaults), + 'options' => $options + ); + if (!isset($this->Controller->request['paging'])) { + $this->Controller->request['paging'] = array(); + } + $this->Controller->request['paging'] = array_merge( + (array)$this->Controller->request['paging'], + array($object->alias => $paging) + ); + + if (!in_array('Paginator', $this->Controller->helpers) && !array_key_exists('Paginator', $this->Controller->helpers)) { + $this->Controller->helpers[] = 'Paginator'; + } + return $results; + } +} \ No newline at end of file diff --git a/cake/libs/controller/controller.php b/cake/libs/controller/controller.php index 7bc58f024..9afc3e315 100644 --- a/cake/libs/controller/controller.php +++ b/cake/libs/controller/controller.php @@ -94,26 +94,6 @@ class Controller extends Object { */ protected $_responseClass = 'CakeResponse'; -/** - * Holds pagination defaults for controller actions. The keys that can be included - * in this array are: 'conditions', 'fields', 'order', 'limit', 'page', and 'recursive', - * similar to the keys in the second parameter of Model::find(). - * - * Pagination defaults can also be supplied in a model-by-model basis by using - * the name of the model as a key for a pagination array: - * - * {{{ - * public $paginate = array( - * 'Post' => array(...), - * 'Comment' => array(...) - * ); - * }}} - * - * @var array - * @link http://book.cakephp.org/view/1231/Pagination - */ - public $paginate = array('limit' => 20, 'page' => 1, 'maxLimit' => 100); - /** * The name of the views subfolder containing views for this controller. * @@ -362,6 +342,8 @@ class Controller extends Object { return isset($this->request->params['action']) ? $this->request->params['action'] : ''; case 'params': return $this->request; + case 'paginate': + return $this->Components->load('Paginator')->settings; } return null; } @@ -382,6 +364,8 @@ class Controller extends Object { return $this->request->params['action'] = $value; case 'params': return $this->request->params = $value; + case 'paginate': + return $this->Components->load('Paginator')->settings = $value; } return $this->{$name} = $value; } @@ -961,201 +945,10 @@ class Controller extends Object { * @param array $whitelist List of allowed options for paging * @return array Model query results * @link http://book.cakephp.org/view/1232/Controller-Setup + * @deprecated Use PaginatorComponent instead */ public function paginate($object = null, $scope = array(), $whitelist = array()) { - if (is_array($object)) { - $whitelist = $scope; - $scope = $object; - $object = null; - } - $assoc = null; - - if (is_string($object)) { - $assoc = null; - if (strpos($object, '.') !== false) { - list($object, $assoc) = pluginSplit($object); - } - - if ($assoc && isset($this->{$object}->{$assoc})) { - $object = $this->{$object}->{$assoc}; - } elseif ( - $assoc && isset($this->{$this->modelClass}) && - isset($this->{$this->modelClass}->{$assoc} - )) { - $object = $this->{$this->modelClass}->{$assoc}; - } elseif (isset($this->{$object})) { - $object = $this->{$object}; - } elseif ( - isset($this->{$this->modelClass}) && isset($this->{$this->modelClass}->{$object} - )) { - $object = $this->{$this->modelClass}->{$object}; - } - } elseif (empty($object) || $object === null) { - if (isset($this->{$this->modelClass})) { - $object = $this->{$this->modelClass}; - } else { - $className = null; - $name = $this->uses[0]; - if (strpos($this->uses[0], '.') !== false) { - list($name, $className) = explode('.', $this->uses[0]); - } - if ($className) { - $object = $this->{$className}; - } else { - $object = $this->{$name}; - } - } - } - - if (!is_object($object)) { - trigger_error(sprintf( - __('Controller::paginate() - can\'t find model %1$s in controller %2$sController'), $object, $this->name - ), E_USER_WARNING); - return array(); - } - $options = array_merge($this->request->params, $this->request->query, $this->passedArgs); - - if (isset($this->paginate[$object->alias])) { - $defaults = $this->paginate[$object->alias]; - } else { - $defaults = $this->paginate; - } - - if (isset($options['show'])) { - $options['limit'] = $options['show']; - } - - if (isset($options['sort'])) { - $direction = null; - if (isset($options['direction'])) { - $direction = strtolower($options['direction']); - } - if ($direction != 'asc' && $direction != 'desc') { - $direction = 'asc'; - } - $options['order'] = array($options['sort'] => $direction); - } - - if (!empty($options['order']) && is_array($options['order'])) { - $alias = $object->alias ; - $key = $field = key($options['order']); - - if (strpos($key, '.') !== false) { - list($alias, $field) = explode('.', $key); - } - $value = $options['order'][$key]; - unset($options['order'][$key]); - - if ($object->hasField($field)) { - $options['order'][$alias . '.' . $field] = $value; - } elseif ($object->hasField($field, true)) { - $options['order'][$field] = $value; - } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field)) { - $options['order'][$alias . '.' . $field] = $value; - } - } - $vars = array('fields', 'order', 'limit', 'page', 'recursive'); - $keys = array_keys($options); - $count = count($keys); - - for ($i = 0; $i < $count; $i++) { - if (!in_array($keys[$i], $vars, true)) { - unset($options[$keys[$i]]); - } - if (empty($whitelist) && ($keys[$i] === 'fields' || $keys[$i] === 'recursive')) { - unset($options[$keys[$i]]); - } elseif (!empty($whitelist) && !in_array($keys[$i], $whitelist)) { - unset($options[$keys[$i]]); - } - } - $conditions = $fields = $order = $limit = $page = $recursive = null; - - if (!isset($defaults['conditions'])) { - $defaults['conditions'] = array(); - } - - $type = 'all'; - - if (isset($defaults[0])) { - $type = $defaults[0]; - unset($defaults[0]); - } - - $options = array_merge(array('page' => 1, 'limit' => 20, 'maxLimit' => 100), $defaults, $options); - $options['limit'] = min((int)$options['limit'], $options['maxLimit']); - if (empty($options['limit']) || $options['limit'] < 1) { - $options['limit'] = 1; - } - - extract($options); - - if (is_array($scope) && !empty($scope)) { - $conditions = array_merge($conditions, $scope); - } elseif (is_string($scope)) { - $conditions = array($conditions, $scope); - } - if ($recursive === null) { - $recursive = $object->recursive; - } - - $extra = array_diff_key($defaults, compact( - 'conditions', 'fields', 'order', 'limit', 'page', 'recursive' - )); - if ($type !== 'all') { - $extra['type'] = $type; - } - - if (method_exists($object, 'paginateCount')) { - $count = $object->paginateCount($conditions, $recursive, $extra); - } else { - $parameters = compact('conditions'); - if ($recursive != $object->recursive) { - $parameters['recursive'] = $recursive; - } - $count = $object->find('count', array_merge($parameters, $extra)); - } - $pageCount = intval(ceil($count / $limit)); - - if ($page === 'last' || $page >= $pageCount) { - $options['page'] = $page = $pageCount; - } elseif (intval($page) < 1) { - $options['page'] = $page = 1; - } - $page = $options['page'] = (int)$page; - - if (method_exists($object, 'paginate')) { - $results = $object->paginate( - $conditions, $fields, $order, $limit, $page, $recursive, $extra - ); - } else { - $parameters = compact('conditions', 'fields', 'order', 'limit', 'page'); - if ($recursive != $object->recursive) { - $parameters['recursive'] = $recursive; - } - $results = $object->find($type, array_merge($parameters, $extra)); - } - $paging = array( - 'page' => $page, - 'current' => count($results), - 'count' => $count, - 'prevPage' => ($page > 1), - 'nextPage' => ($count > ($page * $limit)), - 'pageCount' => $pageCount, - 'defaults' => array_merge(array('limit' => 20, 'step' => 1), $defaults), - 'options' => $options - ); - if (!isset($this->request->params['paging'])) { - $this->request->params['paging'] = array(); - } - $this->request->params['paging'] = array_merge( - (array)$this->request->params['paging'], - array($object->alias => $paging) - ); - - if (!in_array('Paginator', $this->helpers) && !array_key_exists('Paginator', $this->helpers)) { - $this->helpers[] = 'Paginator'; - } - return $results; + return $this->Components->load('Paginator', $this->paginate)->paginate($object, $scope, $whitelist); } /** diff --git a/cake/libs/route/cake_route.php b/cake/libs/route/cake_route.php index 706323f3a..979f90dcf 100644 --- a/cake/libs/route/cake_route.php +++ b/cake/libs/route/cake_route.php @@ -343,7 +343,13 @@ class CakeRoute { if (!empty($params['named']) && is_array($params['named'])) { $named = array(); foreach ($params['named'] as $key => $value) { - $named[] = $key . $separator . $value; + if (is_array($value)) { + foreach ($value as $namedKey => $namedValue) { + $named[] = $key . "[$namedKey]" . $separator . $namedValue; + } + } else { + $named[] = $key . $separator . $value; + } } $params['pass'] = $params['pass'] . '/' . implode('/', $named); } diff --git a/cake/libs/router.php b/cake/libs/router.php index 010511cb2..91261c6ce 100644 --- a/cake/libs/router.php +++ b/cake/libs/router.php @@ -937,8 +937,15 @@ class Router { } if (!empty($named)) { - foreach ($named as $name => $value) { - $output .= '/' . $name . self::$named['separator'] . $value; + foreach ($named as $name => $value) { + if (is_array($value)) { + $flattend = Set::flatten($value, ']['); + foreach ($flattend as $namedKey => $namedValue) { + $output .= '/' . $name . "[$namedKey]" . self::$named['separator'] . $namedValue; + } + } else { + $output .= '/' . $name . self::$named['separator'] . $value; + } } } return $output; @@ -1202,7 +1209,22 @@ class Router { if ($passIt) { $pass[] = $param; } else { - $named[$key] = $val; + if (preg_match_all('/\[([A-Za-z0-9_-]+)?\]/', $key, $matches, PREG_SET_ORDER)) { + $matches = array_reverse($matches); + $key = array_shift(explode('[', $key)); + $arr = $val; + foreach ($matches as $match) { + if (empty($match[1])) { + $arr = array($arr); + } else { + $arr = array( + $match[1] => $arr + ); + } + } + $val = $arr; + } + $named = array_merge_recursive($named, array($key => $val)); } } else { $pass[] = $param; diff --git a/cake/tests/cases/libs/controller/components/paginator.test.php b/cake/tests/cases/libs/controller/components/paginator.test.php new file mode 100644 index 000000000..eebdd3304 --- /dev/null +++ b/cake/tests/cases/libs/controller/components/paginator.test.php @@ -0,0 +1,485 @@ + + * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests + * @package cake + * @subpackage cake.cake.tests.cases.libs.controller.components + * @since CakePHP(tm) v 2.0 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ +App::import('Controller', 'Controller', false); +App::import('Core', array('CakeRequest', 'CakeResponse')); + +/** + * PaginatorTestController class + * + * @package cake + * @subpackage cake.tests.cases.libs.controller.components + */ +class PaginatorTestController extends Controller { +/** + * name property + * + * @var string 'PaginatorTest' + * @access public + */ + public $name = 'PaginatorTest'; + +/** + * uses property + * + * @var array + * @access public + */ + //public $uses = null; + +/** + * components property + * + * @var array + * @access public + */ + public $components = array('Paginator'); +} + +/** + * ControllerPost class + * + * @package cake + * @subpackage cake.tests.cases.libs.controller.components + */ +class ControllerPost extends CakeTestModel { + +/** + * name property + * + * @var string 'ControllerPost' + * @access public + */ + public $name = 'ControllerPost'; + +/** + * useTable property + * + * @var string 'posts' + * @access public + */ + public $useTable = 'posts'; + +/** + * invalidFields property + * + * @var array + * @access public + */ + public $invalidFields = array('name' => 'error_msg'); + +/** + * lastQuery property + * + * @var mixed null + * @access public + */ + public $lastQuery = null; + +/** + * beforeFind method + * + * @param mixed $query + * @access public + * @return void + */ + function beforeFind($query) { + $this->lastQuery = $query; + } + +/** + * find method + * + * @param mixed $type + * @param array $options + * @access public + * @return void + */ + function find($type, $options = array()) { + if ($type == 'popular') { + $conditions = array($this->name . '.' . $this->primaryKey .' > ' => '1'); + $options = Set::merge($options, compact('conditions')); + return parent::find('all', $options); + } + return parent::find($type, $options); + } +} + +/** + * ControllerPaginateModel class + * + * @package cake + * @subpackage cake.tests.cases.libs.controller.components + */ +class ControllerPaginateModel extends CakeTestModel { + +/** + * name property + * + * @var string 'ControllerPaginateModel' + * @access public + */ + public $name = 'ControllerPaginateModel'; + +/** + * useTable property + * + * @var string 'comments' + * @access public + */ + public $useTable = 'comments'; + +/** + * paginate method + * + * @return void + */ + public function paginate($conditions, $fields, $order, $limit, $page, $recursive, $extra) { + $this->extra = $extra; + } + +/** + * paginateCount + * + * @access public + * @return void + */ + function paginateCount($conditions, $recursive, $extra) { + $this->extraCount = $extra; + } +} + +/** + * ControllerComment class + * + * @package cake + * @subpackage cake.tests.cases.libs.controller.components + */ +class ControllerComment extends CakeTestModel { + +/** + * name property + * + * @var string 'Comment' + * @access public + */ + public $name = 'Comment'; + +/** + * useTable property + * + * @var string 'comments' + * @access public + */ + public $useTable = 'comments'; + +/** + * alias property + * + * @var string 'ControllerComment' + * @access public + */ + public $alias = 'ControllerComment'; +} + +class PaginatorTest extends CakeTestCase { + +/** + * fixtures property + * + * @var array + * @access public + */ + public $fixtures = array('core.post', 'core.comment'); + +/** + * testPaginate method + * + * @access public + * @return void + */ + function testPaginate() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new PaginatorTestController($request); + $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->passedArgs[] = '1'; + $Controller->params['url'] = array(); + $Controller->constructClasses(); + + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($results, array(1, 2, 3)); + + $results = Set::extract($Controller->Paginator->paginate('ControllerComment'), '{n}.ControllerComment.id'); + $this->assertEqual($results, array(1, 2, 3, 4, 5, 6)); + + $Controller->modelClass = null; + + $Controller->uses[0] = 'Plugin.ControllerPost'; + $results = Set::extract($Controller->Paginator->paginate(), '{n}.ControllerPost.id'); + $this->assertEqual($results, array(1, 2, 3)); + + $Controller->passedArgs = array('page' => '-1'); + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertEqual($results, array(1, 2, 3)); + + $Controller->passedArgs = array('sort' => 'ControllerPost.id', 'direction' => 'asc'); + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertEqual($results, array(1, 2, 3)); + + $Controller->passedArgs = array('sort' => 'ControllerPost.id', 'direction' => 'desc'); + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertEqual($results, array(3, 2, 1)); + + $Controller->passedArgs = array('sort' => 'id', 'direction' => 'desc'); + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertEqual($results, array(3, 2, 1)); + + $Controller->passedArgs = array('sort' => 'NotExisting.field', 'direction' => 'desc'); + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1, 'Invalid field in query %s'); + $this->assertEqual($results, array(1, 2, 3)); + + $Controller->passedArgs = array('sort' => 'ControllerPost.author_id', 'direction' => 'allYourBase'); + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($Controller->ControllerPost->lastQuery['order'][0], array('ControllerPost.author_id' => 'asc')); + $this->assertEqual($results, array(1, 3, 2)); + + $Controller->passedArgs = array('page' => '1 " onclick="alert(\'xss\');">'); + $Controller->Paginator->settings = array('limit' => 1); + $Controller->Paginator->paginate('ControllerPost'); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1, 'XSS exploit opened %s'); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['options']['page'], 1, 'XSS exploit opened %s'); + + $Controller->passedArgs = array(); + $Controller->Paginator->settings = array('limit' => 0); + $Controller->Paginator->paginate('ControllerPost'); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); + + $Controller->passedArgs = array(); + $Controller->Paginator->settings = array('limit' => 'garbage!'); + $Controller->Paginator->paginate('ControllerPost'); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); + + $Controller->passedArgs = array(); + $Controller->Paginator->settings = array('limit' => '-1'); + $Controller->Paginator->paginate('ControllerPost'); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); + } + +/** + * testPaginateExtraParams method + * + * @access public + * @return void + */ + function testPaginateExtraParams() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new PaginatorTestController($request); + + $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->passedArgs[] = '1'; + $Controller->params['url'] = array(); + $Controller->constructClasses(); + + $Controller->passedArgs = array('page' => '-1', 'contain' => array('ControllerComment')); + $result = $Controller->Paginator->paginate('ControllerPost'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(1, 2, 3)); + $this->assertTrue(!isset($Controller->ControllerPost->lastQuery['contain'])); + + $Controller->passedArgs = array('page' => '-1'); + $Controller->Paginator->settings = array('ControllerPost' => array('contain' => array('ControllerComment'))); + $result = $Controller->Paginator->paginate('ControllerPost'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(1, 2, 3)); + $this->assertTrue(isset($Controller->ControllerPost->lastQuery['contain'])); + + $Controller->Paginator->settings = array('ControllerPost' => array('popular', 'fields' => array('id', 'title'))); + $result = $Controller->Paginator->paginate('ControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(2, 3)); + $this->assertEqual($Controller->ControllerPost->lastQuery['conditions'], array('ControllerPost.id > ' => '1')); + + $Controller->passedArgs = array('limit' => 12); + $Controller->Paginator->settings = array('limit' => 30); + $result = $Controller->Paginator->paginate('ControllerPost'); + $paging = $Controller->params['paging']['ControllerPost']; + + $this->assertEqual($Controller->ControllerPost->lastQuery['limit'], 12); + $this->assertEqual($paging['options']['limit'], 12); + + $Controller = new PaginatorTestController($request); + $Controller->uses = array('ControllerPaginateModel'); + $Controller->params['url'] = array(); + $Controller->constructClasses(); + $Controller->Paginator->settings = array( + 'ControllerPaginateModel' => array('contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id') + ); + $result = $Controller->Paginator->paginate('ControllerPaginateModel'); + $expected = array('contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id'); + $this->assertEqual($Controller->ControllerPaginateModel->extra, $expected); + $this->assertEqual($Controller->ControllerPaginateModel->extraCount, $expected); + + $Controller->Paginator->settings = array( + 'ControllerPaginateModel' => array('foo', 'contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id') + ); + $Controller->Paginator->paginate('ControllerPaginateModel'); + $expected = array('contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id', 'type' => 'foo'); + $this->assertEqual($Controller->ControllerPaginateModel->extra, $expected); + $this->assertEqual($Controller->ControllerPaginateModel->extraCount, $expected); + } + +/** + * testPaginatePassedArgs method + * + * @return void + */ + public function testPaginatePassedArgs() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new PaginatorTestController($request); + $Controller->uses = array('ControllerPost'); + $Controller->passedArgs[] = array('1', '2', '3'); + $Controller->params['url'] = array(); + $Controller->constructClasses(); + + $Controller->Paginator->settings = array( + 'fields' => array(), + 'order' => '', + 'limit' => 5, + 'page' => 1, + 'recursive' => -1 + ); + $conditions = array(); + $Controller->Paginator->paginate('ControllerPost',$conditions); + + $expected = array( + 'fields' => array(), + 'order' => '', + 'limit' => 5, + 'page' => 1, + 'recursive' => -1, + 'conditions' => array() + ); + $this->assertEqual($Controller->params['paging']['ControllerPost']['options'],$expected); + } + +/** + * Test that special paginate types are called and that the type param doesn't leak out into defaults or options. + * + * @return void + */ + function testPaginateSpecialType() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new PaginatorTestController($request); + $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->passedArgs[] = '1'; + $Controller->params['url'] = array(); + $Controller->constructClasses(); + + $Controller->Paginator->settings = array('ControllerPost' => array('popular', 'fields' => array('id', 'title'))); + $result = $Controller->Paginator->paginate('ControllerPost'); + + $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(2, 3)); + $this->assertEqual($Controller->ControllerPost->lastQuery['conditions'], array('ControllerPost.id > ' => '1')); + $this->assertFalse(isset($Controller->params['paging']['ControllerPost']['defaults'][0])); + $this->assertFalse(isset($Controller->params['paging']['ControllerPost']['options'][0])); + } + +/** + * testDefaultPaginateParams method + * + * @access public + * @return void + */ + function testDefaultPaginateParams() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new PaginatorTestController($request); + $Controller->modelClass = 'ControllerPost'; + $Controller->params['url'] = array(); + $Controller->constructClasses(); + $Controller->Paginator->settings = array('order' => 'ControllerPost.id DESC'); + $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['defaults']['order'], 'ControllerPost.id DESC'); + $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['order'], 'ControllerPost.id DESC'); + $this->assertEqual($results, array(3, 2, 1)); + } + +/** + * test paginate() and virtualField interactions + * + * @return void + */ + function testPaginateOrderVirtualField() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new PaginatorTestController($request); + $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->params['url'] = array(); + $Controller->constructClasses(); + $Controller->ControllerPost->virtualFields = array( + 'offset_test' => 'ControllerPost.id + 1' + ); + + $Controller->Paginator->settings = array( + 'fields' => array('id', 'title', 'offset_test'), + 'order' => array('offset_test' => 'DESC') + ); + $result = $Controller->Paginator->paginate('ControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(4, 3, 2)); + + $Controller->passedArgs = array('sort' => 'offset_test', 'direction' => 'asc'); + $result = $Controller->Paginator->paginate('ControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(2, 3, 4)); + } + + function testPaginateMissingModel() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new PaginatorTestController($request); + $Controller->constructClasses(); + $this->expectException('MissingModelException'); + $Controller->Paginator->paginate('MissingModel'); + } +} \ No newline at end of file diff --git a/cake/tests/cases/libs/controller/controller.test.php b/cake/tests/cases/libs/controller/controller.test.php index 089955373..0521283b2 100644 --- a/cake/tests/cases/libs/controller/controller.test.php +++ b/cake/tests/cases/libs/controller/controller.test.php @@ -597,350 +597,6 @@ class ControllerTest extends CakeTestCase { Configure::write('Cache.disable', true); } -/** - * testPaginate method - * - * @access public - * @return void - */ - function testPaginate() { - $request = new CakeRequest('controller_posts/index'); - $request->params['pass'] = $request->params['named'] = array(); - - $Controller = new Controller($request); - $Controller->uses = array('ControllerPost', 'ControllerComment'); - $Controller->passedArgs[] = '1'; - $Controller->params['url'] = array(); - $Controller->constructClasses(); - - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($results, array(1, 2, 3)); - - $results = Set::extract($Controller->paginate('ControllerComment'), '{n}.ControllerComment.id'); - $this->assertEqual($results, array(1, 2, 3, 4, 5, 6)); - - $Controller->modelClass = null; - - $Controller->uses[0] = 'Plugin.ControllerPost'; - $results = Set::extract($Controller->paginate(), '{n}.ControllerPost.id'); - $this->assertEqual($results, array(1, 2, 3)); - - $Controller->passedArgs = array('page' => '-1'); - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual($results, array(1, 2, 3)); - - $Controller->passedArgs = array('sort' => 'ControllerPost.id', 'direction' => 'asc'); - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual($results, array(1, 2, 3)); - - $Controller->passedArgs = array('sort' => 'ControllerPost.id', 'direction' => 'desc'); - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual($results, array(3, 2, 1)); - - $Controller->passedArgs = array('sort' => 'id', 'direction' => 'desc'); - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual($results, array(3, 2, 1)); - - $Controller->passedArgs = array('sort' => 'NotExisting.field', 'direction' => 'desc'); - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1, 'Invalid field in query %s'); - $this->assertEqual($results, array(1, 2, 3)); - - $Controller->passedArgs = array('sort' => 'ControllerPost.author_id', 'direction' => 'allYourBase'); - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->ControllerPost->lastQuery['order'][0], array('ControllerPost.author_id' => 'asc')); - $this->assertEqual($results, array(1, 3, 2)); - - $Controller->passedArgs = array('page' => '1 " onclick="alert(\'xss\');">'); - $Controller->paginate = array('limit' => 1); - $Controller->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1, 'XSS exploit opened %s'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['options']['page'], 1, 'XSS exploit opened %s'); - - $Controller->passedArgs = array(); - $Controller->paginate = array('limit' => 0); - $Controller->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); - - $Controller->passedArgs = array(); - $Controller->paginate = array('limit' => 'garbage!'); - $Controller->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); - - $Controller->passedArgs = array(); - $Controller->paginate = array('limit' => '-1'); - $Controller->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); - } - -/** - * testPaginateExtraParams method - * - * @access public - * @return void - */ - function testPaginateExtraParams() { - $request = new CakeRequest('controller_posts/index'); - $request->params['pass'] = $request->params['named'] = array(); - - $Controller = new Controller($request); - - $Controller->uses = array('ControllerPost', 'ControllerComment'); - $Controller->passedArgs[] = '1'; - $Controller->params['url'] = array(); - $Controller->constructClasses(); - - $Controller->passedArgs = array('page' => '-1', 'contain' => array('ControllerComment')); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(1, 2, 3)); - $this->assertTrue(!isset($Controller->ControllerPost->lastQuery['contain'])); - - $Controller->passedArgs = array('page' => '-1'); - $Controller->paginate = array('ControllerPost' => array('contain' => array('ControllerComment'))); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(1, 2, 3)); - $this->assertTrue(isset($Controller->ControllerPost->lastQuery['contain'])); - - $Controller->paginate = array('ControllerPost' => array('popular', 'fields' => array('id', 'title'))); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(2, 3)); - $this->assertEqual($Controller->ControllerPost->lastQuery['conditions'], array('ControllerPost.id > ' => '1')); - - $Controller->passedArgs = array('limit' => 12); - $Controller->paginate = array('limit' => 30); - $result = $Controller->paginate('ControllerPost'); - $paging = $Controller->params['paging']['ControllerPost']; - - $this->assertEqual($Controller->ControllerPost->lastQuery['limit'], 12); - $this->assertEqual($paging['options']['limit'], 12); - - $Controller = new Controller($request); - $Controller->uses = array('ControllerPaginateModel'); - $Controller->params['url'] = array(); - $Controller->constructClasses(); - $Controller->paginate = array( - 'ControllerPaginateModel' => array('contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id') - ); - $result = $Controller->paginate('ControllerPaginateModel'); - $expected = array('contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id'); - $this->assertEqual($Controller->ControllerPaginateModel->extra, $expected); - $this->assertEqual($Controller->ControllerPaginateModel->extraCount, $expected); - - $Controller->paginate = array( - 'ControllerPaginateModel' => array('foo', 'contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id') - ); - $Controller->paginate('ControllerPaginateModel'); - $expected = array('contain' => array('ControllerPaginateModel'), 'group' => 'Comment.author_id', 'type' => 'foo'); - $this->assertEqual($Controller->ControllerPaginateModel->extra, $expected); - $this->assertEqual($Controller->ControllerPaginateModel->extraCount, $expected); - } - -/** - * testPaginateMaxLimit - * - * @return void - * @access public - */ - function testPaginateMaxLimit() { - $request = new CakeRequest('controller_posts/index'); - $request->params['pass'] = $request->params['named'] = array(); - - $Controller = new Controller($request); - - $Controller->uses = array('ControllerPost', 'ControllerComment'); - $Controller->passedArgs[] = '1'; - $Controller->params['url'] = array(); - $Controller->constructClasses(); - - $Controller->passedArgs = array('contain' => array('ControllerComment'), 'limit' => '1000'); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['limit'], 100); - - $Controller->passedArgs = array('contain' => array('ControllerComment'), 'limit' => '1000', 'maxLimit' => 1000); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['limit'], 100); - - $Controller->passedArgs = array('contain' => array('ControllerComment'), 'limit' => '10'); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['limit'], 10); - - $Controller->passedArgs = array('contain' => array('ControllerComment'), 'limit' => '1000'); - $Controller->paginate = array('maxLimit' => 2000); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['limit'], 1000); - - $Controller->passedArgs = array('contain' => array('ControllerComment'), 'limit' => '5000'); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['limit'], 2000); - } - -/** - * testPaginateFieldsDouble method - * - * @return void - * @access public - */ - function testPaginateFieldsDouble(){ - $request = new CakeRequest('controller_posts/index'); - - $Controller = new Controller($request); - $Controller->uses = array('ControllerPost'); - $Controller->request = $this->getMock('CakeRequest'); - $Controller->request->params['url'] = array(); - $Controller->constructClasses(); - - $Controller->paginate = array( - 'fields' => array( - 'ControllerPost.id', - 'radians(180.0) as floatvalue' - ), - 'order' => array('ControllerPost.created'=>'DESC'), - 'limit' => 1, - 'page' => 1, - 'recursive' => -1 - ); - $conditions = array(); - $result = $Controller->paginate('ControllerPost',$conditions); - $expected = array( - array( - 'ControllerPost' => array( - 'id' => 3, - ), - 0 => array( - 'floatvalue' => '3.14159265358979', - ), - ), - ); - $this->assertEqual($result, $expected); - } - - -/** - * testPaginatePassedArgs method - * - * @return void - */ - public function testPaginatePassedArgs() { - $request = new CakeRequest('controller_posts/index'); - $request->params['pass'] = $request->params['named'] = array(); - - $Controller = new Controller($request); - $Controller->uses = array('ControllerPost'); - $Controller->passedArgs[] = array('1', '2', '3'); - $Controller->params['url'] = array(); - $Controller->constructClasses(); - - $Controller->paginate = array( - 'fields' => array(), - 'order' => '', - 'limit' => 5, - 'page' => 1, - 'recursive' => -1 - ); - $conditions = array(); - $Controller->paginate('ControllerPost',$conditions); - - $expected = array( - 'fields' => array(), - 'order' => '', - 'limit' => 5, - 'maxLimit' => 100, - 'page' => 1, - 'recursive' => -1, - 'conditions' => array() - ); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options'],$expected); - } - -/** - * Test that special paginate types are called and that the type param doesn't leak out into defaults or options. - * - * @return void - */ - function testPaginateSpecialType() { - $request = new CakeRequest('controller_posts/index'); - $request->params['pass'] = $request->params['named'] = array(); - - $Controller = new Controller($request); - $Controller->uses = array('ControllerPost', 'ControllerComment'); - $Controller->passedArgs[] = '1'; - $Controller->params['url'] = array(); - $Controller->constructClasses(); - - $Controller->paginate = array('ControllerPost' => array('popular', 'fields' => array('id', 'title'))); - $result = $Controller->paginate('ControllerPost'); - - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(2, 3)); - $this->assertEqual($Controller->ControllerPost->lastQuery['conditions'], array('ControllerPost.id > ' => '1')); - $this->assertFalse(isset($Controller->params['paging']['ControllerPost']['defaults'][0])); - $this->assertFalse(isset($Controller->params['paging']['ControllerPost']['options'][0])); - } - -/** - * testDefaultPaginateParams method - * - * @access public - * @return void - */ - function testDefaultPaginateParams() { - $request = new CakeRequest('controller_posts/index'); - $request->params['pass'] = $request->params['named'] = array(); - - $Controller = new Controller($request); - $Controller->modelClass = 'ControllerPost'; - $Controller->params['url'] = array(); - $Controller->paginate = array('order' => 'ControllerPost.id DESC'); - $Controller->constructClasses(); - $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['defaults']['order'], 'ControllerPost.id DESC'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['order'], 'ControllerPost.id DESC'); - $this->assertEqual($results, array(3, 2, 1)); - } - -/** - * test paginate() and virtualField interactions - * - * @return void - */ - function testPaginateOrderVirtualField() { - $request = new CakeRequest('controller_posts/index'); - $request->params['pass'] = $request->params['named'] = array(); - - $Controller = new Controller($request); - $Controller->uses = array('ControllerPost', 'ControllerComment'); - $Controller->params['url'] = array(); - $Controller->constructClasses(); - $Controller->ControllerPost->virtualFields = array( - 'offset_test' => 'ControllerPost.id + 1' - ); - - $Controller->paginate = array( - 'fields' => array('id', 'title', 'offset_test'), - 'order' => array('offset_test' => 'DESC') - ); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(4, 3, 2)); - - $Controller->passedArgs = array('sort' => 'offset_test', 'direction' => 'asc'); - $result = $Controller->paginate('ControllerPost'); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(2, 3, 4)); - } - /** * testFlash method * @@ -1648,4 +1304,33 @@ class ControllerTest extends CakeTestCase { $this->assertType('SecurityComponent', $Controller->Security); $this->assertType('ControllerComment', $Controller->ControllerComment); } + +/** + * test that using Controller::paginate() falls back to PaginatorComponent + * + * @return void + */ + function testPaginateBackwardsCompatibility() { + $request = new CakeRequest('controller_posts/index'); + $request->params['pass'] = $request->params['named'] = array(); + + $Controller = new Controller($request); + $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->passedArgs[] = '1'; + $Controller->params['url'] = array(); + $Controller->constructClasses(); + $this->assertEqual($Controller->paginate, array('page' => 1, 'limit' => 20)); + + $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $this->assertEqual($results, array(1, 2, 3)); + + $Controller->passedArgs = array(); + $Controller->paginate = array('limit' => '-1'); + $this->assertEqual($Controller->paginate, array('limit' => '-1')); + $Controller->paginate('ControllerPost'); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); + $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); + } } diff --git a/cake/tests/cases/libs/router.test.php b/cake/tests/cases/libs/router.test.php index ffe168ac8..e0def56f9 100644 --- a/cake/tests/cases/libs/router.test.php +++ b/cake/tests/cases/libs/router.test.php @@ -383,6 +383,113 @@ class RouterTest extends CakeTestCase { $this->assertEqual($result, $expected); } +/** + * Tests using arrays in named parameters + * + * @return void + */ + function testArrayNamedParameters() { + $result = Router::url(array('controller' => 'tests', 'pages' => array( + 1, 2, 3 + ))); + $expected = '/tests/index/pages[0]:1/pages[1]:2/pages[2]:3'; + $this->assertEqual($result, $expected); + + $result = Router::url(array('controller' => 'tests', + 'pages' => array( + 'param1' => array( + 'one', + 'two' + ), + 'three' + ) + )); + $expected = '/tests/index/pages[param1][0]:one/pages[param1][1]:two/pages[0]:three'; + $this->assertEqual($result, $expected); + + $result = Router::url(array('controller' => 'tests', + 'pages' => array( + 'param1' => array( + 'one' => 1, + 'two' => 2 + ), + 'three' + ) + )); + $expected = '/tests/index/pages[param1][one]:1/pages[param1][two]:2/pages[0]:three'; + $this->assertEqual($result, $expected); + + $result = Router::url(array('controller' => 'tests', + 'super' => array( + 'nested' => array( + 'array' => 'awesome', + 'something' => 'else' + ), + 'cool' + ) + )); + $expected = '/tests/index/super[nested][array]:awesome/super[nested][something]:else/super[0]:cool'; + $this->assertEqual($result, $expected); + + $result = Router::url(array('controller' => 'tests', 'namedParam' => array( + 'keyed' => 'is an array', + 'test' + ))); + $expected = '/tests/index/namedParam[keyed]:is an array/namedParam[0]:test'; + $this->assertEqual($result, $expected); + + $result = Router::parse('/tests/action/var[]:val1/var[]:val2'); + $expected = array( + 'controller' => 'tests', + 'action' => 'action', + 'named' => array( + 'var' => array( + 'val1', + 'val2' + ) + ), + 'pass' => array(), + 'plugin' => null + ); + $this->assertEqual($result, $expected); + + $result = Router::parse('/tests/action/theanswer[is]:42/var[]:val2/var[]:val3'); + $expected = array( + 'controller' => 'tests', + 'action' => 'action', + 'named' => array( + 'theanswer' => array( + 'is' => 42 + ), + 'var' => array( + 'val2', + 'val3' + ) + ), + 'pass' => array(), + 'plugin' => null + ); + $this->assertEqual($result, $expected); + + $result = Router::parse('/tests/action/theanswer[is][not]:42/theanswer[]:5/theanswer[is]:6'); + $expected = array( + 'controller' => 'tests', + 'action' => 'action', + 'named' => array( + 'theanswer' => array( + 5, + 'is' => array( + 6, + 'not' => 42 + ) + ), + ), + 'pass' => array(), + 'plugin' => null + ); + $this->assertEqual($result, $expected); + } + /** * Test generation of routes with query string parameters. * From 19f9caed28f1100d87e7ce51e9e2cbaef1972469 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 14 Dec 2010 21:59:53 -0500 Subject: [PATCH 111/125] Fixing tests so they initialize the session, before trying to test things. --- cake/tests/cases/libs/controller/components/session.test.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cake/tests/cases/libs/controller/components/session.test.php b/cake/tests/cases/libs/controller/components/session.test.php index bf605f1df..a2fa96410 100644 --- a/cake/tests/cases/libs/controller/components/session.test.php +++ b/cake/tests/cases/libs/controller/components/session.test.php @@ -143,6 +143,7 @@ class SessionComponentTest extends CakeTestCase { */ function testSessionIdConsistentAcrossRequestAction() { $Session = new SessionComponent($this->ComponentCollection); + $Session->check('Test'); $this->assertTrue(isset($_SESSION)); $Object = new Object(); @@ -287,6 +288,7 @@ class SessionComponentTest extends CakeTestCase { function testSessionId() { unset($_SESSION); $Session = new SessionComponent($this->ComponentCollection); + $Session->check('test'); $this->assertEquals(session_id(), $Session->id()); } From 10bf41a4df1cd16404d80e240a6af0ca910365a8 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 14 Dec 2010 19:00:26 -0800 Subject: [PATCH 112/125] Merge commit '42a5ebf47b73bbdf200f0238e30e6d4893695f80' into 2.0 --- .../cases/libs/controller/components/paginator.test.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cake/tests/cases/libs/controller/components/paginator.test.php b/cake/tests/cases/libs/controller/components/paginator.test.php index eebdd3304..93ee5b6b5 100644 --- a/cake/tests/cases/libs/controller/components/paginator.test.php +++ b/cake/tests/cases/libs/controller/components/paginator.test.php @@ -473,13 +473,17 @@ class PaginatorTest extends CakeTestCase { $this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(2, 3, 4)); } +/** + * Tests for missing models + * + * @expectedException MissingModelException + */ function testPaginateMissingModel() { $request = new CakeRequest('controller_posts/index'); $request->params['pass'] = $request->params['named'] = array(); $Controller = new PaginatorTestController($request); $Controller->constructClasses(); - $this->expectException('MissingModelException'); $Controller->Paginator->paginate('MissingModel'); } } \ No newline at end of file From 75af48b774120394b8870a50b01474eabc27e70f Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 14 Dec 2010 22:09:29 -0500 Subject: [PATCH 113/125] Updating bake templates to let PUT methods through as well. --- cake/console/templates/default/actions/controller_actions.ctp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/console/templates/default/actions/controller_actions.ctp b/cake/console/templates/default/actions/controller_actions.ctp index b02ad7647..0a4c9d311 100644 --- a/cake/console/templates/default/actions/controller_actions.ctp +++ b/cake/console/templates/default/actions/controller_actions.ctp @@ -72,7 +72,7 @@ if (!$this->->exists()) { throw new NotFoundException(__('Invalid ')); } - if ($this->request->is('post')) { + if ($this->request->is('post') || $this->request->is('put')) { if ($this->->save($this->request->data)) { $this->Session->setFlash(__('The has been saved')); From 84414eeb075ab598e4b9018e0c90bd36cd1d4117 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 14 Dec 2010 22:35:43 -0500 Subject: [PATCH 114/125] Removing CakeSession::watch() and CakeSession::ignore(). You should use logging, or an interactive debugger instead. --- cake/libs/cake_session.php | 53 --------------------- cake/tests/cases/libs/cake_session.test.php | 42 ---------------- 2 files changed, 95 deletions(-) diff --git a/cake/libs/cake_session.php b/cake/libs/cake_session.php index a0b44b9cb..2d201f81d 100644 --- a/cake/libs/cake_session.php +++ b/cake/libs/cake_session.php @@ -100,13 +100,6 @@ class CakeSession { */ public static $sessionTime = false; -/** - * Keeps track of keys to watch for writes on - * - * @var array - */ - public static $watchKeys = array(); - /** * Current Session id * @@ -261,9 +254,6 @@ class CakeSession { */ public static function delete($name) { if (self::check($name)) { - if (in_array($name, self::$watchKeys)) { - throw new CakeSessionException(__('Deleting session key {%s}', $name)); - } self::__overwrite($_SESSION, Set::remove($_SESSION, $name)); return (self::check($name) == false); } @@ -402,46 +392,6 @@ class CakeSession { return false; } -/** - * Tells Session to write a notification when a certain session path or subpath is written to - * - * @param mixed $var The variable path to watch - * @return void - */ - public static function watch($var) { - if (!self::started() && !self::start()) { - return false; - } - if (empty($var)) { - return false; - } - if (!in_array($var, self::$watchKeys, true)) { - self::$watchKeys[] = $var; - } - } - -/** - * Tells Session to stop watching a given key path - * - * @param mixed $var The variable path to watch - * @return void - */ - public static function ignore($var) { - if (!self::started() && !self::start()) { - return false; - } - if (!in_array($var, self::$watchKeys)) { - return; - } - foreach (self::$watchKeys as $i => $key) { - if ($key == $var) { - unset(self::$watchKeys[$i]); - self::$watchKeys = array_values(self::$watchKeys); - return; - } - } - } - /** * Writes value to given session variable name. * @@ -461,9 +411,6 @@ class CakeSession { $write = array($name => $value); } foreach ($write as $key => $val) { - if (in_array($key, self::$watchKeys)) { - throw new CakeSessionException(__('Writing session key {%s}: %s', $key, var_export($val, true))); - } self::__overwrite($_SESSION, Set::insert($_SESSION, $key, $val)); if (Set::classicExtract($_SESSION, $key) !== $val) { return false; diff --git a/cake/tests/cases/libs/cake_session.test.php b/cake/tests/cases/libs/cake_session.test.php index 2c84254dd..e25c9416d 100644 --- a/cake/tests/cases/libs/cake_session.test.php +++ b/cake/tests/cases/libs/cake_session.test.php @@ -88,7 +88,6 @@ class CakeSessionTest extends CakeTestCase { 'ini' => array(), )); TestCakeSession::init(); - TestCakeSession::$watchKeys = array(); } /** @@ -365,47 +364,6 @@ class CakeSessionTest extends CakeTestCase { $this->assertFalse(TestCakeSession::check('Clearing')); } -/** - * testWatchVar method - * - * @expectedException CakeSessionException - * @access public - * @return void - */ - function testWatchVarWrite() { - $this->assertFalse(TestCakeSession::watch(null)); - - TestCakeSession::write('Watching', "I'm watching you"); - TestCakeSession::watch('Watching'); - TestCakeSession::write('Watching', 'They found us!'); - } - -/** - * Test that deleting watched vars causes exceptions - * - * @expectedException CakeSessionException - * @return void - */ - function testWatchVarDelete() { - TestCakeSession::write('Watching', 'I am watching you.'); - - TestCakeSession::watch('Watching'); - TestCakeSession::delete('Watching'); - } - -/** - * testIgnore method - * - * @access public - * @return void - */ - function testIgnore() { - TestCakeSession::write('Watching', "I'm watching you"); - TestCakeSession::watch('Watching'); - TestCakeSession::ignore('Watching'); - $this->assertTrue(TestCakeSession::write('Watching', 'They found us!')); - } - /** * testDestroy method * From 99407282e5c6bfda96b7ff311138b6007acc7852 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 15 Dec 2010 01:51:00 -0200 Subject: [PATCH 115/125] Updated the config of auth in digest method. --- cake/libs/http/digest_authentication.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cake/libs/http/digest_authentication.php b/cake/libs/http/digest_authentication.php index ba146e2fc..adcc9dd9d 100644 --- a/cake/libs/http/digest_authentication.php +++ b/cake/libs/http/digest_authentication.php @@ -53,10 +53,10 @@ class DigestAuthentication { */ protected static function _getServerInformation(HttpSocket $http, &$authInfo) { $originalRequest = $http->request; - $http->setAuthConfig(false); + $http->configAuth(false); $http->request($http->request); $http->request = $originalRequest; - $http->setAuthConfig('Digest', $authInfo); + $http->configAuth('Digest', $authInfo); if (empty($http->response['header']['WWW-Authenticate'])) { return false; From 478d158133c3408b0259231b01b144934c58c3df Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 14 Dec 2010 22:52:31 -0500 Subject: [PATCH 116/125] Removing a var_dump because I'm a muppet. --- cake/libs/controller/controller.php | 1 - 1 file changed, 1 deletion(-) diff --git a/cake/libs/controller/controller.php b/cake/libs/controller/controller.php index 7bc58f024..1093c4ac1 100644 --- a/cake/libs/controller/controller.php +++ b/cake/libs/controller/controller.php @@ -445,7 +445,6 @@ class Controller extends Object { is_array($this->uses) && !empty($appVars['uses']) ) { $this->uses = array_merge($this->uses, array_diff($appVars['uses'], $this->uses)); - var_dump($this->uses); } $this->_mergeVars($merge, 'AppController', true); } From 575da672b0c81305eb22fe2ba46bd0d1a164a760 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 15 Dec 2010 01:54:37 -0200 Subject: [PATCH 117/125] Fixed basic proxy test. --- cake/tests/cases/libs/http/basic_authentication.test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cake/tests/cases/libs/http/basic_authentication.test.php b/cake/tests/cases/libs/http/basic_authentication.test.php index 7ba642b64..f886a6686 100644 --- a/cake/tests/cases/libs/http/basic_authentication.test.php +++ b/cake/tests/cases/libs/http/basic_authentication.test.php @@ -53,13 +53,13 @@ class BasicMethodTest extends CakeTestCase { */ public function testProxyAuthentication() { $http = new HttpSocket(); - $http->request['proxy'] = array( + $proxy = array( 'method' => 'Basic', 'user' => 'mark', 'pass' => 'secret' ); - BasicAuthentication::proxyAuthentication($http); + BasicAuthentication::proxyAuthentication($http, $proxy); $this->assertEqual($http->request['header']['Proxy-Authorization'], 'Basic bWFyazpzZWNyZXQ='); } From ad5e7248c56b4e40f53ebe7fb2aa217e52b60d10 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 15 Dec 2010 01:54:48 -0200 Subject: [PATCH 118/125] Fixed documentation. --- cake/libs/http/digest_authentication.php | 1 - 1 file changed, 1 deletion(-) diff --git a/cake/libs/http/digest_authentication.php b/cake/libs/http/digest_authentication.php index adcc9dd9d..21f7ea8e6 100644 --- a/cake/libs/http/digest_authentication.php +++ b/cake/libs/http/digest_authentication.php @@ -32,7 +32,6 @@ class DigestAuthentication { * @param HttpSocket $http * @param array $authInfo * @return void - * @throws Exception * @link http://www.ietf.org/rfc/rfc2617.txt */ public static function authentication(HttpSocket $http, &$authInfo) { From b9143dc7d451d6307aebbf1a74dbaf60248204dd Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 14 Dec 2010 19:58:27 -0800 Subject: [PATCH 119/125] Added ControllerTestCase class for testing controllers. Fixes #1244 --- cake/libs/controller/controller.php | 4 +- cake/libs/dispatcher.php | 16 +- cake/libs/object_collection.php | 14 + cake/libs/router.php | 8 +- cake/tests/cases/libs/all_test_suite.test.php | 1 + .../cases/libs/controller_test_case.test.php | 407 ++++++++++++++++++ .../cases/libs/object_collection.test.php | 20 + cake/tests/lib/controller_test_case.php | 312 ++++++++++++++ cake/tests/lib/test_manager.php | 1 + cake/tests/test_app/config/routes.php | 26 ++ .../controllers/tests_apps_controller.php | 4 + .../test_app/views/layouts/json/default.ctp | 1 + .../test_app/views/tests_apps/json/index.ctp | 1 + 13 files changed, 809 insertions(+), 6 deletions(-) create mode 100644 cake/tests/cases/libs/controller_test_case.test.php create mode 100644 cake/tests/lib/controller_test_case.php create mode 100644 cake/tests/test_app/config/routes.php create mode 100644 cake/tests/test_app/views/layouts/json/default.ctp create mode 100644 cake/tests/test_app/views/tests_apps/json/index.ctp diff --git a/cake/libs/controller/controller.php b/cake/libs/controller/controller.php index 9afc3e315..724fa93aa 100644 --- a/cake/libs/controller/controller.php +++ b/cake/libs/controller/controller.php @@ -301,7 +301,7 @@ class Controller extends Object { $this->methods = array_diff($childMethods, $parentMethods); if ($request instanceof CakeRequest) { - $this->_setRequest($request); + $this->setRequest($request); } $this->getResponse(); parent::__construct(); @@ -377,7 +377,7 @@ class Controller extends Object { * @param CakeRequest $request * @return void */ - protected function _setRequest(CakeRequest $request) { + public function setRequest(CakeRequest $request) { $this->request = $request; $this->plugin = isset($request->params['plugin']) ? $request->params['plugin'] : null; diff --git a/cake/libs/dispatcher.php b/cake/libs/dispatcher.php index 4f35138c8..0b498b5b2 100644 --- a/cake/libs/dispatcher.php +++ b/cake/libs/dispatcher.php @@ -99,8 +99,8 @@ class Dispatcher { return; } - $request = $this->parseParams($request, $additionalParams); - $controller = $this->_getController($request); + $this->request = $this->parseParams($request, $additionalParams); + $controller = $this->_getController($this->request); if (!is_object($controller)) { Router::setRequestInfo($request); @@ -198,7 +198,7 @@ class Dispatcher { if (count(Router::$routes) > 0) { $namedExpressions = Router::getNamedExpressions(); extract($namedExpressions); - include CONFIGS . 'routes.php'; + $this->__loadRoutes(); } $params = Router::parse($request->url); @@ -250,6 +250,16 @@ class Dispatcher { return false; } +/** + * Loads route configuration + * + * @return void + * @access protected + */ + protected function __loadRoutes() { + include CONFIGS . 'routes.php'; + } + /** * Outputs cached dispatch view cache * diff --git a/cake/libs/object_collection.php b/cake/libs/object_collection.php index d91f62cc9..a9750f3e8 100644 --- a/cake/libs/object_collection.php +++ b/cake/libs/object_collection.php @@ -221,6 +221,20 @@ abstract class ObjectCollection { $this->_enabled = array_values(array_diff($this->_enabled, (array)$name)); } +/** + * Adds or overwrites an instatiated object to the collection + * + * @param string $name Name of the object + * @param Object $object The object to use + */ + public function set($name = null, $object = null) { + if (!empty($name) && !empty($object)) { + list($plugin, $name) = pluginSplit($name); + $this->_loaded[$name] = $object; + } + return $this->_loaded; + } + /** * Normalizes an object array, creates an array that makes lazy loading * easier diff --git a/cake/libs/router.php b/cake/libs/router.php index 91261c6ce..a4408b92f 100644 --- a/cake/libs/router.php +++ b/cake/libs/router.php @@ -250,6 +250,9 @@ class Router { throw new RouterException(__('Route classes must extend CakeRoute')); } unset($options['routeClass']); + if ($routeClass == 'RedirectRoute' && isset($defaults['redirect'])) { + $defaults = $defaults['redirect']; + } } self::$routes[] = new $routeClass($route, $defaults, $options); return self::$routes; @@ -284,9 +287,12 @@ class Router { * @see routes * @return array Array of routes */ - public static function redirect($route, $url, $options) { + public static function redirect($route, $url, $options = array()) { App::import('Core', 'route/RedirectRoute'); $options['routeClass'] = 'RedirectRoute'; + if (is_string($url)) { + $url = array('redirect' => $url); + } return self::connect($route, $url, $options); } diff --git a/cake/tests/cases/libs/all_test_suite.test.php b/cake/tests/cases/libs/all_test_suite.test.php index 9c6a46e6a..f1d52c2dc 100644 --- a/cake/tests/cases/libs/all_test_suite.test.php +++ b/cake/tests/cases/libs/all_test_suite.test.php @@ -40,6 +40,7 @@ class AllTestSuiteTest extends PHPUnit_Framework_TestSuite { $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_test_case.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_test_fixture.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'html_coverage_report.test.php'); + $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'controller_test_case.test.php'); return $suite; } } \ No newline at end of file diff --git a/cake/tests/cases/libs/controller_test_case.test.php b/cake/tests/cases/libs/controller_test_case.test.php new file mode 100644 index 000000000..db66d0a9d --- /dev/null +++ b/cake/tests/cases/libs/controller_test_case.test.php @@ -0,0 +1,407 @@ + array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS), + 'controllers' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'controllers' . DS), + 'models' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models' . DS), + 'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS) + )); + $this->Case = new ControllerTestCase(); + Router::reload(); + } + +/** + * teardown + * + * @return void + */ + function tearDown() { + $this->Case->controller = null; + App::build(); + } + +/** + * Test that ControllerTestCase::generate() creates mock objects correctly + */ + function testGenerate() { + $Posts = $this->Case->generate('Posts'); + $this->Case->assertEquals($Posts->name, 'Posts'); + $this->Case->assertEquals($Posts->modelClass, 'Post'); + $this->Case->assertNull($Posts->response->send()); + + $Posts = $this->Case->generate('Posts', array( + 'methods' => array( + 'render' + ) + )); + $this->Case->assertNull($Posts->render('index')); + + $Posts = $this->Case->generate('Posts', array( + 'models' => array('Post'), + 'components' => array('RequestHandler') + )); + $this->Case->assertNull($Posts->Post->save(array())); + $this->Case->assertNull($Posts->Post->find('all')); + $this->Case->assertEquals($Posts->Post->useTable, 'posts'); + $this->Case->assertNull($Posts->RequestHandler->isAjax()); + + $Posts = $this->Case->generate('Posts', array( + 'models' => array( + 'Post' => true + ) + )); + $this->Case->assertNull($Posts->Post->save(array())); + $this->Case->assertNull($Posts->Post->find('all')); + + $Posts = $this->Case->generate('Posts', array( + 'models' => array( + 'Post' => array('save'), + ) + )); + $this->Case->assertNull($Posts->Post->save(array())); + $this->Case->assertIsA($Posts->Post->find('all'), 'array'); + + $Posts = $this->Case->generate('Posts', array( + 'models' => array('Post'), + 'components' => array( + 'RequestHandler' => array('isPut'), + 'Email' => array('send'), + 'Session' + ) + )); + $Posts->RequestHandler->expects($this->once()) + ->method('isPut') + ->will($this->returnValue(true)); + $this->assertTrue($Posts->RequestHandler->isPut()); + + $Posts->Auth->Session->expects($this->any()) + ->method('write') + ->will($this->returnValue('written!')); + $this->assertEquals($Posts->Auth->Session->write('something'), 'written!'); + } + +/** + * Tests testAction + */ + function testTestAction() { + $Controller = $this->Case->generate('TestsApps'); + $this->Case->testAction('/tests_apps/index'); + $this->Case->assertIsA($this->Case->controller->viewVars, 'array'); + + $this->Case->testAction('/tests_apps/set_action'); + $results = $this->Case->controller->viewVars; + $expected = array( + 'var' => 'string' + ); + $this->Case->assertEquals($expected, $results); + + $result = $this->Case->controller->response->body(); + $this->Case->assertPattern('/This is the TestsAppsController index view/', $result); + + $this->Case->testAction('/tests_apps/redirect_to'); + $results = $this->Case->headers; + $expected = array( + 'Location' => 'http://cakephp.org' + ); + $this->Case->assertEquals($expected, $results); + } + +/** + * Tests using loaded routes during tests + */ + function testUseRoutes() { + include TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'config' . DS . 'routes.php'; + $controller = $this->Case->generate('TestsApps'); + $controller->Components->load('RequestHandler'); + $result = $this->Case->testAction('/tests_apps/index.json', array('return' => 'view')); + $result = json_decode($result, true); + $expected = array('cakephp' => 'cool'); + $this->Case->assertEquals($result, $expected); + + include TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'config' . DS . 'routes.php'; + $result = $this->Case->testAction('/some_alias'); + $this->Case->assertEquals($result, 5); + + include TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'config' . DS . 'routes.php'; + $this->Case->testAction('/redirect_me_now'); + $result = $this->Case->headers['Location']; + $this->Case->assertEquals($result, 'http://cakephp.org'); + + include TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'config' . DS . 'routes.php'; + $this->Case->testAction('/redirect_me'); + $result = $this->Case->headers['Location']; + $this->Case->assertEquals($result, Router::url(array('controller' => 'tests_apps', 'action' => 'some_method'), true)); + } + +/** + * Tests not using loaded routes during tests + */ + function testSkipRoutes() { + include TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'config' . DS . 'routes.php'; + + $this->Case->loadRoutes = false; + + $this->expectException('MissingActionException'); + $result = $this->Case->testAction('/tests_apps/index.json', array('return' => 'view')); + } + +/** + * Tests backwards compatibility with setting the return type + */ + function testBCSetReturn() { + $this->Case->autoMock = true; + + $result = $this->Case->testAction('/tests_apps/some_method'); + $this->Case->assertEquals($result, 5); + + $data = array('var' => 'set'); + $result = $this->Case->testAction('/tests_apps_posts/post_var', array( + 'data' => $data, + 'return' => 'vars' + )); + $this->Case->assertEquals($result['data'], $data); + + $result = $this->Case->testAction('/tests_apps/set_action', array( + 'return' => 'view' + )); + $this->Case->assertEquals($result, 'This is the TestsAppsController index view'); + + $result = $this->Case->testAction('/tests_apps/set_action', array( + 'return' => 'contents' + )); + $this->Case->assertPattern('/Case->assertPattern('/This is the TestsAppsController index view/', $result); + $this->Case->assertPattern('/<\/html>/', $result); + } + +/** + * Tests sending POST data to testAction + */ + function testTestActionPostData() { + $this->Case->autoMock = true; + + $data = array( + 'Post' => array( + 'name' => 'Some Post' + ) + ); + $this->Case->testAction('/tests_apps_posts/post_var', array( + 'data' => $data + )); + $this->Case->assertEquals($this->Case->controller->viewVars['data'], $data); + $this->Case->assertEquals($this->Case->controller->data, $data); + + $this->Case->testAction('/tests_apps_posts/post_var/named:param', array( + 'data' => $data + )); + $expected = array( + 'named' => 'param' + ); + $this->Case->assertEqual($this->Case->controller->request->named, $expected); + $this->Case->assertEquals($this->Case->controller->data, $data); + + $result = $this->Case->testAction('/tests_apps_posts/post_var', array( + 'return' => 'vars', + 'method' => 'post', + 'data' => array( + 'name' => 'is jonas', + 'pork' => 'and beans', + ) + )); + $this->assertEqual(array_keys($result['data']), array('name', 'pork')); + + $result = $this->Case->testAction('/tests_apps_posts/add', array('return' => 'vars')); + $this->assertTrue(array_key_exists('posts', $result)); + $this->assertEqual(count($result['posts']), 4); + } + +/** + * Tests sending GET data to testAction + */ + function testTestActionGetData() { + $this->Case->autoMock = true; + + $result = $this->Case->testAction('/tests_apps_posts/url_var', array( + 'method' => 'get', + 'data' => array( + 'some' => 'var', + 'lackof' => 'creativity' + ) + )); + $this->Case->assertEquals($this->Case->controller->request->query['some'], 'var'); + $this->Case->assertEquals($this->Case->controller->request->query['lackof'], 'creativity'); + + $result = $this->Case->testAction('/tests_apps_posts/url_var/var1:value1/var2:val2', array( + 'return' => 'vars', + 'method' => 'get', + )); + $this->assertTrue(isset($result['params']['url']['url'])); + $this->assertEqual(array_keys($result['params']['named']), array('var1', 'var2')); + + $result = $this->Case->testAction('/tests_apps_posts/url_var/gogo/val2', array( + 'return' => 'vars', + 'method' => 'get', + )); + $this->assertEqual($result['params']['pass'], array('gogo', 'val2')); + + $result = $this->Case->testAction('/tests_apps_posts/url_var', array( + 'return' => 'vars', + 'method' => 'get', + 'data' => array( + 'red' => 'health', + 'blue' => 'mana' + ) + )); + $this->assertTrue(isset($result['params']['url']['red'])); + $this->assertTrue(isset($result['params']['url']['blue'])); + $this->assertTrue(isset($result['params']['url']['url'])); + } + +/** + * Tests autoMock ability + */ + function testAutoMock() { + $this->Case->autoMock = true; + $this->Case->testAction('/tests_apps/set_action'); + $results = $this->Case->controller->viewVars; + $expected = array( + 'var' => 'string' + ); + $this->Case->assertEquals($expected, $results); + } + +/** + * Test using testAction and not mocking + */ + function testNoMocking() { + $result = $this->Case->testAction('/tests_apps/some_method'); + $this->Case->assertEquals($result, 5); + + $data = array('var' => 'set'); + $result = $this->Case->testAction('/tests_apps_posts/post_var', array( + 'data' => $data, + 'return' => 'vars' + )); + $this->Case->assertEquals($result['data'], $data); + + $result = $this->Case->testAction('/tests_apps/set_action', array( + 'return' => 'view' + )); + $this->Case->assertEquals($result, 'This is the TestsAppsController index view'); + + $result = $this->Case->testAction('/tests_apps/set_action', array( + 'return' => 'contents' + )); + $this->Case->assertPattern('/Case->assertPattern('/This is the TestsAppsController index view/', $result); + $this->Case->assertPattern('/<\/html>/', $result); + } + +} \ No newline at end of file diff --git a/cake/tests/cases/libs/object_collection.test.php b/cake/tests/cases/libs/object_collection.test.php index fd51cbecd..ac5fb5a4c 100644 --- a/cake/tests/cases/libs/object_collection.test.php +++ b/cake/tests/cases/libs/object_collection.test.php @@ -133,6 +133,26 @@ class ObjectCollectionTest extends CakeTestCase { $this->assertEquals(array('Second'), $result, 'enabled objects are wrong'); } +/** + * Tests set() + * + * @return void + */ + function testSet() { + $this->Objects->load('First'); + + $result = $this->Objects->attached(); + $this->assertEquals(array('First'), $result, 'loaded objects are wrong'); + + $result = $this->Objects->set('First', new SecondGenericObject()); + $this->assertIsA($result['First'], 'SecondGenericObject', 'set failed'); + + $result = $this->Objects->set('Second', new SecondGenericObject()); + $this->assertIsA($result['Second'], 'SecondGenericObject', 'set failed'); + + $this->assertEquals(count($result), 2); + } + /** * creates mock classes for testing * diff --git a/cake/tests/lib/controller_test_case.php b/cake/tests/lib/controller_test_case.php new file mode 100644 index 000000000..d65650601 --- /dev/null +++ b/cake/tests/lib/controller_test_case.php @@ -0,0 +1,312 @@ + + * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests + * @package cake + * @subpackage cake.cake.tests.libs + * @since CakePHP(tm) v 2.0 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); + +require_once CAKE . 'libs' . DS . 'dispatcher.php'; +require_once CAKE_TESTS_LIB . 'cake_test_case.php'; +App::import('Core', array('Router', 'CakeRequest', 'CakeResponse', 'Helper')); + +/** + * ControllerTestDispatcher class + * + * @package cake + * @subpackage cake.cake.tests.lib + */ +class ControllerTestDispatcher extends Dispatcher { + +/** + * The controller to use in the dispatch process + * + * @var Controller + */ + public $testController = null; + +/** + * Use custom routes during tests + * + * @var boolean + */ + public $loadRoutes = true; + +/** + * Returns the test controller + * + * @return Controller + */ + function _getController($request) { + if ($this->testController === null) { + $this->testController = parent::_getController($request); + } + $this->testController->helpers = array_merge(array('InterceptContent'), $this->testController->helpers); + $this->testController->setRequest($request); + $this->testController->response = $this->response; + return $this->testController; + } + +/** + * Loads routes and resets if the test case dictates it should + * + * @return void + * @access private + */ + protected function __loadRoutes() { + parent::__loadRoutes(); + if (!$this->loadRoutes) { + Router::reload(); + } + } +} + +/** + * InterceptContentHelper class + * + * @package cake + * @subpackage cake.cake.tests.lib + */ +class InterceptContentHelper extends Helper { + +/** + * Intercepts and stores the contents of the view before the layout is rendered + * + * @param string $viewFile The view file + */ + function afterRender($viewFile) { + $this->_View->_viewNoLayout = $this->_View->output; + $this->_View->Helpers->unload('InterceptContent'); + } +} + +/** + * ControllerTestCase class + * + * @package cake + * @subpackage cake.cake.tests.lib + */ +class ControllerTestCase extends CakeTestCase { + +/** + * The controller to test in testAction + * + * @var Controller + */ + public $controller = null; + +/** + * Automatically mock controllers that aren't mocked + * + * @var boolean + */ + public $autoMock = false; + +/** + * Use custom routes during tests + * + * @var boolean + */ + public $loadRoutes = true; + +/** + * The resulting view vars of the last testAction call + * + * @var array + */ + public $vars = null; + +/** + * The resulting rendered view of the last testAction call + * + * @var string + */ + public $view = null; + +/** + * The resulting rendered layout+view of the last testAction call + * + * @var string + */ + public $contents = null; + +/** + * The returned result of the dispatch (requestAction), if any + * + * @var string + */ + public $result = null; + +/** + * The headers that would have been sent by the action + * + * @var string + */ + public $headers = null; + +/** + * Used to enable calling ControllerTestCase::testAction() without the testing + * framework thinking that it's a test case + * + * @param string $name The name of the function + * @param array $arguments Array of arguments + * @return Function + */ + public function __call($name, $arguments) { + if ($name == 'testAction') { + return call_user_func_array(array($this, '_testAction'), $arguments); + } + } + +/** + * Tests a controller action. + * + * ### Options: + * - `data` POST or GET data to pass + * - `method` POST or GET + * + * @param string $url The url to test + * @param array $options See options + */ + private function _testAction($url = '', $options = array()) { + $this->vars = $this->result = $this->view = $this->contents = $this->headers = null; + + $options = array_merge(array( + 'data' => array(), + 'method' => 'POST', + 'return' => 'result' + ), $options); + + if (strtoupper($options['method']) == 'GET') { + $_GET = $options['data']; + $_POST = array(); + } else { + $_POST = array('data' => $options['data']); + $_GET = array(); + } + $request = new CakeRequest($url); + $Dispatch = new ControllerTestDispatcher(); + foreach (Router::$routes as $route) { + if (is_a($route, 'RedirectRoute')) { + $route->response = $this->getMock('CakeResponse', array('send')); + } + } + $Dispatch->loadRoutes = $this->loadRoutes; + $request = $Dispatch->parseParams($request); + if (!isset($request->params['controller'])) { + $this->headers = Router::currentRoute()->response->header(); + return; + } + if ($this->controller !== null && Inflector::camelize($request->params['controller']) !== $this->controller->name) { + $this->controller = null; + } + if ($this->controller === null && $this->autoMock) { + $this->generate(Inflector::camelize($request->params['controller'])); + } + $params = array(); + if ($options['return'] == 'result') { + $params['return'] = 1; + $params['bare'] = 1; + $params['requested'] = 1; + } + $Dispatch->testController = $this->controller; + $Dispatch->response = $this->getMock('CakeResponse', array('send')); + $this->result = $Dispatch->dispatch($request, $params); + $this->controller = $Dispatch->testController; + if ($options['return'] != 'result') { + $this->vars = $this->controller->View->viewVars; + $this->view = $this->controller->View->_viewNoLayout; + $this->contents = $this->controller->response->body(); + } + $this->headers = $Dispatch->response->header(); + return $this->{$options['return']}; + } + +/** + * Generates a mocked controller and mocks any classes passed to `$mocks`. By + * default, `_stop()` is stubbed as is sending the response headers, so to not + * interfere with testing. + * + * ### Mocks: + * - `methods` Methods to mock on the controller. `_stop()` is mocked by default + * - `models` Models to mock. Models are added to the ClassRegistry so they any + * time they are instatiated the mock will be created. Pass as key value pairs + * with the value being specific methods on the model to mock. If `true` or + * no value is passed, the entire model will be mocked. + * - `components` Components to mock. Components are only mocked on this controller + * and not within each other (i.e., components on components) + * + * @param string $controller Controller name + * @param array $mocks List of classes and methods to mock + * @return Controller Mocked controller + */ + public function generate($controller, $mocks = array()) { + if (!class_exists($controller.'Controller') && App::import('Controller', $controller) === false) { + throw new MissingControllerException(array('controller' => $controller.'Controller')); + } + ClassRegistry::flush(); + + $mocks = array_merge_recursive(array( + 'methods' => array('_stop'), + 'models' => array(), + 'components' => array() + ), (array)$mocks); + + $_controller = $this->getMock($controller.'Controller', $mocks['methods'], array(), '', false); + $_controller->name = $controller; + $_controller->__construct(); + + foreach ($mocks['models'] as $model => $methods) { + if (is_string($methods)) { + $model = $methods; + $methods = true; + } + if ($methods === true) { + $methods = array(); + } + ClassRegistry::init($model); + $_model = $this->getMock($model, $methods, array(), '', false); + $_model->name = $model; + $_model->__construct(); + ClassRegistry::removeObject($model); + ClassRegistry::addObject($model, $_model); + } + + foreach ($mocks['components'] as $component => $methods) { + if (is_string($methods)) { + $component = $methods; + $methods = true; + } + if ($methods === true) { + $methods = array(); + } + if (!App::import('Component', $component)) { + throw new MissingComponentFileException(array( + 'file' => Inflector::underscore($component) . '.php', + 'class' => $componentClass + )); + } + $_component = $this->getMock($component.'Component', $methods, array(), '', false); + $_controller->Components->set($component, $_component); + } + + $_controller->constructClasses(); + + $this->controller = $_controller; + return $this->controller; + } +} \ No newline at end of file diff --git a/cake/tests/lib/test_manager.php b/cake/tests/lib/test_manager.php index f4f5b4571..9322db04e 100644 --- a/cake/tests/lib/test_manager.php +++ b/cake/tests/lib/test_manager.php @@ -89,6 +89,7 @@ class TestManager { */ public function __construct($params = array()) { require_once(CAKE_TESTS_LIB . 'cake_test_case.php'); + require_once(CAKE_TESTS_LIB . 'controller_test_case.php'); $this->params = $params; if (isset($params['app'])) { diff --git a/cake/tests/test_app/config/routes.php b/cake/tests/test_app/config/routes.php new file mode 100644 index 000000000..17fdccf25 --- /dev/null +++ b/cake/tests/test_app/config/routes.php @@ -0,0 +1,26 @@ + 'tests_apps', 'action' => 'some_method')); +Router::redirect('/redirect_me_now', 'http://cakephp.org'); +Router::redirect('/redirect_me', array('controller' => 'tests_apps', 'action' => 'some_method')); \ No newline at end of file diff --git a/cake/tests/test_app/controllers/tests_apps_controller.php b/cake/tests/test_app/controllers/tests_apps_controller.php index 28ed43f53..f7f2faf9f 100644 --- a/cake/tests/test_app/controllers/tests_apps_controller.php +++ b/cake/tests/test_app/controllers/tests_apps_controller.php @@ -32,4 +32,8 @@ class TestsAppsController extends AppController { $this->set('var', 'string'); $this->render('index'); } + + function redirect_to() { + $this->redirect('http://cakephp.org'); + } } diff --git a/cake/tests/test_app/views/layouts/json/default.ctp b/cake/tests/test_app/views/layouts/json/default.ctp new file mode 100644 index 000000000..3f290130e --- /dev/null +++ b/cake/tests/test_app/views/layouts/json/default.ctp @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cake/tests/test_app/views/tests_apps/json/index.ctp b/cake/tests/test_app/views/tests_apps/json/index.ctp new file mode 100644 index 000000000..49236e795 --- /dev/null +++ b/cake/tests/test_app/views/tests_apps/json/index.ctp @@ -0,0 +1 @@ +{"cakephp":"cool"} \ No newline at end of file From 754c9b2c3dd1198c6fb91c479520fc7c0ef6a396 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 15 Dec 2010 02:01:00 -0200 Subject: [PATCH 120/125] Updated to HttpSocket, HttpResponse and CakeSocket use SocketException. --- cake/libs/cake_socket.php | 4 ++-- cake/libs/error/exceptions.php | 8 +++++++ cake/libs/http_response.php | 10 ++++---- cake/libs/http_socket.php | 24 ++++++++++---------- cake/tests/cases/libs/cake_socket.test.php | 2 +- cake/tests/cases/libs/http_response.test.php | 2 +- 6 files changed, 29 insertions(+), 21 deletions(-) diff --git a/cake/libs/cake_socket.php b/cake/libs/cake_socket.php index 531c3b43a..e6f51ee54 100644 --- a/cake/libs/cake_socket.php +++ b/cake/libs/cake_socket.php @@ -100,7 +100,7 @@ class CakeSocket { * Connect the socket to the given host and port. * * @return boolean Success - * @throws Exception + * @throws SocketException */ public function connect() { if ($this->connection != null) { @@ -120,7 +120,7 @@ class CakeSocket { if (!empty($errNum) || !empty($errStr)) { $this->setLastError($errStr, $errNum); - throw new Exception($errStr, $errNum); + throw new SocketException($errStr, $errNum); } $this->connected = is_resource($this->connection); diff --git a/cake/libs/error/exceptions.php b/cake/libs/error/exceptions.php index b6d49061d..dc8538334 100644 --- a/cake/libs/error/exceptions.php +++ b/cake/libs/error/exceptions.php @@ -430,6 +430,14 @@ class CakeSessionException extends CakeException { } */ class ConfigureException extends CakeException { } +/** + * Exception class for Socket. This exception will be thrown from CakeSocket, HttpSocket and HttpResponse when it + * encounters an error. + * + * @package cake.libs + */ +class SocketException extends CakeException { } + /** * Exception class for Xml. This exception will be thrown from Xml when it * encounters an error. diff --git a/cake/libs/http_response.php b/cake/libs/http_response.php index 77b7feb02..ade1b14f4 100644 --- a/cake/libs/http_response.php +++ b/cake/libs/http_response.php @@ -123,15 +123,15 @@ class HttpResponse implements ArrayAccess { * * @param string $message Message to parse * @return void - * @throw Exception + * @throw SocketException */ public function parseResponse($message) { if (!is_string($message)) { - throw new Exception(__('Invalid response.')); + throw new SocketException(__('Invalid response.')); } if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) { - throw new Exception(__('Invalid HTTP response.')); + throw new SocketException(__('Invalid HTTP response.')); } list(, $statusLine, $header) = $match; @@ -187,7 +187,7 @@ class HttpResponse implements ArrayAccess { * * @param string $body A string continaing the chunked body to decode. * @return mixed Array of response headers and body or false. - * @throws Exception + * @throws SocketException */ protected function _decodeChunkedBody($body) { if (!is_string($body)) { @@ -199,7 +199,7 @@ class HttpResponse implements ArrayAccess { while ($chunkLength !== 0) { if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) { - throw new Exception(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.')); + throw new SocketException(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.')); } $chunkSize = 0; diff --git a/cake/libs/http_socket.php b/cake/libs/http_socket.php index cdbb7d77c..b1df3f25d 100644 --- a/cake/libs/http_socket.php +++ b/cake/libs/http_socket.php @@ -205,7 +205,7 @@ class HttpSocket extends CakeSocket { * * @param mixed $resource Resource or false to disable the resource use * @return void - * @throw Exception + * @throw SocketException */ public function setContentResource($resource) { if ($resource === false) { @@ -213,7 +213,7 @@ class HttpSocket extends CakeSocket { return; } if (!is_resource($resource)) { - throw new Exception(__('Invalid resource.')); + throw new SocketException(__('Invalid resource.')); } $this->_contentResource = $resource; } @@ -366,7 +366,7 @@ class HttpSocket extends CakeSocket { } if (!App::import('Lib', $this->responseClass)) { - throw new Exception(__('Class %s not found.', $this->responseClass)); + throw new SocketException(__('Class %s not found.', $this->responseClass)); } $responseClass = $this->responseClass; $this->response = new $responseClass($response); @@ -525,7 +525,7 @@ class HttpSocket extends CakeSocket { * Set authentication in request * * @return void - * @throws Exception + * @throws SocketException */ protected function _setAuth() { if (empty($this->_auth)) { @@ -534,10 +534,10 @@ class HttpSocket extends CakeSocket { $method = key($this->_auth); $authClass = Inflector::camelize($method) . 'Authentication'; if (!App::import('Lib', 'http/' . $authClass)) { - throw new Exception(__('Unknown authentication method.')); + throw new SocketException(__('Unknown authentication method.')); } if (!method_exists($authClass, 'authentication')) { - throw new Exception(sprintf(__('The %s do not support authentication.'), $authClass)); + throw new SocketException(sprintf(__('The %s do not support authentication.'), $authClass)); } call_user_func("$authClass::authentication", $this, &$this->_auth[$method]); } @@ -546,7 +546,7 @@ class HttpSocket extends CakeSocket { * Set the proxy configuration and authentication * * @return void - * @throws Exception + * @throws SocketException */ protected function _setProxy() { if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) { @@ -560,10 +560,10 @@ class HttpSocket extends CakeSocket { } $authClass = Inflector::camelize($this->_proxy['method']) . 'Authentication'; if (!App::import('Lib', 'http/' . $authClass)) { - throw new Exception(__('Unknown authentication method for proxy.')); + throw new SocketException(__('Unknown authentication method for proxy.')); } if (!method_exists($authClass, 'proxyAuthentication')) { - throw new Exception(sprintf(__('The %s do not support proxy authentication.'), $authClass)); + throw new SocketException(sprintf(__('The %s do not support proxy authentication.'), $authClass)); } call_user_func("$authClass::proxyAuthentication", $this, &$this->_proxy); } @@ -773,7 +773,7 @@ class HttpSocket extends CakeSocket { * @param array $request Needs to contain a 'uri' key. Should also contain a 'method' key, otherwise defaults to GET. * @param string $versionToken The version token to use, defaults to HTTP/1.1 * @return string Request line - * @throws Exception + * @throws SocketException */ protected function _buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') { $asteriskMethods = array('OPTIONS'); @@ -781,7 +781,7 @@ class HttpSocket extends CakeSocket { if (is_string($request)) { $isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match); if (!$this->quirksMode && (!$isValid || ($match[2] == '*' && !in_array($match[3], $asteriskMethods)))) { - throw new Exception(__('HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.')); + throw new SocketException(__('HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.')); } return $request; } elseif (!is_array($request)) { @@ -799,7 +799,7 @@ class HttpSocket extends CakeSocket { } if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) { - throw new Exception(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', implode(',', $asteriskMethods))); + throw new SocketException(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', implode(',', $asteriskMethods))); } return $request['method'] . ' ' . $request['uri'] . ' ' . $versionToken . "\r\n"; } diff --git a/cake/tests/cases/libs/cake_socket.test.php b/cake/tests/cases/libs/cake_socket.test.php index c14afbff6..8359db3bb 100644 --- a/cake/tests/cases/libs/cake_socket.test.php +++ b/cake/tests/cases/libs/cake_socket.test.php @@ -117,7 +117,7 @@ class CakeSocketTest extends CakeTestCase { * testInvalidConnection method * * @dataProvider invalidConnections - * @expectedException Exception + * @expectedException SocketException * return void */ public function testInvalidConnection($data) { diff --git a/cake/tests/cases/libs/http_response.test.php b/cake/tests/cases/libs/http_response.test.php index 63892535c..5d1647ebf 100644 --- a/cake/tests/cases/libs/http_response.test.php +++ b/cake/tests/cases/libs/http_response.test.php @@ -295,7 +295,7 @@ class HttpResponseTest extends CakeTestCase { * testInvalidParseResponseData * * @dataProvider invalidParseResponseDataProvider - * @expectedException Exception + * @expectedException SocketException * return void */ public function testInvalidParseResponseData($value) { From 29441ca880bd4a06325d1b6e9616aa466bd05bd1 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 14 Dec 2010 20:01:31 -0800 Subject: [PATCH 121/125] Added ObjectCollection test to libs group --- cake/tests/cases/libs/all_libs.test.php | 1 + 1 file changed, 1 insertion(+) diff --git a/cake/tests/cases/libs/all_libs.test.php b/cake/tests/cases/libs/all_libs.test.php index 0bab4f0e9..b0a070b49 100644 --- a/cake/tests/cases/libs/all_libs.test.php +++ b/cake/tests/cases/libs/all_libs.test.php @@ -49,6 +49,7 @@ class AllLibsTest extends PHPUnit_Framework_TestSuite { $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'set.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'string.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'validation.test.php'); + $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'object_collection.test.php'); return $suite; } } \ No newline at end of file From a6014cfd8de859cf0ccc34e7037fae78d12552be Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Wed, 15 Dec 2010 02:02:51 -0200 Subject: [PATCH 122/125] Fixed the define name to run all socket tests. --- cake/tests/cases/libs/all_socket.test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/tests/cases/libs/all_socket.test.php b/cake/tests/cases/libs/all_socket.test.php index ec276f580..01af39255 100644 --- a/cake/tests/cases/libs/all_socket.test.php +++ b/cake/tests/cases/libs/all_socket.test.php @@ -38,7 +38,7 @@ class AllSocketTest extends PHPUnit_Framework_TestSuite { $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_socket.test.php'); $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'http_socket.test.php'); - $suite->addTestFile(CAKE_TEST_CASES . DS . 'libs' . DS . 'http_response.test.php'); + $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'http_response.test.php'); $suite->addTestDirectory(CORE_TEST_CASES . DS . 'libs' . DS . 'http'); return $suite; } From 7b4ffa2ee9405ab782254e5fb68a0247772965ec Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 14 Dec 2010 23:22:03 -0500 Subject: [PATCH 123/125] Fixing incorrect exception type. --- cake/libs/controller/component_collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cake/libs/controller/component_collection.php b/cake/libs/controller/component_collection.php index 90ec17f17..b644902a9 100644 --- a/cake/libs/controller/component_collection.php +++ b/cake/libs/controller/component_collection.php @@ -78,7 +78,7 @@ class ComponentCollection extends ObjectCollection { )); } if (!class_exists($componentClass)) { - throw new MissingComponentFileException(array( + throw new MissingComponentClassException(array( 'file' => Inflector::underscore($component) . '.php', 'class' => $componentClass )); From 1531a7226e8cb1317e8a17d7a7c2b06f261e4e5d Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 14 Dec 2010 23:26:24 -0500 Subject: [PATCH 124/125] Removing duplicated tests, and tests for methods that are not implemented in the subclasses. --- .../console/libs/task_collection.test.php | 21 --- .../controller/component_collection.test.php | 156 ------------------ .../cases/libs/object_collection.test.php | 4 +- .../libs/view/helper_collection.test.php | 71 -------- 4 files changed, 2 insertions(+), 250 deletions(-) diff --git a/cake/tests/cases/console/libs/task_collection.test.php b/cake/tests/cases/console/libs/task_collection.test.php index da7d6eaef..b89de158c 100644 --- a/cake/tests/cases/console/libs/task_collection.test.php +++ b/cake/tests/cases/console/libs/task_collection.test.php @@ -118,25 +118,4 @@ class TaskCollectionTest extends CakeTestCase { $this->assertEquals(array('Extract'), $result, 'loaded tasks is wrong'); } -/** - * test normalizeObjectArray - * - * @return void - */ - function testnormalizeObjectArray() { - $tasks = array( - 'Html', - 'Foo.Bar' => array('one', 'two'), - 'Something', - 'Banana.Apple' => array('foo' => 'bar') - ); - $result = TaskCollection::normalizeObjectArray($tasks); - $expected = array( - 'Html' => array('class' => 'Html', 'settings' => array()), - 'Bar' => array('class' => 'Foo.Bar', 'settings' => array('one', 'two')), - 'Something' => array('class' => 'Something', 'settings' => array()), - 'Apple' => array('class' => 'Banana.Apple', 'settings' => array('foo' => 'bar')), - ); - $this->assertEquals($expected, $result); - } } \ No newline at end of file diff --git a/cake/tests/cases/libs/controller/component_collection.test.php b/cake/tests/cases/libs/controller/component_collection.test.php index ff96199b1..ecdac7775 100644 --- a/cake/tests/cases/libs/controller/component_collection.test.php +++ b/cake/tests/cases/libs/controller/component_collection.test.php @@ -119,162 +119,6 @@ class ComponentCollectionTest extends CakeTestCase { $this->assertEquals(array('Security'), $result, 'enabled components is wrong'); } -/** - * creates mock classes for testing - * - * @return void - */ - protected function _makeMockClasses() { - if (!class_exists('TriggerMockCookieComponent')) { - $this->getMock('CookieComponent', array(), array(), 'TriggerMockCookieComponent', false); - $this->getMock('SecurityComponent', array(), array(), 'TriggerMockSecurityComponent', false); - } - } - -/** - * test triggering callbacks. - * - * @return void - */ - function testTrigger() { - $controller = null; - $this->_makeMockClasses(); - $this->Components->load('TriggerMockCookie'); - $this->Components->load('TriggerMockSecurity'); - - $this->Components->TriggerMockCookie->expects($this->once())->method('startup') - ->with(null); - $this->Components->TriggerMockSecurity->expects($this->once())->method('startup') - ->with(null); - - $this->mockObjects[] = $this->Components->TriggerMockCookie; - $this->mockObjects[] = $this->Components->TriggerMockSecurity; - - $this->assertNull($this->Components->trigger('startup', array(&$controller))); - } - -/** - * test that the initalize callback is triggered on all components even those that are disabled. - * - * @return void - */ - function testTriggerWithTriggerDisabledObjects() { - $controller = 'Not a controller'; - - $this->_makeMockClasses(); - $this->Components->load('TriggerMockCookie', array(), false); - $this->Components->load('TriggerMockSecurity'); - - $this->Components->TriggerMockCookie->expects($this->once())->method('initialize') - ->with($controller); - $this->Components->TriggerMockSecurity->expects($this->once())->method('initialize') - ->with($controller); - - $this->mockObjects[] = $this->Components->TriggerMockCookie; - $this->mockObjects[] = $this->Components->TriggerMockSecurity; - - $result = $this->Components->trigger('initialize', array(&$controller), array('triggerDisabled' => true)); - $this->assertNull($result); - } - -/** - * test trigger and disabled helpers. - * - * @return void - */ - function testTriggerWithDisabledComponents() { - $controller = null; - $this->_makeMockClasses(); - $this->Components->load('TriggerMockCookie'); - $this->Components->load('TriggerMockSecurity'); - - $this->Components->TriggerMockCookie->expects($this->once())->method('startup') - ->with($controller); - $this->Components->TriggerMockSecurity->expects($this->never())->method('startup'); - - $this->mockObjects[] = $this->Components->TriggerMockCookie; - $this->mockObjects[] = $this->Components->TriggerMockSecurity; - - $this->Components->disable('TriggerMockSecurity'); - - $this->assertNull($this->Components->trigger('startup', array(&$controller))); - } - -/** - * test that the collectReturn option works. - * - * @return void - */ - function testTriggerWithCollectReturn() { - $controller = null; - $this->_makeMockClasses(); - $this->Components->load('TriggerMockCookie'); - $this->Components->load('TriggerMockSecurity'); - - $this->Components->TriggerMockCookie->expects($this->once())->method('startup') - ->will($this->returnValue(array('one', 'two'))); - $this->Components->TriggerMockSecurity->expects($this->once())->method('startup') - ->will($this->returnValue(array('three', 'four'))); - - $this->mockObjects[] = $this->Components->TriggerMockCookie; - $this->mockObjects[] = $this->Components->TriggerMockSecurity; - - $result = $this->Components->trigger('startup', array(&$controller), array('collectReturn' => true)); - $expected = array( - array('one', 'two'), - array('three', 'four') - ); - $this->assertEquals($expected, $result); - } - -/** - * test that trigger with break & breakOn works. - * - * @return void - */ - function testTriggerWithBreak() { - $controller = null; - $this->_makeMockClasses(); - $this->Components->load('TriggerMockCookie'); - $this->Components->load('TriggerMockSecurity'); - - $this->Components->TriggerMockCookie->expects($this->once())->method('startup') - ->will($this->returnValue(false)); - $this->Components->TriggerMockSecurity->expects($this->never())->method('startup'); - - $this->mockObjects[] = $this->Components->TriggerMockCookie; - $this->mockObjects[] = $this->Components->TriggerMockSecurity; - - $result = $this->Components->trigger( - 'startup', - array(&$controller), - array('break' => true, 'breakOn' => false) - ); - $this->assertFalse($result); - } - -/** - * test normalizeObjectArray - * - * @return void - */ - function testnormalizeObjectArray() { - $components = array( - 'Html', - 'Foo.Bar' => array('one', 'two'), - 'Something', - 'Banana.Apple' => array('foo' => 'bar') - ); - $result = ComponentCollection::normalizeObjectArray($components); - $expected = array( - 'Html' => array('class' => 'Html', 'settings' => array()), - 'Bar' => array('class' => 'Foo.Bar', 'settings' => array('one', 'two')), - 'Something' => array('class' => 'Something', 'settings' => array()), - 'Apple' => array('class' => 'Banana.Apple', 'settings' => array('foo' => 'bar')), - ); - $this->assertEquals($expected, $result); - } - /** * test getting the controller out of the collection * diff --git a/cake/tests/cases/libs/object_collection.test.php b/cake/tests/cases/libs/object_collection.test.php index fd51cbecd..73e0fec4f 100644 --- a/cake/tests/cases/libs/object_collection.test.php +++ b/cake/tests/cases/libs/object_collection.test.php @@ -189,11 +189,11 @@ class ObjectCollectionTest extends CakeTestCase { } /** - * test trigger and disabled helpers. + * test trigger and disabled objects * * @return void */ - function testTriggerWithDisabledComponents() { + function testTriggerWithDisabledObjects() { $this->_makeMockClasses(); $this->Objects->load('TriggerMockFirst'); $this->Objects->load('TriggerMockSecond'); diff --git a/cake/tests/cases/libs/view/helper_collection.test.php b/cake/tests/cases/libs/view/helper_collection.test.php index 403bbc8e7..d5f1480dd 100644 --- a/cake/tests/cases/libs/view/helper_collection.test.php +++ b/cake/tests/cases/libs/view/helper_collection.test.php @@ -116,75 +116,4 @@ class HelperCollectionTest extends CakeTestCase { $this->assertEquals(array('Form'), $result, 'loaded helpers is wrong'); } -/** - * test triggering callbacks. - * - * @return void - */ - function testTrigger() { - if (!class_exists('TriggerMockHtmlHelper')) { - $this->getMock('HtmlHelper', array(), array($this->View), 'TriggerMockHtmlHelper'); - $this->getMock('FormHelper', array(), array($this->View), 'TriggerMockFormHelper'); - } - - $this->Helpers->load('TriggerMockHtml'); - $this->Helpers->load('TriggerMockForm'); - - $this->Helpers->TriggerMockHtml->expects($this->once())->method('beforeRender') - ->with('one', 'two'); - $this->Helpers->TriggerMockForm->expects($this->once())->method('beforeRender') - ->with('one', 'two'); - - $this->mockObjects[] = $this->Helpers->TriggerMockForm; - - $this->assertNull($this->Helpers->trigger('beforeRender', array('one', 'two'))); - } - -/** - * test trigger and disabled helpers. - * - * @return void - */ - function testTriggerWithDisabledHelpers() { - if (!class_exists('TriggerMockHtmlHelper')) { - $this->getMock('HtmlHelper', array(), array(), 'TriggerMockHtmlHelper', false); - $this->getMock('FormHelper', array(), array(), 'TriggerMockFormHelper', false); - } - - $this->Helpers->load('TriggerMockHtml'); - $this->Helpers->load('TriggerMockForm'); - - $this->Helpers->TriggerMockHtml->expects($this->once())->method('beforeRender') - ->with('one', 'two'); - $this->Helpers->TriggerMockForm->expects($this->never())->method('beforeRender'); - - $this->mockObjects[] = $this->Helpers->TriggerMockForm; - $this->mockObjects[] = $this->Helpers->TriggerMockHtml; - - $this->Helpers->disable('TriggerMockForm'); - - $this->assertNull($this->Helpers->trigger('beforeRender', array('one', 'two'))); - } - -/** - * test normalizeObjectArray - * - * @return void - */ - function testnormalizeObjectArray() { - $helpers = array( - 'Html', - 'Foo.Bar' => array('one', 'two'), - 'Something', - 'Banana.Apple' => array('foo' => 'bar') - ); - $result = ObjectCollection::normalizeObjectArray($helpers); - $expected = array( - 'Html' => array('class' => 'Html', 'settings' => array()), - 'Bar' => array('class' => 'Foo.Bar', 'settings' => array('one', 'two')), - 'Something' => array('class' => 'Something', 'settings' => array()), - 'Apple' => array('class' => 'Banana.Apple', 'settings' => array('foo' => 'bar')), - ); - $this->assertEquals($expected, $result); - } } \ No newline at end of file From 97c82e28a1c19397a4990f83016449bf99f24427 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 14 Dec 2010 20:27:12 -0800 Subject: [PATCH 125/125] Fixed problems where running all tests will fail due to duplicate classes --- .../controller/components/paginator.test.php | 172 +++++++++--------- .../cases/libs/controller/controller.test.php | 44 ----- .../cases/libs/controller_test_case.test.php | 28 +-- 3 files changed, 102 insertions(+), 142 deletions(-) diff --git a/cake/tests/cases/libs/controller/components/paginator.test.php b/cake/tests/cases/libs/controller/components/paginator.test.php index 93ee5b6b5..cb6beb153 100644 --- a/cake/tests/cases/libs/controller/components/paginator.test.php +++ b/cake/tests/cases/libs/controller/components/paginator.test.php @@ -55,20 +55,20 @@ class PaginatorTestController extends Controller { } /** - * ControllerPost class + * PaginatorControllerPost class * * @package cake * @subpackage cake.tests.cases.libs.controller.components */ -class ControllerPost extends CakeTestModel { +class PaginatorControllerPost extends CakeTestModel { /** * name property * - * @var string 'ControllerPost' + * @var string 'PaginatorControllerPost' * @access public */ - public $name = 'ControllerPost'; + public $name = 'PaginatorControllerPost'; /** * useTable property @@ -168,12 +168,12 @@ class ControllerPaginateModel extends CakeTestModel { } /** - * ControllerComment class + * PaginatorControllerCommentclass * * @package cake * @subpackage cake.tests.cases.libs.controller.components */ -class ControllerComment extends CakeTestModel { +class PaginatorControllerComment extends CakeTestModel { /** * name property @@ -194,10 +194,10 @@ class ControllerComment extends CakeTestModel { /** * alias property * - * @var string 'ControllerComment' + * @var string 'PaginatorControllerComment' * @access public */ - public $alias = 'ControllerComment'; + public $alias = 'PaginatorControllerComment'; } class PaginatorTest extends CakeTestCase { @@ -221,82 +221,82 @@ class PaginatorTest extends CakeTestCase { $request->params['pass'] = $request->params['named'] = array(); $Controller = new PaginatorTestController($request); - $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment'); $Controller->passedArgs[] = '1'; $Controller->params['url'] = array(); $Controller->constructClasses(); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); $this->assertEqual($results, array(1, 2, 3)); - $results = Set::extract($Controller->Paginator->paginate('ControllerComment'), '{n}.ControllerComment.id'); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerComment'), '{n}.PaginatorControllerComment.id'); $this->assertEqual($results, array(1, 2, 3, 4, 5, 6)); $Controller->modelClass = null; - $Controller->uses[0] = 'Plugin.ControllerPost'; - $results = Set::extract($Controller->Paginator->paginate(), '{n}.ControllerPost.id'); + $Controller->uses[0] = 'Plugin.PaginatorControllerPost'; + $results = Set::extract($Controller->Paginator->paginate(), '{n}.PaginatorControllerPost.id'); $this->assertEqual($results, array(1, 2, 3)); $Controller->passedArgs = array('page' => '-1'); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['page'], 1); $this->assertEqual($results, array(1, 2, 3)); - $Controller->passedArgs = array('sort' => 'ControllerPost.id', 'direction' => 'asc'); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $Controller->passedArgs = array('sort' => 'PaginatorControllerPost.id', 'direction' => 'asc'); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['page'], 1); $this->assertEqual($results, array(1, 2, 3)); - $Controller->passedArgs = array('sort' => 'ControllerPost.id', 'direction' => 'desc'); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $Controller->passedArgs = array('sort' => 'PaginatorControllerPost.id', 'direction' => 'desc'); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['page'], 1); $this->assertEqual($results, array(3, 2, 1)); $Controller->passedArgs = array('sort' => 'id', 'direction' => 'desc'); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['page'], 1); $this->assertEqual($results, array(3, 2, 1)); $Controller->passedArgs = array('sort' => 'NotExisting.field', 'direction' => 'desc'); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1, 'Invalid field in query %s'); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['page'], 1, 'Invalid field in query %s'); $this->assertEqual($results, array(1, 2, 3)); - $Controller->passedArgs = array('sort' => 'ControllerPost.author_id', 'direction' => 'allYourBase'); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->ControllerPost->lastQuery['order'][0], array('ControllerPost.author_id' => 'asc')); + $Controller->passedArgs = array('sort' => 'PaginatorControllerPost.author_id', 'direction' => 'allYourBase'); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); + $this->assertEqual($Controller->PaginatorControllerPost->lastQuery['order'][0], array('PaginatorControllerPost.author_id' => 'asc')); $this->assertEqual($results, array(1, 3, 2)); $Controller->passedArgs = array('page' => '1 " onclick="alert(\'xss\');">'); $Controller->Paginator->settings = array('limit' => 1); - $Controller->Paginator->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1, 'XSS exploit opened %s'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['options']['page'], 1, 'XSS exploit opened %s'); + $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['page'], 1, 'XSS exploit opened %s'); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['options']['page'], 1, 'XSS exploit opened %s'); $Controller->passedArgs = array(); $Controller->Paginator->settings = array('limit' => 0); - $Controller->Paginator->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); + $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['page'], 1); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['pageCount'], 3); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['prevPage'], false); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['nextPage'], true); $Controller->passedArgs = array(); $Controller->Paginator->settings = array('limit' => 'garbage!'); - $Controller->Paginator->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); + $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['page'], 1); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['pageCount'], 3); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['prevPage'], false); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['nextPage'], true); $Controller->passedArgs = array(); $Controller->Paginator->settings = array('limit' => '-1'); - $Controller->Paginator->paginate('ControllerPost'); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false); - $this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true); + $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['page'], 1); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['pageCount'], 3); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['prevPage'], false); + $this->assertIdentical($Controller->params['paging']['PaginatorControllerPost']['nextPage'], true); } /** @@ -311,35 +311,35 @@ class PaginatorTest extends CakeTestCase { $Controller = new PaginatorTestController($request); - $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment'); $Controller->passedArgs[] = '1'; $Controller->params['url'] = array(); $Controller->constructClasses(); - $Controller->passedArgs = array('page' => '-1', 'contain' => array('ControllerComment')); - $result = $Controller->Paginator->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(1, 2, 3)); - $this->assertTrue(!isset($Controller->ControllerPost->lastQuery['contain'])); + $Controller->passedArgs = array('page' => '-1', 'contain' => array('PaginatorControllerComment')); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['page'], 1); + $this->assertEqual(Set::extract($result, '{n}.PaginatorControllerPost.id'), array(1, 2, 3)); + $this->assertTrue(!isset($Controller->PaginatorControllerPost->lastQuery['contain'])); $Controller->passedArgs = array('page' => '-1'); - $Controller->Paginator->settings = array('ControllerPost' => array('contain' => array('ControllerComment'))); - $result = $Controller->Paginator->paginate('ControllerPost'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['page'], 1); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(1, 2, 3)); - $this->assertTrue(isset($Controller->ControllerPost->lastQuery['contain'])); + $Controller->Paginator->settings = array('PaginatorControllerPost' => array('contain' => array('PaginatorControllerComment'))); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['page'], 1); + $this->assertEqual(Set::extract($result, '{n}.PaginatorControllerPost.id'), array(1, 2, 3)); + $this->assertTrue(isset($Controller->PaginatorControllerPost->lastQuery['contain'])); - $Controller->Paginator->settings = array('ControllerPost' => array('popular', 'fields' => array('id', 'title'))); - $result = $Controller->Paginator->paginate('ControllerPost'); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(2, 3)); - $this->assertEqual($Controller->ControllerPost->lastQuery['conditions'], array('ControllerPost.id > ' => '1')); + $Controller->Paginator->settings = array('PaginatorControllerPost' => array('popular', 'fields' => array('id', 'title'))); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.PaginatorControllerPost.id'), array(2, 3)); + $this->assertEqual($Controller->PaginatorControllerPost->lastQuery['conditions'], array('PaginatorControllerPost.id > ' => '1')); $Controller->passedArgs = array('limit' => 12); $Controller->Paginator->settings = array('limit' => 30); - $result = $Controller->Paginator->paginate('ControllerPost'); - $paging = $Controller->params['paging']['ControllerPost']; + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $paging = $Controller->params['paging']['PaginatorControllerPost']; - $this->assertEqual($Controller->ControllerPost->lastQuery['limit'], 12); + $this->assertEqual($Controller->PaginatorControllerPost->lastQuery['limit'], 12); $this->assertEqual($paging['options']['limit'], 12); $Controller = new PaginatorTestController($request); @@ -373,7 +373,7 @@ class PaginatorTest extends CakeTestCase { $request->params['pass'] = $request->params['named'] = array(); $Controller = new PaginatorTestController($request); - $Controller->uses = array('ControllerPost'); + $Controller->uses = array('PaginatorControllerPost'); $Controller->passedArgs[] = array('1', '2', '3'); $Controller->params['url'] = array(); $Controller->constructClasses(); @@ -386,7 +386,7 @@ class PaginatorTest extends CakeTestCase { 'recursive' => -1 ); $conditions = array(); - $Controller->Paginator->paginate('ControllerPost',$conditions); + $Controller->Paginator->paginate('PaginatorControllerPost',$conditions); $expected = array( 'fields' => array(), @@ -396,7 +396,7 @@ class PaginatorTest extends CakeTestCase { 'recursive' => -1, 'conditions' => array() ); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options'],$expected); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['options'],$expected); } /** @@ -409,18 +409,18 @@ class PaginatorTest extends CakeTestCase { $request->params['pass'] = $request->params['named'] = array(); $Controller = new PaginatorTestController($request); - $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment'); $Controller->passedArgs[] = '1'; $Controller->params['url'] = array(); $Controller->constructClasses(); - $Controller->Paginator->settings = array('ControllerPost' => array('popular', 'fields' => array('id', 'title'))); - $result = $Controller->Paginator->paginate('ControllerPost'); + $Controller->Paginator->settings = array('PaginatorControllerPost' => array('popular', 'fields' => array('id', 'title'))); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.id'), array(2, 3)); - $this->assertEqual($Controller->ControllerPost->lastQuery['conditions'], array('ControllerPost.id > ' => '1')); - $this->assertFalse(isset($Controller->params['paging']['ControllerPost']['defaults'][0])); - $this->assertFalse(isset($Controller->params['paging']['ControllerPost']['options'][0])); + $this->assertEqual(Set::extract($result, '{n}.PaginatorControllerPost.id'), array(2, 3)); + $this->assertEqual($Controller->PaginatorControllerPost->lastQuery['conditions'], array('PaginatorControllerPost.id > ' => '1')); + $this->assertFalse(isset($Controller->params['paging']['PaginatorControllerPost']['defaults'][0])); + $this->assertFalse(isset($Controller->params['paging']['PaginatorControllerPost']['options'][0])); } /** @@ -434,13 +434,13 @@ class PaginatorTest extends CakeTestCase { $request->params['pass'] = $request->params['named'] = array(); $Controller = new PaginatorTestController($request); - $Controller->modelClass = 'ControllerPost'; + $Controller->modelClass = 'PaginatorControllerPost'; $Controller->params['url'] = array(); $Controller->constructClasses(); - $Controller->Paginator->settings = array('order' => 'ControllerPost.id DESC'); - $results = Set::extract($Controller->Paginator->paginate('ControllerPost'), '{n}.ControllerPost.id'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['defaults']['order'], 'ControllerPost.id DESC'); - $this->assertEqual($Controller->params['paging']['ControllerPost']['options']['order'], 'ControllerPost.id DESC'); + $Controller->Paginator->settings = array('order' => 'PaginatorControllerPost.id DESC'); + $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['defaults']['order'], 'PaginatorControllerPost.id DESC'); + $this->assertEqual($Controller->params['paging']['PaginatorControllerPost']['options']['order'], 'PaginatorControllerPost.id DESC'); $this->assertEqual($results, array(3, 2, 1)); } @@ -454,23 +454,23 @@ class PaginatorTest extends CakeTestCase { $request->params['pass'] = $request->params['named'] = array(); $Controller = new PaginatorTestController($request); - $Controller->uses = array('ControllerPost', 'ControllerComment'); + $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment'); $Controller->params['url'] = array(); $Controller->constructClasses(); - $Controller->ControllerPost->virtualFields = array( - 'offset_test' => 'ControllerPost.id + 1' + $Controller->PaginatorControllerPost->virtualFields = array( + 'offset_test' => 'PaginatorControllerPost.id + 1' ); $Controller->Paginator->settings = array( 'fields' => array('id', 'title', 'offset_test'), 'order' => array('offset_test' => 'DESC') ); - $result = $Controller->Paginator->paginate('ControllerPost'); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(4, 3, 2)); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.PaginatorControllerPost.offset_test'), array(4, 3, 2)); $Controller->passedArgs = array('sort' => 'offset_test', 'direction' => 'asc'); - $result = $Controller->Paginator->paginate('ControllerPost'); - $this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(2, 3, 4)); + $result = $Controller->Paginator->paginate('PaginatorControllerPost'); + $this->assertEqual(Set::extract($result, '{n}.PaginatorControllerPost.offset_test'), array(2, 3, 4)); } /** diff --git a/cake/tests/cases/libs/controller/controller.test.php b/cake/tests/cases/libs/controller/controller.test.php index 0521283b2..6f217b3e9 100644 --- a/cake/tests/cases/libs/controller/controller.test.php +++ b/cake/tests/cases/libs/controller/controller.test.php @@ -222,50 +222,6 @@ class ControllerAlias extends CakeTestModel { public $useTable = 'posts'; } -/** - * ControllerPaginateModel class - * - * @package cake - * @subpackage cake.tests.cases.libs.controller - */ -class ControllerPaginateModel extends CakeTestModel { - -/** - * name property - * - * @var string - * @access public - */ - public $name = 'ControllerPaginateModel'; - -/** - * useTable property - * - * @var string' - * @access public - */ - public $useTable = 'comments'; - -/** - * paginate method - * - * @return void - */ - public function paginate($conditions, $fields, $order, $limit, $page, $recursive, $extra) { - $this->extra = $extra; - } - -/** - * paginateCount - * - * @access public - * @return void - */ - function paginateCount($conditions, $recursive, $extra) { - $this->extraCount = $extra; - } -} - /** * NameTest class * diff --git a/cake/tests/cases/libs/controller_test_case.test.php b/cake/tests/cases/libs/controller_test_case.test.php index db66d0a9d..5b5294e75 100644 --- a/cake/tests/cases/libs/controller_test_case.test.php +++ b/cake/tests/cases/libs/controller_test_case.test.php @@ -65,24 +65,28 @@ if (!class_exists('AppController')) { /** * PostsController class */ -class PostsController extends AppController { +if (!class_exists('PostsController')) { + class PostsController extends AppController { -/** - * Components array - * - * @var array - */ - public $components = array( - 'RequestHandler', - 'Email', - 'Auth' - ); + /** + * Components array + * + * @var array + */ + public $components = array( + 'RequestHandler', + 'Email', + 'Auth' + ); + } } /** * Post model */ -class Post extends CakeTestModel { +if (!class_exists('Post')) { + class Post extends CakeTestModel { + } } /**