Merge branch 'refs/heads/master' into unittests

This commit is contained in:
Chris Boden 2011-12-02 19:47:38 -05:00
commit 3ec97f6442
5 changed files with 41 additions and 10 deletions
lib/Ratchet/Application

View File

@ -78,6 +78,7 @@ class App implements ApplicationInterface {
$this->_connections[$host->getResource()] = new Connection($host); $this->_connections[$host->getResource()] = new Connection($host);
$this->_resources[] = $host->getResource(); $this->_resources[] = $host->getResource();
gc_enable();
set_time_limit(0); set_time_limit(0);
ob_implicit_flush(); ob_implicit_flush();

View File

@ -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 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 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 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 { class App implements ApplicationInterface, ConfiguratorInterface {
/** /**
@ -40,6 +39,8 @@ class App implements ApplicationInterface, ConfiguratorInterface {
, 'Hixie76' => null , 'Hixie76' => null
); );
protected $_mask_payload = false;
public function __construct(ApplicationInterface $app = null) { public function __construct(ApplicationInterface $app = null) {
if (null === $app) { if (null === $app) {
throw new \UnexpectedValueException("WebSocket requires an application to run"); throw new \UnexpectedValueException("WebSocket requires an application to run");
@ -166,18 +167,36 @@ class App implements ApplicationInterface, ConfiguratorInterface {
* @return Ratchet\Resource\Command\CommandInterface|NULL * @return Ratchet\Resource\Command\CommandInterface|NULL
*/ */
protected function prepareCommand(CommandInterface $command = 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 ($command instanceof SendMessage) {
if (!isset($command->getConnection()->WebSocket->version)) { // Client could close connection before handshake complete or invalid handshake if (!isset($command->getConnection()->WebSocket->version)) { // Client could close connection before handshake complete or invalid handshake
return $command; return $command;
} }
$version = $command->getConnection()->WebSocket->version; $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) { if ($command instanceof \Traversable) {
foreach ($command as $cmd) { foreach ($command as $cmd) {
$cmd = $this->prepareCommand($cmd); $cmd = $this->mungCommand($cmd, $cache);
} }
} }
@ -206,8 +225,8 @@ class App implements ApplicationInterface, ConfiguratorInterface {
} else { } else {
$ns = __NAMESPACE__ . "\\Version\\{$name}"; $ns = __NAMESPACE__ . "\\Version\\{$name}";
if ($ns::isProtocol($headers)) { if ($ns::isProtocol($headers)) {
$this->_version[$name] = new $ns; $this->_versions[$name] = new $ns;
return $this->_version[$name]; return $this->_versions[$name];
} }
} }
} }
@ -227,4 +246,14 @@ class App implements ApplicationInterface, ConfiguratorInterface {
unset($this->_versions[$name]); 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;
}
} }

View File

@ -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... * 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! * 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 * 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 * 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 * The Hixie76 is currently implemented by Safari
* Handshake from Andrea Giammarchi (http://webreflection.blogspot.com/2010/06/websocket-handshake-76-simplified.html) * 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; return new Hixie76\Frame;
} }
public function frame($message) { public function frame($message, $mask = true) {
return chr(0) . $message . chr(255); return chr(0) . $message . chr(255);
} }

View File

@ -61,10 +61,10 @@ class HyBi10 implements VersionInterface {
* @param string * @param string
* @return string * @return string
*/ */
public function frame($message) { public function frame($message, $mask = true) {
$payload = $message; $payload = $message;
$type = 'text'; $type = 'text';
$masked = true; $masked = $mask;
$frameHead = array(); $frameHead = array();
$frame = ''; $frame = '';

View File

@ -35,8 +35,9 @@ interface VersionInterface {
/** /**
* @param string * @param string
* @param bool
* @return string * @return string
* @todo Change to use other classes, this will be removed eventually * @todo Change to use other classes, this will be removed eventually
*/ */
function frame($message); function frame($message, $mask = true);
} }