Merge branch 'refs/heads/master' (v0.2.7) into 0.3

Conflicts:
	CHANGELOG.md
	composer.json
	composer.lock
	src/Ratchet/ConnectionInterface.php
	src/Ratchet/WebSocket/Version/HyBi10.php
	src/Ratchet/WebSocket/Version/RFC6455.php
	src/Ratchet/WebSocket/WsServer.php
This commit is contained in:
Chris Boden 2013-06-09 11:53:18 -04:00
commit 40f267834a
11 changed files with 92 additions and 81 deletions

View File

@ -15,6 +15,14 @@ CHANGELOG
* BC: Decoupled HTTP from WebSocket component -> Ratchet\Http\HttpServer * BC: Decoupled HTTP from WebSocket component -> Ratchet\Http\HttpServer
* Updated dependency to React/0.3 * Updated dependency to React/0.3
* 0.2.7 (2013-06-09)
* BF: Sub-protocol negotation with Guzzle 3.6
* 0.2.6 (2013-06-01)
* Guzzle 3.6 support
* 0.2.5 (2013-04-01) * 0.2.5 (2013-04-01)
* Fixed Hixie-76 handshake bug * Fixed Hixie-76 handshake bug

View File

@ -8,7 +8,7 @@ Build up your application through simple interfaces and re-use your application
##WebSocket Compliance ##WebSocket Compliance
* Supports the RFC6455, HyBi-10+, and Hixie76 protocol versions (at the same time) * Supports the RFC6455, HyBi-10+, and Hixie76 protocol versions (at the same time)
* Tested on Chrome 13 - 26, Firefox 6 - 20, Safari 5.0.1 - 6, iOS 4.2 - 6 * Tested on Chrome 13 - 27, Firefox 6 - 21, Safari 5.0.1 - 6, iOS 4.2 - 6
* Ratchet [passes](http://socketo.me/reports/ab/) the [Autobahn Testsuite](http://autobahn.ws/testsuite) (non-binary messages) * Ratchet [passes](http://socketo.me/reports/ab/) the [Autobahn Testsuite](http://autobahn.ws/testsuite) (non-binary messages)
##Requirements ##Requirements

View File

@ -26,8 +26,8 @@
} }
, "require": { , "require": {
"php": ">=5.3.9" "php": ">=5.3.9"
, "react/socket": "~0.2" , "react/socket": "0.3.*"
, "guzzle/http": "~3.0" , "guzzle/http": "3.6.*"
, "symfony/http-foundation": "~2.2" , "symfony/http-foundation": "~2.2"
, "symfony/routing": "~2.2" , "symfony/routing": "~2.2"
} }

126
composer.lock generated
View File

@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
], ],
"hash": "6006ea344879ef78bf1a490e630a74fc", "hash": "d5a238bcdccc33fab13dd3c65b663beb",
"packages": [ "packages": [
{ {
"name": "evenement/evenement", "name": "evenement/evenement",
@ -47,17 +47,17 @@
}, },
{ {
"name": "guzzle/common", "name": "guzzle/common",
"version": "v3.4.3", "version": "v3.6.0",
"target-dir": "Guzzle/Common", "target-dir": "Guzzle/Common",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/common.git", "url": "https://github.com/guzzle/common.git",
"reference": "v3.4.3" "reference": "v3.6.0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/common/zipball/v3.4.3", "url": "https://api.github.com/repos/guzzle/common/zipball/v3.6.0",
"reference": "v3.4.3", "reference": "v3.6.0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -67,7 +67,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.4-dev" "dev-master": "3.6-dev"
} }
}, },
"autoload": { "autoload": {
@ -87,21 +87,21 @@
"event", "event",
"exception" "exception"
], ],
"time": "2013-04-30 20:30:19" "time": "2013-05-30 07:01:25"
}, },
{ {
"name": "guzzle/http", "name": "guzzle/http",
"version": "v3.4.3", "version": "v3.6.0",
"target-dir": "Guzzle/Http", "target-dir": "Guzzle/Http",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/http.git", "url": "https://github.com/guzzle/http.git",
"reference": "v3.4.3" "reference": "v3.6.0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/http/zipball/v3.4.3", "url": "https://api.github.com/repos/guzzle/http/zipball/v3.6.0",
"reference": "v3.4.3", "reference": "v3.6.0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -116,7 +116,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.4-dev" "dev-master": "3.6-dev"
} }
}, },
"autoload": { "autoload": {
@ -144,21 +144,21 @@
"http", "http",
"http client" "http client"
], ],
"time": "2013-04-30 20:30:19" "time": "2013-05-30 07:01:25"
}, },
{ {
"name": "guzzle/parser", "name": "guzzle/parser",
"version": "v3.4.3", "version": "v3.6.0",
"target-dir": "Guzzle/Parser", "target-dir": "Guzzle/Parser",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/parser.git", "url": "https://github.com/guzzle/parser.git",
"reference": "v3.4.3" "reference": "v3.6.0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/parser/zipball/v3.4.3", "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.6.0",
"reference": "v3.4.3", "reference": "v3.6.0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -167,7 +167,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.4-dev" "dev-master": "3.6-dev"
} }
}, },
"autoload": { "autoload": {
@ -188,21 +188,21 @@
"message", "message",
"url" "url"
], ],
"time": "2013-04-26 15:47:38" "time": "2013-05-30 07:01:25"
}, },
{ {
"name": "guzzle/stream", "name": "guzzle/stream",
"version": "v3.4.3", "version": "v3.6.0",
"target-dir": "Guzzle/Stream", "target-dir": "Guzzle/Stream",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/stream.git", "url": "https://github.com/guzzle/stream.git",
"reference": "v3.4.3" "reference": "v3.6.0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/stream/zipball/v3.4.3", "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.6.0",
"reference": "v3.4.3", "reference": "v3.6.0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -215,7 +215,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.4-dev" "dev-master": "3.6-dev"
} }
}, },
"autoload": { "autoload": {
@ -241,21 +241,21 @@
"component", "component",
"stream" "stream"
], ],
"time": "2013-04-26 15:47:38" "time": "2013-05-30 07:01:25"
}, },
{ {
"name": "react/event-loop", "name": "react/event-loop",
"version": "v0.3.1", "version": "v0.3.2",
"target-dir": "React/EventLoop", "target-dir": "React/EventLoop",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/reactphp/event-loop.git", "url": "https://github.com/reactphp/event-loop.git",
"reference": "v0.3.1" "reference": "v0.3.2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/reactphp/event-loop/zipball/v0.3.1", "url": "https://api.github.com/repos/reactphp/event-loop/zipball/v0.3.2",
"reference": "v0.3.1", "reference": "v0.3.2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -288,17 +288,17 @@
}, },
{ {
"name": "react/socket", "name": "react/socket",
"version": "v0.3.1", "version": "v0.3.2",
"target-dir": "React/Socket", "target-dir": "React/Socket",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/reactphp/socket.git", "url": "https://github.com/reactphp/socket.git",
"reference": "v0.3.1" "reference": "v0.3.2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/reactphp/socket/zipball/v0.3.1", "url": "https://api.github.com/repos/reactphp/socket/zipball/v0.3.2",
"reference": "v0.3.1", "reference": "v0.3.2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -326,21 +326,21 @@
"keywords": [ "keywords": [
"Socket" "Socket"
], ],
"time": "2013-04-20 14:53:10" "time": "2013-04-26 20:23:10"
}, },
{ {
"name": "react/stream", "name": "react/stream",
"version": "v0.3.1", "version": "v0.3.2",
"target-dir": "React/Stream", "target-dir": "React/Stream",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/reactphp/stream.git", "url": "https://github.com/reactphp/stream.git",
"reference": "v0.3.1" "reference": "v0.3.2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/reactphp/stream/zipball/v0.3.1", "url": "https://api.github.com/repos/reactphp/stream/zipball/v0.3.2",
"reference": "v0.3.1", "reference": "v0.3.2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -371,21 +371,21 @@
"pipe", "pipe",
"stream" "stream"
], ],
"time": "2013-04-21 13:25:49" "time": "2013-05-10 15:12:22"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v2.2.1", "version": "v2.3.0",
"target-dir": "Symfony/Component/EventDispatcher", "target-dir": "Symfony/Component/EventDispatcher",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/EventDispatcher.git", "url": "https://github.com/symfony/EventDispatcher.git",
"reference": "v2.2.1" "reference": "v2.3.0-RC1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.1", "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.0-RC1",
"reference": "v2.2.1", "reference": "v2.3.0-RC1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -395,13 +395,13 @@
"symfony/dependency-injection": ">=2.0,<3.0" "symfony/dependency-injection": ">=2.0,<3.0"
}, },
"suggest": { "suggest": {
"symfony/dependency-injection": "2.2.*", "symfony/dependency-injection": "",
"symfony/http-kernel": "2.2.*" "symfony/http-kernel": ""
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-master": "2.3-dev"
} }
}, },
"autoload": { "autoload": {
@ -425,21 +425,21 @@
], ],
"description": "Symfony EventDispatcher Component", "description": "Symfony EventDispatcher Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2013-02-11 11:26:43" "time": "2013-05-13 14:36:40"
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
"version": "v2.2.1", "version": "v2.3.0",
"target-dir": "Symfony/Component/HttpFoundation", "target-dir": "Symfony/Component/HttpFoundation",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/HttpFoundation.git", "url": "https://github.com/symfony/HttpFoundation.git",
"reference": "v2.2.1" "reference": "v2.3.0-RC1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.2.1", "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.3.0-RC1",
"reference": "v2.2.1", "reference": "v2.3.0-RC1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -448,7 +448,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-master": "2.3-dev"
} }
}, },
"autoload": { "autoload": {
@ -475,21 +475,21 @@
], ],
"description": "Symfony HttpFoundation Component", "description": "Symfony HttpFoundation Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2013-04-06 10:15:43" "time": "2013-05-10 06:00:03"
}, },
{ {
"name": "symfony/routing", "name": "symfony/routing",
"version": "v2.2.1", "version": "v2.3.0",
"target-dir": "Symfony/Component/Routing", "target-dir": "Symfony/Component/Routing",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/Routing.git", "url": "https://github.com/symfony/Routing.git",
"reference": "v2.2.1" "reference": "v2.3.0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/Routing/zipball/v2.2.1", "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.0",
"reference": "v2.2.1", "reference": "v2.3.0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -498,18 +498,18 @@
"require-dev": { "require-dev": {
"doctrine/common": ">=2.2,<3.0", "doctrine/common": ">=2.2,<3.0",
"psr/log": ">=1.0,<2.0", "psr/log": ">=1.0,<2.0",
"symfony/config": ">=2.2,<2.3-dev", "symfony/config": ">=2.2,<3.0",
"symfony/yaml": ">=2.0,<3.0" "symfony/yaml": ">=2.0,<3.0"
}, },
"suggest": { "suggest": {
"doctrine/common": "~2.2", "doctrine/common": "",
"symfony/config": "2.2.*", "symfony/config": "",
"symfony/yaml": "2.2.*" "symfony/yaml": ""
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-master": "2.3-dev"
} }
}, },
"autoload": { "autoload": {
@ -533,7 +533,7 @@
], ],
"description": "Symfony Routing Component", "description": "Symfony Routing Component",
"homepage": "http://symfony.com", "homepage": "http://symfony.com",
"time": "2013-03-23 12:03:22" "time": "2013-05-20 08:57:26"
} }
], ],
"packages-dev": [ "packages-dev": [

View File

@ -7,7 +7,7 @@ class RequestFactory extends GuzzleRequestFactory {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function create($method, $url, $headers = null, $body = '') { public function create($method, $url, $headers = null, $body = '', array $options = array()) {
$c = $this->entityEnclosingRequestClass; $c = $this->entityEnclosingRequestClass;
$request = new $c($method, $url, $headers); $request = new $c($method, $url, $headers);
$request->setBody(EntityBody::factory($body)); $request->setBody(EntityBody::factory($body));

View File

@ -23,7 +23,7 @@ class Hixie76 implements VersionInterface {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isProtocol(RequestInterface $request) { public function isProtocol(RequestInterface $request) {
return !(null === $request->getHeader('Sec-WebSocket-Key2', true)); return !(null === $request->getHeader('Sec-WebSocket-Key2'));
} }
/** /**
@ -44,13 +44,13 @@ class Hixie76 implements VersionInterface {
throw new \UnderflowException("Not enough data received to issue challenge response"); throw new \UnderflowException("Not enough data received to issue challenge response");
} }
$challenge = $this->sign($request->getHeader('Sec-WebSocket-Key1', true), $request->getHeader('Sec-WebSocket-Key2', true), $body); $challenge = $this->sign((string)$request->getHeader('Sec-WebSocket-Key1'), (string)$request->getHeader('Sec-WebSocket-Key2'), $body);
$headers = array( $headers = array(
'Upgrade' => 'WebSocket' 'Upgrade' => 'WebSocket'
, 'Connection' => 'Upgrade' , 'Connection' => 'Upgrade'
, 'Sec-WebSocket-Origin' => $request->getHeader('Origin', true) , 'Sec-WebSocket-Origin' => (string)$request->getHeader('Origin')
, 'Sec-WebSocket-Location' => 'ws://' . $request->getHeader('Host', true) . $request->getPath() , 'Sec-WebSocket-Location' => 'ws://' . (string)$request->getHeader('Host') . $request->getPath()
); );
$response = new Response(101, $headers, $challenge); $response = new Response(101, $headers, $challenge);

View File

@ -4,7 +4,7 @@ use Guzzle\Http\Message\RequestInterface;
class HyBi10 extends RFC6455 { class HyBi10 extends RFC6455 {
public function isProtocol(RequestInterface $request) { public function isProtocol(RequestInterface $request) {
$version = $request->hasHeader('Sec-WebSocket-Version') ? (int)$request->getHeader('Sec-WebSocket-Version', true) : -1; $version = (int)(string)$request->getHeader('Sec-WebSocket-Version');
return ($version >= 6 && $version < 13); return ($version >= 6 && $version < 13);
} }

View File

@ -50,7 +50,7 @@ class RFC6455 implements VersionInterface {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isProtocol(RequestInterface $request) { public function isProtocol(RequestInterface $request) {
$version = $request->hasHeader('Sec-WebSocket-Version') ? (int)$request->getHeader('Sec-WebSocket-Version', true) : -1; $version = (int)(string)$request->getHeader('Sec-WebSocket-Version');
return ($this->getVersionNumber() === $version); return ($this->getVersionNumber() === $version);
} }
@ -73,7 +73,7 @@ class RFC6455 implements VersionInterface {
return new Response(101, array( return new Response(101, array(
'Upgrade' => 'websocket' 'Upgrade' => 'websocket'
, 'Connection' => 'Upgrade' , 'Connection' => 'Upgrade'
, 'Sec-WebSocket-Accept' => $this->sign($request->getHeader('Sec-WebSocket-Key', true)) , 'Sec-WebSocket-Accept' => $this->sign((string)$request->getHeader('Sec-WebSocket-Key'))
)); ));
} }
@ -268,4 +268,4 @@ class RFC6455 implements VersionInterface {
$this->closeCodes[Frame::CLOSE_SRV_ERR] = true; $this->closeCodes[Frame::CLOSE_SRV_ERR] = true;
//$this->closeCodes[Frame::CLOSE_TLS] = true; //$this->closeCodes[Frame::CLOSE_TLS] = true;
} }
} }

View File

@ -19,10 +19,10 @@ class HandshakeVerifier {
$passes += (int)$this->verifyMethod($request->getMethod()); $passes += (int)$this->verifyMethod($request->getMethod());
$passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion()); $passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion());
$passes += (int)$this->verifyRequestURI($request->getPath()); $passes += (int)$this->verifyRequestURI($request->getPath());
$passes += (int)$this->verifyHost($request->getHeader('Host', true)); $passes += (int)$this->verifyHost((string)$request->getHeader('Host'));
$passes += (int)$this->verifyUpgradeRequest($request->getHeader('Upgrade', true)); $passes += (int)$this->verifyUpgradeRequest((string)$request->getHeader('Upgrade'));
$passes += (int)$this->verifyConnection($request->getHeader('Connection', true)); $passes += (int)$this->verifyConnection((string)$request->getHeader('Connection'));
$passes += (int)$this->verifyKey($request->getHeader('Sec-WebSocket-Key', true)); $passes += (int)$this->verifyKey((string)$request->getHeader('Sec-WebSocket-Key'));
//$passes += (int)$this->verifyVersion($headers['Sec-WebSocket-Version']); // Temporarily breaking functionality //$passes += (int)$this->verifyVersion($headers['Sec-WebSocket-Version']); // Temporarily breaking functionality
return (7 === $passes); return (7 === $passes);

View File

@ -111,8 +111,10 @@ class WsServer implements HttpServerInterface {
return; return;
} }
if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($conn->WebSocket->request->getTokenizedHeader('Sec-WebSocket-Protocol', ',')))) { if (null !== ($subHeader = $conn->WebSocket->request->getHeader('Sec-WebSocket-Protocol'))) {
$response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols); if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($subHeader->normalize()))) {
$response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols);
}
} }
$response->setHeader('X-Powered-By', \Ratchet\VERSION); $response->setHeader('X-Powered-By', \Ratchet\VERSION);

View File

@ -75,6 +75,7 @@ class SessionProviderTest extends AbstractMessageComponentTestCase {
); );
$pdo = new \PDO("sqlite::memory:"); $pdo = new \PDO("sqlite::memory:");
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->exec(vsprintf("CREATE TABLE %s (%s VARCHAR(255) PRIMARY KEY, %s TEXT, %s INTEGER)", $dbOptions)); $pdo->exec(vsprintf("CREATE TABLE %s (%s VARCHAR(255) PRIMARY KEY, %s TEXT, %s INTEGER)", $dbOptions));
$pdo->prepare(vsprintf("INSERT INTO %s (%s, %s, %s) VALUES (?, ?, ?)", $dbOptions))->execute(array($sessionId, base64_encode('_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}'), time())); $pdo->prepare(vsprintf("INSERT INTO %s (%s, %s, %s) VALUES (?, ?, ?)", $dbOptions))->execute(array($sessionId, base64_encode('_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}'), time()));