diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..987e2a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +composer.lock +vendor diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..66857ea --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011-2014 Chris Boden + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Version/Hixie76.php b/Version/Hixie76.php deleted file mode 100644 index f521992..0000000 --- a/Version/Hixie76.php +++ /dev/null @@ -1,120 +0,0 @@ -getHeader('Sec-WebSocket-Key2')); - } - - /** - * {@inheritdoc} - */ - public function getVersionNumber() { - return 0; - } - - /** - * @param \Guzzle\Http\Message\RequestInterface $request - * @return \Guzzle\Http\Message\Response - * @throws \UnderflowException If there hasn't been enough data received - */ - public function handshake(RequestInterface $request) { - $body = substr($request->getBody(), 0, 8); - if (8 !== strlen($body)) { - throw new \UnderflowException("Not enough data received to issue challenge response"); - } - - $challenge = $this->sign((string)$request->getHeader('Sec-WebSocket-Key1'), (string)$request->getHeader('Sec-WebSocket-Key2'), $body); - - $headers = array( - 'Upgrade' => 'WebSocket' - , 'Connection' => 'Upgrade' - , 'Sec-WebSocket-Origin' => (string)$request->getHeader('Origin') - , 'Sec-WebSocket-Location' => 'ws://' . (string)$request->getHeader('Host') . $request->getPath() - ); - - $response = new Response(101, $headers, $challenge); - $response->setStatus(101, 'WebSocket Protocol Handshake'); - - return $response; - } - - /** - * {@inheritdoc} - */ - public function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback) { - $upgraded = new Connection($conn); - - if (!isset($upgraded->WebSocket)) { - $upgraded->WebSocket = new \StdClass; - } - - $upgraded->WebSocket->coalescedCallback = $coalescedCallback; - - return $upgraded; - } - - public function onMessage(ConnectionInterface $from, $data) { - $overflow = ''; - - if (!isset($from->WebSocket->frame)) { - $from->WebSocket->frame = $this->newFrame(); - } - - $from->WebSocket->frame->addBuffer($data); - if ($from->WebSocket->frame->isCoalesced()) { - $overflow = $from->WebSocket->frame->extractOverflow(); - - $parsed = $from->WebSocket->frame->getPayload(); - unset($from->WebSocket->frame); - - $from->WebSocket->coalescedCallback->onMessage($from, $parsed); - - unset($from->WebSocket->frame); - } - - if (strlen($overflow) > 0) { - $this->onMessage($from, $overflow); - } - } - - public function newFrame() { - return new Frame; - } - - public function generateKeyNumber($key) { - if (0 === substr_count($key, ' ')) { - return 0; - } - - return preg_replace('[\D]', '', $key) / substr_count($key, ' '); - } - - protected function sign($key1, $key2, $code) { - return md5( - pack('N', $this->generateKeyNumber($key1)) - . pack('N', $this->generateKeyNumber($key2)) - . $code - , true); - } -} diff --git a/Version/Hixie76/Connection.php b/Version/Hixie76/Connection.php deleted file mode 100644 index e3d0834..0000000 --- a/Version/Hixie76/Connection.php +++ /dev/null @@ -1,26 +0,0 @@ -WebSocket->closing) { - $this->getConnection()->send(chr(0) . $msg . chr(255)); - } - - return $this; - } - - public function close() { - if (!$this->WebSocket->closing) { - $this->getConnection()->send(chr(255)); - $this->getConnection()->close(); - - $this->WebSocket->closing = true; - } - } -} diff --git a/Version/Hixie76/Frame.php b/Version/Hixie76/Frame.php deleted file mode 100644 index 28eb90e..0000000 --- a/Version/Hixie76/Frame.php +++ /dev/null @@ -1,86 +0,0 @@ -_data[0] == chr(0) && substr($this->_data, -1) == chr(255)); - } - - /** - * {@inheritdoc} - */ - public function addBuffer($buf) { - $this->_data .= (string)$buf; - } - - /** - * {@inheritdoc} - */ - public function isFinal() { - return true; - } - - /** - * {@inheritdoc} - */ - public function isMasked() { - return false; - } - - /** - * {@inheritdoc} - */ - public function getOpcode() { - return 1; - } - - /** - * {@inheritdoc} - */ - public function getPayloadLength() { - if (!$this->isCoalesced()) { - throw new \UnderflowException('Not enough of the message has been buffered to determine the length of the payload'); - } - - return strlen($this->_data) - 2; - } - - /** - * {@inheritdoc} - */ - public function getMaskingKey() { - return ''; - } - - /** - * {@inheritdoc} - */ - public function getPayload() { - if (!$this->isCoalesced()) { - return new \UnderflowException('Not enough data buffered to read payload'); - } - - return substr($this->_data, 1, strlen($this->_data) - 2); - } - - public function getContents() { - return $this->_data; - } - - public function extractOverflow() { - return ''; - } -} diff --git a/Version/HyBi10.php b/Version/HyBi10.php deleted file mode 100644 index a53d338..0000000 --- a/Version/HyBi10.php +++ /dev/null @@ -1,15 +0,0 @@ -getHeader('Sec-WebSocket-Version'); - - return ($version >= 6 && $version < 13); - } - - public function getVersionNumber() { - return 6; - } -} diff --git a/VersionManager.php b/VersionManager.php deleted file mode 100644 index f514e1b..0000000 --- a/VersionManager.php +++ /dev/null @@ -1,90 +0,0 @@ -versions as $version) { - if ($version->isProtocol($request)) { - return $version; - } - } - - throw new \InvalidArgumentException("Version not found"); - } - - /** - * @param \Guzzle\Http\Message\RequestInterface - * @return bool - */ - public function isVersionEnabled(RequestInterface $request) { - foreach ($this->versions as $version) { - if ($version->isProtocol($request)) { - return true; - } - } - - return false; - } - - /** - * Enable support for a specific version of the WebSocket protocol - * @param \Ratchet\WebSocket\Version\VersionInterface $version - * @return VersionManager - */ - public function enableVersion(VersionInterface $version) { - $this->versions[$version->getVersionNumber()] = $version; - - if (empty($this->versionString)) { - $this->versionString = (string)$version->getVersionNumber(); - } else { - $this->versionString .= ", {$version->getVersionNumber()}"; - } - - return $this; - } - - /** - * Disable support for a specific WebSocket protocol version - * @param int $versionId The version ID to un-support - * @return VersionManager - */ - public function disableVersion($versionId) { - unset($this->versions[$versionId]); - - $this->versionString = implode(',', array_keys($this->versions)); - - return $this; - } - - /** - * Get a string of version numbers supported (comma delimited) - * @return string - */ - public function getSupportedVersionString() { - return $this->versionString; - } -} diff --git a/WsServer.php b/WsServer.php deleted file mode 100644 index b4be1f0..0000000 --- a/WsServer.php +++ /dev/null @@ -1,232 +0,0 @@ -versioner = new VersionManager; - $this->validator = new ToggleableValidator; - - $this->versioner - ->enableVersion(new Version\RFC6455($this->validator)) - ->enableVersion(new Version\HyBi10($this->validator)) - ->enableVersion(new Version\Hixie76) - ; - - $this->component = $component; - $this->connections = new \SplObjectStorage; - } - - /** - * {@inheritdoc} - */ - public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { - if (null === $request) { - throw new \UnexpectedValueException('$request can not be null'); - } - - $conn->WebSocket = new \StdClass; - $conn->WebSocket->request = $request; - $conn->WebSocket->established = false; - $conn->WebSocket->closing = false; - - $this->attemptUpgrade($conn); - } - - /** - * {@inheritdoc} - */ - public function onMessage(ConnectionInterface $from, $msg) { - if ($from->WebSocket->closing) { - return; - } - - if (true === $from->WebSocket->established) { - return $from->WebSocket->version->onMessage($this->connections[$from], $msg); - } - - $this->attemptUpgrade($from, $msg); - } - - protected function attemptUpgrade(ConnectionInterface $conn, $data = '') { - if ('' !== $data) { - $conn->WebSocket->request->getBody()->write($data); - } else { - if (!$this->versioner->isVersionEnabled($conn->WebSocket->request)) { - return $this->close($conn); - } - - $conn->WebSocket->version = $this->versioner->getVersion($conn->WebSocket->request); - } - - try { - $response = $conn->WebSocket->version->handshake($conn->WebSocket->request); - } catch (\UnderflowException $e) { - return; - } - - if (null !== ($subHeader = $conn->WebSocket->request->getHeader('Sec-WebSocket-Protocol'))) { - if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($subHeader->normalize()))) { - $response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols); - } - } - - $response->setHeader('X-Powered-By', \Ratchet\VERSION); - $conn->send((string)$response); - - if (101 != $response->getStatusCode()) { - return $conn->close(); - } - - $upgraded = $conn->WebSocket->version->upgradeConnection($conn, $this->component); - - $this->connections->attach($conn, $upgraded); - - $upgraded->WebSocket->established = true; - - return $this->component->onOpen($upgraded); - } - - /** - * {@inheritdoc} - */ - public function onClose(ConnectionInterface $conn) { - if ($this->connections->contains($conn)) { - $decor = $this->connections[$conn]; - $this->connections->detach($conn); - - $this->component->onClose($decor); - } - } - - /** - * {@inheritdoc} - */ - public function onError(ConnectionInterface $conn, \Exception $e) { - if ($conn->WebSocket->established && $this->connections->contains($conn)) { - $this->component->onError($this->connections[$conn], $e); - } else { - $conn->close(); - } - } - - /** - * Disable a specific version of the WebSocket protocol - * @param int $versionId Version ID to disable - * @return WsServer - */ - public function disableVersion($versionId) { - $this->versioner->disableVersion($versionId); - - return $this; - } - - /** - * Toggle weather to check encoding of incoming messages - * @param bool - * @return WsServer - */ - public function setEncodingChecks($opt) { - $this->validator->on = (boolean)$opt; - - return $this; - } - - /** - * @param string - * @return boolean - */ - public function isSubProtocolSupported($name) { - if (!$this->isSpGenerated) { - if ($this->component instanceof WsServerInterface) { - $this->acceptedSubProtocols = array_flip($this->component->getSubProtocols()); - } - - $this->isSpGenerated = true; - } - - return array_key_exists($name, $this->acceptedSubProtocols); - } - - /** - * @param \Traversable|null $requested - * @return string - */ - protected function getSubProtocolString(\Traversable $requested = null) { - if (null !== $requested) { - foreach ($requested as $sub) { - if ($this->isSubProtocolSupported($sub)) { - return $sub; - } - } - } - - return ''; - } - - /** - * Close a connection with an HTTP response - * @param \Ratchet\ConnectionInterface $conn - * @param int $code HTTP status code - */ - protected function close(ConnectionInterface $conn, $code = 400) { - $response = new Response($code, array( - 'Sec-WebSocket-Version' => $this->versioner->getSupportedVersionString() - , 'X-Powered-By' => \Ratchet\VERSION - )); - - $conn->send((string)$response); - $conn->close(); - } -} diff --git a/WsServerInterface.php b/WsServerInterface.php deleted file mode 100644 index 03b0710..0000000 --- a/WsServerInterface.php +++ /dev/null @@ -1,14 +0,0 @@ -=5.4.2" + } +} diff --git a/Encoding/ToggleableValidator.php b/src/Encoding/ToggleableValidator.php similarity index 100% rename from Encoding/ToggleableValidator.php rename to src/Encoding/ToggleableValidator.php diff --git a/Encoding/Validator.php b/src/Encoding/Validator.php similarity index 100% rename from Encoding/Validator.php rename to src/Encoding/Validator.php diff --git a/Encoding/ValidatorInterface.php b/src/Encoding/ValidatorInterface.php similarity index 100% rename from Encoding/ValidatorInterface.php rename to src/Encoding/ValidatorInterface.php diff --git a/Version/DataInterface.php b/src/Version/DataInterface.php similarity index 100% rename from Version/DataInterface.php rename to src/Version/DataInterface.php diff --git a/Version/FrameInterface.php b/src/Version/FrameInterface.php similarity index 100% rename from Version/FrameInterface.php rename to src/Version/FrameInterface.php diff --git a/Version/MessageInterface.php b/src/Version/MessageInterface.php similarity index 100% rename from Version/MessageInterface.php rename to src/Version/MessageInterface.php diff --git a/Version/RFC6455.php b/src/Version/RFC6455.php similarity index 100% rename from Version/RFC6455.php rename to src/Version/RFC6455.php diff --git a/Version/RFC6455/Connection.php b/src/Version/RFC6455/Connection.php similarity index 100% rename from Version/RFC6455/Connection.php rename to src/Version/RFC6455/Connection.php diff --git a/Version/RFC6455/Frame.php b/src/Version/RFC6455/Frame.php similarity index 100% rename from Version/RFC6455/Frame.php rename to src/Version/RFC6455/Frame.php diff --git a/Version/RFC6455/HandshakeVerifier.php b/src/Version/RFC6455/HandshakeVerifier.php similarity index 100% rename from Version/RFC6455/HandshakeVerifier.php rename to src/Version/RFC6455/HandshakeVerifier.php diff --git a/Version/RFC6455/Message.php b/src/Version/RFC6455/Message.php similarity index 100% rename from Version/RFC6455/Message.php rename to src/Version/RFC6455/Message.php diff --git a/Version/VersionInterface.php b/src/Version/VersionInterface.php similarity index 100% rename from Version/VersionInterface.php rename to src/Version/VersionInterface.php