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/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 diff --git a/lib/Ratchet/Application/Server/App.php b/lib/Ratchet/Application/Server/App.php index 5964f39..39e144e 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; } @@ -84,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 { @@ -109,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 new file mode 100644 index 0000000..776bbba --- /dev/null +++ b/lib/Ratchet/Application/WAMP/App.php @@ -0,0 +1,167 @@ +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) { + $conn->WAMP = new \StdClass; + $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); + } + + /** + * @{inherit} + * @throws Exception + * @throws JSONException + */ + public function onMessage(Connection $from, $msg) { + if (null === ($json = @json_decode($msg, true))) { + throw new JSONException; + } + + switch ($json[0]) { + case static::MSG_PREFIX: + $ret = $this->addPrefix($from, $json[1], $json[2]); + break; + + case static::MSG_CALL: + array_shift($json); + $callID = array_shift($json); + $procURI = array_shift($json); + + if (count($json) == 1 && is_array($json[0])) { + $json = $json[0]; + } + + $ret = $this->_app->onCall($from, $callID, $procURI, $json); + break; + + case static::MSG_SUBSCRIBE: + $ret = $this->_app->onSubscribe($from, $this->getUri($from, $json[1])); + break; + + case static::MSG_UNSUBSCRIBE: + $ret = $this->_app->onUnSubscribe($from, $this->getUri($from, $json[1])); + break; + + case static::MSG_PUBLISH: + $ret = $this->_app->onPublish($from, $this->getUri($from, $json[1]), $json[2]); + break; + + default: + throw new Exception('Invalid message type'); + } + + return $this->attachStack($ret); + } + + /** + * 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) { + return (isset($conn->WAMP->prefixes[$uri]) ? $conn->WAMP->prefixes[$uri] : $uri); + } + + /** + * 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 + */ + 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->_msg_buffer = new Composite; + } + + public function onClose(Connection $conn) { + 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/Command/Action/CallError.php b/lib/Ratchet/Application/WAMP/Command/Action/CallError.php new file mode 100644 index 0000000..6938dc1 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/CallError.php @@ -0,0 +1,32 @@ +_id = $callId; + $this->_uri = $uri; + $this->_desc = $desc; + + return $this->setMessage(json_encode(array(WAMP::MSG_CALL_ERROR, $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..e839567 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/CallResult.php @@ -0,0 +1,27 @@ +_id = $callId; + $this->_data = $data; + + return $this->setMessage(json_encode(array(WAMP::MSG_CALL_RESULT, $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/Event.php b/lib/Ratchet/Application/WAMP/Command/Action/Event.php new file mode 100644 index 0000000..6ec8813 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/Event.php @@ -0,0 +1,19 @@ +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 new file mode 100644 index 0000000..a66a033 --- /dev/null +++ b/lib/Ratchet/Application/WAMP/Command/Action/Prefix.php @@ -0,0 +1,40 @@ +_curie = $curie; + $this->_uri = $uri; + + return $this->setMessage(json_encode(array(WAMP::MSG_PREFIX, $curie, $uri))); + } + + /** + * @return string + */ + public function getCurie() { + return $this->_curie; + } + + /** + * @return string + */ + public function getUri() { + return $this->_uri; + } +} 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 @@ +_app = $app; $this->_factory = new Factory; } @@ -80,18 +83,32 @@ 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::fromRequest($from->WebSocket->headers); + $from->WebSocket->version = $this->getVersion($headers); + $from->WebSocket->headers = $headers; } $response = $from->WebSocket->version->handshake($from->WebSocket->headers); $from->WebSocket->handshake = true; if (is_array($response)) { + // 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 = ''; foreach ($response as $key => $val) { if (!empty($key)) { @@ -154,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 @@ -212,21 +221,15 @@ 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) { 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]; } @@ -236,6 +239,29 @@ class App implements ApplicationInterface, ConfiguratorInterface { throw new \InvalidArgumentException('Could not identify WebSocket protocol'); } + /** + * @param string + * @return bool + * @todo Abstract, some hard coding done for (stupid) Hixie protocol + */ + protected function isMessageComplete($message) { + static $crlf = "\r\n\r\n"; + + $headers = (boolean)strstr($message, $crlf); + if (!$headers) { + + return false; + } + + if (strstr($message, 'Sec-WebSocket-Key2')) { + if (8 !== strlen(substr($message, strpos($message, $crlf) + strlen($crlf)))) { + return false; + } + } + + return true; + } + /** * 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/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..bea5578 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 + * @todo Unhack this mess...or wait for Hixie to die (HURRY UP APPLE) */ - public function handshake($message) { - $buffer = $message; + public function handshake(RequestInterface $request) { + $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]; diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php index 39f20ea..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 d1c7d83..bb579cb 100644 --- a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php +++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php @@ -1,10 +1,10 @@ _verifier = new HandshakeVerifier; } - public static function isProtocol(array $headers) { - if (isset($headers['Sec-Websocket-Version'])) { - if ((int)$headers['Sec-Websocket-Version'] == 13) { - return true; - } - } - - return false; + /** + * @todo Change the request to be a Guzzle RequestInterface + */ + public static function isProtocol(RequestInterface $request) { + $version = (int)$request->getHeader('Sec-WebSocket-Version', -1); + return (13 === $version); } /** @@ -33,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 = HTTP::getHeaders($message); - $key = $this->sign($headers['Sec-Websocket-Key']); - - if (true !== $this->_verifier->verifyAll($headers)) { + public function handshake(RequestInterface $request) { + if (true !== $this->_verifier->verifyAll($request)) { throw new \InvalidArgumentException('Invalid HTTP header'); } @@ -45,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/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..8a13b70 100644 --- a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php +++ b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php @@ -1,5 +1,6 @@ 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"); } /** 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 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(); 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 2f02d40..d8416df 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,4 +5,7 @@ $app->register(); $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'); $app->register(); \ No newline at end of file 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 diff --git a/vendor/guzzle b/vendor/guzzle new file mode 160000 index 0000000..ac64abc --- /dev/null +++ b/vendor/guzzle @@ -0,0 +1 @@ +Subproject commit ac64abc2c05b921efc4623379c1674a282475ae5