diff --git a/CHANGELOG.md b/CHANGELOG.md index aac7b5f..6066d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,14 @@ CHANGELOG * BC: Decoupled HTTP from WebSocket component -> Ratchet\Http\HttpServer * 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) * Fixed Hixie-76 handshake bug diff --git a/README.md b/README.md index 767e45c..8de8cc1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 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 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) ##Requirements diff --git a/composer.json b/composer.json index 89eec01..a790d55 100644 --- a/composer.json +++ b/composer.json @@ -26,8 +26,8 @@ } , "require": { "php": ">=5.3.9" - , "react/socket": "~0.2" - , "guzzle/http": "~3.0" + , "react/socket": "0.3.*" + , "guzzle/http": "3.6.*" , "symfony/http-foundation": "~2.2" , "symfony/routing": "~2.2" } diff --git a/composer.lock b/composer.lock index f49c13e..a803718 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "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" ], - "hash": "6006ea344879ef78bf1a490e630a74fc", + "hash": "d5a238bcdccc33fab13dd3c65b663beb", "packages": [ { "name": "evenement/evenement", @@ -47,17 +47,17 @@ }, { "name": "guzzle/common", - "version": "v3.4.3", + "version": "v3.6.0", "target-dir": "Guzzle/Common", "source": { "type": "git", "url": "https://github.com/guzzle/common.git", - "reference": "v3.4.3" + "reference": "v3.6.0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/common/zipball/v3.4.3", - "reference": "v3.4.3", + "url": "https://api.github.com/repos/guzzle/common/zipball/v3.6.0", + "reference": "v3.6.0", "shasum": "" }, "require": { @@ -67,7 +67,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -87,21 +87,21 @@ "event", "exception" ], - "time": "2013-04-30 20:30:19" + "time": "2013-05-30 07:01:25" }, { "name": "guzzle/http", - "version": "v3.4.3", + "version": "v3.6.0", "target-dir": "Guzzle/Http", "source": { "type": "git", "url": "https://github.com/guzzle/http.git", - "reference": "v3.4.3" + "reference": "v3.6.0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/http/zipball/v3.4.3", - "reference": "v3.4.3", + "url": "https://api.github.com/repos/guzzle/http/zipball/v3.6.0", + "reference": "v3.6.0", "shasum": "" }, "require": { @@ -116,7 +116,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -144,21 +144,21 @@ "http", "http client" ], - "time": "2013-04-30 20:30:19" + "time": "2013-05-30 07:01:25" }, { "name": "guzzle/parser", - "version": "v3.4.3", + "version": "v3.6.0", "target-dir": "Guzzle/Parser", "source": { "type": "git", "url": "https://github.com/guzzle/parser.git", - "reference": "v3.4.3" + "reference": "v3.6.0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.4.3", - "reference": "v3.4.3", + "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.6.0", + "reference": "v3.6.0", "shasum": "" }, "require": { @@ -167,7 +167,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -188,21 +188,21 @@ "message", "url" ], - "time": "2013-04-26 15:47:38" + "time": "2013-05-30 07:01:25" }, { "name": "guzzle/stream", - "version": "v3.4.3", + "version": "v3.6.0", "target-dir": "Guzzle/Stream", "source": { "type": "git", "url": "https://github.com/guzzle/stream.git", - "reference": "v3.4.3" + "reference": "v3.6.0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.4.3", - "reference": "v3.4.3", + "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.6.0", + "reference": "v3.6.0", "shasum": "" }, "require": { @@ -215,7 +215,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -241,21 +241,21 @@ "component", "stream" ], - "time": "2013-04-26 15:47:38" + "time": "2013-05-30 07:01:25" }, { "name": "react/event-loop", - "version": "v0.3.1", + "version": "v0.3.2", "target-dir": "React/EventLoop", "source": { "type": "git", "url": "https://github.com/reactphp/event-loop.git", - "reference": "v0.3.1" + "reference": "v0.3.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/v0.3.1", - "reference": "v0.3.1", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/v0.3.2", + "reference": "v0.3.2", "shasum": "" }, "require": { @@ -288,17 +288,17 @@ }, { "name": "react/socket", - "version": "v0.3.1", + "version": "v0.3.2", "target-dir": "React/Socket", "source": { "type": "git", "url": "https://github.com/reactphp/socket.git", - "reference": "v0.3.1" + "reference": "v0.3.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/v0.3.1", - "reference": "v0.3.1", + "url": "https://api.github.com/repos/reactphp/socket/zipball/v0.3.2", + "reference": "v0.3.2", "shasum": "" }, "require": { @@ -326,21 +326,21 @@ "keywords": [ "Socket" ], - "time": "2013-04-20 14:53:10" + "time": "2013-04-26 20:23:10" }, { "name": "react/stream", - "version": "v0.3.1", + "version": "v0.3.2", "target-dir": "React/Stream", "source": { "type": "git", "url": "https://github.com/reactphp/stream.git", - "reference": "v0.3.1" + "reference": "v0.3.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/stream/zipball/v0.3.1", - "reference": "v0.3.1", + "url": "https://api.github.com/repos/reactphp/stream/zipball/v0.3.2", + "reference": "v0.3.2", "shasum": "" }, "require": { @@ -371,21 +371,21 @@ "pipe", "stream" ], - "time": "2013-04-21 13:25:49" + "time": "2013-05-10 15:12:22" }, { "name": "symfony/event-dispatcher", - "version": "v2.2.1", + "version": "v2.3.0", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "v2.2.1" + "reference": "v2.3.0-RC1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.0-RC1", + "reference": "v2.3.0-RC1", "shasum": "" }, "require": { @@ -395,13 +395,13 @@ "symfony/dependency-injection": ">=2.0,<3.0" }, "suggest": { - "symfony/dependency-injection": "2.2.*", - "symfony/http-kernel": "2.2.*" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -425,21 +425,21 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "http://symfony.com", - "time": "2013-02-11 11:26:43" + "time": "2013-05-13 14:36:40" }, { "name": "symfony/http-foundation", - "version": "v2.2.1", + "version": "v2.3.0", "target-dir": "Symfony/Component/HttpFoundation", "source": { "type": "git", "url": "https://github.com/symfony/HttpFoundation.git", - "reference": "v2.2.1" + "reference": "v2.3.0-RC1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.3.0-RC1", + "reference": "v2.3.0-RC1", "shasum": "" }, "require": { @@ -448,7 +448,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -475,21 +475,21 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "http://symfony.com", - "time": "2013-04-06 10:15:43" + "time": "2013-05-10 06:00:03" }, { "name": "symfony/routing", - "version": "v2.2.1", + "version": "v2.3.0", "target-dir": "Symfony/Component/Routing", "source": { "type": "git", "url": "https://github.com/symfony/Routing.git", - "reference": "v2.2.1" + "reference": "v2.3.0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.0", + "reference": "v2.3.0", "shasum": "" }, "require": { @@ -498,18 +498,18 @@ "require-dev": { "doctrine/common": ">=2.2,<3.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" }, "suggest": { - "doctrine/common": "~2.2", - "symfony/config": "2.2.*", - "symfony/yaml": "2.2.*" + "doctrine/common": "", + "symfony/config": "", + "symfony/yaml": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -533,7 +533,7 @@ ], "description": "Symfony Routing Component", "homepage": "http://symfony.com", - "time": "2013-03-23 12:03:22" + "time": "2013-05-20 08:57:26" } ], "packages-dev": [ diff --git a/src/Ratchet/Http/Guzzle/Http/Message/RequestFactory.php b/src/Ratchet/Http/Guzzle/Http/Message/RequestFactory.php index 0ebcc35..abf8aac 100644 --- a/src/Ratchet/Http/Guzzle/Http/Message/RequestFactory.php +++ b/src/Ratchet/Http/Guzzle/Http/Message/RequestFactory.php @@ -7,7 +7,7 @@ class RequestFactory extends GuzzleRequestFactory { /** * {@inheritdoc} */ - public function create($method, $url, $headers = null, $body = '') { + public function create($method, $url, $headers = null, $body = '', array $options = array()) { $c = $this->entityEnclosingRequestClass; $request = new $c($method, $url, $headers); $request->setBody(EntityBody::factory($body)); diff --git a/src/Ratchet/WebSocket/Version/Hixie76.php b/src/Ratchet/WebSocket/Version/Hixie76.php index 069263a..8b0e2c4 100644 --- a/src/Ratchet/WebSocket/Version/Hixie76.php +++ b/src/Ratchet/WebSocket/Version/Hixie76.php @@ -23,7 +23,7 @@ class Hixie76 implements VersionInterface { * {@inheritdoc} */ 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"); } - $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( 'Upgrade' => 'WebSocket' , 'Connection' => 'Upgrade' - , 'Sec-WebSocket-Origin' => $request->getHeader('Origin', true) - , 'Sec-WebSocket-Location' => 'ws://' . $request->getHeader('Host', true) . $request->getPath() + , 'Sec-WebSocket-Origin' => (string)$request->getHeader('Origin') + , 'Sec-WebSocket-Location' => 'ws://' . (string)$request->getHeader('Host') . $request->getPath() ); $response = new Response(101, $headers, $challenge); diff --git a/src/Ratchet/WebSocket/Version/HyBi10.php b/src/Ratchet/WebSocket/Version/HyBi10.php index 5d89078..70329c6 100644 --- a/src/Ratchet/WebSocket/Version/HyBi10.php +++ b/src/Ratchet/WebSocket/Version/HyBi10.php @@ -4,7 +4,7 @@ use Guzzle\Http\Message\RequestInterface; class HyBi10 extends RFC6455 { 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); } diff --git a/src/Ratchet/WebSocket/Version/RFC6455.php b/src/Ratchet/WebSocket/Version/RFC6455.php index 22a96a0..23e166c 100644 --- a/src/Ratchet/WebSocket/Version/RFC6455.php +++ b/src/Ratchet/WebSocket/Version/RFC6455.php @@ -50,7 +50,7 @@ class RFC6455 implements VersionInterface { * {@inheritdoc} */ 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); } @@ -73,7 +73,7 @@ class RFC6455 implements VersionInterface { return new Response(101, array( 'Upgrade' => 'websocket' , '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_TLS] = true; } -} \ No newline at end of file +} diff --git a/src/Ratchet/WebSocket/Version/RFC6455/HandshakeVerifier.php b/src/Ratchet/WebSocket/Version/RFC6455/HandshakeVerifier.php index ea17d08..41057cc 100644 --- a/src/Ratchet/WebSocket/Version/RFC6455/HandshakeVerifier.php +++ b/src/Ratchet/WebSocket/Version/RFC6455/HandshakeVerifier.php @@ -19,10 +19,10 @@ class HandshakeVerifier { $passes += (int)$this->verifyMethod($request->getMethod()); $passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion()); $passes += (int)$this->verifyRequestURI($request->getPath()); - $passes += (int)$this->verifyHost($request->getHeader('Host', true)); - $passes += (int)$this->verifyUpgradeRequest($request->getHeader('Upgrade', true)); - $passes += (int)$this->verifyConnection($request->getHeader('Connection', true)); - $passes += (int)$this->verifyKey($request->getHeader('Sec-WebSocket-Key', true)); + $passes += (int)$this->verifyHost((string)$request->getHeader('Host')); + $passes += (int)$this->verifyUpgradeRequest((string)$request->getHeader('Upgrade')); + $passes += (int)$this->verifyConnection((string)$request->getHeader('Connection')); + $passes += (int)$this->verifyKey((string)$request->getHeader('Sec-WebSocket-Key')); //$passes += (int)$this->verifyVersion($headers['Sec-WebSocket-Version']); // Temporarily breaking functionality return (7 === $passes); diff --git a/src/Ratchet/WebSocket/WsServer.php b/src/Ratchet/WebSocket/WsServer.php index 0373a14..460e328 100644 --- a/src/Ratchet/WebSocket/WsServer.php +++ b/src/Ratchet/WebSocket/WsServer.php @@ -111,8 +111,10 @@ class WsServer implements HttpServerInterface { return; } - if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($conn->WebSocket->request->getTokenizedHeader('Sec-WebSocket-Protocol', ',')))) { - $response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols); + if (null !== ($subHeader = $conn->WebSocket->request->getHeader('Sec-WebSocket-Protocol'))) { + if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($subHeader->normalize()))) { + $response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols); + } } $response->setHeader('X-Powered-By', \Ratchet\VERSION); diff --git a/tests/Ratchet/Tests/Session/SessionComponentTest.php b/tests/Ratchet/Tests/Session/SessionComponentTest.php index b97d273..a411eb1 100644 --- a/tests/Ratchet/Tests/Session/SessionComponentTest.php +++ b/tests/Ratchet/Tests/Session/SessionComponentTest.php @@ -75,6 +75,7 @@ class SessionProviderTest extends AbstractMessageComponentTestCase { ); $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->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()));