Browse Source

Files Created

pull/14/merge
Amir 8 years ago
parent
commit
04459364f0
  1. 179
      comm.php
  2. 2
      config.php
  3. 232
      css/comm.css
  4. BIN
      img/favicon.ico
  5. BIN
      img/vidbg.PNG
  6. 34
      index.php
  7. 1980
      js/adapter.js
  8. 1027
      js/comm.js
  9. BIN
      media/callertone.mp3
  10. BIN
      media/msgtone.mp3
  11. 195
      ws/bin/amir/Comm.php
  12. 25
      ws/bin/server.php
  13. 11
      ws/composer.json
  14. 691
      ws/composer.lock
  15. 7
      ws/vendor/autoload.php
  16. 5
      ws/vendor/cboden/ratchet/.gitignore
  17. 13
      ws/vendor/cboden/ratchet/.travis.yml
  18. 134
      ws/vendor/cboden/ratchet/CHANGELOG.md
  19. 19
      ws/vendor/cboden/ratchet/LICENSE
  20. 35
      ws/vendor/cboden/ratchet/Makefile
  21. 90
      ws/vendor/cboden/ratchet/README.md
  22. 32
      ws/vendor/cboden/ratchet/composer.json
  23. 30
      ws/vendor/cboden/ratchet/phpunit.xml.dist
  24. 41
      ws/vendor/cboden/ratchet/src/Ratchet/AbstractConnectionDecorator.php
  25. 146
      ws/vendor/cboden/ratchet/src/Ratchet/App.php
  26. 31
      ws/vendor/cboden/ratchet/src/Ratchet/ComponentInterface.php
  27. 26
      ws/vendor/cboden/ratchet/src/Ratchet/ConnectionInterface.php
  28. 34
      ws/vendor/cboden/ratchet/src/Ratchet/Http/Guzzle/Http/Message/RequestFactory.php
  29. 56
      ws/vendor/cboden/ratchet/src/Ratchet/Http/HttpRequestParser.php
  30. 90
      ws/vendor/cboden/ratchet/src/Ratchet/Http/HttpServer.php
  31. 14
      ws/vendor/cboden/ratchet/src/Ratchet/Http/HttpServerInterface.php
  32. 79
      ws/vendor/cboden/ratchet/src/Ratchet/Http/OriginCheck.php
  33. 105
      ws/vendor/cboden/ratchet/src/Ratchet/Http/Router.php
  34. 5
      ws/vendor/cboden/ratchet/src/Ratchet/MessageComponentInterface.php
  35. 12
      ws/vendor/cboden/ratchet/src/Ratchet/MessageInterface.php
  36. 23
      ws/vendor/cboden/ratchet/src/Ratchet/Server/EchoServer.php
  37. 200
      ws/vendor/cboden/ratchet/src/Ratchet/Server/FlashPolicy.php
  38. 38
      ws/vendor/cboden/ratchet/src/Ratchet/Server/IoConnection.php
  39. 141
      ws/vendor/cboden/ratchet/src/Ratchet/Server/IoServer.php
  40. 111
      ws/vendor/cboden/ratchet/src/Ratchet/Server/IpBlackList.php
  41. 16
      ws/vendor/cboden/ratchet/src/Ratchet/Session/Serialize/HandlerInterface.php
  42. 33
      ws/vendor/cboden/ratchet/src/Ratchet/Session/Serialize/PhpBinaryHandler.php
  43. 49
      ws/vendor/cboden/ratchet/src/Ratchet/Session/Serialize/PhpHandler.php
  44. 161
      ws/vendor/cboden/ratchet/src/Ratchet/Session/SessionProvider.php
  45. 54
      ws/vendor/cboden/ratchet/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php
  46. 88
      ws/vendor/cboden/ratchet/src/Ratchet/Session/Storage/VirtualSessionStorage.php
  47. 5
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/Exception.php
  48. 31
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/JsonException.php
  49. 157
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/ServerProtocol.php
  50. 106
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/Topic.php
  51. 125
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/TopicManager.php
  52. 115
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/WampConnection.php
  53. 67
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/WampServer.php
  54. 43
      ws/vendor/cboden/ratchet/src/Ratchet/Wamp/WampServerInterface.php
  55. 31
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Encoding/ToggleableValidator.php
  56. 93
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Encoding/Validator.php
  57. 12
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Encoding/ValidatorInterface.php
  58. 28
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/DataInterface.php
  59. 38
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/FrameInterface.php
  60. 120
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/Hixie76.php
  61. 26
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/Hixie76/Connection.php
  62. 86
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/Hixie76/Frame.php
  63. 15
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/HyBi10.php
  64. 15
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/MessageInterface.php
  65. 273
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455.php
  66. 44
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/Connection.php
  67. 451
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/Frame.php
  68. 137
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/HandshakeVerifier.php
  69. 107
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/Message.php
  70. 57
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/VersionInterface.php
  71. 90
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/VersionManager.php
  72. 232
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/WsServer.php
  73. 14
      ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/WsServerInterface.php
  74. 17
      ws/vendor/cboden/ratchet/tests/autobahn/bin/fuzzingserver-noutf8.php
  75. 15
      ws/vendor/cboden/ratchet/tests/autobahn/bin/fuzzingserver.php
  76. 16
      ws/vendor/cboden/ratchet/tests/autobahn/fuzzingclient-all.json
  77. 12
      ws/vendor/cboden/ratchet/tests/autobahn/fuzzingclient-profile.json
  78. 12
      ws/vendor/cboden/ratchet/tests/autobahn/fuzzingclient-quick.json
  79. 4
      ws/vendor/cboden/ratchet/tests/bootstrap.php
  80. 50
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/AbstractMessageComponentTestCase.php
  81. 35
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/Component.php
  82. 20
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/Connection.php
  83. 22
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/ConnectionDecorator.php
  84. 43
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/WampComponent.php
  85. 28
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/NullComponent.php
  86. 7
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Wamp/Stub/WsWampServerInterface.php
  87. 7
      ws/vendor/cboden/ratchet/tests/helpers/Ratchet/WebSocket/Stub/WsMessageComponentInterface.php
  88. 53
      ws/vendor/cboden/ratchet/tests/integration/GuzzleTest.php
  89. 147
      ws/vendor/cboden/ratchet/tests/unit/AbstractConnectionDecoratorTest.php
  90. 67
      ws/vendor/cboden/ratchet/tests/unit/Http/Guzzle/Http/Message/RequestFactoryTest.php
  91. 51
      ws/vendor/cboden/ratchet/tests/unit/Http/HttpRequestParserTest.php
  92. 64
      ws/vendor/cboden/ratchet/tests/unit/Http/HttpServerTest.php
  93. 46
      ws/vendor/cboden/ratchet/tests/unit/Http/OriginCheckTest.php
  94. 140
      ws/vendor/cboden/ratchet/tests/unit/Http/RouterTest.php
  95. 26
      ws/vendor/cboden/ratchet/tests/unit/Server/EchoServerTest.php
  96. 152
      ws/vendor/cboden/ratchet/tests/unit/Server/FlashPolicyComponentTest.php
  97. 32
      ws/vendor/cboden/ratchet/tests/unit/Server/IoConnectionTest.php
  98. 118
      ws/vendor/cboden/ratchet/tests/unit/Server/IoServerTest.php
  99. 125
      ws/vendor/cboden/ratchet/tests/unit/Server/IpBlackListComponentTest.php
  100. 43
      ws/vendor/cboden/ratchet/tests/unit/Session/Serialize/PhpHandlerTest.php
  101. Some files were not shown because too many files have changed in this diff Show More

179
comm.php

@ -0,0 +1,179 @@ @@ -0,0 +1,179 @@
<?php
require_once 'config.php';
/**
* @fileName comm
* @author Amir <amirsanni@gmail.com>
* @date 22-Dec-2016
*/
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chat App</title>
<!-- Favicon -->
<link rel="shortcut icon" href="img/favicon.ico">
<!-- favicon ends -->
<!--- LOAD FILES -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome-animation/0.0.8/font-awesome-animation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- Custom styles -->
<link rel="stylesheet" href="css/comm.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.3/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container-fluid">
<div class="row">
<!-- Remote Video -->
<video id="peerVid" poster="img/vidbg.png" playsinline autoplay></video>
<!-- Remote Video -->
</div>
<div class="row margin-top-20">
<!-- Call Buttons -->
<div class="col-sm-12 text-center" id="callBtns">
<button class="btn btn-success btn-sm initCall" id="initAudio"><i class="fa fa-phone"></i></button>
<button class="btn btn-info btn-sm initCall" id="initVideo"><i class="fa fa-video-camera"></i></button>
<button class="btn btn-danger btn-sm" id="terminateCall" disabled><i class="fa fa-phone-square"></i></button>
</div>
<!-- Call Buttons -->
<!-- Timer -->
<div class="col-sm-12 text-center margin-top-5" style="color:#fff">
<span id="countHr"></span>h:
<span id="countMin"></span>m:
<span id="countSec"></span>s
</div>
<!-- Timer -->
</div>
<!-- Local Video -->
<div class="row">
<div class="col-sm-12">
<video id="myVid" poster="img/vidbg.png" muted autoplay></video>
</div>
</div>
<!-- Local Video -->
</div>
<div class="container-fluid chat-pane">
<!-- CHAT PANEL-->
<div class="row chat-window col-xs-12 col-md-4">
<div class="">
<div class="panel panel-default chat-pane-panel">
<div class="panel-heading chat-pane-top-bar">
<div class="col-xs-10" style="margin-left:-20px">
<i class="fa fa-comment" id="remoteStatus"></i> Remote
<b id="remoteStatusTxt">(Offline)</b>
</div>
<div class="col-xs-2 pull-right">
<span id="minim_chat_window" class="panel-collapsed fa fa-plus icon_minim pointer"></span>
</div>
</div>
<div class="panel-body msg_container_base" id="chats"></div>
<div class="panel-footer">
<span id="typingInfo"></span>
<div class="input-group">
<input id="chatInput" type="text" class="form-control input-sm chat_input" placeholder="Type message here...">
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="chatSendBtn">Send</button>
</span>
</div>
</div>
</div>
</div>
</div>
<!-- CHAT PANEL -->
</div>
<!--Modal to show that we are calling-->
<div id="callModal" class="modal fade" role="dialog" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content text-center">
<div class="modal-header" id="callerInfo"></div>
<div class="modal-body">
<button type="button" class="btn btn-danger btn-sm" id='endCall'>
<i class="fa fa-times-circle"></i> End Call
</button>
</div>
</div>
</div>
</div>
<!--Modal end-->
<!--Modal to give options to receive call-->
<div id="rcivModal" class="modal fade" role="dialog" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" id="calleeInfo"></div>
<div class="modal-body text-center">
<button type="button" class="btn btn-success btn-sm answerCall" id='startAudio'>
<i class="fa fa-phone"></i> Audio Call
</button>
<button type="button" class="btn btn-success btn-sm answerCall" id='startVideo'>
<i class="fa fa-video-camera"></i> Video Call
</button>
<button type="button" class="btn btn-danger btn-sm" id='rejectCall'>
<i class="fa fa-times-circle"></i> Reject Call
</button>
</div>
</div>
</div>
</div>
<!--Modal end-->
<!--Modal to show flash message-->
<div id="flashMsgModal" class="modal fade" role="dialog" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" id="flashMsgHeader">
<button type="button" class="close" id='closeFlashMsg' data-dismiss="modal">&times;</button>
<center><i id="flashMsgIcon"></i> <font id="flashMsg"></font></center>
</div>
</div>
</div>
</div>
<!--Modal end-->
<!--Snackbar -->
<div id="snackbar"></div>
<!-- Snackbar -->
<!-- custom js -->
<script>
var room = "<?=filter_input(INPUT_GET, 'room')?>";
var wsChat = new WebSocket("<?=WS_URL?>");
</script>
<script src="js/adapter.js"></script>
<script src="js/comm.js"></script>
<audio id="callerTone" src="media/callertone.mp3" loop preload="auto"></audio>
<audio id="msgTone" src="media/msgtone.mp3" preload="auto"></audio>
</body>
</html>

2
config.php

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
<?php
define('WS_URL', 'ws://localhost:8080/comm');

232
css/comm.css

@ -0,0 +1,232 @@ @@ -0,0 +1,232 @@
/*
Created on : 22-Dec-2016
Author : Amir <amirsanni@gmail.com>
*/
.margin-top-20{
margin-top: 20px;
}
.pointer{
cursor: pointer;
}
/* CHAT PANE */
#typingInfo{
font-size: 10px;
color: #3a87ad;
}
.col-md-4, .col-md-10{
padding:0;
}
.chat-pane-panel{
margin-bottom: 0px;
}
.chat-window{
bottom:0;
position:fixed;
}
.chat-pane-panel{
border-radius: 5px 5px 0 0;
}
.icon_minim{
padding:2px 10px;
}
.msg_container_base{
background: #e5e5e5;
margin: 0;
padding: 0 10px 10px;
max-height:300px;
overflow-x:hidden;
display: none;
}
.chat-pane-top-bar {
background: #666;
color: white;
position: relative;
overflow: hidden;
}
.msg_receive{
padding-left:0;
margin-left:0;
}
.msg_sent{
padding-bottom:20px !important;
margin-right:0;
}
.messages {
background: white;
padding: 10px;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
max-width:100%;
}
.messages > p {
font-size: 13px;
margin: 0 0 0.2rem 0;
word-wrap: break-word
}
.messages > time {
font-size: 11px;
color: #ccc;
}
.msg_container {
padding: 10px;
overflow: hidden;
display: flex;
}
.chat-pane-img {
display: block;
width: 100%;
}
.chat-avatar {
position: relative;
}
.base_receive > .chat-avatar:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 0;
height: 0;
border: 5px solid #FFF;
border-left-color: rgba(0, 0, 0, 0);
border-bottom-color: rgba(0, 0, 0, 0);
}
.base_sent {
justify-content: flex-end;
align-items: flex-end;
}
.base_sent > .chat-avatar:after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 0;
border: 5px solid white;
border-right-color: transparent;
border-top-color: transparent;
box-shadow: 1px 1px 2px rgba(black, 0.2); /*not quite perfect but close*/
}
.msg_sent > time{
float: right;
}
.msg_container_base::-webkit-scrollbar-track
{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
background-color: #F5F5F5;
}
.msg_container_base::-webkit-scrollbar
{
width: 12px;
background-color: #F5F5F5;
}
.msg_container_base::-webkit-scrollbar-thumb
{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #555;
}
/* _CHAT PANE */
/*
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
*/
/* VIDEO */
#peerVid{
position: fixed;
top: 50%;
left: 50%;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -100;
-ms-transform: translateX(-50%) translateY(-50%);
-moz-transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
background: url(../img/vidbg.png) no-repeat;
background-size: cover;
}
#myVid{
width: 300px;
height: 200px;
bottom: 0;
position: fixed;
right: 0;
}
/* Small screens */
@media(max-width:768px){
#myVid{
width: 200px;
height: 100px;
bottom: 100px;
position: fixed;
left: 0;
}
}
/* _VIDEO */
/* SNACKBAR */
/* The snackbar - position it at the bottom and in the middle of the screen */
#snackbar {
visibility: hidden; /* Hidden by default. Visible on click */
min-width: 250px; /* Set a default minimum width */
margin-left: -125px; /* Divide value of min-width by 2 */
background-color: rgba(158,31,99,0.9); /* background color */
color: #fff; /* White text color */
text-align: center; /* Centered text */
border-radius: 2px; /* Rounded borders */
padding: 16px; /* Padding */
position: fixed; /* Sit on top of the screen */
z-index: 1; /* Add a z-index if needed */
right: 0; /* Right the snackbar */
top: 90px; /* 90px from the top */
}
/* Show the snackbar when clicking on a button (class added with JavaScript) */
#snackbar.show {
visibility: visible; /* Show the snackbar */
}
/* Animations to fade the snackbar in and out */
@-webkit-keyframes fadein {
from {right: 0; opacity: 0;}
to {top: 90px; opacity: 1;}
}
@keyframes fadein {
from {right: 0; opacity: 0;}
to {top: 90px; opacity: 1;}
}
@-webkit-keyframes fadeout {
from {top: 90px; opacity: 1;}
to {right: 0; opacity: 0;}
}
@keyframes fadeout {
from {top: 90px; opacity: 1;}
to {right: 0; opacity: 0;}
}
/* _SNACKBAR */

BIN
img/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
img/vidbg.PNG

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

34
index.php

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
<?php
/**
* @fileName index.php
* @author Amir <amirsanni@gmail.com>
* @date 22-Dec-2016
*/
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chat App</title>
<!-- Favicon -->
<link rel="shortcut icon" href="img/favicon.ico">
<!-- favicon ends -->
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.3/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<input type="button" id='createRoom'>
</body>
</html>

1980
js/adapter.js

File diff suppressed because it is too large Load Diff

1027
js/comm.js

File diff suppressed because it is too large Load Diff

BIN
media/callertone.mp3

Binary file not shown.

BIN
media/msgtone.mp3

Binary file not shown.

195
ws/bin/amir/Comm.php

@ -0,0 +1,195 @@ @@ -0,0 +1,195 @@
<?php
namespace Amir;
/**
* Description of Comm
*
* @author Amir <amirsanni@gmail.com>
* @date 26-Oct-2016
*/
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Comm implements MessageComponentInterface {
protected $clients;
private $rooms;
public function __construct() {
$this->clients = new \SplObjectStorage;
$this->rooms = [];
}
/*
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
*/
/**
*
* @param ConnectionInterface $conn
*/
public function onOpen(ConnectionInterface $conn) {
// Store the new connection
$this->clients->attach($conn);
}
/*
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
*/
/**
*
* @param ConnectionInterface $from
* @param type $msg
*/
public function onMessage(ConnectionInterface $from, $msg) {
$data = json_decode($msg);
$action = $data->action;
$room = isset($data->room) ? $data->room : "";
if(($action == 'subscribe') && $room){
//subscribe user to room only if he hasn't subscribed
//if room exist and user is yet to subscribe, then subscibe him to room
//OR
//if room does not exist, create it by adding user to it
if((array_key_exists($room, $this->rooms) && !in_array($from, $this->rooms[$room])) || !array_key_exists($room, $this->rooms)){
if(isset($this->rooms[$room]) && count($this->rooms[$room]) >= 2){
//maximum number of connection reached
$msg_to_send = json_encode(['action'=>'subRejected']);
$from->send($msg_to_send);
}
else{
$this->rooms[$room][] = $from;//subscribe user to room
$this->notifyUsersOfConnection($room, $from);
}
}
else{
//tell user he has subscribed on another device/browser
$msg_to_send = json_encode(['action'=>'subRejected']);
$from->send($msg_to_send);
}
}
//for other actions
else if($room && isset($this->rooms[$room])){
//send to everybody subscribed to the room received except the sender
foreach($this->rooms[$room] as $client){
if ($client !== $from) {
$client->send($msg);
}
}
}
}
/*
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
*/
/**
*
* @param ConnectionInterface $conn
*/
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove connection
$this->clients->detach($conn);
if(count($this->rooms)){//if there is at least one room created
foreach($this->rooms as $room=>$arr_of_subscribers){//loop through the rooms
foreach ($arr_of_subscribers as $key=>$ratchet_conn){//loop through the users connected to each room
if($ratchet_conn == $conn){//if the disconnecting user subscribed to this room
unset($this->rooms[$room][$key]);//remove him from the room
//notify other subscribers that he has disconnected
$this->notifyUsersOfDisconnection($room, $conn);
echo 'user left';
}
}
}
}
}
/*
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
*/
/**
*
* @param ConnectionInterface $conn
* @param \Exception $e
*/
public function onError(ConnectionInterface $conn, \Exception $e) {
//echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
/*
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
*/
/**
*
* @param type $room
* @param type $from
*/
private function notifyUsersOfConnection($room, $from){
//echo "User subscribed to room ".$room ."\n";
$msg_to_broadcast = json_encode(['action'=>'newSub', 'room'=>$room]);
//notify user that someone has joined room
foreach($this->rooms[$room] as $client){
if ($client !== $from) {
$client->send($msg_to_broadcast);
}
}
}
/*
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
*/
private function notifyUsersOfDisconnection($room, $from){
$msg_to_broadcast = json_encode(['action'=>'imOffline', 'room'=>$room]);
//notify user that remote has left the room
foreach($this->rooms[$room] as $client){
if ($client !== $from) {
$client->send($msg_to_broadcast);
}
}
}
}

25
ws/bin/server.php

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
<?php
/**
* Description of server
*
* @author Amir <amirsanni@gmail.com>
* @date 23-Dec-2016
*/
require '../vendor/autoload.php';
use Amir\Comm;
//set an array of origins allowed to connect to this server
$allowed_origins = ['localhost', '127.0.0.1'];
// Run the server application through the WebSocket protocol on port 8080
$app = new Ratchet\App('localhost', 8080, '0.0.0.0');//App(hostname, port, 'whoCanConnectIP', '')
//create socket routes
//route(uri, classInstance, arrOfAllowedOrigins)
$app->route('/comm', new Comm, $allowed_origins);
//run websocket
$app->run();

11
ws/composer.json

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
{
"require":{
"cboden/ratchet" : "0.3.*"
},
"autoload": {
"psr-4": {
"Amir\\": "bin/amir/"
}
}
}

691
ws/composer.lock generated

@ -0,0 +1,691 @@ @@ -0,0 +1,691 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "762037d3d8d94aec831d234f71791628",
"content-hash": "858ccf2b00629904fbfcaf8568d3cb4b",
"packages": [
{
"name": "cboden/ratchet",
"version": "v0.3.5",
"source": {
"type": "git",
"url": "https://github.com/ratchetphp/Ratchet.git",
"reference": "b5ccecad9390db85d2c8df7cbeb047292fbbf4b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ratchetphp/Ratchet/zipball/b5ccecad9390db85d2c8df7cbeb047292fbbf4b8",
"reference": "b5ccecad9390db85d2c8df7cbeb047292fbbf4b8",
"shasum": ""
},
"require": {
"guzzle/http": "^3.6",
"php": ">=5.3.9",
"react/socket": "^0.3 || ^0.4",
"symfony/http-foundation": "^2.2|^3.0",
"symfony/routing": "^2.2|^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Ratchet\\": "src/Ratchet"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Boden",
"email": "cboden@gmail.com",
"role": "Developer"
}
],
"description": "PHP WebSocket library",
"homepage": "http://socketo.me",
"keywords": [
"Ratchet",
"WebSockets",
"server",
"sockets"
],
"time": "2016-05-25 12:55:03"
},
{
"name": "evenement/evenement",
"version": "v2.0.0",
"source": {
"type": "git",
"url": "https://github.com/igorw/evenement.git",
"reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e",
"reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-0": {
"Evenement": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch",
"homepage": "http://wiedler.ch/igor/"
}
],
"description": "Événement is a very simple event dispatching library for PHP",
"keywords": [
"event-dispatcher",
"event-emitter"
],
"time": "2012-11-02 14:49:47"
},
{
"name": "guzzle/common",
"version": "v3.9.2",
"target-dir": "Guzzle/Common",
"source": {
"type": "git",
"url": "https://github.com/Guzzle3/common.git",
"reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Guzzle3/common/zipball/2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc",
"reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc",
"shasum": ""
},
"require": {
"php": ">=5.3.2",
"symfony/event-dispatcher": ">=2.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.7-dev"
}
},
"autoload": {
"psr-0": {
"Guzzle\\Common": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Common libraries used by Guzzle",
"homepage": "http://guzzlephp.org/",
"keywords": [
"collection",
"common",
"event",
"exception"
],
"abandoned": "guzzle/guzzle",
"time": "2014-08-11 04:32:36"
},
{
"name": "guzzle/http",
"version": "v3.9.2",
"target-dir": "Guzzle/Http",
"source": {
"type": "git",
"url": "https://github.com/Guzzle3/http.git",
"reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Guzzle3/http/zipball/1e8dd1e2ba9dc42332396f39fbfab950b2301dc5",
"reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5",
"shasum": ""
},
"require": {
"guzzle/common": "self.version",
"guzzle/parser": "self.version",
"guzzle/stream": "self.version",
"php": ">=5.3.2"
},
"suggest": {
"ext-curl": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.7-dev"
}
},
"autoload": {
"psr-0": {
"Guzzle\\Http": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "HTTP libraries used by Guzzle",
"homepage": "http://guzzlephp.org/",
"keywords": [
"Guzzle",
"client",
"curl",
"http",
"http client"
],
"abandoned": "guzzle/guzzle",
"time": "2014-08-11 04:32:36"
},
{
"name": "guzzle/parser",
"version": "v3.9.2",
"target-dir": "Guzzle/Parser",
"source": {
"type": "git",
"url": "https://github.com/Guzzle3/parser.git",
"reference": "6874d171318a8e93eb6d224cf85e4678490b625c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Guzzle3/parser/zipball/6874d171318a8e93eb6d224cf85e4678490b625c",
"reference": "6874d171318a8e93eb6d224cf85e4678490b625c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.7-dev"
}
},
"autoload": {
"psr-0": {
"Guzzle\\Parser": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Interchangeable parsers used by Guzzle",
"homepage": "http://guzzlephp.org/",
"keywords": [
"URI Template",
"cookie",
"http",
"message",
"url"
],
"abandoned": "guzzle/guzzle",
"time": "2014-02-05 18:29:46"
},
{
"name": "guzzle/stream",
"version": "v3.9.2",
"target-dir": "Guzzle/Stream",
"source": {
"type": "git",
"url": "https://github.com/Guzzle3/stream.git",
"reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Guzzle3/stream/zipball/60c7fed02e98d2c518dae8f97874c8f4622100f0",
"reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0",
"shasum": ""
},
"require": {
"guzzle/common": "self.version",
"php": ">=5.3.2"
},
"suggest": {
"guzzle/http": "To convert Guzzle request objects to PHP streams"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.7-dev"
}
},
"autoload": {
"psr-0": {
"Guzzle\\Stream": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle stream wrapper component",
"homepage": "http://guzzlephp.org/",
"keywords": [
"Guzzle",
"component",
"stream"
],
"abandoned": "guzzle/guzzle",
"time": "2014-05-01 21:36:02"
},
{
"name": "react/event-loop",
"version": "v0.4.2",
"source": {
"type": "git",
"url": "https://github.com/reactphp/event-loop.git",
"reference": "164799f73175e1c80bba92a220ea35df6ca371dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/event-loop/zipball/164799f73175e1c80bba92a220ea35df6ca371dd",
"reference": "164799f73175e1c80bba92a220ea35df6ca371dd",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"suggest": {
"ext-event": "~1.0",
"ext-libev": "*",
"ext-libevent": ">=0.1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.5-dev"
}
},
"autoload": {
"psr-4": {
"React\\EventLoop\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Event loop abstraction layer that libraries can use for evented I/O.",
"keywords": [
"asynchronous",
"event-loop"
],
"time": "2016-03-08 02:09:32"
},
{
"name": "react/socket",
"version": "v0.4.3",
"source": {
"type": "git",
"url": "https://github.com/reactphp/socket.git",
"reference": "ce015ec5879b96f5d30905f035f223aa85013fcc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/socket/zipball/ce015ec5879b96f5d30905f035f223aa85013fcc",
"reference": "ce015ec5879b96f5d30905f035f223aa85013fcc",
"shasum": ""
},
"require": {
"evenement/evenement": "~2.0|~1.0",
"php": ">=5.3.0",
"react/event-loop": "0.4.*|0.3.*",
"react/stream": "0.4.*|0.3.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.4-dev"
}
},
"autoload": {
"psr-4": {
"React\\Socket\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Library for building an evented socket server.",
"keywords": [
"Socket"
],
"time": "2016-03-01 20:10:35"
},
{
"name": "react/stream",
"version": "v0.4.4",
"source": {
"type": "git",
"url": "https://github.com/reactphp/stream.git",
"reference": "fcc9e7cea126962cff303c90c05e2efdcec09a27"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/stream/zipball/fcc9e7cea126962cff303c90c05e2efdcec09a27",
"reference": "fcc9e7cea126962cff303c90c05e2efdcec09a27",
"shasum": ""
},
"require": {
"evenement/evenement": "^2.0|^1.0",
"php": ">=5.3.8"
},
"require-dev": {
"clue/stream-filter": "~1.2",
"react/event-loop": "^0.4|^0.3",
"react/promise": "^2.0|^1.0"
},
"suggest": {
"react/event-loop": "^0.4",
"react/promise": "^2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Stream\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Basic readable and writable stream interfaces that support piping.",
"keywords": [
"pipe",
"stream"
],
"time": "2016-08-22 09:51:07"
},
{
"name": "symfony/event-dispatcher",
"version": "v3.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/28b0832b2553ffb80cabef6a7a812ff1e670c0bc",
"reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~2.8|~3.0",
"symfony/dependency-injection": "~2.8|~3.0",
"symfony/expression-language": "~2.8|~3.0",
"symfony/stopwatch": "~2.8|~3.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2016-10-13 06:28:43"
},
{
"name": "symfony/http-foundation",
"version": "v3.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "f21e5a8b88274b7720779aa88f9c02c6d6ec08d7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/f21e5a8b88274b7720779aa88f9c02c6d6ec08d7",
"reference": "f21e5a8b88274b7720779aa88f9c02c6d6ec08d7",
"shasum": ""
},
"require": {
"php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.1"
},
"require-dev": {
"symfony/expression-language": "~2.8|~3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpFoundation\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
"time": "2016-10-24 15:52:44"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "dff51f72b0706335131b00a7f49606168c582594"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
"reference": "dff51f72b0706335131b00a7f49606168c582594",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"time": "2016-05-18 14:26:46"
},
{
"name": "symfony/routing",
"version": "v3.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/8edf62498a1a4c57ba317664a4b698339c10cdf6",
"reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"conflict": {
"symfony/config": "<2.8"
},
"require-dev": {
"doctrine/annotations": "~1.0",
"doctrine/common": "~2.2",
"psr/log": "~1.0",
"symfony/config": "~2.8|~3.0",
"symfony/expression-language": "~2.8|~3.0",
"symfony/http-foundation": "~2.8|~3.0",
"symfony/yaml": "~2.8|~3.0"
},
"suggest": {
"doctrine/annotations": "For using the annotation loader",
"symfony/config": "For using the all-in-one router or any loader",
"symfony/dependency-injection": "For loading routes from a service",
"symfony/expression-language": "For using expression matching",
"symfony/http-foundation": "For using a Symfony Request object",
"symfony/yaml": "For using the YAML loader"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Routing\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Routing Component",
"homepage": "https://symfony.com",
"keywords": [
"router",
"routing",
"uri",
"url"
],
"time": "2016-08-16 14:58:24"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}

7
ws/vendor/autoload.php vendored

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInita3d708ca3bb0f3f4e817238e4fb57153::getLoader();

5
ws/vendor/cboden/ratchet/.gitignore vendored

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
phpunit.xml
reports
sandbox
vendor
composer.lock

13
ws/vendor/cboden/ratchet/.travis.yml vendored

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7
- hhvm
before_script:
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "session.serialize_handler = php" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
- composer install --dev --prefer-source

134
ws/vendor/cboden/ratchet/CHANGELOG.md vendored

@ -0,0 +1,134 @@ @@ -0,0 +1,134 @@
CHANGELOG
=========
###Legend
* "BC": Backwards compatibility break (from public component APIs)
* "BF": Bug fix
---
* 0.3.5 (2016-05-25)
* BF: Unmask responding close frame
* Added write handler for PHP session serializer
* 0.3.4 (2015-12-23)
* BF: Edge case where version check wasn't run on message coalesce
* BF: Session didn't start when using pdo_sqlite
* BF: WAMP currie prefix check when using '#'
* Compatibility with Symfony 3
* 0.3.3 (2015-05-26)
* BF: Framing bug on large messages upon TCP fragmentation
* BF: Symfony Router query parameter defaults applied to Request
* BF: WAMP CURIE on all URIs
* OriginCheck rules applied to FlashPolicy
* Switched from PSR-0 to PSR-4
* 0.3.2 (2014-06-08)
* BF: No messages after closing handshake (fixed rare race condition causing 100% CPU)
* BF: Fixed accidental BC break from v0.3.1
* Added autoDelete parameter to Topic to destroy when empty of connections
* Exposed React Socket on IoServer (allowing FlashPolicy shutdown in App)
* Normalized Exceptions in WAMP
* 0.3.1 (2014-05-26)
* Added query parameter support to Router, set in HTTP request (ws://server?hello=world)
* HHVM compatibility
* BF: React/0.4 support; CPU starvation bug fixes
* BF: Allow App::route to ignore Host header
* Added expected filters to WAMP Topic broadcast method
* Resource cleanup in WAMP TopicManager
* 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)
* React 0.3 support
* 0.2.7 (2013-06-09)
* BF: Sub-protocol negotation with Guzzle 3.6
* 0.2.6 (2013-06-01)
* Guzzle 3.6 support
* 0.2.5 (2013-04-01)
* Fixed Hixie-76 handshake bug
* 0.2.4 (2013-03-09)
* Support for Symfony 2.2 and Guzzle 2.3
* Minor bug fixes when handling errors
* 0.2.3 (2012-11-21)
* Bumped dep: Guzzle to v3, React to v0.2.4
* More tests
* 0.2.2 (2012-10-20)
* Bumped deps to use React v0.2
* 0.2.1 (2012-10-13)
* BF: No more UTF-8 warnings in browsers (no longer sending empty sub-protocol string)
* Documentation corrections
* Using new composer structure
* 0.2 (2012-09-07)
* Ratchet passes every non-binary-frame test from the Autobahn Testsuite
* Major performance improvements
* BC: Renamed "WampServer" to "ServerProtocol"
* BC: New "WampServer" component passes Topic container objects of subscribed Connections
* Option to turn off UTF-8 checks in order to increase performance
* Switched dependency guzzle/guzzle to guzzle/http (no API changes)
* mbstring no longer required
* 0.1.5 (2012-07-12)
* BF: Error where service wouldn't run on PHP <= 5.3.8
* Dependency library updates
* 0.1.4 (2012-06-17)
* Fixed dozens of failing AB tests
* BF: Proper socket buffer handling
* 0.1.3 (2012-06-15)
* Major refactor inside WebSocket protocol handling, more loosley coupled
* BF: Proper error handling on failed WebSocket connections
* BF: Handle TCP message concatenation
* Inclusion of the AutobahnTestSuite checking WebSocket protocol compliance
* mb_string now a requirement
* 0.1.2 (2012-05-19)
* BC/BF: Updated WAMP API to coincide with the official spec
* Tweaks to improve running as a long lived process
* 0.1.1 (2012-05-14)
* Separated interfaces allowing WebSockets to support multiple sub protocols
* BF: remoteAddress variable on connections returns proper value
* 0.1 (2012-05-11)
* First release with components: IoServer, WsServer, SessionProvider, WampServer, FlashPolicy, IpBlackList
* I/O now handled by React, making Ratchet fully asynchronous

19
ws/vendor/cboden/ratchet/LICENSE vendored

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
Copyright (c) 2011-2016 Chris Boden
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

35
ws/vendor/cboden/ratchet/Makefile vendored

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
# This file is intended to ease the author's development and testing process
# Users do not need to use `make`; Ratchet does not need to be compiled
test:
phpunit
cover:
phpunit --coverage-text --coverage-html=reports/coverage
abtests:
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8001 LibEvent &
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8002 StreamSelect &
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver-noutf8.php 8003 StreamSelect &
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8004 LibEv &
wstest -m testeeserver -w ws://localhost:8000 &
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-all.json
killall php wstest
abtest:
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8000 StreamSelect &
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-quick.json
killall php
profile:
php -d 'xdebug.profiler_enable=1' tests/autobahn/bin/fuzzingserver.php 8000 LibEvent &
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-profile.json
killall php
apidocs:
apigen --title Ratchet -d reports/api -s src/ \
-s vendor/react \
-s vendor/guzzle \
-s vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session \
-s vendor/symfony/routing/Symfony/Component/Routing \
-s vendor/evenement/evenement/src/Evenement

90
ws/vendor/cboden/ratchet/README.md vendored

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
#Ratchet
[![Build Status](https://secure.travis-ci.org/ratchetphp/Ratchet.png?branch=master)](http://travis-ci.org/ratchetphp/Ratchet)
[![Latest Stable Version](https://poser.pugx.org/cboden/ratchet/v/stable.png)](https://packagist.org/packages/cboden/ratchet)
A PHP 5.3 library for asynchronously serving WebSockets.
Build up your application through simple interfaces and re-use your application without changing any of its code just by combining different components.
##WebSocket Compliance
* Supports the RFC6455, HyBi-10+, and Hixie76 protocol versions (at the same time)
* Tested on Chrome 13+, Firefox 6+, Safari 5+, iOS 4.2+, IE 8+
* Ratchet [passes](http://socketo.me/reports/ab/) the [Autobahn Testsuite](http://autobahn.ws/testsuite) (non-binary messages)
##Requirements
Shell access is required and root access is recommended.
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.
You can find more details in the [server conf docs](http://socketo.me/docs/deploy#serverconfiguration).
PHP 5.3.9 (or higher) is required. If you have access, PHP 5.4 (or higher) is *highly* recommended for its performance improvements.
### Documentation
User and API documentation is available on Ratchet's website: http://socketo.me
See https://github.com/cboden/Ratchet-examples for some out-of-the-box working demos using Ratchet.
Need help? Have a question? Want to provide feedback? Write a message on the [Google Groups Mailing List](https://groups.google.com/forum/#!forum/ratchet-php).
---
###A quick example
```php
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
// Make sure composer dependencies have been installed
require __DIR__ . '/vendor/autoload.php';
/**
* chat.php
* Send any incoming messages to all connected clients (except sender)
*/
class MyChat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $from, $msg) {
foreach ($this->clients as $client) {
if ($from != $client) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$conn->close();
}
}
// Run the server application through the WebSocket protocol on port 8080
$app = new Ratchet\App('localhost', 8080);
$app->route('/chat', new MyChat);
$app->route('/echo', new Ratchet\Server\EchoServer, array('*'));
$app->run();
```
$ 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!');
```

32
ws/vendor/cboden/ratchet/composer.json vendored

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
{
"name": "cboden/ratchet"
, "type": "library"
, "description": "PHP WebSocket library"
, "keywords": ["WebSockets", "Server", "Ratchet", "Sockets"]
, "homepage": "http://socketo.me"
, "license": "MIT"
, "authors": [
{
"name": "Chris Boden"
, "email": "cboden@gmail.com"
, "role": "Developer"
}
]
, "support": {
"forum": "https://groups.google.com/forum/#!forum/ratchet-php"
, "issues": "https://github.com/ratchetphp/Ratchet/issues"
, "irc": "irc://irc.freenode.org/reactphp"
}
, "autoload": {
"psr-4": {
"Ratchet\\": "src/Ratchet"
}
}
, "require": {
"php": ">=5.3.9"
, "react/socket": "^0.3 || ^0.4"
, "guzzle/http": "^3.6"
, "symfony/http-foundation": "^2.2|^3.0"
, "symfony/routing": "^2.2|^3.0"
}
}

30
ws/vendor/cboden/ratchet/phpunit.xml.dist vendored

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
forceCoversAnnotation="true"
mapTestClassNameToCoveredClassName="true"
bootstrap="tests/bootstrap.php"
colors="true"
backupGlobals="false"
backupStaticAttributes="false"
syntaxCheck="false"
stopOnError="false"
>
<testsuites>
<testsuite name="unit">
<directory>./tests/unit/</directory>
</testsuite>
</testsuites>
<testsuites>
<testsuite name="integration">
<directory>./tests/integration/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/</directory>
</whitelist>
</filter>
</phpunit>

41
ws/vendor/cboden/ratchet/src/Ratchet/AbstractConnectionDecorator.php vendored

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
<?php
namespace Ratchet;
/**
* Wraps ConnectionInterface objects via the decorator pattern but allows
* parameters to bubble through with magic methods
* @todo It sure would be nice if I could make most of this a trait...
*/
abstract class AbstractConnectionDecorator implements ConnectionInterface {
/**
* @var ConnectionInterface
*/
protected $wrappedConn;
public function __construct(ConnectionInterface $conn) {
$this->wrappedConn = $conn;
}
/**
* @return ConnectionInterface
*/
protected function getConnection() {
return $this->wrappedConn;
}
public function __set($name, $value) {
$this->wrappedConn->$name = $value;
}
public function __get($name) {
return $this->wrappedConn->$name;
}
public function __isset($name) {
return isset($this->wrappedConn->$name);
}
public function __unset($name) {
unset($this->wrappedConn->$name);
}
}

146
ws/vendor/cboden/ratchet/src/Ratchet/App.php vendored

@ -0,0 +1,146 @@ @@ -0,0 +1,146 @@
<?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;
/***
* The port the socket is listening
* @var int
*/
protected $port;
/**
* @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')) {
trigger_error('XDebug extension detected. Remember to disable this if performance testing or going live!', E_USER_WARNING);
}
if (3 !== strlen('✓')) {
throw new \DomainException('Bad encoding, length of unicode character ✓ should be 3. Ensure charset UTF-8 and check ini val mbstring.func_autoload');
}
if (null === $loop) {
$loop = LoopFactory::create();
}
$this->httpHost = $httpHost;
$this->port = $port;
$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 endpoint/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;
}
if ($httpHost === null) {
$httpHost = $this->httpHost;
}
$allowedOrigins = array_values($allowedOrigins);
if (0 === count($allowedOrigins)) {
$allowedOrigins[] = $httpHost;
}
if ('*' !== $allowedOrigins[0]) {
$decorated = new OriginCheck($decorated, $allowedOrigins);
}
//allow origins in flash policy server
if(empty($this->flashServer) === false) {
foreach($allowedOrigins as $allowedOrgin) {
$this->flashServer->app->addAllowedAccess($allowedOrgin, $this->port);
}
}
$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();
}
}

31
ws/vendor/cboden/ratchet/src/Ratchet/ComponentInterface.php vendored

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
<?php
namespace Ratchet;
/**
* This is the interface to build a Ratchet application with.
* It implements the decorator pattern to build an application stack
*/
interface ComponentInterface {
/**
* When a new connection is opened it will be passed to this method
* @param ConnectionInterface $conn The socket/connection that just connected to your application
* @throws \Exception
*/
function onOpen(ConnectionInterface $conn);
/**
* This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed.
* @param ConnectionInterface $conn The socket/connection that is closing/closed
* @throws \Exception
*/
function onClose(ConnectionInterface $conn);
/**
* If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown,
* the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method
* @param ConnectionInterface $conn
* @param \Exception $e
* @throws \Exception
*/
function onError(ConnectionInterface $conn, \Exception $e);
}

26
ws/vendor/cboden/ratchet/src/Ratchet/ConnectionInterface.php vendored

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
<?php
namespace Ratchet;
/**
* The version of Ratchet being used
* @var string
*/
const VERSION = 'Ratchet/0.3.5';
/**
* A proxy object representing a connection to the application
* This acts as a container to store data (in memory) about the connection
*/
interface ConnectionInterface {
/**
* Send data to the connection
* @param string $data
* @return \Ratchet\ConnectionInterface
*/
function send($data);
/**
* Close the connection
*/
function close();
}

34
ws/vendor/cboden/ratchet/src/Ratchet/Http/Guzzle/Http/Message/RequestFactory.php vendored

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
<?php
namespace Ratchet\Http\Guzzle\Http\Message;
use Guzzle\Http\Message\RequestFactory as GuzzleRequestFactory;
use Guzzle\Http\EntityBody;
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}
*/
public function create($method, $url, $headers = null, $body = '', array $options = array()) {
$c = $this->entityEnclosingRequestClass;
$request = new $c($method, $url, $headers);
$request->setBody(EntityBody::factory($body));
return $request;
}
}

56
ws/vendor/cboden/ratchet/src/Ratchet/Http/HttpRequestParser.php vendored

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
<?php
namespace Ratchet\Http;
use Ratchet\MessageInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\Guzzle\Http\Message\RequestFactory;
/**
* This class receives streaming data from a client request
* and parses HTTP headers, returning a Guzzle Request object
* once it's been buffered
*/
class HttpRequestParser implements MessageInterface {
const EOM = "\r\n\r\n";
/**
* The maximum number of bytes the request can be
* This is a security measure to prevent attacks
* @var int
*/
public $maxSize = 4096;
/**
* @param \Ratchet\ConnectionInterface $context
* @param string $data Data stream to buffer
* @return \Guzzle\Http\Message\RequestInterface|null
* @throws \OverflowException If the message buffer has become too large
*/
public function onMessage(ConnectionInterface $context, $data) {
if (!isset($context->httpBuffer)) {
$context->httpBuffer = '';
}
$context->httpBuffer .= $data;
if (strlen($context->httpBuffer) > (int)$this->maxSize) {
throw new \OverflowException("Maximum buffer size of {$this->maxSize} exceeded parsing HTTP header");
}
if ($this->isEom($context->httpBuffer)) {
$request = RequestFactory::getInstance()->fromMessage($context->httpBuffer);
unset($context->httpBuffer);
return $request;
}
}
/**
* Determine if the message has been buffered as per the HTTP specification
* @param string $message
* @return boolean
*/
public function isEom($message) {
return (boolean)strpos($message, static::EOM);
}
}

90
ws/vendor/cboden/ratchet/src/Ratchet/Http/HttpServer.php vendored

@ -0,0 +1,90 @@ @@ -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
ws/vendor/cboden/ratchet/src/Ratchet/Http/HttpServerInterface.php vendored

@ -0,0 +1,14 @@ @@ -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
ws/vendor/cboden/ratchet/src/Ratchet/Http/OriginCheck.php vendored

@ -0,0 +1,79 @@ @@ -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();
}
}

105
ws/vendor/cboden/ratchet/src/Ratchet/Http/Router.php vendored

@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
<?php
namespace Ratchet\Http;
use Ratchet\ConnectionInterface;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Guzzle\Http\Url;
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');
}
$parameters = array();
foreach($route as $key => $value) {
if ((is_string($key)) && ('_' !== substr($key, 0, 1))) {
$parameters[$key] = $value;
}
}
$parameters = array_merge($parameters, $request->getQuery()->getAll());
$url = Url::factory($request->getPath());
$url->setQuery($parameters);
$request->setUrl($url);
$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();
}
}

5
ws/vendor/cboden/ratchet/src/Ratchet/MessageComponentInterface.php vendored

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
<?php
namespace Ratchet;
interface MessageComponentInterface extends ComponentInterface, MessageInterface {
}

12
ws/vendor/cboden/ratchet/src/Ratchet/MessageInterface.php vendored

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
<?php
namespace Ratchet;
interface MessageInterface {
/**
* Triggered when a client sends data through the socket
* @param \Ratchet\ConnectionInterface $from The socket/connection that sent the message to your application
* @param string $msg The message received
* @throws \Exception
*/
function onMessage(ConnectionInterface $from, $msg);
}

23
ws/vendor/cboden/ratchet/src/Ratchet/Server/EchoServer.php vendored

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
<?php
namespace Ratchet\Server;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
/**
* 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 onMessage(ConnectionInterface $from, $msg) {
$from->send($msg);
}
public function onClose(ConnectionInterface $conn) {
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$conn->close();
}
}

200
ws/vendor/cboden/ratchet/src/Ratchet/Server/FlashPolicy.php vendored

@ -0,0 +1,200 @@ @@ -0,0 +1,200 @@
<?php
namespace Ratchet\Server;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
/**
* An app to go on a server stack to pass a policy file to a Flash socket
* Useful if you're using Flash as a WebSocket polyfill on IE
* Be sure to run your server instance on port 843
* By default this lets accepts everything, make sure you tighten the rules up for production
* @final
* @link http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html
* @link http://learn.adobe.com/wiki/download/attachments/64389123/CrossDomain_PolicyFile_Specification.pdf?version=1
* @link view-source:http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd
*/
class FlashPolicy implements MessageComponentInterface {
/**
* Contains the root policy node
* @var string
*/
protected $_policy = '<?xml version="1.0"?><!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd"><cross-domain-policy></cross-domain-policy>';
/**
* Stores an array of allowed domains and their ports
* @var array
*/
protected $_access = array();
/**
* @var string
*/
protected $_siteControl = '';
/**
* @var string
*/
protected $_cache = '';
/**
* @var string
*/
protected $_cacheValid = false;
/**
* Add a domain to an allowed access list.
*
* @param string $domain Specifies a requesting domain to be granted access. Both named domains and IP
* addresses are acceptable values. Subdomains are considered different domains. A wildcard (*) can
* be used to match all domains when used alone, or multiple domains (subdomains) when used as a
* prefix for an explicit, second-level domain name separated with a dot (.)
* @param string $ports A comma-separated list of ports or range of ports that a socket connection
* is allowed to connect to. A range of ports is specified through a dash (-) between two port numbers.
* Ranges can be used with individual ports when separated with a comma. A single wildcard (*) can
* be used to allow all ports.
* @param bool $secure
* @throws \UnexpectedValueException
* @return FlashPolicy
*/
public function addAllowedAccess($domain, $ports = '*', $secure = false) {
if (!$this->validateDomain($domain)) {
throw new \UnexpectedValueException('Invalid domain');
}
if (!$this->validatePorts($ports)) {
throw new \UnexpectedValueException('Invalid Port');
}
$this->_access[] = array($domain, $ports, (boolean)$secure);
$this->_cacheValid = false;
return $this;
}
/**
* Removes all domains from the allowed access list.
*
* @return \Ratchet\Server\FlashPolicy
*/
public function clearAllowedAccess() {
$this->_access = array();
$this->_cacheValid = false;
return $this;
}
/**
* site-control defines the meta-policy for the current domain. A meta-policy specifies acceptable
* domain policy files other than the master policy file located in the target domain's root and named
* crossdomain.xml.
*
* @param string $permittedCrossDomainPolicies
* @throws \UnexpectedValueException
* @return FlashPolicy
*/
public function setSiteControl($permittedCrossDomainPolicies = 'all') {
if (!$this->validateSiteControl($permittedCrossDomainPolicies)) {
throw new \UnexpectedValueException('Invalid site control set');
}
$this->_siteControl = $permittedCrossDomainPolicies;
$this->_cacheValid = false;
return $this;
}
/**
* {@inheritdoc}
*/
public function onOpen(ConnectionInterface $conn) {
}
/**
* {@inheritdoc}
*/
public function onMessage(ConnectionInterface $from, $msg) {
if (!$this->_cacheValid) {
$this->_cache = $this->renderPolicy()->asXML();
$this->_cacheValid = true;
}
$from->send($this->_cache . "\0");
$from->close();
}
/**
* {@inheritdoc}
*/
public function onClose(ConnectionInterface $conn) {
}
/**
* {@inheritdoc}
*/
public function onError(ConnectionInterface $conn, \Exception $e) {
$conn->close();
}
/**
* Builds the crossdomain file based on the template policy
*
* @throws \UnexpectedValueException
* @return \SimpleXMLElement
*/
public function renderPolicy() {
$policy = new \SimpleXMLElement($this->_policy);
$siteControl = $policy->addChild('site-control');
if ($this->_siteControl == '') {
$this->setSiteControl();
}
$siteControl->addAttribute('permitted-cross-domain-policies', $this->_siteControl);
if (empty($this->_access)) {
throw new \UnexpectedValueException('You must add a domain through addAllowedAccess()');
}
foreach ($this->_access as $access) {
$tmp = $policy->addChild('allow-access-from');
$tmp->addAttribute('domain', $access[0]);
$tmp->addAttribute('to-ports', $access[1]);
$tmp->addAttribute('secure', ($access[2] === true) ? 'true' : 'false');
}
return $policy;
}
/**
* Make sure the proper site control was passed
*
* @param string $permittedCrossDomainPolicies
* @return bool
*/
public function validateSiteControl($permittedCrossDomainPolicies) {
//'by-content-type' and 'by-ftp-filename' are not available for sockets
return (bool)in_array($permittedCrossDomainPolicies, array('none', 'master-only', 'all'));
}
/**
* Validate for proper domains (wildcards allowed)
*
* @param string $domain
* @return bool
*/
public function validateDomain($domain) {
return (bool)preg_match("/^((http(s)?:\/\/)?([a-z0-9-_]+\.|\*\.)*([a-z0-9-_\.]+)|\*)$/i", $domain);
}
/**
* Make sure valid ports were passed
*
* @param string $port
* @return bool
*/
public function validatePorts($port) {
return (bool)preg_match('/^(\*|(\d+[,-]?)*\d+)$/', $port);
}
}

38
ws/vendor/cboden/ratchet/src/Ratchet/Server/IoConnection.php vendored

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
<?php
namespace Ratchet\Server;
use Ratchet\ConnectionInterface;
use React\Socket\ConnectionInterface as ReactConn;
/**
* {@inheritdoc}
*/
class IoConnection implements ConnectionInterface {
/**
* @var \React\Socket\ConnectionInterface
*/
protected $conn;
/**
* @param \React\Socket\ConnectionInterface $conn
*/
public function __construct(ReactConn $conn) {
$this->conn = $conn;
}
/**
* {@inheritdoc}
*/
public function send($data) {
$this->conn->write($data);
return $this;
}
/**
* {@inheritdoc}
*/
public function close() {
$this->conn->end();
}
}

141
ws/vendor/cboden/ratchet/src/Ratchet/Server/IoServer.php vendored

@ -0,0 +1,141 @@ @@ -0,0 +1,141 @@
<?php
namespace Ratchet\Server;
use Ratchet\MessageComponentInterface;
use React\EventLoop\LoopInterface;
use React\Socket\ServerInterface;
use React\EventLoop\Factory as LoopFactory;
use React\Socket\Server as Reactor;
/**
* Creates an open-ended socket to listen on a port for incoming connections.
* Events are delegated through this to attached applications
*/
class IoServer {
/**
* @var \React\EventLoop\LoopInterface
*/
public $loop;
/**
* @var \Ratchet\MessageComponentInterface
*/
public $app;
/**
* Array of React event handlers
* @var \SplFixedArray
*/
protected $handlers;
/**
* The socket server the Ratchet Application is run off of
* @var \React\Socket\ServerInterface
*/
public $socket;
/**
* @param \Ratchet\MessageComponentInterface $app The Ratchet application stack to host
* @param \React\Socket\ServerInterface $socket The React socket server to run the Ratchet application off of
* @param \React\EventLoop\LoopInterface|null $loop The React looper to run the Ratchet application off of
*/
public function __construct(MessageComponentInterface $app, ServerInterface $socket, LoopInterface $loop = null) {
if (false === strpos(PHP_VERSION, "hiphop")) {
gc_enable();
}
set_time_limit(0);
ob_implicit_flush();
$this->loop = $loop;
$this->app = $app;
$this->socket = $socket;
$socket->on('connection', array($this, 'handleConnect'));
$this->handlers = new \SplFixedArray(3);
$this->handlers[0] = array($this, 'handleData');
$this->handlers[1] = array($this, 'handleEnd');
$this->handlers[2] = array($this, 'handleError');
}
/**
* @param \Ratchet\MessageComponentInterface $component The application that I/O will call when events are received
* @param int $port The port to server sockets on
* @param string $address The address to receive sockets on (0.0.0.0 means receive connections from any)
* @return IoServer
*/
public static function factory(MessageComponentInterface $component, $port = 80, $address = '0.0.0.0') {
$loop = LoopFactory::create();
$socket = new Reactor($loop);
$socket->listen($port, $address);
return new static($component, $socket, $loop);
}
/**
* Run the application by entering the event loop
* @throws \RuntimeException If a loop was not previously specified
*/
public function run() {
if (null === $this->loop) {
throw new \RuntimeException("A React Loop was not provided during instantiation");
}
// @codeCoverageIgnoreStart
$this->loop->run();
// @codeCoverageIgnoreEnd
}
/**
* Triggered when a new connection is received from React
* @param \React\Socket\ConnectionInterface $conn
*/
public function handleConnect($conn) {
$conn->decor = new IoConnection($conn);
$conn->decor->resourceId = (int)$conn->stream;
$conn->decor->remoteAddress = $conn->getRemoteAddress();
$this->app->onOpen($conn->decor);
$conn->on('data', $this->handlers[0]);
$conn->on('end', $this->handlers[1]);
$conn->on('error', $this->handlers[2]);
}
/**
* Data has been received from React
* @param string $data
* @param \React\Socket\ConnectionInterface $conn
*/
public function handleData($data, $conn) {
try {
$this->app->onMessage($conn->decor, $data);
} catch (\Exception $e) {
$this->handleError($e, $conn);
}
}
/**
* A connection has been closed by React
* @param \React\Socket\ConnectionInterface $conn
*/
public function handleEnd($conn) {
try {
$this->app->onClose($conn->decor);
} catch (\Exception $e) {
$this->handleError($e, $conn);
}
unset($conn->decor);
}
/**
* An error has occurred, let the listening application know
* @param \Exception $e
* @param \React\Socket\ConnectionInterface $conn
*/
public function handleError(\Exception $e, $conn) {
$this->app->onError($conn->decor, $e);
}
}

111
ws/vendor/cboden/ratchet/src/Ratchet/Server/IpBlackList.php vendored

@ -0,0 +1,111 @@ @@ -0,0 +1,111 @@
<?php
namespace Ratchet\Server;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class IpBlackList implements MessageComponentInterface {
/**
* @var array
*/
protected $_blacklist = array();
/**
* @var \Ratchet\MessageComponentInterface
*/
protected $_decorating;
/**
* @param \Ratchet\MessageComponentInterface $component
*/
public function __construct(MessageComponentInterface $component) {
$this->_decorating = $component;
}
/**
* Add an address to the blacklist that will not be allowed to connect to your application
* @param string $ip IP address to block from connecting to your application
* @return IpBlackList
*/
public function blockAddress($ip) {
$this->_blacklist[$ip] = true;
return $this;
}
/**
* Unblock an address so they can access your application again
* @param string $ip IP address to unblock from connecting to your application
* @return IpBlackList
*/
public function unblockAddress($ip) {
if (isset($this->_blacklist[$this->filterAddress($ip)])) {
unset($this->_blacklist[$this->filterAddress($ip)]);
}
return $this;
}
/**
* @param string $address
* @return bool
*/
public function isBlocked($address) {
return (isset($this->_blacklist[$this->filterAddress($address)]));
}
/**
* Get an array of all the addresses blocked
* @return array
*/
public function getBlockedAddresses() {
return array_keys($this->_blacklist);
}
/**
* @param string $address
* @return string
*/
public function filterAddress($address) {
if (strstr($address, ':') && substr_count($address, '.') == 3) {
list($address, $port) = explode(':', $address);
}
return $address;
}
/**
* {@inheritdoc}
*/
function onOpen(ConnectionInterface $conn) {
if ($this->isBlocked($conn->remoteAddress)) {
return $conn->close();
}
return $this->_decorating->onOpen($conn);
}
/**
* {@inheritdoc}
*/
function onMessage(ConnectionInterface $from, $msg) {
return $this->_decorating->onMessage($from, $msg);
}
/**
* {@inheritdoc}
*/
function onClose(ConnectionInterface $conn) {
if (!$this->isBlocked($conn->remoteAddress)) {
$this->_decorating->onClose($conn);
}
}
/**
* {@inheritdoc}
*/
function onError(ConnectionInterface $conn, \Exception $e) {
if (!$this->isBlocked($conn->remoteAddress)) {
$this->_decorating->onError($conn, $e);
}
}
}

16
ws/vendor/cboden/ratchet/src/Ratchet/Session/Serialize/HandlerInterface.php vendored

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
<?php
namespace Ratchet\Session\Serialize;
interface HandlerInterface {
/**
* @param array
* @return string
*/
function serialize(array $data);
/**
* @param string
* @return array
*/
function unserialize($raw);
}

33
ws/vendor/cboden/ratchet/src/Ratchet/Session/Serialize/PhpBinaryHandler.php vendored

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
<?php
namespace Ratchet\Session\Serialize;
class PhpBinaryHandler implements HandlerInterface {
/**
* {@inheritdoc}
*/
function serialize(array $data) {
throw new \RuntimeException("Serialize PhpHandler:serialize code not written yet, write me!");
}
/**
* {@inheritdoc}
* @link http://ca2.php.net/manual/en/function.session-decode.php#108037 Code from this comment on php.net
*/
public function unserialize($raw) {
$returnData = array();
$offset = 0;
while ($offset < strlen($raw)) {
$num = ord($raw[$offset]);
$offset += 1;
$varname = substr($raw, $offset, $num);
$offset += $num;
$data = unserialize(substr($raw, $offset));
$returnData[$varname] = $data;
$offset += strlen(serialize($data));
}
return $returnData;
}
}

49
ws/vendor/cboden/ratchet/src/Ratchet/Session/Serialize/PhpHandler.php vendored

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
<?php
namespace Ratchet\Session\Serialize;
class PhpHandler implements HandlerInterface {
/**
* Simply reverse behaviour of unserialize method.
* {@inheritdoc}
*/
function serialize(array $data) {
$preSerialized = array();
$serialized = '';
if (count($data)) {
foreach ($data as $bucket => $bucketData) {
$preSerialized[] = $bucket . '|' . serialize($bucketData);
}
$serialized = implode('', $preSerialized);
}
return $serialized;
}
/**
* {@inheritdoc}
* @link http://ca2.php.net/manual/en/function.session-decode.php#108037 Code from this comment on php.net
* @throws \UnexpectedValueException If there is a problem parsing the data
*/
public function unserialize($raw) {
$returnData = array();
$offset = 0;
while ($offset < strlen($raw)) {
if (!strstr(substr($raw, $offset), "|")) {
throw new \UnexpectedValueException("invalid data, remaining: " . substr($raw, $offset));
}
$pos = strpos($raw, "|", $offset);
$num = $pos - $offset;
$varname = substr($raw, $offset, $num);
$offset += $num + 1;
$data = unserialize(substr($raw, $offset));
$returnData[$varname] = $data;
$offset += strlen(serialize($data));
}
return $returnData;
}
}

161
ws/vendor/cboden/ratchet/src/Ratchet/Session/SessionProvider.php vendored

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
<?php
namespace Ratchet\Session;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\Session\Storage\VirtualSessionStorage;
use Ratchet\Session\Serialize\HandlerInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
/**
* This component will allow access to session data from your website for each user connected
* Symfony HttpFoundation is required for this component to work
* Your website must also use Symfony HttpFoundation Sessions to read your sites session data
* If your are not using at least PHP 5.4 you must include a SessionHandlerInterface stub (is included in Symfony HttpFoundation, loaded w/ composer)
*/
class SessionProvider implements MessageComponentInterface, WsServerInterface {
/**
* @var \Ratchet\MessageComponentInterface
*/
protected $_app;
/**
* Selected handler storage assigned by the developer
* @var \SessionHandlerInterface
*/
protected $_handler;
/**
* Null storage handler if no previous session was found
* @var \SessionHandlerInterface
*/
protected $_null;
/**
* @var \Ratchet\Session\Serialize\HandlerInterface
*/
protected $_serializer;
/**
* @param \Ratchet\MessageComponentInterface $app
* @param \SessionHandlerInterface $handler
* @param array $options
* @param \Ratchet\Session\Serialize\HandlerInterface $serializer
* @throws \RuntimeException
*/
public function __construct(MessageComponentInterface $app, \SessionHandlerInterface $handler, array $options = array(), HandlerInterface $serializer = null) {
$this->_app = $app;
$this->_handler = $handler;
$this->_null = new NullSessionHandler;
ini_set('session.auto_start', 0);
ini_set('session.cache_limiter', '');
ini_set('session.use_cookies', 0);
$this->setOptions($options);
if (null === $serializer) {
$serialClass = __NAMESPACE__ . "\\Serialize\\{$this->toClassCase(ini_get('session.serialize_handler'))}Handler"; // awesome/terrible hack, eh?
if (!class_exists($serialClass)) {
throw new \RuntimeException('Unable to parse session serialize handler');
}
$serializer = new $serialClass;
}
$this->_serializer = $serializer;
}
/**
* {@inheritdoc}
*/
function onOpen(ConnectionInterface $conn) {
if (!isset($conn->WebSocket) || null === ($id = $conn->WebSocket->request->getCookie(ini_get('session.name')))) {
$saveHandler = $this->_null;
$id = '';
} else {
$saveHandler = $this->_handler;
}
$conn->Session = new Session(new VirtualSessionStorage($saveHandler, $id, $this->_serializer));
if (ini_get('session.auto_start')) {
$conn->Session->start();
}
return $this->_app->onOpen($conn);
}
/**
* {@inheritdoc}
*/
function onMessage(ConnectionInterface $from, $msg) {
return $this->_app->onMessage($from, $msg);
}
/**
* {@inheritdoc}
*/
function onClose(ConnectionInterface $conn) {
// "close" session for Connection
return $this->_app->onClose($conn);
}
/**
* {@inheritdoc}
*/
function onError(ConnectionInterface $conn, \Exception $e) {
return $this->_app->onError($conn, $e);
}
/**
* {@inheritdoc}
*/
public function getSubProtocols() {
if ($this->_app instanceof WsServerInterface) {
return $this->_app->getSubProtocols();
} else {
return array();
}
}
/**
* Set all the php session. ini options
* © Symfony
* @param array $options
* @return array
*/
protected function setOptions(array $options) {
$all = array(
'auto_start', 'cache_limiter', 'cookie_domain', 'cookie_httponly',
'cookie_lifetime', 'cookie_path', 'cookie_secure',
'entropy_file', 'entropy_length', 'gc_divisor',
'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
'hash_function', 'name', 'referer_check',
'serialize_handler', 'use_cookies',
'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags'
);
foreach ($all as $key) {
if (!array_key_exists($key, $options)) {
$options[$key] = ini_get("session.{$key}");
} else {
ini_set("session.{$key}", $options[$key]);
}
}
return $options;
}
/**
* @param string $langDef Input to convert
* @return string
*/
protected function toClassCase($langDef) {
return str_replace(' ', '', ucwords(str_replace('_', ' ', $langDef)));
}
}

54
ws/vendor/cboden/ratchet/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php vendored

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
<?php
namespace Ratchet\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
class VirtualProxy extends SessionHandlerProxy {
/**
* @var string
*/
protected $_sessionId;
/**
* @var string
*/
protected $_sessionName;
/**
* {@inheritdoc}
*/
public function __construct(\SessionHandlerInterface $handler) {
parent::__construct($handler);
$this->saveHandlerName = 'user';
$this->_sessionName = ini_get('session.name');
}
/**
* {@inheritdoc}
*/
public function getId() {
return $this->_sessionId;
}
/**
* {@inheritdoc}
*/
public function setId($id) {
$this->_sessionId = $id;
}
/**
* {@inheritdoc}
*/
public function getName() {
return $this->_sessionName;
}
/**
* DO NOT CALL THIS METHOD
* @internal
*/
public function setName($name) {
throw new \RuntimeException("Can not change session name in VirtualProxy");
}
}

88
ws/vendor/cboden/ratchet/src/Ratchet/Session/Storage/VirtualSessionStorage.php vendored

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
<?php
namespace Ratchet\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Ratchet\Session\Storage\Proxy\VirtualProxy;
use Ratchet\Session\Serialize\HandlerInterface;
class VirtualSessionStorage extends NativeSessionStorage {
/**
* @var \Ratchet\Session\Serialize\HandlerInterface
*/
protected $_serializer;
/**
* @param \SessionHandlerInterface $handler
* @param string $sessionId The ID of the session to retrieve
* @param \Ratchet\Session\Serialize\HandlerInterface $serializer
*/
public function __construct(\SessionHandlerInterface $handler, $sessionId, HandlerInterface $serializer) {
$this->setSaveHandler($handler);
$this->saveHandler->setId($sessionId);
$this->_serializer = $serializer;
$this->setMetadataBag(null);
}
/**
* {@inheritdoc}
*/
public function start() {
if ($this->started && !$this->closed) {
return true;
}
// You have to call Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler::open() to use
// pdo_sqlite (and possible pdo_*) as session storage, if you are using a DSN string instead of a \PDO object
// in the constructor. The method arguments are filled with the values, which are also used by the symfony
// framework in this case. This must not be the best choice, but it works.
$this->saveHandler->open(session_save_path(), session_name());
$rawData = $this->saveHandler->read($this->saveHandler->getId());
$sessionData = $this->_serializer->unserialize($rawData);
$this->loadSession($sessionData);
if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
$this->saveHandler->setActive(false);
}
return true;
}
/**
* {@inheritdoc}
*/
public function regenerate($destroy = false, $lifetime = null) {
// .. ?
}
/**
* {@inheritdoc}
*/
public function save() {
// get the data from the bags?
// serialize the data
// save the data using the saveHandler
// $this->saveHandler->write($this->saveHandler->getId(),
if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) {
$this->saveHandler->setActive(false);
}
$this->closed = true;
}
/**
* {@inheritdoc}
*/
public function setSaveHandler($saveHandler = null) {
if (!($saveHandler instanceof \SessionHandlerInterface)) {
throw new \InvalidArgumentException('Handler must be instance of SessionHandlerInterface');
}
if (!($saveHandler instanceof VirtualProxy)) {
$saveHandler = new VirtualProxy($saveHandler);
}
$this->saveHandler = $saveHandler;
}
}

5
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/Exception.php vendored

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
<?php
namespace Ratchet\Wamp;
class Exception extends \Exception {
}

31
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/JsonException.php vendored

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
<?php
namespace Ratchet\Wamp;
class JsonException extends Exception {
public function __construct() {
$code = json_last_error();
switch ($code) {
case JSON_ERROR_DEPTH:
$msg = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$msg = 'Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$msg = 'Unknown error';
break;
}
parent::__construct($msg, $code);
}
}

157
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/ServerProtocol.php vendored

@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
<?php
namespace Ratchet\Wamp;
use Ratchet\MessageComponentInterface;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\ConnectionInterface;
/**
* WebSocket Application Messaging Protocol
*
* @link http://wamp.ws/spec
* @link https://github.com/oberstet/AutobahnJS
*
* +--------------+----+------------------+
* | Message Type | ID | DIRECTION |
* |--------------+----+------------------+
* | WELCOME | 0 | Server-to-Client |
* | PREFIX | 1 | Bi-Directional |
* | CALL | 2 | Client-to-Server |
* | CALL RESULT | 3 | Server-to-Client |
* | CALL ERROR | 4 | Server-to-Client |
* | SUBSCRIBE | 5 | Client-to-Server |
* | UNSUBSCRIBE | 6 | Client-to-Server |
* | PUBLISH | 7 | Client-to-Server |
* | EVENT | 8 | Server-to-Client |
* +--------------+----+------------------+
*/
class ServerProtocol implements MessageComponentInterface, WsServerInterface {
const MSG_WELCOME = 0;
const MSG_PREFIX = 1;
const MSG_CALL = 2;
const MSG_CALL_RESULT = 3;
const MSG_CALL_ERROR = 4;
const MSG_SUBSCRIBE = 5;
const MSG_UNSUBSCRIBE = 6;
const MSG_PUBLISH = 7;
const MSG_EVENT = 8;
/**
* @var WampServerInterface
*/
protected $_decorating;
/**
* @var \SplObjectStorage
*/
protected $connections;
/**
* @param WampServerInterface $serverComponent An class to propagate calls through
*/
public function __construct(WampServerInterface $serverComponent) {
$this->_decorating = $serverComponent;
$this->connections = new \SplObjectStorage;
}
/**
* {@inheritdoc}
*/
public function getSubProtocols() {
if ($this->_decorating instanceof WsServerInterface) {
$subs = $this->_decorating->getSubProtocols();
$subs[] = 'wamp';
return $subs;
} else {
return array('wamp');
}
}
/**
* {@inheritdoc}
*/
public function onOpen(ConnectionInterface $conn) {
$decor = new WampConnection($conn);
$this->connections->attach($conn, $decor);
$this->_decorating->onOpen($decor);
}
/**
* {@inheritdoc}
* @throws \Ratchet\Wamp\Exception
* @throws \Ratchet\Wamp\JsonException
*/
public function onMessage(ConnectionInterface $from, $msg) {
$from = $this->connections[$from];
if (null === ($json = @json_decode($msg, true))) {
throw new JsonException;
}
if (!is_array($json) || $json !== array_values($json)) {
throw new Exception("Invalid WAMP message format");
}
switch ($json[0]) {
case static::MSG_PREFIX:
$from->WAMP->prefixes[$json[1]] = $json[2];
break;
case static::MSG_CALL:
array_shift($json);
$callID = array_shift($json);
$procURI = array_shift($json);
if (count($json) == 1 && is_array($json[0])) {
$json = $json[0];
}
$this->_decorating->onCall($from, $callID, $from->getUri($procURI), $json);
break;
case static::MSG_SUBSCRIBE:
$this->_decorating->onSubscribe($from, $from->getUri($json[1]));
break;
case static::MSG_UNSUBSCRIBE:
$this->_decorating->onUnSubscribe($from, $from->getUri($json[1]));
break;
case static::MSG_PUBLISH:
$exclude = (array_key_exists(3, $json) ? $json[3] : null);
if (!is_array($exclude)) {
if (true === (boolean)$exclude) {
$exclude = array($from->WAMP->sessionId);
} else {
$exclude = array();
}
}
$eligible = (array_key_exists(4, $json) ? $json[4] : array());
$this->_decorating->onPublish($from, $from->getUri($json[1]), $json[2], $exclude, $eligible);
break;
default:
throw new Exception('Invalid WAMP message type');
}
}
/**
* {@inheritdoc}
*/
public function onClose(ConnectionInterface $conn) {
$decor = $this->connections[$conn];
$this->connections->detach($conn);
$this->_decorating->onClose($decor);
}
/**
* {@inheritdoc}
*/
public function onError(ConnectionInterface $conn, \Exception $e) {
return $this->_decorating->onError($this->connections[$conn], $e);
}
}

106
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/Topic.php vendored

@ -0,0 +1,106 @@ @@ -0,0 +1,106 @@
<?php
namespace Ratchet\Wamp;
use Ratchet\ConnectionInterface;
/**
* A topic/channel containing connections that have subscribed to it
*/
class Topic implements \IteratorAggregate, \Countable {
/**
* If true the TopicManager will destroy this object if it's ever empty of connections
* @deprecated in v0.4
* @type bool
*/
public $autoDelete = false;
private $id;
private $subscribers;
/**
* @param string $topicId Unique ID for this object
*/
public function __construct($topicId) {
$this->id = $topicId;
$this->subscribers = new \SplObjectStorage;
}
/**
* @return string
*/
public function getId() {
return $this->id;
}
public function __toString() {
return $this->getId();
}
/**
* Send a message to all the connections in this topic
* @param string $msg Payload to publish
* @param array $exclude A list of session IDs the message should be excluded from (blacklist)
* @param array $eligible A list of session Ids the message should be send to (whitelist)
* @return Topic The same Topic object to chain
*/
public function broadcast($msg, array $exclude = array(), array $eligible = array()) {
$useEligible = (bool)count($eligible);
foreach ($this->subscribers as $client) {
if (in_array($client->WAMP->sessionId, $exclude)) {
continue;
}
if ($useEligible && !in_array($client->WAMP->sessionId, $eligible)) {
continue;
}
$client->event($this->id, $msg);
}
return $this;
}
/**
* @param WampConnection $conn
* @return boolean
*/
public function has(ConnectionInterface $conn) {
return $this->subscribers->contains($conn);
}
/**
* @param WampConnection $conn
* @return Topic
*/
public function add(ConnectionInterface $conn) {
$this->subscribers->attach($conn);
return $this;
}
/**
* @param WampConnection $conn
* @return Topic
*/
public function remove(ConnectionInterface $conn) {
if ($this->subscribers->contains($conn)) {
$this->subscribers->detach($conn);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getIterator() {
return $this->subscribers;
}
/**
* {@inheritdoc}
*/
public function count() {
return $this->subscribers->count();
}
}

125
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/TopicManager.php vendored

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
<?php
namespace Ratchet\Wamp;
use Ratchet\ConnectionInterface;
use Ratchet\WebSocket\WsServerInterface;
class TopicManager implements WsServerInterface, WampServerInterface {
/**
* @var WampServerInterface
*/
protected $app;
/**
* @var array
*/
protected $topicLookup = array();
public function __construct(WampServerInterface $app) {
$this->app = $app;
}
/**
* {@inheritdoc}
*/
public function onOpen(ConnectionInterface $conn) {
$conn->WAMP->subscriptions = new \SplObjectStorage;
$this->app->onOpen($conn);
}
/**
* {@inheritdoc}
*/
public function onCall(ConnectionInterface $conn, $id, $topic, array $params) {
$this->app->onCall($conn, $id, $this->getTopic($topic), $params);
}
/**
* {@inheritdoc}
*/
public function onSubscribe(ConnectionInterface $conn, $topic) {
$topicObj = $this->getTopic($topic);
if ($conn->WAMP->subscriptions->contains($topicObj)) {
return;
}
$this->topicLookup[$topic]->add($conn);
$conn->WAMP->subscriptions->attach($topicObj);
$this->app->onSubscribe($conn, $topicObj);
}
/**
* {@inheritdoc}
*/
public function onUnsubscribe(ConnectionInterface $conn, $topic) {
$topicObj = $this->getTopic($topic);
if (!$conn->WAMP->subscriptions->contains($topicObj)) {
return;
}
$this->cleanTopic($topicObj, $conn);
$this->app->onUnsubscribe($conn, $topicObj);
}
/**
* {@inheritdoc}
*/
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) {
$this->app->onPublish($conn, $this->getTopic($topic), $event, $exclude, $eligible);
}
/**
* {@inheritdoc}
*/
public function onClose(ConnectionInterface $conn) {
$this->app->onClose($conn);
foreach ($this->topicLookup as $topic) {
$this->cleanTopic($topic, $conn);
}
}
/**
* {@inheritdoc}
*/
public function onError(ConnectionInterface $conn, \Exception $e) {
$this->app->onError($conn, $e);
}
/**
* {@inheritdoc}
*/
public function getSubProtocols() {
if ($this->app instanceof WsServerInterface) {
return $this->app->getSubProtocols();
}
return array();
}
/**
* @param string
* @return Topic
*/
protected function getTopic($topic) {
if (!array_key_exists($topic, $this->topicLookup)) {
$this->topicLookup[$topic] = new Topic($topic);
}
return $this->topicLookup[$topic];
}
protected function cleanTopic(Topic $topic, ConnectionInterface $conn) {
if ($conn->WAMP->subscriptions->contains($topic)) {
$conn->WAMP->subscriptions->detach($topic);
}
$this->topicLookup[$topic->getId()]->remove($conn);
if ($topic->autoDelete && 0 === $topic->count()) {
unset($this->topicLookup[$topic->getId()]);
}
}
}

115
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/WampConnection.php vendored

@ -0,0 +1,115 @@ @@ -0,0 +1,115 @@
<?php
namespace Ratchet\Wamp;
use Ratchet\ConnectionInterface;
use Ratchet\AbstractConnectionDecorator;
use Ratchet\Wamp\ServerProtocol as WAMP;
/**
* A ConnectionInterface object wrapper that is passed to your WAMP application
* representing a client. Methods on this Connection are therefore different.
* @property \stdClass $WAMP
*/
class WampConnection extends AbstractConnectionDecorator {
/**
* {@inheritdoc}
*/
public function __construct(ConnectionInterface $conn) {
parent::__construct($conn);
$this->WAMP = new \StdClass;
$this->WAMP->sessionId = str_replace('.', '', uniqid(mt_rand(), true));
$this->WAMP->prefixes = array();
$this->send(json_encode(array(WAMP::MSG_WELCOME, $this->WAMP->sessionId, 1, \Ratchet\VERSION)));
}
/**
* Successfully respond to a call made by the client
* @param string $id The unique ID given by the client to respond to
* @param array $data an object or array
* @return WampConnection
*/
public function callResult($id, $data = array()) {
return $this->send(json_encode(array(WAMP::MSG_CALL_RESULT, $id, $data)));
}
/**
* Respond with an error to a client call
* @param string $id The unique ID given by the client to respond to
* @param string $errorUri The URI given to identify the specific error
* @param string $desc A developer-oriented description of the error
* @param string $details An optional human readable detail message to send back
* @return WampConnection
*/
public function callError($id, $errorUri, $desc = '', $details = null) {
if ($errorUri instanceof Topic) {
$errorUri = (string)$errorUri;
}
$data = array(WAMP::MSG_CALL_ERROR, $id, $errorUri, $desc);
if (null !== $details) {
$data[] = $details;
}
return $this->send(json_encode($data));
}
/**
* @param string $topic The topic to broadcast to
* @param mixed $msg Data to send with the event. Anything that is json'able
* @return WampConnection
*/
public function event($topic, $msg) {
return $this->send(json_encode(array(WAMP::MSG_EVENT, (string)$topic, $msg)));
}
/**
* @param string $curie
* @param string $uri
* @return WampConnection
*/
public function prefix($curie, $uri) {
$this->WAMP->prefixes[$curie] = (string)$uri;
return $this->send(json_encode(array(WAMP::MSG_PREFIX, $curie, (string)$uri)));
}
/**
* Get the full request URI from the connection object if a prefix has been established for it
* @param string $uri
* @return string
*/
public function getUri($uri) {
$curieSeperator = ':';
if (preg_match('/http(s*)\:\/\//', $uri) == false) {
if (strpos($uri, $curieSeperator) !== false) {
list($prefix, $action) = explode($curieSeperator, $uri);
if(isset($this->WAMP->prefixes[$prefix]) === true){
return $this->WAMP->prefixes[$prefix] . '#' . $action;
}
}
}
return $uri;
}
/**
* @internal
*/
public function send($data) {
$this->getConnection()->send($data);
return $this;
}
/**
* {@inheritdoc}
*/
public function close($opt = null) {
$this->getConnection()->close($opt);
}
}

67
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/WampServer.php vendored

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
<?php
namespace Ratchet\Wamp;
use Ratchet\MessageComponentInterface;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\ConnectionInterface;
/**
* Enable support for the official WAMP sub-protocol in your application
* WAMP allows for Pub/Sub and RPC
* @link http://wamp.ws The WAMP specification
* @link https://github.com/oberstet/AutobahnJS Souce for client side library
* @link http://autobahn.s3.amazonaws.com/js/autobahn.min.js Minified client side library
*/
class WampServer implements MessageComponentInterface, WsServerInterface {
/**
* @var ServerProtocol
*/
protected $wampProtocol;
/**
* This class just makes it 1 step easier to use Topic objects in WAMP
* If you're looking at the source code, look in the __construct of this
* class and use that to make your application instead of using this
*/
public function __construct(WampServerInterface $app) {
$this->wampProtocol = new ServerProtocol(new TopicManager($app));
}
/**
* {@inheritdoc}
*/
public function onOpen(ConnectionInterface $conn) {
$this->wampProtocol->onOpen($conn);
}
/**
* {@inheritdoc}
*/
public function onMessage(ConnectionInterface $conn, $msg) {
try {
$this->wampProtocol->onMessage($conn, $msg);
} catch (Exception $we) {
$conn->close(1007);
}
}
/**
* {@inheritdoc}
*/
public function onClose(ConnectionInterface $conn) {
$this->wampProtocol->onClose($conn);
}
/**
* {@inheritdoc}
*/
public function onError(ConnectionInterface $conn, \Exception $e) {
$this->wampProtocol->onError($conn, $e);
}
/**
* {@inheritdoc}
*/
public function getSubProtocols() {
return $this->wampProtocol->getSubProtocols();
}
}

43
ws/vendor/cboden/ratchet/src/Ratchet/Wamp/WampServerInterface.php vendored

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
<?php
namespace Ratchet\Wamp;
use Ratchet\ComponentInterface;
use Ratchet\ConnectionInterface;
/**
* An extension of Ratchet\ComponentInterface to server a WAMP application
* onMessage is replaced by various types of messages for this protocol (pub/sub or rpc)
*/
interface WampServerInterface extends ComponentInterface {
/**
* An RPC call has been received
* @param \Ratchet\ConnectionInterface $conn
* @param string $id The unique ID of the RPC, required to respond to
* @param string|Topic $topic The topic to execute the call against
* @param array $params Call parameters received from the client
*/
function onCall(ConnectionInterface $conn, $id, $topic, array $params);
/**
* A request to subscribe to a topic has been made
* @param \Ratchet\ConnectionInterface $conn
* @param string|Topic $topic The topic to subscribe to
*/
function onSubscribe(ConnectionInterface $conn, $topic);
/**
* A request to unsubscribe from a topic has been made
* @param \Ratchet\ConnectionInterface $conn
* @param string|Topic $topic The topic to unsubscribe from
*/
function onUnSubscribe(ConnectionInterface $conn, $topic);
/**
* A client is attempting to publish content to a subscribed connections on a URI
* @param \Ratchet\ConnectionInterface $conn
* @param string|Topic $topic The topic the user has attempted to publish to
* @param string $event Payload of the publish
* @param array $exclude A list of session IDs the message should be excluded from (blacklist)
* @param array $eligible A list of session Ids the message should be send to (whitelist)
*/
function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible);
}

31
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Encoding/ToggleableValidator.php vendored

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
<?php
namespace Ratchet\WebSocket\Encoding;
class ToggleableValidator implements ValidatorInterface {
/**
* Toggle if checkEncoding checks the encoding or not
* @var bool
*/
public $on;
/**
* @var Validator
*/
private $validator;
public function __construct($on = true) {
$this->validator = new Validator;
$this->on = (boolean)$on;
}
/**
* {@inheritdoc}
*/
public function checkEncoding($str, $encoding) {
if (!(boolean)$this->on) {
return true;
}
return $this->validator->checkEncoding($str, $encoding);
}
}

93
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Encoding/Validator.php vendored

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
<?php
namespace Ratchet\WebSocket\Encoding;
/**
* This class handled encoding validation
*/
class Validator {
const UTF8_ACCEPT = 0;
const UTF8_REJECT = 1;
/**
* Incremental UTF-8 validator with constant memory consumption (minimal state).
*
* Implements the algorithm "Flexible and Economical UTF-8 Decoder" by
* Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/).
*/
protected static $dfa = array(
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, # 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, # a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, # c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, # e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, # f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, # s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, # s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, # s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, # s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # s7..s8
);
/**
* Lookup if mbstring is available
* @var bool
*/
private $hasMbString = false;
/**
* Lookup if iconv is available
* @var bool
*/
private $hasIconv = false;
public function __construct() {
$this->hasMbString = extension_loaded('mbstring');
$this->hasIconv = extension_loaded('iconv');
}
/**
* @param string $str The value to check the encoding
* @param string $against The type of encoding to check against
* @return bool
*/
public function checkEncoding($str, $against) {
if ('UTF-8' == $against) {
return $this->isUtf8($str);
}
if ($this->hasMbString) {
return mb_check_encoding($str, $against);
} elseif ($this->hasIconv) {
return ($str == iconv($against, "{$against}//IGNORE", $str));
}
return true;
}
protected function isUtf8($str) {
if ($this->hasMbString) {
if (false === mb_check_encoding($str, 'UTF-8')) {
return false;
}
} elseif ($this->hasIconv) {
if ($str != iconv('UTF-8', 'UTF-8//IGNORE', $str)) {
return false;
}
}
$state = static::UTF8_ACCEPT;
for ($i = 0, $len = strlen($str); $i < $len; $i++) {
$state = static::$dfa[256 + ($state << 4) + static::$dfa[ord($str[$i])]];
if (static::UTF8_REJECT === $state) {
return false;
}
}
return true;
}
}

12
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Encoding/ValidatorInterface.php vendored

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
<?php
namespace Ratchet\WebSocket\Encoding;
interface ValidatorInterface {
/**
* Verify a string matches the encoding type
* @param string $str The string to check
* @param string $encoding The encoding type to check against
* @return bool
*/
function checkEncoding($str, $encoding);
}

28
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/DataInterface.php vendored

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<?php
namespace Ratchet\WebSocket\Version;
interface DataInterface {
/**
* Determine if the message is complete or still fragmented
* @return bool
*/
function isCoalesced();
/**
* Get the number of bytes the payload is set to be
* @return int
*/
function getPayloadLength();
/**
* Get the payload (message) sent from peer
* @return string
*/
function getPayload();
/**
* Get raw contents of the message
* @return string
*/
function getContents();
}

38
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/FrameInterface.php vendored

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
<?php
namespace Ratchet\WebSocket\Version;
interface FrameInterface extends DataInterface {
/**
* Add incoming data to the frame from peer
* @param string
*/
function addBuffer($buf);
/**
* Is this the final frame in a fragmented message?
* @return bool
*/
function isFinal();
/**
* Is the payload masked?
* @return bool
*/
function isMasked();
/**
* @return int
*/
function getOpcode();
/**
* @return int
*/
//function getReceivedPayloadLength();
/**
* 32-big string
* @return string
*/
function getMaskingKey();
}

120
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/Hixie76.php vendored

@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
<?php
namespace Ratchet\WebSocket\Version;
use Ratchet\ConnectionInterface;
use Ratchet\MessageInterface;
use Ratchet\WebSocket\Version\Hixie76\Connection;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Ratchet\WebSocket\Version\Hixie76\Frame;
/**
* FOR THE LOVE OF BEER, PLEASE PLEASE PLEASE DON'T allow the use of this in your application!
* Hixie76 is bad for 2 (there's more) reasons:
* 1) The handshake is done in HTTP, which includes a key for signing in the body...
* BUT there is no Length defined in the header (as per HTTP spec) so the TCP buffer can't tell when the message is done!
* 2) By nature it's insecure. Google did a test study where they were able to do a
* man-in-the-middle attack on 10%-15% of the people who saw their ad who had a browser (currently only Safari) supporting the Hixie76 protocol.
* This was exploited by taking advantage of proxy servers in front of the user who ignored some HTTP headers in the handshake
* The Hixie76 is currently implemented by Safari
* @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
*/
class Hixie76 implements VersionInterface {
/**
* {@inheritdoc}
*/
public function isProtocol(RequestInterface $request) {
return !(null === $request->getHeader('Sec-WebSocket-Key2'));
}
/**
* {@inheritdoc}
*/
public function getVersionNumber() {
return 0;
}
/**
* @param \Guzzle\Http\Message\RequestInterface $request
* @return \Guzzle\Http\Message\Response
* @throws \UnderflowException If there hasn't been enough data received
*/
public function handshake(RequestInterface $request) {
$body = substr($request->getBody(), 0, 8);
if (8 !== strlen($body)) {
throw new \UnderflowException("Not enough data received to issue challenge response");
}
$challenge = $this->sign((string)$request->getHeader('Sec-WebSocket-Key1'), (string)$request->getHeader('Sec-WebSocket-Key2'), $body);
$headers = array(
'Upgrade' => 'WebSocket'
, 'Connection' => 'Upgrade'
, 'Sec-WebSocket-Origin' => (string)$request->getHeader('Origin')
, 'Sec-WebSocket-Location' => 'ws://' . (string)$request->getHeader('Host') . $request->getPath()
);
$response = new Response(101, $headers, $challenge);
$response->setStatus(101, 'WebSocket Protocol Handshake');
return $response;
}
/**
* {@inheritdoc}
*/
public function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback) {
$upgraded = new Connection($conn);
if (!isset($upgraded->WebSocket)) {
$upgraded->WebSocket = new \StdClass;
}
$upgraded->WebSocket->coalescedCallback = $coalescedCallback;
return $upgraded;
}
public function onMessage(ConnectionInterface $from, $data) {
$overflow = '';
if (!isset($from->WebSocket->frame)) {
$from->WebSocket->frame = $this->newFrame();
}
$from->WebSocket->frame->addBuffer($data);
if ($from->WebSocket->frame->isCoalesced()) {
$overflow = $from->WebSocket->frame->extractOverflow();
$parsed = $from->WebSocket->frame->getPayload();
unset($from->WebSocket->frame);
$from->WebSocket->coalescedCallback->onMessage($from, $parsed);
unset($from->WebSocket->frame);
}
if (strlen($overflow) > 0) {
$this->onMessage($from, $overflow);
}
}
public function newFrame() {
return new Frame;
}
public function generateKeyNumber($key) {
if (0 === substr_count($key, ' ')) {
return 0;
}
return preg_replace('[\D]', '', $key) / substr_count($key, ' ');
}
protected function sign($key1, $key2, $code) {
return md5(
pack('N', $this->generateKeyNumber($key1))
. pack('N', $this->generateKeyNumber($key2))
. $code
, true);
}
}

26
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/Hixie76/Connection.php vendored

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
<?php
namespace Ratchet\WebSocket\Version\Hixie76;
use Ratchet\AbstractConnectionDecorator;
/**
* {@inheritdoc}
* @property \StdClass $WebSocket
*/
class Connection extends AbstractConnectionDecorator {
public function send($msg) {
if (!$this->WebSocket->closing) {
$this->getConnection()->send(chr(0) . $msg . chr(255));
}
return $this;
}
public function close() {
if (!$this->WebSocket->closing) {
$this->getConnection()->send(chr(255));
$this->getConnection()->close();
$this->WebSocket->closing = true;
}
}
}

86
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/Hixie76/Frame.php vendored

@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
<?php
namespace Ratchet\WebSocket\Version\Hixie76;
use Ratchet\WebSocket\Version\FrameInterface;
/**
* This does not entirely follow the protocol to spec, but (mostly) works
* Hixie76 probably should not even be supported
*/
class Frame implements FrameInterface {
/**
* @type string
*/
protected $_data = '';
/**
* {@inheritdoc}
*/
public function isCoalesced() {
return (boolean)($this->_data[0] == chr(0) && substr($this->_data, -1) == chr(255));
}
/**
* {@inheritdoc}
*/
public function addBuffer($buf) {
$this->_data .= (string)$buf;
}
/**
* {@inheritdoc}
*/
public function isFinal() {
return true;
}
/**
* {@inheritdoc}
*/
public function isMasked() {
return false;
}
/**
* {@inheritdoc}
*/
public function getOpcode() {
return 1;
}
/**
* {@inheritdoc}
*/
public function getPayloadLength() {
if (!$this->isCoalesced()) {
throw new \UnderflowException('Not enough of the message has been buffered to determine the length of the payload');
}
return strlen($this->_data) - 2;
}
/**
* {@inheritdoc}
*/
public function getMaskingKey() {
return '';
}
/**
* {@inheritdoc}
*/
public function getPayload() {
if (!$this->isCoalesced()) {
return new \UnderflowException('Not enough data buffered to read payload');
}
return substr($this->_data, 1, strlen($this->_data) - 2);
}
public function getContents() {
return $this->_data;
}
public function extractOverflow() {
return '';
}
}

15
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/HyBi10.php vendored

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<?php
namespace Ratchet\WebSocket\Version;
use Guzzle\Http\Message\RequestInterface;
class HyBi10 extends RFC6455 {
public function isProtocol(RequestInterface $request) {
$version = (int)(string)$request->getHeader('Sec-WebSocket-Version');
return ($version >= 6 && $version < 13);
}
public function getVersionNumber() {
return 6;
}
}

15
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/MessageInterface.php vendored

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<?php
namespace Ratchet\WebSocket\Version;
interface MessageInterface extends DataInterface {
/**
* @param FrameInterface $fragment
* @return MessageInterface
*/
function addFrame(FrameInterface $fragment);
/**
* @return int
*/
function getOpcode();
}

273
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455.php vendored

@ -0,0 +1,273 @@ @@ -0,0 +1,273 @@
<?php
namespace Ratchet\WebSocket\Version;
use Ratchet\ConnectionInterface;
use Ratchet\MessageInterface;
use Ratchet\WebSocket\Version\RFC6455\HandshakeVerifier;
use Ratchet\WebSocket\Version\RFC6455\Message;
use Ratchet\WebSocket\Version\RFC6455\Frame;
use Ratchet\WebSocket\Version\RFC6455\Connection;
use Ratchet\WebSocket\Encoding\ValidatorInterface;
use Ratchet\WebSocket\Encoding\Validator;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
/**
* The latest version of the WebSocket protocol
* @link http://tools.ietf.org/html/rfc6455
* @todo Unicode: return mb_convert_encoding(pack("N",$u), mb_internal_encoding(), 'UCS-4BE');
*/
class RFC6455 implements VersionInterface {
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
/**
* @var RFC6455\HandshakeVerifier
*/
protected $_verifier;
/**
* A lookup of the valid close codes that can be sent in a frame
* @var array
*/
private $closeCodes = array();
/**
* @var \Ratchet\WebSocket\Encoding\ValidatorInterface
*/
protected $validator;
public function __construct(ValidatorInterface $validator = null) {
$this->_verifier = new HandshakeVerifier;
$this->setCloseCodes();
if (null === $validator) {
$validator = new Validator;
}
$this->validator = $validator;
}
/**
* {@inheritdoc}
*/
public function isProtocol(RequestInterface $request) {
$version = (int)(string)$request->getHeader('Sec-WebSocket-Version');
return ($this->getVersionNumber() === $version);
}
/**
* {@inheritdoc}
*/
public function getVersionNumber() {
return 13;
}
/**
* {@inheritdoc}
*/
public function handshake(RequestInterface $request) {
if (true !== $this->_verifier->verifyAll($request)) {
return new Response(400);
}
return new Response(101, array(
'Upgrade' => 'websocket'
, 'Connection' => 'Upgrade'
, 'Sec-WebSocket-Accept' => $this->sign((string)$request->getHeader('Sec-WebSocket-Key'))
));
}
/**
* @param \Ratchet\ConnectionInterface $conn
* @param \Ratchet\MessageInterface $coalescedCallback
* @return \Ratchet\WebSocket\Version\RFC6455\Connection
*/
public function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback) {
$upgraded = new Connection($conn);
if (!isset($upgraded->WebSocket)) {
$upgraded->WebSocket = new \StdClass;
}
$upgraded->WebSocket->coalescedCallback = $coalescedCallback;
return $upgraded;
}
/**
* @param \Ratchet\WebSocket\Version\RFC6455\Connection $from
* @param string $data
*/
public function onMessage(ConnectionInterface $from, $data) {
$overflow = '';
if (!isset($from->WebSocket->message)) {
$from->WebSocket->message = $this->newMessage();
}
// There is a frame fragment attached to the connection, add to it
if (!isset($from->WebSocket->frame)) {
$from->WebSocket->frame = $this->newFrame();
}
$from->WebSocket->frame->addBuffer($data);
if ($from->WebSocket->frame->isCoalesced()) {
$frame = $from->WebSocket->frame;
if (false !== $frame->getRsv1() ||
false !== $frame->getRsv2() ||
false !== $frame->getRsv3()
) {
return $from->close($frame::CLOSE_PROTOCOL);
}
if (!$frame->isMasked()) {
return $from->close($frame::CLOSE_PROTOCOL);
}
$opcode = $frame->getOpcode();
if ($opcode > 2) {
if ($frame->getPayloadLength() > 125 || !$frame->isFinal()) {
return $from->close($frame::CLOSE_PROTOCOL);
}
switch ($opcode) {
case $frame::OP_CLOSE:
$closeCode = 0;
$bin = $frame->getPayload();
if (empty($bin)) {
return $from->close();
}
if (strlen($bin) >= 2) {
list($closeCode) = array_merge(unpack('n*', substr($bin, 0, 2)));
}
if (!$this->isValidCloseCode($closeCode)) {
return $from->close($frame::CLOSE_PROTOCOL);
}
if (!$this->validator->checkEncoding(substr($bin, 2), 'UTF-8')) {
return $from->close($frame::CLOSE_BAD_PAYLOAD);
}
$frame->unMaskPayload();
return $from->close($frame);
break;
case $frame::OP_PING:
$from->send($this->newFrame($frame->getPayload(), true, $frame::OP_PONG));
break;
case $frame::OP_PONG:
break;
default:
return $from->close($frame::CLOSE_PROTOCOL);
break;
}
$overflow = $from->WebSocket->frame->extractOverflow();
unset($from->WebSocket->frame, $frame, $opcode);
if (strlen($overflow) > 0) {
$this->onMessage($from, $overflow);
}
return;
}
$overflow = $from->WebSocket->frame->extractOverflow();
if ($frame::OP_CONTINUE == $frame->getOpcode() && 0 == count($from->WebSocket->message)) {
return $from->close($frame::CLOSE_PROTOCOL);
}
if (count($from->WebSocket->message) > 0 && $frame::OP_CONTINUE != $frame->getOpcode()) {
return $from->close($frame::CLOSE_PROTOCOL);
}
$from->WebSocket->message->addFrame($from->WebSocket->frame);
unset($from->WebSocket->frame);
}
if ($from->WebSocket->message->isCoalesced()) {
$parsed = $from->WebSocket->message->getPayload();
unset($from->WebSocket->message);
if (!$this->validator->checkEncoding($parsed, 'UTF-8')) {
return $from->close(Frame::CLOSE_BAD_PAYLOAD);
}
$from->WebSocket->coalescedCallback->onMessage($from, $parsed);
}
if (strlen($overflow) > 0) {
$this->onMessage($from, $overflow);
}
}
/**
* @return RFC6455\Message
*/
public function newMessage() {
return new Message;
}
/**
* @param string|null $payload
* @param bool|null $final
* @param int|null $opcode
* @return RFC6455\Frame
*/
public function newFrame($payload = null, $final = null, $opcode = null) {
return new Frame($payload, $final, $opcode);
}
/**
* Used when doing the handshake to encode the key, verifying client/server are speaking the same language
* @param string $key
* @return string
* @internal
*/
public function sign($key) {
return base64_encode(sha1($key . static::GUID, true));
}
/**
* Determine if a close code is valid
* @param int|string
* @return bool
*/
public function isValidCloseCode($val) {
if (array_key_exists($val, $this->closeCodes)) {
return true;
}
if ($val >= 3000 && $val <= 4999) {
return true;
}
return false;
}
/**
* Creates a private lookup of valid, private close codes
*/
protected function setCloseCodes() {
$this->closeCodes[Frame::CLOSE_NORMAL] = true;
$this->closeCodes[Frame::CLOSE_GOING_AWAY] = true;
$this->closeCodes[Frame::CLOSE_PROTOCOL] = true;
$this->closeCodes[Frame::CLOSE_BAD_DATA] = true;
//$this->closeCodes[Frame::CLOSE_NO_STATUS] = true;
//$this->closeCodes[Frame::CLOSE_ABNORMAL] = true;
$this->closeCodes[Frame::CLOSE_BAD_PAYLOAD] = true;
$this->closeCodes[Frame::CLOSE_POLICY] = true;
$this->closeCodes[Frame::CLOSE_TOO_BIG] = true;
$this->closeCodes[Frame::CLOSE_MAND_EXT] = true;
$this->closeCodes[Frame::CLOSE_SRV_ERR] = true;
//$this->closeCodes[Frame::CLOSE_TLS] = true;
}
}

44
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/Connection.php vendored

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
<?php
namespace Ratchet\WebSocket\Version\RFC6455;
use Ratchet\AbstractConnectionDecorator;
use Ratchet\WebSocket\Version\DataInterface;
/**
* {@inheritdoc}
* @property \StdClass $WebSocket
*/
class Connection extends AbstractConnectionDecorator {
/**
* {@inheritdoc}
*/
public function send($msg) {
if (!$this->WebSocket->closing) {
if (!($msg instanceof DataInterface)) {
$msg = new Frame($msg);
}
$this->getConnection()->send($msg->getContents());
}
return $this;
}
/**
* {@inheritdoc}
*/
public function close($code = 1000) {
if ($this->WebSocket->closing) {
return;
}
if ($code instanceof DataInterface) {
$this->send($code);
} else {
$this->send(new Frame(pack('n', $code), true, Frame::OP_CLOSE));
}
$this->getConnection()->close();
$this->WebSocket->closing = true;
}
}

451
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/Frame.php vendored

@ -0,0 +1,451 @@ @@ -0,0 +1,451 @@
<?php
namespace Ratchet\WebSocket\Version\RFC6455;
use Ratchet\WebSocket\Version\FrameInterface;
class Frame implements FrameInterface {
const OP_CONTINUE = 0;
const OP_TEXT = 1;
const OP_BINARY = 2;
const OP_CLOSE = 8;
const OP_PING = 9;
const OP_PONG = 10;
const CLOSE_NORMAL = 1000;
const CLOSE_GOING_AWAY = 1001;
const CLOSE_PROTOCOL = 1002;
const CLOSE_BAD_DATA = 1003;
const CLOSE_NO_STATUS = 1005;
const CLOSE_ABNORMAL = 1006;
const CLOSE_BAD_PAYLOAD = 1007;
const CLOSE_POLICY = 1008;
const CLOSE_TOO_BIG = 1009;
const CLOSE_MAND_EXT = 1010;
const CLOSE_SRV_ERR = 1011;
const CLOSE_TLS = 1015;
const MASK_LENGTH = 4;
/**
* The contents of the frame
* @var string
*/
protected $data = '';
/**
* Number of bytes received from the frame
* @var int
*/
public $bytesRecvd = 0;
/**
* Number of bytes in the payload (as per framing protocol)
* @var int
*/
protected $defPayLen = -1;
/**
* If the frame is coalesced this is true
* This is to prevent doing math every time ::isCoalesced is called
* @var boolean
*/
private $isCoalesced = false;
/**
* The unpacked first byte of the frame
* @var int
*/
protected $firstByte = -1;
/**
* The unpacked second byte of the frame
* @var int
*/
protected $secondByte = -1;
/**
* @param string|null $payload
* @param bool $final
* @param int $opcode
*/
public function __construct($payload = null, $final = true, $opcode = 1) {
if (null === $payload) {
return;
}
$this->defPayLen = strlen($payload);
$this->firstByte = ($final ? 128 : 0) + $opcode;
$this->secondByte = $this->defPayLen;
$this->isCoalesced = true;
$ext = '';
if ($this->defPayLen > 65535) {
$ext = pack('NN', 0, $this->defPayLen);
$this->secondByte = 127;
} elseif ($this->defPayLen > 125) {
$ext = pack('n', $this->defPayLen);
$this->secondByte = 126;
}
$this->data = chr($this->firstByte) . chr($this->secondByte) . $ext . $payload;
$this->bytesRecvd = 2 + strlen($ext) + $this->defPayLen;
}
/**
* {@inheritdoc}
*/
public function isCoalesced() {
if (true === $this->isCoalesced) {
return true;
}
try {
$payload_length = $this->getPayloadLength();
$payload_start = $this->getPayloadStartingByte();
} catch (\UnderflowException $e) {
return false;
}
$this->isCoalesced = $this->bytesRecvd >= $payload_length + $payload_start;
return $this->isCoalesced;
}
/**
* {@inheritdoc}
*/
public function addBuffer($buf) {
$len = strlen($buf);
$this->data .= $buf;
$this->bytesRecvd += $len;
if ($this->firstByte === -1 && $this->bytesRecvd !== 0) {
$this->firstByte = ord($this->data[0]);
}
if ($this->secondByte === -1 && $this->bytesRecvd >= 2) {
$this->secondByte = ord($this->data[1]);
}
}
/**
* {@inheritdoc}
*/
public function isFinal() {
if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine if this is the final frame in message');
}
return 128 === ($this->firstByte & 128);
}
/**
* @return boolean
* @throws \UnderflowException
*/
public function getRsv1() {
if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine reserved bit');
}
return 64 === ($this->firstByte & 64);
}
/**
* @return boolean
* @throws \UnderflowException
*/
public function getRsv2() {
if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine reserved bit');
}
return 32 === ($this->firstByte & 32);
}
/**
* @return boolean
* @throws \UnderflowException
*/
public function getRsv3() {
if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine reserved bit');
}
return 16 == ($this->firstByte & 16);
}
/**
* {@inheritdoc}
*/
public function isMasked() {
if (-1 === $this->secondByte) {
throw new \UnderflowException("Not enough bytes received ({$this->bytesRecvd}) to determine if mask is set");
}
return 128 === ($this->secondByte & 128);
}
/**
* {@inheritdoc}
*/
public function getMaskingKey() {
if (!$this->isMasked()) {
return '';
}
$start = 1 + $this->getNumPayloadBytes();
if ($this->bytesRecvd < $start + static::MASK_LENGTH) {
throw new \UnderflowException('Not enough data buffered to calculate the masking key');
}
return substr($this->data, $start, static::MASK_LENGTH);
}
/**
* Create a 4 byte masking key
* @return string
*/
public function generateMaskingKey() {
$mask = '';
for ($i = 1; $i <= static::MASK_LENGTH; $i++) {
$mask .= chr(rand(32, 126));
}
return $mask;
}
/**
* Apply a mask to the payload
* @param string|null If NULL is passed a masking key will be generated
* @throws \OutOfBoundsException
* @throws \InvalidArgumentException If there is an issue with the given masking key
* @return Frame
*/
public function maskPayload($maskingKey = null) {
if (null === $maskingKey) {
$maskingKey = $this->generateMaskingKey();
}
if (static::MASK_LENGTH !== strlen($maskingKey)) {
throw new \InvalidArgumentException("Masking key must be " . static::MASK_LENGTH ." characters");
}
if (extension_loaded('mbstring') && true !== mb_check_encoding($maskingKey, 'US-ASCII')) {
throw new \OutOfBoundsException("Masking key MUST be ASCII");
}
$this->unMaskPayload();
$this->secondByte = $this->secondByte | 128;
$this->data[1] = chr($this->secondByte);
$this->data = substr_replace($this->data, $maskingKey, $this->getNumPayloadBytes() + 1, 0);
$this->bytesRecvd += static::MASK_LENGTH;
$this->data = substr_replace($this->data, $this->applyMask($maskingKey), $this->getPayloadStartingByte(), $this->getPayloadLength());
return $this;
}
/**
* Remove a mask from the payload
* @throws \UnderFlowException If the frame is not coalesced
* @return Frame
*/
public function unMaskPayload() {
if (!$this->isCoalesced()) {
throw new \UnderflowException('Frame must be coalesced before applying mask');
}
if (!$this->isMasked()) {
return $this;
}
$maskingKey = $this->getMaskingKey();
$this->secondByte = $this->secondByte & ~128;
$this->data[1] = chr($this->secondByte);
$this->data = substr_replace($this->data, '', $this->getNumPayloadBytes() + 1, static::MASK_LENGTH);
$this->bytesRecvd -= static::MASK_LENGTH;
$this->data = substr_replace($this->data, $this->applyMask($maskingKey), $this->getPayloadStartingByte(), $this->getPayloadLength());
return $this;
}
/**
* Apply a mask to a string or the payload of the instance
* @param string $maskingKey The 4 character masking key to be applied
* @param string|null $payload A string to mask or null to use the payload
* @throws \UnderflowException If using the payload but enough hasn't been buffered
* @return string The masked string
*/
public function applyMask($maskingKey, $payload = null) {
if (null === $payload) {
if (!$this->isCoalesced()) {
throw new \UnderflowException('Frame must be coalesced to apply a mask');
}
$payload = substr($this->data, $this->getPayloadStartingByte(), $this->getPayloadLength());
}
$applied = '';
for ($i = 0, $len = strlen($payload); $i < $len; $i++) {
$applied .= $payload[$i] ^ $maskingKey[$i % static::MASK_LENGTH];
}
return $applied;
}
/**
* {@inheritdoc}
*/
public function getOpcode() {
if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine opcode');
}
return ($this->firstByte & ~240);
}
/**
* Gets the decimal value of bits 9 (10th) through 15 inclusive
* @return int
* @throws \UnderflowException If the buffer doesn't have enough data to determine this
*/
protected function getFirstPayloadVal() {
if (-1 === $this->secondByte) {
throw new \UnderflowException('Not enough bytes received');
}
return $this->secondByte & 127;
}
/**
* @return int (7|23|71) Number of bits defined for the payload length in the fame
* @throws \UnderflowException
*/
protected function getNumPayloadBits() {
if (-1 === $this->secondByte) {
throw new \UnderflowException('Not enough bytes received');
}
// By default 7 bits are used to describe the payload length
// These are bits 9 (10th) through 15 inclusive
$bits = 7;
// Get the value of those bits
$check = $this->getFirstPayloadVal();
// If the value is 126 the 7 bits plus the next 16 are used to describe the payload length
if ($check >= 126) {
$bits += 16;
}
// If the value of the initial payload length are is 127 an additional 48 bits are used to describe length
// Note: The documentation specifies the length is to be 63 bits, but I think that's a typo and is 64 (16+48)
if ($check === 127) {
$bits += 48;
}
return $bits;
}
/**
* This just returns the number of bytes used in the frame to describe the payload length (as opposed to # of bits)
* @see getNumPayloadBits
*/
protected function getNumPayloadBytes() {
return (1 + $this->getNumPayloadBits()) / 8;
}
/**
* {@inheritdoc}
*/
public function getPayloadLength() {
if ($this->defPayLen !== -1) {
return $this->defPayLen;
}
$this->defPayLen = $this->getFirstPayloadVal();
if ($this->defPayLen <= 125) {
return $this->getPayloadLength();
}
$byte_length = $this->getNumPayloadBytes();
if ($this->bytesRecvd < 1 + $byte_length) {
$this->defPayLen = -1;
throw new \UnderflowException('Not enough data buffered to determine payload length');
}
$len = 0;
for ($i = 2; $i <= $byte_length; $i++) {
$len <<= 8;
$len += ord($this->data[$i]);
}
$this->defPayLen = $len;
return $this->getPayloadLength();
}
/**
* {@inheritdoc}
*/
public function getPayloadStartingByte() {
return 1 + $this->getNumPayloadBytes() + ($this->isMasked() ? static::MASK_LENGTH : 0);
}
/**
* {@inheritdoc}
* @todo Consider not checking mask, always returning the payload, masked or not
*/
public function getPayload() {
if (!$this->isCoalesced()) {
throw new \UnderflowException('Can not return partial message');
}
$payload = substr($this->data, $this->getPayloadStartingByte(), $this->getPayloadLength());
if ($this->isMasked()) {
$payload = $this->applyMask($this->getMaskingKey(), $payload);
}
return $payload;
}
/**
* Get the raw contents of the frame
* @todo This is untested, make sure the substr is right - trying to return the frame w/o the overflow
*/
public function getContents() {
return substr($this->data, 0, $this->getPayloadStartingByte() + $this->getPayloadLength());
}
/**
* Sometimes clients will concatenate more than one frame over the wire
* This method will take the extra bytes off the end and return them
* @todo Consider returning new Frame
* @return string
*/
public function extractOverflow() {
if ($this->isCoalesced()) {
$endPoint = $this->getPayloadLength();
$endPoint += $this->getPayloadStartingByte();
if ($this->bytesRecvd > $endPoint) {
$overflow = substr($this->data, $endPoint);
$this->data = substr($this->data, 0, $endPoint);
return $overflow;
}
}
return '';
}
}

137
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/HandshakeVerifier.php vendored

@ -0,0 +1,137 @@ @@ -0,0 +1,137 @@
<?php
namespace Ratchet\WebSocket\Version\RFC6455;
use Guzzle\Http\Message\RequestInterface;
/**
* These are checks to ensure the client requested handshake are valid
* Verification rules come from section 4.2.1 of the RFC6455 document
* @todo Currently just returning invalid - should consider returning appropriate HTTP status code error #s
*/
class HandshakeVerifier {
/**
* Given an array of the headers this method will run through all verification methods
* @param \Guzzle\Http\Message\RequestInterface $request
* @return bool TRUE if all headers are valid, FALSE if 1 or more were invalid
*/
public function verifyAll(RequestInterface $request) {
$passes = 0;
$passes += (int)$this->verifyMethod($request->getMethod());
$passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion());
$passes += (int)$this->verifyRequestURI($request->getPath());
$passes += (int)$this->verifyHost((string)$request->getHeader('Host'));
$passes += (int)$this->verifyUpgradeRequest((string)$request->getHeader('Upgrade'));
$passes += (int)$this->verifyConnection((string)$request->getHeader('Connection'));
$passes += (int)$this->verifyKey((string)$request->getHeader('Sec-WebSocket-Key'));
//$passes += (int)$this->verifyVersion($headers['Sec-WebSocket-Version']); // Temporarily breaking functionality
return (7 === $passes);
}
/**
* Test the HTTP method. MUST be "GET"
* @param string
* @return bool
*/
public function verifyMethod($val) {
return ('get' === strtolower($val));
}
/**
* Test the HTTP version passed. MUST be 1.1 or greater
* @param string|int
* @return bool
*/
public function verifyHTTPVersion($val) {
return (1.1 <= (double)$val);
}
/**
* @param string
* @return bool
*/
public function verifyRequestURI($val) {
if ($val[0] != '/') {
return false;
}
if (false !== strstr($val, '#')) {
return false;
}
if (!extension_loaded('mbstring')) {
return true;
}
return mb_check_encoding($val, 'US-ASCII');
}
/**
* @param string|null
* @return bool
* @todo Find out if I can find the master socket, ensure the port is attached to header if not 80 or 443 - not sure if this is possible, as I tried to hide it
* @todo Once I fix HTTP::getHeaders just verify this isn't NULL or empty...or maybe need to verify it's a valid domain??? Or should it equal $_SERVER['HOST'] ?
*/
public function verifyHost($val) {
return (null !== $val);
}
/**
* Verify the Upgrade request to WebSockets.
* @param string $val MUST equal "websocket"
* @return bool
*/
public function verifyUpgradeRequest($val) {
return ('websocket' === strtolower($val));
}
/**
* Verify the Connection header
* @param string $val MUST equal "Upgrade"
* @return bool
*/
public function verifyConnection($val) {
$val = strtolower($val);
if ('upgrade' === $val) {
return true;
}
$vals = explode(',', str_replace(', ', ',', $val));
return (false !== array_search('upgrade', $vals));
}
/**
* This function verifies the nonce is valid (64 big encoded, 16 bytes random string)
* @param string|null
* @return bool
* @todo The spec says we don't need to base64_decode - can I just check if the length is 24 and not decode?
* @todo Check the spec to see what the encoding of the key could be
*/
public function verifyKey($val) {
return (16 === strlen(base64_decode((string)$val)));
}
/**
* Verify the version passed matches this RFC
* @param string|int MUST equal 13|"13"
* @return bool
* @todo Ran in to a problem here...I'm having HyBi use the RFC files, this breaks it! oops
*/
public function verifyVersion($val) {
return (13 === (int)$val);
}
/**
* @todo Write logic for this method. See section 4.2.1.8
*/
public function verifyProtocol($val) {
}
/**
* @todo Write logic for this method. See section 4.2.1.9
*/
public function verifyExtensions($val) {
}
}

107
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/RFC6455/Message.php vendored

@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
<?php
namespace Ratchet\WebSocket\Version\RFC6455;
use Ratchet\WebSocket\Version\MessageInterface;
use Ratchet\WebSocket\Version\FrameInterface;
class Message implements MessageInterface, \Countable {
/**
* @var \SplDoublyLinkedList
*/
protected $_frames;
public function __construct() {
$this->_frames = new \SplDoublyLinkedList;
}
/**
* {@inheritdoc}
*/
public function count() {
return count($this->_frames);
}
/**
* {@inheritdoc}
*/
public function isCoalesced() {
if (count($this->_frames) == 0) {
return false;
}
$last = $this->_frames->top();
return ($last->isCoalesced() && $last->isFinal());
}
/**
* {@inheritdoc}
* @todo Also, I should perhaps check the type...control frames (ping/pong/close) are not to be considered part of a message
*/
public function addFrame(FrameInterface $fragment) {
$this->_frames->push($fragment);
return $this;
}
/**
* {@inheritdoc}
*/
public function getOpcode() {
if (count($this->_frames) == 0) {
throw new \UnderflowException('No frames have been added to this message');
}
return $this->_frames->bottom()->getOpcode();
}
/**
* {@inheritdoc}
*/
public function getPayloadLength() {
$len = 0;
foreach ($this->_frames as $frame) {
try {
$len += $frame->getPayloadLength();
} catch (\UnderflowException $e) {
// Not an error, want the current amount buffered
}
}
return $len;
}
/**
* {@inheritdoc}
*/
public function getPayload() {
if (!$this->isCoalesced()) {
throw new \UnderflowException('Message has not been put back together yet');
}
$buffer = '';
foreach ($this->_frames as $frame) {
$buffer .= $frame->getPayload();
}
return $buffer;
}
/**
* {@inheritdoc}
*/
public function getContents() {
if (!$this->isCoalesced()) {
throw new \UnderflowException("Message has not been put back together yet");
}
$buffer = '';
foreach ($this->_frames as $frame) {
$buffer .= $frame->getContents();
}
return $buffer;
}
}

57
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/Version/VersionInterface.php vendored

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
<?php
namespace Ratchet\WebSocket\Version;
use Ratchet\MessageInterface;
use Ratchet\ConnectionInterface;
use Guzzle\Http\Message\RequestInterface;
/**
* A standard interface for interacting with the various version of the WebSocket protocol
*/
interface VersionInterface extends MessageInterface {
/**
* Given an HTTP header, determine if this version should handle the protocol
* @param \Guzzle\Http\Message\RequestInterface $request
* @return bool
* @throws \UnderflowException If the protocol thinks the headers are still fragmented
*/
function isProtocol(RequestInterface $request);
/**
* Although the version has a name associated with it the integer returned is the proper identification
* @return int
*/
function getVersionNumber();
/**
* Perform the handshake and return the response headers
* @param \Guzzle\Http\Message\RequestInterface $request
* @return \Guzzle\Http\Message\Response
* @throws \UnderflowException If the message hasn't finished buffering (not yet implemented, theoretically will only happen with Hixie version)
*/
function handshake(RequestInterface $request);
/**
* @param \Ratchet\ConnectionInterface $conn
* @param \Ratchet\MessageInterface $coalescedCallback
* @return \Ratchet\ConnectionInterface
*/
function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback);
/**
* @return MessageInterface
*/
//function newMessage();
/**
* @return FrameInterface
*/
//function newFrame();
/**
* @param string
* @param bool
* @return string
* @todo Change to use other classes, this will be removed eventually
*/
//function frame($message, $mask = true);
}

90
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/VersionManager.php vendored

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
<?php
namespace Ratchet\WebSocket;
use Ratchet\WebSocket\Version\VersionInterface;
use Guzzle\Http\Message\RequestInterface;
/**
* Manage the various versions of the WebSocket protocol
* This accepts interfaces of versions to enable/disable
*/
class VersionManager {
/**
* The header string to let clients know which versions are supported
* @var string
*/
private $versionString = '';
/**
* Storage of each version enabled
* @var array
*/
protected $versions = array();
/**
* Get the protocol negotiator for the request, if supported
* @param \Guzzle\Http\Message\RequestInterface $request
* @throws \InvalidArgumentException
* @return \Ratchet\WebSocket\Version\VersionInterface
*/
public function getVersion(RequestInterface $request) {
foreach ($this->versions as $version) {
if ($version->isProtocol($request)) {
return $version;
}
}
throw new \InvalidArgumentException("Version not found");
}
/**
* @param \Guzzle\Http\Message\RequestInterface
* @return bool
*/
public function isVersionEnabled(RequestInterface $request) {
foreach ($this->versions as $version) {
if ($version->isProtocol($request)) {
return true;
}
}
return false;
}
/**
* Enable support for a specific version of the WebSocket protocol
* @param \Ratchet\WebSocket\Version\VersionInterface $version
* @return VersionManager
*/
public function enableVersion(VersionInterface $version) {
$this->versions[$version->getVersionNumber()] = $version;
if (empty($this->versionString)) {
$this->versionString = (string)$version->getVersionNumber();
} else {
$this->versionString .= ", {$version->getVersionNumber()}";
}
return $this;
}
/**
* Disable support for a specific WebSocket protocol version
* @param int $versionId The version ID to un-support
* @return VersionManager
*/
public function disableVersion($versionId) {
unset($this->versions[$versionId]);
$this->versionString = implode(',', array_keys($this->versions));
return $this;
}
/**
* Get a string of version numbers supported (comma delimited)
* @return string
*/
public function getSupportedVersionString() {
return $this->versionString;
}
}

232
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/WsServer.php vendored

@ -0,0 +1,232 @@ @@ -0,0 +1,232 @@
<?php
namespace Ratchet\WebSocket;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Ratchet\WebSocket\Version;
use Ratchet\WebSocket\Encoding\ToggleableValidator;
/**
* The adapter to handle WebSocket requests/responses
* This is a mediator between the Server and your application to handle real-time messaging through a web browser
* @link http://ca.php.net/manual/en/ref.http.php
* @link http://dev.w3.org/html5/websockets/
*/
class WsServer implements HttpServerInterface {
/**
* Manage the various WebSocket versions to support
* @var VersionManager
* @note May not expose this in the future, may do through facade methods
*/
public $versioner;
/**
* Decorated component
* @var \Ratchet\MessageComponentInterface
*/
public $component;
/**
* @var \SplObjectStorage
*/
protected $connections;
/**
* Holder of accepted protocols, implement through WampServerInterface
*/
protected $acceptedSubProtocols = array();
/**
* UTF-8 validator
* @var \Ratchet\WebSocket\Encoding\ValidatorInterface
*/
protected $validator;
/**
* Flag if we have checked the decorated component for sub-protocols
* @var boolean
*/
private $isSpGenerated = false;
/**
* @param \Ratchet\MessageComponentInterface $component Your application to run with WebSockets
* If you want to enable sub-protocols have your component implement WsServerInterface as well
*/
public function __construct(MessageComponentInterface $component) {
$this->versioner = new VersionManager;
$this->validator = new ToggleableValidator;
$this->versioner
->enableVersion(new Version\RFC6455($this->validator))
->enableVersion(new Version\HyBi10($this->validator))
->enableVersion(new Version\Hixie76)
;
$this->component = $component;
$this->connections = new \SplObjectStorage;
}
/**
* {@inheritdoc}
*/
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) {
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->closing = false;
$this->attemptUpgrade($conn);
}
/**
* {@inheritdoc}
*/
public function onMessage(ConnectionInterface $from, $msg) {
if ($from->WebSocket->closing) {
return;
}
if (true === $from->WebSocket->established) {
return $from->WebSocket->version->onMessage($this->connections[$from], $msg);
}
$this->attemptUpgrade($from, $msg);
}
protected function attemptUpgrade(ConnectionInterface $conn, $data = '') {
if ('' !== $data) {
$conn->WebSocket->request->getBody()->write($data);
}
if (!$this->versioner->isVersionEnabled($conn->WebSocket->request)) {
return $this->close($conn);
}
$conn->WebSocket->version = $this->versioner->getVersion($conn->WebSocket->request);
try {
$response = $conn->WebSocket->version->handshake($conn->WebSocket->request);
} catch (\UnderflowException $e) {
return;
}
if (null !== ($subHeader = $conn->WebSocket->request->getHeader('Sec-WebSocket-Protocol'))) {
if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($subHeader->normalize()))) {
$response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols);
}
}
$response->setHeader('X-Powered-By', \Ratchet\VERSION);
$conn->send((string)$response);
if (101 != $response->getStatusCode()) {
return $conn->close();
}
$upgraded = $conn->WebSocket->version->upgradeConnection($conn, $this->component);
$this->connections->attach($conn, $upgraded);
$upgraded->WebSocket->established = true;
return $this->component->onOpen($upgraded);
}
/**
* {@inheritdoc}
*/
public function onClose(ConnectionInterface $conn) {
if ($this->connections->contains($conn)) {
$decor = $this->connections[$conn];
$this->connections->detach($conn);
$this->component->onClose($decor);
}
}
/**
* {@inheritdoc}
*/
public function onError(ConnectionInterface $conn, \Exception $e) {
if ($conn->WebSocket->established && $this->connections->contains($conn)) {
$this->component->onError($this->connections[$conn], $e);
} else {
$conn->close();
}
}
/**
* Disable a specific version of the WebSocket protocol
* @param int $versionId Version ID to disable
* @return WsServer
*/
public function disableVersion($versionId) {
$this->versioner->disableVersion($versionId);
return $this;
}
/**
* Toggle weather to check encoding of incoming messages
* @param bool
* @return WsServer
*/
public function setEncodingChecks($opt) {
$this->validator->on = (boolean)$opt;
return $this;
}
/**
* @param string
* @return boolean
*/
public function isSubProtocolSupported($name) {
if (!$this->isSpGenerated) {
if ($this->component instanceof WsServerInterface) {
$this->acceptedSubProtocols = array_flip($this->component->getSubProtocols());
}
$this->isSpGenerated = true;
}
return array_key_exists($name, $this->acceptedSubProtocols);
}
/**
* @param \Traversable|null $requested
* @return string
*/
protected function getSubProtocolString(\Traversable $requested = null) {
if (null !== $requested) {
foreach ($requested as $sub) {
if ($this->isSubProtocolSupported($sub)) {
return $sub;
}
}
}
return '';
}
/**
* Close a connection with an HTTP response
* @param \Ratchet\ConnectionInterface $conn
* @param int $code HTTP status code
*/
protected function close(ConnectionInterface $conn, $code = 400) {
$response = new Response($code, array(
'Sec-WebSocket-Version' => $this->versioner->getSupportedVersionString()
, 'X-Powered-By' => \Ratchet\VERSION
));
$conn->send((string)$response);
$conn->close();
}
}

14
ws/vendor/cboden/ratchet/src/Ratchet/WebSocket/WsServerInterface.php vendored

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
<?php
namespace Ratchet\WebSocket;
/**
* WebSocket Server Interface
*/
interface WsServerInterface {
/**
* If any component in a stack supports a WebSocket sub-protocol return each supported in an array
* @return array
* @todo This method may be removed in future version (note that will not break code, just make some code obsolete)
*/
function getSubProtocols();
}

17
ws/vendor/cboden/ratchet/tests/autobahn/bin/fuzzingserver-noutf8.php vendored

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
<?php
require dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
$port = $argc > 1 ? $argv[1] : 8000;
$impl = sprintf('React\EventLoop\%sLoop', $argc > 2 ? $argv[2] : 'StreamSelect');
$loop = new $impl;
$sock = new React\Socket\Server($loop);
$web = new Ratchet\WebSocket\WsServer(new Ratchet\Server\EchoServer);
$app = new Ratchet\Http\HttpServer($web);
$web->setEncodingChecks(false);
$sock->listen($port, '0.0.0.0');
$server = new Ratchet\Server\IoServer($app, $sock, $loop);
$server->run();

15
ws/vendor/cboden/ratchet/tests/autobahn/bin/fuzzingserver.php vendored

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<?php
require dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
$port = $argc > 1 ? $argv[1] : 8000;
$impl = sprintf('React\EventLoop\%sLoop', $argc > 2 ? $argv[2] : 'StreamSelect');
$loop = new $impl;
$sock = new React\Socket\Server($loop);
$app = new Ratchet\Http\HttpServer(new Ratchet\WebSocket\WsServer(new Ratchet\Server\EchoServer));
$sock->listen($port, '0.0.0.0');
$server = new Ratchet\Server\IoServer($app, $sock, $loop);
$server->run();

16
ws/vendor/cboden/ratchet/tests/autobahn/fuzzingclient-all.json vendored

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
{
"options": {"failByDrop": false}
, "outdir": "reports/ab"
, "servers": [
{"agent": "Ratchet/0.3 libevent", "url": "ws://localhost:8001", "options": {"version": 18}}
, {"agent": "Ratchet/0.3 libev", "url": "ws://localhost:8004", "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": {}
}

12
ws/vendor/cboden/ratchet/tests/autobahn/fuzzingclient-profile.json vendored

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
{
"options": {"failByDrop": false}
, "outdir": "reports/profile"
, "servers": [
{"agent": "Ratchet", "url": "ws://localhost:8000", "options": {"version": 18}}
]
, "cases": ["9.7.4"]
, "exclude-cases": ["1.2.*", "2.3", "2.4", "2.6", "9.2.*", "9.4.*", "9.6.*", "9.8.*"]
, "exclude-agent-cases": {}
}

12
ws/vendor/cboden/ratchet/tests/autobahn/fuzzingclient-quick.json vendored

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
{
"options": {"failByDrop": false}
, "outdir": "reports/rfc"
, "servers": [
{"agent": "Ratchet", "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": {}
}

4
ws/vendor/cboden/ratchet/tests/bootstrap.php vendored

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
<?php
$loader = require __DIR__ . '/../vendor/autoload.php';
$loader->addPsr4('Ratchet\\', __DIR__ . '/helpers/Ratchet');

50
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/AbstractMessageComponentTestCase.php vendored

@ -0,0 +1,50 @@ @@ -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);
}
}

35
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/Component.php vendored

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
<?php
namespace Ratchet\Mock;
use Ratchet\MessageComponentInterface;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\ConnectionInterface;
class Component implements MessageComponentInterface, WsServerInterface {
public $last = array();
public $protocols = array();
public function __construct(ComponentInterface $app = null) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onOpen(ConnectionInterface $conn) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onMessage(ConnectionInterface $from, $msg) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onClose(ConnectionInterface $conn) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$this->last[__FUNCTION__] = func_get_args();
}
public function getSubProtocols() {
return $this->protocols;
}
}

20
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/Connection.php vendored

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
<?php
namespace Ratchet\Mock;
use Ratchet\ConnectionInterface;
class Connection implements ConnectionInterface {
public $last = array(
'send' => ''
, 'close' => false
);
public $remoteAddress = '127.0.0.1';
public function send($data) {
$this->last[__FUNCTION__] = $data;
}
public function close() {
$this->last[__FUNCTION__] = true;
}
}

22
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/ConnectionDecorator.php vendored

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
<?php
namespace Ratchet\Mock;
use Ratchet\AbstractConnectionDecorator;
class ConnectionDecorator extends AbstractConnectionDecorator {
public $last = array(
'write' => ''
, 'end' => false
);
public function send($data) {
$this->last[__FUNCTION__] = $data;
$this->getConnection()->send($data);
}
public function close() {
$this->last[__FUNCTION__] = true;
$this->getConnection()->close();
}
}

43
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Mock/WampComponent.php vendored

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
<?php
namespace Ratchet\Mock;
use Ratchet\Wamp\WampServerInterface;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\ConnectionInterface;
class WampComponent implements WampServerInterface, WsServerInterface {
public $last = array();
public $protocols = array();
public function getSubProtocols() {
return $this->protocols;
}
public function onCall(ConnectionInterface $conn, $id, $procURI, array $params) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onSubscribe(ConnectionInterface $conn, $topic) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onUnSubscribe(ConnectionInterface $conn, $topic) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onOpen(ConnectionInterface $conn) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onClose(ConnectionInterface $conn) {
$this->last[__FUNCTION__] = func_get_args();
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$this->last[__FUNCTION__] = func_get_args();
}
}

28
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/NullComponent.php vendored

@ -0,0 +1,28 @@ @@ -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();
}
}

7
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/Wamp/Stub/WsWampServerInterface.php vendored

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
<?php
namespace Ratchet\Wamp\Stub;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\Wamp\WampServerInterface;
interface WsWampServerInterface extends WsServerInterface, WampServerInterface {
}

7
ws/vendor/cboden/ratchet/tests/helpers/Ratchet/WebSocket/Stub/WsMessageComponentInterface.php vendored

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
<?php
namespace Ratchet\WebSocket\Stub;
use Ratchet\MessageComponentInterface;
use Ratchet\WebSocket\WsServerInterface;
interface WsMessageComponentInterface extends MessageComponentInterface, WsServerInterface {
}

53
ws/vendor/cboden/ratchet/tests/integration/GuzzleTest.php vendored

@ -0,0 +1,53 @@ @@ -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());
}
}

147
ws/vendor/cboden/ratchet/tests/unit/AbstractConnectionDecoratorTest.php vendored

@ -0,0 +1,147 @@ @@ -0,0 +1,147 @@
<?php
namespace Ratchet;
use Ratchet\Mock\ConnectionDecorator;
/**
* @covers Ratchet\AbstractConnectionDecorator
* @covers Ratchet\ConnectionInterface
*/
class AbstractConnectionDecoratorTest extends \PHPUnit_Framework_TestCase {
protected $mock;
protected $l1;
protected $l2;
public function setUp() {
$this->mock = $this->getMock('\Ratchet\ConnectionInterface');
$this->l1 = new ConnectionDecorator($this->mock);
$this->l2 = new ConnectionDecorator($this->l1);
}
public function testGet() {
$var = 'hello';
$val = 'world';
$this->mock->$var = $val;
$this->assertEquals($val, $this->l1->$var);
$this->assertEquals($val, $this->l2->$var);
}
public function testSet() {
$var = 'Chris';
$val = 'Boden';
$this->l1->$var = $val;
$this->assertEquals($val, $this->mock->$var);
}
public function testSetLevel2() {
$var = 'Try';
$val = 'Again';
$this->l2->$var = $val;
$this->assertEquals($val, $this->mock->$var);
}
public function testIsSetTrue() {
$var = 'PHP';
$val = 'Ratchet';
$this->mock->$var = $val;
$this->assertTrue(isset($this->l1->$var));
$this->assertTrue(isset($this->l2->$var));
}
public function testIsSetFalse() {
$var = 'herp';
$val = 'derp';
$this->assertFalse(isset($this->l1->$var));
$this->assertFalse(isset($this->l2->$var));
}
public function testUnset() {
$var = 'Flying';
$val = 'Monkey';
$this->mock->$var = $val;
unset($this->l1->$var);
$this->assertFalse(isset($this->mock->$var));
}
public function testUnsetLevel2() {
$var = 'Flying';
$val = 'Monkey';
$this->mock->$var = $val;
unset($this->l2->$var);
$this->assertFalse(isset($this->mock->$var));
}
public function testGetConnection() {
$class = new \ReflectionClass('\\Ratchet\\AbstractConnectionDecorator');
$method = $class->getMethod('getConnection');
$method->setAccessible(true);
$conn = $method->invokeArgs($this->l1, array());
$this->assertSame($this->mock, $conn);
}
public function testGetConnectionLevel2() {
$class = new \ReflectionClass('\\Ratchet\\AbstractConnectionDecorator');
$method = $class->getMethod('getConnection');
$method->setAccessible(true);
$conn = $method->invokeArgs($this->l2, array());
$this->assertSame($this->l1, $conn);
}
public function testWrapperCanStoreSelfInDecorator() {
$this->mock->decorator = $this->l1;
$this->assertSame($this->l1, $this->l2->decorator);
}
public function testDecoratorRecursion() {
$this->mock->decorator = new \stdClass;
$this->mock->decorator->conn = $this->l1;
$this->assertSame($this->l1, $this->mock->decorator->conn);
$this->assertSame($this->l1, $this->l1->decorator->conn);
$this->assertSame($this->l1, $this->l2->decorator->conn);
}
public function testDecoratorRecursionLevel2() {
$this->mock->decorator = new \stdClass;
$this->mock->decorator->conn = $this->l2;
$this->assertSame($this->l2, $this->mock->decorator->conn);
$this->assertSame($this->l2, $this->l1->decorator->conn);
$this->assertSame($this->l2, $this->l2->decorator->conn);
// just for fun
$this->assertSame($this->l2, $this->l2->decorator->conn->decorator->conn->decorator->conn);
}
public function testWarningGettingNothing() {
$this->setExpectedException('PHPUnit_Framework_Error');
$var = $this->mock->nonExistant;
}
public function testWarningGettingNothingLevel1() {
$this->setExpectedException('PHPUnit_Framework_Error');
$var = $this->l1->nonExistant;
}
public function testWarningGettingNothingLevel2() {
$this->setExpectedException('PHPUnit_Framework_Error');
$var = $this->l2->nonExistant;
}
}

67
ws/vendor/cboden/ratchet/tests/unit/Http/Guzzle/Http/Message/RequestFactoryTest.php vendored

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
<?php
namespace Ratchet\Http\Guzzle\Http\Message;
use Ratchet\Http\Guzzle\Http\Message\RequestFactory;
/**
* @covers Ratchet\Http\Guzzle\Http\Message\RequestFactory
*/
class RequestFactoryTest extends \PHPUnit_Framework_TestCase {
protected $factory;
public function setUp() {
$this->factory = RequestFactory::getInstance();
}
public function testMessageProvider() {
return array(
'status' => 'GET / HTTP/1.1'
, 'headers' => array(
'Upgrade' => 'WebSocket'
, 'Connection' => 'Upgrade'
, 'Host' => 'localhost:8000'
, 'Sec-WebSocket-Key1' => '> b3lU Z0 fh f 3+83394 6 (zG4'
, 'Sec-WebSocket-Key2' => ',3Z0X0677 dV-d [159 Z*4'
)
, 'body' => "123456\r\n\r\n"
);
}
public function combineMessage($status, array $headers, $body = '') {
$message = $status . "\r\n";
foreach ($headers as $key => $val) {
$message .= "{$key}: {$val}\r\n";
}
$message .= "\r\n{$body}";
return $message;
}
public function testExpectedDataFromGuzzleHeaders() {
$parts = $this->testMessageProvider();
$message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']);
$object = $this->factory->fromMessage($message);
foreach ($parts['headers'] as $key => $val) {
$this->assertEquals($val, $object->getHeader($key, true));
}
}
public function testExpectedDataFromNonGuzzleHeaders() {
$parts = $this->testMessageProvider();
$message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']);
$object = $this->factory->fromMessage($message);
$this->assertNull($object->getHeader('Nope', true));
$this->assertNull($object->getHeader('Nope'));
}
public function testExpectedDataFromNonGuzzleBody() {
$parts = $this->testMessageProvider();
$message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']);
$object = $this->factory->fromMessage($message);
$this->assertEquals($parts['body'], (string)$object->getBody());
}
}

51
ws/vendor/cboden/ratchet/tests/unit/Http/HttpRequestParserTest.php vendored

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
<?php
namespace Ratchet\Http;
use Ratchet\Http\HttpRequestParser;
/**
* @covers Ratchet\Http\HttpRequestParser
*/
class HttpRequestParserTest extends \PHPUnit_Framework_TestCase {
protected $parser;
public function setUp() {
$this->parser = new HttpRequestParser;
}
public function headersProvider() {
return array(
array(false, "GET / HTTP/1.1\r\nHost: socketo.me\r\n")
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n")
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n1")
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\nHixie✖")
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\nHixie✖\r\n\r\n")
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\nHixie\r\n")
);
}
/**
* @dataProvider headersProvider
*/
public function testIsEom($expected, $message) {
$this->assertEquals($expected, $this->parser->isEom($message));
}
public function testBufferOverflowResponse() {
$conn = $this->getMock('\Ratchet\ConnectionInterface');
$this->parser->maxSize = 20;
$this->assertNull($this->parser->onMessage($conn, "GET / HTTP/1.1\r\n"));
$this->setExpectedException('OverflowException');
$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
ws/vendor/cboden/ratchet/tests/unit/Http/HttpServerTest.php vendored

@ -0,0 +1,64 @@ @@ -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
ws/vendor/cboden/ratchet/tests/unit/Http/OriginCheckTest.php vendored

@ -0,0 +1,46 @@ @@ -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!');
}
}

140
ws/vendor/cboden/ratchet/tests/unit/Http/RouterTest.php vendored

@ -0,0 +1,140 @@ @@ -0,0 +1,140 @@
<?php
namespace Ratchet\Http;
use Ratchet\Http\Router;
use Ratchet\WebSocket\WsServerInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
/**
* @covers Ratchet\Http\Router
*/
class RouterTest extends \PHPUnit_Framework_TestCase {
protected $_router;
protected $_matcher;
protected $_conn;
protected $_req;
public function setUp() {
$queryMock = $this->getMock('Guzzle\Http\QueryString');
$queryMock
->expects($this->any())
->method('getAll')
->will($this->returnValue(array()));
$this->_conn = $this->getMock('\Ratchet\ConnectionInterface');
$this->_req = $this->getMock('\Guzzle\Http\Message\RequestInterface');
$this->_req
->expects($this->any())
->method('getQuery')
->will($this->returnValue($queryMock));
$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);
}
public function testRouterGeneratesRouteParameters() {
/** @var $controller WsServerInterface */
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock();
/** @var $matcher UrlMatcherInterface */
$this->_matcher->expects($this->any())->method('match')->will(
$this->returnValue(array('_controller' => $controller, 'foo' => 'bar', 'baz' => 'qux'))
);
$conn = $this->getMock('Ratchet\Mock\Connection');
$request = $this->getMock('Guzzle\Http\Message\Request', array('getPath'), array('GET', 'ws://random.url'), '', false);
$request->expects($this->any())->method('getPath')->will($this->returnValue('ws://doesnt.matter/'));
$request->setHeaderFactory($this->getMock('Guzzle\Http\Message\Header\HeaderFactoryInterface'));
$request->setUrl('ws://doesnt.matter/');
$router = new Router($this->_matcher);
$router->onOpen($conn, $request);
$this->assertEquals(array('foo' => 'bar', 'baz' => 'qux'), $request->getQuery()->getAll());
}
public function testQueryParams() {
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock();
$this->_matcher->expects($this->any())->method('match')->will(
$this->returnValue(array('_controller' => $controller, 'foo' => 'bar', 'baz' => 'qux'))
);
$conn = $this->getMock('Ratchet\Mock\Connection');
$request = $this->getMock('Guzzle\Http\Message\Request', array('getPath'), array('GET', ''), '', false);
$request->setHeaderFactory($this->getMock('Guzzle\Http\Message\Header\HeaderFactoryInterface'));
$request->setUrl('ws://doesnt.matter?hello=world&foo=nope');
$router = new Router($this->_matcher);
$router->onOpen($conn, $request);
$this->assertEquals(array('foo' => 'nope', 'baz' => 'qux', 'hello' => 'world'), $request->getQuery()->getAll());
}
}

26
ws/vendor/cboden/ratchet/tests/unit/Server/EchoServerTest.php vendored

@ -0,0 +1,26 @@ @@ -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();
}
}

152
ws/vendor/cboden/ratchet/tests/unit/Server/FlashPolicyComponentTest.php vendored

@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
<?php
namespace Ratchet\Application\Server;
use Ratchet\Server\FlashPolicy;
/**
* @covers Ratchet\Server\FlashPolicy
*/
class FlashPolicyTest extends \PHPUnit_Framework_TestCase {
protected $_policy;
public function setUp() {
$this->_policy = new FlashPolicy();
}
public function testPolicyRender() {
$this->_policy->setSiteControl('all');
$this->_policy->addAllowedAccess('example.com', '*');
$this->_policy->addAllowedAccess('dev.example.com', '*');
$this->assertInstanceOf('SimpleXMLElement', $this->_policy->renderPolicy());
}
public function testInvalidPolicyReader() {
$this->setExpectedException('UnexpectedValueException');
$this->_policy->renderPolicy();
}
public function testInvalidDomainPolicyReader() {
$this->setExpectedException('UnexpectedValueException');
$this->_policy->setSiteControl('all');
$this->_policy->addAllowedAccess('dev.example.*', '*');
$this->_policy->renderPolicy();
}
/**
* @dataProvider siteControl
*/
public function testSiteControlValidation($accept, $permittedCrossDomainPolicies) {
$this->assertEquals($accept, $this->_policy->validateSiteControl($permittedCrossDomainPolicies));
}
public static function siteControl() {
return array(
array(true, 'all')
, array(true, 'none')
, array(true, 'master-only')
, array(false, 'by-content-type')
, array(false, 'by-ftp-filename')
, array(false, '')
, array(false, 'all ')
, array(false, 'asdf')
, array(false, '@893830')
, array(false, '*')
);
}
/**
* @dataProvider URI
*/
public function testDomainValidation($accept, $domain) {
$this->assertEquals($accept, $this->_policy->validateDomain($domain));
}
public static function URI() {
return array(
array(true, '*')
, array(true, 'example.com')
, array(true, 'exam-ple.com')
, array(true, '*.example.com')
, array(true, 'www.example.com')
, array(true, 'dev.dev.example.com')
, array(true, 'http://example.com')
, array(true, 'https://example.com')
, array(true, 'http://*.example.com')
, array(false, 'exam*ple.com')
, array(true, '127.0.255.1')
, array(true, 'localhost')
, array(false, 'www.example.*')
, array(false, 'www.exa*le.com')
, array(false, 'www.example.*com')
, array(false, '*.example.*')
, array(false, 'gasldf*$#a0sdf0a8sdf')
);
}
/**
* @dataProvider ports
*/
public function testPortValidation($accept, $ports) {
$this->assertEquals($accept, $this->_policy->validatePorts($ports));
}
public static function ports() {
return array(
array(true, '*')
, array(true, '80')
, array(true, '80,443')
, array(true, '507,516-523')
, array(true, '507,516-523,333')
, array(true, '507,516-523,507,516-523')
, array(false, '516-')
, array(true, '516-523,11')
, array(false, '516,-523,11')
, array(false, 'example')
, array(false, 'asdf,123')
, array(false, '--')
, array(false, ',,,')
, array(false, '838*')
);
}
public function testAddAllowedAccessOnlyAcceptsValidPorts() {
$this->setExpectedException('UnexpectedValueException');
$this->_policy->addAllowedAccess('*', 'nope');
}
public function testSetSiteControlThrowsException() {
$this->setExpectedException('UnexpectedValueException');
$this->_policy->setSiteControl('nope');
}
public function testErrorClosesConnection() {
$conn = $this->getMock('\\Ratchet\\ConnectionInterface');
$conn->expects($this->once())->method('close');
$this->_policy->onError($conn, new \Exception);
}
public function testOnMessageSendsString() {
$this->_policy->addAllowedAccess('*', '*');
$conn = $this->getMock('\\Ratchet\\ConnectionInterface');
$conn->expects($this->once())->method('send')->with($this->isType('string'));
$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);
}
}

32
ws/vendor/cboden/ratchet/tests/unit/Server/IoConnectionTest.php vendored

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
<?php
namespace Ratchet\Application\Server;
use Ratchet\Server\IoConnection;
/**
* @covers Ratchet\Server\IoConnection
*/
class IoConnectionTest extends \PHPUnit_Framework_TestCase {
protected $sock;
protected $conn;
public function setUp() {
$this->sock = $this->getMock('\\React\\Socket\\ConnectionInterface');
$this->conn = new IoConnection($this->sock);
}
public function testCloseBubbles() {
$this->sock->expects($this->once())->method('end');
$this->conn->close();
}
public function testSendBubbles() {
$msg = '6 hour rides are productive';
$this->sock->expects($this->once())->method('write')->with($msg);
$this->conn->send($msg);
}
public function testSendReturnsSelf() {
$this->assertSame($this->conn, $this->conn->send('fluent interface'));
}
}

118
ws/vendor/cboden/ratchet/tests/unit/Server/IoServerTest.php vendored

@ -0,0 +1,118 @@ @@ -0,0 +1,118 @@
<?php
namespace Ratchet\Server;
use Ratchet\Server\IoServer;
use React\EventLoop\StreamSelectLoop;
use React\Socket\Server;
/**
* @covers Ratchet\Server\IoServer
*/
class IoServerTest extends \PHPUnit_Framework_TestCase {
protected $server;
protected $app;
protected $port;
protected $reactor;
public function setUp() {
$this->app = $this->getMock('\\Ratchet\\MessageComponentInterface');
$loop = new StreamSelectLoop;
$this->reactor = new Server($loop);
$this->reactor->listen(0);
$this->port = $this->reactor->getPort();
$this->server = new IoServer($this->app, $this->reactor, $loop);
}
public function testOnOpen() {
$this->app->expects($this->once())->method('onOpen')->with($this->isInstanceOf('\\Ratchet\\ConnectionInterface'));
$client = stream_socket_client("tcp://localhost:{$this->port}");
$this->server->loop->tick();
//$this->assertTrue(is_string($this->app->last['onOpen'][0]->remoteAddress));
//$this->assertTrue(is_int($this->app->last['onOpen'][0]->resourceId));
}
public function testOnData() {
$msg = 'Hello World!';
$this->app->expects($this->once())->method('onMessage')->with(
$this->isInstanceOf('\\Ratchet\\ConnectionInterface')
, $msg
);
$client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($client, SOL_SOCKET, SO_REUSEADDR, 1);
socket_set_option($client, SOL_SOCKET, SO_SNDBUF, 4096);
socket_set_block($client);
socket_connect($client, 'localhost', $this->port);
$this->server->loop->tick();
socket_write($client, $msg);
$this->server->loop->tick();
socket_shutdown($client, 1);
socket_shutdown($client, 0);
socket_close($client);
$this->server->loop->tick();
}
public function testOnClose() {
$this->app->expects($this->once())->method('onClose')->with($this->isInstanceOf('\\Ratchet\\ConnectionInterface'));
$client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($client, SOL_SOCKET, SO_REUSEADDR, 1);
socket_set_option($client, SOL_SOCKET, SO_SNDBUF, 4096);
socket_set_block($client);
socket_connect($client, 'localhost', $this->port);
$this->server->loop->tick();
socket_shutdown($client, 1);
socket_shutdown($client, 0);
socket_close($client);
$this->server->loop->tick();
}
public function testFactory() {
$this->assertInstanceOf('\\Ratchet\\Server\\IoServer', IoServer::factory($this->app, 0));
}
public function testNoLoopProvidedError() {
$this->setExpectedException('RuntimeException');
$io = new IoServer($this->app, $this->reactor);
$io->run();
}
public function testOnErrorPassesException() {
$conn = $this->getMock('\\React\\Socket\\ConnectionInterface');
$conn->decor = $this->getMock('\\Ratchet\\ConnectionInterface');
$err = new \Exception("Nope");
$this->app->expects($this->once())->method('onError')->with($conn->decor, $err);
$this->server->handleError($err, $conn);
}
public function onErrorCalledWhenExceptionThrown() {
$this->markTestIncomplete("Need to learn how to throw an exception from a mock");
$conn = $this->getMock('\\React\\Socket\\ConnectionInterface');
$this->server->handleConnect($conn);
$e = new \Exception;
$this->app->expects($this->once())->method('onMessage')->with($this->isInstanceOf('\\Ratchet\\ConnectionInterface'), 'f')->will($e);
$this->app->expects($this->once())->method('onError')->with($this->instanceOf('\\Ratchet\\ConnectionInterface', $e));
$this->server->handleData('f', $conn);
}
}

125
ws/vendor/cboden/ratchet/tests/unit/Server/IpBlackListComponentTest.php vendored

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
<?php
namespace Ratchet\Server;
use Ratchet\Server\IpBlackList;
/**
* @covers Ratchet\Server\IpBlackList
*/
class IpBlackListTest extends \PHPUnit_Framework_TestCase {
protected $blocker;
protected $mock;
public function setUp() {
$this->mock = $this->getMock('\\Ratchet\\MessageComponentInterface');
$this->blocker = new IpBlackList($this->mock);
}
public function testOnOpen() {
$this->mock->expects($this->exactly(3))->method('onOpen');
$conn1 = $this->newConn();
$conn2 = $this->newConn();
$conn3 = $this->newConn();
$this->blocker->onOpen($conn1);
$this->blocker->onOpen($conn3);
$this->blocker->onOpen($conn2);
}
public function testBlockDoesNotTriggerOnOpen() {
$conn = $this->newConn();
$this->blocker->blockAddress($conn->remoteAddress);
$this->mock->expects($this->never())->method('onOpen');
$ret = $this->blocker->onOpen($conn);
}
public function testBlockDoesNotTriggerOnClose() {
$conn = $this->newConn();
$this->blocker->blockAddress($conn->remoteAddress);
$this->mock->expects($this->never())->method('onClose');
$ret = $this->blocker->onOpen($conn);
}
public function testOnMessageDecoration() {
$conn = $this->newConn();
$msg = 'Hello not being blocked';
$this->mock->expects($this->once())->method('onMessage')->with($conn, $msg);
$this->blocker->onMessage($conn, $msg);
}
public function testOnCloseDecoration() {
$conn = $this->newConn();
$this->mock->expects($this->once())->method('onClose')->with($conn);
$this->blocker->onClose($conn);
}
public function testBlockClosesConnection() {
$conn = $this->newConn();
$this->blocker->blockAddress($conn->remoteAddress);
$conn->expects($this->once())->method('close');
$this->blocker->onOpen($conn);
}
public function testAddAndRemoveWithFluentInterfaces() {
$blockOne = '127.0.0.1';
$blockTwo = '192.168.1.1';
$unblock = '75.119.207.140';
$this->blocker
->blockAddress($unblock)
->blockAddress($blockOne)
->unblockAddress($unblock)
->blockAddress($blockTwo)
;
$this->assertEquals(array($blockOne, $blockTwo), $this->blocker->getBlockedAddresses());
}
public function testDecoratorPassesErrors() {
$conn = $this->newConn();
$e = new \Exception('I threw an error');
$this->mock->expects($this->once())->method('onError')->with($conn, $e);
$this->blocker->onError($conn, $e);
}
public function addressProvider() {
return array(
array('127.0.0.1', '127.0.0.1')
, array('localhost', 'localhost')
, array('fe80::1%lo0', 'fe80::1%lo0')
, array('127.0.0.1', '127.0.0.1:6392')
);
}
/**
* @dataProvider addressProvider
*/
public function testFilterAddress($expected, $input) {
$this->assertEquals($expected, $this->blocker->filterAddress($input));
}
public function testUnblockingSilentlyFails() {
$this->assertInstanceOf('\\Ratchet\\Server\\IpBlackList', $this->blocker->unblockAddress('localhost'));
}
protected function newConn() {
$conn = $this->getMock('\\Ratchet\\ConnectionInterface');
$conn->remoteAddress = '127.0.0.1';
return $conn;
}
}

43
ws/vendor/cboden/ratchet/tests/unit/Session/Serialize/PhpHandlerTest.php vendored

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
<?php
namespace Ratchet\Session\Serialize;
use Ratchet\Session\Serialize\PhpHandler;
/**
* @covers Ratchet\Session\Serialize\PhpHandler
*/
class PhpHandlerTest extends \PHPUnit_Framework_TestCase {
protected $_handler;
public function setUp() {
$this->_handler = new PhpHandler;
}
public function serializedProvider() {
return array(
array(
'_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}'
, array(
'_sf2_attributes' => array(
'hello' => 'world'
, 'last' => 1332872102
)
, '_sf2_flashes' => array()
)
)
);
}
/**
* @dataProvider serializedProvider
*/
public function testUnserialize($in, $expected) {
$this->assertEquals($expected, $this->_handler->unserialize($in));
}
/**
* @dataProvider serializedProvider
*/
public function testSerialize($serialized, $original) {
$this->assertEquals($serialized, $this->_handler->serialize($original));
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save