From 3aa1892121aa25357aa5cf5f78bcc48c967568c7 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 13 Apr 2014 12:09:16 -0400 Subject: [PATCH 01/25] [hhvm] remove session serialize handler hack --- src/Ratchet/Session/SessionProvider.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Ratchet/Session/SessionProvider.php b/src/Ratchet/Session/SessionProvider.php index 8aefc96..a8495b2 100644 --- a/src/Ratchet/Session/SessionProvider.php +++ b/src/Ratchet/Session/SessionProvider.php @@ -56,14 +56,7 @@ class SessionProvider implements MessageComponentInterface, WsServerInterface { $this->setOptions($options); if (null === $serializer) { - // Temporarily fixing HHVM issue w/ reading ini values - $handler_name = ini_get('session.serialize_handler'); - if ('' === $handler_name) { - trigger_error('ini value session.seralize_handler was empty, assuming "php" - tmp hack/fix, bad things might happen', E_USER_WARNING); - $handler_name = 'php'; - } - - $serialClass = __NAMESPACE__ . "\\Serialize\\{$this->toClassCase($handler_name)}Handler"; // awesome/terrible hack, eh? + $serialClass = __NAMESPACE__ . "\\Serialize\\{$this->toClassCase(ini_get('session.serialize_handler'))}Handler"; // awesome/terrible hack, eh? if (!class_exists($serialClass)) { throw new \RuntimeException('Unable to parse session serialize handler'); } From 9b38d863b8dbac73298a9e495677f71598d600c7 Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Mon, 14 Apr 2014 17:24:36 +0200 Subject: [PATCH 02/25] Fix app for flash usage --- src/Ratchet/App.php | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index da634af..7cb4363 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -49,12 +49,16 @@ class App { protected $_routeCounter = 0; /** - * @param string $httpHost HTTP hostname clients intend to connect to. MUST match JS `new WebSocket('ws://$httpHost');` - * @param int $port Port to listen on. If 80, assuming production, Flash on 843 otherwise expecting Flash to be proxied through 8843 - * @param string $address IP address to bind to. Default is localhost/proxy only. '0.0.0.0' for any machine. + * @param string $httpHost HTTP hostname clients intend to connect to. MUST match JS `new WebSocket('ws://$httpHost');` + * @param int $port Port to listen on. If 80, assuming production, Flash on 843 otherwise expecting Flash to be proxied through 8843 + * @param string $address IP address to bind to. Default is localhost/proxy only. '0.0.0.0' for any machine. + * @param array $flashAllowedHosts associative array with ports as key and hostnames as value. These domains are the domains the fhlash websocket fallback may connect from + * @param int $flashPort the port the flash cross-domain-policy file will be hosted on + * @param string $flashHost the host the flash cross-domain-policy file will be hosted on * @param LoopInterface $loop Specific React\EventLoop to bind the application to. null will create one for you. */ - public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', LoopInterface $loop = null) { + public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', $flashAllowedHosts = false, $flashPort = 8843, $flashHost = '0.0.0.0', LoopInterface $loop = null) { + if (extension_loaded('xdebug')) { trigger_error("XDebug extension detected. Remember to disable this if performance testing or going live!", E_USER_WARNING); } @@ -75,17 +79,20 @@ class App { $this->routes = new RouteCollection; $this->_server = new IoServer(new HttpServer(new Router(new UrlMatcher($this->routes, new RequestContext))), $socket, $loop); - $policy = new FlashPolicy; - $policy->addAllowedAccess($httpHost, 80); - $policy->addAllowedAccess($httpHost, $port); - $flashSock = new Reactor($loop); - $this->flashServer = new IoServer($policy, $flashSock); - - if (80 == $port) { - $flashSock->listen(843, '0.0.0.0'); - } else { - $flashSock->listen(8843); + if ($flashAllowedHosts === false) { + $flashAllowedHosts = [ 80 => $httpHost ]; } + + $policy = new FlashPolicy(); + + foreach ($flashAllowedHosts as $flashAllowedPort => $flashAllowedHost) { + $policy->addAllowedAccess($flashAllowedHost, $flashAllowedPort); + } + + $flashSock = new Reactor($loop); + + $this->flashServer = new IoServer($policy, $flashSock); + $flashSock->listen($flashPort, $flashHost); } /** From 97e01225700147acfbd202a693d7a26216fb8be9 Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Tue, 15 Apr 2014 09:29:17 +0200 Subject: [PATCH 03/25] Improved comments and changed some parameter definitions/names. --- src/Ratchet/App.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index 7cb4363..1d87915 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -49,15 +49,15 @@ class App { protected $_routeCounter = 0; /** - * @param string $httpHost HTTP hostname clients intend to connect to. MUST match JS `new WebSocket('ws://$httpHost');` - * @param int $port Port to listen on. If 80, assuming production, Flash on 843 otherwise expecting Flash to be proxied through 8843 - * @param string $address IP address to bind to. Default is localhost/proxy only. '0.0.0.0' for any machine. - * @param array $flashAllowedHosts associative array with ports as key and hostnames as value. These domains are the domains the fhlash websocket fallback may connect from + * @param string $httpHost HTTP hostname clients intend to connect to. MUST match JS `new WebSocket('ws://$httpHost') + * @param int $port Port to listen on + * @param string $address IP address to bind to. Default is localhost/proxy only. '0.0.0.0' for any machine + * @param array $flashAllowedHosts associative array with hostnames as key and ports as value. These domains are the domains the flash websocket fallback may connect from * @param int $flashPort the port the flash cross-domain-policy file will be hosted on - * @param string $flashHost the host the flash cross-domain-policy file will be hosted on + * @param string $flashAddress the IP address the flash cross-domain-policy server will bind to * @param LoopInterface $loop Specific React\EventLoop to bind the application to. null will create one for you. */ - public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', $flashAllowedHosts = false, $flashPort = 8843, $flashHost = '0.0.0.0', LoopInterface $loop = null) { + public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', $flashAllowedHosts = false, $flashPort = 8843, $flashAddress = '0.0.0.0', LoopInterface $loop = null) { if (extension_loaded('xdebug')) { trigger_error("XDebug extension detected. Remember to disable this if performance testing or going live!", E_USER_WARNING); @@ -85,14 +85,14 @@ class App { $policy = new FlashPolicy(); - foreach ($flashAllowedHosts as $flashAllowedPort => $flashAllowedHost) { + foreach ($flashAllowedHosts as $flashAllowedHost => $flashAllowedPort) { $policy->addAllowedAccess($flashAllowedHost, $flashAllowedPort); } $flashSock = new Reactor($loop); $this->flashServer = new IoServer($policy, $flashSock); - $flashSock->listen($flashPort, $flashHost); + $flashSock->listen($flashPort, $flashAddress); } /** From 8dd1fd8882dde5ff350eab1d7fbd6dcf0298a94d Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 19 Apr 2014 13:43:09 -0400 Subject: [PATCH 04/25] [Sessions] Attempt to set ini vars for CI to fix HHVM --- .travis.yml | 1 + tests/config.ini | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 tests/config.ini diff --git a/.travis.yml b/.travis.yml index 2c7bef4..611c0ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,5 @@ matrix: - php: hhvm before_script: + - phpenv config-add tests/config.ini - composer install --dev --prefer-source diff --git a/tests/config.ini b/tests/config.ini new file mode 100644 index 0000000..be28dd1 --- /dev/null +++ b/tests/config.ini @@ -0,0 +1,2 @@ +session.serialize_handler = php + From b4dda40ba45a8a8c08ed6b82ec78a1122ef42995 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 19 Apr 2014 13:56:21 -0400 Subject: [PATCH 05/25] [Sessions][HHVM] Another attempt to pass CI tests --- .travis.yml | 2 +- tests/config.ini | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 tests/config.ini diff --git a/.travis.yml b/.travis.yml index 611c0ea..30f5601 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,5 +11,5 @@ matrix: - php: hhvm before_script: - - phpenv config-add tests/config.ini + - sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "session.serialize_handler = php" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;' - composer install --dev --prefer-source diff --git a/tests/config.ini b/tests/config.ini deleted file mode 100644 index be28dd1..0000000 --- a/tests/config.ini +++ /dev/null @@ -1,2 +0,0 @@ -session.serialize_handler = php - From 4100daef7a8af71534f87e3bb8b42e768650178f Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 3 May 2014 10:24:38 -0400 Subject: [PATCH 06/25] [tests] Added hhvm-nightly to travis builds --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 30f5601..e3bd916 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,12 @@ php: - 5.4 - 5.5 - hhvm + - hhvm-nightly matrix: allow_failures: - php: hhvm + - php: hhvm-nightly before_script: - sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "session.serialize_handler = php" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;' From 20c55be5132a1bf41de9328dec4b0fb046a1b5f0 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 3 May 2014 10:27:43 -0400 Subject: [PATCH 07/25] [tests] Removed hhvm-nightly due to build error --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e3bd916..30f5601 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,10 @@ php: - 5.4 - 5.5 - hhvm - - hhvm-nightly matrix: allow_failures: - php: hhvm - - php: hhvm-nightly before_script: - sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "session.serialize_handler = php" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;' From ae5e383c02e4600f345a450552a34f0dc672e768 Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Mon, 19 May 2014 09:28:43 +0200 Subject: [PATCH 08/25] small change for PHP 5.3 compatibility --- src/Ratchet/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index 1d87915..d9baff0 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -80,7 +80,7 @@ class App { $this->_server = new IoServer(new HttpServer(new Router(new UrlMatcher($this->routes, new RequestContext))), $socket, $loop); if ($flashAllowedHosts === false) { - $flashAllowedHosts = [ 80 => $httpHost ]; + $flashAllowedHosts = array( 80 => $httpHost ); } $policy = new FlashPolicy(); From 06c4c3ddd8b8c54c56739af1b36e14d2ee8192a8 Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Mon, 19 May 2014 09:36:28 +0200 Subject: [PATCH 09/25] PHPDoc formatting fix --- src/Ratchet/App.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index d9baff0..229a448 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -54,8 +54,8 @@ class App { * @param string $address IP address to bind to. Default is localhost/proxy only. '0.0.0.0' for any machine * @param array $flashAllowedHosts associative array with hostnames as key and ports as value. These domains are the domains the flash websocket fallback may connect from * @param int $flashPort the port the flash cross-domain-policy file will be hosted on - * @param string $flashAddress the IP address the flash cross-domain-policy server will bind to - * @param LoopInterface $loop Specific React\EventLoop to bind the application to. null will create one for you. + * @param string $flashAddress the IP address the flash cross-domain-policy server will bind to + * @param LoopInterface $loop Specific React\EventLoop to bind the application to. null will create one for you. */ public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', $flashAllowedHosts = false, $flashPort = 8843, $flashAddress = '0.0.0.0', LoopInterface $loop = null) { From dc9945f2a3f17790c97e62bbee26e77f4782d73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 19 May 2014 15:15:09 +0200 Subject: [PATCH 10/25] Support bypassing Host check An empty $httpHost can be passed to circumvent checking Host header. --- src/Ratchet/App.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index da634af..cc4aea4 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -107,7 +107,9 @@ class App { $decorated = $controller; } - $httpHost = $httpHost ?: $this->httpHost; + if ($httpHost === null) { + $httpHost = $this->httpHost; + } $allowedOrigins = array_values($allowedOrigins); if (0 === count($allowedOrigins)) { From fb1ba88fcce876cb49bf80a1b1909317702262d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 19 May 2014 15:46:18 +0200 Subject: [PATCH 11/25] Consistent Exception handling for WAMP protocol errors --- src/Ratchet/Wamp/ServerProtocol.php | 4 ++-- src/Ratchet/Wamp/WampServer.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Ratchet/Wamp/ServerProtocol.php b/src/Ratchet/Wamp/ServerProtocol.php index 0a5805e..5b8645c 100644 --- a/src/Ratchet/Wamp/ServerProtocol.php +++ b/src/Ratchet/Wamp/ServerProtocol.php @@ -90,7 +90,7 @@ class ServerProtocol implements MessageComponentInterface, WsServerInterface { } if (!is_array($json) || $json !== array_values($json)) { - throw new \UnexpectedValueException("Invalid WAMP message format"); + throw new Exception("Invalid WAMP message format"); } switch ($json[0]) { @@ -134,7 +134,7 @@ class ServerProtocol implements MessageComponentInterface, WsServerInterface { break; default: - throw new Exception('Invalid message type'); + throw new Exception('Invalid WAMP message type'); } } diff --git a/src/Ratchet/Wamp/WampServer.php b/src/Ratchet/Wamp/WampServer.php index 7644fdc..b4cd88e 100644 --- a/src/Ratchet/Wamp/WampServer.php +++ b/src/Ratchet/Wamp/WampServer.php @@ -39,7 +39,7 @@ class WampServer implements MessageComponentInterface, WsServerInterface { public function onMessage(ConnectionInterface $conn, $msg) { try { $this->wampProtocol->onMessage($conn, $msg); - } catch (JsonException $je) { + } catch (Exception $je) { $conn->close(1007); } catch (\UnexpectedValueException $uve) { $conn->close(1007); From a456c50df437616648d45a73c711d78804ded21d Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Fri, 23 May 2014 16:20:27 +0200 Subject: [PATCH 12/25] Reverted the changes previously made in favor of a different approach as requested in https://github.com/cboden/Ratchet/pull/188 --- src/Ratchet/App.php | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index 229a448..5cafeae 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -1,5 +1,7 @@ routes = new RouteCollection; $this->_server = new IoServer(new HttpServer(new Router(new UrlMatcher($this->routes, new RequestContext))), $socket, $loop); - if ($flashAllowedHosts === false) { - $flashAllowedHosts = array( 80 => $httpHost ); - } - $policy = new FlashPolicy(); - - foreach ($flashAllowedHosts as $flashAllowedHost => $flashAllowedPort) { - $policy->addAllowedAccess($flashAllowedHost, $flashAllowedPort); - } - + $policy->addAllowedAccess($httpHost, 80); + $policy->addAllowedAccess($httpHost, $port); $flashSock = new Reactor($loop); - $this->flashServer = new IoServer($policy, $flashSock); - $flashSock->listen($flashPort, $flashAddress); + + if (80 == $port) { + $flashSock->listen(843, '0.0.0.0'); + } else { + $flashSock->listen(8843); + } + } + + /** + * Returns the FlashPolicy running in the FlashServer. Modifications of this object take effect immediately! + * + * @return FlashPolicy + */ + public function getFlashPolicy() { + return $this->flashServer->getApp(); } /** @@ -136,3 +140,4 @@ class App { $this->_server->run(); } } + From a1c27ac91b7a07326785acf4ad0bfeb03d0488ef Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Fri, 23 May 2014 16:21:13 +0200 Subject: [PATCH 13/25] Added the property socket to the IOServer class and exposed the app and socket properties through getters. --- src/Ratchet/Server/IoServer.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Ratchet/Server/IoServer.php b/src/Ratchet/Server/IoServer.php index b27ee93..587dcd5 100644 --- a/src/Ratchet/Server/IoServer.php +++ b/src/Ratchet/Server/IoServer.php @@ -1,5 +1,7 @@ loop = $loop; $this->app = $app; + $this->socket = $socket; $socket->on('connection', array($this, 'handleConnect')); @@ -50,6 +59,24 @@ class IoServer { $this->handlers[1] = array($this, 'handleEnd'); $this->handlers[2] = array($this, 'handleError'); } + + /** + * Returns the Ratchet App + * + * @return \Ratchet\MessageComponentInterface + */ + public function getApp() { + return $this->app; + } + + /** + * Returns the Socket + * + * @return \React\Socket\ServerInterface + */ + public function getSocket() { + return $this->socket; + } /** * @param \Ratchet\MessageComponentInterface $component The application that I/O will call when events are received From 5ad295e02ad35625e4ee3eea904f794ea7140de1 Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Fri, 23 May 2014 16:22:00 +0200 Subject: [PATCH 14/25] Added a method to clear the allowedAccess array. --- src/Ratchet/Server/FlashPolicy.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Ratchet/Server/FlashPolicy.php b/src/Ratchet/Server/FlashPolicy.php index 4997362..4a1b8bd 100644 --- a/src/Ratchet/Server/FlashPolicy.php +++ b/src/Ratchet/Server/FlashPolicy.php @@ -71,6 +71,18 @@ class FlashPolicy implements MessageComponentInterface { return $this; } + + /** + * Removes all domains from the allowed access list. + * + * @return \Ratchet\Server\FlashPolicy + */ + public function clearAllowedAccess() { + $this->_access = array(); + $this->_cacheValid = false; + + return $this; + } /** * site-control defines the meta-policy for the current domain. A meta-policy specifies acceptable From 478bdc10c52023dfddfb30c2512a047a731a072f Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Fri, 23 May 2014 16:31:08 +0200 Subject: [PATCH 15/25] Added a method to expose the flashsocket --- src/Ratchet/App.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index 03bf1bb..e59c074 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -91,13 +91,22 @@ class App { } /** - * Returns the FlashPolicy running in the FlashServer. Modifications of this object take effect immediately! + * Returns the FlashPolicy running in the flash server. Modifications of this object take effect immediately! * * @return FlashPolicy */ public function getFlashPolicy() { return $this->flashServer->getApp(); } + + /** + * Returns the FlashSocket of the flash server. + * + * @return \React\Socket\ServerInterface + */ + public function getFlashSocket() { + return $this->flashServer->getSocket(); + } /** * Add an endpiont/application to the server From e1dba722549186de5d887624e18f20894d5417cd Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Mon, 26 May 2014 22:38:42 -0400 Subject: [PATCH 16/25] Meta for 0.3.1 tag --- .travis.yml | 4 ---- CHANGELOG.md | 9 +++++++++ README.md | 4 ++-- src/Ratchet/ConnectionInterface.php | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 30f5601..1113aa6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,6 @@ php: - 5.5 - hhvm -matrix: - allow_failures: - - php: hhvm - before_script: - sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "session.serialize_handler = php" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;' - composer install --dev --prefer-source diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aae881..d3d4f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,15 @@ CHANGELOG --- +* 0.3.1 (2014-05-26) + + * Added query parameter support to Router, set in HTTP request (ws://server?hello=world) + * HHVM compatibility + * BF: React/0.4 support; CPU starvation bug fixes + * BF: Allow App::route to ignore Host header + * Added expected filters to WAMP Topic broadcast method + * Resource cleanup in WAMP TopicManager + * 0.3.0 (2013-10-14) * Added the `App` class to help making Ratchet so easy to use it's silly diff --git a/README.md b/README.md index a863173..e1ed87e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Build up your application through simple interfaces and re-use your application ##WebSocket Compliance * Supports the RFC6455, HyBi-10+, and Hixie76 protocol versions (at the same time) -* Tested on Chrome 13 - 31, Firefox 6 - 26, Safari 5.0.1 - 6.1, iOS 4.2 - 7 +* Tested on Chrome 13+, Firefox 6+, Safari 5+, iOS 4.2+, IE 8+ * Ratchet [passes](http://socketo.me/reports/ab/) the [Autobahn Testsuite](http://autobahn.ws/testsuite) (non-binary messages) ##Requirements @@ -19,7 +19,7 @@ To avoid proxy/firewall blockage it's recommended WebSockets are requested on po In order to do this, along with your sync web stack, you can either use a reverse proxy or two separate machines. You can find more details in the [server conf docs](http://socketo.me/docs/deploy#serverconfiguration). -PHP 5.3.9 (or higher) is required. If you have access, PHP 5.4 is *highly* recommended for its performance improvements. +PHP 5.3.9 (or higher) is required. If you have access, PHP 5.4 (or higher) is *highly* recommended for its performance improvements. ### Documentation diff --git a/src/Ratchet/ConnectionInterface.php b/src/Ratchet/ConnectionInterface.php index 8741ed5..cb28b5e 100644 --- a/src/Ratchet/ConnectionInterface.php +++ b/src/Ratchet/ConnectionInterface.php @@ -5,7 +5,7 @@ namespace Ratchet; * The version of Ratchet being used * @var string */ -const VERSION = 'Ratchet/0.3'; +const VERSION = 'Ratchet/0.3.1'; /** * A proxy object representing a connection to the application From c86fdadcdec7ad59724502ca4bd50d4cc4986980 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 3 Jun 2014 22:30:40 -0400 Subject: [PATCH 17/25] Revert "Fixed a memory leak when a connection is closed the topics should also be removed if they are empty" This reverts commit c089aea8ebad521795610feb36bc7a937794a88c. --- src/Ratchet/Wamp/TopicManager.php | 7 ++----- tests/unit/Wamp/TopicManagerTest.php | 7 ------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/Ratchet/Wamp/TopicManager.php b/src/Ratchet/Wamp/TopicManager.php index a69e315..bceee73 100644 --- a/src/Ratchet/Wamp/TopicManager.php +++ b/src/Ratchet/Wamp/TopicManager.php @@ -77,11 +77,8 @@ class TopicManager implements WsServerInterface, WampServerInterface { public function onClose(ConnectionInterface $conn) { $this->app->onClose($conn); - foreach ($this->topicLookup as $topic => $storage) { - $storage->remove($conn); - if (0 === $storage->count()) { - unset($this->topicLookup[$topic]); - } + foreach ($this->topicLookup as $topic) { + $topic->remove($conn); } } diff --git a/tests/unit/Wamp/TopicManagerTest.php b/tests/unit/Wamp/TopicManagerTest.php index 7439064..0c31d9a 100644 --- a/tests/unit/Wamp/TopicManagerTest.php +++ b/tests/unit/Wamp/TopicManagerTest.php @@ -166,19 +166,12 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase { $method = $class->getMethod('getTopic'); $method->setAccessible(true); - $attribute = $class->getProperty('topicLookup'); - $attribute->setAccessible(true); - $topic = $method->invokeArgs($this->mngr, array($name)); - $this->assertCount(1, $attribute->getValue($this->mngr)); - $this->mngr->onSubscribe($this->conn, $name); $this->mngr->onClose($this->conn); $this->assertFalse($topic->has($this->conn)); - - $this->assertCount(0, $attribute->getValue($this->mngr)); } public function testOnErrorBubbles() { From 77c6d53a4dad77d082cbd13a4d405403f7e54946 Mon Sep 17 00:00:00 2001 From: Gerrit Drost Date: Wed, 4 Jun 2014 16:59:30 +0200 Subject: [PATCH 18/25] Made changes as suggested in pull request. Getters have been removed from IoServer and desired properties have been made public. --- src/Ratchet/App.php | 4 ++-- src/Ratchet/Server/IoServer.php | 20 +------------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index e59c074..cc724fc 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -96,7 +96,7 @@ class App { * @return FlashPolicy */ public function getFlashPolicy() { - return $this->flashServer->getApp(); + return $this->flashServer->app; } /** @@ -105,7 +105,7 @@ class App { * @return \React\Socket\ServerInterface */ public function getFlashSocket() { - return $this->flashServer->getSocket(); + return $this->flashServer->socket; } /** diff --git a/src/Ratchet/Server/IoServer.php b/src/Ratchet/Server/IoServer.php index 587dcd5..160a1fc 100644 --- a/src/Ratchet/Server/IoServer.php +++ b/src/Ratchet/Server/IoServer.php @@ -33,7 +33,7 @@ class IoServer { * The socket server the Ratchet Application is run off of * @var \React\Socket\ServerInterface */ - protected $socket; + public $socket; /** * @param \Ratchet\MessageComponentInterface $app The Ratchet application stack to host @@ -59,24 +59,6 @@ class IoServer { $this->handlers[1] = array($this, 'handleEnd'); $this->handlers[2] = array($this, 'handleError'); } - - /** - * Returns the Ratchet App - * - * @return \Ratchet\MessageComponentInterface - */ - public function getApp() { - return $this->app; - } - - /** - * Returns the Socket - * - * @return \React\Socket\ServerInterface - */ - public function getSocket() { - return $this->socket; - } /** * @param \Ratchet\MessageComponentInterface $component The application that I/O will call when events are received From 87de418446e0c34fc923656ae140f2be5eddebdd Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Wed, 4 Jun 2014 20:59:10 -0400 Subject: [PATCH 19/25] Revert "Revert "Fixed a memory leak when a connection is closed the topics should also be removed if they are empty"" This reverts commit c86fdadcdec7ad59724502ca4bd50d4cc4986980. --- src/Ratchet/Wamp/TopicManager.php | 7 +++++-- tests/unit/Wamp/TopicManagerTest.php | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Ratchet/Wamp/TopicManager.php b/src/Ratchet/Wamp/TopicManager.php index bceee73..a69e315 100644 --- a/src/Ratchet/Wamp/TopicManager.php +++ b/src/Ratchet/Wamp/TopicManager.php @@ -77,8 +77,11 @@ class TopicManager implements WsServerInterface, WampServerInterface { public function onClose(ConnectionInterface $conn) { $this->app->onClose($conn); - foreach ($this->topicLookup as $topic) { - $topic->remove($conn); + foreach ($this->topicLookup as $topic => $storage) { + $storage->remove($conn); + if (0 === $storage->count()) { + unset($this->topicLookup[$topic]); + } } } diff --git a/tests/unit/Wamp/TopicManagerTest.php b/tests/unit/Wamp/TopicManagerTest.php index 0c31d9a..7439064 100644 --- a/tests/unit/Wamp/TopicManagerTest.php +++ b/tests/unit/Wamp/TopicManagerTest.php @@ -166,12 +166,19 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase { $method = $class->getMethod('getTopic'); $method->setAccessible(true); + $attribute = $class->getProperty('topicLookup'); + $attribute->setAccessible(true); + $topic = $method->invokeArgs($this->mngr, array($name)); + $this->assertCount(1, $attribute->getValue($this->mngr)); + $this->mngr->onSubscribe($this->conn, $name); $this->mngr->onClose($this->conn); $this->assertFalse($topic->has($this->conn)); + + $this->assertCount(0, $attribute->getValue($this->mngr)); } public function testOnErrorBubbles() { From a0d858a638f89e2314343dad57f0618dda1f73c9 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 5 Jun 2014 08:13:35 -0400 Subject: [PATCH 20/25] [WAMP] Added autoDelete to Topics --- src/Ratchet/Wamp/Topic.php | 7 +++++++ src/Ratchet/Wamp/TopicManager.php | 26 +++++++++++++++++--------- tests/unit/Wamp/TopicManagerTest.php | 1 + 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Ratchet/Wamp/Topic.php b/src/Ratchet/Wamp/Topic.php index f1bd68a..3fe73d1 100644 --- a/src/Ratchet/Wamp/Topic.php +++ b/src/Ratchet/Wamp/Topic.php @@ -6,6 +6,13 @@ use Ratchet\ConnectionInterface; * A topic/channel containing connections that have subscribed to it */ class Topic implements \IteratorAggregate, \Countable { + /** + * If true the TopicManager will destroy this object if it's ever empty of connections + * @deprecated in v0.4 + * @type bool + */ + public $autoDelete = false; + private $id; private $subscribers; diff --git a/src/Ratchet/Wamp/TopicManager.php b/src/Ratchet/Wamp/TopicManager.php index a69e315..318b986 100644 --- a/src/Ratchet/Wamp/TopicManager.php +++ b/src/Ratchet/Wamp/TopicManager.php @@ -54,13 +54,12 @@ class TopicManager implements WsServerInterface, WampServerInterface { public function onUnsubscribe(ConnectionInterface $conn, $topic) { $topicObj = $this->getTopic($topic); - if ($conn->WAMP->subscriptions->contains($topicObj)) { - $conn->WAMP->subscriptions->detach($topicObj); - } else { + if (!$conn->WAMP->subscriptions->contains($topicObj)) { return; } - $this->topicLookup[$topic]->remove($conn); + $this->cleanTopic($topicObj, $conn); + $this->app->onUnsubscribe($conn, $topicObj); } @@ -77,11 +76,8 @@ class TopicManager implements WsServerInterface, WampServerInterface { public function onClose(ConnectionInterface $conn) { $this->app->onClose($conn); - foreach ($this->topicLookup as $topic => $storage) { - $storage->remove($conn); - if (0 === $storage->count()) { - unset($this->topicLookup[$topic]); - } + foreach ($this->topicLookup as $topic) { + $this->cleanTopic($topic, $conn); } } @@ -114,4 +110,16 @@ class TopicManager implements WsServerInterface, WampServerInterface { return $this->topicLookup[$topic]; } + + protected function cleanTopic(Topic $topic, ConnectionInterface $conn) { + if ($conn->WAMP->subscriptions->contains($topic)) { + $conn->WAMP->subscriptions->detach($topic); + } + + $this->topicLookup[$topic->getId()]->remove($conn); + + if ($topic->autoDelete && 0 === $topic->count()) { + unset($this->topicLookup[$topic->getId()]); + } + } } diff --git a/tests/unit/Wamp/TopicManagerTest.php b/tests/unit/Wamp/TopicManagerTest.php index 7439064..79ff2ff 100644 --- a/tests/unit/Wamp/TopicManagerTest.php +++ b/tests/unit/Wamp/TopicManagerTest.php @@ -170,6 +170,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase { $attribute->setAccessible(true); $topic = $method->invokeArgs($this->mngr, array($name)); + $topic->autoDelete = true; $this->assertCount(1, $attribute->getValue($this->mngr)); From f21a1951c659455f91e4602b2235ff364b92f14a Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 7 Jun 2014 10:51:32 -0400 Subject: [PATCH 21/25] [WAMP] Tests for new Topic autoDelete handling --- tests/unit/Wamp/TopicManagerTest.php | 35 ++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/tests/unit/Wamp/TopicManagerTest.php b/tests/unit/Wamp/TopicManagerTest.php index 79ff2ff..8482877 100644 --- a/tests/unit/Wamp/TopicManagerTest.php +++ b/tests/unit/Wamp/TopicManagerTest.php @@ -159,9 +159,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase { $this->mngr->onClose($this->conn); } - public function testConnIsRemovedFromTopicOnClose() { - $name = 'State testing'; - + protected function topicProvider($name) { $class = new \ReflectionClass('Ratchet\Wamp\TopicManager'); $method = $class->getMethod('getTopic'); $method->setAccessible(true); @@ -170,7 +168,13 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase { $attribute->setAccessible(true); $topic = $method->invokeArgs($this->mngr, array($name)); - $topic->autoDelete = true; + + return array($topic, $attribute); + } + + public function testConnIsRemovedFromTopicOnClose() { + $name = 'State Testing'; + list($topic, $attribute) = $this->topicProvider($name); $this->assertCount(1, $attribute->getValue($this->mngr)); @@ -178,8 +182,29 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase { $this->mngr->onClose($this->conn); $this->assertFalse($topic->has($this->conn)); + } - $this->assertCount(0, $attribute->getValue($this->mngr)); + public static function topicConnExpectationProvider() { + return array( + array(true, 'onClose', 0) + , array(true, 'onUnsubscribe', 0) + , array(false, 'onClose', 1) + , array(false, 'onUnsubscribe', 1) + ); + } + + /** + * @dataProvider topicConnExpectationProvider + */ + public function testTopicRetentionFromLeavingConnections($autoDelete, $methodCall, $expectation) { + $topicName = 'checkTopic'; + list($topic, $attribute) = $this->topicProvider($topicName); + $topic->autoDelete = $autoDelete; + + $this->mngr->onSubscribe($this->conn, $topicName); + call_user_func_array(array($this->mngr, $methodCall), array($this->conn, $topicName)); + + $this->assertCount($expectation, $attribute->getValue($this->mngr)); } public function testOnErrorBubbles() { From 989235132e17bfe61ab27c7e8f98f6cb8bfd42f2 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 7 Jun 2014 11:06:57 -0400 Subject: [PATCH 22/25] [App] Reverted API API changes - back to v0.3.1 version --- src/Ratchet/App.php | 25 ++----------------------- src/Ratchet/Server/IoServer.php | 4 +--- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/Ratchet/App.php b/src/Ratchet/App.php index cc724fc..c6d9ceb 100644 --- a/src/Ratchet/App.php +++ b/src/Ratchet/App.php @@ -1,7 +1,5 @@ routes = new RouteCollection; $this->_server = new IoServer(new HttpServer(new Router(new UrlMatcher($this->routes, new RequestContext))), $socket, $loop); - $policy = new FlashPolicy(); + $policy = new FlashPolicy; $policy->addAllowedAccess($httpHost, 80); $policy->addAllowedAccess($httpHost, $port); $flashSock = new Reactor($loop); @@ -89,24 +87,6 @@ class App { $flashSock->listen(8843); } } - - /** - * Returns the FlashPolicy running in the flash server. Modifications of this object take effect immediately! - * - * @return FlashPolicy - */ - public function getFlashPolicy() { - return $this->flashServer->app; - } - - /** - * Returns the FlashSocket of the flash server. - * - * @return \React\Socket\ServerInterface - */ - public function getFlashSocket() { - return $this->flashServer->socket; - } /** * Add an endpiont/application to the server @@ -150,5 +130,4 @@ class App { public function run() { $this->_server->run(); } -} - +} \ No newline at end of file diff --git a/src/Ratchet/Server/IoServer.php b/src/Ratchet/Server/IoServer.php index 160a1fc..921c7b1 100644 --- a/src/Ratchet/Server/IoServer.php +++ b/src/Ratchet/Server/IoServer.php @@ -1,7 +1,5 @@ Date: Sat, 7 Jun 2014 11:35:54 -0400 Subject: [PATCH 23/25] [WAMP] Errors Cleaned up error handling and tests. refs #190 --- src/Ratchet/Wamp/ServerProtocol.php | 4 ++-- src/Ratchet/Wamp/WampServer.php | 4 ++-- tests/unit/Wamp/ServerProtocolTest.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Ratchet/Wamp/ServerProtocol.php b/src/Ratchet/Wamp/ServerProtocol.php index 5b8645c..92dbd85 100644 --- a/src/Ratchet/Wamp/ServerProtocol.php +++ b/src/Ratchet/Wamp/ServerProtocol.php @@ -79,8 +79,8 @@ class ServerProtocol implements MessageComponentInterface, WsServerInterface { /** * {@inheritdoc} - * @throws \Exception - * @throws JsonException + * @throws \Ratchet\Wamp\Exception + * @throws \Ratchet\Wamp\JsonException */ public function onMessage(ConnectionInterface $from, $msg) { $from = $this->connections[$from]; diff --git a/src/Ratchet/Wamp/WampServer.php b/src/Ratchet/Wamp/WampServer.php index b4cd88e..d839fb8 100644 --- a/src/Ratchet/Wamp/WampServer.php +++ b/src/Ratchet/Wamp/WampServer.php @@ -39,9 +39,9 @@ class WampServer implements MessageComponentInterface, WsServerInterface { public function onMessage(ConnectionInterface $conn, $msg) { try { $this->wampProtocol->onMessage($conn, $msg); - } catch (Exception $je) { + } catch (Exception $we) { $conn->close(1007); - } catch (\UnexpectedValueException $uve) { + } catch (JsonException $je) { $conn->close(1007); } } diff --git a/tests/unit/Wamp/ServerProtocolTest.php b/tests/unit/Wamp/ServerProtocolTest.php index 3cc44f0..1b423d2 100644 --- a/tests/unit/Wamp/ServerProtocolTest.php +++ b/tests/unit/Wamp/ServerProtocolTest.php @@ -258,7 +258,7 @@ class ServerProtocolTest extends \PHPUnit_Framework_TestCase { * @dataProvider badFormatProvider */ public function testValidJsonButInvalidProtocol($message) { - $this->setExpectedException('\UnexpectedValueException'); + $this->setExpectedException('\Ratchet\Wamp\Exception'); $conn = $this->newConn(); $this->_comp->onOpen($conn); From 1d5af1e34d5c822e589e0b0e27a3c1a48daa06fb Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 8 Jun 2014 10:55:57 -0400 Subject: [PATCH 24/25] [WebSocket] Halt communication after closing frame Also send closing frame in Hixie --- .../WebSocket/Version/Hixie76/Connection.php | 11 +++++++++-- .../WebSocket/Version/RFC6455/Connection.php | 19 +++++++++++++++---- src/Ratchet/WebSocket/WsServer.php | 5 +++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/Ratchet/WebSocket/Version/Hixie76/Connection.php b/src/Ratchet/WebSocket/Version/Hixie76/Connection.php index 2a5f845..e3d0834 100644 --- a/src/Ratchet/WebSocket/Version/Hixie76/Connection.php +++ b/src/Ratchet/WebSocket/Version/Hixie76/Connection.php @@ -8,12 +8,19 @@ use Ratchet\AbstractConnectionDecorator; */ class Connection extends AbstractConnectionDecorator { public function send($msg) { - $this->getConnection()->send(chr(0) . $msg . chr(255)); + if (!$this->WebSocket->closing) { + $this->getConnection()->send(chr(0) . $msg . chr(255)); + } return $this; } public function close() { - $this->getConnection()->close(); + if (!$this->WebSocket->closing) { + $this->getConnection()->send(chr(255)); + $this->getConnection()->close(); + + $this->WebSocket->closing = true; + } } } diff --git a/src/Ratchet/WebSocket/Version/RFC6455/Connection.php b/src/Ratchet/WebSocket/Version/RFC6455/Connection.php index 5bfa4a9..a17e382 100644 --- a/src/Ratchet/WebSocket/Version/RFC6455/Connection.php +++ b/src/Ratchet/WebSocket/Version/RFC6455/Connection.php @@ -8,12 +8,17 @@ use Ratchet\WebSocket\Version\DataInterface; * @property \StdClass $WebSocket */ class Connection extends AbstractConnectionDecorator { + /** + * {@inheritdoc} + */ public function send($msg) { - if (!($msg instanceof DataInterface)) { - $msg = new Frame($msg); - } + if (!$this->WebSocket->closing) { + if (!($msg instanceof DataInterface)) { + $msg = new Frame($msg); + } - $this->getConnection()->send($msg->getContents()); + $this->getConnection()->send($msg->getContents()); + } return $this; } @@ -22,6 +27,10 @@ class Connection extends AbstractConnectionDecorator { * {@inheritdoc} */ public function close($code = 1000) { + if ($this->WebSocket->closing) { + return; + } + if ($code instanceof DataInterface) { $this->send($code); } else { @@ -29,5 +38,7 @@ class Connection extends AbstractConnectionDecorator { } $this->getConnection()->close(); + + $this->WebSocket->closing = true; } } diff --git a/src/Ratchet/WebSocket/WsServer.php b/src/Ratchet/WebSocket/WsServer.php index 8ad6e4e..b4be1f0 100644 --- a/src/Ratchet/WebSocket/WsServer.php +++ b/src/Ratchet/WebSocket/WsServer.php @@ -79,6 +79,7 @@ class WsServer implements HttpServerInterface { $conn->WebSocket = new \StdClass; $conn->WebSocket->request = $request; $conn->WebSocket->established = false; + $conn->WebSocket->closing = false; $this->attemptUpgrade($conn); } @@ -87,6 +88,10 @@ class WsServer implements HttpServerInterface { * {@inheritdoc} */ public function onMessage(ConnectionInterface $from, $msg) { + if ($from->WebSocket->closing) { + return; + } + if (true === $from->WebSocket->established) { return $from->WebSocket->version->onMessage($this->connections[$from], $msg); } From d36a8699df04354147a4f47845035b1ea8239189 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 8 Jun 2014 11:19:45 -0400 Subject: [PATCH 25/25] Updates for tag --- CHANGELOG.md | 8 ++++++++ src/Ratchet/ConnectionInterface.php | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3d4f20..e1585c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ CHANGELOG --- +* 0.3.2 (2014-06-08) + + * BF: No messages after closing handshake (fixed rare race condition causing 100% CPU) + * BF: Fixed accidental BC break from v0.3.1 + * Added autoDelete parameter to Topic to destroy when empty of connections + * Exposed React Socket on IoServer (allowing FlashPolicy shutdown in App) + * Normalized Exceptions in WAMP + * 0.3.1 (2014-05-26) * Added query parameter support to Router, set in HTTP request (ws://server?hello=world) diff --git a/src/Ratchet/ConnectionInterface.php b/src/Ratchet/ConnectionInterface.php index cb28b5e..594e339 100644 --- a/src/Ratchet/ConnectionInterface.php +++ b/src/Ratchet/ConnectionInterface.php @@ -5,7 +5,7 @@ namespace Ratchet; * The version of Ratchet being used * @var string */ -const VERSION = 'Ratchet/0.3.1'; +const VERSION = 'Ratchet/0.3.2'; /** * A proxy object representing a connection to the application