[WebSockets] Handshake encoding + case insensitivity
Updated RFC6455 handshaker to check values case insensitively Made sure RFC6455 handshaker matches encoding properly Added mbstring as a requirement for Ratchet Refs #28, #30
This commit is contained in:
parent
27716fef78
commit
d075b99c26
@ -8,13 +8,14 @@ Build up your application through simple interfaces and re-use your application
|
||||
##WebSocket Compliance
|
||||
|
||||
* Supports the RFC6455, HyBi-10+, and Hixie76 protocol versions (at the same time)
|
||||
* Tested on Chrome 18 - 16, Firefox 6 - 12, Safari 5, iOS 4.2, iOS 5
|
||||
* Tested on Chrome 13 - 19, Firefox 6 - 12, Safari 5.0.1+, iOS 4.2, iOS 5
|
||||
|
||||
##Requirements
|
||||
|
||||
Shell access is required and a dedicated machine with root access is recommended.
|
||||
To avoid proxy/firewall blockage it's recommended WebSockets are run on port 80, which requires root access.
|
||||
Note that you can not run two applications (Apache and Ratchet) on the same port, thus the requirement for a separate machine (for now).
|
||||
PHP 5.3.2 (or higher) is required with mbstring enabled (*--enable-mbstring* flag during compile time). PHP5.4 is recommended for its performance improvements.
|
||||
|
||||
Cookies from your domain will be passed to the socket server, allowing you to identify users.
|
||||
Accessing your website's session data in Ratchet requires you to use [Symfony2 Sessions](http://symfony.com/doc/master/components/http_foundation/sessions.html) on your website.
|
||||
|
@ -21,6 +21,7 @@
|
||||
}
|
||||
, "require": {
|
||||
"php": ">=5.3.2"
|
||||
, "ext-mbstring": "*"
|
||||
, "guzzle/guzzle": "2.5.*"
|
||||
, "symfony/http-foundation": "2.1.*"
|
||||
, "react/socket": "dev-master"
|
||||
|
16
composer.lock
generated
16
composer.lock
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"hash": "cbea4e3e4d74a22ba34d4edf2ce44df3",
|
||||
"hash": "253370657f067dacf104d5fae531f20a",
|
||||
"packages": [
|
||||
{
|
||||
"package": "evenement/evenement",
|
||||
@ -32,13 +32,6 @@
|
||||
"version": "dev-master",
|
||||
"source-reference": "eb82542e8ec9506096caf7c528564c740a214f56"
|
||||
},
|
||||
{
|
||||
"package": "symfony/event-dispatcher",
|
||||
"version": "dev-master",
|
||||
"source-reference": "0b58a4019befc0bd038bc0ec0165101d5dd31754",
|
||||
"alias-pretty-version": "2.1.x-dev",
|
||||
"alias-version": "2.1.9999999.9999999-dev"
|
||||
},
|
||||
{
|
||||
"package": "symfony/http-foundation",
|
||||
"version": "dev-master",
|
||||
@ -50,13 +43,6 @@
|
||||
"package": "symfony/http-foundation",
|
||||
"version": "dev-master",
|
||||
"source-reference": "3d9f4ce435f6322b9720c209ad610202526373c0"
|
||||
},
|
||||
{
|
||||
"package": "symfony/http-foundation",
|
||||
"version": "dev-master",
|
||||
"source-reference": "cf8e8324c68ce584525502702866485f17f1c8a5",
|
||||
"alias-pretty-version": "2.1.x-dev",
|
||||
"alias-version": "2.1.9999999.9999999-dev"
|
||||
}
|
||||
],
|
||||
"packages-dev": null,
|
||||
|
@ -2,12 +2,6 @@
|
||||
namespace Ratchet\WebSocket\Version;
|
||||
|
||||
interface FrameInterface {
|
||||
/**
|
||||
* Dunno if I'll use this
|
||||
* Thinking could be used if a control frame?
|
||||
*/
|
||||
// function __invoke();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -32,10 +32,9 @@ class HandshakeVerifier {
|
||||
* Test the HTTP method. MUST be "GET"
|
||||
* @param string
|
||||
* @return bool
|
||||
* @todo Look into STD if "get" is valid (am I supposed to do case conversion?)
|
||||
*/
|
||||
public function verifyMethod($val) {
|
||||
return ('GET' === $val);
|
||||
return ('get' === mb_strtolower($val, 'ASCII'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,7 +49,6 @@ class HandshakeVerifier {
|
||||
/**
|
||||
* @param string
|
||||
* @return bool
|
||||
* @todo Verify the logic here is correct
|
||||
*/
|
||||
public function verifyRequestURI($val) {
|
||||
if ($val[0] != '/') {
|
||||
@ -80,7 +78,7 @@ class HandshakeVerifier {
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyUpgradeRequest($val) {
|
||||
return ('websocket' === $val);
|
||||
return ('websocket' === mb_strtolower($val, 'ASCII'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,12 +87,16 @@ class HandshakeVerifier {
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyConnection($val) {
|
||||
if ('Upgrade' === $val) {
|
||||
$val = mb_strtolower($val, 'ASCII');
|
||||
|
||||
if ('upgrade' === $val) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// todo change this to mb_eregi_replace
|
||||
$vals = explode(',', str_replace(', ', ',', $val));
|
||||
return (false !== array_search('Upgrade', $vals));
|
||||
|
||||
return (false !== array_search('upgrade', $vals));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,8 @@ class HandshakeVerifierTest extends \PHPUnit_Framework_TestCase {
|
||||
public static function methodProvider() {
|
||||
return array(
|
||||
array(true, 'GET')
|
||||
, array(false, 'get') // I'm not sure if this is valid or not, need to check standard
|
||||
, array(true, 'get')
|
||||
, array(true, 'Get')
|
||||
, array(false, 'POST')
|
||||
, array(false, 'DELETE')
|
||||
, array(false, 'PUT')
|
||||
@ -64,6 +65,7 @@ class HandshakeVerifierTest extends \PHPUnit_Framework_TestCase {
|
||||
, array(false, '/chat#bad')
|
||||
, array(false, 'nope')
|
||||
, array(false, '/ ಠ_ಠ ')
|
||||
, array(false, '/✖')
|
||||
);
|
||||
}
|
||||
|
||||
@ -91,7 +93,8 @@ class HandshakeVerifierTest extends \PHPUnit_Framework_TestCase {
|
||||
public static function upgradeProvider() {
|
||||
return array(
|
||||
array(true, 'websocket')
|
||||
, array(false, 'Websocket')
|
||||
, array(true, 'Websocket')
|
||||
, array(true, 'webSocket')
|
||||
, array(false, null)
|
||||
, array(false, '')
|
||||
);
|
||||
@ -107,7 +110,7 @@ class HandshakeVerifierTest extends \PHPUnit_Framework_TestCase {
|
||||
public static function connectionProvider() {
|
||||
return array(
|
||||
array(true, 'Upgrade')
|
||||
, array(false, 'upgrade')
|
||||
, array(true, 'upgrade')
|
||||
, array(true, 'keep-alive, Upgrade')
|
||||
, array(true, 'Upgrade, keep-alive')
|
||||
, array(true, 'keep-alive, Upgrade, something')
|
||||
@ -133,6 +136,8 @@ class HandshakeVerifierTest extends \PHPUnit_Framework_TestCase {
|
||||
, array(false, 'Hello World')
|
||||
, array(false, '1234567890123456')
|
||||
, array(false, '123456789012345678901234')
|
||||
, array(true, base64_encode('UTF8allthngs+✓'))
|
||||
, array(true, 'dGhlIHNhbXBsZSBub25jZQ==')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3,33 +3,26 @@ namespace Ratchet\Tests\WebSocket\Version;
|
||||
use Ratchet\WebSocket\Version\RFC6455;
|
||||
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
||||
use Guzzle\Http\Message\RequestFactory;
|
||||
use Guzzle\Http\Message\EntityEnclosingRequest;
|
||||
|
||||
/**
|
||||
* @covers Ratchet\WebSocket\Version\RFC6455
|
||||
*/
|
||||
class RFC6455Test extends \PHPUnit_Framework_TestCase {
|
||||
protected $_version;
|
||||
protected $version;
|
||||
|
||||
public function setUp() {
|
||||
$this->_version = new RFC6455();
|
||||
$this->version = new RFC6455;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this useful?
|
||||
*/
|
||||
public function testClassImplementsVersionInterface() {
|
||||
$constraint = $this->isInstanceOf('\\Ratchet\\WebSocket\\Version\\VersionInterface');
|
||||
$this->assertThat($this->_version, $constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider HandshakeProvider
|
||||
* @dataProvider handshakeProvider
|
||||
*/
|
||||
public function testKeySigningForHandshake($key, $accept) {
|
||||
$this->assertEquals($accept, $this->_version->sign($key));
|
||||
$this->assertEquals($accept, $this->version->sign($key));
|
||||
}
|
||||
|
||||
public static function HandshakeProvider() {
|
||||
public static function handshakeProvider() {
|
||||
return array(
|
||||
array('x3JJHMbDL1EzLkh9GBhXDw==', 'HSmrc0sMlYUkAGmm5OPpG2HaGWk=')
|
||||
, array('dGhlIHNhbXBsZSBub25jZQ==', 's3pPLMBiTxaQ9kYGzzhZRbK+xOo=')
|
||||
@ -56,8 +49,8 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
public function testUnframeMatchesPreFraming() {
|
||||
$string = 'Hello World!';
|
||||
$framed = $this->_version->frame($string);
|
||||
$string = 'Hello World!';
|
||||
$framed = $this->version->frame($string);
|
||||
|
||||
$frame = new Frame;
|
||||
$frame->addBuffer($framed);
|
||||
@ -77,6 +70,26 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase {
|
||||
, 'Sec-WebSocket-Version' => 13
|
||||
);
|
||||
|
||||
public function caseVariantProvider() {
|
||||
return array(
|
||||
array('Sec-Websocket-Version')
|
||||
, array('sec-websocket-version')
|
||||
, array('SEC-WEBSOCKET-VERSION')
|
||||
, array('sEC-wEBsOCKET-vERSION')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider caseVariantProvider
|
||||
*/
|
||||
public function testIsProtocolWithCaseInsensitivity($headerName) {
|
||||
$header = static::$good_header;
|
||||
unset($header['Sec-WebSocket-Version']);
|
||||
$header[$headerName] = 13;
|
||||
|
||||
$this->assertTrue($this->version->isProtocol(new EntityEnclosingRequest('get', '/', $header)));
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to try and quickly put together a valid WebSocket HTTP handshake
|
||||
* but optionally replace a piece to an invalid value for failure testing
|
||||
@ -119,18 +132,18 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase {
|
||||
$request = RequestFactory::getInstance()->fromMessage($header);
|
||||
|
||||
if ($pass) {
|
||||
$this->assertInstanceOf('\\Guzzle\\Http\\Message\\Response', $this->_version->handshake($request));
|
||||
$this->assertInstanceOf('\\Guzzle\\Http\\Message\\Response', $this->version->handshake($request));
|
||||
} else {
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$this->_version->handshake($request);
|
||||
$this->version->handshake($request);
|
||||
}
|
||||
}
|
||||
|
||||
public function testNewMessage() {
|
||||
$this->assertInstanceOf('\\Ratchet\\WebSocket\\Version\\RFC6455\\Message', $this->_version->newMessage());
|
||||
$this->assertInstanceOf('\\Ratchet\\WebSocket\\Version\\RFC6455\\Message', $this->version->newMessage());
|
||||
}
|
||||
|
||||
public function testNewFrame() {
|
||||
$this->assertInstanceOf('\\Ratchet\\WebSocket\\Version\\RFC6455\\Frame', $this->_version->newFrame());
|
||||
$this->assertInstanceOf('\\Ratchet\\WebSocket\\Version\\RFC6455\\Frame', $this->version->newFrame());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user