WebSocket versions

Allowed user to disable WebSocket versions
Change how versions are detected, responsibility is on the concrete version class instead of factory
This commit is contained in:
Chris Boden 2011-11-24 20:59:19 -05:00
parent 4da707b653
commit d75113ec5e
4 changed files with 46 additions and 14 deletions

View File

@ -7,6 +7,7 @@ use Ratchet\Resource\Command\Factory;
use Ratchet\Resource\Command\CommandInterface; use Ratchet\Resource\Command\CommandInterface;
use Ratchet\Resource\Command\Action\SendMessage; use Ratchet\Resource\Command\Action\SendMessage;
use Ratchet\Application\WebSocket\Util\HTTP; use Ratchet\Application\WebSocket\Util\HTTP;
use Ratchet\Application\WebSocket\Version;
/** /**
* The adapter to handle WebSocket requests/responses * The adapter to handle WebSocket requests/responses
@ -185,11 +186,10 @@ class App implements ApplicationInterface, ConfiguratorInterface {
/** /**
* Detect the WebSocket protocol version a client is using based on the HTTP header request * Detect the WebSocket protocol version a client is using based on the HTTP header request
* @param array of HTTP headers * @param string HTTP handshake request
* @return Version\VersionInterface * @return Version\VersionInterface
* @throws UnderFlowException If we think the entire header message hasn't been buffered yet * @throws UnderFlowException If we think the entire header message hasn't been buffered yet
* @throws InvalidArgumentException If we can't understand protocol version request * @throws InvalidArgumentException If we can't understand protocol version request
* @todo Can/will add more versions later, but perhaps a chain of responsibility, ask each version if they want to handle the request
*/ */
protected function getVersion($message) { protected function getVersion($message) {
if (false === strstr($message, "\r\n\r\n")) { // This CAN fail with Hixie, depending on the TCP buffer in between if (false === strstr($message, "\r\n\r\n")) { // This CAN fail with Hixie, depending on the TCP buffer in between
@ -198,27 +198,33 @@ class App implements ApplicationInterface, ConfiguratorInterface {
$headers = HTTP::getHeaders($message); $headers = HTTP::getHeaders($message);
if (isset($headers['Sec-Websocket-Version'])) { // HyBi foreach ($this->_versions as $name => $instance) {
if ((int)$headers['Sec-Websocket-Version'] >= 6) { if (null !== $instance) {
return $this->versionFactory('HyBi10'); if ($instance::isProtocol($headers)) {
return $instance;
}
} else {
$ns = __NAMESPACE__ . "\\Version\\{$name}";
if ($ns::isProtocol($headers)) {
$this->_version[$name] = new $ns;
return $this->_version[$name];
}
} }
} elseif (isset($headers['Sec-Websocket-Key2'])) { // Hixie
return $this->versionFactory('Hixie76');
} }
throw new \InvalidArgumentException('Could not identify WebSocket protocol'); throw new \InvalidArgumentException('Could not identify WebSocket protocol');
} }
/** /**
* Create and return the instance of a version class * Disable a version of the WebSocket protocol *cough*Hixie76*cough*
* @return Version\VersionInterface * @param string The name of the version to disable
* @throws InvalidArgumentException If the given version does not exist
*/ */
protected function versionFactory($version) { public function disableVersion($name) {
if (null === $this->_versions[$version]) { if (!array_key_exists($name, $this->_versions)) {
$ns = __NAMESPACE__ . "\\Version\\{$version}"; throw new \InvalidArgumentException("Version {$name} not found");
$this->_version[$version] = new $ns;
} }
return $this->_version[$version]; unset($this->_versions[$name]);
} }
} }

View File

@ -14,6 +14,10 @@ namespace Ratchet\Application\WebSocket\Version;
* @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 * @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
*/ */
class Hixie76 implements VersionInterface { class Hixie76 implements VersionInterface {
public static function isProtocol(array $headers) {
return isset($headers['Sec-Websocket-Key2']);
}
/** /**
* @param string * @param string
* @return string * @return string

View File

@ -10,6 +10,19 @@ use Ratchet\Application\WebSocket\Util\HTTP;
class HyBi10 implements VersionInterface { class HyBi10 implements VersionInterface {
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
/**
* @todo When I support later version (that implement extension) change >= 6 to 6 through 10 (or w/e #)
*/
public static function isProtocol(array $headers) {
if (isset($headers['Sec-Websocket-Version'])) {
if ((int)$headers['Sec-Websocket-Version'] >= 6) {
return true;
}
}
return false;
}
/** /**
* @return array * @return array
* 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 * 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

View File

@ -8,6 +8,14 @@ namespace Ratchet\Application\WebSocket\Version;
* The current method names suggest you could create a new message/frame to send, which they can not do * The current method names suggest you could create a new message/frame to send, which they can not do
*/ */
interface VersionInterface { interface VersionInterface {
/**
* Given an HTTP header, determine if this version should handle the protocol
* @param array
* @return bool
* @throws UnderflowException If the protocol thinks the headers are still fragmented
*/
static function isProtocol(array $headers);
/** /**
* Perform the handshake and return the response headers * Perform the handshake and return the response headers
* @param string * @param string
@ -28,6 +36,7 @@ interface VersionInterface {
/** /**
* @param string * @param string
* @return string * @return string
* @todo Change to use other classes, this will be removed eventually
*/ */
function frame($message); function frame($message);
} }