Merge branch 'refs/heads/0.3'
This commit is contained in:
commit
d756e0b507
@ -1,9 +1,9 @@
|
|||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 5.3.3
|
|
||||||
- 5.3
|
- 5.3
|
||||||
- 5.4
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- curl -s http://getcomposer.org/installer | php
|
- curl -s http://getcomposer.org/installer | php
|
||||||
|
@ -8,6 +8,15 @@ CHANGELOG
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
* 0.3.0 (2013-10-14)
|
||||||
|
|
||||||
|
* Added the `App` class to help making Ratchet so easy to use it's silly
|
||||||
|
* BC: Require hostname to do HTTP Host header match and do Origin HTTP header check, verify same name by default, helping prevent CSRF attacks
|
||||||
|
* Added Symfony/2.2 based HTTP Router component to allowing for a single Ratchet server to handle multiple apps -> Ratchet\Http\Router
|
||||||
|
* BC: Decoupled HTTP from WebSocket component -> Ratchet\Http\HttpServer
|
||||||
|
* BF: Single sub-protocol selection to conform with RFC6455
|
||||||
|
* BF: Sanity checks on WAMP protocol to prevent errors
|
||||||
|
|
||||||
* 0.2.8 (2013-09-19)
|
* 0.2.8 (2013-09-19)
|
||||||
|
|
||||||
* React 0.3 support
|
* React 0.3 support
|
||||||
|
19
Makefile
19
Makefile
@ -8,23 +8,21 @@ cover:
|
|||||||
phpunit --coverage-text --coverage-html=reports/coverage
|
phpunit --coverage-text --coverage-html=reports/coverage
|
||||||
|
|
||||||
abtests:
|
abtests:
|
||||||
ulimit -n 2048 && php tests/AutobahnTestSuite/bin/fuzzingserver-libevent.php 8002 &
|
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver-libevent.php 8001 &
|
||||||
ulimit -n 2048 && php tests/AutobahnTestSuite/bin/fuzzingserver-stream.php 8001 &
|
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver-stream.php 8002 &
|
||||||
ulimit -n 2048 && php tests/AutobahnTestSuite/bin/fuzzingserver-libev.php 8004 &
|
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver-noutf8.php 8003 &
|
||||||
ulimit -n 2048 && php tests/AutobahnTestSuite/bin/fuzzingserver-libuv.php 8005 &
|
|
||||||
ulimit -n 2048 && php tests/AutobahnTestSuite/bin/fuzzingserver-noutf8.php 8003 &
|
|
||||||
wstest -m testeeserver -w ws://localhost:8000 &
|
wstest -m testeeserver -w ws://localhost:8000 &
|
||||||
wstest -m fuzzingclient -s tests/AutobahnTestSuite/fuzzingclient-all.json
|
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-all.json
|
||||||
killall php wstest
|
killall php wstest
|
||||||
|
|
||||||
abtest:
|
abtest:
|
||||||
ulimit -n 2048 && php tests/AutobahnTestSuite/bin/fuzzingserver-stream.php &
|
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver-stream.php &
|
||||||
wstest -m fuzzingclient -s tests/AutobahnTestSuite/fuzzingclient-quick.json
|
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-quick.json
|
||||||
killall php
|
killall php
|
||||||
|
|
||||||
profile:
|
profile:
|
||||||
php -d 'xdebug.profiler_enable=1' tests/AutobahnTestSuite/bin/fuzzingserver-libevent.php &
|
php -d 'xdebug.profiler_enable=1' tests/autobahn/bin/fuzzingserver-libevent.php &
|
||||||
wstest -m fuzzingclient -s tests/AutobahnTestSuite/fuzzingclient-profile.json
|
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-profile.json
|
||||||
killall php
|
killall php
|
||||||
|
|
||||||
apidocs:
|
apidocs:
|
||||||
@ -32,4 +30,5 @@ apidocs:
|
|||||||
-s vendor/react \
|
-s vendor/react \
|
||||||
-s vendor/guzzle \
|
-s vendor/guzzle \
|
||||||
-s vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session \
|
-s vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session \
|
||||||
|
-s vendor/symfony/routing/Symfony/Component/Routing \
|
||||||
-s vendor/evenement/evenement/src/Evenement
|
-s vendor/evenement/evenement/src/Evenement
|
||||||
|
26
README.md
26
README.md
@ -8,17 +8,17 @@ 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 - 27, Firefox 6 - 21, Safari 5.0.1 - 6, iOS 4.2 - 6
|
* Tested on Chrome 13 - 30, Firefox 6 - 24, Safari 5.0.1 - 6, iOS 4.2 - 7
|
||||||
* 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
|
||||||
|
|
||||||
Shell access is required and root access is recommended.
|
Shell access is required and root access is recommended.
|
||||||
To avoid proxy/firewall blockage it's recommended WebSockets are requested on port 80, which requires root access.
|
To avoid proxy/firewall blockage it's recommended WebSockets are requested on port 80 or 443 (SSL), which requires root access.
|
||||||
In order to do this, along with your sync web stack, you can either use a reverse proxy or two separate machines.
|
In order to do this, along with your sync web stack, you can either use a reverse proxy or two separate machines.
|
||||||
You can find more details in the [server conf docs](http://socketo.me/docs/deploy#serverconfiguration).
|
You can find more details in the [server conf docs](http://socketo.me/docs/deploy#serverconfiguration).
|
||||||
|
|
||||||
PHP 5.3.3 (or higher) is required. If you have access, PHP 5.4 is *highly* recommended for its performance improvements.
|
PHP 5.3.9 (or higher) is required. If you have access, PHP 5.4 is *highly* recommended for its performance improvements.
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
@ -30,22 +30,21 @@ Need help? Have a question? Want to provide feedback? Write a message on the
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
###A quick server example
|
###A quick example
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
use Ratchet\MessageComponentInterface;
|
use Ratchet\MessageComponentInterface;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
use Ratchet\Server\IoServer;
|
|
||||||
use Ratchet\WebSocket\WsServer;
|
|
||||||
|
|
||||||
|
// Make sure composer dependencies have been installed
|
||||||
require __DIR__ . '/vendor/autoload.php';
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* chat.php
|
* chat.php
|
||||||
* Send any incoming messages to all connected clients (except sender)
|
* Send any incoming messages to all connected clients (except sender)
|
||||||
*/
|
*/
|
||||||
class Chat implements MessageComponentInterface {
|
class MyChat implements MessageComponentInterface {
|
||||||
protected $clients;
|
protected $clients;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
@ -74,8 +73,17 @@ class Chat implements MessageComponentInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run the server application through the WebSocket protocol on port 8080
|
// Run the server application through the WebSocket protocol on port 8080
|
||||||
$server = IoServer::factory(new WsServer(new Chat), 8080);
|
$app = new Ratchet\App('localhost', 8080);
|
||||||
$server->run();
|
$app->route('/chat', new MyChat);
|
||||||
|
$app->route('/echo', new Ratchet\Server\EchoServer, array(*));
|
||||||
|
$app->run();
|
||||||
```
|
```
|
||||||
|
|
||||||
$ php chat.php
|
$ php chat.php
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Then some JavaScript in the browser:
|
||||||
|
var conn = new WebSocket('ws://localhost:8080/echo');
|
||||||
|
conn.onmessage = function(e) { console.log(e.data); };
|
||||||
|
conn.send('Hello Me!');
|
||||||
|
```
|
@ -20,14 +20,14 @@
|
|||||||
}
|
}
|
||||||
, "autoload": {
|
, "autoload": {
|
||||||
"psr-0": {
|
"psr-0": {
|
||||||
"Ratchet": "src",
|
"Ratchet": "src"
|
||||||
"Ratchet\\Tests": "tests"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, "require": {
|
, "require": {
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.9"
|
||||||
, "react/socket": ">=0.2.0,<0.4.0-dev"
|
, "react/socket": "0.3.*"
|
||||||
, "guzzle/http": ">=3.6.0,<3.8.0-dev"
|
, "guzzle/http": ">=3.6.0,<3.8.0-dev"
|
||||||
, "symfony/http-foundation": "~2.1"
|
, "symfony/http-foundation": "~2.2"
|
||||||
|
, "symfony/routing": "~2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
106
composer.lock
generated
106
composer.lock
generated
@ -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": "a62a14a02670ed6aedd683b1cb2b414f",
|
"hash": "a45c5bcb9c18e390adc2a60ffd059a52",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "evenement/evenement",
|
"name": "evenement/evenement",
|
||||||
@ -47,17 +47,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzle/common",
|
"name": "guzzle/common",
|
||||||
"version": "v3.7.3",
|
"version": "v3.7.4",
|
||||||
"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": "bf73c87375f60861f8c7ccc7b95878023ade5306"
|
"reference": "5126e268446c7e7df961b89128d71878e0652432"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/common/zipball/bf73c87375f60861f8c7ccc7b95878023ade5306",
|
"url": "https://api.github.com/repos/guzzle/common/zipball/5126e268446c7e7df961b89128d71878e0652432",
|
||||||
"reference": "bf73c87375f60861f8c7ccc7b95878023ade5306",
|
"reference": "5126e268446c7e7df961b89128d71878e0652432",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -87,21 +87,21 @@
|
|||||||
"event",
|
"event",
|
||||||
"exception"
|
"exception"
|
||||||
],
|
],
|
||||||
"time": "2013-09-08 21:09:18"
|
"time": "2013-10-02 20:47:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzle/http",
|
"name": "guzzle/http",
|
||||||
"version": "v3.7.3",
|
"version": "v3.7.4",
|
||||||
"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": "1034125dfd906b73119e535f03153a62fccb1989"
|
"reference": "3420035adcf312d62a2e64f3e6b3e3e590121786"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/http/zipball/1034125dfd906b73119e535f03153a62fccb1989",
|
"url": "https://api.github.com/repos/guzzle/http/zipball/3420035adcf312d62a2e64f3e6b3e3e590121786",
|
||||||
"reference": "1034125dfd906b73119e535f03153a62fccb1989",
|
"reference": "3420035adcf312d62a2e64f3e6b3e3e590121786",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -144,11 +144,11 @@
|
|||||||
"http",
|
"http",
|
||||||
"http client"
|
"http client"
|
||||||
],
|
],
|
||||||
"time": "2013-09-06 11:34:26"
|
"time": "2013-09-20 22:05:53"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzle/parser",
|
"name": "guzzle/parser",
|
||||||
"version": "v3.7.3",
|
"version": "v3.7.4",
|
||||||
"target-dir": "Guzzle/Parser",
|
"target-dir": "Guzzle/Parser",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -192,7 +192,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzle/stream",
|
"name": "guzzle/stream",
|
||||||
"version": "v3.7.3",
|
"version": "v3.7.4",
|
||||||
"target-dir": "Guzzle/Stream",
|
"target-dir": "Guzzle/Stream",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -375,17 +375,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/event-dispatcher",
|
"name": "symfony/event-dispatcher",
|
||||||
"version": "v2.3.4",
|
"version": "v2.3.6",
|
||||||
"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": "41c9826457c65fa3cf746f214985b7ca9cba42f8"
|
"reference": "7fc72a7a346a1887d3968cc1ce5642a15cd182e9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/41c9826457c65fa3cf746f214985b7ca9cba42f8",
|
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/7fc72a7a346a1887d3968cc1ce5642a15cd182e9",
|
||||||
"reference": "41c9826457c65fa3cf746f214985b7ca9cba42f8",
|
"reference": "7fc72a7a346a1887d3968cc1ce5642a15cd182e9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -425,21 +425,21 @@
|
|||||||
],
|
],
|
||||||
"description": "Symfony EventDispatcher Component",
|
"description": "Symfony EventDispatcher Component",
|
||||||
"homepage": "http://symfony.com",
|
"homepage": "http://symfony.com",
|
||||||
"time": "2013-07-21 12:12:18"
|
"time": "2013-09-19 09:45:20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-foundation",
|
"name": "symfony/http-foundation",
|
||||||
"version": "v2.3.4",
|
"version": "v2.3.6",
|
||||||
"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": "fdf130fe65457aedbc4639a22f4ef9d3be5c002c"
|
"reference": "59e712338cd05463ebcb8da6422a01b1291871e3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/fdf130fe65457aedbc4639a22f4ef9d3be5c002c",
|
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/59e712338cd05463ebcb8da6422a01b1291871e3",
|
||||||
"reference": "fdf130fe65457aedbc4639a22f4ef9d3be5c002c",
|
"reference": "59e712338cd05463ebcb8da6422a01b1291871e3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -475,7 +475,65 @@
|
|||||||
],
|
],
|
||||||
"description": "Symfony HttpFoundation Component",
|
"description": "Symfony HttpFoundation Component",
|
||||||
"homepage": "http://symfony.com",
|
"homepage": "http://symfony.com",
|
||||||
"time": "2013-08-26 05:49:51"
|
"time": "2013-09-29 19:41:41"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/routing",
|
||||||
|
"version": "v2.3.6",
|
||||||
|
"target-dir": "Symfony/Component/Routing",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/Routing.git",
|
||||||
|
"reference": "7d41463094752e87a0fae60316d236abecb8a034"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/Routing/zipball/7d41463094752e87a0fae60316d236abecb8a034",
|
||||||
|
"reference": "7d41463094752e87a0fae60316d236abecb8a034",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/common": "~2.2",
|
||||||
|
"psr/log": "~1.0",
|
||||||
|
"symfony/config": "~2.2",
|
||||||
|
"symfony/yaml": "~2.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"doctrine/common": "",
|
||||||
|
"symfony/config": "",
|
||||||
|
"symfony/yaml": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.3-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"Symfony\\Component\\Routing\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "http://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Routing Component",
|
||||||
|
"homepage": "http://symfony.com",
|
||||||
|
"time": "2013-09-29 19:41:41"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
@ -489,7 +547,7 @@
|
|||||||
|
|
||||||
],
|
],
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.9"
|
||||||
},
|
},
|
||||||
"platform-dev": [
|
"platform-dev": [
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<phpunit
|
<phpunit
|
||||||
forceCoversAnnotation="true"
|
forceCoversAnnotation="true"
|
||||||
mapTestClassNameToCoveredClassName="true"
|
mapTestClassNameToCoveredClassName="true"
|
||||||
bootstrap="vendor/autoload.php"
|
bootstrap="tests/bootstrap.php"
|
||||||
colors="true"
|
colors="true"
|
||||||
backupGlobals="false"
|
backupGlobals="false"
|
||||||
backupStaticAttributes="false"
|
backupStaticAttributes="false"
|
||||||
@ -11,15 +11,20 @@
|
|||||||
>
|
>
|
||||||
|
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="Ratchet Test Suite">
|
<testsuite name="unit">
|
||||||
<directory>./tests/Ratchet/</directory>
|
<directory>./tests/unit/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="integration">
|
||||||
|
<directory>./tests/integration/</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
<blacklist>
|
<whitelist>
|
||||||
<directory>./tests/</directory>
|
<directory>./src/</directory>
|
||||||
<directory>./vendor/</directory>
|
</whitelist>
|
||||||
</blacklist>
|
|
||||||
</filter>
|
</filter>
|
||||||
</phpunit>
|
</phpunit>
|
127
src/Ratchet/App.php
Normal file
127
src/Ratchet/App.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet;
|
||||||
|
use React\EventLoop\LoopInterface;
|
||||||
|
use React\EventLoop\Factory as LoopFactory;
|
||||||
|
use React\Socket\Server as Reactor;
|
||||||
|
use Ratchet\Http\HttpServerInterface;
|
||||||
|
use Ratchet\Http\OriginCheck;
|
||||||
|
use Ratchet\Wamp\WampServerInterface;
|
||||||
|
use Ratchet\Server\IoServer;
|
||||||
|
use Ratchet\Server\FlashPolicy;
|
||||||
|
use Ratchet\Http\HttpServer;
|
||||||
|
use Ratchet\Http\Router;
|
||||||
|
use Ratchet\WebSocket\WsServer;
|
||||||
|
use Ratchet\Wamp\WampServer;
|
||||||
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
use Symfony\Component\Routing\Route;
|
||||||
|
use Symfony\Component\Routing\RequestContext;
|
||||||
|
use Symfony\Component\Routing\Matcher\UrlMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An opinionated facade class to quickly and easily create a WebSocket server.
|
||||||
|
* A few configuration assumptions are made and some best-practice security conventions are applied by default.
|
||||||
|
*/
|
||||||
|
class App {
|
||||||
|
/**
|
||||||
|
* @var \Symfony\Component\Routing\RouteCollection
|
||||||
|
*/
|
||||||
|
public $routes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Ratchet\Server\IoServer
|
||||||
|
*/
|
||||||
|
public $flashServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Ratchet\Server\IoServer
|
||||||
|
*/
|
||||||
|
protected $_server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Host passed in construct used for same origin policy
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $httpHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $_routeCounter = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $httpHost HTTP hostname clients intend to connect to. MUST match JS `new WebSocket('ws://$httpHost');`
|
||||||
|
* @param int $port Port to listen on. If 80, assuming production, Flash on 843 otherwise expecting Flash to be proxied through 8843
|
||||||
|
* @param string $address IP address to bind to. Default is localhost/proxy only. '0.0.0.0' for any machine.
|
||||||
|
* @param LoopInterface $loop Specific React\EventLoop to bind the application to. null will create one for you.
|
||||||
|
*/
|
||||||
|
public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', LoopInterface $loop = null) {
|
||||||
|
if (extension_loaded('xdebug')) {
|
||||||
|
echo "XDebug extension detected. Remember to disable this if performance testing or going live!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $loop) {
|
||||||
|
$loop = LoopFactory::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->httpHost = $httpHost;
|
||||||
|
|
||||||
|
$socket = new Reactor($loop);
|
||||||
|
$socket->listen($port, $address);
|
||||||
|
|
||||||
|
$this->routes = new RouteCollection;
|
||||||
|
$this->_server = new IoServer(new HttpServer(new Router(new UrlMatcher($this->routes, new RequestContext))), $socket, $loop);
|
||||||
|
|
||||||
|
$policy = new FlashPolicy;
|
||||||
|
$policy->addAllowedAccess($httpHost, 80);
|
||||||
|
$policy->addAllowedAccess($httpHost, $port);
|
||||||
|
$flashSock = new Reactor($loop);
|
||||||
|
$this->flashServer = new IoServer($policy, $flashSock);
|
||||||
|
|
||||||
|
if (80 == $port) {
|
||||||
|
$flashSock->listen(843, '0.0.0.0');
|
||||||
|
} else {
|
||||||
|
$flashSock->listen(8843);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an endpiont/application to the server
|
||||||
|
* @param string $path The URI the client will connect to
|
||||||
|
* @param ComponentInterface $controller Your application to server for the route. If not specified, assumed to be for a WebSocket
|
||||||
|
* @param array $allowedOrigins An array of hosts allowed to connect (same host by default), [*] for any
|
||||||
|
* @param string $httpHost Override the $httpHost variable provided in the __construct
|
||||||
|
* @return ComponentInterface|WsServer
|
||||||
|
*/
|
||||||
|
public function route($path, ComponentInterface $controller, array $allowedOrigins = array(), $httpHost = null) {
|
||||||
|
if ($controller instanceof HttpServerInterface || $controller instanceof WsServer) {
|
||||||
|
$decorated = $controller;
|
||||||
|
} elseif ($controller instanceof WampServerInterface) {
|
||||||
|
$decorated = new WsServer(new WampServer($controller));
|
||||||
|
} elseif ($controller instanceof MessageComponentInterface) {
|
||||||
|
$decorated = new WsServer($controller);
|
||||||
|
} else {
|
||||||
|
$decorated = $controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
$httpHost = $httpHost ?: $this->httpHost;
|
||||||
|
|
||||||
|
$allowedOrigins = array_values($allowedOrigins);
|
||||||
|
if (0 === count($allowedOrigins)) {
|
||||||
|
$allowedOrigins[] = $httpHost;
|
||||||
|
}
|
||||||
|
if ('*' !== $allowedOrigins[0]) {
|
||||||
|
$decorated = new OriginCheck($decorated, $allowedOrigins);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->routes->add('rr-' . ++$this->_routeCounter, new Route($path, array('_controller' => $decorated), array('Origin' => $this->httpHost), array(), $httpHost));
|
||||||
|
|
||||||
|
return $decorated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the server by entering the event loop
|
||||||
|
*/
|
||||||
|
public function run() {
|
||||||
|
$this->_server->run();
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ namespace Ratchet;
|
|||||||
* The version of Ratchet being used
|
* The version of Ratchet being used
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const VERSION = 'Ratchet/0.2.7';
|
const VERSION = 'Ratchet/0.3';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A proxy object representing a connection to the application
|
* A proxy object representing a connection to the application
|
||||||
|
@ -1,9 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\WebSocket\Guzzle\Http\Message;
|
namespace Ratchet\Http\Guzzle\Http\Message;
|
||||||
use Guzzle\Http\Message\RequestFactory as GuzzleRequestFactory;
|
use Guzzle\Http\Message\RequestFactory as GuzzleRequestFactory;
|
||||||
use Guzzle\Http\EntityBody;
|
use Guzzle\Http\EntityBody;
|
||||||
|
|
||||||
class RequestFactory extends GuzzleRequestFactory {
|
class RequestFactory extends GuzzleRequestFactory {
|
||||||
|
|
||||||
|
protected static $ratchetInstance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInstance()
|
||||||
|
{
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
if (!static::$ratchetInstance) {
|
||||||
|
static::$ratchetInstance = new static();
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
return static::$ratchetInstance;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\WebSocket;
|
namespace Ratchet\Http;
|
||||||
use Ratchet\MessageInterface;
|
use Ratchet\MessageInterface;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
use Ratchet\WebSocket\Guzzle\Http\Message\RequestFactory;
|
use Ratchet\Http\Guzzle\Http\Message\RequestFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class receives streaming data from a client request
|
* This class receives streaming data from a client request
|
90
src/Ratchet/Http/HttpServer.php
Normal file
90
src/Ratchet/Http/HttpServer.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Http;
|
||||||
|
use Ratchet\MessageComponentInterface;
|
||||||
|
use Ratchet\ConnectionInterface;
|
||||||
|
use Guzzle\Http\Message\Response;
|
||||||
|
|
||||||
|
class HttpServer implements MessageComponentInterface {
|
||||||
|
/**
|
||||||
|
* Buffers incoming HTTP requests returning a Guzzle Request when coalesced
|
||||||
|
* @var HttpRequestParser
|
||||||
|
* @note May not expose this in the future, may do through facade methods
|
||||||
|
*/
|
||||||
|
protected $_reqParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Ratchet\Http\HttpServerInterface
|
||||||
|
*/
|
||||||
|
protected $_httpServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param HttpServerInterface
|
||||||
|
*/
|
||||||
|
public function __construct(HttpServerInterface $component) {
|
||||||
|
$this->_httpServer = $component;
|
||||||
|
$this->_reqParser = new HttpRequestParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onOpen(ConnectionInterface $conn) {
|
||||||
|
$conn->httpHeadersReceived = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onMessage(ConnectionInterface $from, $msg) {
|
||||||
|
if (true !== $from->httpHeadersReceived) {
|
||||||
|
try {
|
||||||
|
if (null === ($request = $this->_reqParser->onMessage($from, $msg))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (\OverflowException $oe) {
|
||||||
|
return $this->close($from, 413);
|
||||||
|
}
|
||||||
|
|
||||||
|
$from->httpHeadersReceived = true;
|
||||||
|
|
||||||
|
return $this->_httpServer->onOpen($from, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_httpServer->onMessage($from, $msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onClose(ConnectionInterface $conn) {
|
||||||
|
if ($conn->httpHeadersReceived) {
|
||||||
|
$this->_httpServer->onClose($conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onError(ConnectionInterface $conn, \Exception $e) {
|
||||||
|
if ($conn->httpHeadersReceived) {
|
||||||
|
$this->_httpServer->onError($conn, $e);
|
||||||
|
} else {
|
||||||
|
$this->close($conn, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a connection with an HTTP response
|
||||||
|
* @param \Ratchet\ConnectionInterface $conn
|
||||||
|
* @param int $code HTTP status code
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
protected function close(ConnectionInterface $conn, $code = 400) {
|
||||||
|
$response = new Response($code, array(
|
||||||
|
'X-Powered-By' => \Ratchet\VERSION
|
||||||
|
));
|
||||||
|
|
||||||
|
$conn->send((string)$response);
|
||||||
|
$conn->close();
|
||||||
|
}
|
||||||
|
}
|
14
src/Ratchet/Http/HttpServerInterface.php
Normal file
14
src/Ratchet/Http/HttpServerInterface.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Http;
|
||||||
|
use Ratchet\MessageComponentInterface;
|
||||||
|
use Ratchet\ConnectionInterface;
|
||||||
|
use Guzzle\Http\Message\RequestInterface;
|
||||||
|
|
||||||
|
interface HttpServerInterface extends MessageComponentInterface {
|
||||||
|
/**
|
||||||
|
* @param \Ratchet\ConnectionInterface $conn
|
||||||
|
* @param \Guzzle\Http\Message\RequestInterface $request null is default because PHP won't let me overload; don't pass null!!!
|
||||||
|
* @throws \UnexpectedValueException if a RequestInterface is not passed
|
||||||
|
*/
|
||||||
|
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null);
|
||||||
|
}
|
79
src/Ratchet/Http/OriginCheck.php
Normal file
79
src/Ratchet/Http/OriginCheck.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Http;
|
||||||
|
use Guzzle\Http\Message\RequestInterface;
|
||||||
|
use Ratchet\ConnectionInterface;
|
||||||
|
use Ratchet\MessageComponentInterface;
|
||||||
|
use Guzzle\Http\Message\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A middleware to ensure JavaScript clients connecting are from the expected domain.
|
||||||
|
* This protects other websites from open WebSocket connections to your application.
|
||||||
|
* Note: This can be spoofed from non-web browser clients
|
||||||
|
*/
|
||||||
|
class OriginCheck implements HttpServerInterface {
|
||||||
|
/**
|
||||||
|
* @var \Ratchet\MessageComponentInterface
|
||||||
|
*/
|
||||||
|
protected $_component;
|
||||||
|
|
||||||
|
public $allowedOrigins = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MessageComponentInterface $component Component/Application to decorate
|
||||||
|
* @param array $allowed An array of allowed domains that are allowed to connect from
|
||||||
|
*/
|
||||||
|
public function __construct(MessageComponentInterface $component, array $allowed = array()) {
|
||||||
|
$this->_component = $component;
|
||||||
|
$this->allowedOrigins += $allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) {
|
||||||
|
$header = (string)$request->getHeader('Origin');
|
||||||
|
$origin = parse_url($header, PHP_URL_HOST) ?: $header;
|
||||||
|
|
||||||
|
if (!in_array($origin, $this->allowedOrigins)) {
|
||||||
|
return $this->close($conn, 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_component->onOpen($conn, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
function onMessage(ConnectionInterface $from, $msg) {
|
||||||
|
return $this->_component->onMessage($from, $msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
function onClose(ConnectionInterface $conn) {
|
||||||
|
return $this->_component->onClose($conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
function onError(ConnectionInterface $conn, \Exception $e) {
|
||||||
|
return $this->_component->onError($conn, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a connection with an HTTP response
|
||||||
|
* @param \Ratchet\ConnectionInterface $conn
|
||||||
|
* @param int $code HTTP status code
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
protected function close(ConnectionInterface $conn, $code = 400) {
|
||||||
|
$response = new Response($code, array(
|
||||||
|
'X-Powered-By' => \Ratchet\VERSION
|
||||||
|
));
|
||||||
|
|
||||||
|
$conn->send((string)$response);
|
||||||
|
$conn->close();
|
||||||
|
}
|
||||||
|
}
|
92
src/Ratchet/Http/Router.php
Normal file
92
src/Ratchet/Http/Router.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Http;
|
||||||
|
use Ratchet\ConnectionInterface;
|
||||||
|
use Guzzle\Http\Message\RequestInterface;
|
||||||
|
use Guzzle\Http\Message\Response;
|
||||||
|
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
|
||||||
|
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
||||||
|
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
|
|
||||||
|
class Router implements HttpServerInterface {
|
||||||
|
/**
|
||||||
|
* @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface
|
||||||
|
*/
|
||||||
|
protected $_matcher;
|
||||||
|
|
||||||
|
public function __construct(UrlMatcherInterface $matcher) {
|
||||||
|
$this->_matcher = $matcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
* @throws \UnexpectedValueException If a controller is not \Ratchet\Http\HttpServerInterface
|
||||||
|
*/
|
||||||
|
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) {
|
||||||
|
if (null === $request) {
|
||||||
|
throw new \UnexpectedValueException('$request can not be null');
|
||||||
|
}
|
||||||
|
|
||||||
|
$context = $this->_matcher->getContext();
|
||||||
|
$context->setMethod($request->getMethod());
|
||||||
|
$context->setHost($request->getHost());
|
||||||
|
|
||||||
|
try {
|
||||||
|
$route = $this->_matcher->match($request->getPath());
|
||||||
|
} catch (MethodNotAllowedException $nae) {
|
||||||
|
return $this->close($conn, 403);
|
||||||
|
} catch (ResourceNotFoundException $nfe) {
|
||||||
|
return $this->close($conn, 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($route['_controller']) && class_exists($route['_controller'])) {
|
||||||
|
$route['_controller'] = new $route['_controller'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($route['_controller'] instanceof HttpServerInterface)) {
|
||||||
|
throw new \UnexpectedValueException('All routes must implement Ratchet\Http\HttpServerInterface');
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn->controller = $route['_controller'];
|
||||||
|
$conn->controller->onOpen($conn, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
function onMessage(ConnectionInterface $from, $msg) {
|
||||||
|
$from->controller->onMessage($from, $msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
function onClose(ConnectionInterface $conn) {
|
||||||
|
if (isset($conn->controller)) {
|
||||||
|
$conn->controller->onClose($conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
function onError(ConnectionInterface $conn, \Exception $e) {
|
||||||
|
if (isset($conn->controller)) {
|
||||||
|
$conn->controller->onError($conn, $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a connection with an HTTP response
|
||||||
|
* @param \Ratchet\ConnectionInterface $conn
|
||||||
|
* @param int $code HTTP status code
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
protected function close(ConnectionInterface $conn, $code = 400) {
|
||||||
|
$response = new Response($code, array(
|
||||||
|
'X-Powered-By' => \Ratchet\VERSION
|
||||||
|
));
|
||||||
|
|
||||||
|
$conn->send((string)$response);
|
||||||
|
$conn->close();
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests;
|
namespace Ratchet\Server;
|
||||||
use Ratchet\MessageComponentInterface;
|
use Ratchet\MessageComponentInterface;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
|
|
||||||
class AbFuzzyServer implements MessageComponentInterface {
|
/**
|
||||||
|
* A simple Ratchet application that will reply to all messages with the message it received
|
||||||
|
*/
|
||||||
|
class EchoServer implements MessageComponentInterface {
|
||||||
public function onOpen(ConnectionInterface $conn) {
|
public function onOpen(ConnectionInterface $conn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,8 +18,6 @@ class AbFuzzyServer implements MessageComponentInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) {
|
public function onError(ConnectionInterface $conn, \Exception $e) {
|
||||||
echo $e->getMessage() . "\n";
|
|
||||||
|
|
||||||
$conn->close();
|
$conn->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -108,6 +108,7 @@ class FlashPolicy implements MessageComponentInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$from->send($this->_cache . "\0");
|
$from->send($this->_cache . "\0");
|
||||||
|
$from->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +42,7 @@ class SessionProvider implements MessageComponentInterface, WsServerInterface {
|
|||||||
* @param \SessionHandlerInterface $handler
|
* @param \SessionHandlerInterface $handler
|
||||||
* @param array $options
|
* @param array $options
|
||||||
* @param \Ratchet\Session\Serialize\HandlerInterface $serializer
|
* @param \Ratchet\Session\Serialize\HandlerInterface $serializer
|
||||||
* @throws \RuntimeExcpetion
|
* @throws \RuntimeException
|
||||||
*/
|
*/
|
||||||
public function __construct(MessageComponentInterface $app, \SessionHandlerInterface $handler, array $options = array(), HandlerInterface $serializer = null) {
|
public function __construct(MessageComponentInterface $app, \SessionHandlerInterface $handler, array $options = array(), HandlerInterface $serializer = null) {
|
||||||
$this->_app = $app;
|
$this->_app = $app;
|
||||||
@ -71,7 +71,7 @@ class SessionProvider implements MessageComponentInterface, WsServerInterface {
|
|||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
function onOpen(ConnectionInterface $conn) {
|
function onOpen(ConnectionInterface $conn) {
|
||||||
if (null === ($id = $conn->WebSocket->request->getCookie(ini_get('session.name')))) {
|
if (!isset($conn->WebSocket) || null === ($id = $conn->WebSocket->request->getCookie(ini_get('session.name')))) {
|
||||||
$saveHandler = $this->_null;
|
$saveHandler = $this->_null;
|
||||||
$id = '';
|
$id = '';
|
||||||
} else {
|
} else {
|
||||||
|
@ -89,6 +89,10 @@ class ServerProtocol implements MessageComponentInterface, WsServerInterface {
|
|||||||
throw new JsonException;
|
throw new JsonException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_array($json) || $json !== array_values($json)) {
|
||||||
|
throw new \UnexpectedValueException("Invalid WAMP message format");
|
||||||
|
}
|
||||||
|
|
||||||
switch ($json[0]) {
|
switch ($json[0]) {
|
||||||
case static::MSG_PREFIX:
|
case static::MSG_PREFIX:
|
||||||
$from->WAMP->prefixes[$json[1]] = $json[2];
|
$from->WAMP->prefixes[$json[1]] = $json[2];
|
||||||
|
@ -96,7 +96,7 @@ class WampConnection extends AbstractConnectionDecorator {
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function close() {
|
public function close($opt = null) {
|
||||||
$this->getConnection()->close();
|
$this->getConnection()->close($opt);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -37,7 +37,13 @@ class WampServer implements MessageComponentInterface, WsServerInterface {
|
|||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function onMessage(ConnectionInterface $conn, $msg) {
|
public function onMessage(ConnectionInterface $conn, $msg) {
|
||||||
$this->wampProtocol->onMessage($conn, $msg);
|
try {
|
||||||
|
$this->wampProtocol->onMessage($conn, $msg);
|
||||||
|
} catch (JsonException $je) {
|
||||||
|
$conn->close(1007);
|
||||||
|
} catch (\UnexpectedValueException $uve) {
|
||||||
|
$conn->close(1007);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,22 +113,6 @@ class HandshakeVerifier {
|
|||||||
return (16 === strlen(base64_decode((string)$val)));
|
return (16 === strlen(base64_decode((string)$val)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify Origin matches RFC6454 IF it is set
|
|
||||||
* Origin is an optional field
|
|
||||||
* @param string|null
|
|
||||||
* @return bool
|
|
||||||
* @todo Implement verification functionality - see section 4.2.1.7
|
|
||||||
*/
|
|
||||||
public function verifyOrigin($val) {
|
|
||||||
if (null === $val) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// logic here
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify the version passed matches this RFC
|
* Verify the version passed matches this RFC
|
||||||
* @param string|int MUST equal 13|"13"
|
* @param string|int MUST equal 13|"13"
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
namespace Ratchet\WebSocket;
|
namespace Ratchet\WebSocket;
|
||||||
use Ratchet\MessageComponentInterface;
|
use Ratchet\MessageComponentInterface;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
|
use Ratchet\Http\HttpServerInterface;
|
||||||
|
use Guzzle\Http\Message\RequestInterface;
|
||||||
|
use Guzzle\Http\Message\Response;
|
||||||
use Ratchet\WebSocket\Version;
|
use Ratchet\WebSocket\Version;
|
||||||
use Ratchet\WebSocket\Encoding\ToggleableValidator;
|
use Ratchet\WebSocket\Encoding\ToggleableValidator;
|
||||||
use Guzzle\Http\Message\Response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The adapter to handle WebSocket requests/responses
|
* The adapter to handle WebSocket requests/responses
|
||||||
@ -12,14 +14,7 @@ use Guzzle\Http\Message\Response;
|
|||||||
* @link http://ca.php.net/manual/en/ref.http.php
|
* @link http://ca.php.net/manual/en/ref.http.php
|
||||||
* @link http://dev.w3.org/html5/websockets/
|
* @link http://dev.w3.org/html5/websockets/
|
||||||
*/
|
*/
|
||||||
class WsServer implements MessageComponentInterface {
|
class WsServer implements HttpServerInterface {
|
||||||
/**
|
|
||||||
* Buffers incoming HTTP requests returning a Guzzle Request when coalesced
|
|
||||||
* @var HttpRequestParser
|
|
||||||
* @note May not expose this in the future, may do through facade methods
|
|
||||||
*/
|
|
||||||
public $reqParser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage the various WebSocket versions to support
|
* Manage the various WebSocket versions to support
|
||||||
* @var VersionManager
|
* @var VersionManager
|
||||||
@ -31,7 +26,7 @@ class WsServer implements MessageComponentInterface {
|
|||||||
* Decorated component
|
* Decorated component
|
||||||
* @var \Ratchet\MessageComponentInterface
|
* @var \Ratchet\MessageComponentInterface
|
||||||
*/
|
*/
|
||||||
protected $_decorating;
|
public $component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \SplObjectStorage
|
* @var \SplObjectStorage
|
||||||
@ -39,9 +34,7 @@ class WsServer implements MessageComponentInterface {
|
|||||||
protected $connections;
|
protected $connections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For now, array_push accepted subprotocols to this array
|
* Holder of accepted protocols, implement through WampServerInterface
|
||||||
* @deprecated
|
|
||||||
* @temporary
|
|
||||||
*/
|
*/
|
||||||
protected $acceptedSubProtocols = array();
|
protected $acceptedSubProtocols = array();
|
||||||
|
|
||||||
@ -62,7 +55,6 @@ class WsServer implements MessageComponentInterface {
|
|||||||
* If you want to enable sub-protocols have your component implement WsServerInterface as well
|
* If you want to enable sub-protocols have your component implement WsServerInterface as well
|
||||||
*/
|
*/
|
||||||
public function __construct(MessageComponentInterface $component) {
|
public function __construct(MessageComponentInterface $component) {
|
||||||
$this->reqParser = new HttpRequestParser;
|
|
||||||
$this->versioner = new VersionManager;
|
$this->versioner = new VersionManager;
|
||||||
$this->validator = new ToggleableValidator;
|
$this->validator = new ToggleableValidator;
|
||||||
|
|
||||||
@ -72,16 +64,23 @@ class WsServer implements MessageComponentInterface {
|
|||||||
->enableVersion(new Version\Hixie76)
|
->enableVersion(new Version\Hixie76)
|
||||||
;
|
;
|
||||||
|
|
||||||
$this->_decorating = $component;
|
$this->component = $component;
|
||||||
$this->connections = new \SplObjectStorage;
|
$this->connections = new \SplObjectStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function onOpen(ConnectionInterface $conn) {
|
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) {
|
||||||
$conn->WebSocket = new \StdClass;
|
if (null === $request) {
|
||||||
|
throw new \UnexpectedValueException('$request can not be null');
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn->WebSocket = new \StdClass;
|
||||||
|
$conn->WebSocket->request = $request;
|
||||||
$conn->WebSocket->established = false;
|
$conn->WebSocket->established = false;
|
||||||
|
|
||||||
|
$this->attemptUpgrade($conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,51 +91,46 @@ class WsServer implements MessageComponentInterface {
|
|||||||
return $from->WebSocket->version->onMessage($this->connections[$from], $msg);
|
return $from->WebSocket->version->onMessage($this->connections[$from], $msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($from->WebSocket->request)) {
|
$this->attemptUpgrade($from, $msg);
|
||||||
$from->WebSocket->request->getBody()->write($msg);
|
}
|
||||||
|
|
||||||
|
protected function attemptUpgrade(ConnectionInterface $conn, $data = '') {
|
||||||
|
if ('' !== $data) {
|
||||||
|
$conn->WebSocket->request->getBody()->write($data);
|
||||||
} else {
|
} else {
|
||||||
try {
|
if (!$this->versioner->isVersionEnabled($conn->WebSocket->request)) {
|
||||||
if (null === ($request = $this->reqParser->onMessage($from, $msg))) {
|
return $this->close($conn);
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (\OverflowException $oe) {
|
|
||||||
return $this->close($from, 413);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->versioner->isVersionEnabled($request)) {
|
$conn->WebSocket->version = $this->versioner->getVersion($conn->WebSocket->request);
|
||||||
return $this->close($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
$from->WebSocket->request = $request;
|
|
||||||
$from->WebSocket->version = $this->versioner->getVersion($request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$response = $from->WebSocket->version->handshake($from->WebSocket->request);
|
$response = $conn->WebSocket->version->handshake($conn->WebSocket->request);
|
||||||
} catch (\UnderflowException $e) {
|
} catch (\UnderflowException $e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== ($subHeader = $from->WebSocket->request->getHeader('Sec-WebSocket-Protocol'))) {
|
if (null !== ($subHeader = $conn->WebSocket->request->getHeader('Sec-WebSocket-Protocol'))) {
|
||||||
if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($subHeader->normalize()))) {
|
if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($subHeader->normalize()))) {
|
||||||
$response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols);
|
$response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->setHeader('X-Powered-By', \Ratchet\VERSION);
|
$response->setHeader('X-Powered-By', \Ratchet\VERSION);
|
||||||
$from->send((string)$response);
|
$conn->send((string)$response);
|
||||||
|
|
||||||
if (101 != $response->getStatusCode()) {
|
if (101 != $response->getStatusCode()) {
|
||||||
return $from->close();
|
return $conn->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
$upgraded = $from->WebSocket->version->upgradeConnection($from, $this->_decorating);
|
$upgraded = $conn->WebSocket->version->upgradeConnection($conn, $this->component);
|
||||||
|
|
||||||
$this->connections->attach($from, $upgraded);
|
$this->connections->attach($conn, $upgraded);
|
||||||
|
|
||||||
$upgraded->WebSocket->established = true;
|
$upgraded->WebSocket->established = true;
|
||||||
|
|
||||||
return $this->_decorating->onOpen($upgraded);
|
return $this->component->onOpen($upgraded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,7 +141,7 @@ class WsServer implements MessageComponentInterface {
|
|||||||
$decor = $this->connections[$conn];
|
$decor = $this->connections[$conn];
|
||||||
$this->connections->detach($conn);
|
$this->connections->detach($conn);
|
||||||
|
|
||||||
$this->_decorating->onClose($decor);
|
$this->component->onClose($decor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,8 +149,8 @@ class WsServer implements MessageComponentInterface {
|
|||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) {
|
public function onError(ConnectionInterface $conn, \Exception $e) {
|
||||||
if ($conn->WebSocket->established) {
|
if ($conn->WebSocket->established && $this->connections->contains($conn)) {
|
||||||
$this->_decorating->onError($this->connections[$conn], $e);
|
$this->component->onError($this->connections[$conn], $e);
|
||||||
} else {
|
} else {
|
||||||
$conn->close();
|
$conn->close();
|
||||||
}
|
}
|
||||||
@ -190,8 +184,8 @@ class WsServer implements MessageComponentInterface {
|
|||||||
*/
|
*/
|
||||||
public function isSubProtocolSupported($name) {
|
public function isSubProtocolSupported($name) {
|
||||||
if (!$this->isSpGenerated) {
|
if (!$this->isSpGenerated) {
|
||||||
if ($this->_decorating instanceof WsServerInterface) {
|
if ($this->component instanceof WsServerInterface) {
|
||||||
$this->acceptedSubProtocols = array_flip($this->_decorating->getSubProtocols());
|
$this->acceptedSubProtocols = array_flip($this->component->getSubProtocols());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->isSpGenerated = true;
|
$this->isSpGenerated = true;
|
||||||
@ -205,26 +199,21 @@ class WsServer implements MessageComponentInterface {
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getSubProtocolString(\Traversable $requested = null) {
|
protected function getSubProtocolString(\Traversable $requested = null) {
|
||||||
if (null === $requested) {
|
if (null !== $requested) {
|
||||||
return '';
|
foreach ($requested as $sub) {
|
||||||
}
|
if ($this->isSubProtocolSupported($sub)) {
|
||||||
|
return $sub;
|
||||||
$result = array();
|
}
|
||||||
|
|
||||||
foreach ($requested as $sub) {
|
|
||||||
if ($this->isSubProtocolSupported($sub)) {
|
|
||||||
$result[] = $sub;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode(',', $result);
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close a connection with an HTTP response
|
* Close a connection with an HTTP response
|
||||||
* @param \Ratchet\ConnectionInterface $conn
|
* @param \Ratchet\ConnectionInterface $conn
|
||||||
* @param int $code HTTP status code
|
* @param int $code HTTP status code
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
protected function close(ConnectionInterface $conn, $code = 400) {
|
protected function close(ConnectionInterface $conn, $code = 400) {
|
||||||
$response = new Response($code, array(
|
$response = new Response($code, array(
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
|
|
||||||
|
|
||||||
$loop = new React\EventLoop\LibEvLoop;
|
|
||||||
$sock = new React\Socket\Server($loop);
|
|
||||||
$app = new Ratchet\WebSocket\WsServer(new Ratchet\Tests\AbFuzzyServer);
|
|
||||||
|
|
||||||
$port = $argc > 1 ? $argv[1] : 8000;
|
|
||||||
$sock->listen($port, '0.0.0.0');
|
|
||||||
|
|
||||||
$server = new Ratchet\Server\IoServer($app, $sock, $loop);
|
|
||||||
$server->run();
|
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"options": {"failByDrop": false}
|
|
||||||
, "outdir": "reports/ab"
|
|
||||||
|
|
||||||
, "servers": [
|
|
||||||
{"agent": "Ratchet/0.2.5 libevent", "url": "ws://localhost:8002", "options": {"version": 18}}
|
|
||||||
, {"agent": "Ratchet/0.2.5 libuv", "url": "ws://localhost:8005", "options": {"version": 18}}
|
|
||||||
, {"agent": "Ratchet/0.2.5 libev", "url": "ws://localhost:8004", "options": {"version": 18}}
|
|
||||||
, {"agent": "Ratchet/0.2.5 -utf8", "url": "ws://localhost:8003", "options": {"version": 18}}
|
|
||||||
, {"agent": "Ratchet/0.2.5 streams", "url": "ws://localhost:8001", "options": {"version": 18}}
|
|
||||||
, {"agent": "AutobahnTestSuite/0.5.9", "url": "ws://localhost:8000", "options": {"version": 18}}
|
|
||||||
]
|
|
||||||
|
|
||||||
, "cases": ["*"]
|
|
||||||
, "exclude-cases": ["1.2.*", "2.3", "2.4", "2.6", "9.2.*", "9.4.*", "9.6.*", "9.8.*"]
|
|
||||||
, "exclude-agent-cases": {}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\Tests\Mock;
|
|
||||||
|
|
||||||
class MemorySessionHandler implements \SessionHandlerInterface {
|
|
||||||
protected $_sessions = array();
|
|
||||||
|
|
||||||
public function close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function destroy($session_id) {
|
|
||||||
if (isset($this->_sessions[$session_id])) {
|
|
||||||
unset($this->_sessions[$session_id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function gc($maxlifetime) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function open($save_path, $session_id) {
|
|
||||||
if (!isset($this->_sessions[$session_id])) {
|
|
||||||
$this->_sessions[$session_id] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function read($session_id) {
|
|
||||||
return $this->_sessions[$session_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function write($session_id, $session_data) {
|
|
||||||
$this->_sessions[$session_id] = $session_data;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\Tests\Wamp;
|
|
||||||
use Ratchet\Wamp\WampServer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @covers Ratchet\Wamp\WampServer
|
|
||||||
*/
|
|
||||||
class WampServerTest extends \PHPUnit_Framework_TestCase {
|
|
||||||
private $serv;
|
|
||||||
private $mock;
|
|
||||||
private $conn;
|
|
||||||
|
|
||||||
public function setUp() {
|
|
||||||
$this->mock = $this->getMock('\\Ratchet\\Wamp\\WampServerInterface');
|
|
||||||
$this->serv = new WampServer($this->mock);
|
|
||||||
$this->conn = $this->getMock('\\Ratchet\\ConnectionInterface');
|
|
||||||
|
|
||||||
$this->serv->onOpen($this->conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isWampConn() {
|
|
||||||
return new \PHPUnit_Framework_Constraint_IsInstanceOf('\\Ratchet\\Wamp\\WampConnection');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOpen() {
|
|
||||||
$this->mock->expects($this->once())->method('onOpen')->with($this->isWampConn());
|
|
||||||
$this->serv->onOpen($this->getMock('\\Ratchet\\ConnectionInterface'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOnClose() {
|
|
||||||
$this->mock->expects($this->once())->method('onClose')->with($this->isWampConn());
|
|
||||||
$this->serv->onClose($this->conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOnError() {
|
|
||||||
$e = new \Exception('hurr hurr');
|
|
||||||
$this->mock->expects($this->once())->method('onError')->with($this->isWampConn(), $e);
|
|
||||||
$this->serv->onError($this->conn, $e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOnMessageToEvent() {
|
|
||||||
$published = 'Client published this message';
|
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('onPublish')->with(
|
|
||||||
$this->isWampConn()
|
|
||||||
, new \PHPUnit_Framework_Constraint_IsInstanceOf('\\Ratchet\\Wamp\\Topic')
|
|
||||||
, $published
|
|
||||||
, array()
|
|
||||||
, array()
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->serv->onMessage($this->conn, json_encode(array(7, 'topic', $published)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetSubProtocols() {
|
|
||||||
// todo: could expand on this
|
|
||||||
$this->assertInternalType('array', $this->serv->getSubProtocols());
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
$loop = new React\EventLoop\LibEvLoop;
|
$loop = new React\EventLoop\LibEvLoop;
|
||||||
$sock = new React\Socket\Server($loop);
|
$sock = new React\Socket\Server($loop);
|
||||||
$app = new Ratchet\WebSocket\WsServer(new Ratchet\Tests\AbFuzzyServer);
|
$app = new Ratchet\Http\HttpServer(new Ratchet\WebSocket\WsServer(new Ratchet\Server\EchoServer));
|
||||||
|
|
||||||
$port = $argc > 1 ? $argv[1] : 8000;
|
$port = $argc > 1 ? $argv[1] : 8000;
|
||||||
$sock->listen($port, '0.0.0.0');
|
$sock->listen($port, '0.0.0.0');
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
$loop = new React\EventLoop\LibEventLoop;
|
$loop = new React\EventLoop\LibEventLoop;
|
||||||
$sock = new React\Socket\Server($loop);
|
$sock = new React\Socket\Server($loop);
|
||||||
$app = new Ratchet\WebSocket\WsServer(new Ratchet\Tests\AbFuzzyServer);
|
$app = new Ratchet\Http\HttpServer(new Ratchet\WebSocket\WsServer(new Ratchet\Server\EchoServer));
|
||||||
|
|
||||||
$port = $argc > 1 ? $argv[1] : 8000;
|
$port = $argc > 1 ? $argv[1] : 8000;
|
||||||
$sock->listen($port, '0.0.0.0');
|
$sock->listen($port, '0.0.0.0');
|
@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
$loop = new React\EventLoop\StreamSelectLoop;
|
$loop = new React\EventLoop\StreamSelectLoop;
|
||||||
$sock = new React\Socket\Server($loop);
|
$sock = new React\Socket\Server($loop);
|
||||||
$app = new Ratchet\WebSocket\WsServer(new Ratchet\Tests\AbFuzzyServer);
|
$web = new Ratchet\WebSocket\WsServer(new Ratchet\Server\EchoServer);
|
||||||
$app->setEncodingChecks(false);
|
$app = new Ratchet\Http\HttpServer($web);
|
||||||
|
$web->setEncodingChecks(false);
|
||||||
|
|
||||||
$port = $argc > 1 ? $argv[1] : 8000;
|
$port = $argc > 1 ? $argv[1] : 8000;
|
||||||
$sock->listen($port, '0.0.0.0');
|
$sock->listen($port, '0.0.0.0');
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
$loop = new React\EventLoop\StreamSelectLoop;
|
$loop = new React\EventLoop\StreamSelectLoop;
|
||||||
$sock = new React\Socket\Server($loop);
|
$sock = new React\Socket\Server($loop);
|
||||||
$app = new Ratchet\WebSocket\WsServer(new Ratchet\Tests\AbFuzzyServer);
|
$app = new Ratchet\Http\HttpServer(new Ratchet\WebSocket\WsServer(new Ratchet\Server\EchoServer));
|
||||||
|
|
||||||
$port = $argc > 1 ? $argv[1] : 8000;
|
$port = $argc > 1 ? $argv[1] : 8000;
|
||||||
$sock->listen($port, '0.0.0.0');
|
$sock->listen($port, '0.0.0.0');
|
15
tests/autobahn/fuzzingclient-all.json
Normal file
15
tests/autobahn/fuzzingclient-all.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"options": {"failByDrop": false}
|
||||||
|
, "outdir": "reports/ab"
|
||||||
|
|
||||||
|
, "servers": [
|
||||||
|
{"agent": "Ratchet/0.3 libevent", "url": "ws://localhost:8001", "options": {"version": 18}}
|
||||||
|
, {"agent": "Ratchet/0.3 streams", "url": "ws://localhost:8002", "options": {"version": 18}}
|
||||||
|
, {"agent": "Ratchet/0.3 -utf8", "url": "ws://localhost:8003", "options": {"version": 18}}
|
||||||
|
, {"agent": "AutobahnTestSuite/0.5.9", "url": "ws://localhost:8000", "options": {"version": 18}}
|
||||||
|
]
|
||||||
|
|
||||||
|
, "cases": ["*"]
|
||||||
|
, "exclude-cases": ["1.2.*", "2.3", "2.4", "2.6", "9.2.*", "9.4.*", "9.6.*", "9.8.*"]
|
||||||
|
, "exclude-agent-cases": {}
|
||||||
|
}
|
5
tests/bootstrap.php
Normal file
5
tests/bootstrap.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$loader = require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
$loader->add('Ratchet', __DIR__ . '/helpers');
|
||||||
|
$loader->register();
|
50
tests/helpers/Ratchet/AbstractMessageComponentTestCase.php
Normal file
50
tests/helpers/Ratchet/AbstractMessageComponentTestCase.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet;
|
||||||
|
|
||||||
|
abstract class AbstractMessageComponentTestCase extends \PHPUnit_Framework_TestCase {
|
||||||
|
protected $_app;
|
||||||
|
protected $_serv;
|
||||||
|
protected $_conn;
|
||||||
|
|
||||||
|
abstract public function getConnectionClassString();
|
||||||
|
abstract public function getDecoratorClassString();
|
||||||
|
abstract public function getComponentClassString();
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->_app = $this->getMock($this->getComponentClassString());
|
||||||
|
$decorator = $this->getDecoratorClassString();
|
||||||
|
$this->_serv = new $decorator($this->_app);
|
||||||
|
$this->_conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
|
|
||||||
|
$this->doOpen($this->_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doOpen($conn) {
|
||||||
|
$this->_serv->onOpen($conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isExpectedConnection() {
|
||||||
|
return new \PHPUnit_Framework_Constraint_IsInstanceOf($this->getConnectionClassString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOpen() {
|
||||||
|
$this->_app->expects($this->once())->method('onOpen')->with($this->isExpectedConnection());
|
||||||
|
$this->doOpen($this->getMock('\Ratchet\ConnectionInterface'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnClose() {
|
||||||
|
$this->_app->expects($this->once())->method('onClose')->with($this->isExpectedConnection());
|
||||||
|
$this->_serv->onClose($this->_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnError() {
|
||||||
|
$e = new \Exception('Whoops!');
|
||||||
|
$this->_app->expects($this->once())->method('onError')->with($this->isExpectedConnection(), $e);
|
||||||
|
$this->_serv->onError($this->_conn, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function passthroughMessageTest($value) {
|
||||||
|
$this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $value);
|
||||||
|
$this->_serv->onMessage($this->_conn, $value);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Mock;
|
namespace Ratchet\Mock;
|
||||||
use Ratchet\MessageComponentInterface;
|
use Ratchet\MessageComponentInterface;
|
||||||
use Ratchet\WebSocket\WsServerInterface;
|
use Ratchet\WebSocket\WsServerInterface;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Mock;
|
namespace Ratchet\Mock;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
|
|
||||||
class Connection implements ConnectionInterface {
|
class Connection implements ConnectionInterface {
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Mock;
|
namespace Ratchet\Mock;
|
||||||
use Ratchet\AbstractConnectionDecorator;
|
use Ratchet\AbstractConnectionDecorator;
|
||||||
|
|
||||||
class ConnectionDecorator extends AbstractConnectionDecorator {
|
class ConnectionDecorator extends AbstractConnectionDecorator {
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Mock;
|
namespace Ratchet\Mock;
|
||||||
use Ratchet\Wamp\WampServerInterface;
|
use Ratchet\Wamp\WampServerInterface;
|
||||||
use Ratchet\WebSocket\WsServerInterface;
|
use Ratchet\WebSocket\WsServerInterface;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
28
tests/helpers/Ratchet/NullComponent.php
Normal file
28
tests/helpers/Ratchet/NullComponent.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet;
|
||||||
|
use Ratchet\ConnectionInterface;
|
||||||
|
use Ratchet\MessageComponentInterface;
|
||||||
|
use Ratchet\WebSocket\WsServerInterface;
|
||||||
|
use Ratchet\Wamp\WampServerInterface;
|
||||||
|
|
||||||
|
class NullComponent implements MessageComponentInterface, WsServerInterface, WampServerInterface {
|
||||||
|
public function onOpen(ConnectionInterface $conn) {}
|
||||||
|
|
||||||
|
public function onMessage(ConnectionInterface $conn, $msg) {}
|
||||||
|
|
||||||
|
public function onClose(ConnectionInterface $conn) {}
|
||||||
|
|
||||||
|
public function onError(ConnectionInterface $conn, \Exception $e) {}
|
||||||
|
|
||||||
|
public function onCall(ConnectionInterface $conn, $id, $topic, array $params) {}
|
||||||
|
|
||||||
|
public function onSubscribe(ConnectionInterface $conn, $topic) {}
|
||||||
|
|
||||||
|
public function onUnSubscribe(ConnectionInterface $conn, $topic) {}
|
||||||
|
|
||||||
|
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude = array(), array $eligible = array()) {}
|
||||||
|
|
||||||
|
public function getSubProtocols() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Wamp\Stub;
|
namespace Ratchet\Wamp\Stub;
|
||||||
use Ratchet\WebSocket\WsServerInterface;
|
use Ratchet\WebSocket\WsServerInterface;
|
||||||
use Ratchet\Wamp\WampServerInterface;
|
use Ratchet\Wamp\WampServerInterface;
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Stub;
|
namespace Ratchet\WebSocket\Stub;
|
||||||
use Ratchet\MessageComponentInterface;
|
use Ratchet\MessageComponentInterface;
|
||||||
use Ratchet\WebSocket\WsServerInterface;
|
use Ratchet\WebSocket\WsServerInterface;
|
||||||
|
|
53
tests/integration/GuzzleTest.php
Normal file
53
tests/integration/GuzzleTest.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
use Guzzle\Http\Message\Request;
|
||||||
|
|
||||||
|
class GuzzleTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
protected $_request;
|
||||||
|
|
||||||
|
protected $_headers = array(
|
||||||
|
'Upgrade' => 'websocket'
|
||||||
|
, 'Connection' => 'Upgrade'
|
||||||
|
, 'Host' => 'localhost:8080'
|
||||||
|
, 'Origin' => 'chrome://newtab'
|
||||||
|
, 'Sec-WebSocket-Protocol' => 'one, two, three'
|
||||||
|
, 'Sec-WebSocket-Key' => '9bnXNp3ae6FbFFRtPdiPXA=='
|
||||||
|
, 'Sec-WebSocket-Version' => '13'
|
||||||
|
);
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->_request = new Request('GET', 'http://localhost', $this->_headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetHeaderString() {
|
||||||
|
$this->assertEquals('Upgrade', (string)$this->_request->getHeader('connection'));
|
||||||
|
$this->assertEquals('9bnXNp3ae6FbFFRtPdiPXA==', (string)$this->_request->getHeader('Sec-Websocket-Key'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetHeaderInteger() {
|
||||||
|
$this->assertSame('13', (string)$this->_request->getHeader('Sec-Websocket-Version'));
|
||||||
|
$this->assertSame(13, (int)(string)$this->_request->getHeader('Sec-WebSocket-Version'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetHeaderObject() {
|
||||||
|
$this->assertInstanceOf('Guzzle\Http\Message\Header', $this->_request->getHeader('Origin'));
|
||||||
|
$this->assertNull($this->_request->getHeader('Non-existant-header'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHeaderObjectNormalizeValues() {
|
||||||
|
$expected = 1 + substr_count($this->_headers['Sec-WebSocket-Protocol'], ',');
|
||||||
|
$protocols = $this->_request->getHeader('Sec-WebSocket-Protocol')->normalize();
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
foreach ($protocols as $protocol) {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $count);
|
||||||
|
$this->assertEquals($expected, count($protocols));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRequestFactoryCreateSignature() {
|
||||||
|
$ref = new \ReflectionMethod('Guzzle\Http\Message\RequestFactory', 'create');
|
||||||
|
$this->assertEquals(2, $ref->getNumberOfRequiredParameters());
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests;
|
namespace Ratchet;
|
||||||
use Ratchet\Tests\Mock\ConnectionDecorator;
|
use Ratchet\Mock\ConnectionDecorator;
|
||||||
use Ratchet\Tests\Mock\Connection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Ratchet\AbstractConnectionDecorator
|
* @covers Ratchet\AbstractConnectionDecorator
|
||||||
@ -13,7 +12,7 @@ class AbstractConnectionDecoratorTest extends \PHPUnit_Framework_TestCase {
|
|||||||
protected $l2;
|
protected $l2;
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
$this->mock = new Connection;
|
$this->mock = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
$this->l1 = new ConnectionDecorator($this->mock);
|
$this->l1 = new ConnectionDecorator($this->mock);
|
||||||
$this->l2 = new ConnectionDecorator($this->l1);
|
$this->l2 = new ConnectionDecorator($this->l1);
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Guzzle\Http\Message;
|
namespace Ratchet\Http\Guzzle\Http\Message;
|
||||||
use Ratchet\WebSocket\Guzzle\Http\Message\RequestFactory;
|
use Ratchet\Http\Guzzle\Http\Message\RequestFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Ratchet\WebSocket\Guzzle\Http\Message\RequestFactory
|
* @covers Ratchet\Http\Guzzle\Http\Message\RequestFactory
|
||||||
*/
|
*/
|
||||||
class RequestFactoryTest extends \PHPUnit_Framework_TestCase {
|
class RequestFactoryTest extends \PHPUnit_Framework_TestCase {
|
||||||
protected $factory;
|
protected $factory;
|
@ -1,10 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket;
|
namespace Ratchet\Http;
|
||||||
use Ratchet\WebSocket\HttpRequestParser;
|
use Ratchet\Http\HttpRequestParser;
|
||||||
use Ratchet\Tests\Mock\Connection as ConnectionStub;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Ratchet\WebSocket\HttpRequestParser
|
* @covers Ratchet\Http\HttpRequestParser
|
||||||
*/
|
*/
|
||||||
class HttpRequestParserTest extends \PHPUnit_Framework_TestCase {
|
class HttpRequestParserTest extends \PHPUnit_Framework_TestCase {
|
||||||
protected $parser;
|
protected $parser;
|
||||||
@ -32,7 +31,7 @@ class HttpRequestParserTest extends \PHPUnit_Framework_TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testBufferOverflowResponse() {
|
public function testBufferOverflowResponse() {
|
||||||
$conn = new ConnectionStub;
|
$conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
|
|
||||||
$this->parser->maxSize = 20;
|
$this->parser->maxSize = 20;
|
||||||
|
|
||||||
@ -42,4 +41,11 @@ class HttpRequestParserTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
$this->parser->onMessage($conn, "Header-Is: Too Big");
|
$this->parser->onMessage($conn, "Header-Is: Too Big");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testReturnTypeIsRequest() {
|
||||||
|
$conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
|
$return = $this->parser->onMessage($conn, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n");
|
||||||
|
|
||||||
|
$this->assertInstanceOf('\Guzzle\Http\Message\RequestInterface', $return);
|
||||||
|
}
|
||||||
}
|
}
|
64
tests/unit/Http/HttpServerTest.php
Normal file
64
tests/unit/Http/HttpServerTest.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Http;
|
||||||
|
use Ratchet\AbstractMessageComponentTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Ratchet\Http\HttpServer
|
||||||
|
*/
|
||||||
|
class HttpServerTest extends AbstractMessageComponentTestCase {
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->_conn->httpHeadersReceived = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConnectionClassString() {
|
||||||
|
return '\Ratchet\ConnectionInterface';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDecoratorClassString() {
|
||||||
|
return '\Ratchet\Http\HttpServer';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponentClassString() {
|
||||||
|
return '\Ratchet\Http\HttpServerInterface';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOpen() {
|
||||||
|
$headers = "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n";
|
||||||
|
|
||||||
|
$this->_conn->httpHeadersReceived = false;
|
||||||
|
$this->_app->expects($this->once())->method('onOpen')->with($this->isExpectedConnection());
|
||||||
|
$this->_serv->onMessage($this->_conn, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnMessageAfterHeaders() {
|
||||||
|
$headers = "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n";
|
||||||
|
$this->_conn->httpHeadersReceived = false;
|
||||||
|
$this->_serv->onMessage($this->_conn, $headers);
|
||||||
|
|
||||||
|
$message = "Hello World!";
|
||||||
|
$this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $message);
|
||||||
|
$this->_serv->onMessage($this->_conn, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBufferOverflow() {
|
||||||
|
$this->_conn->expects($this->once())->method('close');
|
||||||
|
$this->_conn->httpHeadersReceived = false;
|
||||||
|
|
||||||
|
$this->_serv->onMessage($this->_conn, str_repeat('a', 5000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCloseIfNotEstablished() {
|
||||||
|
$this->_conn->httpHeadersReceived = false;
|
||||||
|
$this->_conn->expects($this->once())->method('close');
|
||||||
|
$this->_serv->onError($this->_conn, new \Exception('Whoops!'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBufferHeaders() {
|
||||||
|
$this->_conn->httpHeadersReceived = false;
|
||||||
|
$this->_app->expects($this->never())->method('onOpen');
|
||||||
|
$this->_app->expects($this->never())->method('onMessage');
|
||||||
|
|
||||||
|
$this->_serv->onMessage($this->_conn, "GET / HTTP/1.1");
|
||||||
|
}
|
||||||
|
}
|
46
tests/unit/Http/OriginCheckTest.php
Normal file
46
tests/unit/Http/OriginCheckTest.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Http;
|
||||||
|
use Ratchet\AbstractMessageComponentTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Ratchet\Http\OriginCheck
|
||||||
|
*/
|
||||||
|
class OriginCheckTest extends AbstractMessageComponentTestCase {
|
||||||
|
protected $_reqStub;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->_reqStub = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||||
|
$this->_reqStub->expects($this->any())->method('getHeader')->will($this->returnValue('localhost'));
|
||||||
|
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->_serv->allowedOrigins[] = 'localhost';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doOpen($conn) {
|
||||||
|
$this->_serv->onOpen($conn, $this->_reqStub);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConnectionClassString() {
|
||||||
|
return '\Ratchet\ConnectionInterface';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDecoratorClassString() {
|
||||||
|
return '\Ratchet\Http\OriginCheck';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponentClassString() {
|
||||||
|
return '\Ratchet\Http\HttpServerInterface';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCloseOnNonMatchingOrigin() {
|
||||||
|
$this->_serv->allowedOrigins = array('socketo.me');
|
||||||
|
$this->_conn->expects($this->once())->method('close');
|
||||||
|
|
||||||
|
$this->_serv->onOpen($this->_conn, $this->_reqStub);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnMessage() {
|
||||||
|
$this->passthroughMessageTest('Hello World!');
|
||||||
|
}
|
||||||
|
}
|
88
tests/unit/Http/RouterTest.php
Normal file
88
tests/unit/Http/RouterTest.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Http;
|
||||||
|
use Ratchet\Http\Router;
|
||||||
|
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Ratchet\Http\Router
|
||||||
|
*/
|
||||||
|
class RouterTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
protected $_router;
|
||||||
|
protected $_matcher;
|
||||||
|
protected $_conn;
|
||||||
|
protected $_req;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->_conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
|
$this->_req = $this->getMock('\Guzzle\Http\Message\RequestInterface');
|
||||||
|
$this->_matcher = $this->getMock('Symfony\Component\Routing\Matcher\UrlMatcherInterface');
|
||||||
|
$this->_matcher
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getContext')
|
||||||
|
->will($this->returnValue($this->getMock('Symfony\Component\Routing\RequestContext')));
|
||||||
|
$this->_router = new Router($this->_matcher);
|
||||||
|
|
||||||
|
$this->_req->expects($this->any())->method('getPath')->will($this->returnValue('/whatever'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFourOhFour() {
|
||||||
|
$this->_conn->expects($this->once())->method('close');
|
||||||
|
|
||||||
|
$nope = new ResourceNotFoundException;
|
||||||
|
$this->_matcher->expects($this->any())->method('match')->will($this->throwException($nope));
|
||||||
|
|
||||||
|
$this->_router->onOpen($this->_conn, $this->_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNullRequest() {
|
||||||
|
$this->setExpectedException('\UnexpectedValueException');
|
||||||
|
$this->_router->onOpen($this->_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testControllerIsMessageComponentInterface() {
|
||||||
|
$this->setExpectedException('\UnexpectedValueException');
|
||||||
|
$this->_matcher->expects($this->any())->method('match')->will($this->returnValue(array('_controller' => new \StdClass)));
|
||||||
|
$this->_router->onOpen($this->_conn, $this->_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testControllerOnOpen() {
|
||||||
|
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock();
|
||||||
|
$this->_matcher->expects($this->any())->method('match')->will($this->returnValue(array('_controller' => $controller)));
|
||||||
|
$this->_router->onOpen($this->_conn, $this->_req);
|
||||||
|
|
||||||
|
$expectedConn = new \PHPUnit_Framework_Constraint_IsInstanceOf('\Ratchet\ConnectionInterface');
|
||||||
|
$controller->expects($this->once())->method('onOpen')->with($expectedConn, $this->_req);
|
||||||
|
|
||||||
|
$this->_matcher->expects($this->any())->method('match')->will($this->returnValue(array('_controller' => $controller)));
|
||||||
|
$this->_router->onOpen($this->_conn, $this->_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testControllerOnMessageBubbles() {
|
||||||
|
$message = "The greatest trick the Devil ever pulled was convincing the world he didn't exist";
|
||||||
|
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock();
|
||||||
|
$controller->expects($this->once())->method('onMessage')->with($this->_conn, $message);
|
||||||
|
|
||||||
|
$this->_conn->controller = $controller;
|
||||||
|
|
||||||
|
$this->_router->onMessage($this->_conn, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testControllerOnCloseBubbles() {
|
||||||
|
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock();
|
||||||
|
$controller->expects($this->once())->method('onClose')->with($this->_conn);
|
||||||
|
|
||||||
|
$this->_conn->controller = $controller;
|
||||||
|
|
||||||
|
$this->_router->onClose($this->_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testControllerOnErrorBubbles() {
|
||||||
|
$e= new \Exception('One cannot be betrayed if one has no exceptions');
|
||||||
|
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock();
|
||||||
|
$controller->expects($this->once())->method('onError')->with($this->_conn, $e);
|
||||||
|
|
||||||
|
$this->_conn->controller = $controller;
|
||||||
|
|
||||||
|
$this->_router->onError($this->_conn, $e);
|
||||||
|
}
|
||||||
|
}
|
26
tests/unit/Server/EchoServerTest.php
Normal file
26
tests/unit/Server/EchoServerTest.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Server;
|
||||||
|
use Ratchet\Server\EchoServer;
|
||||||
|
|
||||||
|
class EchoServerTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
protected $_conn;
|
||||||
|
protected $_comp;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->_conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
|
$this->_comp = new EchoServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMessageEchod() {
|
||||||
|
$message = 'Tillsonburg, my back still aches when I hear that word.';
|
||||||
|
$this->_conn->expects($this->once())->method('send')->with($message);
|
||||||
|
$this->_comp->onMessage($this->_conn, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testErrorClosesConnection() {
|
||||||
|
ob_start();
|
||||||
|
$this->_conn->expects($this->once())->method('close');
|
||||||
|
$this->_comp->onError($this->_conn, new \Exception);
|
||||||
|
ob_end_clean();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Application\Server;
|
namespace Ratchet\Application\Server;
|
||||||
use Ratchet\Server\FlashPolicy;
|
use Ratchet\Server\FlashPolicy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,4 +137,16 @@ class FlashPolicyTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
$this->_policy->onMessage($conn, ' ');
|
$this->_policy->onMessage($conn, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testOnOpenExists() {
|
||||||
|
$this->assertTrue(method_exists($this->_policy, 'onOpen'));
|
||||||
|
$conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
|
$this->_policy->onOpen($conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnCloseExists() {
|
||||||
|
$this->assertTrue(method_exists($this->_policy, 'onClose'));
|
||||||
|
$conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
|
$this->_policy->onClose($conn);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Application\Server;
|
namespace Ratchet\Application\Server;
|
||||||
use Ratchet\Server\IoConnection;
|
use Ratchet\Server\IoConnection;
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Server;
|
namespace Ratchet\Server;
|
||||||
use Ratchet\Server\IoServer;
|
use Ratchet\Server\IoServer;
|
||||||
use React\EventLoop\StreamSelectLoop;
|
use React\EventLoop\StreamSelectLoop;
|
||||||
use React\Socket\Server;
|
use React\Socket\Server;
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Server;
|
namespace Ratchet\Server;
|
||||||
use Ratchet\Server\IpBlackList;
|
use Ratchet\Server\IpBlackList;
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Session\Serialize;
|
namespace Ratchet\Session\Serialize;
|
||||||
use Ratchet\Session\Serialize\PhpHandler;
|
use Ratchet\Session\Serialize\PhpHandler;
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,7 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Session;
|
namespace Ratchet\Session;
|
||||||
|
use Ratchet\AbstractMessageComponentTestCase;
|
||||||
use Ratchet\Session\SessionProvider;
|
use Ratchet\Session\SessionProvider;
|
||||||
use Ratchet\Tests\Mock\MemorySessionHandler;
|
use Ratchet\Mock\MemorySessionHandler;
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
|
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
|
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
|
||||||
use Guzzle\Http\Message\Request;
|
use Guzzle\Http\Message\Request;
|
||||||
@ -11,11 +12,30 @@ use Guzzle\Http\Message\Request;
|
|||||||
* @covers Ratchet\Session\Storage\VirtualSessionStorage
|
* @covers Ratchet\Session\Storage\VirtualSessionStorage
|
||||||
* @covers Ratchet\Session\Storage\Proxy\VirtualProxy
|
* @covers Ratchet\Session\Storage\Proxy\VirtualProxy
|
||||||
*/
|
*/
|
||||||
class SessionProviderTest extends \PHPUnit_Framework_TestCase {
|
class SessionProviderTest extends AbstractMessageComponentTestCase {
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
if (!class_exists('Symfony\\Component\\HttpFoundation\\Session\\Session')) {
|
if (!class_exists('Symfony\Component\HttpFoundation\Session\Session')) {
|
||||||
return $this->markTestSkipped('Dependency of Symfony HttpFoundation failed');
|
return $this->markTestSkipped('Dependency of Symfony HttpFoundation failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parent::setUp();
|
||||||
|
$this->_serv = new SessionProvider($this->_app, new NullSessionHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown() {
|
||||||
|
ini_set('session.serialize_handler', 'php');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConnectionClassString() {
|
||||||
|
return '\Ratchet\ConnectionInterface';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDecoratorClassString() {
|
||||||
|
return '\Ratchet\NullComponent';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponentClassString() {
|
||||||
|
return '\Ratchet\MessageComponentInterface';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function classCaseProvider() {
|
public function classCaseProvider() {
|
||||||
@ -33,7 +53,7 @@ class SessionProviderTest extends \PHPUnit_Framework_TestCase {
|
|||||||
$method = $ref->getMethod('toClassCase');
|
$method = $ref->getMethod('toClassCase');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
$component = new SessionProvider($this->getMock('Ratchet\\MessageComponentInterface'), new MemorySessionHandler);
|
$component = new SessionProvider($this->getMock('Ratchet\\MessageComponentInterface'), $this->getMock('\SessionHandlerInterface'));
|
||||||
$this->assertEquals($out, $method->invokeArgs($component, array($in)));
|
$this->assertEquals($out, $method->invokeArgs($component, array($in)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,9 +94,9 @@ class SessionProviderTest extends \PHPUnit_Framework_TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function newConn() {
|
protected function newConn() {
|
||||||
$conn = $this->getMock('Ratchet\\ConnectionInterface');
|
$conn = $this->getMock('Ratchet\ConnectionInterface');
|
||||||
|
|
||||||
$headers = $this->getMock('Guzzle\\Http\\Message\\Request', array('getCookie'), array('POST', '/', array()));
|
$headers = $this->getMock('Guzzle\Http\Message\Request', array('getCookie'), array('POST', '/', array()));
|
||||||
$headers->expects($this->once())->method('getCookie', array(ini_get('session.name')))->will($this->returnValue(null));
|
$headers->expects($this->once())->method('getCookie', array(ini_get('session.name')))->will($this->returnValue(null));
|
||||||
|
|
||||||
$conn->WebSocket = new \StdClass;
|
$conn->WebSocket = new \StdClass;
|
||||||
@ -85,46 +105,10 @@ class SessionProviderTest extends \PHPUnit_Framework_TestCase {
|
|||||||
return $conn;
|
return $conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testOnOpenBubbles() {
|
public function testOnMessageDecorator() {
|
||||||
$conn = $this->newConn();
|
$message = "Database calls are usually blocking :(";
|
||||||
$mock = $this->getMock('Ratchet\\MessageComponentInterface');
|
$this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $message);
|
||||||
$comp = new SessionProvider($mock, new NullSessionHandler);
|
$this->_serv->onMessage($this->_conn, $message);
|
||||||
|
|
||||||
$mock->expects($this->once())->method('onOpen')->with($conn);
|
|
||||||
$comp->onOpen($conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getOpenConn() {
|
|
||||||
$conn = $this->newConn();
|
|
||||||
$mock = $this->getMock('Ratchet\\MessageComponentInterface');
|
|
||||||
$prov = new SessionProvider($mock, new NullSessionHandler);
|
|
||||||
|
|
||||||
$prov->onOpen($conn);
|
|
||||||
|
|
||||||
return array($conn, $mock, $prov);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOnMessageBubbles() {
|
|
||||||
list($conn, $mock, $prov) = $this->getOpenConn();
|
|
||||||
$msg = 'No sessions here';
|
|
||||||
|
|
||||||
$mock->expects($this->once())->method('onMessage')->with($conn, $msg);
|
|
||||||
$prov->onMessage($conn, $msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOnCloseBubbles() {
|
|
||||||
list($conn, $mock, $prov) = $this->getOpenConn();
|
|
||||||
|
|
||||||
$mock->expects($this->once())->method('onClose')->with($conn);
|
|
||||||
$prov->onClose($conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOnErrorBubbles() {
|
|
||||||
list($conn, $mock, $prov) = $this->getOpenConn();
|
|
||||||
$e = new \Exception('I made a boo boo');
|
|
||||||
|
|
||||||
$mock->expects($this->once())->method('onError')->with($conn, $e);
|
|
||||||
$prov->onError($conn, $e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetSubProtocolsReturnsArray() {
|
public function testGetSubProtocolsReturnsArray() {
|
||||||
@ -135,10 +119,20 @@ class SessionProviderTest extends \PHPUnit_Framework_TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testGetSubProtocolsGetFromApp() {
|
public function testGetSubProtocolsGetFromApp() {
|
||||||
$mock = $this->getMock('Ratchet\\Tests\\WebSocket\\Stub\\WsMessageComponentInterface');
|
$mock = $this->getMock('Ratchet\WebSocket\Stub\WsMessageComponentInterface');
|
||||||
$mock->expects($this->once())->method('getSubProtocols')->will($this->returnValue(array('hello', 'world')));
|
$mock->expects($this->once())->method('getSubProtocols')->will($this->returnValue(array('hello', 'world')));
|
||||||
$comp = new SessionProvider($mock, new NullSessionHandler);
|
$comp = new SessionProvider($mock, new NullSessionHandler);
|
||||||
|
|
||||||
$this->assertGreaterThanOrEqual(2, count($comp->getSubProtocols()));
|
$this->assertGreaterThanOrEqual(2, count($comp->getSubProtocols()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRejectInvalidSeralizers() {
|
||||||
|
if (!function_exists('wddx_serialize_value')) {
|
||||||
|
$this->markTestSkipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_set('session.serialize_handler', 'wddx');
|
||||||
|
$this->setExpectedException('\RuntimeException');
|
||||||
|
new SessionProvider($this->getMock('\Ratchet\MessageComponentInterface'), $this->getMock('\SessionHandlerInterface'));
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Wamp;
|
namespace Ratchet\Wamp;
|
||||||
use Ratchet\Wamp\ServerProtocol;
|
use Ratchet\Wamp\ServerProtocol;
|
||||||
use Ratchet\Wamp\WampConnection;
|
use Ratchet\Wamp\WampConnection;
|
||||||
use Ratchet\Tests\Mock\Connection;
|
use Ratchet\Mock\Connection;
|
||||||
use Ratchet\Tests\Mock\WampComponent as TestComponent;
|
use Ratchet\Mock\WampComponent as TestComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Ratchet\Wamp\ServerProtocol
|
* @covers Ratchet\Wamp\ServerProtocol
|
||||||
@ -38,7 +38,7 @@ class ServerProtocolTest extends \PHPUnit_Framework_TestCase {
|
|||||||
* @dataProvider invalidMessageProvider
|
* @dataProvider invalidMessageProvider
|
||||||
*/
|
*/
|
||||||
public function testInvalidMessages($type) {
|
public function testInvalidMessages($type) {
|
||||||
$this->setExpectedException('\\Ratchet\\Wamp\\Exception');
|
$this->setExpectedException('\Ratchet\Wamp\Exception');
|
||||||
|
|
||||||
$conn = $this->newConn();
|
$conn = $this->newConn();
|
||||||
$this->_comp->onOpen($conn);
|
$this->_comp->onOpen($conn);
|
||||||
@ -247,4 +247,23 @@ class ServerProtocolTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
$this->assertContains('wamp', $wamp->getSubProtocols());
|
$this->assertContains('wamp', $wamp->getSubProtocols());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function badFormatProvider() {
|
||||||
|
return array(
|
||||||
|
array(json_encode(true))
|
||||||
|
, array('{"valid":"json", "invalid": "message"}')
|
||||||
|
, array('{"0": "fail", "hello": "world"}')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider badFormatProvider
|
||||||
|
*/
|
||||||
|
public function testValidJsonButInvalidProtocol($message) {
|
||||||
|
$this->setExpectedException('\UnexpectedValueException');
|
||||||
|
|
||||||
|
$conn = $this->newConn();
|
||||||
|
$this->_comp->onOpen($conn);
|
||||||
|
$this->_comp->onMessage($conn, $message);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Wamp;
|
namespace Ratchet\Wamp;
|
||||||
use Ratchet\Wamp\TopicManager;
|
use Ratchet\Wamp\TopicManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -7,12 +7,20 @@ use Ratchet\Wamp\TopicManager;
|
|||||||
*/
|
*/
|
||||||
class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
||||||
private $mock;
|
private $mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Ratchet\Wamp\TopicManager
|
||||||
|
*/
|
||||||
private $mngr;
|
private $mngr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Ratchet\ConnectionInterface
|
||||||
|
*/
|
||||||
private $conn;
|
private $conn;
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
$this->conn = $this->getMock('Ratchet\\ConnectionInterface');
|
$this->conn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
$this->mock = $this->getMock('Ratchet\\Wamp\\WampServerInterface');
|
$this->mock = $this->getMock('\Ratchet\Wamp\WampServerInterface');
|
||||||
$this->mngr = new TopicManager($this->mock);
|
$this->mngr = new TopicManager($this->mock);
|
||||||
|
|
||||||
$this->conn->WAMP = new \StdClass;
|
$this->conn->WAMP = new \StdClass;
|
||||||
@ -20,19 +28,19 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testGetTopicReturnsTopicObject() {
|
public function testGetTopicReturnsTopicObject() {
|
||||||
$class = new \ReflectionClass('Ratchet\\Wamp\\TopicManager');
|
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager');
|
||||||
$method = $class->getMethod('getTopic');
|
$method = $class->getMethod('getTopic');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
$topic = $method->invokeArgs($this->mngr, array('The Topic'));
|
$topic = $method->invokeArgs($this->mngr, array('The Topic'));
|
||||||
|
|
||||||
$this->assertInstanceOf('Ratchet\\Wamp\\Topic', $topic);
|
$this->assertInstanceOf('Ratchet\Wamp\Topic', $topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetTopicCreatesTopicWithSameName() {
|
public function testGetTopicCreatesTopicWithSameName() {
|
||||||
$name = 'The Topic';
|
$name = 'The Topic';
|
||||||
|
|
||||||
$class = new \ReflectionClass('Ratchet\\Wamp\\TopicManager');
|
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager');
|
||||||
$method = $class->getMethod('getTopic');
|
$method = $class->getMethod('getTopic');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
@ -42,7 +50,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testGetTopicReturnsSameObject() {
|
public function testGetTopicReturnsSameObject() {
|
||||||
$class = new \ReflectionClass('Ratchet\\Wamp\\TopicManager');
|
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager');
|
||||||
$method = $class->getMethod('getTopic');
|
$method = $class->getMethod('getTopic');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
@ -63,7 +71,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
$this->mock->expects($this->once())->method('onCall')->with(
|
$this->mock->expects($this->once())->method('onCall')->with(
|
||||||
$this->conn
|
$this->conn
|
||||||
, $id
|
, $id
|
||||||
, $this->isInstanceOf('Ratchet\\Wamp\\Topic')
|
, $this->isInstanceOf('Ratchet\Wamp\Topic')
|
||||||
, array()
|
, array()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -72,7 +80,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
public function testOnSubscribeCreatesTopicObject() {
|
public function testOnSubscribeCreatesTopicObject() {
|
||||||
$this->mock->expects($this->once())->method('onSubscribe')->with(
|
$this->mock->expects($this->once())->method('onSubscribe')->with(
|
||||||
$this->conn, $this->isInstanceOf('Ratchet\\Wamp\\Topic')
|
$this->conn, $this->isInstanceOf('Ratchet\Wamp\Topic')
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, 'new topic');
|
$this->mngr->onSubscribe($this->conn, 'new topic');
|
||||||
@ -81,7 +89,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
public function testTopicIsInConnectionOnSubscribe() {
|
public function testTopicIsInConnectionOnSubscribe() {
|
||||||
$name = 'New Topic';
|
$name = 'New Topic';
|
||||||
|
|
||||||
$class = new \ReflectionClass('Ratchet\\Wamp\\TopicManager');
|
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager');
|
||||||
$method = $class->getMethod('getTopic');
|
$method = $class->getMethod('getTopic');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
@ -102,7 +110,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
public function testUnsubscribeEvent() {
|
public function testUnsubscribeEvent() {
|
||||||
$name = 'in and out';
|
$name = 'in and out';
|
||||||
$this->mock->expects($this->once())->method('onUnsubscribe')->with(
|
$this->mock->expects($this->once())->method('onUnsubscribe')->with(
|
||||||
$this->conn, $this->isInstanceOf('Ratchet\\Wamp\\Topic')
|
$this->conn, $this->isInstanceOf('Ratchet\Wamp\Topic')
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, $name);
|
$this->mngr->onSubscribe($this->conn, $name);
|
||||||
@ -121,7 +129,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
public function testUnsubscribeRemovesTopicFromConnection() {
|
public function testUnsubscribeRemovesTopicFromConnection() {
|
||||||
$name = 'Bye Bye Topic';
|
$name = 'Bye Bye Topic';
|
||||||
|
|
||||||
$class = new \ReflectionClass('Ratchet\\Wamp\\TopicManager');
|
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager');
|
||||||
$method = $class->getMethod('getTopic');
|
$method = $class->getMethod('getTopic');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
@ -138,7 +146,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
$this->mock->expects($this->once())->method('onPublish')->with(
|
$this->mock->expects($this->once())->method('onPublish')->with(
|
||||||
$this->conn
|
$this->conn
|
||||||
, $this->isInstanceOf('Ratchet\\Wamp\\Topic')
|
, $this->isInstanceOf('Ratchet\Wamp\Topic')
|
||||||
, $msg
|
, $msg
|
||||||
, $this->isType('array')
|
, $this->isType('array')
|
||||||
, $this->isType('array')
|
, $this->isType('array')
|
||||||
@ -155,7 +163,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
public function testConnIsRemovedFromTopicOnClose() {
|
public function testConnIsRemovedFromTopicOnClose() {
|
||||||
$name = 'State testing';
|
$name = 'State testing';
|
||||||
|
|
||||||
$class = new \ReflectionClass('Ratchet\\Wamp\\TopicManager');
|
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager');
|
||||||
$method = $class->getMethod('getTopic');
|
$method = $class->getMethod('getTopic');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
@ -180,7 +188,7 @@ class TopicManagerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
public function testGetSubProtocolsBubbles() {
|
public function testGetSubProtocolsBubbles() {
|
||||||
$subs = array('hello', 'world');
|
$subs = array('hello', 'world');
|
||||||
$app = $this->getMock('Ratchet\\Tests\\Wamp\\Stub\\WsWampServerInterface');
|
$app = $this->getMock('Ratchet\Wamp\Stub\WsWampServerInterface');
|
||||||
$app->expects($this->once())->method('getSubProtocols')->will($this->returnValue($subs));
|
$app->expects($this->once())->method('getSubProtocols')->will($this->returnValue($subs));
|
||||||
$mngr = new TopicManager($app);
|
$mngr = new TopicManager($app);
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Wamp;
|
namespace Ratchet\Wamp;
|
||||||
use Ratchet\Wamp\Topic;
|
use Ratchet\Wamp\Topic;
|
||||||
use Ratchet\Wamp\WampConnection;
|
use Ratchet\Wamp\WampConnection;
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\Wamp;
|
namespace Ratchet\Wamp;
|
||||||
use Ratchet\Wamp\WampConnection;
|
use Ratchet\Wamp\WampConnection;
|
||||||
|
|
||||||
/**
|
/**
|
50
tests/unit/Wamp/WampServerTest.php
Normal file
50
tests/unit/Wamp/WampServerTest.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Wamp;
|
||||||
|
use Ratchet\Wamp\WampServer;
|
||||||
|
use Ratchet\AbstractMessageComponentTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Ratchet\Wamp\WampServer
|
||||||
|
*/
|
||||||
|
class WampServerTest extends AbstractMessageComponentTestCase {
|
||||||
|
public function getConnectionClassString() {
|
||||||
|
return '\Ratchet\Wamp\WampConnection';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDecoratorClassString() {
|
||||||
|
return 'Ratchet\Wamp\WampServer';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponentClassString() {
|
||||||
|
return '\Ratchet\Wamp\WampServerInterface';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnMessageToEvent() {
|
||||||
|
$published = 'Client published this message';
|
||||||
|
|
||||||
|
$this->_app->expects($this->once())->method('onPublish')->with(
|
||||||
|
$this->isExpectedConnection()
|
||||||
|
, new \PHPUnit_Framework_Constraint_IsInstanceOf('\Ratchet\Wamp\Topic')
|
||||||
|
, $published
|
||||||
|
, array()
|
||||||
|
, array()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->_serv->onMessage($this->_conn, json_encode(array(7, 'topic', $published)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetSubProtocols() {
|
||||||
|
// todo: could expand on this
|
||||||
|
$this->assertInternalType('array', $this->_serv->getSubProtocols());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConnectionClosesOnInvalidJson() {
|
||||||
|
$this->_conn->expects($this->once())->method('close');
|
||||||
|
$this->_serv->onMessage($this->_conn, 'invalid json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConnectionClosesOnProtocolError() {
|
||||||
|
$this->_conn->expects($this->once())->method('close');
|
||||||
|
$this->_serv->onMessage($this->_conn, json_encode(array('valid' => 'json', 'invalid' => 'protocol')));
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Version;
|
namespace Ratchet\WebSocket\Version;
|
||||||
use Ratchet\WebSocket\Version\Hixie76;
|
use Ratchet\WebSocket\Version\Hixie76;
|
||||||
|
use Ratchet\Http\HttpServer;
|
||||||
use Ratchet\WebSocket\WsServer;
|
use Ratchet\WebSocket\WsServer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,7 +44,7 @@ class Hixie76Test extends \PHPUnit_Framework_TestCase {
|
|||||||
$headers = "GET / HTTP/1.1";
|
$headers = "GET / HTTP/1.1";
|
||||||
$headers .= "Upgrade: WebSocket{$this->_crlf}";
|
$headers .= "Upgrade: WebSocket{$this->_crlf}";
|
||||||
$headers .= "Connection: Upgrade{$this->_crlf}";
|
$headers .= "Connection: Upgrade{$this->_crlf}";
|
||||||
$headers .= "Host: home.chrisboden.ca{$this->_crlf}";
|
$headers .= "Host: socketo.me{$this->_crlf}";
|
||||||
$headers .= "Origin: http://fiddle.jshell.net{$this->_crlf}";
|
$headers .= "Origin: http://fiddle.jshell.net{$this->_crlf}";
|
||||||
$headers .= "Sec-WebSocket-Key1:17 Z4< F94 N3 7P41 7{$this->_crlf}";
|
$headers .= "Sec-WebSocket-Key1:17 Z4< F94 N3 7P41 7{$this->_crlf}";
|
||||||
$headers .= "Sec-WebSocket-Key2:1 23C3:,2% 1-29 4 f0{$this->_crlf}";
|
$headers .= "Sec-WebSocket-Key2:1 23C3:,2% 1-29 4 f0{$this->_crlf}";
|
||||||
@ -55,12 +56,11 @@ class Hixie76Test extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
public function testNoUpgradeBeforeBody() {
|
public function testNoUpgradeBeforeBody() {
|
||||||
$headers = $this->headerProvider();
|
$headers = $this->headerProvider();
|
||||||
$body = base64_decode($this->_body);
|
|
||||||
|
|
||||||
$mockConn = $this->getMock('\\Ratchet\\ConnectionInterface');
|
$mockConn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
$mockApp = $this->getMock('\\Ratchet\\MessageComponentInterface');
|
$mockApp = $this->getMock('\Ratchet\MessageComponentInterface');
|
||||||
|
|
||||||
$server = new WsServer($mockApp);
|
$server = new HttpServer(new WsServer($mockApp));
|
||||||
$server->onOpen($mockConn);
|
$server->onOpen($mockConn);
|
||||||
$mockApp->expects($this->exactly(0))->method('onOpen');
|
$mockApp->expects($this->exactly(0))->method('onOpen');
|
||||||
$server->onMessage($mockConn, $headers);
|
$server->onMessage($mockConn, $headers);
|
||||||
@ -70,10 +70,10 @@ class Hixie76Test extends \PHPUnit_Framework_TestCase {
|
|||||||
$headers = $this->headerProvider();
|
$headers = $this->headerProvider();
|
||||||
$body = base64_decode($this->_body);
|
$body = base64_decode($this->_body);
|
||||||
|
|
||||||
$mockConn = $this->getMock('\\Ratchet\\ConnectionInterface');
|
$mockConn = $this->getMock('\Ratchet\ConnectionInterface');
|
||||||
$mockApp = $this->getMock('\\Ratchet\\MessageComponentInterface');
|
$mockApp = $this->getMock('\Ratchet\MessageComponentInterface');
|
||||||
|
|
||||||
$server = new WsServer($mockApp);
|
$server = new HttpServer(new WsServer($mockApp));
|
||||||
$server->onOpen($mockConn);
|
$server->onOpen($mockConn);
|
||||||
$server->onMessage($mockConn, $headers);
|
$server->onMessage($mockConn, $headers);
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Version;
|
namespace Ratchet\WebSocket\Version;
|
||||||
use Ratchet\WebSocket\Version\HyBi10;
|
use Ratchet\WebSocket\Version\HyBi10;
|
||||||
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Version\RFC6455;
|
namespace Ratchet\WebSocket\Version\RFC6455;
|
||||||
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Version\RFC6455;
|
namespace Ratchet\WebSocket\Version\RFC6455;
|
||||||
use Ratchet\WebSocket\Version\RFC6455\HandshakeVerifier;
|
use Ratchet\WebSocket\Version\RFC6455\HandshakeVerifier;
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Version\RFC6455\Message;
|
namespace Ratchet\WebSocket\Version\RFC6455\Message;
|
||||||
use Ratchet\WebSocket\Version\RFC6455\Message;
|
use Ratchet\WebSocket\Version\RFC6455\Message;
|
||||||
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket\Version;
|
namespace Ratchet\WebSocket\Version;
|
||||||
use Ratchet\WebSocket\Version\RFC6455;
|
use Ratchet\WebSocket\Version\RFC6455;
|
||||||
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
use Ratchet\WebSocket\Version\RFC6455\Frame;
|
||||||
use Guzzle\Http\Message\RequestFactory;
|
use Guzzle\Http\Message\RequestFactory;
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket;
|
namespace Ratchet\WebSocket;
|
||||||
use Ratchet\WebSocket\VersionManager;
|
use Ratchet\WebSocket\VersionManager;
|
||||||
use Ratchet\WebSocket\Version\RFC6455;
|
use Ratchet\WebSocket\Version\RFC6455;
|
||||||
use Ratchet\WebSocket\Version\HyBi10;
|
use Ratchet\WebSocket\Version\HyBi10;
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Tests\WebSocket;
|
namespace Ratchet\WebSocket;
|
||||||
use Ratchet\WebSocket\WsServer;
|
use Ratchet\WebSocket\WsServer;
|
||||||
use Ratchet\Tests\Mock\Component as MockComponent;
|
use Ratchet\Mock\Component as MockComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Ratchet\WebSocket\WsServer
|
* @covers Ratchet\WebSocket\WsServer
|
||||||
@ -27,10 +27,11 @@ class WsServerTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
public function protocolProvider() {
|
public function protocolProvider() {
|
||||||
return array(
|
return array(
|
||||||
array('hello,world', array('hello', 'world'), array('hello', 'world'))
|
array('hello', array('hello', 'world'), array('hello', 'world'))
|
||||||
, array('', array('hello', 'world'), array('wamp'))
|
, array('', array('hello', 'world'), array('wamp'))
|
||||||
, array('', array(), null)
|
, array('', array(), null)
|
||||||
, array('wamp', array('hello', 'wamp', 'world'), array('herp', 'derp', 'wamp'))
|
, array('wamp', array('hello', 'wamp', 'world'), array('herp', 'derp', 'wamp'))
|
||||||
|
, array('wamp', array('wamp'), array('wamp'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user