From c56ba3b2f1132426ad3e85a16c28b811646e83c2 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 18 Dec 2011 15:32:11 -0500 Subject: [PATCH 01/22] Init WAMP Starting work on the WebSocket Application Messaging Protocol (WAMP). JSON messages, supports pub/sub and RPC via HTTP endpoints for website integration --- lib/Ratchet/Application/WAMP/App.php | 89 +++++++++++++++++++ lib/Ratchet/Application/WAMP/Exception.php | 5 ++ .../Application/WAMP/JSONException.php | 31 +++++++ .../Application/WAMP/ServerInterface.php | 13 +++ lib/Ratchet/Application/WebSocket/App.php | 10 +++ .../WebSocket/WebSocketAppInterface.php | 2 +- 6 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 lib/Ratchet/Application/WAMP/App.php create mode 100644 lib/Ratchet/Application/WAMP/Exception.php create mode 100644 lib/Ratchet/Application/WAMP/JSONException.php create mode 100644 lib/Ratchet/Application/WAMP/ServerInterface.php diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php new file mode 100644 index 0000000..cfd320c --- /dev/null +++ b/lib/Ratchet/Application/WAMP/App.php @@ -0,0 +1,89 @@ +prefixes[$uri] = $curie; + } + + public function sendEvent($uri, $event) { + } + + public function onCall(Connection $conn, $id, $uri) { + } + + public function onOpen(Connection $conn) { + $conn->WAMP = new \StdClass; + $conn->WAMP->prefixes = array(); + $conn->WAMP->subscriptions = array(); + } + + /** + * @{inherit} + * @throws Exception + * @throws JSONException + */ + public function onMessage(Connection $from, $msg) { + if (null === ($json = @json_decode($msg, true))) { + throw new JSONException; + } + + if (!in_array($json[0], static::$_incoming)) { + throw new Exception('Invalid message type'); + } + + if ($json[0] == 1) { + $this->addPrefix($conn, $json[2], $json[1]); + } + } + + public function __construct(ApplicationInterface $app = null) { + if (null !== $app) { + throw new \InvalidArgumentException('WAMP is the end of the Socket stack, apps build on this must conform to the WAMP protocol'); + } + } + + public function onClose(Connection $conn) { + // remove all prefixes associated with connection? or will those just be destroyed w/ Connection + } + + public function onError(Connection $conn, \Exception $e) { + } +} \ No newline at end of file diff --git a/lib/Ratchet/Application/WAMP/Exception.php b/lib/Ratchet/Application/WAMP/Exception.php new file mode 100644 index 0000000..e590104 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Exception.php @@ -0,0 +1,5 @@ +WebSocket->handshake) { @@ -92,6 +93,15 @@ class App implements ApplicationInterface, ConfiguratorInterface { $from->WebSocket->handshake = true; if (is_array($response)) { + if ($this->_app instanceof WebSocketAppInterface) { + // Note: this logic is wrong - we're supposed to check what the client sent + // as its sub protocol and if we support any of the requested we send that back. + // This is just sending what ever one wwe support + // This will be changed when I rewrite how headers are handled + // Also...what happens if something like a logger is put between this and the sub-protocol app? + $response['Sec-WebSocket-Protocol'] = $this->_app->getSubProtocol(); + } + $header = ''; foreach ($response as $key => $val) { if (!empty($key)) { diff --git a/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php b/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php index f78ca6c..642a625 100644 --- a/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php +++ b/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php @@ -12,7 +12,7 @@ interface WebSocketAppInterface extends ApplicationInterface { * Currently instead of this, I'm setting header in the Connection object passed around...not sure which I like more * @param string */ - function setHeaders($headers); + //function setHeaders($headers); /** * @return string From d37237c274e08f3686a324320a9c1445e6d55191 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 3 Jan 2012 12:22:02 -0700 Subject: [PATCH 02/22] AppInterface Method Removal Removed the construct AppInterface requirement in the construct to let applications branch out easier. Each application can now specify its own dependancies rather than trying to rabbit hole apps. --- lib/Ratchet/Application/ApplicationInterface.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/Ratchet/Application/ApplicationInterface.php b/lib/Ratchet/Application/ApplicationInterface.php index 4c0c919..6d964cb 100644 --- a/lib/Ratchet/Application/ApplicationInterface.php +++ b/lib/Ratchet/Application/ApplicationInterface.php @@ -7,12 +7,6 @@ use Ratchet\Resource\Connection; * It impelemtns the decorator and command pattern to build an application stack */ interface ApplicationInterface { - /** - * Decorator pattern - * @param Ratchet\ApplicationInterface Application to wrap in protocol - */ - public function __construct(ApplicationInterface $app = null); - /** * When a new connection is opened it will be passed to this method * @param Ratchet\Resource\Connection The socket/connection that just connected to your application From ed3cfc16da8d1712f53dd44a4fdc66ffe59bb342 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Wed, 4 Jan 2012 11:22:42 -0700 Subject: [PATCH 03/22] Loosened Dependencies Removed construct dependency from ApplicationInterface - changing full decorator to changeable stack. --- lib/Ratchet/Application/Server/App.php | 6 +----- lib/Ratchet/Application/WebSocket/App.php | 6 +----- lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php | 2 +- tests/Ratchet/Tests/Application/Server/AppTest.php | 5 ----- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/lib/Ratchet/Application/Server/App.php b/lib/Ratchet/Application/Server/App.php index 5964f39..8eb8fb0 100644 --- a/lib/Ratchet/Application/Server/App.php +++ b/lib/Ratchet/Application/Server/App.php @@ -41,11 +41,7 @@ class App implements ApplicationInterface { */ protected $_run = true; - public function __construct(ApplicationInterface $application = null) { - if (null === $application) { - throw new \UnexpectedValueException("Server requires an application to run off of"); - } - + public function __construct(ApplicationInterface $application) { $this->_app = $application; } diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php index 362039c..c0454e4 100644 --- a/lib/Ratchet/Application/WebSocket/App.php +++ b/lib/Ratchet/Application/WebSocket/App.php @@ -41,11 +41,7 @@ class App implements ApplicationInterface, ConfiguratorInterface { protected $_mask_payload = false; - public function __construct(ApplicationInterface $app = null) { - if (null === $app) { - throw new \UnexpectedValueException("WebSocket requires an application to run"); - } - + public function __construct(ApplicationInterface $app) { $this->_app = $app; $this->_factory = new Factory; } diff --git a/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php b/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php index f78ca6c..642a625 100644 --- a/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php +++ b/lib/Ratchet/Application/WebSocket/WebSocketAppInterface.php @@ -12,7 +12,7 @@ interface WebSocketAppInterface extends ApplicationInterface { * Currently instead of this, I'm setting header in the Connection object passed around...not sure which I like more * @param string */ - function setHeaders($headers); + //function setHeaders($headers); /** * @return string diff --git a/tests/Ratchet/Tests/Application/Server/AppTest.php b/tests/Ratchet/Tests/Application/Server/AppTest.php index a9e96a6..4e3aed6 100644 --- a/tests/Ratchet/Tests/Application/Server/AppTest.php +++ b/tests/Ratchet/Tests/Application/Server/AppTest.php @@ -36,11 +36,6 @@ class AppTest extends \PHPUnit_Framework_TestCase { return array_pop($connections); } - public function testDoNotAllowStacklessServer() { - $this->setExpectedException('UnexpectedValueException'); - new ServerApp; - } - public function testOnOpenPassesClonedSocket() { $this->_server->run($this->_catalyst); $master = $this->getMasterConnection(); From 08fa8a948ffd75b02fd514c42a80ec910f092121 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 6 Jan 2012 16:18:12 -0500 Subject: [PATCH 04/22] Guzzle Implementing Guzzle to parse incoming handshake request Functional on RFC version --- lib/Ratchet/Application/WebSocket/App.php | 30 ++++++---- .../Application/WebSocket/Util/HTTP.php | 56 ------------------- .../Application/WebSocket/Version/Hixie76.php | 4 +- .../Application/WebSocket/Version/HyBi10.php | 6 +- .../Application/WebSocket/Version/RFC6455.php | 19 ++++--- .../Version/RFC6455/HandshakeVerifier.php | 19 ++++--- .../WebSocket/Version/VersionInterface.php | 3 +- tests/bootstrap.php | 4 +- 8 files changed, 51 insertions(+), 90 deletions(-) delete mode 100644 lib/Ratchet/Application/WebSocket/Util/HTTP.php diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php index 362039c..75e7207 100644 --- a/lib/Ratchet/Application/WebSocket/App.php +++ b/lib/Ratchet/Application/WebSocket/App.php @@ -6,7 +6,8 @@ use Ratchet\Resource\Connection; use Ratchet\Resource\Command\Factory; use Ratchet\Resource\Command\CommandInterface; use Ratchet\Resource\Command\Action\SendMessage; -use Ratchet\Application\WebSocket\Util\HTTP; +use Guzzle\Http\Message\RequestInterface; +use Guzzle\Http\Message\RequestFactory; /** * The adapter to handle WebSocket requests/responses @@ -80,12 +81,14 @@ class App implements ApplicationInterface, ConfiguratorInterface { public function onMessage(Connection $from, $msg) { if (true !== $from->WebSocket->handshake) { if (!isset($from->WebSocket->version)) { - try { - $from->WebSocket->headers .= $msg; - $from->WebSocket->version = $this->getVersion($from->WebSocket->headers); - } catch (\UnderflowException $e) { + $from->WebSocket->headers .= $msg; + if (!$this->isMessageComplete($from->WebSocket->headers)) { return; } + + $headers = RequestFactory::fromMessage($from->WebSocket->headers); + $from->WebSocket->version = $this->getVersion($headers); + $from->WebSocket->headers = $headers; } $response = $from->WebSocket->version->handshake($from->WebSocket->headers); @@ -212,12 +215,8 @@ class App implements ApplicationInterface, ConfiguratorInterface { * @throws InvalidArgumentException If we can't understand protocol version request * @todo Verify the first line of the HTTP header as per page 16 of RFC 6455 */ - protected function getVersion($message) { - if (false === strstr($message, "\r\n\r\n")) { // This CAN fail with Hixie, depending on the TCP buffer in between - throw new \UnderflowException; - } - - $headers = HTTP::getHeaders($message); + protected function getVersion(RequestInterface $request) { + $headers = $request->getHeaders(); foreach ($this->_versions as $name => $instance) { if (null !== $instance) { @@ -236,6 +235,15 @@ class App implements ApplicationInterface, ConfiguratorInterface { throw new \InvalidArgumentException('Could not identify WebSocket protocol'); } + /** + * @param string + * @return bool + * @todo Method is flawed, this CAN result in an error with the Hixie protocol + */ + protected function isMessageComplete($message) { + return (boolean)strstr($message, "\r\n\r\n"); + } + /** * Disable a version of the WebSocket protocol *cough*Hixie76*cough* * @param string The name of the version to disable diff --git a/lib/Ratchet/Application/WebSocket/Util/HTTP.php b/lib/Ratchet/Application/WebSocket/Util/HTTP.php deleted file mode 100644 index c8f711f..0000000 --- a/lib/Ratchet/Application/WebSocket/Util/HTTP.php +++ /dev/null @@ -1,56 +0,0 @@ - null - , 'Upgrade' => null - , 'Connection' => null - , 'Sec-Websocket-Key' => null - , 'Origin' => null - , 'Sec-Websocket-Protocol' => null - , 'Sec-Websocket-Version' => null - , 'Sec-Websocket-Origin' => null - ); - } - - /** - * @param string - * @return array - * This is a fallback method for http_parse_headers as not all php installs have the HTTP module present - * @internal - */ - protected static function http_parse_headers($http_message) { - $retVal = array(); - $fields = explode("br", preg_replace("%(<|/\>|>)%", "", nl2br($http_message))); - - foreach ($fields as $field) { - if (preg_match('%^(GET|POST|PUT|DELETE|PATCH)(\s)(.*)%', $field, $matchReq)) { - $retVal["Request Method"] = $matchReq[1]; - $retVal["Request Url"] = $matchReq[3]; - } elseif (preg_match('/([^:]+): (.+)/m', $field, $match) ) { - $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($match[1]))); - if (isset($retVal[$match[1]])) { - $retVal[$match[1]] = array($retVal[$match[1]], $match[2]); - } else { - $retVal[$match[1]] = trim($match[2]); - } - } - } - - return $retVal; - } -} \ No newline at end of file diff --git a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php index 0777701..4540714 100644 --- a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php +++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php @@ -14,8 +14,8 @@ namespace Ratchet\Application\WebSocket\Version; * @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 */ class Hixie76 implements VersionInterface { - public static function isProtocol(array $headers) { - return isset($headers['Sec-Websocket-Key2']); + public static function isProtocol($headers) { + return isset($headers['Sec-WebSocket-Key2']); } /** diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php index 39f20ea..ee24fe2 100644 --- a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php +++ b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php @@ -5,9 +5,9 @@ namespace Ratchet\Application\WebSocket\Version; * @todo Note: Even though this is the "legacy" HyBi version, it's using the RFC Message and Frame classes - change if needed */ class HyBi10 extends RFC6455 { - public static function isProtocol(array $headers) { - if (isset($headers['Sec-Websocket-Version'])) { - if ((int)$headers['Sec-Websocket-Version'] >= 6 && (int)$headers['Sec-Websocket-Version'] < 13) { + public static function isProtocol($headers) { + if (isset($headers['Sec-WebSocket-Version'])) { + if ((int)$headers['Sec-WebSocket-Version'] >= 6 && (int)$headers['Sec-WebSocket-Version'] < 13) { return true; } } diff --git a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php index d1c7d83..fbb003f 100644 --- a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php +++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php @@ -1,7 +1,7 @@ _verifier = new HandshakeVerifier; } - public static function isProtocol(array $headers) { - if (isset($headers['Sec-Websocket-Version'])) { - if ((int)$headers['Sec-Websocket-Version'] == 13) { + /** + * @todo Change the request to be a Guzzle RequestInterface + */ + public static function isProtocol($headers) { + if (isset($headers['Sec-WebSocket-Version'])) { + if ((int)$headers['Sec-WebSocket-Version'] == 13) { return true; } } @@ -34,10 +37,10 @@ class RFC6455 implements VersionInterface { * @todo Decide what to do on failure...currently throwing an exception and I think socket connection is closed. Should be sending 40x error - but from where? */ public function handshake($message) { - $headers = HTTP::getHeaders($message); - $key = $this->sign($headers['Sec-Websocket-Key']); + $headers = $message->getHeaders(); + $key = $this->sign($headers['Sec-WebSocket-Key']); - if (true !== $this->_verifier->verifyAll($headers)) { + if (true !== $this->_verifier->verifyAll($message)) { throw new \InvalidArgumentException('Invalid HTTP header'); } @@ -45,7 +48,7 @@ class RFC6455 implements VersionInterface { '' => 'HTTP/1.1 101 Switching Protocols' , 'Upgrade' => 'websocket' , 'Connection' => 'Upgrade' - , 'Sec-WebSocket-Accept' => $this->sign($headers['Sec-Websocket-Key']) + , 'Sec-WebSocket-Accept' => $this->sign($headers['Sec-WebSocket-Key']) // , 'Sec-WebSocket-Protocol' => '' ); } diff --git a/lib/Ratchet/Application/WebSocket/Version/RFC6455/HandshakeVerifier.php b/lib/Ratchet/Application/WebSocket/Version/RFC6455/HandshakeVerifier.php index 224e870..331f62f 100644 --- a/lib/Ratchet/Application/WebSocket/Version/RFC6455/HandshakeVerifier.php +++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455/HandshakeVerifier.php @@ -1,5 +1,6 @@ getHeaders(); + $passes = 0; - $passes += (int)$this->verifyMethod($headers['Request Method']); - //$passes += (int)$this->verifyHTTPVersion($headers['???']); // This isn't in the array! - $passes += (int)$this->verifyRequestURI($headers['Request Url']); + $passes += (int)$this->verifyMethod($request->getMethod()); + $passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion()); + $passes += (int)$this->verifyRequestURI($request->getPath()); $passes += (int)$this->verifyHost($headers['Host']); $passes += (int)$this->verifyUpgradeRequest($headers['Upgrade']); $passes += (int)$this->verifyConnection($headers['Connection']); - $passes += (int)$this->verifyKey($headers['Sec-Websocket-Key']); - //$passes += (int)$this->verifyVersion($headers['Sec-Websocket-Version']); // Temporarily breaking functionality + $passes += (int)$this->verifyKey($headers['Sec-WebSocket-Key']); + //$passes += (int)$this->verifyVersion($headers['Sec-WebSocket-Version']); // Temporarily breaking functionality - return (6 === $passes); + return (7 === $passes); } /** diff --git a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php index 53ce979..ebc9d8f 100644 --- a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php +++ b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php @@ -14,7 +14,7 @@ interface VersionInterface { * @return bool * @throws UnderflowException If the protocol thinks the headers are still fragmented */ - static function isProtocol(array $headers); + static function isProtocol($headers); /** * Perform the handshake and return the response headers @@ -22,6 +22,7 @@ interface VersionInterface { * @return array|string * @throws InvalidArgumentException If the HTTP handshake is mal-formed * @throws UnderflowException If the message hasn't finished buffering (not yet implemented, theoretically will only happen with Hixie version) + * @todo Change param to accept a Guzzle RequestInterface object */ function handshake($message); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 2f02d40..cb1e591 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,4 +5,6 @@ $app->register(); $app = new SplClassLoader('Ratchet', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'lib'); - $app->register(); \ No newline at end of file + $app->register(); + + $app = new SplClassLoader('Guzzle', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'guzzle' . DIRECTORY_SEPARATOR . 'src'); \ No newline at end of file From e20a52dacc99248ba407841bf0f1fec5c11e5652 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 6 Jan 2012 16:43:02 -0500 Subject: [PATCH 05/22] Guzzle Typecasting Updated all WebSocket protocol version to accept a Guzzle Request object --- lib/Ratchet/Application/WebSocket/App.php | 6 ++---- .../Application/WebSocket/Version/Hixie76.php | 9 ++++++--- .../Application/WebSocket/Version/HyBi10.php | 12 ++++------- .../Application/WebSocket/Version/RFC6455.php | 20 ++++++------------- .../WebSocket/Version/VersionInterface.php | 9 +++++---- 5 files changed, 23 insertions(+), 33 deletions(-) diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php index 75e7207..9feb7f8 100644 --- a/lib/Ratchet/Application/WebSocket/App.php +++ b/lib/Ratchet/Application/WebSocket/App.php @@ -216,16 +216,14 @@ class App implements ApplicationInterface, ConfiguratorInterface { * @todo Verify the first line of the HTTP header as per page 16 of RFC 6455 */ protected function getVersion(RequestInterface $request) { - $headers = $request->getHeaders(); - foreach ($this->_versions as $name => $instance) { if (null !== $instance) { - if ($instance::isProtocol($headers)) { + if ($instance::isProtocol($request)) { return $instance; } } else { $ns = __NAMESPACE__ . "\\Version\\{$name}"; - if ($ns::isProtocol($headers)) { + if ($ns::isProtocol($request)) { $this->_versions[$name] = new $ns; return $this->_versions[$name]; } diff --git a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php index 4540714..5f98e3c 100644 --- a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php +++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php @@ -1,5 +1,6 @@ getHeader('Sec-WebSocket-Key2')); } /** * @param string * @return string */ - public function handshake($message) { + public function handshake(RequestInterface $request) { + $message = $request->getRawHeaders() . $request->getResponse()->getBody(true); + $buffer = $message; $resource = $host = $origin = $key1 = $key2 = $protocol = $code = $handshake = null; diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php index ee24fe2..920b966 100644 --- a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php +++ b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php @@ -1,18 +1,14 @@ = 6 && (int)$headers['Sec-WebSocket-Version'] < 13) { - return true; - } - } - - return false; + public static function isProtocol(RequestInterface $request) { + $version = (int)$request->getHeader('Sec-WebSocket-Version', -1); + return ($version >= 6 && $version < 13); } /** diff --git a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php index fbb003f..ad41e66 100644 --- a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php +++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php @@ -21,14 +21,9 @@ class RFC6455 implements VersionInterface { /** * @todo Change the request to be a Guzzle RequestInterface */ - public static function isProtocol($headers) { - if (isset($headers['Sec-WebSocket-Version'])) { - if ((int)$headers['Sec-WebSocket-Version'] == 13) { - return true; - } - } - - return false; + public static function isProtocol(RequestInterface $request) { + $version = (int)$request->getHeader('Sec-WebSocket-Version', -1); + return (13 === $version); } /** @@ -36,11 +31,8 @@ class RFC6455 implements VersionInterface { * I kept this as an array and combined in App for future considerations...easier to add a subprotol as a key value than edit a string * @todo Decide what to do on failure...currently throwing an exception and I think socket connection is closed. Should be sending 40x error - but from where? */ - public function handshake($message) { - $headers = $message->getHeaders(); - $key = $this->sign($headers['Sec-WebSocket-Key']); - - if (true !== $this->_verifier->verifyAll($message)) { + public function handshake(RequestInterface $request) { + if (true !== $this->_verifier->verifyAll($request)) { throw new \InvalidArgumentException('Invalid HTTP header'); } @@ -48,7 +40,7 @@ class RFC6455 implements VersionInterface { '' => 'HTTP/1.1 101 Switching Protocols' , 'Upgrade' => 'websocket' , 'Connection' => 'Upgrade' - , 'Sec-WebSocket-Accept' => $this->sign($headers['Sec-WebSocket-Key']) + , 'Sec-WebSocket-Accept' => $this->sign($request->getHeader('Sec-WebSocket-Key')) // , 'Sec-WebSocket-Protocol' => '' ); } diff --git a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php index ebc9d8f..8a13b70 100644 --- a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php +++ b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php @@ -1,5 +1,6 @@ Date: Fri, 6 Jan 2012 21:54:32 -0500 Subject: [PATCH 06/22] Passing Tests Finally able to do incomplete tests. Ratchet passes (finally). --- .../WebSocket/Version/RFC6455/FrameTest.php | 42 ++++++++++++++++--- .../WebSocket/Version/RFC6455Test.php | 24 ++++------- tests/bootstrap.php | 3 +- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455/FrameTest.php b/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455/FrameTest.php index 90ab37d..c870d65 100644 --- a/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455/FrameTest.php +++ b/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455/FrameTest.php @@ -20,6 +20,17 @@ class FrameTest extends \PHPUnit_Framework_TestCase { } protected static function convert($in) { + if (strlen($in) > 8) { + $out = ''; + + while (strlen($in) > 8) { + $out .= static::convert(substr($in, 0, 8)); + $in = substr($in, 8); + } + + return $out; + } + return pack('C', bindec($in)); } @@ -37,6 +48,31 @@ class FrameTest extends \PHPUnit_Framework_TestCase { ); } + public static function underflowProvider() { + return array( + array('isFinal', '') + , array('getOpcode', '') + , array('isMasked', '10000001') + , array('getPayloadLength', '10000001') + , array('getPayloadLength', '1000000111111110') + , array('getMaskingKey', '1000000110000111') + , array('getPayload', '100000011000000100011100101010101001100111110100') + ); + } + + /** + * @dataProvider underflowProvider + */ + public function testUnderflowExceptionFromAllTheMethodsMimickingBuffering($method, $bin) { + $this->setExpectedException('\UnderflowException'); + + if (!empty($bin)) { + $this->_frame->addBuffer(static::convert($bin)); + } + + call_user_func(array($this->_frame, $method)); + } + /** * A data provider for testing the first byte of a WebSocket frame * @param bool Given, is the byte indicate this is the final frame @@ -53,12 +89,6 @@ class FrameTest extends \PHPUnit_Framework_TestCase { ); } - public function testUnderflowExceptionFromAllTheMethodsMimickingBuffering() { - return $this->markTestIncomplete(); - - $this->expectException('\UnderflowException'); - } - /** * @dataProvider firstByteProvider */ diff --git a/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455Test.php b/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455Test.php index 3be4b74..f32f59f 100644 --- a/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455Test.php +++ b/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455Test.php @@ -2,6 +2,7 @@ namespace Ratchet\Tests\Application\WebSocket\Version; use Ratchet\Application\WebSocket\Version\RFC6455; use Ratchet\Application\WebSocket\Version\RFC6455\Frame; +use Guzzle\Http\Message\RequestFactory; /** * @covers Ratchet\Application\WebSocket\Version\RFC6455 @@ -103,32 +104,25 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase { public static function headerHandshakeProvider() { return array( array(false, "GET /test HTTP/1.0\r\n" . static::getAndSpliceHeader()) + , array(true, static::$good_rest . "\r\n" . static::getAndSpliceHeader()) + , array(false, "POST / HTTP:/1.1\r\n" . static::getAndSpliceHeader()) + , array(false, static::$good_rest . "\r\n" . static::getAndSpliceHeader('Upgrade', 'useless')) + , array(false, "GET /ಠ_ಠ HTTP/1.1\r\n" . static::getAndSpliceHeader()) + , array(true, static::$good_rest . "\r\n" . static::getAndSpliceHeader('Connection', 'Herp, Upgrade, Derp')) ); } -/* RFC example of a good header - GET /chat HTTP/1.1 - Host: server.example.com - Upgrade: websocket - Connection: Upgrade - Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - Origin: http://example.com - Sec-WebSocket-Protocol: chat, superchat - Sec-WebSocket-Version: 13 -*/ - /** * @dataProvider headerHandshakeProvider - * @todo Can't finish this test until I rewrite headers */ public function testVariousHeadersToCheckHandshakeTolerance($pass, $header) { - return $this->markTestIncomplete(); + $request = RequestFactory::fromMessage($header); if ($pass) { - $this->assertTrue(is_array($this->_version->handshake($header))); + $this->assertTrue(is_array($this->_version->handshake($request))); } else { $this->setExpectedException('InvalidArgumentException'); - $this->_version->handshake($header); + $this->_version->handshake($request); } } } \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php index cb1e591..d8416df 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -7,4 +7,5 @@ $app = new SplClassLoader('Ratchet', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'lib'); $app->register(); - $app = new SplClassLoader('Guzzle', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'guzzle' . DIRECTORY_SEPARATOR . 'src'); \ No newline at end of file + $app = new SplClassLoader('Guzzle', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'guzzle' . DIRECTORY_SEPARATOR . 'src'); + $app->register(); \ No newline at end of file From a1c6ee163f2d7bc7f7608a682fd32976d5d16983 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 6 Jan 2012 22:34:01 -0500 Subject: [PATCH 07/22] Guzzle Submodule Added Guzzle as a submodule --- .gitmodules | 3 +++ vendor/guzzle | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 vendor/guzzle diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..40105df --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/guzzle"] + path = vendor/guzzle + url = git://github.com/guzzle/guzzle.git diff --git a/vendor/guzzle b/vendor/guzzle new file mode 160000 index 0000000..13ea2e7 --- /dev/null +++ b/vendor/guzzle @@ -0,0 +1 @@ +Subproject commit 13ea2e723eaba72d99eefb24ec36f95ff7ef0068 From 83f49f1f55be94a82785b60610a427ff36c55a28 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 7 Jan 2012 00:40:31 -0500 Subject: [PATCH 08/22] Ugly Hacks Added some ugly hacks to fix Hixie: * Hixie now should work no matter how small the I/O buffer is * Hixie now works with the Guzzle library* --- lib/Ratchet/Application/WebSocket/App.php | 29 +++++++++++++++++-- .../Application/WebSocket/Version/Hixie76.php | 2 +- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php index 9feb7f8..edda0ef 100644 --- a/lib/Ratchet/Application/WebSocket/App.php +++ b/lib/Ratchet/Application/WebSocket/App.php @@ -18,6 +18,8 @@ use Guzzle\Http\Message\RequestFactory; * @todo Consider chaning this class to a State Pattern. If a WS App interface is passed use different state for additional methods used */ class App implements ApplicationInterface, ConfiguratorInterface { + const CRLF = "\r\n\r\n"; + /** * Decorated application * @var Ratchet\Application\ApplicationInterface @@ -87,6 +89,7 @@ class App implements ApplicationInterface, ConfiguratorInterface { } $headers = RequestFactory::fromMessage($from->WebSocket->headers); + $headers->setHeader('X-Body', $this->getBody($from->WebSocket->headers)); $from->WebSocket->version = $this->getVersion($headers); $from->WebSocket->headers = $headers; } @@ -236,10 +239,32 @@ class App implements ApplicationInterface, ConfiguratorInterface { /** * @param string * @return bool - * @todo Method is flawed, this CAN result in an error with the Hixie protocol + * @todo Abstract, some hard coding done for (stupid) Hixie protocol */ protected function isMessageComplete($message) { - return (boolean)strstr($message, "\r\n\r\n"); + $headers = (boolean)strstr($message, static::CRLF); + if (!$headers) { + + return false; + } + + if (strstr($message, 'Sec-WebSocket-Key2')) { + if (8 !== strlen($this->getBody($message))) { + return false; + } + } + + return true; + } + + /** + * @param string + * @return string + * @deprecated + * @todo Remove soon, this is a temp hack for Hixie + */ + protected function getBody($message) { + return substr($message, strpos($message, static::CRLF) + strlen(static::CRLF)); } /** diff --git a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php index 5f98e3c..7a04958 100644 --- a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php +++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php @@ -24,7 +24,7 @@ class Hixie76 implements VersionInterface { * @return string */ public function handshake(RequestInterface $request) { - $message = $request->getRawHeaders() . $request->getResponse()->getBody(true); + $message = $request->getRawHeaders() . "\r\n\r\n" . $request->getHeader('X-Body'); $buffer = $message; $resource = $host = $origin = $key1 = $key2 = $protocol = $code = $handshake = null; From 67267bfd946f04be446aa8c7e9af7184942d118d Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sat, 7 Jan 2012 01:20:34 -0500 Subject: [PATCH 09/22] Cleanup Using native Guzzle object in Hixie handshake instead of hack being done in App. Thanks to @mtdowling for the lead. --- lib/Ratchet/Application/WebSocket/App.php | 23 +++------- .../Guzzle/Http/Message/RequestFactory.php | 43 +++++++++++++++++++ .../Application/WebSocket/Version/Hixie76.php | 5 +-- 3 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 lib/Ratchet/Application/WebSocket/Guzzle/Http/Message/RequestFactory.php diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php index edda0ef..d56a6a8 100644 --- a/lib/Ratchet/Application/WebSocket/App.php +++ b/lib/Ratchet/Application/WebSocket/App.php @@ -7,7 +7,7 @@ use Ratchet\Resource\Command\Factory; use Ratchet\Resource\Command\CommandInterface; use Ratchet\Resource\Command\Action\SendMessage; use Guzzle\Http\Message\RequestInterface; -use Guzzle\Http\Message\RequestFactory; +use Ratchet\Application\WebSocket\Guzzle\Http\Message\RequestFactory; /** * The adapter to handle WebSocket requests/responses @@ -18,8 +18,6 @@ use Guzzle\Http\Message\RequestFactory; * @todo Consider chaning this class to a State Pattern. If a WS App interface is passed use different state for additional methods used */ class App implements ApplicationInterface, ConfiguratorInterface { - const CRLF = "\r\n\r\n"; - /** * Decorated application * @var Ratchet\Application\ApplicationInterface @@ -88,8 +86,7 @@ class App implements ApplicationInterface, ConfiguratorInterface { return; } - $headers = RequestFactory::fromMessage($from->WebSocket->headers); - $headers->setHeader('X-Body', $this->getBody($from->WebSocket->headers)); + $headers = RequestFactory::fromRequest($from->WebSocket->headers); $from->WebSocket->version = $this->getVersion($headers); $from->WebSocket->headers = $headers; } @@ -242,14 +239,16 @@ class App implements ApplicationInterface, ConfiguratorInterface { * @todo Abstract, some hard coding done for (stupid) Hixie protocol */ protected function isMessageComplete($message) { - $headers = (boolean)strstr($message, static::CRLF); + static $crlf = "\r\n\r\n"; + + $headers = (boolean)strstr($message, $crlf); if (!$headers) { return false; } if (strstr($message, 'Sec-WebSocket-Key2')) { - if (8 !== strlen($this->getBody($message))) { + if (8 !== strlen(substr($message, strpos($message, $crlf) + strlen($crlf)))) { return false; } } @@ -257,16 +256,6 @@ class App implements ApplicationInterface, ConfiguratorInterface { return true; } - /** - * @param string - * @return string - * @deprecated - * @todo Remove soon, this is a temp hack for Hixie - */ - protected function getBody($message) { - return substr($message, strpos($message, static::CRLF) + strlen(static::CRLF)); - } - /** * Disable a version of the WebSocket protocol *cough*Hixie76*cough* * @param string The name of the version to disable diff --git a/lib/Ratchet/Application/WebSocket/Guzzle/Http/Message/RequestFactory.php b/lib/Ratchet/Application/WebSocket/Guzzle/Http/Message/RequestFactory.php new file mode 100644 index 0000000..5184ce0 --- /dev/null +++ b/lib/Ratchet/Application/WebSocket/Guzzle/Http/Message/RequestFactory.php @@ -0,0 +1,43 @@ +setProtocolVersion($protocolVersion); + } + + protected static function requestCreate($method, $url, $headers = null, $body = null) { + $c = static::$entityEnclosingRequestClass; + $request = new $c($method, $url, $headers); + $request->setBody($body); + + return $request; + } +} \ No newline at end of file diff --git a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php index 7a04958..bea5578 100644 --- a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php +++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php @@ -22,11 +22,10 @@ class Hixie76 implements VersionInterface { /** * @param string * @return string + * @todo Unhack this mess...or wait for Hixie to die (HURRY UP APPLE) */ public function handshake(RequestInterface $request) { - $message = $request->getRawHeaders() . "\r\n\r\n" . $request->getHeader('X-Body'); - - $buffer = $message; + $buffer = $request->getRawHeaders() . "\r\n\r\n" . $request->getBody(); $resource = $host = $origin = $key1 = $key2 = $protocol = $code = $handshake = null; preg_match('#GET (.*?) HTTP#', $buffer, $match) && $resource = $match[1]; From 4b2e731b6ffd6e5b6f8fb18d7ff69ceb0dc0b0fe Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 8 Jan 2012 19:47:41 -0500 Subject: [PATCH 10/22] Added vendor info --- vendor/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 vendor/README.md diff --git a/vendor/README.md b/vendor/README.md new file mode 100644 index 0000000..03f7f86 --- /dev/null +++ b/vendor/README.md @@ -0,0 +1,5 @@ +## External Libraries + +### Guzzle + +Used to parse the incoming HTTP handshake request. A Guzzle Request object is then passed around the application for a consistent API. \ No newline at end of file From 3a4bdc918c9f27f4860371204f1d034d26922650 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 8 Jan 2012 22:15:31 -0500 Subject: [PATCH 11/22] WAMP Interface Updated interfaces from app refactor to branch out WAMP on top of WebSocket app --- lib/Ratchet/Application/Server/App.php | 3 ++- lib/Ratchet/Application/WAMP/App.php | 15 +++++++-------- lib/Ratchet/Application/WAMP/JSONException.php | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/Ratchet/Application/Server/App.php b/lib/Ratchet/Application/Server/App.php index 8eb8fb0..39e144e 100644 --- a/lib/Ratchet/Application/Server/App.php +++ b/lib/Ratchet/Application/Server/App.php @@ -80,6 +80,7 @@ class App implements ApplicationInterface { declare(ticks = 1); + $host->set_option(SOL_SOCKET, SO_SNDBUF, $this->_buffer_size); $host->set_nonblock()->bind($address, (int)$port)->listen(); do { @@ -105,7 +106,7 @@ class App implements ApplicationInterface { $res = $this->onOpen($conn); } else { $data = $buf = ''; - $bytes = $conn->getSocket()->recv($buf, $this->_buffer_size, 0); + $bytes = $conn->getSocket()->recv($buf, $this->_buffer_size, MSG_DONTWAIT); if ($bytes > 0) { $data = $buf; diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index cfd320c..2829b47 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -21,16 +21,15 @@ use Ratchet\Resource\Connection; * @link http://www.tavendo.de/autobahn/protocol.html * @todo I can't make up my mind what interface to present to the server application */ -class App implements ApplicationInterface, WebSocketAppInterface { +class App implements WebSocketAppInterface { + protected $_app; + protected static $_incoming = array(1, 2, 5, 6, 7); public function getSubProtocol() { return 'wamp'; } - public function attachHandler(ServerInterface $app) { - } - /** * @todo WAMP spec does not say what to do when there is an error with PREFIX... */ @@ -72,12 +71,12 @@ class App implements ApplicationInterface, WebSocketAppInterface { if ($json[0] == 1) { $this->addPrefix($conn, $json[2], $json[1]); } + + // Determine WAMP message type, call $_this->_app->on(); } - public function __construct(ApplicationInterface $app = null) { - if (null !== $app) { - throw new \InvalidArgumentException('WAMP is the end of the Socket stack, apps build on this must conform to the WAMP protocol'); - } + public function __construct(ServerInterface $app) { + $this->_app = $app; } public function onClose(Connection $conn) { diff --git a/lib/Ratchet/Application/WAMP/JSONException.php b/lib/Ratchet/Application/WAMP/JSONException.php index 8e238c0..c8cb7c1 100644 --- a/lib/Ratchet/Application/WAMP/JSONException.php +++ b/lib/Ratchet/Application/WAMP/JSONException.php @@ -1,7 +1,7 @@ Date: Fri, 13 Jan 2012 21:43:50 -0500 Subject: [PATCH 12/22] Guzzle upgrade Changed branch to 2.0b Includes addition of Message::getTokenizedHeader() added by @ mtdowling for Ratchet (thanks!) --- vendor/guzzle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/guzzle b/vendor/guzzle index 13ea2e7..ba265df 160000 --- a/vendor/guzzle +++ b/vendor/guzzle @@ -1 +1 @@ -Subproject commit 13ea2e723eaba72d99eefb24ec36f95ff7ef0068 +Subproject commit ba265df35892c55f03f1a239a0bac17f00031d16 From ad302a00d1c371420e7d022338e93c9248795b47 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 13 Jan 2012 23:46:30 -0500 Subject: [PATCH 13/22] WAMP incoming functionality WAMP server interface initial incoming message functionality Able to receive and pass on client to server messages to attached interface --- lib/Ratchet/Application/WAMP/App.php | 46 +++++++++++------ .../Application/WAMP/ServerInterface.php | 51 +++++++++++++++++++ lib/Ratchet/Application/WebSocket/App.php | 32 ++++++------ .../Application/WebSocket/Version/RFC6455.php | 2 +- phpunit.xml.dist | 1 + 5 files changed, 99 insertions(+), 33 deletions(-) diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index 2829b47..f97e17b 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -19,13 +19,10 @@ use Ratchet\Resource\Connection; * | EVENT | 8 | Server-to-Client | * +--------------+----+------------------+ * @link http://www.tavendo.de/autobahn/protocol.html - * @todo I can't make up my mind what interface to present to the server application */ class App implements WebSocketAppInterface { protected $_app; - protected static $_incoming = array(1, 2, 5, 6, 7); - public function getSubProtocol() { return 'wamp'; } @@ -42,16 +39,12 @@ class App implements WebSocketAppInterface { $conn->prefixes[$uri] = $curie; } - public function sendEvent($uri, $event) { - } - - public function onCall(Connection $conn, $id, $uri) { - } - public function onOpen(Connection $conn) { $conn->WAMP = new \StdClass; $conn->WAMP->prefixes = array(); $conn->WAMP->subscriptions = array(); + + return $this->_app->onOpen($conn); } /** @@ -64,15 +57,35 @@ class App implements WebSocketAppInterface { throw new JSONException; } - if (!in_array($json[0], static::$_incoming)) { - throw new Exception('Invalid message type'); + switch ($json[0]) { + case 1: + return $this->addPrefix($conn, $json[2], $json[1]); + break; + + case 2: + $ret = $this->_app->onCall($from, $json[1], $json[2]); + break; + + case 5: + $ret = $this->_app->onSubscribe($from, $json[1]); + break; + + case 6: + $ret = $this->_app->onUnSubscribe($from, $json[1]); + break; + + case 7: + $ret = $this->_app->onPublish($from, $json[1], $json[2]); + break; + + default: + throw new Exception('Invalid message type'); } - if ($json[0] == 1) { - $this->addPrefix($conn, $json[2], $json[1]); - } + // create method to loop through $ret + // json_encode messages, return $ret back to WebSocket - // Determine WAMP message type, call $_this->_app->on(); + return $ret; } public function __construct(ServerInterface $app) { @@ -80,9 +93,10 @@ class App implements WebSocketAppInterface { } public function onClose(Connection $conn) { - // remove all prefixes associated with connection? or will those just be destroyed w/ Connection + return $this->_app->onClose($conn); } public function onError(Connection $conn, \Exception $e) { + return $this->_app->onError($conn, $e); } } \ No newline at end of file diff --git a/lib/Ratchet/Application/WAMP/ServerInterface.php b/lib/Ratchet/Application/WAMP/ServerInterface.php index 69f484a..86b3df6 100644 --- a/lib/Ratchet/Application/WAMP/ServerInterface.php +++ b/lib/Ratchet/Application/WAMP/ServerInterface.php @@ -2,12 +2,63 @@ namespace Ratchet\Application\WAMP; use Ratchet\Resource\Connection; +/** + * A (not literal) extension of Ratchet\Application\ApplicationInterface + * onMessage is replaced by various types of messages for this protocol (pub/sub or rpc) + * @todo Thought: URI as class. Class has short and long version stored (if as prefix) + */ interface ServerInterface { + /** + * When a new connection is opened it will be passed to this method + * @param Ratchet\Resource\Connection + */ + function onOpen(Connection $conn); + + /** + * The user closed their connection + * @param Ratchet\Resource\Connection + * @return Ratchet\Resource\Command\CommandInterface|null + */ + function onClose(Connection $conn); + + /** + * @param Ratchet\Resource\Connection + * @param \Exception + * @return Ratchet\Resource\Command\CommandInterface|null + */ + function onError(Connection $conn, \Exception $e); + + /** + * An RPC call has been received + * @param Ratchet\Resource\Connection + * @param string + * @param ... + * @return Ratchet\Resource\Command\CommandInterface|null + */ function onCall(Connection $conn, $callID, $uri); + /** + * A request to subscribe to a URI has been made + * @param Ratchet\Resource\Connection + * @param ... + * @return Ratchet\Resource\Command\CommandInterface|null + */ function onSubscribe(Connection $conn, $uri); + /** + * A request to unsubscribe from a URI has been made + * @param Ratchet\Resource\Connection + * @param ... + * @return Ratchet\Resource\Command\CommandInterface|null + */ function onUnSubscribe(Connection $conn, $uri); + /** + * A client is attempting to publish content to a subscribed connections on a URI + * @param Ratchet\Resource\Connection + * @param ... + * @param string + * @return Ratchet\Resource\Command\CommandInterface|null + */ function onPublish(Connection $conn, $uri, $event); } \ No newline at end of file diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php index 0900067..8753c93 100644 --- a/lib/Ratchet/Application/WebSocket/App.php +++ b/lib/Ratchet/Application/WebSocket/App.php @@ -42,6 +42,12 @@ class App implements ApplicationInterface, ConfiguratorInterface { protected $_mask_payload = false; + /** + * @deprecated + * @temporary + */ + public $accepted_subprotocols = array(); + public function __construct(ApplicationInterface $app) { $this->_app = $app; $this->_factory = new Factory; @@ -73,7 +79,6 @@ class App implements ApplicationInterface, ConfiguratorInterface { * Do handshake, frame/unframe messages coming/going in stack * @todo This needs some major refactoring * @todo "Once the client's opening handshake has been sent, the client MUST wait for a response from the server before sending any further data." - * @todo Change Header to be a class, not array|string - will make things SO much easier...right now can't do WAMP on Hixie */ public function onMessage(Connection $from, $msg) { if (true !== $from->WebSocket->handshake) { @@ -92,13 +97,16 @@ class App implements ApplicationInterface, ConfiguratorInterface { $from->WebSocket->handshake = true; if (is_array($response)) { - if ($this->_app instanceof WebSocketAppInterface) { - // Note: this logic is wrong - we're supposed to check what the client sent - // as its sub protocol and if we support any of the requested we send that back. - // This is just sending what ever one wwe support - // This will be changed when I rewrite how headers are handled - // Also...what happens if something like a logger is put between this and the sub-protocol app? - $response['Sec-WebSocket-Protocol'] = $this->_app->getSubProtocol(); + // This block is to be moved/changed later + $agreed_protocols = array(); + $requested_protocols = $from->WebSocket->headers->getTokenizedHeader('Sec-WebSocket-Protocol', ','); + foreach ($this->accepted_subprotocols as $sub_protocol) { + if (false !== $requested_protocols->hasValue($sub_protocol)) { + $agreed_protocols[] = $sub_protocol; + } + } + if (count($agreed_protocols) > 0) { + $response['Sec-WebSocket-Protocol'] = implode(',', $agreed_protocols); } $header = ''; @@ -163,14 +171,6 @@ class App implements ApplicationInterface, ConfiguratorInterface { return $this->_app->onError($conn, $e); } - /** - * Incomplete, WebSocket protocol allows client to ask to use a sub-protocol, I'm thinking/wanting to somehow implement this in an application decorated class - * @param string - * @todo Implement or delete... - */ - public function setSubProtocol($name) { - } - /** * Checks if a return Command from your application is a message, if so encode it/them * @param Ratchet\Resource\Command\CommandInterface|NULL diff --git a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php index ad41e66..bb579cb 100644 --- a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php +++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php @@ -4,7 +4,7 @@ use Ratchet\Application\WebSocket\Version\RFC6455\HandshakeVerifier; use Guzzle\Http\Message\RequestInterface; /** - * @link http://www.rfc-editor.org/authors/rfc6455.txt + * @link http://tools.ietf.org/html/rfc6455 */ class RFC6455 implements VersionInterface { const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bb897be..e093f23 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -19,6 +19,7 @@ ./tests/ + ./vendor/ \ No newline at end of file From 9b14684cbe772f17a462aa6f5e228b48a3d9a3d9 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Mon, 16 Jan 2012 22:54:28 -0500 Subject: [PATCH 14/22] WAMP Event Action Added the Event action in WAMP (like SendMessage) Confirmed subscribe, unsubscribe, publish, event working in WAMP --- lib/Ratchet/Application/WAMP/App.php | 14 +++++--------- .../Application/WAMP/Command/Action/Event.php | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 lib/Ratchet/Application/WAMP/Command/Action/Event.php diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index f97e17b..e0f79d9 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -6,6 +6,7 @@ use Ratchet\Resource\Connection; /** * WebSocket Application Messaging Protocol + * * +--------------+----+------------------+ * | Message Type | ID | DIRECTION | * |--------------+----+------------------+ @@ -63,29 +64,24 @@ class App implements WebSocketAppInterface { break; case 2: - $ret = $this->_app->onCall($from, $json[1], $json[2]); + return $this->_app->onCall($from, $json[1], $json[2]); break; case 5: - $ret = $this->_app->onSubscribe($from, $json[1]); + return $this->_app->onSubscribe($from, $json[1]); break; case 6: - $ret = $this->_app->onUnSubscribe($from, $json[1]); + return $this->_app->onUnSubscribe($from, $json[1]); break; case 7: - $ret = $this->_app->onPublish($from, $json[1], $json[2]); + return $this->_app->onPublish($from, $json[1], $json[2]); break; default: throw new Exception('Invalid message type'); } - - // create method to loop through $ret - // json_encode messages, return $ret back to WebSocket - - return $ret; } public function __construct(ServerInterface $app) { diff --git a/lib/Ratchet/Application/WAMP/Command/Action/Event.php b/lib/Ratchet/Application/WAMP/Command/Action/Event.php new file mode 100644 index 0000000..2f4a389 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/Event.php @@ -0,0 +1,17 @@ +setMessage(json_encode(array(8, $uri, (string)$msg))); + } +} \ No newline at end of file From 5e82fc76c688af9310b47ed78137001439728ab9 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 17 Jan 2012 20:39:07 -0500 Subject: [PATCH 15/22] Factory Caching If a Command class was found in the factory save its class name. This prevents looping and checking 'class_exists' if it's already been found before. --- lib/Ratchet/Resource/Command/Factory.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/Ratchet/Resource/Command/Factory.php b/lib/Ratchet/Resource/Command/Factory.php index 077530a..559ee13 100644 --- a/lib/Ratchet/Resource/Command/Factory.php +++ b/lib/Ratchet/Resource/Command/Factory.php @@ -8,6 +8,8 @@ use Ratchet\Resource\Connection; class Factory { protected $_paths = array(); + protected $_mapped_commands = array(); + public function __construct() { $this->addActionPath(__NAMESPACE__ . '\\Action'); } @@ -33,19 +35,19 @@ class Factory { * @throws UnexpectedValueException */ public function newCommand($name, Connection $conn) { - $cmd = null; + if (isset($this->_mapped_commands[$name])) { + $cmd = $this->_mapped_commands[$name]; + return new $cmd($conn); + } + foreach ($this->_paths as $path) { if (class_exists($path . $name)) { - $cmd = $path . $name; - break; + $this->_mapped_commands[$name] = $path . $name; + return $this->newCommand($name, $conn); } } - if (null === $cmd) { - throw new \UnexepctedValueException("Command {$name} not found"); - } - - return new $cmd($conn); + throw new \UnexepctedValueException("Command {$name} not found"); } /** From b2e4578e19bff38730e1ed5ca65606eede5bdb8f Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 17 Jan 2012 20:39:53 -0500 Subject: [PATCH 16/22] WAMP onCall Functioning onCall on WAMP Fixed bug on Event - fluent interface (had broken factory) --- lib/Ratchet/Application/WAMP/App.php | 4 +++- lib/Ratchet/Application/WAMP/Command/Action/Event.php | 2 +- lib/Ratchet/Application/WAMP/ServerInterface.php | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index e0f79d9..a1c6f32 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -64,7 +64,9 @@ class App implements WebSocketAppInterface { break; case 2: - return $this->_app->onCall($from, $json[1], $json[2]); + array_shift($json); + array_unshift($json, $from); + return call_user_func_array(array($this->_app, 'onCall'), $json); break; case 5: diff --git a/lib/Ratchet/Application/WAMP/Command/Action/Event.php b/lib/Ratchet/Application/WAMP/Command/Action/Event.php index 2f4a389..77bc270 100644 --- a/lib/Ratchet/Application/WAMP/Command/Action/Event.php +++ b/lib/Ratchet/Application/WAMP/Command/Action/Event.php @@ -12,6 +12,6 @@ class Event extends SendMessage { * @param string */ public function setEvent($uri, $msg) { - $this->setMessage(json_encode(array(8, $uri, (string)$msg))); + return $this->setMessage(json_encode(array(8, $uri, (string)$msg))); } } \ No newline at end of file diff --git a/lib/Ratchet/Application/WAMP/ServerInterface.php b/lib/Ratchet/Application/WAMP/ServerInterface.php index 86b3df6..b636f2d 100644 --- a/lib/Ratchet/Application/WAMP/ServerInterface.php +++ b/lib/Ratchet/Application/WAMP/ServerInterface.php @@ -35,7 +35,7 @@ interface ServerInterface { * @param ... * @return Ratchet\Resource\Command\CommandInterface|null */ - function onCall(Connection $conn, $callID, $uri); + function onCall(); /** * A request to subscribe to a URI has been made From eb82a7ab0444afc0b8e4f86fdfd7da4809f33c0d Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 17 Jan 2012 21:05:32 -0500 Subject: [PATCH 17/22] WAMP Prefixes WAMP Client to server prefixes and transparent interpretation to application working --- lib/Ratchet/Application/WAMP/App.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index a1c6f32..5d4e67d 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -31,13 +31,13 @@ class App implements WebSocketAppInterface { /** * @todo WAMP spec does not say what to do when there is an error with PREFIX... */ - public function addPrefix(Connection $conn, $uri, $curie) { + public function addPrefix(Connection $conn, $curie, $uri) { // validate uri // validate curie // make sure the curie is shorter than the uri - $conn->prefixes[$uri] = $curie; + $conn->WAMP->prefixes[$curie] = $uri; } public function onOpen(Connection $conn) { @@ -60,7 +60,7 @@ class App implements WebSocketAppInterface { switch ($json[0]) { case 1: - return $this->addPrefix($conn, $json[2], $json[1]); + return $this->addPrefix($from, $json[1], $json[2]); break; case 2: @@ -70,15 +70,15 @@ class App implements WebSocketAppInterface { break; case 5: - return $this->_app->onSubscribe($from, $json[1]); + return $this->_app->onSubscribe($from, $this->getUri($from, $json[1])); break; case 6: - return $this->_app->onUnSubscribe($from, $json[1]); + return $this->_app->onUnSubscribe($from, $this->getUri($from, $json[1])); break; case 7: - return $this->_app->onPublish($from, $json[1], $json[2]); + return $this->_app->onPublish($from, $this->getUri($from, $json[1]), $json[2]); break; default: @@ -86,6 +86,16 @@ class App implements WebSocketAppInterface { } } + /** + * Get the full request URI from the connection object if a prefix has been established for it + * @param Ratchet\Resource\Connection + * @param ... + * @return string + */ + protected function getUri(Connection $conn, $uri) { + $ret = (isset($conn->WAMP->prefixes[$uri]) ? $conn->WAMP->prefixes[$uri] : $uri); + } + public function __construct(ServerInterface $app) { $this->_app = $app; } From dbcb6f2cdea2469a687c867613d32227533e1151 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 17 Jan 2012 22:47:17 -0500 Subject: [PATCH 18/22] WAMP Cleanup Fixed a bug in getURI Cleaned up roc calls - cleaner api, no more call_() calls --- lib/Ratchet/Application/WAMP/App.php | 12 +++++++++--- .../Application/WAMP/Command/Action/Event.php | 1 + lib/Ratchet/Application/WAMP/ServerInterface.php | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index 5d4e67d..cf31c92 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -65,8 +65,14 @@ class App implements WebSocketAppInterface { case 2: array_shift($json); - array_unshift($json, $from); - return call_user_func_array(array($this->_app, 'onCall'), $json); + $callID = array_shift($json); + $procURI = array_shift($json); + + if (count($json) == 1 && is_array($json[0])) { + $json = $json[0]; + } + + return $this->_app->onCall($from, $callID, $procURI, $json); break; case 5: @@ -93,7 +99,7 @@ class App implements WebSocketAppInterface { * @return string */ protected function getUri(Connection $conn, $uri) { - $ret = (isset($conn->WAMP->prefixes[$uri]) ? $conn->WAMP->prefixes[$uri] : $uri); + return (isset($conn->WAMP->prefixes[$uri]) ? $conn->WAMP->prefixes[$uri] : $uri); } public function __construct(ServerInterface $app) { diff --git a/lib/Ratchet/Application/WAMP/Command/Action/Event.php b/lib/Ratchet/Application/WAMP/Command/Action/Event.php index 77bc270..fac4428 100644 --- a/lib/Ratchet/Application/WAMP/Command/Action/Event.php +++ b/lib/Ratchet/Application/WAMP/Command/Action/Event.php @@ -10,6 +10,7 @@ class Event extends SendMessage { /** * @param ... * @param string + * @return Event */ public function setEvent($uri, $msg) { return $this->setMessage(json_encode(array(8, $uri, (string)$msg))); diff --git a/lib/Ratchet/Application/WAMP/ServerInterface.php b/lib/Ratchet/Application/WAMP/ServerInterface.php index b636f2d..f072181 100644 --- a/lib/Ratchet/Application/WAMP/ServerInterface.php +++ b/lib/Ratchet/Application/WAMP/ServerInterface.php @@ -33,9 +33,10 @@ interface ServerInterface { * @param Ratchet\Resource\Connection * @param string * @param ... + * @param array Call parameters received from the client * @return Ratchet\Resource\Command\CommandInterface|null */ - function onCall(); + function onCall(Connection $conn, $id, $procURI, array $params); /** * A request to subscribe to a URI has been made From f84be39fcffe854a759a078376af2079ba1f6918 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Wed, 18 Jan 2012 08:06:02 -0500 Subject: [PATCH 19/22] WAMP server prefix Server to client set Prefix in WAMP working via lambda in Connection object --- lib/Ratchet/Application/WAMP/App.php | 52 ++++++++++++++++--- .../WAMP/Command/Action/Prefix.php | 36 +++++++++++++ 2 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 lib/Ratchet/Application/WAMP/Command/Action/Prefix.php diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index cf31c92..f726460 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -3,6 +3,9 @@ namespace Ratchet\Application\WAMP; use Ratchet\Application\ApplicationInterface; use Ratchet\Application\WebSocket\WebSocketAppInterface; use Ratchet\Resource\Connection; +use Ratchet\Resource\Command\Composite; +use Ratchet\Resource\Command\CommandInterface; +use Ratchet\Application\WAMP\Command\Action\Prefix; /** * WebSocket Application Messaging Protocol @@ -24,6 +27,13 @@ use Ratchet\Resource\Connection; class App implements WebSocketAppInterface { protected $_app; + /** + * Any server to client prefixes are stored here + * They're taxied along with the next outgoing message + * @var Ratchet\Resource\Command\Composite + */ + protected $_msg_buffer = null; + public function getSubProtocol() { return 'wamp'; } @@ -31,13 +41,20 @@ class App implements WebSocketAppInterface { /** * @todo WAMP spec does not say what to do when there is an error with PREFIX... */ - public function addPrefix(Connection $conn, $curie, $uri) { + public function addPrefix(Connection $conn, $curie, $uri, $from_server = false) { // validate uri // validate curie // make sure the curie is shorter than the uri $conn->WAMP->prefixes[$curie] = $uri; + + if ($from_server) { + $prefix = new Prefix($conn); + $prefix->setPrefix($curie, $uri); + + $this->_msg_buffer->enqueue($prefix); + } } public function onOpen(Connection $conn) { @@ -45,6 +62,11 @@ class App implements WebSocketAppInterface { $conn->WAMP->prefixes = array(); $conn->WAMP->subscriptions = array(); + $wamp = $this; + $conn->WAMP->addPrefix = function($curie, $uri) use ($wamp, $conn) { + $wamp->addPrefix($conn, $curie, $uri, true); + }; + return $this->_app->onOpen($conn); } @@ -60,7 +82,7 @@ class App implements WebSocketAppInterface { switch ($json[0]) { case 1: - return $this->addPrefix($from, $json[1], $json[2]); + $ret = $this->addPrefix($from, $json[1], $json[2]); break; case 2: @@ -72,24 +94,26 @@ class App implements WebSocketAppInterface { $json = $json[0]; } - return $this->_app->onCall($from, $callID, $procURI, $json); + $ret = $this->_app->onCall($from, $callID, $procURI, $json); break; case 5: - return $this->_app->onSubscribe($from, $this->getUri($from, $json[1])); + $ret = $this->_app->onSubscribe($from, $this->getUri($from, $json[1])); break; case 6: - return $this->_app->onUnSubscribe($from, $this->getUri($from, $json[1])); + $ret = $this->_app->onUnSubscribe($from, $this->getUri($from, $json[1])); break; case 7: - return $this->_app->onPublish($from, $this->getUri($from, $json[1]), $json[2]); + $ret = $this->_app->onPublish($from, $this->getUri($from, $json[1]), $json[2]); break; default: throw new Exception('Invalid message type'); } + + return $this->attachStack($ret); } /** @@ -102,8 +126,22 @@ class App implements WebSocketAppInterface { return (isset($conn->WAMP->prefixes[$uri]) ? $conn->WAMP->prefixes[$uri] : $uri); } + /** + * @param Ratchet\Resource\Command\CommandInterface|NULL + * @return Ratchet\Resource\Command\Composite + */ + protected function attachStack(CommandInterface $command = null) { + $stack = $this->_msg_buffer; + $stack->enqueue($command); + + $this->_msg_buffer = new Composite; + + return $stack; + } + public function __construct(ServerInterface $app) { - $this->_app = $app; + $this->_app = $app; + $this->_msg_buffer = new Composite; } public function onClose(Connection $conn) { diff --git a/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php b/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php new file mode 100644 index 0000000..56a5d00 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php @@ -0,0 +1,36 @@ +_curie = $curie; + $this->_uri = $uri; + + return $this->setMessage(json_encode(array(1, $curie, $uri))); + } + + /** + * @return string + */ + public function getCurie() { + return $this->_curie; + } + + /** + * @return string + */ + public function getUri() { + return $this->_uri; + } +} From 3372f72344ed28dfa5520ea820e36edb5f7d1800 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 19 Jan 2012 21:20:36 -0500 Subject: [PATCH 20/22] WAMP FUNCTIONAL RPC return message RPC return error WAMP protocol functionally complete! --- lib/Ratchet/Application/WAMP/App.php | 2 ++ .../WAMP/Command/Action/CallError.php | 31 +++++++++++++++++++ .../WAMP/Command/Action/CallResult.php | 26 ++++++++++++++++ .../WAMP/Command/Action/Prefix.php | 3 ++ 4 files changed, 62 insertions(+) create mode 100644 lib/Ratchet/Application/WAMP/Command/Action/CallError.php create mode 100644 lib/Ratchet/Application/WAMP/Command/Action/CallResult.php diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index f726460..6d9c002 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -127,6 +127,8 @@ class App implements WebSocketAppInterface { } /** + * If the developer's application as set some server-to-client prefixes to be set, + * this method ensures those are taxied to the next outgoing message * @param Ratchet\Resource\Command\CommandInterface|NULL * @return Ratchet\Resource\Command\Composite */ diff --git a/lib/Ratchet/Application/WAMP/Command/Action/CallError.php b/lib/Ratchet/Application/WAMP/Command/Action/CallError.php new file mode 100644 index 0000000..afba2b2 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/CallError.php @@ -0,0 +1,31 @@ +_id = $callId; + $this->_uri = $uri; + $this->_desc = $desc; + + return $this->setMessage(json_encode(array(4, $callId, $uri, $desc))); + } + + public function getId() { + return $this->_id; + } + + public function getUri() { + return $this->_uri; + } + + public function getDescription() { + return $this->_desc; + } +} \ No newline at end of file diff --git a/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php b/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php new file mode 100644 index 0000000..5e41a8a --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php @@ -0,0 +1,26 @@ +_id = $callId; + $this->_data = $data; + + return $this->setMessage(json_encode(array(3, $callId, $data))); + } + + public function getId() { + return $this->_id; + } + + public function getData() { + return $this->_data; + } +} \ No newline at end of file diff --git a/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php b/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php index 56a5d00..627dce2 100644 --- a/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php +++ b/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php @@ -3,6 +3,9 @@ namespace Ratchet\Application\WAMP\Command\Action; use Ratchet\Resource\Command\Action\SendMessage; /** + * Send a curie to uri mapping to the client + * Both sides will agree to send the curie, representing the uri, + * resulting in less data transfered */ class Prefix extends SendMessage { protected $_curie; From 4372f9a8c3a4f75bcbb89fad2c65410a2081e77f Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 19 Jan 2012 21:33:45 -0500 Subject: [PATCH 21/22] Updated Guzzle Updated Guzzle to v2.0.2 as previous branch 2.0b was removed --- vendor/guzzle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/guzzle b/vendor/guzzle index ba265df..ac64abc 160000 --- a/vendor/guzzle +++ b/vendor/guzzle @@ -1 +1 @@ -Subproject commit ba265df35892c55f03f1a239a0bac17f00031d16 +Subproject commit ac64abc2c05b921efc4623379c1674a282475ae5 From aceb2c90062a9776ae5324b93d90ae99fd1e9733 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 20 Jan 2012 17:48:35 -0500 Subject: [PATCH 22/22] WAMP Codes Changed the WAMP codes back into constants. Added the new Welcome constant (not yet implemented) --- lib/Ratchet/Application/WAMP/App.php | 21 ++++++++++++++----- .../WAMP/Command/Action/CallError.php | 3 ++- .../WAMP/Command/Action/CallResult.php | 3 ++- .../Application/WAMP/Command/Action/Event.php | 3 ++- .../WAMP/Command/Action/Prefix.php | 3 ++- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/Ratchet/Application/WAMP/App.php b/lib/Ratchet/Application/WAMP/App.php index 6d9c002..776bbba 100644 --- a/lib/Ratchet/Application/WAMP/App.php +++ b/lib/Ratchet/Application/WAMP/App.php @@ -23,8 +23,19 @@ use Ratchet\Application\WAMP\Command\Action\Prefix; * | EVENT | 8 | Server-to-Client | * +--------------+----+------------------+ * @link http://www.tavendo.de/autobahn/protocol.html + * @link https://raw.github.com/oberstet/Autobahn/master/lib/javascript/autobahn.js */ class App implements WebSocketAppInterface { + const MSG_WELCOME = 0; + const MSG_PREFIX = 1; + const MSG_CALL = 2; + const MSG_CALL_RESULT = 3; + const MSG_CALL_ERROR = 4; + const MSG_SUBSCRIBE = 5; + const MSG_UNSUBSCRIBE = 6; + const MSG_PUBLISH = 7; + const MSG_EVENT = 8; + protected $_app; /** @@ -81,11 +92,11 @@ class App implements WebSocketAppInterface { } switch ($json[0]) { - case 1: + case static::MSG_PREFIX: $ret = $this->addPrefix($from, $json[1], $json[2]); break; - case 2: + case static::MSG_CALL: array_shift($json); $callID = array_shift($json); $procURI = array_shift($json); @@ -97,15 +108,15 @@ class App implements WebSocketAppInterface { $ret = $this->_app->onCall($from, $callID, $procURI, $json); break; - case 5: + case static::MSG_SUBSCRIBE: $ret = $this->_app->onSubscribe($from, $this->getUri($from, $json[1])); break; - case 6: + case static::MSG_UNSUBSCRIBE: $ret = $this->_app->onUnSubscribe($from, $this->getUri($from, $json[1])); break; - case 7: + case static::MSG_PUBLISH: $ret = $this->_app->onPublish($from, $this->getUri($from, $json[1]), $json[2]); break; diff --git a/lib/Ratchet/Application/WAMP/Command/Action/CallError.php b/lib/Ratchet/Application/WAMP/Command/Action/CallError.php index afba2b2..6938dc1 100644 --- a/lib/Ratchet/Application/WAMP/Command/Action/CallError.php +++ b/lib/Ratchet/Application/WAMP/Command/Action/CallError.php @@ -1,6 +1,7 @@ _uri = $uri; $this->_desc = $desc; - return $this->setMessage(json_encode(array(4, $callId, $uri, $desc))); + return $this->setMessage(json_encode(array(WAMP::MSG_CALL_ERROR, $callId, $uri, $desc))); } public function getId() { diff --git a/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php b/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php index 5e41a8a..e839567 100644 --- a/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php +++ b/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php @@ -1,6 +1,7 @@ _id = $callId; $this->_data = $data; - return $this->setMessage(json_encode(array(3, $callId, $data))); + return $this->setMessage(json_encode(array(WAMP::MSG_CALL_RESULT, $callId, $data))); } public function getId() { diff --git a/lib/Ratchet/Application/WAMP/Command/Action/Event.php b/lib/Ratchet/Application/WAMP/Command/Action/Event.php index fac4428..6ec8813 100644 --- a/lib/Ratchet/Application/WAMP/Command/Action/Event.php +++ b/lib/Ratchet/Application/WAMP/Command/Action/Event.php @@ -1,6 +1,7 @@ setMessage(json_encode(array(8, $uri, (string)$msg))); + return $this->setMessage(json_encode(array(WAMP::MSG_EVENT, $uri, (string)$msg))); } } \ No newline at end of file diff --git a/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php b/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php index 627dce2..a66a033 100644 --- a/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php +++ b/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php @@ -1,6 +1,7 @@ _curie = $curie; $this->_uri = $uri; - return $this->setMessage(json_encode(array(1, $curie, $uri))); + return $this->setMessage(json_encode(array(WAMP::MSG_PREFIX, $curie, $uri))); } /**