diff --git a/lib/Ratchet/Application/Server/App.php b/lib/Ratchet/Application/Server/App.php index 13762c4..5964f39 100644 --- a/lib/Ratchet/Application/Server/App.php +++ b/lib/Ratchet/Application/Server/App.php @@ -78,6 +78,7 @@ class App implements ApplicationInterface { $this->_connections[$host->getResource()] = new Connection($host); $this->_resources[] = $host->getResource(); + gc_enable(); set_time_limit(0); ob_implicit_flush(); diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php index 46aaba3..4600473 100644 --- a/lib/Ratchet/Application/WebSocket/App.php +++ b/lib/Ratchet/Application/WebSocket/App.php @@ -16,7 +16,6 @@ use Ratchet\Application\WebSocket\Version; * @todo Make sure this works both ways (client/server) as stack needs to exist on client for framing * @todo Learn about closing the socket. A message has to be sent prior to closing - does the message get sent onClose event or CloseConnection command? * @todo Consider chaning this class to a State Pattern. If a WS App interface is passed use different state for additional methods used - * @todo I think I need to overhaul the architecture of this...more onus should be on the VersionInterfaces in case of changes...let them handle more decisions, not just parsing */ class App implements ApplicationInterface, ConfiguratorInterface { /** @@ -40,6 +39,8 @@ class App implements ApplicationInterface, ConfiguratorInterface { , 'Hixie76' => null ); + protected $_mask_payload = false; + public function __construct(ApplicationInterface $app = null) { if (null === $app) { throw new \UnexpectedValueException("WebSocket requires an application to run"); @@ -166,18 +167,36 @@ class App implements ApplicationInterface, ConfiguratorInterface { * @return Ratchet\Resource\Command\CommandInterface|NULL */ protected function prepareCommand(CommandInterface $command = null) { + $cache = array(); + return $this->mungCommand($command, $cache); + } + + /** + * Does the actual work of prepareCommand + * Separated to pass the cache array by reference, so we're not framing the same stirng over and over + * @param Ratchet\Resource\Command\CommandInterface|NULL + * @param array + * @return Ratchet\Resource\Command\CommandInterface|NULL + */ + protected function mungCommand(CommandInterface $command = null, &$cache) { if ($command instanceof SendMessage) { if (!isset($command->getConnection()->WebSocket->version)) { // Client could close connection before handshake complete or invalid handshake return $command; } $version = $command->getConnection()->WebSocket->version; - return $command->setMessage($version->frame($command->getMessage())); + $hash = md5($command->getMessage()) . '-' . spl_object_hash($version); + + if (!isset($cache[$hash])) { + $cache[$hash] = $version->frame($command->getMessage(), $this->_mask_payload); + } + + return $command->setMessage($cache[$hash]); } if ($command instanceof \Traversable) { foreach ($command as $cmd) { - $cmd = $this->prepareCommand($cmd); + $cmd = $this->mungCommand($cmd, $cache); } } @@ -206,8 +225,8 @@ class App implements ApplicationInterface, ConfiguratorInterface { } else { $ns = __NAMESPACE__ . "\\Version\\{$name}"; if ($ns::isProtocol($headers)) { - $this->_version[$name] = new $ns; - return $this->_version[$name]; + $this->_versions[$name] = new $ns; + return $this->_versions[$name]; } } } @@ -227,4 +246,14 @@ class App implements ApplicationInterface, ConfiguratorInterface { unset($this->_versions[$name]); } + + /** + * Set the option to mask the payload upon sending to client + * If WebSocket is used as server, this should be false, client to true + * @param bool + * @todo User shouldn't have to know/set this, need to figure out how to do this automatically + */ + public function setMaskPayload($opt) { + $this->_mask_payload = (boolean)$opt; + } } \ 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 38e94d8..0777701 100644 --- a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php +++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php @@ -7,7 +7,7 @@ namespace Ratchet\Application\WebSocket\Version; * 1) The handshake is done in HTTP, which includes a key for signing in the body... * BUT there is no Length defined in the header (as per HTTP spec) so the TCP buffer can't tell when the message is done! * 2) By nature it's insecure. Google did a test study where they were able to do a - * man-in-the-middle attack on 10%-15% of the people who saw their add who had a browser (currently only Safari) supporting the Hixie76 protocol. + * man-in-the-middle attack on 10%-15% of the people who saw their ad who had a browser (currently only Safari) supporting the Hixie76 protocol. * This was exploited by taking advantage of proxy servers in front of the user who ignored some HTTP headers in the handshake * The Hixie76 is currently implemented by Safari * Handshake from Andrea Giammarchi (http://webreflection.blogspot.com/2010/06/websocket-handshake-76-simplified.html) @@ -53,7 +53,7 @@ class Hixie76 implements VersionInterface { return new Hixie76\Frame; } - public function frame($message) { + public function frame($message, $mask = true) { return chr(0) . $message . chr(255); } diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php index 80316b3..78efb88 100644 --- a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php +++ b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php @@ -61,10 +61,10 @@ class HyBi10 implements VersionInterface { * @param string * @return string */ - public function frame($message) { + public function frame($message, $mask = true) { $payload = $message; $type = 'text'; - $masked = true; + $masked = $mask; $frameHead = array(); $frame = ''; diff --git a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php index b6078d9..461e149 100644 --- a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php +++ b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php @@ -35,8 +35,9 @@ interface VersionInterface { /** * @param string + * @param bool * @return string * @todo Change to use other classes, this will be removed eventually */ - function frame($message); + function frame($message, $mask = true); } \ No newline at end of file