Full Code of ratchetphp/Ratchet for AI

0.4.x 9ac6a412a26d cached
87 files
188.1 KB
50.0k tokens
479 symbols
1 requests
Download .txt
Showing preview only (209K chars total). Download the full file or copy to clipboard to get everything.
Repository: ratchetphp/Ratchet
Branch: 0.4.x
Commit: 9ac6a412a26d
Files: 87
Total size: 188.1 KB

Directory structure:
gitextract_uifflmqw/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bugreport.yml
│   │   └── config.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── composer.json
├── phpunit.xml.dist
├── phpunit.xml.legacy
├── src/
│   └── Ratchet/
│       ├── AbstractConnectionDecorator.php
│       ├── App.php
│       ├── ComponentInterface.php
│       ├── ConnectionInterface.php
│       ├── Http/
│       │   ├── CloseResponseTrait.php
│       │   ├── HttpRequestParser.php
│       │   ├── HttpServer.php
│       │   ├── HttpServerInterface.php
│       │   ├── NoOpHttpServerController.php
│       │   ├── OriginCheck.php
│       │   └── Router.php
│       ├── MessageComponentInterface.php
│       ├── MessageInterface.php
│       ├── Server/
│       │   ├── EchoServer.php
│       │   ├── FlashPolicy.php
│       │   ├── IoConnection.php
│       │   ├── IoServer.php
│       │   └── IpBlackList.php
│       ├── Session/
│       │   ├── Serialize/
│       │   │   ├── HandlerInterface.php
│       │   │   ├── PhpBinaryHandler.php
│       │   │   └── PhpHandler.php
│       │   ├── SessionProvider.php
│       │   └── Storage/
│       │       ├── Proxy/
│       │       │   ├── VirtualProxy.php
│       │       │   ├── VirtualProxyForSymfony6.php
│       │       │   └── VirtualProxyForSymfony7.php
│       │       ├── VirtualSessionStorage.php
│       │       ├── VirtualSessionStorageForSymfony6.php
│       │       └── VirtualSessionStorageForSymfony7.php
│       ├── Wamp/
│       │   ├── Exception.php
│       │   ├── JsonException.php
│       │   ├── ServerProtocol.php
│       │   ├── Topic.php
│       │   ├── TopicManager.php
│       │   ├── WampConnection.php
│       │   ├── WampServer.php
│       │   └── WampServerInterface.php
│       └── WebSocket/
│           ├── ConnContext.php
│           ├── MessageCallableInterface.php
│           ├── MessageComponentInterface.php
│           ├── WsConnection.php
│           ├── WsServer.php
│           └── WsServerInterface.php
└── tests/
    ├── autobahn/
    │   ├── bin/
    │   │   └── fuzzingserver.php
    │   ├── fuzzingclient-all.json
    │   ├── fuzzingclient-profile.json
    │   └── fuzzingclient-quick.json
    ├── bootstrap.php
    ├── helpers/
    │   └── Ratchet/
    │       ├── AbstractMessageComponentTestCase.php
    │       ├── Mock/
    │       │   ├── Connection.php
    │       │   ├── ConnectionDecorator.php
    │       │   └── WampComponent.php
    │       ├── NullComponent.php
    │       ├── Wamp/
    │       │   └── Stub/
    │       │       └── WsWampServerInterface.php
    │       └── WebSocket/
    │           └── Stub/
    │               └── WsMessageComponentInterface.php
    └── unit/
        ├── AbstractConnectionDecoratorTest.php
        ├── AppTest.php
        ├── Http/
        │   ├── HttpRequestParserTest.php
        │   ├── HttpServerTest.php
        │   ├── OriginCheckTest.php
        │   └── RouterTest.php
        ├── Server/
        │   ├── EchoServerTest.php
        │   ├── FlashPolicyComponentTest.php
        │   ├── IoConnectionTest.php
        │   ├── IoServerTest.php
        │   └── IpBlackListComponentTest.php
        ├── Session/
        │   ├── Serialize/
        │   │   ├── PhpBinaryHandlerTest.php
        │   │   └── PhpHandlerTest.php
        │   ├── SessionProviderTest.php
        │   └── Storage/
        │       └── VirtualSessionStoragePDOTest.php
        └── Wamp/
            ├── ServerProtocolTest.php
            ├── TopicManagerTest.php
            ├── TopicTest.php
            ├── WampConnectionTest.php
            └── WampServerTest.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
github: 
    - ReactPHP
    - clue 
    - cboden


================================================
FILE: .github/ISSUE_TEMPLATE/bugreport.yml
================================================
name: "🐛 Bug Report"
description: "Found a bug in our project? Create a report to help us improve."
body:
  - type: markdown
    attributes:
      value: "Thanks for helping improve Ratchet by reporting a bug! 
    Please check [existing Issues](https://github.com/ratchetphp/Ratchet/issues) before submitting."
  
  - type: textarea
    id: reproduction
    attributes:
      label: "Reproduction Steps"
      description: "Exact steps to reproduce (include code samples)"
    validations:
      required: true

  - type: textarea
    id: environment
    attributes:
      label: "Runtime Environment"
      placeholder: "PHP version, Ratchet version, etc."
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
  - name: "Ratchet Discussions"
    url: https://github.com/ratchetphp/Ratchet/discussions
    about: 'We are happy to answer your questions! Start a new discussion in our "Q&A" category.'
  - name: "Feature Requests"
    url: https://github.com/ratchetphp/Ratchet/discussions/categories/ideas
    about: 'You have ideas to improve our project? Start a new discussion in our "Ideas" category.'


================================================
FILE: .github/workflows/ci.yml
================================================
name: "CI"

on:
  push:
  pull_request:

jobs:
  phpunit:
    name: "PHPUnit"
    runs-on: "ubuntu-24.04"

    strategy:
      matrix:
        php-version:
          - "5.4"
          - "5.5"
          - "5.6"
          - "7.0"
          - "7.1"
          - "7.2"
          - "7.3"
          - "7.4"
          - "8.0"
          - "8.1"
          - "8.2"
          - "8.3"
          - "8.4"
        dependencies:
          - "highest"
        include:
          - dependencies: "lowest"
            php-version: "5.4"

    steps:
      - name: "Checkout"
        uses: "actions/checkout@v4"
        with:
          fetch-depth: 2

      - name: "Install PHP"
        uses: "shivammathur/setup-php@v2"
        with:
          php-version: "${{ matrix.php-version }}"
          coverage: "none"
          ini-values: "zend.assertions=1"

      - name: "Install dependencies with Composer"
        uses: "ramsey/composer-install@v3"
        with:
          dependency-versions: "${{ matrix.dependencies }}"

      - name: "Run PHPUnit"
        run: "vendor/bin/phpunit ${{ matrix.php-version < 7.3 && ' -c phpunit.xml.legacy' || '' }}"


================================================
FILE: .gitignore
================================================
phpunit.xml
reports
sandbox
vendor
composer.lock

================================================
FILE: CHANGELOG.md
================================================
CHANGELOG
=========

### Legend

* "BC": Backwards compatibility break (from public component APIs)
* "BF": Bug fix

---

* 0.4.4 (2021-12-11)
  * Correct and update dependencies for forward compatibility
  * Added context for React Socket server to App
  * Use non-deprecated Guzzle API calls

* 0.4.3 (2020-06-04)
  * BF: Fixed interface acceptable regression in `App`
  * Update RFC6455 library with latest fixes

* 0.4.2 (2020-01-27)
  * Support Symfony 5
  * BF: Use phpunit from vendor directory
  * Allow disabling of xdebug warning by defining `RATCHET_DISABLE_XDEBUG_WARN`
  * Stop using `LoopInterface::tick()` for testing

* 0.4.1 (2017-12-11)
  * Only enableKeepAlive in App if no WsServer passed allowing user to set their own timeout duration
  * Support Symfony 4
  * BF: Plug NOOP controller in connection from router in case of misbehaving client
  * BF: Raise error from invalid WAMP payload

* 0.4 (2017-09-14)
  * BC: $conn->WebSocket->request replaced with $conn->httpRequest which is a PSR-7 object
  * Binary messages now supported via Ratchet\WebSocket\MessageComponentInterface
  * Added heartbeat support via ping/pong in WsServer
  * BC: No longer support old (and insecure) Hixie76 and Hybi protocols
  * BC: No longer support disabling UTF-8 checks
  * BC: The Session component implements HttpServerInterface instead of WsServerInterface
  * BC: PHP 5.3 no longer supported
  * BC: Update to newer version of react/socket dependency
  * BC: WAMP topics reduced to 0 subscriptions are deleted, new subs to same name will result in new Topic instance
  * Significant performance enhancements

* 0.3.6 (2017-01-06)
  * BF: Keep host and scheme in HTTP request object attatched to connection
  * BF: Return correct HTTP response (405) when non-GET request made

* 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


================================================
FILE: LICENSE
================================================
Copyright (c) 2011 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.


================================================
FILE: Makefile
================================================
# 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:
	vendor/bin/phpunit

cover:
	vendor/bin/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.php 8004 LibEv &
	wstest -m testeeserver -w ws://localhost:8000 &
	sleep 1
	wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-all.json
	killall php wstest

abtest:
	ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8000 StreamSelect &
	sleep 1
	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 &
	sleep 1
	wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-profile.json
	killall php

apidocs:
	apigen --title Ratchet -d reports/api \
		-s src/ \
		-s vendor/ratchet/rfc6455/src \
		-s vendor/react/event-loop/src \
		-s vendor/react/socket/src \
		-s vendor/react/stream/src \
		-s vendor/psr/http-message/src \
		-s vendor/symfony/http-foundation/Session \
		-s vendor/symfony/routing \
		-s vendor/evenement/evenement/src/Evenement \
		--exclude=vendor/symfony/routing/Tests \


================================================
FILE: README.md
================================================
# Ratchet

[![CI status](https://github.com/ratchetphp/Ratchet/actions/workflows/ci.yml/badge.svg)](https://github.com/ratchetphp/Ratchet/actions)
[![Autobahn Testsuite](https://img.shields.io/badge/Autobahn-passing-brightgreen.svg)](http://socketo.me/reports/ab/index.html)
[![Latest Stable Version](https://poser.pugx.org/cboden/ratchet/v/stable.png)](https://packagist.org/packages/cboden/ratchet)

A PHP 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.

## Reviving Ratchet!

We're currently aiming to revive Ratchet to get it up to date with the latest versions and use this as a starting point for bigger updates to come.
We need your help to achieve this goal, see [ticket #1054](https://github.com/ratchetphp/Ratchet/issues/1054) for ways to help out. ❤️

## 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#server_configuration).

### 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, array('*'));
    $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.onopen = function(e) { conn.send('Hello Me!'); };
```

## Install

The recommended way to install this library is [through Composer](https://getcomposer.org/).
[New to Composer?](https://getcomposer.org/doc/00-intro.md)

This will install the latest supported version:

```bash
composer require cboden/ratchet:^0.4.4
```

See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP
extensions and supports running on legacy PHP 5.4 through current PHP 8+.
It's *highly recommended to use the latest supported PHP version* for this project.

See above note about [Reviving Ratchet](#reviving-ratchet) for newer PHP support.

## License

MIT, see [LICENSE file](LICENSE).


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Reporting a Vulnerability

Please report security issues to:
    
* Chris Boden [cboden@gmail.com](cboden@gmail.com)
* Matt Bonneau [matt@bonneau.net](matt@bonneau.net)


================================================
FILE: composer.json
================================================
{
    "name": "cboden/ratchet"
  , "type": "library"
  , "description": "PHP WebSocket library"
  , "keywords": ["WebSockets", "Server", "Ratchet", "Sockets", "WebSocket"]
  , "homepage": "http://socketo.me"
  , "license": "MIT"
  , "authors": [
        {
            "name": "Chris Boden"
          , "email": "cboden@gmail.com"
          , "role": "Developer"
        }
      , {
            "name": "Matt Bonneau"
          , "role": "Developer"
        }
    ]
  , "support": {
        "issues": "https://github.com/ratchetphp/Ratchet/issues"
      , "chat":    "https://gitter.im/reactphp/reactphp"
    }
  , "autoload": {
        "psr-4": {
            "Ratchet\\": "src/Ratchet"
        }
    }
  , "require": {
        "php": ">=5.4.2"
      , "ratchet/rfc6455": "^0.4.0 | ^0.3.1"
      , "react/socket": "^1.0 || ^0.8 || ^0.7 || ^0.6 || ^0.5"
      , "react/event-loop": "^1.0 || ^0.5 || ^0.4"
      , "guzzlehttp/psr7": "^1.7|^2.0"
      , "symfony/http-foundation": "^2.6|^3.0|^4.0|^5.0|^6.0|^7.0"
      , "symfony/routing": "^2.6|^3.0|^4.0|^5.0|^6.0|^7.0"
    }
  , "require-dev": {
        "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
    }
}


================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>

<!-- PHPUnit configuration file with new format for PHPUnit 9.6+ -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd"
         bootstrap="tests/bootstrap.php"
         cacheResult="false"
         colors="true"
         convertDeprecationsToExceptions="true">
    <testsuites>
        <testsuite name="Ratchet test suite">
            <directory>./tests/unit/</directory>
        </testsuite>
    </testsuites>
    <coverage>
        <include>
            <directory>./src/</directory>
        </include>
    </coverage>
    <php>
        <ini name="error_reporting" value="-1" />
    </php>
</phpunit>


================================================
FILE: phpunit.xml.legacy
================================================
<?xml version="1.0" encoding="UTF-8"?>

<!-- PHPUnit configuration file with old format for legacy PHPUnit -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/4.8/phpunit.xsd"
         bootstrap="tests/bootstrap.php"
         colors="true">
    <testsuites>
        <testsuite name="Ratchet Test Suite">
            <directory>./tests/unit/</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist>
            <directory>./src/</directory>
        </whitelist>
    </filter>
    <php>
        <ini name="error_reporting" value="-1" />
    </php>
</phpunit>


================================================
FILE: src/Ratchet/AbstractConnectionDecorator.php
================================================
<?php
namespace Ratchet;

/**
 * Wraps ConnectionInterface objects via the decorator pattern but allows
 * parameters to bubble through with magic methods
 *
 * Note that this instance does not use the `#[\AllowDynamicProperties]`
 * attribute for PHP 8.2+ compatibility as any properties added to this class
 * will be forwarded to the wrapped instance.
 *
 * @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);
    }
}


================================================
FILE: src/Ratchet/App.php
================================================
<?php
namespace Ratchet;
use React\EventLoop\Factory as LegacyLoopFactory;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\Socket\Server as LegacySocketServer;
use React\Socket\SocketServer;
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\MessageComponentInterface as WsMessageComponentInterface;
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.
     * @param array          $context
     */
    public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', $loop = null, $context = array()) {
        if (extension_loaded('xdebug') && getenv('RATCHET_DISABLE_XDEBUG_WARN') === false) {
            trigger_error('XDebug extension detected. Remember to disable this if performance testing or going live!', E_USER_WARNING);
        }
        if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1
            throw new \InvalidArgumentException('Argument #4 ($loop) expected null|React\EventLoop\LoopInterface');
        }

        if (null === $loop) {
            // prefer default Loop (reactphp/event-loop v1.2+) over legacy \React\EventLoop\Factory
            $loop = class_exists('React\EventLoop\Loop') ? Loop::get() : LegacyLoopFactory::create();
        }

        $this->httpHost = $httpHost;
        $this->port = $port;

        // prefer SocketServer (reactphp/socket v1.9+) over legacy \React\Socket\Server
        $socket = class_exists('React\Socket\SocketServer') ? new SocketServer($address . ':' . $port, $context, $loop) : new LegacySocketServer($address . ':' . $port, $loop, $context);

        $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);

        if (80 == $port) {
            $flashUri = '0.0.0.0:843';
        } else {
            $flashUri = '127.0.0.1:8843';
        }

        // prefer SocketServer (reactphp/socket v1.9+) over legacy \React\Socket\Server
        $flashSock = class_exists('React\Socket\SocketServer') ? new SocketServer($flashUri, [], $loop) : new LegacySocketServer($flashUri, $loop);
        $this->flashServer = new IoServer($policy, $flashSock);
    }

    /**
     * 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));
            $decorated->enableKeepAlive($this->_server->loop);
        } elseif ($controller instanceof MessageComponentInterface || $controller instanceof WsMessageComponentInterface) {
            $decorated = new WsServer($controller);
            $decorated->enableKeepAlive($this->_server->loop);
        } 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, array(), array('GET')));

        return $decorated;
    }

    /**
     * Run the server by entering the event loop
     */
    public function run() {
        $this->_server->run();
    }
}


================================================
FILE: src/Ratchet/ComponentInterface.php
================================================
<?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);
}


================================================
FILE: src/Ratchet/ConnectionInterface.php
================================================
<?php
namespace Ratchet;

/**
 * The version of Ratchet being used
 * @var string
 */
const VERSION = 'Ratchet/0.4.4';

/**
 * A proxy object representing a connection to the application
 * This acts as a container to store data (in memory) about the connection
 *
 * Note that Ratchet makes heavy use of the decorator pattern and dynamic
 * properties. This means any object that implements this interface may not
 * have the same methods or properties as the ones in this interface.
 * Implementations of this interface may have to use the `#[\AllowDynamicProperties]`
 * attribute to allow dynamic properties on PHP 8.2+.
 */
interface ConnectionInterface {
    /**
     * Send data to the connection
     * @param  string $data
     * @return \Ratchet\ConnectionInterface
     */
    function send($data);

    /**
     * Close the connection
     */
    function close();
}


================================================
FILE: src/Ratchet/Http/CloseResponseTrait.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\ConnectionInterface;
use GuzzleHttp\Psr7\Message;
use GuzzleHttp\Psr7\Response;

trait CloseResponseTrait {
    /**
     * Close a connection with an HTTP response
     * @param \Ratchet\ConnectionInterface $conn
     * @param int                          $code HTTP status code
     * @return null
     */
    private function close(ConnectionInterface $conn, $code = 400, array $additional_headers = []) {
        $response = new Response($code, array_merge([
            'X-Powered-By' => \Ratchet\VERSION
        ], $additional_headers));

        $conn->send(Message::toString($response));
        $conn->close();
    }
}


================================================
FILE: src/Ratchet/Http/HttpRequestParser.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\MessageInterface;
use Ratchet\ConnectionInterface;
use GuzzleHttp\Psr7\Message;

/**
 * This class receives streaming data from a client request
 * and parses HTTP headers, returning a PSR-7 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 \Psr\Http\Message\RequestInterface
     * @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 = $this->parse($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 strpos($message, static::EOM) !== false;
    }

    /**
     * @param string $headers
     * @return \Psr\Http\Message\RequestInterface
     */
    public function parse($headers) {
        return Message::parseRequest($headers);
    }
}


================================================
FILE: src/Ratchet/Http/HttpServer.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class HttpServer implements MessageComponentInterface {
    use CloseResponseTrait;

    /**
     * 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);
        }
    }
}


================================================
FILE: src/Ratchet/Http/HttpServerInterface.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Psr\Http\Message\RequestInterface;

interface HttpServerInterface extends MessageComponentInterface {
    /**
     * @param \Ratchet\ConnectionInterface          $conn
     * @param \Psr\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
     */
    #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null); /*
    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null); /**/
}


================================================
FILE: src/Ratchet/Http/NoOpHttpServerController.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\ConnectionInterface;
use Psr\Http\Message\RequestInterface;

class NoOpHttpServerController implements HttpServerInterface {
    #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null) { /*
    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { /**/
    }

    public function onMessage(ConnectionInterface $from, $msg) {
    }

    public function onClose(ConnectionInterface $conn) {
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
    }
}


================================================
FILE: src/Ratchet/Http/OriginCheck.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
use Psr\Http\Message\RequestInterface;

/**
 * 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 {
    use CloseResponseTrait;

    /**
     * @var \Ratchet\MessageComponentInterface
     */
    protected $_component;

    public $allowedOrigins = [];

    /**
     * @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 = []) {
        $this->_component = $component;
        $this->allowedOrigins += $allowed;
    }

    /**
     * {@inheritdoc}
     */
    #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null) { /*
    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { /**/
        $header = $request->getHeaderLine('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);
    }
}

================================================
FILE: src/Ratchet/Http/Router.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\ConnectionInterface;
use Psr\Http\Message\RequestInterface;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use GuzzleHttp\Psr7\Query;

class Router implements HttpServerInterface {
    use CloseResponseTrait;

    /**
     * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface
     */
    protected $_matcher;

    private $_noopController;

    public function __construct(UrlMatcherInterface $matcher) {
        $this->_matcher = $matcher;
        $this->_noopController = new NoOpHttpServerController;
    }

    /**
     * {@inheritdoc}
     * @throws \UnexpectedValueException If a controller is not \Ratchet\Http\HttpServerInterface
     */
    #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null) { /*
    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { /**/
        if (null === $request) {
            throw new \UnexpectedValueException('$request can not be null');
        }

        $conn->controller = $this->_noopController;

        $uri = $request->getUri();

        $context = $this->_matcher->getContext();
        $context->setMethod($request->getMethod());
        $context->setHost($uri->getHost());

        try {
            $route = $this->_matcher->match($uri->getPath());
        } catch (MethodNotAllowedException $nae) {
            return $this->close($conn, 405, array('Allow' => $nae->getAllowedMethods()));
        } 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 = [];
        foreach($route as $key => $value) {
            if ((is_string($key)) && ('_' !== substr($key, 0, 1))) {
                $parameters[$key] = $value;
            }
        }
        $parameters = array_merge($parameters, Query::parse($uri->getQuery() ?: ''));

        $request = $request->withUri($uri->withQuery(Query::build($parameters)));

        $conn->controller = $route['_controller'];
        $conn->controller->onOpen($conn, $request);
    }

    /**
     * {@inheritdoc}
     */
    public function onMessage(ConnectionInterface $from, $msg) {
        $from->controller->onMessage($from, $msg);
    }

    /**
     * {@inheritdoc}
     */
    public function onClose(ConnectionInterface $conn) {
        if (isset($conn->controller)) {
            $conn->controller->onClose($conn);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function onError(ConnectionInterface $conn, \Exception $e) {
        if (isset($conn->controller)) {
            $conn->controller->onError($conn, $e);
        }
    }
}


================================================
FILE: src/Ratchet/MessageComponentInterface.php
================================================
<?php
namespace Ratchet;

interface MessageComponentInterface extends ComponentInterface, MessageInterface {
}


================================================
FILE: src/Ratchet/MessageInterface.php
================================================
<?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);
}


================================================
FILE: src/Ratchet/Server/EchoServer.php
================================================
<?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();
    }
}


================================================
FILE: src/Ratchet/Server/FlashPolicy.php
================================================
<?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);
    }
}


================================================
FILE: src/Ratchet/Server/IoConnection.php
================================================
<?php
namespace Ratchet\Server;
use Ratchet\ConnectionInterface;
use React\Socket\ConnectionInterface as SocketConnection;

/**
 * {@inheritdoc}
 */
#[\AllowDynamicProperties]
class IoConnection implements ConnectionInterface {
    /**
     * @var \React\Socket\ConnectionInterface
     */
    protected $conn;


    /**
     * @param \React\Socket\ConnectionInterface $conn
     */
    public function __construct(SocketConnection $conn) {
        $this->conn = $conn;
    }

    /**
     * {@inheritdoc}
     */
    public function send($data) {
        $this->conn->write($data);

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function close() {
        $this->conn->end();
    }
}


================================================
FILE: src/Ratchet/Server/IoServer.php
================================================
<?php
namespace Ratchet\Server;
use Ratchet\MessageComponentInterface;
use React\EventLoop\Factory as LegacyLoopFactory;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\Socket\ConnectionInterface as SocketConnection;
use React\Socket\Server as LegacySocketServer;
use React\Socket\ServerInterface;
use React\Socket\SocketServer;

/**
 * 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;

    /**
     * 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, $loop = null) {
        if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1
            throw new \InvalidArgumentException('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
        }

        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'));
    }

    /**
     * @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') {
        // prefer default Loop (reactphp/event-loop v1.2+) over legacy \React\EventLoop\Factory
        $loop = class_exists('React\EventLoop\Loop') ? Loop::get() : LegacyLoopFactory::create();

        // prefer SocketServer (reactphp/socket v1.9+) over legacy \React\Socket\Server
        $socket = class_exists('React\Socket\SocketServer') ? new SocketServer($address . ':' . $port, [], $loop) : new LegacySocketServer($address . ':' . $port, $loop);

        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(SocketConnection $conn) {
        // assign dynamic `$decor` property used by Ratchet without raising notice on PHP 8.2+
        // need this hack because we can't use `#[\AllowDynamicProperties]` on vendor code
        set_error_handler(function () { }, E_DEPRECATED);
        $conn->decor = new IoConnection($conn);
        restore_error_handler();

        $conn->decor->resourceId = (int)$conn->stream;

        $uri = (string) $conn->getRemoteAddress();
        $conn->decor->remoteAddress = trim(
            parse_url((strpos($uri, '://') === false ? 'tcp://' : '') . $uri, PHP_URL_HOST),
            '[]'
        );

        $this->app->onOpen($conn->decor);

        $conn->on('data', function ($data) use ($conn) {
            $this->handleData($data, $conn);
        });
        $conn->on('close', function () use ($conn) {
            $this->handleEnd($conn);
        });
        $conn->on('error', function (\Exception $e) use ($conn) {
            $this->handleError($e, $conn);
        });
    }

    /**
     * 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);
    }
}


================================================
FILE: src/Ratchet/Server/IpBlackList.php
================================================
<?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);
        }
    }
}


================================================
FILE: src/Ratchet/Session/Serialize/HandlerInterface.php
================================================
<?php
namespace Ratchet\Session\Serialize;

interface HandlerInterface {
    /**
     * @param array
     * @return string
     */
    function serialize(array $data);

    /**
     * @param string
     * @return array
     */
    function unserialize($raw);
}


================================================
FILE: src/Ratchet/Session/Serialize/PhpBinaryHandler.php
================================================
<?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;

            // try to unserialize one piece of data from current offset, ignoring any warnings for trailing data on PHP 8.3+
            // @link https://wiki.php.net/rfc/unserialize_warn_on_trailing_data
            $data = @unserialize(substr($raw, $offset));

            $returnData[$varname] = $data;
            $offset += strlen(serialize($data));
        }

        return $returnData;
    }
}


================================================
FILE: src/Ratchet/Session/Serialize/PhpHandler.php
================================================
<?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;

            // try to unserialize one piece of data from current offset, ignoring any warnings for trailing data on PHP 8.3+
            // @link https://wiki.php.net/rfc/unserialize_warn_on_trailing_data
            $data = @unserialize(substr($raw, $offset));

            $returnData[$varname] = $data;
            $offset += strlen(serialize($data));
        }

        return $returnData;
    }
}


================================================
FILE: src/Ratchet/Session/SessionProvider.php
================================================
<?php
namespace Ratchet\Session;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
use Psr\Http\Message\RequestInterface;
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 HttpServerInterface {
    /**
     * @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\Http\HttpServerInterface            $app
     * @param \SessionHandlerInterface                     $handler
     * @param array                                        $options
     * @param ?\Ratchet\Session\Serialize\HandlerInterface $serializer
     * @throws \RuntimeException
     */
    public function __construct(HttpServerInterface $app, \SessionHandlerInterface $handler, array $options = array(), $serializer = null) {
        if ($serializer !== null && !$serializer instanceof HandlerInterface) { // manual type check to support legacy PHP < 7.1
            throw new \InvalidArgumentException('Argument #4 ($serializer) expected null|Ratchet\Session\Serialize\HandlerInterface');
        }
        $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}
     */
    #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null) { /*
    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { /**/
        $sessionName = ini_get('session.name');

        $id = array_reduce($request->getHeader('Cookie'), function($accumulator, $cookie) use ($sessionName) {
            if ($accumulator) {
                return $accumulator;
            }

            $crumbs = $this->parseCookie($cookie);

            return isset($crumbs['cookies'][$sessionName]) ? $crumbs['cookies'][$sessionName] : false;
        }, false);

        if (null === $request || false === $id) {
            $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, $request);
    }

    /**
     * {@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);
    }

    /**
     * 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)));
    }

    /**
     * Taken from Guzzle3
     */
    private static $cookieParts = array(
        'domain'      => 'Domain',
        'path'        => 'Path',
        'max_age'     => 'Max-Age',
        'expires'     => 'Expires',
        'version'     => 'Version',
        'secure'      => 'Secure',
        'port'        => 'Port',
        'discard'     => 'Discard',
        'comment'     => 'Comment',
        'comment_url' => 'Comment-Url',
        'http_only'   => 'HttpOnly'
    );

    /**
     * Taken from Guzzle3
     */
    private function parseCookie($cookie, $host = null, $path = null, $decode = false) {
        // Explode the cookie string using a series of semicolons
        $pieces = array_filter(array_map('trim', explode(';', $cookie)));

        // The name of the cookie (first kvp) must include an equal sign.
        if (empty($pieces) || !strpos($pieces[0], '=')) {
            return false;
        }

        // Create the default return array
        $data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array(
            'cookies'   => array(),
            'data'      => array(),
            'path'      => $path ?: '/',
            'http_only' => false,
            'discard'   => false,
            'domain'    => $host
        ));
        $foundNonCookies = 0;

        // Add the cookie pieces into the parsed data array
        foreach ($pieces as $part) {

            $cookieParts = explode('=', $part, 2);
            $key = trim($cookieParts[0]);

            if (count($cookieParts) == 1) {
                // Can be a single value (e.g. secure, httpOnly)
                $value = true;
            } else {
                // Be sure to strip wrapping quotes
                $value = trim($cookieParts[1], " \n\r\t\0\x0B\"");
                if ($decode) {
                    $value = urldecode($value);
                }
            }

            // Only check for non-cookies when cookies have been found
            if (!empty($data['cookies'])) {
                foreach (self::$cookieParts as $mapValue => $search) {
                    if (!strcasecmp($search, $key)) {
                        $data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value;
                        $foundNonCookies++;
                        continue 2;
                    }
                }
            }

            // If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a
            // cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data.
            $data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value;
        }

        // Calculate the expires date
        if (!$data['expires'] && $data['max_age']) {
            $data['expires'] = time() + (int) $data['max_age'];
        }

        return $data;
    }
}


================================================
FILE: src/Ratchet/Session/Storage/Proxy/VirtualProxy.php
================================================
<?php
namespace Ratchet\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;

if (PHP_VERSION_ID > 80200 && (new \ReflectionMethod('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy','setId'))->hasReturnType()) {
    // alias to class for Symfony 7 on PHP 8.2+ using native types like `setId(string $id): void`
    class_alias(__NAMESPACE__ . '\\VirtualProxyForSymfony7', __NAMESPACE__ . '\\VirtualProxy');
} elseif (PHP_VERSION_ID > 80000 && (new \ReflectionMethod('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy','getId'))->hasReturnType()) {
    // alias to class for Symfony 6 on PHP 8+ using native types like `getId(): string`
    class_alias(__NAMESPACE__ . '\\VirtualProxyForSymfony6', __NAMESPACE__ . '\\VirtualProxy');
} else {
    // fall back to class without native types

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");
    }
}

}


================================================
FILE: src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony6.php
================================================
<?php
namespace Ratchet\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;

/**
 * [internal] VirtualProxy for Symfony 6 on PHP 8+ using native types like `getId(): string`
 *
 * @internal used internally only, should not be referenced directly
 * @see VirtualProxy
 */
class VirtualProxyForSymfony6 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(): string {
        return $this->_sessionId;
    }

    /**
     * {@inheritdoc}
     */
    public function setId($id) {
        $this->_sessionId = $id;
    }

    /**
     * {@inheritdoc}
     */
    public function getName(): string {
        return $this->_sessionName;
    }

    /**
     * DO NOT CALL THIS METHOD
     * @internal
     */
    public function setName($name) {
        throw new \RuntimeException("Can not change session name in VirtualProxy");
    }
}


================================================
FILE: src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony7.php
================================================
<?php
namespace Ratchet\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;

/**
 * [internal] VirtualProxy for Symfony 7 on PHP 8.2+ using native types like `setId(string $id): void`
 *
 * @internal used internally only, should not be referenced directly
 * @see VirtualProxy
 */
class VirtualProxyForSymfony7 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(): string {
        return $this->_sessionId;
    }

    /**
     * {@inheritdoc}
     */
    public function setId(string $id): void {
        $this->_sessionId = $id;
    }

    /**
     * {@inheritdoc}
     */
    public function getName(): string {
        return $this->_sessionName;
    }

    /**
     * DO NOT CALL THIS METHOD
     * @internal
     */
    public function setName(string $name): void {
        throw new \RuntimeException("Can not change session name in VirtualProxy");
    }
}


================================================
FILE: src/Ratchet/Session/Storage/VirtualSessionStorage.php
================================================
<?php
namespace Ratchet\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Ratchet\Session\Storage\Proxy\VirtualProxy;
use Ratchet\Session\Serialize\HandlerInterface;

if (PHP_VERSION_ID > 80200 && (new \ReflectionMethod('Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage','save'))->hasReturnType()) {
    // alias to class for Symfony 7 on PHP 8.2+ using native types like `save(): void`
    class_alias(__NAMESPACE__ . '\\VirtualSessionStorageForSymfony7', __NAMESPACE__ . '\\VirtualSessionStorage');
} elseif (PHP_VERSION_ID > 80000 && (new \ReflectionMethod('Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage','start'))->hasReturnType()) {
    // alias to class for Symfony 6 on PHP 8+ using native types like `start(): bool`
    class_alias(__NAMESPACE__ . '\\VirtualSessionStorageForSymfony6', __NAMESPACE__ . '\\VirtualSessionStorage');
} else {
    // fall back to class without native types

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) {
        // .. ?
        return false;
    }

    /**
     * {@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;
    }
}

}


================================================
FILE: src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php
================================================
<?php
namespace Ratchet\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Ratchet\Session\Storage\Proxy\VirtualProxy;
use Ratchet\Session\Serialize\HandlerInterface;

/**
 * [internal] VirtualSessionStorage for Symfony 6 on PHP 8+ using native types like `start(): bool`
 *
 * @internal used internally only, should not be referenced directly
 * @see VirtualSessionStorage
 */
class VirtualSessionStorageForSymfony6 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(): bool {
        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(bool $destroy = false, ?int $lifetime = null): bool {
        // .. ?
        return false;
    }

    /**
     * {@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;
    }
}


================================================
FILE: src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony7.php
================================================
<?php
namespace Ratchet\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
use Ratchet\Session\Storage\Proxy\VirtualProxy;
use Ratchet\Session\Serialize\HandlerInterface;

/**
 * [internal] VirtualSessionStorage for Symfony 7 on PHP 8.2+ using native types like `save(): void`
 *
 * @internal used internally only, should not be referenced directly
 * @see VirtualSessionStorage
 */
class VirtualSessionStorageForSymfony7 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(): bool {
        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(bool $destroy = false, ?int $lifetime = null): bool {
        // .. ?
        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function save(): void {
        // 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(AbstractProxy|\SessionHandlerInterface|null $saveHandler): void {
        if (!($saveHandler instanceof \SessionHandlerInterface)) {
            throw new \InvalidArgumentException('Handler must be instance of SessionHandlerInterface');
        }

        if (!($saveHandler instanceof VirtualProxy)) {
            $saveHandler = new VirtualProxy($saveHandler);
        }

        $this->saveHandler = $saveHandler;
    }
}


================================================
FILE: src/Ratchet/Wamp/Exception.php
================================================
<?php
namespace Ratchet\Wamp;

class Exception extends \Exception {
}


================================================
FILE: src/Ratchet/Wamp/JsonException.php
================================================
<?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);
    }
}


================================================
FILE: src/Ratchet/Wamp/ServerProtocol.php
================================================
<?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/autobahn-js
 *
 * +--------------+----+------------------+
 * | 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;
        }

        return ['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");
        }

        if (isset($json[1]) && !(is_string($json[1]) || is_numeric($json[1]))) {
            throw new Exception('Invalid Topic, must be a string');
        }

        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 = [$from->WAMP->sessionId];
                    } else {
                        $exclude = [];
                    }
                }

                $eligible = (array_key_exists(4, $json) ? $json[4] : []);

                $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);
    }
}


================================================
FILE: src/Ratchet/Wamp/Topic.php
================================================
<?php
namespace Ratchet\Wamp;
use Ratchet\ConnectionInterface;

/**
 * A topic/channel containing connections that have subscribed to it
 */
class Topic implements \IteratorAggregate, \Countable {
    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|array $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}
     */
    #[\ReturnTypeWillChange]
    public function getIterator() {
        return $this->subscribers;
    }

    /**
     * {@inheritdoc}
     */
    #[\ReturnTypeWillChange]
    public function count() {
        return $this->subscribers->count();
    }
}


================================================
FILE: src/Ratchet/Wamp/TopicManager.php
================================================
<?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 (0 === $topic->count()) {
            unset($this->topicLookup[$topic->getId()]);
        }
    }
}


================================================
FILE: src/Ratchet/Wamp/WampConnection.php
================================================
<?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);
    }

}


================================================
FILE: src/Ratchet/Wamp/WampServer.php
================================================
<?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/autobahn-js 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();
    }
}


================================================
FILE: src/Ratchet/Wamp/WampServerInterface.php
================================================
<?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);
}


================================================
FILE: src/Ratchet/WebSocket/ConnContext.php
================================================
<?php
namespace Ratchet\WebSocket;
use Ratchet\RFC6455\Messaging\MessageBuffer;

class ConnContext {
    /**
     * @var \Ratchet\WebSocket\WsConnection
     */
    public $connection;

    /**
     * @var \Ratchet\RFC6455\Messaging\MessageBuffer;
     */
    public $buffer;

    public function __construct(WsConnection $conn, MessageBuffer $buffer) {
        $this->connection = $conn;
        $this->buffer = $buffer;
    }
}


================================================
FILE: src/Ratchet/WebSocket/MessageCallableInterface.php
================================================
<?php
namespace Ratchet\WebSocket;
use Ratchet\ConnectionInterface;
use Ratchet\RFC6455\Messaging\MessageInterface;

interface MessageCallableInterface {
    public function onMessage(ConnectionInterface $conn, MessageInterface $msg);
}


================================================
FILE: src/Ratchet/WebSocket/MessageComponentInterface.php
================================================
<?php
namespace Ratchet\WebSocket;
use Ratchet\ComponentInterface;

interface MessageComponentInterface extends ComponentInterface, MessageCallableInterface {
}


================================================
FILE: src/Ratchet/WebSocket/WsConnection.php
================================================
<?php
namespace Ratchet\WebSocket;
use Ratchet\AbstractConnectionDecorator;
use Ratchet\RFC6455\Messaging\DataInterface;
use Ratchet\RFC6455\Messaging\Frame;

/**
 * {@inheritdoc}
 * @property \StdClass $WebSocket
 */
class WsConnection 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;
    }

    /**
     * @param int|\Ratchet\RFC6455\Messaging\DataInterface
     */
    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;
    }
}


================================================
FILE: src/Ratchet/WebSocket/WsServer.php
================================================
<?php
namespace Ratchet\WebSocket;
use Ratchet\ComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface as DataComponentInterface;
use Ratchet\Http\HttpServerInterface;
use Ratchet\Http\CloseResponseTrait;
use Psr\Http\Message\RequestInterface;
use Ratchet\RFC6455\Messaging\MessageInterface;
use Ratchet\RFC6455\Messaging\FrameInterface;
use Ratchet\RFC6455\Messaging\Frame;
use Ratchet\RFC6455\Messaging\MessageBuffer;
use Ratchet\RFC6455\Messaging\CloseFrameChecker;
use Ratchet\RFC6455\Handshake\ServerNegotiator;
use Ratchet\RFC6455\Handshake\RequestVerifier;
use React\EventLoop\LoopInterface;
use GuzzleHttp\Psr7\HttpFactory;
use GuzzleHttp\Psr7\Message;

/**
 * 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 {
    use CloseResponseTrait;

    /**
     * Decorated component
     * @var \Ratchet\ComponentInterface
     */
    private $delegate;

    /**
     * @var \SplObjectStorage
     */
    protected $connections;

    /**
     * @var \Ratchet\RFC6455\Messaging\CloseFrameChecker
     */
    private $closeFrameChecker;

    /**
     * @var \Ratchet\RFC6455\Handshake\ServerNegotiator
     */
    private $handshakeNegotiator;

    /**
     * @var \Closure
     */
    private $ueFlowFactory;

    /**
     * @var \Closure
     */
    private $pongReceiver;

    /**
     * @var \Closure
     */
    private $msgCb;

    /**
     * @param \Ratchet\WebSocket\MessageComponentInterface|\Ratchet\MessageComponentInterface $component Your application to run with WebSockets
     * @note If you want to enable sub-protocols have your component implement WsServerInterface as well
     */
    public function __construct(ComponentInterface $component) {
        if ($component instanceof MessageComponentInterface) {
            $this->msgCb = function(ConnectionInterface $conn, MessageInterface $msg) {
                $this->delegate->onMessage($conn, $msg);
            };
        } elseif ($component instanceof DataComponentInterface) {
            $this->msgCb = function(ConnectionInterface $conn, MessageInterface $msg) {
                $this->delegate->onMessage($conn, $msg->getPayload());
            };
        } else {
            throw new \UnexpectedValueException('Expected instance of \Ratchet\WebSocket\MessageComponentInterface or \Ratchet\MessageComponentInterface');
        }

        if (bin2hex('✓') !== 'e29c93') {
            throw new \DomainException('Bad encoding, unicode character ✓ did not match expected value. Ensure charset UTF-8 and check ini val mbstring.func_autoload');
        }

        $this->delegate    = $component;
        $this->connections = new \SplObjectStorage;

        $this->closeFrameChecker   = new CloseFrameChecker;

        if (self::isRFC6455v03()) {
            $this->handshakeNegotiator = new ServerNegotiator(new RequestVerifier);
        } else {
            $this->handshakeNegotiator = new ServerNegotiator(new RequestVerifier, new HttpFactory);
        }

        $this->handshakeNegotiator->setStrictSubProtocolCheck(true);

        if ($component instanceof WsServerInterface) {
            $this->handshakeNegotiator->setSupportedSubProtocols($component->getSubProtocols());
        }

        $this->pongReceiver = function() {};

        $reusableUnderflowException = new \UnderflowException;
        $this->ueFlowFactory = function() use ($reusableUnderflowException) {
            return $reusableUnderflowException;
        };
    }

    private static function isRFC6455v03() {
        $reflection = new \ReflectionClass('Ratchet\RFC6455\Handshake\ServerNegotiator');
        return $reflection->getMethod('__construct')->getNumberOfRequiredParameters() === 1;
    }

    /**
     * {@inheritdoc}
     */
    #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null) { /*
    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { /**/
        if (null === $request) {
            throw new \UnexpectedValueException('$request can not be null');
        }

        $conn->httpRequest = $request;

        $conn->WebSocket            = new \StdClass;
        $conn->WebSocket->closing   = false;

        $response = $this->handshakeNegotiator->handshake($request)->withHeader('X-Powered-By', \Ratchet\VERSION);

        $conn->send(Message::toString($response));

        if (101 !== $response->getStatusCode()) {
            return $conn->close();
        }

        $wsConn = new WsConnection($conn);

        $streamer = new MessageBuffer(
            $this->closeFrameChecker,
            function(MessageInterface $msg) use ($wsConn) {
                $cb = $this->msgCb;
                $cb($wsConn, $msg);
            },
            function(FrameInterface $frame) use ($wsConn) {
                $this->onControlFrame($frame, $wsConn);
            },
            true,
            $this->ueFlowFactory
        );

        $this->connections->attach($conn, new ConnContext($wsConn, $streamer));

        return $this->delegate->onOpen($wsConn);
    }

    /**
     * {@inheritdoc}
     */
    public function onMessage(ConnectionInterface $from, $msg) {
        if ($from->WebSocket->closing) {
            return;
        }

        $this->connections[$from]->buffer->onData($msg);
    }

    /**
     * {@inheritdoc}
     */
    public function onClose(ConnectionInterface $conn) {
        if ($this->connections->contains($conn)) {
            $context = $this->connections[$conn];
            $this->connections->detach($conn);

            $this->delegate->onClose($context->connection);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function onError(ConnectionInterface $conn, \Exception $e) {
        if ($this->connections->contains($conn)) {
            $this->delegate->onError($this->connections[$conn]->connection, $e);
        } else {
            $conn->close();
        }
    }

    public function onControlFrame(FrameInterface $frame, WsConnection $conn) {
        switch ($frame->getOpCode()) {
            case Frame::OP_CLOSE:
                $conn->close($frame);
                break;
            case Frame::OP_PING:
                $conn->send(new Frame($frame->getPayload(), true, Frame::OP_PONG));
                break;
            case Frame::OP_PONG:
                $pongReceiver = $this->pongReceiver;
                $pongReceiver($frame, $conn);
            break;
        }
    }

    public function setStrictSubProtocolCheck($enable) {
        $this->handshakeNegotiator->setStrictSubProtocolCheck($enable);
    }

    public function enableKeepAlive(LoopInterface $loop, $interval = 30) {
        $lastPing = new Frame(uniqid(), true, Frame::OP_PING);
        $pingedConnections = new \SplObjectStorage;
        $splClearer = new \SplObjectStorage;

        $this->pongReceiver = function(FrameInterface $frame, $wsConn) use ($pingedConnections, &$lastPing) {
            if ($frame->getPayload() === $lastPing->getPayload()) {
                $pingedConnections->detach($wsConn);
            }
        };

        $loop->addPeriodicTimer((int)$interval, function() use ($pingedConnections, &$lastPing, $splClearer) {
            foreach ($pingedConnections as $wsConn) {
                $wsConn->close();
            }
            $pingedConnections->removeAllExcept($splClearer);

            $lastPing = new Frame(uniqid(), true, Frame::OP_PING);

            foreach ($this->connections as $key => $conn) {
                $wsConn  = $this->connections[$conn]->connection;

                $wsConn->send($lastPing);
                $pingedConnections->attach($wsConn);
            }
        });
   }
}


================================================
FILE: src/Ratchet/WebSocket/WsServerInterface.php
================================================
<?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();
}


================================================
FILE: tests/autobahn/bin/fuzzingserver.php
================================================
<?php
use Ratchet\ConnectionInterface;

    require dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';

class BinaryEcho implements \Ratchet\WebSocket\MessageComponentInterface {
    public function onMessage(ConnectionInterface $from, \Ratchet\RFC6455\Messaging\MessageInterface $msg) {
        $from->send($msg);
    }

    public function onOpen(ConnectionInterface $conn) {
    }

    public function onClose(ConnectionInterface $conn) {
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
    }
}

    $port = $argc > 1 ? $argv[1] : 8000;
    $impl = sprintf('React\EventLoop\%sLoop', $argc > 2 ? $argv[2] : 'StreamSelect');

    $loop = new $impl;

    // prefer SocketServer (reactphp/socket v1.9+) over legacy \React\Socket\Server
    $sock = class_exists('React\Socket\SocketServer') ? new React\Socket\SocketServer('0.0.0.0:' . $port, [], $loop) : new React\Socket\Server('0.0.0.0:' . $port, $loop);

    $wsServer = new Ratchet\WebSocket\WsServer(new BinaryEcho);
    // This is enabled to test https://github.com/ratchetphp/Ratchet/issues/430
    // The time is left at 10 minutes so that it will not try to every ping anything
    // This causes the Ratchet server to crash on test 2.7
    $wsServer->enableKeepAlive($loop, 600);

    $app = new Ratchet\Http\HttpServer($wsServer);

    $server = new Ratchet\Server\IoServer($app, $sock, $loop);
    $server->run();


================================================
FILE: tests/autobahn/fuzzingclient-all.json
================================================
{
    "options": {"failByDrop": false}
  , "outdir": "reports/ab"

  , "servers": [
        {"agent": "Ratchet/0.4 libevent", "url": "ws://localhost:8001", "options": {"version": 18}}
      , {"agent": "Ratchet/0.4 libev", "url": "ws://localhost:8004", "options": {"version": 18}}
      , {"agent": "Ratchet/0.4 streams", "url": "ws://localhost:8002", "options": {"version": 18}}
      , {"agent": "AutobahnTestSuite/0.5.9", "url": "ws://localhost:8000", "options": {"version": 18}}
    ]

  , "cases": ["*"]
  , "exclude-cases": []
  , "exclude-agent-cases": {}
}


================================================
FILE: tests/autobahn/fuzzingclient-profile.json
================================================
{
    "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": {}
}


================================================
FILE: tests/autobahn/fuzzingclient-quick.json
================================================
{
    "options": {"failByDrop": false}
  , "outdir": "reports/rfc"

  , "servers": [
       {"agent": "Ratchet", "url": "ws://localhost:8000", "options": {"version": 18}}
    ]

  , "cases": ["*"]
  , "exclude-cases": []
  , "exclude-agent-cases": {}
}


================================================
FILE: tests/bootstrap.php
================================================
<?php

    $loader = require __DIR__ . '/../vendor/autoload.php';
    $loader->addPsr4('Ratchet\\', __DIR__ . '/helpers/Ratchet');


================================================
FILE: tests/helpers/Ratchet/AbstractMessageComponentTestCase.php
================================================
<?php
namespace Ratchet;

use PHPUnit\Framework\TestCase;

abstract class AbstractMessageComponentTestCase extends TestCase {
    protected $_app;
    protected $_serv;
    protected $_conn;

    abstract public function getConnectionClassString();
    abstract public function getDecoratorClassString();
    abstract public function getComponentClassString();

    /**
     * @before
     */
    public function setUpConnection() {
        $this->_app  = $this->getMockBuilder($this->getComponentClassString())->getMock();
        $decorator   = $this->getDecoratorClassString();
        $this->_serv = new $decorator($this->_app);
        $this->_conn = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();

        $this->doOpen($this->_conn);
    }

    protected function doOpen($conn) {
        $this->_serv->onOpen($conn);
    }

    public function isExpectedConnection() {
        return $this->isInstanceOf($this->getConnectionClassString());
    }

    public function testOpen() {
        $this->_app->expects($this->once())->method('onOpen')->with($this->isExpectedConnection());
        $this->doOpen($this->getMockBuilder('Ratchet\Mock\Connection')->getMock());
    }

    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);
    }
}


================================================
FILE: tests/helpers/Ratchet/Mock/Connection.php
================================================
<?php
namespace Ratchet\Mock;
use Ratchet\ConnectionInterface;

#[\AllowDynamicProperties]
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;
    }
}


================================================
FILE: tests/helpers/Ratchet/Mock/ConnectionDecorator.php
================================================
<?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();
    }
}


================================================
FILE: tests/helpers/Ratchet/Mock/WampComponent.php
================================================
<?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();
    }
}


================================================
FILE: tests/helpers/Ratchet/NullComponent.php
================================================
<?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();
    }
}


================================================
FILE: tests/helpers/Ratchet/Wamp/Stub/WsWampServerInterface.php
================================================
<?php
namespace Ratchet\Wamp\Stub;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\Wamp\WampServerInterface;

interface WsWampServerInterface extends WsServerInterface, WampServerInterface {
}


================================================
FILE: tests/helpers/Ratchet/WebSocket/Stub/WsMessageComponentInterface.php
================================================
<?php
namespace Ratchet\WebSocket\Stub;
use Ratchet\MessageComponentInterface;
use Ratchet\WebSocket\WsServerInterface;

interface WsMessageComponentInterface extends MessageComponentInterface, WsServerInterface {
}


================================================
FILE: tests/unit/AbstractConnectionDecoratorTest.php
================================================
<?php
namespace Ratchet;
use PHPUnit\Framework\TestCase;
use Ratchet\Mock\ConnectionDecorator;

/**
 * @covers Ratchet\AbstractConnectionDecorator
 * @covers Ratchet\ConnectionInterface
 */
class AbstractConnectionDecoratorTest extends TestCase {
    protected $mock;
    protected $l1;
    protected $l2;

    /**
     * @before
     */
    public function setUpConnection() {
        $this->mock = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();
        $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() {
        $error = false;
        set_error_handler(function () use (&$error) {
            $error = true;
        }, PHP_VERSION_ID >= 80000 ? E_WARNING : E_NOTICE);

        $var = $this->mock->nonExistant;

        restore_error_handler();

        $this->assertTrue($error);
        $this->assertNull($var);
    }

    public function testWarningGettingNothingLevel1() {
        $error = false;
        set_error_handler(function () use (&$error) {
            $error = true;
        }, PHP_VERSION_ID >= 80000 ? E_WARNING : E_NOTICE);

        $var = $this->l1->nonExistant;

        restore_error_handler();

        $this->assertTrue($error);
        $this->assertNull($var);
    }

    public function testWarningGettingNothingLevel2() {
        $error = false;
        set_error_handler(function () use (&$error) {
            $error = true;
        }, PHP_VERSION_ID >= 80000 ? E_WARNING : E_NOTICE);

        $var = $this->l2->nonExistant;

        restore_error_handler();

        $this->assertTrue($error);
        $this->assertNull($var);
    }
}


================================================
FILE: tests/unit/AppTest.php
================================================
<?php
namespace Ratchet;

use PHPUnit\Framework\TestCase;
use Ratchet\App;
use Ratchet\Server\IoServer;

class AppTest extends TestCase {
    public function testCtorThrowsForInvalidLoop() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('InvalidArgumentException');
            $this->expectExceptionMessage('Argument #4 ($loop) expected null|React\EventLoop\LoopInterface');
        } else {
            $this->setExpectedException('InvalidArgumentException', 'Argument #4 ($loop) expected null|React\EventLoop\LoopInterface');
        }
        new App('localhost', 8080, '127.0.0.1', 'loop');
    }

    public function testCtorWithoutArgumentsStartsListeningOnDefaultPorts() {
        if (@stream_socket_server('127.0.0.1:8080') === false || @stream_socket_server('127.0.0.1:8843') === false) {
            $this->markTestSkipped('Default socket port 8080 or 8843 not available or already in use');
        }
        $app = new App();

        $ref = new \ReflectionProperty($app, '_server');
        $ref->setAccessible(true);
        $server = $ref->getValue($app);
        assert($server instanceof IoServer);

        $this->assertStringMatchesFormat('%S127.0.0.1:8080', $server->socket->getAddress());
        $this->assertStringMatchesFormat('%S127.0.0.1:8843', $app->flashServer->socket->getAddress());

        $server->socket->close();
        $app->flashServer->socket->close();
    }
}


================================================
FILE: tests/unit/Http/HttpRequestParserTest.php
================================================
<?php
namespace Ratchet\Http;

use PHPUnit\Framework\TestCase;

/**
 * @covers Ratchet\Http\HttpRequestParser
 */
class HttpRequestParserTest extends TestCase {
    protected $parser;

    /**
     * @before
     */
    public function setUpParser() {
        $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->getMockBuilder('Ratchet\Mock\Connection')->getMock();

        $this->parser->maxSize = 20;

        $this->assertNull($this->parser->onMessage($conn, "GET / HTTP/1.1\r\n"));

        if (method_exists($this, 'expectException')) {
            $this->expectException('OverflowException');
        } else {
            $this->setExpectedException('OverflowException');
        }

        $this->parser->onMessage($conn, "Header-Is: Too Big");
    }

    public function testOnMessageThrowsExceptionForEmptyNewlines() {
        $conn = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();

        if (method_exists($this, 'expectException')) {
            $this->expectException('InvalidArgumentException');
        } else {
            $this->setExpectedException('InvalidArgumentException');
        }

        $this->parser->onMessage($conn, "\r\n\r\n");
    }

    public function testReturnTypeIsRequest() {
        $conn = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();
        $return = $this->parser->onMessage($conn, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n");

        $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $return);
    }
}


================================================
FILE: tests/unit/Http/HttpServerTest.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\AbstractMessageComponentTestCase;

/**
 * @covers Ratchet\Http\HttpServer
 */
class HttpServerTest extends AbstractMessageComponentTestCase {
    /**
     * @before
     */
    public function setUpConnection() {
        parent::setUpConnection();
        $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");
    }
}


================================================
FILE: tests/unit/Http/OriginCheckTest.php
================================================
<?php
namespace Ratchet\Http;
use Ratchet\AbstractMessageComponentTestCase;

/**
 * @covers Ratchet\Http\OriginCheck
 */
class OriginCheckTest extends AbstractMessageComponentTestCase {
    protected $_reqStub;

    /**
     * @before
     */
    public function setUpConnection() {
        $this->_reqStub = $this->getMockBuilder('Psr\Http\Message\RequestInterface')->getMock();
        $this->_reqStub->expects($this->any())->method('getHeaderLine')->with('Origin')->willReturn('localhost');

        parent::setUpConnection();

        assert($this->_serv instanceof OriginCheck);
        $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 = ['socketo.me'];
        $this->_conn->expects($this->once())->method('close');

        $this->_serv->onOpen($this->_conn, $this->_reqStub);
    }

    public function testCloseOnMissingOrigin() {
        $this->_serv->allowedOrigins = ['socketo.me'];
        $this->_conn->expects($this->once())->method('close');

        $this->_reqStub->expects($this->once())->method('getHeaderLine')->with('Origin')->willReturn('');

        $this->_serv->onOpen($this->_conn, $this->_reqStub);
    }

    public function testCloseOnDuplicateOrigin() {
        $this->_serv->allowedOrigins = ['socketo.me'];
        $this->_conn->expects($this->once())->method('close');

        $this->_reqStub->expects($this->once())->method('getHeaderLine')->with('Origin')->willReturn('http://socketo.me,https://socketo.me');

        $this->_serv->onOpen($this->_conn, $this->_reqStub);
    }

    public function testOnMessage() {
        $this->passthroughMessageTest('Hello World!');
    }
}


================================================
FILE: tests/unit/Http/RouterTest.php
================================================
<?php
namespace Ratchet\Http;
use PHPUnit\Framework\TestCase;
use Ratchet\WebSocket\WsServerInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Matcher\UrlMatcher;

/**
 * @covers Ratchet\Http\Router
 */
class RouterTest extends TestCase {
    protected $_router;
    protected $_matcher;
    protected $_conn;
    protected $_uri;
    protected $_req;

    /**
     * @before
     */
    public function setUpConnection() {
        $this->_conn = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();
        $this->_uri  = $this->getMockBuilder('Psr\Http\Message\UriInterface')->getMock();
        $this->_req  = $this->getMockBuilder('Psr\Http\Message\RequestInterface')->getMock();
        $this->_req
            ->expects($this->any())
            ->method('getUri')
            ->will($this->returnValue($this->_uri));
        $this->_matcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\UrlMatcherInterface')->getMock();
        $this->_matcher
            ->expects($this->any())
            ->method('getContext')
            ->will($this->returnValue($this->getMockBuilder('Symfony\Component\Routing\RequestContext')->getMock()));
        $this->_router  = new Router($this->_matcher);

        $this->_uri->expects($this->any())->method('getPath')->will($this->returnValue('ws://doesnt.matter/'));
        $this->_uri->expects($this->any())->method('withQuery')->with($this->callback(function($val) {
            $this->setResult($val);

            return true;
        }))->will($this->returnSelf());
        $this->_uri->expects($this->any())->method('getHost')->willReturn('example.com');
        $this->_req->expects($this->any())->method('withUri')->will($this->returnSelf());
        $this->_req->expects($this->any())->method('getMethod')->willReturn('GET');
    }

    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() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('UnexpectedValueException');
        } else {
            $this->setExpectedException('UnexpectedValueException');
        }
        $this->_router->onOpen($this->_conn);
    }

    public function testControllerIsMessageComponentInterface() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('UnexpectedValueException');
        } else {
            $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 = $this->isInstanceOf('Ratchet\Mock\Connection');
        $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(['_controller' => $controller, 'foo' => 'bar', 'baz' => 'qux'])
        );
        $conn = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();

        $this->_uri->expects($this->once())->method('withQuery')->with('foo=bar&baz=qux')->willReturnSelf();
        $this->_req->expects($this->once())->method('withUri')->will($this->returnSelf());

        $router = new Router($this->_matcher);

        $router->onOpen($conn, $this->_req);
    }

    public function testQueryParams() {
        $controller = $this->getMockBuilder('Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock();
        $this->_matcher->expects($this->any())->method('match')->will(
            $this->returnValue(['_controller' => $controller, 'foo' => 'bar', 'baz' => 'qux'])
        );

        $conn    = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();
        $request = $this->getMockBuilder('Psr\Http\Message\RequestInterface')->getMock();
        $uri = new \GuzzleHttp\Psr7\Uri('ws://doesnt.matter/endpoint?hello=world&foo=nope');

        $request->expects($this->any())->method('getUri')->will($this->returnCallback(function() use (&$uri) {
            return $uri;
        }));
        $request->expects($this->any())->method('withUri')->with($this->callback(function($url) use (&$uri) {
            $uri = $url;

            return true;
        }))->will($this->returnSelf());
        $request->expects($this->once())->method('getMethod')->willReturn('GET');

        $router = new Router($this->_matcher);
        $router->onOpen($conn, $request);

        $this->assertEquals('foo=nope&baz=qux&hello=world', $request->getUri()->getQuery());
        $this->assertEquals('ws', $request->getUri()->getScheme());
        $this->assertEquals('doesnt.matter', $request->getUri()->getHost());
    }

    public function testImpatientClientOverflow() {
        $this->_conn->expects($this->once())->method('close');

        $header = "GET /nope HTTP/1.1
Upgrade: websocket                                   
Connection: upgrade                                  
Host: localhost                                 
Origin: http://localhost                        
Sec-WebSocket-Version: 13\r\n\r\n";

        $app = new HttpServer(new Router(new UrlMatcher(new RouteCollection, new RequestContext)));
        $app->onOpen($this->_conn);
        $app->onMessage($this->_conn, $header);
        $app->onMessage($this->_conn, 'Silly body');
    }
}


================================================
FILE: tests/unit/Server/EchoServerTest.php
================================================
<?php
namespace Ratchet\Server;
use PHPUnit\Framework\TestCase;
use Ratchet\Server\EchoServer;

class EchoServerTest extends TestCase {
    protected $_conn;
    protected $_comp;

    /**
     * @before
     */
    public function setUpServer() {
        $this->_conn = $this->getMockBuilder('Ratchet\ConnectionInterface')->getMock();
        $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();
    }
}


================================================
FILE: tests/unit/Server/FlashPolicyComponentTest.php
================================================
<?php
namespace Ratchet\Application\Server;
use PHPUnit\Framework\TestCase;
use Ratchet\Server\FlashPolicy;

/**
 * @covers Ratchet\Server\FlashPolicy
 */
class FlashPolicyTest extends TestCase {

    protected $_policy;

    /**
     * @before
     */
    public function setUpPolicy() {
        $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() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('UnexpectedValueException');
        } else {
            $this->setExpectedException('UnexpectedValueException');
        }
        $this->_policy->renderPolicy();
    }

    public function testInvalidDomainPolicyReader() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('UnexpectedValueException');
        } else {
            $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() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('UnexpectedValueException');
        } else {
            $this->setExpectedException('UnexpectedValueException');
        }

        $this->_policy->addAllowedAccess('*', 'nope');
    }

    public function testSetSiteControlThrowsException() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('UnexpectedValueException');
        } else {
            $this->setExpectedException('UnexpectedValueException');
        }

        $this->_policy->setSiteControl('nope');
    }

    public function testErrorClosesConnection() {
        $conn = $this->getMockBuilder('Ratchet\\ConnectionInterface')->getMock();
        $conn->expects($this->once())->method('close');

        $this->_policy->onError($conn, new \Exception);
    }

    public function testOnMessageSendsString() {
        $this->_policy->addAllowedAccess('*', '*');

        $conn = $this->getMockBuilder('Ratchet\\ConnectionInterface')->getMock();
        $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->getMockBuilder('Ratchet\ConnectionInterface')->getMock();
        $this->_policy->onOpen($conn);
    }

    public function testOnCloseExists() {
        $this->assertTrue(method_exists($this->_policy, 'onClose'));
        $conn = $this->getMockBuilder('Ratchet\ConnectionInterface')->getMock();
        $this->_policy->onClose($conn);
    }
}


================================================
FILE: tests/unit/Server/IoConnectionTest.php
================================================
<?php
namespace Ratchet\Application\Server;
use PHPUnit\Framework\TestCase;
use Ratchet\Server\IoConnection;

/**
 * @covers Ratchet\Server\IoConnection
 */
class IoConnectionTest extends TestCase {
    protected $sock;
    protected $conn;

    /**
     * @before
     */
    public function setUpConnection() {
        $this->sock = $this->getMockBuilder('React\\Socket\\ConnectionInterface')->getMock();
        $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'));
    }
}


================================================
FILE: tests/unit/Server/IoServerTest.php
================================================
<?php
namespace Ratchet\Server;
use PHPUnit\Framework\TestCase;
use React\EventLoop\StreamSelectLoop;
use React\EventLoop\LoopInterface;
use React\Socket\Server as LegacySocketServer;
use React\Socket\SocketServer;

/**
 * @covers Ratchet\Server\IoServer
 */
class IoServerTest extends TestCase {
    protected $server;

    protected $app;

    protected $port;

    protected $reactor;

    protected function tickLoop(LoopInterface $loop) {
        $loop->futureTick(function () use ($loop) {
            $loop->stop();
        });

        $loop->run();
    }

    /**
     * @before
     */
    public function setUpServer() {
        $this->app = $this->getMockBuilder('Ratchet\\MessageComponentInterface')->getMock();

        $loop = new StreamSelectLoop;

        // prefer SocketServer (reactphp/socket v1.9+) over legacy \React\Socket\Server
        $this->reactor = class_exists('React\Socket\SocketServer') ? new SocketServer('127.0.0.1:0', [], $loop) : new LegacySocketServer('127.0.0.1:0', $loop);

        $uri = $this->reactor->getAddress();
        $this->port   = parse_url((strpos($uri, '://') === false ? 'tcp://' : '') . $uri, PHP_URL_PORT);
        $this->server = new IoServer($this->app, $this->reactor, $loop);
    }

    public function testCtorThrowsForInvalidLoop() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('InvalidArgumentException');
            $this->expectExceptionMessage('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
        } else {
            $this->setExpectedException('InvalidArgumentException', 'Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
        }
        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->tickLoop($this->server->loop);

        //$this->assertTrue(is_string($this->app->last['onOpen'][0]->remoteAddress));
        //$this->assertTrue(is_int($this->app->last['onOpen'][0]->resourceId));
    }

    public function testHandleOpenWithoutRemoteAddressAssignsEmptyRemoteAddress() {
        $this->app->expects($this->once())->method('onOpen')->with($this->isInstanceOf('Ratchet\\ConnectionInterface'));

        $conn = $this->getMockBuilder('React\\Socket\\ConnectionInterface')->getMock();
        $conn->expects($this->once())->method('getRemoteAddress')->willReturn(null);

        // assign dynamic property without raising notice on PHP 8.2+
        set_error_handler(function () { }, E_DEPRECATED);
        $conn->stream = STDOUT;
        restore_error_handler();

        $this->server->handleConnect($conn);

        $this->assertSame('', $conn->decor->remoteAddress);
        $this->assertSame((int) STDOUT, $conn->decor->resourceId);
    }

    /**
     * @requires extension sockets
     */
    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->tickLoop($this->server->loop);

        socket_write($client, $msg);
        $this->tickLoop($this->server->loop);

        socket_shutdown($client, 1);
        socket_shutdown($client, 0);
        socket_close($client);

        $this->tickLoop($this->server->loop);
    }

    /**
     * @requires extension sockets
     */
    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->tickLoop($this->server->loop);

        socket_shutdown($client, 1);
        socket_shutdown($client, 0);
        socket_close($client);

        $this->tickLoop($this->server->loop);
    }

    public function testFactory() {
        $server = IoServer::factory($this->app, 0);
        $server->socket->close();

        $this->assertInstanceOf('Ratchet\\Server\\IoServer', $server);
    }

    public function testNoLoopProvidedError() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('RuntimeException');
        } else {
            $this->setExpectedException('RuntimeException');
        }

        $io   = new IoServer($this->app, $this->reactor);
        $io->run();
    }

    public function testOnErrorPassesException() {
        $conn = $this->getMockBuilder('React\\Socket\\ConnectionInterface')->getMock();

        // assign dynamic property without raising notice on PHP 8.2+
        set_error_handler(function () { }, E_DEPRECATED);
        $conn->decor = $this->getMockBuilder('Ratchet\\ConnectionInterface')->getMock();
        restore_error_handler();

        $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->getMockBuilder('React\\Socket\\ConnectionInterface')->getMock();
        $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);
    }
}


================================================
FILE: tests/unit/Server/IpBlackListComponentTest.php
================================================
<?php
namespace Ratchet\Server;
use PHPUnit\Framework\TestCase;
use Ratchet\Server\IpBlackList;

/**
 * @covers Ratchet\Server\IpBlackList
 */
class IpBlackListTest extends TestCase {
    protected $blocker;
    protected $mock;

    /**
     * @before
     */
    public function setUpBlocker() {
        $this->mock = $this->getMockBuilder('Ratchet\\MessageComponentInterface')->getMock();
        $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->getMockBuilder('Ratchet\Mock\Connection')->getMock();
        $conn->remoteAddress = '127.0.0.1';

        return $conn;
    }
}


================================================
FILE: tests/unit/Session/Serialize/PhpBinaryHandlerTest.php
================================================
<?php
namespace Ratchet\Session\Serialize;
use PHPUnit\Framework\TestCase;
use Ratchet\Session\Serialize\PhpBinaryHandler;

/**
 * @covers Ratchet\Session\Serialize\PhpHandler
 */
class PhpBinaryHandlerTest extends TestCase {
    protected $_handler;

    /**
     * @before
     */
    public function setUpHandler() {
        $this->_handler = new PhpBinaryHandler;
    }

    public function serializedProvider() {
        return array(
            array(
                "\x0f" . '_sf2_attributes' . 'a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}' . "\x0c" . '_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));
    }
}


================================================
FILE: tests/unit/Session/Serialize/PhpHandlerTest.php
================================================
<?php
namespace Ratchet\Session\Serialize;
use PHPUnit\Framework\TestCase;
use Ratchet\Session\Serialize\PhpHandler;

/**
 * @covers Ratchet\Session\Serialize\PhpHandler
 */
class PhpHandlerTest extends TestCase {
    protected $_handler;

    /**
     * @before
     */
    public function setUpHandler() {
        $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));
    }
}


================================================
FILE: tests/unit/Session/SessionProviderTest.php
================================================
<?php
namespace Ratchet\Session;
use Ratchet\AbstractMessageComponentTestCase;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;

/**
 * @covers Ratchet\Session\SessionProvider
 * @covers Ratchet\Session\Storage\VirtualSessionStorage
 * @covers Ratchet\Session\Storage\Proxy\VirtualProxy
 */
class SessionProviderTest extends AbstractMessageComponentTestCase {
    /**
     * @before
     */
    public function setUpProvider() {
        return $this->markTestIncomplete('Test needs to be updated for ini_set issue in PHP 7.2');

        if (!class_exists('Symfony\Component\HttpFoundation\Session\Session')) {
            return $this->markTestSkipped('Dependency of Symfony HttpFoundation failed');
        }

        parent::setUpConnection();
        $this->_serv = new SessionProvider($this->_app, new NullSessionHandler);
    }

    public function testCtorThrowsForInvalidSerializer() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('InvalidArgumentException');
            $this->expectExceptionMessage('Argument #4 ($serializer) expected null|Ratchet\Session\Serialize\HandlerInterface');
        } else {
            $this->setExpectedException('InvalidArgumentException', 'Argument #4 ($serializer) expected null|Ratchet\Session\Serialize\HandlerInterface');
        }
        new SessionProvider($this->_app, new NullSessionHandler(), [], 'serializer');
    }

    /**
     * @after
     */
    public function tearDownHandler() {
        ini_set('session.serialize_handler', 'php');
    }

    public function getConnectionClassString() {
        return 'Ratchet\ConnectionInterface';
    }

    public function getDecoratorClassString() {
        return 'Ratchet\NullComponent';
    }

    public function getComponentClassString() {
        return 'Ratchet\Http\HttpServerInterface';
    }

    public function classCaseProvider() {
        return array(
            array('php', 'Php')
          , array('php_binary', 'PhpBinary')
        );
    }

    /**
     * @dataProvider classCaseProvider
     */
    public function testToClassCase($in, $out) {
        $ref = new \ReflectionClass('Ratchet\\Session\\SessionProvider');
        $method = $ref->getMethod('toClassCase');
        $method->setAccessible(true);

        $component = new SessionProvider($this->getMockBuilder($this->getComponentClassString())->getMock(), $this->getMockBuilder('SessionHandlerInterface')->getMock());
        $this->assertEquals($out, $method->invokeArgs($component, array($in)));
    }

    /**
     * I think I have severely butchered this test...it's not so much of a unit test as it is a full-fledged component test
     */
    public function testConnectionValueFromPdo() {
        if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
            return $this->markTestSkipped('Session test requires PDO and pdo_sqlite');
        }

        $sessionId = md5('testSession');

        $dbOptions = array(
            'db_table'    => 'sessions'
          , 'db_id_col'   => 'sess_id'
          , 'db_data_col' => 'sess_data'
          , 'db_time_col' => 'sess_time'
          , 'db_lifetime_col' => 'sess_lifetime'
        );

        $pdo = new \PDO("sqlite::memory:");
        $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        $pdo->exec(vsprintf("CREATE TABLE %s (%s TEXT NOT NULL PRIMARY KEY, %s BLOB NOT NULL, %s INTEGER NOT NULL, %s INTEGER)", $dbOptions));

        $pdoHandler = new PdoSessionHandler($pdo, $dbOptions);
        $pdoHandler->write($sessionId, '_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}');

        $component  = new SessionProvider($this->getMockBuilder($this->getComponentClassString())->getMock(), $pdoHandler, array('auto_start' => 1));
        $connection = $this->getMockBuilder('Ratchet\\ConnectionInterface')->getMock();

        $headers = $this->getMockBuilder('Psr\Http\Message\RequestInterface')->getMock();
        $headers->expects($this->once())->method('getHeader')->will($this->returnValue([ini_get('session.name') . "={$sessionId};"]));

        $component->onOpen($connection, $headers);

        $this->assertEquals('world', $connection->Session->get('hello'));
    }

    protected function newConn() {
        $conn = $this->getMockBuilder('Ratchet\ConnectionInterface')->getMock();

        $headers = $this->getMockBuilder('Psr\Http\Message\Request', array('getCookie'), array('POST', '/', array()))->getMock();
        $headers->expects($this->once())->method('getCookie', array(ini_get('session.name')))->will($this->returnValue(null));

        return $conn;
    }

    public function testOnMessageDecorator() {
        $message = "Database calls are usually blocking  :(";
        $this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $message);
        $this->_serv->onMessage($this->_conn, $message);
    }

    public function testRejectInvalidSeralizers() {
        if (!function_exists('wddx_serialize_value')) {
            $this->markTestSkipped();
        }

        ini_set('session.serialize_handler', 'wddx');
        $this->setExpectedException('RuntimeException');
        new SessionProvider($this->getMockBuilder($this->getComponentClassString())->getMock(), $this->getMockBuilder('SessionHandlerInterface')->getMock());
    }

    protected function doOpen($conn) {
        $request = $this->getMockBuilder('Psr\Http\Message\RequestInterface')->getMock();
        $request->expects($this->any())->method('getHeader')->will($this->returnValue([]));

        $this->_serv->onOpen($conn, $request);
    }
}


================================================
FILE: tests/unit/Session/Storage/VirtualSessionStoragePDOTest.php
================================================
<?php
namespace Ratchet\Session\Storage;
use PHPUnit\Framework\TestCase;
use Ratchet\Session\Serialize\PhpHandler;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;

class VirtualSessionStoragePDOTest extends TestCase {
    /**
     * @var VirtualSessionStorage
     */
    protected $_virtualSessionStorage;

    protected $_pathToDB;

    /**
     * @before
     */
    public function setUpHandler() {
        if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
            return $this->markTestSkipped('Session test requires PDO and pdo_sqlite');
        }

        $schema = <<<SQL
CREATE TABLE `sessions` (
    `sess_id` VARBINARY(128) NOT NULL PRIMARY KEY,
    `sess_data` BLOB NOT NULL,
    `sess_time` INTEGER UNSIGNED NOT NULL,
    `sess_lifetime` MEDIUMINT NOT NULL
);
SQL;
        $this->_pathToDB = tempnam(sys_get_temp_dir(), 'SQ3');;
        $dsn = 'sqlite:' . $this->_pathToDB;

        $pdo = new \PDO($dsn);
        $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        $pdo->exec($schema);
        $pdo = null;

        $sessionHandler = new PdoSessionHandler($dsn);
        $serializer = new PhpHandler();
        $this->_virtualSessionStorage = new VirtualSessionStorage($sessionHandler, 'foobar', $serializer);
        $this->_virtualSessionStorage->registerBag(new FlashBag());
        $this->_virtualSessionStorage->registerBag(new AttributeBag());
    }

    /**
     * @after
     */
    public function tearDownHandler() {
        unlink($this->_pathToDB);
    }

    public function testStartWithDSN() {
        $this->_virtualSessionStorage->start();

        $this->assertTrue($this->_virtualSessionStorage->isStarted());
    }
}


================================================
FILE: tests/unit/Wamp/ServerProtocolTest.php
================================================
<?php
namespace Ratchet\Wamp;
use PHPUnit\Framework\TestCase;
use Ratchet\Mock\Connection;
use Ratchet\Mock\WampComponent as TestComponent;

/**
 * @covers \Ratchet\Wamp\ServerProtocol
 * @covers \Ratchet\Wamp\WampServerInterface
 * @covers \Ratchet\Wamp\WampConnection
 */
class ServerProtocolTest extends TestCase {
    protected $_comp;

    protected $_app;

    /**
     * @before
     */
    public function setUpProtocol() {
        $this->_app  = new TestComponent;
        $this->_comp = new ServerProtocol($this->_app);
    }

    protected function newConn() {
        return new Connection;
    }

    public function invalidMessageProvider() {
        return [
            [0]
          , [3]
          , [4]
          , [8]
          , [9]
        ];
    }

    /**
     * @dataProvider invalidMessageProvider
     */
    public function testInvalidMessages($type) {
        if (method_exists($this, 'expectException')) {
            $this->expectException('Ratchet\Wamp\Exception');
        } else {
            $this->setExpectedException('Ratchet\Wamp\Exception');
        }

        $conn = $this->newConn();
        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, json_encode([$type]));
    }

    public function testWelcomeMessage() {
        $conn = $this->newConn();

        $this->_comp->onOpen($conn);

        $message = $conn->last['send'];
        $json    = json_decode($message);

        $this->assertEquals(4, count($json));
        $this->assertEquals(0, $json[0]);
        $this->assertTrue(is_string($json[1]));
        $this->assertEquals(1, $json[2]);
    }

    public function testSubscribe() {
        $uri = 'http://example.com';
        $clientMessage = array(5, $uri);

        $conn = $this->newConn();

        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, json_encode($clientMessage));

        $this->assertEquals($uri, $this->_app->last['onSubscribe'][1]);
    }

    public function testUnSubscribe() {
        $uri = 'http://example.com/endpoint';
        $clientMessage = array(6, $uri);

        $conn = $this->newConn();

        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, json_encode($clientMessage));

        $this->assertEquals($uri, $this->_app->last['onUnSubscribe'][1]);
    }

    public function callProvider() {
        return [
            [2, 'a', 'b']
          , [2, ['a', 'b']]
          , [1, 'one']
          , [3, 'one', 'two', 'three']
          , [3, ['un', 'deux', 'trois']]
          , [2, 'hi', ['hello', 'world']]
          , [2, ['hello', 'world'], 'hi']
          , [2, ['hello' => 'world', 'herp' => 'derp']]
        ];
    }

    /**
     * @dataProvider callProvider
     */
    public function testCall() {
        $args     = func_get_args();
        $paramNum = array_shift($args);

        $uri = 'http://example.com/endpoint/' . rand(1, 100);
        $id  = uniqid('', false);
        $clientMessage = array_merge(array(2, $id, $uri), $args);

        $conn = $this->newConn();

        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, json_encode($clientMessage));

        $this->assertEquals($id,  $this->_app->last['onCall'][1]);
        $this->assertEquals($uri, $this->_app->last['onCall'][2]);

        $this->assertEquals($paramNum, count($this->_app->last['onCall'][3]));
    }

    public function testPublish() {
        $conn = $this->newConn();

        $topic = 'pubsubhubbub';
        $event = 'Here I am, publishing data';

        $clientMessage = array(7, $topic, $event);

        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, json_encode($clientMessage));

        $this->assertEquals($topic, $this->_app->last['onPublish'][1]);
        $this->assertEquals($event, $this->_app->last['onPublish'][2]);
        $this->assertEquals(array(), $this->_app->last['onPublish'][3]);
        $this->assertEquals(array(), $this->_app->last['onPublish'][4]);
    }

    public function testPublishAndExcludeMe() {
        $conn = $this->newConn();

        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, json_encode(array(7, 'topic', 'event', true)));

        $this->assertEquals($conn->WAMP->sessionId, $this->_app->last['onPublish'][3][0]);
    }

    public function testPublishAndEligible() {
        $conn = $this->newConn();

        $buddy  = uniqid('', false);
        $friend = uniqid('', false);

        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, json_encode(array(7, 'topic', 'event', false, array($buddy, $friend))));

        $this->assertEquals(array(), $this->_app->last['onPublish'][3]);
        $this->assertEquals(2, count($this->_app->last['onPublish'][4]));
    }

    public function eventProvider() {
        return array(
            array('http://example.com', array('one', 'two'))
          , array('curie', array(array('hello' => 'world', 'herp' => 'derp')))
        );
    }

    /**
     * @dataProvider eventProvider
     */
    public function testEvent($topic, $payload) {
        $conn = new WampConnection($this->newConn());
        $conn->event($topic, $payload);

        $eventString = $conn->last['send'];

        $this->assertSame(array(8, $topic, $payload), json_decode($eventString, true));
    }

    public function testOnClosePropagation() {
        $conn = new Connection;

        $this->_comp->onOpen($conn);
        $this->_comp->onClose($conn);

        $class  = new \ReflectionClass('Ratchet\\Wamp\\WampConnection');
        $method = $class->getMethod('getConnection');
        $method->setAccessible(true);

        $check = $method->invokeArgs($this->_app->last['onClose'][0], array());

        $this->assertSame($conn, $check);
    }

    public function testOnErrorPropagation() {
        $conn = new Connection;

        $e = new \Exception('Nope');

        $this->_comp->onOpen($conn);
        $this->_comp->onError($conn, $e);

        $class  = new \ReflectionClass('Ratchet\\Wamp\\WampConnection');
        $method = $class->getMethod('getConnection');
        $method->setAccessible(true);

        $check = $method->invokeArgs($this->_app->last['onError'][0], array());

        $this->assertSame($conn, $check);
        $this->assertSame($e, $this->_app->last['onError'][1]);
    }

    public function testPrefix() {
        $conn = new WampConnection($this->newConn());
        $this->_comp->onOpen($conn);

        $prefix  = 'incoming';
        $fullURI   = "http://example.com/$prefix";
        $method = 'call';

        $this->_comp->onMessage($conn, json_encode(array(1, $prefix, $fullURI)));

        $this->assertEquals($fullURI, $conn->WAMP->prefixes[$prefix]);
        $this->assertEquals("$fullURI#$method", $conn->getUri("$prefix:$method"));
    }

    public function testMessageMustBeJson() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('Ratchet\Wamp\Exception');
        } else {
            $this->setExpectedException('Ratchet\Wamp\Exception');
        }

        $conn = new Connection;

        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, 'Hello World!');
    }

    public function testGetSubProtocolsReturnsArray() {
        $this->assertTrue(is_array($this->_comp->getSubProtocols()));
    }

    public function testGetSubProtocolsGetFromApp() {
        $this->_app->protocols = array('hello', 'world');

        $this->assertGreaterThanOrEqual(3, count($this->_comp->getSubProtocols()));
    }

    public function testWampOnMessageApp() {
        $app = $this->getMockBuilder('Ratchet\\Wamp\\WampServerInterface')->getMock();
        $wamp = new ServerProtocol($app);

        $this->assertContains('wamp', $wamp->getSubProtocols());
    }

    public function badFormatProvider() {
        return array(
            array(json_encode(true))
          , array('{"valid":"json", "invalid": "message"}')
          , array('{"0": "fail", "hello": "world"}')
        );
    }

    /**
     * @dataProvider badFormatProvider
     */
    public function testValidJsonButInvalidProtocol($message) {
        if (method_exists($this, 'expectException')) {
            $this->expectException('Ratchet\Wamp\Exception');
        } else {
            $this->setExpectedException('Ratchet\Wamp\Exception');
        }

        $conn = $this->newConn();
        $this->_comp->onOpen($conn);
        $this->_comp->onMessage($conn, $message);
    }

    public function testBadClientInputFromNonStringTopic() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('Ratchet\Wamp\Exception');
        } else {
            $this->setExpectedException('Ratchet\Wamp\Exception');
        }

        $conn = new WampConnection($this->newConn());
        $this->_comp->onOpen($conn);

        $this->_comp->onMessage($conn, json_encode([5, ['hells', 'nope']]));
    }

    public function testBadPrefixWithNonStringTopic() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('Ratchet\Wamp\Exception');
        } else {
            $this->setExpectedException('Ratchet\Wamp\Exception');
        }

        $conn = new WampConnection($this->newConn());
        $this->_comp->onOpen($conn);

        $this->_comp->onMessage($conn, json_encode([1, ['hells', 'nope'], ['bad', 'input']]));
    }

    public function testBadPublishWithNonStringTopic() {
        if (method_exists($this, 'expectException')) {
            $this->expectException('Ratchet\Wamp\Exception');
        } else {
            $this->setExpectedException('Ratchet\Wamp\Exception');
        }

        $conn = new WampConnection($this->newConn());
        $this->_comp->onOpen($conn);

        $this->_comp->onMessage($conn, json_encode([7, ['bad', 'input'], 'Hider']));
    }
}


================================================
FILE: tests/unit/Wamp/TopicManagerTest.php
================================================
<?php
namespace Ratchet\Wamp;

use PHPUnit\Framework\TestCase;

/**
 * @covers Ratchet\Wamp\TopicManager
 */
class TopicManagerTest extends TestCase {
    private $mock;

    /**
     * @var \Ratchet\Wamp\TopicManager
     */
    private $mngr;

    /**
     * @var \Ratchet\ConnectionInterface
     */
    private $conn;

    /**
     * @before
     */
    public function setUpManager() {
        $this->conn = $this->getMockBuilder('Ratchet\Mock\Connection')->getMock();
        $this->mock = $this->getMockBuilder('Ratchet\Wamp\WampServerInterface')->getMock();
        $this->mngr = new TopicManager($this->mock);

        $this->conn->WAMP = new \StdClass;
        $this->mngr->onOpen($this->conn);
    }

    public function testGetTopicReturnsTopicObject() {
        $class  = new \ReflectionClass('Ratchet\Wamp\TopicManager');
        $method = $class->getMethod('getTopic');
        $method->setAccessible(true);

        $topic = $method->invokeArgs($this->mngr, array('The Topic'));

        $this->assertInstanceOf('Ratchet\Wamp\Topic', $topic);
    }

    public function testGetTopicCreatesTopicWithSameName() {
        $name = 'The Topic';

        $class  = new \ReflectionClass('Ratchet\Wamp\TopicManager');
        $method = $class->getMethod('getTopic');
        $method->setAccessible(true);

        $topic = $method->invokeArgs($this->mngr, array($name));

        $this->assertEquals($name, $topic->getId());
    }

    public function testGetTopicReturnsSameObject() {
        $class  = new \ReflectionClass('Ratchet\Wamp\TopicManager');
        $method = $class->getMethod('getTopic');
        $method->setAccessible(true);

        $topic = $method->invokeArgs($this->mngr, array('No copy'));
        $again = $method->invokeArgs($this->mngr, array('No copy'));

        $this->assertSame($topic, $again);
    }

    public function testOnOpen() {
        $this->mock->expects($this->once())->method('onOpen');
        $this->mngr->onOpen($this->conn);
    }

    public function testOnCall() {
        $id = uniqid();

        $this->mock->expects($this->once())->method('onCall')->with(
            $this->conn
          , $id
          , $this->isInstanceOf('Ratchet\Wamp\Topic')
          , array()
        );

        $this->mngr->onCall($this->conn, $id, 'new topic', array());
    }

    public function testOnSubscribeCreatesTopicObject() {
        $this->mock->expects($this->once())->method('onSubscribe')->with(
            $this->conn, $this->isInstanceOf('Ratchet\Wamp\Topic')
        );

        $this->mngr->onSubscribe($this->conn, 'new topic');
    }

    public function testTopicIsInConnectionOnSubscribe() {
        $name = 'New Topic';

        $class  = new \ReflectionClass('Ratchet\Wamp\TopicManager');
        $method = $class->getMethod('getTopic');
        $method->setAccessible(true);

        $topic = $method->invokeArgs($this->mngr, array($name));

        $this->mngr->onSubscribe($this->conn, $name);

        $this->assertTrue($this->conn->WAMP->subscriptions->contains($topic));
    }

    public function testDoubleSubscriptionFiresOnce() {
        $this->mock->expects($this->exactly(1))->method('onSubscribe');

        $this->mngr->onSubscribe($this->conn, 'same topic');
        $this->mngr->onSubscribe($this->conn, 'same topic');
    }

    public function testUnsubscribeEvent() {
        $name = 'in and out';
        $this->mock->expects($this->once())->method('onUnsubscribe')->with(
            $this->conn, $this->isInstanceOf('Ratchet\Wamp\Topic')
        );

        $this->mngr->onSubscribe($this->conn, $name);
        $this->mngr->onUnsubscribe($this->conn, $name);
    }

    public function testUnsubscribeFiresOnce() {
        $name = 'getting sleepy';
        $this->mock->expects($this->exactly(1))->method('onUnsubscribe');

        $this->mngr->onSubscribe($this->conn,   $name);
        $this->mngr->onUnsubscribe($this->conn, $name);
        $this->mngr->onUnsubscribe($this->conn, $name);
    }

    public function testUnsubscribeRemovesTopicFromConnection() {
        $name = 'Bye Bye Topic';

        $class  = new \ReflectionClass('Ratchet\Wamp\TopicManager');
        $method = $class->getMethod('getTopic');
        $method->setAccessible(true);

        $topic = $method->invokeArgs($this->mngr, array($name));

        $this->mngr->onSubscribe($this->conn, $name);
        $this->mngr->onUnsubscribe($this->conn, $name);

        $this->assertFalse($this->conn->WAMP->subscriptions->contains($topic));
    }

    public function testOnPublishBubbles() {
        $msg = 'Cover all the code!';

        $this->mock->expects($this->once())->method('onPublish')->with(
            $this->conn
          , $this->isInstanceOf('Ratchet\Wamp\Topic')
          , $msg
          , $this->isType('array')
          , $this->isType('array')
        );

        $this->mngr->onPublish($this->conn, 'topic coverage', $msg, array(), array());
    }

    public function testOnCloseBubbles() {
        $this->mock->expects($this->once())->method('onClose')->with($this->conn);
        $this->mngr->onClose($this->conn);
    }

    protected function topicProvider($name) {
        $class  = new \ReflectionClass('Ratchet\Wamp\TopicManager');
        $method = $class->getMethod('getTopic');
        $method->setAccessible(true);

        $attribute = $class->getProperty('topicLookup');
        $attribute->setAccessible(true);

        $topic = $method->invokeArgs($this->mngr, array($name));

        return array($topic, $attribute);
    }

    public function testConnIsRemovedFromTopicOnClose() {
        $name = 'State Testing';
        list($topic, $attribute) = $this->topicProvider($name);

        $this->assertCount(1, $attribute->getValue($this->mngr));

        $this->mngr->onSubscribe($this->conn, $name);
        $this->mngr->onClose($this->conn);

        $this->assertFalse($topic->has($this->conn));
    }

    public static function topicConnExpectationProvider() {
        return [
            [ 'onClose', 0]
          , ['onUnsubscribe', 0]
        ];
    }

    /**
     * @dataProvider topicConnExpectationProvider
     */
    public function testTopicRetentionFromLeavingConnections($methodCall, $expectation) {
        $topicName = 'checkTopic';
        list($topic, $attribute) = $this->topicProvider($topicName);

        $this->mngr->onSubscribe($this->conn, $topicName);
        call_user_func_array(array($this->mngr, $methodCall), array($this->conn, $topicName));

        $this->assertCount($expectation, $attribute->getValue($this->mngr));
    }

    public function testOnErrorBubbles() {
        $e = new \Exception('All work and no play makes Chris a dull boy');
        $this->mock->expects($this->once())->method('onError')->with($this->conn, $e);

        $this->mngr->onError($this->conn, $e);
    }

    public function testGetSubProtocolsReturnsArray() {
        if (method_exists($this, 'assertIsArray')) {
            // PHPUnit 7+
            $this->assertIsArray($this->mngr->getSubProtocols());
        } else {
            // legacy PHPUnit
            $this->assertInternalType('array', $this->mngr->getSubProtocols());
        }
    }

    public function testGetSubProtocolsBubbles() {
        $subs = array('hello', 'world');
        $app  = $this->getMockBuilder('Ratchet\Wamp\Stub\WsWampServerInterface')->getMock();
        $app->expects($this->once())->method('getSubProtocols')->will($this->returnValue($subs));
        $mngr = new TopicManager($app);

        $this->assertEquals($subs, $mngr->getSubProtocols());
    }
}


================================================
FILE: tests/unit/Wamp/TopicTest.php
================================================
<?php
namespace Ratchet\Wamp;

use PHPUnit\Framework\TestCase;

/**
 * @covers Ratchet\Wamp\Topic
 */
class TopicTest extends TestCase {
    public function testGetId() {
        $id    = uniqid();
        $topic = new Topic($id);

        $this->assertEquals($id, $topic->getId());
    }

    public function testAddAndCount() {
        $topic = new Topic('merp');

        $topic->add($this->newConn());
        $topic->add($this->newConn());
        $topic->add($this->newConn());

        $this->assertEquals(3, count($topic));
    }

    public function testRemove() {
        $topic   = new Topic('boop');
        $tracked = $this->newConn();

        $topic->add($this->newConn());
        $topic->add($tracked);
        $topic->add($this->newConn());

        $topic->remove($tracked);

        $this->assertEquals(2, count($topic));
    }

    public function testBroadcast() {
        $msg  = 'Hello World!';
        $name = 'Batman';
        $protocol = json_encode(array(8, $name, $msg));

        $first  = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();
        $second = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();

        $first->expects($this->once())
              ->method('send')
              ->with($this->equalTo($protocol));

        $second->expects($this->once())
              ->method('send')
              ->with($this->equalTo($protocol));

        $topic = new Topic($name);
        $topic->add($first);
        $topic->add($second);

        $topic->broadcast($msg);
    }

    public function testBroadcastWithExclude() {
        $msg  = 'Hello odd numbers';
        $name = 'Excluding';
        $protocol = json_encode(array(8, $name, $msg));

        $first  = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();
        $second = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();
        $third  = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();

        $first->expects($this->once())
            ->method('send')
            ->with($this->equalTo($protocol));

        $second->expects($this->never())->method('send');

        $third->expects($this->once())
            ->method('send')
            ->with($this->equalTo($protocol));

        $topic = new Topic($name);
        $topic->add($first);
        $topic->add($second);
        $topic->add($third);

        $topic->broadcast($msg, array($second->WAMP->sessionId));
    }

    public function testBroadcastWithEligible() {
        $msg  = 'Hello white list';
        $name = 'Eligible';
        $protocol = json_encode(array(8, $name, $msg));

        $first  = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();
        $second = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();
        $third  = $this->getMockBuilder('Ratchet\\Wamp\\WampConnection')->setMethods(array('send'))->setConstructorArgs(array($this->getMockBuilder('Ratchet\Mock\Connection')->getMock()))->getMock();

        $first->expects($this->once())
            ->method('send')
            ->with($this->equalTo($protocol));

        $second->expects($this->never())->method('send');

        $third->expects($this->once())
            ->method('send')
            ->with($this->equalTo($protocol));

        $topic = new Topic($name);
        $topic->add($first);
        $topic->add($second);
        $topic->add($third);

        $topic->broadcast($msg, array(), array($first->WAMP->sessionId, $third->WAMP->sessionId));
    }

    public function testIterator() {
        $first  = $this->newConn();
        $second = $this->newConn();
        $third  = $this->newConn();

        $topic  = new Topic('Joker');
        $topic->add($first)->add($second)->add($third);

        $check = array($first, $second, $third);

        foreach ($topic as $mock) {
            $this->assertNotSame(false, array_search($mock, $check));
        }
    }

    public function testToString() {
        $name  = 'Bane';
        $topic = new Topic($name);

        $this->assertEquals($name, (string)$topic);
    }

    public function
Download .txt
gitextract_uifflmqw/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bugreport.yml
│   │   └── config.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── composer.json
├── phpunit.xml.dist
├── phpunit.xml.legacy
├── src/
│   └── Ratchet/
│       ├── AbstractConnectionDecorator.php
│       ├── App.php
│       ├── ComponentInterface.php
│       ├── ConnectionInterface.php
│       ├── Http/
│       │   ├── CloseResponseTrait.php
│       │   ├── HttpRequestParser.php
│       │   ├── HttpServer.php
│       │   ├── HttpServerInterface.php
│       │   ├── NoOpHttpServerController.php
│       │   ├── OriginCheck.php
│       │   └── Router.php
│       ├── MessageComponentInterface.php
│       ├── MessageInterface.php
│       ├── Server/
│       │   ├── EchoServer.php
│       │   ├── FlashPolicy.php
│       │   ├── IoConnection.php
│       │   ├── IoServer.php
│       │   └── IpBlackList.php
│       ├── Session/
│       │   ├── Serialize/
│       │   │   ├── HandlerInterface.php
│       │   │   ├── PhpBinaryHandler.php
│       │   │   └── PhpHandler.php
│       │   ├── SessionProvider.php
│       │   └── Storage/
│       │       ├── Proxy/
│       │       │   ├── VirtualProxy.php
│       │       │   ├── VirtualProxyForSymfony6.php
│       │       │   └── VirtualProxyForSymfony7.php
│       │       ├── VirtualSessionStorage.php
│       │       ├── VirtualSessionStorageForSymfony6.php
│       │       └── VirtualSessionStorageForSymfony7.php
│       ├── Wamp/
│       │   ├── Exception.php
│       │   ├── JsonException.php
│       │   ├── ServerProtocol.php
│       │   ├── Topic.php
│       │   ├── TopicManager.php
│       │   ├── WampConnection.php
│       │   ├── WampServer.php
│       │   └── WampServerInterface.php
│       └── WebSocket/
│           ├── ConnContext.php
│           ├── MessageCallableInterface.php
│           ├── MessageComponentInterface.php
│           ├── WsConnection.php
│           ├── WsServer.php
│           └── WsServerInterface.php
└── tests/
    ├── autobahn/
    │   ├── bin/
    │   │   └── fuzzingserver.php
    │   ├── fuzzingclient-all.json
    │   ├── fuzzingclient-profile.json
    │   └── fuzzingclient-quick.json
    ├── bootstrap.php
    ├── helpers/
    │   └── Ratchet/
    │       ├── AbstractMessageComponentTestCase.php
    │       ├── Mock/
    │       │   ├── Connection.php
    │       │   ├── ConnectionDecorator.php
    │       │   └── WampComponent.php
    │       ├── NullComponent.php
    │       ├── Wamp/
    │       │   └── Stub/
    │       │       └── WsWampServerInterface.php
    │       └── WebSocket/
    │           └── Stub/
    │               └── WsMessageComponentInterface.php
    └── unit/
        ├── AbstractConnectionDecoratorTest.php
        ├── AppTest.php
        ├── Http/
        │   ├── HttpRequestParserTest.php
        │   ├── HttpServerTest.php
        │   ├── OriginCheckTest.php
        │   └── RouterTest.php
        ├── Server/
        │   ├── EchoServerTest.php
        │   ├── FlashPolicyComponentTest.php
        │   ├── IoConnectionTest.php
        │   ├── IoServerTest.php
        │   └── IpBlackListComponentTest.php
        ├── Session/
        │   ├── Serialize/
        │   │   ├── PhpBinaryHandlerTest.php
        │   │   └── PhpHandlerTest.php
        │   ├── SessionProviderTest.php
        │   └── Storage/
        │       └── VirtualSessionStoragePDOTest.php
        └── Wamp/
            ├── ServerProtocolTest.php
            ├── TopicManagerTest.php
            ├── TopicTest.php
            ├── WampConnectionTest.php
            └── WampServerTest.php
Download .txt
SYMBOL INDEX (479 symbols across 70 files)

FILE: src/Ratchet/AbstractConnectionDecorator.php
  class AbstractConnectionDecorator (line 14) | abstract class AbstractConnectionDecorator implements ConnectionInterface {
    method __construct (line 20) | public function __construct(ConnectionInterface $conn) {
    method getConnection (line 27) | protected function getConnection() {
    method __set (line 31) | public function __set($name, $value) {
    method __get (line 35) | public function __get($name) {
    method __isset (line 39) | public function __isset($name) {
    method __unset (line 43) | public function __unset($name) {

FILE: src/Ratchet/App.php
  class App (line 27) | class App {
    method __construct (line 67) | public function __construct($httpHost = 'localhost', $port = 8080, $ad...
    method route (line 112) | public function route($path, ComponentInterface $controller, array $al...
    method run (line 152) | public function run() {

FILE: src/Ratchet/ComponentInterface.php
  type ComponentInterface (line 8) | interface ComponentInterface {
    method onOpen (line 14) | function onOpen(ConnectionInterface $conn);
    method onClose (line 21) | function onClose(ConnectionInterface $conn);
    method onError (line 30) | function onError(ConnectionInterface $conn, \Exception $e);

FILE: src/Ratchet/ConnectionInterface.php
  type ConnectionInterface (line 20) | interface ConnectionInterface {
    method send (line 26) | function send($data);
    method close (line 31) | function close();

FILE: src/Ratchet/Http/CloseResponseTrait.php
  type CloseResponseTrait (line 7) | trait CloseResponseTrait {
    method close (line 14) | private function close(ConnectionInterface $conn, $code = 400, array $...

FILE: src/Ratchet/Http/HttpRequestParser.php
  class HttpRequestParser (line 12) | class HttpRequestParser implements MessageInterface {
    method onMessage (line 28) | public function onMessage(ConnectionInterface $context, $data) {
    method isEom (line 53) | public function isEom($message) {
    method parse (line 61) | public function parse($headers) {

FILE: src/Ratchet/Http/HttpServer.php
  class HttpServer (line 6) | class HttpServer implements MessageComponentInterface {
    method __construct (line 24) | public function __construct(HttpServerInterface $component) {
    method onOpen (line 32) | public function onOpen(ConnectionInterface $conn) {
    method onMessage (line 39) | public function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 60) | public function onClose(ConnectionInterface $conn) {
    method onError (line 69) | public function onError(ConnectionInterface $conn, \Exception $e) {

FILE: src/Ratchet/Http/HttpServerInterface.php
  type HttpServerInterface (line 7) | interface HttpServerInterface extends MessageComponentInterface {
    method onOpen (line 13) | #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn...

FILE: src/Ratchet/Http/NoOpHttpServerController.php
  class NoOpHttpServerController (line 6) | class NoOpHttpServerController implements HttpServerInterface {
    method onOpen (line 7) | #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn...
    method onMessage (line 11) | public function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 14) | public function onClose(ConnectionInterface $conn) {
    method onError (line 17) | public function onError(ConnectionInterface $conn, \Exception $e) {

FILE: src/Ratchet/Http/OriginCheck.php
  class OriginCheck (line 12) | class OriginCheck implements HttpServerInterface {
    method __construct (line 26) | public function __construct(MessageComponentInterface $component, arra...
    method onOpen (line 34) | #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn...
    method onMessage (line 49) | function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 56) | function onClose(ConnectionInterface $conn) {
    method onError (line 63) | function onError(ConnectionInterface $conn, \Exception $e) {

FILE: src/Ratchet/Http/Router.php
  class Router (line 10) | class Router implements HttpServerInterface {
    method __construct (line 20) | public function __construct(UrlMatcherInterface $matcher) {
    method onOpen (line 29) | #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn...
    method onMessage (line 76) | public function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 83) | public function onClose(ConnectionInterface $conn) {
    method onError (line 92) | public function onError(ConnectionInterface $conn, \Exception $e) {

FILE: src/Ratchet/MessageComponentInterface.php
  type MessageComponentInterface (line 4) | interface MessageComponentInterface extends ComponentInterface, MessageI...

FILE: src/Ratchet/MessageInterface.php
  type MessageInterface (line 4) | interface MessageInterface {
    method onMessage (line 11) | function onMessage(ConnectionInterface $from, $msg);

FILE: src/Ratchet/Server/EchoServer.php
  class EchoServer (line 9) | class EchoServer implements MessageComponentInterface {
    method onOpen (line 10) | public function onOpen(ConnectionInterface $conn) {
    method onMessage (line 13) | public function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 17) | public function onClose(ConnectionInterface $conn) {
    method onError (line 20) | public function onError(ConnectionInterface $conn, \Exception $e) {

FILE: src/Ratchet/Server/FlashPolicy.php
  class FlashPolicy (line 16) | class FlashPolicy implements MessageComponentInterface {
    method addAllowedAccess (line 60) | public function addAllowedAccess($domain, $ports = '*', $secure = fals...
    method clearAllowedAccess (line 80) | public function clearAllowedAccess() {
    method setSiteControl (line 96) | public function setSiteControl($permittedCrossDomainPolicies = 'all') {
    method onOpen (line 110) | public function onOpen(ConnectionInterface $conn) {
    method onMessage (line 116) | public function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 129) | public function onClose(ConnectionInterface $conn) {
    method onError (line 135) | public function onError(ConnectionInterface $conn, \Exception $e) {
    method renderPolicy (line 145) | public function renderPolicy() {
    method validateSiteControl (line 176) | public function validateSiteControl($permittedCrossDomainPolicies) {
    method validateDomain (line 187) | public function validateDomain($domain) {
    method validatePorts (line 197) | public function validatePorts($port) {

FILE: src/Ratchet/Server/IoConnection.php
  class IoConnection (line 9) | #[\AllowDynamicProperties]
    method __construct (line 20) | public function __construct(SocketConnection $conn) {
    method send (line 27) | public function send($data) {
    method close (line 36) | public function close() {

FILE: src/Ratchet/Server/IoServer.php
  class IoServer (line 16) | class IoServer {
    method __construct (line 38) | public function __construct(MessageComponentInterface $app, ServerInte...
    method factory (line 63) | public static function factory(MessageComponentInterface $component, $...
    method run (line 77) | public function run() {
    method handleConnect (line 91) | public function handleConnect(SocketConnection $conn) {
    method handleData (line 124) | public function handleData($data, $conn) {
    method handleEnd (line 136) | public function handleEnd($conn) {
    method handleError (line 151) | public function handleError(\Exception $e, $conn) {

FILE: src/Ratchet/Server/IpBlackList.php
  class IpBlackList (line 6) | class IpBlackList implements MessageComponentInterface {
    method __construct (line 20) | public function __construct(MessageComponentInterface $component) {
    method blockAddress (line 29) | public function blockAddress($ip) {
    method unblockAddress (line 40) | public function unblockAddress($ip) {
    method isBlocked (line 52) | public function isBlocked($address) {
    method getBlockedAddresses (line 60) | public function getBlockedAddresses() {
    method filterAddress (line 68) | public function filterAddress($address) {
    method onOpen (line 79) | function onOpen(ConnectionInterface $conn) {
    method onMessage (line 90) | function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 97) | function onClose(ConnectionInterface $conn) {
    method onError (line 106) | function onError(ConnectionInterface $conn, \Exception $e) {

FILE: src/Ratchet/Session/Serialize/HandlerInterface.php
  type HandlerInterface (line 4) | interface HandlerInterface {
    method serialize (line 9) | function serialize(array $data);
    method unserialize (line 15) | function unserialize($raw);

FILE: src/Ratchet/Session/Serialize/PhpBinaryHandler.php
  class PhpBinaryHandler (line 4) | class PhpBinaryHandler implements HandlerInterface {
    method serialize (line 8) | function serialize(array $data) {
    method unserialize (line 16) | public function unserialize($raw) {

FILE: src/Ratchet/Session/Serialize/PhpHandler.php
  class PhpHandler (line 4) | class PhpHandler implements HandlerInterface {
    method serialize (line 9) | function serialize(array $data) {
    method unserialize (line 28) | public function unserialize($raw) {

FILE: src/Ratchet/Session/SessionProvider.php
  class SessionProvider (line 17) | class SessionProvider implements HttpServerInterface {
    method __construct (line 47) | public function __construct(HttpServerInterface $app, \SessionHandlerI...
    method onOpen (line 76) | #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn...
    method onMessage (line 109) | function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 116) | function onClose(ConnectionInterface $conn) {
    method onError (line 125) | function onError(ConnectionInterface $conn, \Exception $e) {
    method setOptions (line 135) | protected function setOptions(array $options) {
    method toClassCase (line 163) | protected function toClassCase($langDef) {
    method parseCookie (line 187) | private function parseCookie($cookie, $host = null, $path = null, $dec...

FILE: src/Ratchet/Session/Storage/Proxy/VirtualProxy.php
  class VirtualProxy (line 14) | class VirtualProxy extends SessionHandlerProxy {
    method __construct (line 28) | public function __construct(\SessionHandlerInterface $handler) {
    method getId (line 38) | public function getId() {
    method setId (line 45) | public function setId($id) {
    method getName (line 52) | public function getName() {
    method setName (line 60) | public function setName($name) {

FILE: src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony6.php
  class VirtualProxyForSymfony6 (line 11) | class VirtualProxyForSymfony6 extends SessionHandlerProxy {
    method __construct (line 25) | public function __construct(\SessionHandlerInterface $handler) {
    method getId (line 35) | public function getId(): string {
    method setId (line 42) | public function setId($id) {
    method getName (line 49) | public function getName(): string {
    method setName (line 57) | public function setName($name) {

FILE: src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony7.php
  class VirtualProxyForSymfony7 (line 11) | class VirtualProxyForSymfony7 extends SessionHandlerProxy {
    method __construct (line 25) | public function __construct(\SessionHandlerInterface $handler) {
    method getId (line 35) | public function getId(): string {
    method setId (line 42) | public function setId(string $id): void {
    method getName (line 49) | public function getName(): string {
    method setName (line 57) | public function setName(string $name): void {

FILE: src/Ratchet/Session/Storage/VirtualSessionStorage.php
  class VirtualSessionStorage (line 16) | class VirtualSessionStorage extends NativeSessionStorage {
    method __construct (line 27) | public function __construct(\SessionHandlerInterface $handler, $sessio...
    method start (line 37) | public function start() {
    method regenerate (line 63) | public function regenerate($destroy = false, $lifetime = null) {
    method save (line 71) | public function save() {
    method setSaveHandler (line 87) | public function setSaveHandler($saveHandler = null) {

FILE: src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php
  class VirtualSessionStorageForSymfony6 (line 13) | class VirtualSessionStorageForSymfony6 extends NativeSessionStorage {
    method __construct (line 24) | public function __construct(\SessionHandlerInterface $handler, $sessio...
    method start (line 34) | public function start(): bool {
    method regenerate (line 60) | public function regenerate(bool $destroy = false, ?int $lifetime = nul...
    method save (line 68) | public function save() {
    method setSaveHandler (line 84) | public function setSaveHandler($saveHandler = null) {

FILE: src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony7.php
  class VirtualSessionStorageForSymfony7 (line 14) | class VirtualSessionStorageForSymfony7 extends NativeSessionStorage {
    method __construct (line 25) | public function __construct(\SessionHandlerInterface $handler, $sessio...
    method start (line 35) | public function start(): bool {
    method regenerate (line 61) | public function regenerate(bool $destroy = false, ?int $lifetime = nul...
    method save (line 69) | public function save(): void {
    method setSaveHandler (line 85) | public function setSaveHandler(AbstractProxy|\SessionHandlerInterface|...

FILE: src/Ratchet/Wamp/Exception.php
  class Exception (line 4) | class Exception extends \Exception {

FILE: src/Ratchet/Wamp/JsonException.php
  class JsonException (line 4) | class JsonException extends Exception {
    method __construct (line 5) | public function __construct() {

FILE: src/Ratchet/Wamp/ServerProtocol.php
  class ServerProtocol (line 27) | class ServerProtocol implements MessageComponentInterface, WsServerInter...
    method __construct (line 51) | public function __construct(WampServerInterface $serverComponent) {
    method getSubProtocols (line 59) | public function getSubProtocols() {
    method onOpen (line 73) | public function onOpen(ConnectionInterface $conn) {
    method onMessage (line 85) | public function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 148) | public function onClose(ConnectionInterface $conn) {
    method onError (line 158) | public function onError(ConnectionInterface $conn, \Exception $e) {

FILE: src/Ratchet/Wamp/Topic.php
  class Topic (line 8) | class Topic implements \IteratorAggregate, \Countable {
    method __construct (line 16) | public function __construct($topicId) {
    method getId (line 24) | public function getId() {
    method __toString (line 28) | public function __toString() {
    method broadcast (line 39) | public function broadcast($msg, array $exclude = array(), array $eligi...
    method has (line 60) | public function has(ConnectionInterface $conn) {
    method add (line 68) | public function add(ConnectionInterface $conn) {
    method remove (line 78) | public function remove(ConnectionInterface $conn) {
    method getIterator (line 89) | #[\ReturnTypeWillChange]
    method count (line 97) | #[\ReturnTypeWillChange]

FILE: src/Ratchet/Wamp/TopicManager.php
  class TopicManager (line 6) | class TopicManager implements WsServerInterface, WampServerInterface {
    method __construct (line 17) | public function __construct(WampServerInterface $app) {
    method onOpen (line 24) | public function onOpen(ConnectionInterface $conn) {
    method onCall (line 32) | public function onCall(ConnectionInterface $conn, $id, $topic, array $...
    method onSubscribe (line 39) | public function onSubscribe(ConnectionInterface $conn, $topic) {
    method onUnsubscribe (line 54) | public function onUnsubscribe(ConnectionInterface $conn, $topic) {
    method onPublish (line 69) | public function onPublish(ConnectionInterface $conn, $topic, $event, a...
    method onClose (line 76) | public function onClose(ConnectionInterface $conn) {
    method onError (line 87) | public function onError(ConnectionInterface $conn, \Exception $e) {
    method getSubProtocols (line 94) | public function getSubProtocols() {
    method getTopic (line 106) | protected function getTopic($topic) {
    method cleanTopic (line 114) | protected function cleanTopic(Topic $topic, ConnectionInterface $conn) {

FILE: src/Ratchet/Wamp/WampConnection.php
  class WampConnection (line 12) | class WampConnection extends AbstractConnectionDecorator {
    method __construct (line 16) | public function __construct(ConnectionInterface $conn) {
    method callResult (line 32) | public function callResult($id, $data = array()) {
    method callError (line 44) | public function callError($id, $errorUri, $desc = '', $details = null) {
    method event (line 63) | public function event($topic, $msg) {
    method prefix (line 72) | public function prefix($curie, $uri) {
    method getUri (line 83) | public function getUri($uri) {
    method send (line 102) | public function send($data) {
    method close (line 111) | public function close($opt = null) {

FILE: src/Ratchet/Wamp/WampServer.php
  class WampServer (line 14) | class WampServer implements MessageComponentInterface, WsServerInterface {
    method __construct (line 25) | public function __construct(WampServerInterface $app) {
    method onOpen (line 32) | public function onOpen(ConnectionInterface $conn) {
    method onMessage (line 39) | public function onMessage(ConnectionInterface $conn, $msg) {
    method onClose (line 50) | public function onClose(ConnectionInterface $conn) {
    method onError (line 57) | public function onError(ConnectionInterface $conn, \Exception $e) {
    method getSubProtocols (line 64) | public function getSubProtocols() {

FILE: src/Ratchet/Wamp/WampServerInterface.php
  type WampServerInterface (line 10) | interface WampServerInterface extends ComponentInterface {
    method onCall (line 18) | function onCall(ConnectionInterface $conn, $id, $topic, array $params);
    method onSubscribe (line 25) | function onSubscribe(ConnectionInterface $conn, $topic);
    method onUnSubscribe (line 32) | function onUnSubscribe(ConnectionInterface $conn, $topic);
    method onPublish (line 42) | function onPublish(ConnectionInterface $conn, $topic, $event, array $e...

FILE: src/Ratchet/WebSocket/ConnContext.php
  class ConnContext (line 5) | class ConnContext {
    method __construct (line 16) | public function __construct(WsConnection $conn, MessageBuffer $buffer) {

FILE: src/Ratchet/WebSocket/MessageCallableInterface.php
  type MessageCallableInterface (line 6) | interface MessageCallableInterface {
    method onMessage (line 7) | public function onMessage(ConnectionInterface $conn, MessageInterface ...

FILE: src/Ratchet/WebSocket/MessageComponentInterface.php
  type MessageComponentInterface (line 5) | interface MessageComponentInterface extends ComponentInterface, MessageC...

FILE: src/Ratchet/WebSocket/WsConnection.php
  class WsConnection (line 11) | class WsConnection extends AbstractConnectionDecorator {
    method send (line 15) | public function send($msg) {
    method close (line 30) | public function close($code = 1000) {

FILE: src/Ratchet/WebSocket/WsServer.php
  class WsServer (line 26) | class WsServer implements HttpServerInterface {
    method __construct (line 69) | public function __construct(ComponentInterface $component) {
    method isRFC6455v03 (line 111) | private static function isRFC6455v03() {
    method onOpen (line 119) | #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn...
    method onMessage (line 161) | public function onMessage(ConnectionInterface $from, $msg) {
    method onClose (line 172) | public function onClose(ConnectionInterface $conn) {
    method onError (line 184) | public function onError(ConnectionInterface $conn, \Exception $e) {
    method onControlFrame (line 192) | public function onControlFrame(FrameInterface $frame, WsConnection $co...
    method setStrictSubProtocolCheck (line 207) | public function setStrictSubProtocolCheck($enable) {
    method enableKeepAlive (line 211) | public function enableKeepAlive(LoopInterface $loop, $interval = 30) {

FILE: src/Ratchet/WebSocket/WsServerInterface.php
  type WsServerInterface (line 7) | interface WsServerInterface {
    method getSubProtocols (line 13) | function getSubProtocols();

FILE: tests/autobahn/bin/fuzzingserver.php
  class BinaryEcho (line 6) | class BinaryEcho implements \Ratchet\WebSocket\MessageComponentInterface {
    method onMessage (line 7) | public function onMessage(ConnectionInterface $from, \Ratchet\RFC6455\...
    method onOpen (line 11) | public function onOpen(ConnectionInterface $conn) {
    method onClose (line 14) | public function onClose(ConnectionInterface $conn) {
    method onError (line 17) | public function onError(ConnectionInterface $conn, \Exception $e) {

FILE: tests/helpers/Ratchet/AbstractMessageComponentTestCase.php
  class AbstractMessageComponentTestCase (line 6) | abstract class AbstractMessageComponentTestCase extends TestCase {
    method getConnectionClassString (line 11) | abstract public function getConnectionClassString();
    method getDecoratorClassString (line 12) | abstract public function getDecoratorClassString();
    method getComponentClassString (line 13) | abstract public function getComponentClassString();
    method setUpConnection (line 18) | public function setUpConnection() {
    method doOpen (line 27) | protected function doOpen($conn) {
    method isExpectedConnection (line 31) | public function isExpectedConnection() {
    method testOpen (line 35) | public function testOpen() {
    method testOnClose (line 40) | public function testOnClose() {
    method testOnError (line 45) | public function testOnError() {
    method passthroughMessageTest (line 51) | public function passthroughMessageTest($value) {

FILE: tests/helpers/Ratchet/Mock/Connection.php
  class Connection (line 5) | #[\AllowDynamicProperties]
    method send (line 14) | public function send($data) {
    method close (line 18) | public function close() {

FILE: tests/helpers/Ratchet/Mock/ConnectionDecorator.php
  class ConnectionDecorator (line 5) | class ConnectionDecorator extends AbstractConnectionDecorator {
    method send (line 11) | public function send($data) {
    method close (line 17) | public function close() {

FILE: tests/helpers/Ratchet/Mock/WampComponent.php
  class WampComponent (line 7) | class WampComponent implements WampServerInterface, WsServerInterface {
    method getSubProtocols (line 12) | public function getSubProtocols() {
    method onCall (line 16) | public function onCall(ConnectionInterface $conn, $id, $procURI, array...
    method onSubscribe (line 20) | public function onSubscribe(ConnectionInterface $conn, $topic) {
    method onUnSubscribe (line 24) | public function onUnSubscribe(ConnectionInterface $conn, $topic) {
    method onPublish (line 28) | public function onPublish(ConnectionInterface $conn, $topic, $event, a...
    method onOpen (line 32) | public function onOpen(ConnectionInterface $conn) {
    method onClose (line 36) | public function onClose(ConnectionInterface $conn) {
    method onError (line 40) | public function onError(ConnectionInterface $conn, \Exception $e) {

FILE: tests/helpers/Ratchet/NullComponent.php
  class NullComponent (line 8) | class NullComponent implements MessageComponentInterface, WsServerInterf...
    method onOpen (line 9) | public function onOpen(ConnectionInterface $conn) {}
    method onMessage (line 11) | public function onMessage(ConnectionInterface $conn, $msg) {}
    method onClose (line 13) | public function onClose(ConnectionInterface $conn) {}
    method onError (line 15) | public function onError(ConnectionInterface $conn, \Exception $e) {}
    method onCall (line 17) | public function onCall(ConnectionInterface $conn, $id, $topic, array $...
    method onSubscribe (line 19) | public function onSubscribe(ConnectionInterface $conn, $topic) {}
    method onUnSubscribe (line 21) | public function onUnSubscribe(ConnectionInterface $conn, $topic) {}
    method onPublish (line 23) | public function onPublish(ConnectionInterface $conn, $topic, $event, a...
    method getSubProtocols (line 25) | public function getSubProtocols() {

FILE: tests/helpers/Ratchet/Wamp/Stub/WsWampServerInterface.php
  type WsWampServerInterface (line 6) | interface WsWampServerInterface extends WsServerInterface, WampServerInt...

FILE: tests/helpers/Ratchet/WebSocket/Stub/WsMessageComponentInterface.php
  type WsMessageComponentInterface (line 6) | interface WsMessageComponentInterface extends MessageComponentInterface,...

FILE: tests/unit/AbstractConnectionDecoratorTest.php
  class AbstractConnectionDecoratorTest (line 10) | class AbstractConnectionDecoratorTest extends TestCase {
    method setUpConnection (line 18) | public function setUpConnection() {
    method testGet (line 24) | public function testGet() {
    method testSet (line 34) | public function testSet() {
    method testSetLevel2 (line 43) | public function testSetLevel2() {
    method testIsSetTrue (line 52) | public function testIsSetTrue() {
    method testIsSetFalse (line 62) | public function testIsSetFalse() {
    method testUnset (line 70) | public function testUnset() {
    method testUnsetLevel2 (line 80) | public function testUnsetLevel2() {
    method testGetConnection (line 90) | public function testGetConnection() {
    method testGetConnectionLevel2 (line 100) | public function testGetConnectionLevel2() {
    method testWrapperCanStoreSelfInDecorator (line 110) | public function testWrapperCanStoreSelfInDecorator() {
    method testDecoratorRecursion (line 116) | public function testDecoratorRecursion() {
    method testDecoratorRecursionLevel2 (line 125) | public function testDecoratorRecursionLevel2() {
    method testWarningGettingNothing (line 137) | public function testWarningGettingNothing() {
    method testWarningGettingNothingLevel1 (line 151) | public function testWarningGettingNothingLevel1() {
    method testWarningGettingNothingLevel2 (line 165) | public function testWarningGettingNothingLevel2() {

FILE: tests/unit/AppTest.php
  class AppTest (line 8) | class AppTest extends TestCase {
    method testCtorThrowsForInvalidLoop (line 9) | public function testCtorThrowsForInvalidLoop() {
    method testCtorWithoutArgumentsStartsListeningOnDefaultPorts (line 19) | public function testCtorWithoutArgumentsStartsListeningOnDefaultPorts() {

FILE: tests/unit/Http/HttpRequestParserTest.php
  class HttpRequestParserTest (line 9) | class HttpRequestParserTest extends TestCase {
    method setUpParser (line 15) | public function setUpParser() {
    method headersProvider (line 19) | public function headersProvider() {
    method testIsEom (line 33) | public function testIsEom($expected, $message) {
    method testBufferOverflowResponse (line 37) | public function testBufferOverflowResponse() {
    method testOnMessageThrowsExceptionForEmptyNewlines (line 53) | public function testOnMessageThrowsExceptionForEmptyNewlines() {
    method testReturnTypeIsRequest (line 65) | public function testReturnTypeIsRequest() {

FILE: tests/unit/Http/HttpServerTest.php
  class HttpServerTest (line 8) | class HttpServerTest extends AbstractMessageComponentTestCase {
    method setUpConnection (line 12) | public function setUpConnection() {
    method getConnectionClassString (line 17) | public function getConnectionClassString() {
    method getDecoratorClassString (line 21) | public function getDecoratorClassString() {
    method getComponentClassString (line 25) | public function getComponentClassString() {
    method testOpen (line 29) | public function testOpen() {
    method testOnMessageAfterHeaders (line 37) | public function testOnMessageAfterHeaders() {
    method testBufferOverflow (line 47) | public function testBufferOverflow() {
    method testCloseIfNotEstablished (line 54) | public function testCloseIfNotEstablished() {
    method testBufferHeaders (line 60) | public function testBufferHeaders() {

FILE: tests/unit/Http/OriginCheckTest.php
  class OriginCheckTest (line 8) | class OriginCheckTest extends AbstractMessageComponentTestCase {
    method setUpConnection (line 14) | public function setUpConnection() {
    method doOpen (line 24) | protected function doOpen($conn) {
    method getConnectionClassString (line 28) | public function getConnectionClassString() {
    method getDecoratorClassString (line 32) | public function getDecoratorClassString() {
    method getComponentClassString (line 36) | public function getComponentClassString() {
    method testCloseOnNonMatchingOrigin (line 40) | public function testCloseOnNonMatchingOrigin() {
    method testCloseOnMissingOrigin (line 47) | public function testCloseOnMissingOrigin() {
    method testCloseOnDuplicateOrigin (line 56) | public function testCloseOnDuplicateOrigin() {
    method testOnMessage (line 65) | public function testOnMessage() {

FILE: tests/unit/Http/RouterTest.php
  class RouterTest (line 14) | class RouterTest extends TestCase {
    method setUpConnection (line 24) | public function setUpConnection() {
    method testFourOhFour (line 50) | public function testFourOhFour() {
    method testNullRequest (line 59) | public function testNullRequest() {
    method testControllerIsMessageComponentInterface (line 68) | public function testControllerIsMessageComponentInterface() {
    method testControllerOnOpen (line 78) | public function testControllerOnOpen() {
    method testControllerOnMessageBubbles (line 90) | public function testControllerOnMessageBubbles() {
    method testControllerOnCloseBubbles (line 100) | public function testControllerOnCloseBubbles() {
    method testControllerOnErrorBubbles (line 109) | public function testControllerOnErrorBubbles() {
    method testRouterGeneratesRouteParameters (line 119) | public function testRouterGeneratesRouteParameters() {
    method testQueryParams (line 136) | public function testQueryParams() {
    method testImpatientClientOverflow (line 164) | public function testImpatientClientOverflow() {

FILE: tests/unit/Server/EchoServerTest.php
  class EchoServerTest (line 6) | class EchoServerTest extends TestCase {
    method setUpServer (line 13) | public function setUpServer() {
    method testMessageEchod (line 18) | public function testMessageEchod() {
    method testErrorClosesConnection (line 24) | public function testErrorClosesConnection() {

FILE: tests/unit/Server/FlashPolicyComponentTest.php
  class FlashPolicyTest (line 9) | class FlashPolicyTest extends TestCase {
    method setUpPolicy (line 16) | public function setUpPolicy() {
    method testPolicyRender (line 20) | public function testPolicyRender() {
    method testInvalidPolicyReader (line 28) | public function testInvalidPolicyReader() {
    method testInvalidDomainPolicyReader (line 37) | public function testInvalidDomainPolicyReader() {
    method testSiteControlValidation (line 51) | public function testSiteControlValidation($accept, $permittedCrossDoma...
    method siteControl (line 55) | public static function siteControl() {
    method testDomainValidation (line 73) | public function testDomainValidation($accept, $domain) {
    method URI (line 77) | public static function URI() {
    method testPortValidation (line 102) | public function testPortValidation($accept, $ports) {
    method ports (line 106) | public static function ports() {
    method testAddAllowedAccessOnlyAcceptsValidPorts (line 125) | public function testAddAllowedAccessOnlyAcceptsValidPorts() {
    method testSetSiteControlThrowsException (line 135) | public function testSetSiteControlThrowsException() {
    method testErrorClosesConnection (line 145) | public function testErrorClosesConnection() {
    method testOnMessageSendsString (line 152) | public function testOnMessageSendsString() {
    method testOnOpenExists (line 161) | public function testOnOpenExists() {
    method testOnCloseExists (line 167) | public function testOnCloseExists() {

FILE: tests/unit/Server/IoConnectionTest.php
  class IoConnectionTest (line 9) | class IoConnectionTest extends TestCase {
    method setUpConnection (line 16) | public function setUpConnection() {
    method testCloseBubbles (line 21) | public function testCloseBubbles() {
    method testSendBubbles (line 26) | public function testSendBubbles() {
    method testSendReturnsSelf (line 33) | public function testSendReturnsSelf() {

FILE: tests/unit/Server/IoServerTest.php
  class IoServerTest (line 12) | class IoServerTest extends TestCase {
    method tickLoop (line 21) | protected function tickLoop(LoopInterface $loop) {
    method setUpServer (line 32) | public function setUpServer() {
    method testCtorThrowsForInvalidLoop (line 45) | public function testCtorThrowsForInvalidLoop() {
    method testOnOpen (line 55) | public function testOnOpen() {
    method testHandleOpenWithoutRemoteAddressAssignsEmptyRemoteAddress (line 66) | public function testHandleOpenWithoutRemoteAddressAssignsEmptyRemoteAd...
    method testOnData (line 86) | public function testOnData() {
    method testOnClose (line 115) | public function testOnClose() {
    method testFactory (line 133) | public function testFactory() {
    method testNoLoopProvidedError (line 140) | public function testNoLoopProvidedError() {
    method testOnErrorPassesException (line 151) | public function testOnErrorPassesException() {
    method onErrorCalledWhenExceptionThrown (line 166) | public function onErrorCalledWhenExceptionThrown() {

FILE: tests/unit/Server/IpBlackListComponentTest.php
  class IpBlackListTest (line 9) | class IpBlackListTest extends TestCase {
    method setUpBlocker (line 16) | public function setUpBlocker() {
    method testOnOpen (line 21) | public function testOnOpen() {
    method testBlockDoesNotTriggerOnOpen (line 33) | public function testBlockDoesNotTriggerOnOpen() {
    method testBlockDoesNotTriggerOnClose (line 43) | public function testBlockDoesNotTriggerOnClose() {
    method testOnMessageDecoration (line 53) | public function testOnMessageDecoration() {
    method testOnCloseDecoration (line 62) | public function testOnCloseDecoration() {
    method testBlockClosesConnection (line 70) | public function testBlockClosesConnection() {
    method testAddAndRemoveWithFluentInterfaces (line 79) | public function testAddAndRemoveWithFluentInterfaces() {
    method testDecoratorPassesErrors (line 94) | public function testDecoratorPassesErrors() {
    method addressProvider (line 103) | public function addressProvider() {
    method testFilterAddress (line 115) | public function testFilterAddress($expected, $input) {
    method testUnblockingSilentlyFails (line 119) | public function testUnblockingSilentlyFails() {
    method newConn (line 123) | protected function newConn() {

FILE: tests/unit/Session/Serialize/PhpBinaryHandlerTest.php
  class PhpBinaryHandlerTest (line 9) | class PhpBinaryHandlerTest extends TestCase {
    method setUpHandler (line 15) | public function setUpHandler() {
    method serializedProvider (line 19) | public function serializedProvider() {
    method testUnserialize (line 37) | public function testUnserialize($in, $expected) {

FILE: tests/unit/Session/Serialize/PhpHandlerTest.php
  class PhpHandlerTest (line 9) | class PhpHandlerTest extends TestCase {
    method setUpHandler (line 15) | public function setUpHandler() {
    method serializedProvider (line 19) | public function serializedProvider() {
    method testUnserialize (line 37) | public function testUnserialize($in, $expected) {
    method testSerialize (line 44) | public function testSerialize($serialized, $original) {

FILE: tests/unit/Session/SessionProviderTest.php
  class SessionProviderTest (line 12) | class SessionProviderTest extends AbstractMessageComponentTestCase {
    method setUpProvider (line 16) | public function setUpProvider() {
    method testCtorThrowsForInvalidSerializer (line 27) | public function testCtorThrowsForInvalidSerializer() {
    method tearDownHandler (line 40) | public function tearDownHandler() {
    method getConnectionClassString (line 44) | public function getConnectionClassString() {
    method getDecoratorClassString (line 48) | public function getDecoratorClassString() {
    method getComponentClassString (line 52) | public function getComponentClassString() {
    method classCaseProvider (line 56) | public function classCaseProvider() {
    method testToClassCase (line 66) | public function testToClassCase($in, $out) {
    method testConnectionValueFromPdo (line 78) | public function testConnectionValueFromPdo() {
    method newConn (line 111) | protected function newConn() {
    method testOnMessageDecorator (line 120) | public function testOnMessageDecorator() {
    method testRejectInvalidSeralizers (line 126) | public function testRejectInvalidSeralizers() {
    method doOpen (line 136) | protected function doOpen($conn) {

FILE: tests/unit/Session/Storage/VirtualSessionStoragePDOTest.php
  class VirtualSessionStoragePDOTest (line 9) | class VirtualSessionStoragePDOTest extends TestCase {
    method setUpHandler (line 20) | public function setUpHandler() {
    method tearDownHandler (line 51) | public function tearDownHandler() {
    method testStartWithDSN (line 55) | public function testStartWithDSN() {

FILE: tests/unit/Wamp/ServerProtocolTest.php
  class ServerProtocolTest (line 12) | class ServerProtocolTest extends TestCase {
    method setUpProtocol (line 20) | public function setUpProtocol() {
    method newConn (line 25) | protected function newConn() {
    method invalidMessageProvider (line 29) | public function invalidMessageProvider() {
    method testInvalidMessages (line 42) | public function testInvalidMessages($type) {
    method testWelcomeMessage (line 54) | public function testWelcomeMessage() {
    method testSubscribe (line 68) | public function testSubscribe() {
    method testUnSubscribe (line 80) | public function testUnSubscribe() {
    method callProvider (line 92) | public function callProvider() {
    method testCall (line 108) | public function testCall() {
    method testPublish (line 127) | public function testPublish() {
    method testPublishAndExcludeMe (line 144) | public function testPublishAndExcludeMe() {
    method testPublishAndEligible (line 153) | public function testPublishAndEligible() {
    method eventProvider (line 166) | public function eventProvider() {
    method testEvent (line 176) | public function testEvent($topic, $payload) {
    method testOnClosePropagation (line 185) | public function testOnClosePropagation() {
    method testOnErrorPropagation (line 200) | public function testOnErrorPropagation() {
    method testPrefix (line 218) | public function testPrefix() {
    method testMessageMustBeJson (line 232) | public function testMessageMustBeJson() {
    method testGetSubProtocolsReturnsArray (line 245) | public function testGetSubProtocolsReturnsArray() {
    method testGetSubProtocolsGetFromApp (line 249) | public function testGetSubProtocolsGetFromApp() {
    method testWampOnMessageApp (line 255) | public function testWampOnMessageApp() {
    method badFormatProvider (line 262) | public function badFormatProvider() {
    method testValidJsonButInvalidProtocol (line 273) | public function testValidJsonButInvalidProtocol($message) {
    method testBadClientInputFromNonStringTopic (line 285) | public function testBadClientInputFromNonStringTopic() {
    method testBadPrefixWithNonStringTopic (line 298) | public function testBadPrefixWithNonStringTopic() {
    method testBadPublishWithNonStringTopic (line 311) | public function testBadPublishWithNonStringTopic() {

FILE: tests/unit/Wamp/TopicManagerTest.php
  class TopicManagerTest (line 9) | class TopicManagerTest extends TestCase {
    method setUpManager (line 25) | public function setUpManager() {
    method testGetTopicReturnsTopicObject (line 34) | public function testGetTopicReturnsTopicObject() {
    method testGetTopicCreatesTopicWithSameName (line 44) | public function testGetTopicCreatesTopicWithSameName() {
    method testGetTopicReturnsSameObject (line 56) | public function testGetTopicReturnsSameObject() {
    method testOnOpen (line 67) | public function testOnOpen() {
    method testOnCall (line 72) | public function testOnCall() {
    method testOnSubscribeCreatesTopicObject (line 85) | public function testOnSubscribeCreatesTopicObject() {
    method testTopicIsInConnectionOnSubscribe (line 93) | public function testTopicIsInConnectionOnSubscribe() {
    method testDoubleSubscriptionFiresOnce (line 107) | public function testDoubleSubscriptionFiresOnce() {
    method testUnsubscribeEvent (line 114) | public function testUnsubscribeEvent() {
    method testUnsubscribeFiresOnce (line 124) | public function testUnsubscribeFiresOnce() {
    method testUnsubscribeRemovesTopicFromConnection (line 133) | public function testUnsubscribeRemovesTopicFromConnection() {
    method testOnPublishBubbles (line 148) | public function testOnPublishBubbles() {
    method testOnCloseBubbles (line 162) | public function testOnCloseBubbles() {
    method topicProvider (line 167) | protected function topicProvider($name) {
    method testConnIsRemovedFromTopicOnClose (line 180) | public function testConnIsRemovedFromTopicOnClose() {
    method topicConnExpectationProvider (line 192) | public static function topicConnExpectationProvider() {
    method testTopicRetentionFromLeavingConnections (line 202) | public function testTopicRetentionFromLeavingConnections($methodCall, ...
    method testOnErrorBubbles (line 212) | public function testOnErrorBubbles() {
    method testGetSubProtocolsReturnsArray (line 219) | public function testGetSubProtocolsReturnsArray() {
    method testGetSubProtocolsBubbles (line 229) | public function testGetSubProtocolsBubbles() {

FILE: tests/unit/Wamp/TopicTest.php
  class TopicTest (line 9) | class TopicTest extends TestCase {
    method testGetId (line 10) | public function testGetId() {
    method testAddAndCount (line 17) | public function testAddAndCount() {
    method testRemove (line 27) | public function testRemove() {
    method testBroadcast (line 40) | public function testBroadcast() {
    method testBroadcastWithExclude (line 63) | public function testBroadcastWithExclude() {
    method testBroadcastWithEligible (line 90) | public function testBroadcastWithEligible() {
    method testIterator (line 117) | public function testIterator() {
    method testToString (line 132) | public function testToString() {
    method testDoesHave (line 139) | public function testDoesHave() {
    method testDoesNotHave (line 147) | public function testDoesNotHave() {
    method testDoesNotHaveAfterRemove (line 154) | public function testDoesNotHaveAfterRemove() {
    method newConn (line 163) | protected function newConn() {

FILE: tests/unit/Wamp/WampConnectionTest.php
  class WampConnectionTest (line 9) | class WampConnectionTest extends TestCase {
    method setUpConnection (line 16) | public function setUpConnection() {
    method testCallResult (line 21) | public function testCallResult() {
    method testCallError (line 30) | public function testCallError() {
    method testCallErrorWithTopic (line 39) | public function testCallErrorWithTopic() {
    method testDetailedCallError (line 48) | public function testDetailedCallError() {
    method testPrefix (line 59) | public function testPrefix() {
    method testGetUriWhenNoCurieGiven (line 68) | public function testGetUriWhenNoCurieGiven() {
    method testClose (line 74) | public function testClose() {

FILE: tests/unit/Wamp/WampServerTest.php
  class WampServerTest (line 8) | class WampServerTest extends AbstractMessageComponentTestCase {
    method getConnectionClassString (line 9) | public function getConnectionClassString() {
    method getDecoratorClassString (line 13) | public function getDecoratorClassString() {
    method getComponentClassString (line 17) | public function getComponentClassString() {
    method testOnMessageToEvent (line 21) | public function testOnMessageToEvent() {
    method testGetSubProtocols (line 35) | public function testGetSubProtocols() {
    method testConnectionClosesOnInvalidJson (line 46) | public function testConnectionClosesOnInvalidJson() {
    method testConnectionClosesOnProtocolError (line 51) | public function testConnectionClosesOnProtocolError() {
Condensed preview — 87 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (206K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 49,
    "preview": "github: \n    - ReactPHP\n    - clue \n    - cboden\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bugreport.yml",
    "chars": 697,
    "preview": "name: \"🐛 Bug Report\"\ndescription: \"Found a bug in our project? Create a report to help us improve.\"\nbody:\n  - type: mark"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 436,
    "preview": "blank_issues_enabled: true\ncontact_links:\n  - name: \"Ratchet Discussions\"\n    url: https://github.com/ratchetphp/Ratchet"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1132,
    "preview": "name: \"CI\"\n\non:\n  push:\n  pull_request:\n\njobs:\n  phpunit:\n    name: \"PHPUnit\"\n    runs-on: \"ubuntu-24.04\"\n\n    strategy:"
  },
  {
    "path": ".gitignore",
    "chars": 52,
    "preview": "phpunit.xml\r\nreports\r\nsandbox\r\nvendor\r\ncomposer.lock"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 5725,
    "preview": "CHANGELOG\n=========\n\n### Legend\n\n* \"BC\": Backwards compatibility break (from public component APIs)\n* \"BF\": Bug fix\n\n---"
  },
  {
    "path": "LICENSE",
    "chars": 1055,
    "preview": "Copyright (c) 2011 Chris Boden\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this sof"
  },
  {
    "path": "Makefile",
    "chars": 1401,
    "preview": "# This file is intended to ease the author's development and testing process\n# Users do not need to use `make`; Ratchet "
  },
  {
    "path": "README.md",
    "chars": 3935,
    "preview": "# Ratchet\n\n[![CI status](https://github.com/ratchetphp/Ratchet/actions/workflows/ci.yml/badge.svg)](https://github.com/r"
  },
  {
    "path": "SECURITY.md",
    "chars": 191,
    "preview": "# Security Policy\n\n## Reporting a Vulnerability\n\nPlease report security issues to:\n    \n* Chris Boden [cboden@gmail.com]"
  },
  {
    "path": "composer.json",
    "chars": 1156,
    "preview": "{\n    \"name\": \"cboden/ratchet\"\n  , \"type\": \"library\"\n  , \"description\": \"PHP WebSocket library\"\n  , \"keywords\": [\"WebSoc"
  },
  {
    "path": "phpunit.xml.dist",
    "chars": 740,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- PHPUnit configuration file with new format for PHPUnit 9.6+ -->\n<phpunit xm"
  },
  {
    "path": "phpunit.xml.legacy",
    "chars": 665,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- PHPUnit configuration file with old format for legacy PHPUnit -->\n<phpunit "
  },
  {
    "path": "src/Ratchet/AbstractConnectionDecorator.php",
    "chars": 1182,
    "preview": "<?php\nnamespace Ratchet;\n\n/**\n * Wraps ConnectionInterface objects via the decorator pattern but allows\n * parameters to"
  },
  {
    "path": "src/Ratchet/App.php",
    "chars": 6337,
    "preview": "<?php\nnamespace Ratchet;\nuse React\\EventLoop\\Factory as LegacyLoopFactory;\nuse React\\EventLoop\\Loop;\nuse React\\EventLoop"
  },
  {
    "path": "src/Ratchet/ComponentInterface.php",
    "chars": 1238,
    "preview": "<?php\nnamespace Ratchet;\n\n/**\n * This is the interface to build a Ratchet application with.\n * It implements the decorat"
  },
  {
    "path": "src/Ratchet/ConnectionInterface.php",
    "chars": 879,
    "preview": "<?php\nnamespace Ratchet;\n\n/**\n * The version of Ratchet being used\n * @var string\n */\nconst VERSION = 'Ratchet/0.4.4';\n\n"
  },
  {
    "path": "src/Ratchet/Http/CloseResponseTrait.php",
    "chars": 669,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\ConnectionInterface;\nuse GuzzleHttp\\Psr7\\Message;\nuse GuzzleHttp\\Psr7\\Response"
  },
  {
    "path": "src/Ratchet/Http/HttpRequestParser.php",
    "chars": 1830,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\MessageInterface;\nuse Ratchet\\ConnectionInterface;\nuse GuzzleHttp\\Psr7\\Message"
  },
  {
    "path": "src/Ratchet/Http/HttpServer.php",
    "chars": 1945,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\ConnectionInterface;\n\nclass HttpServer "
  },
  {
    "path": "src/Ratchet/Http/HttpServerInterface.php",
    "chars": 701,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\ConnectionInterface;\nuse Psr\\Http\\Messa"
  },
  {
    "path": "src/Ratchet/Http/NoOpHttpServerController.php",
    "chars": 601,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\ConnectionInterface;\nuse Psr\\Http\\Message\\RequestInterface;\n\nclass NoOpHttpSer"
  },
  {
    "path": "src/Ratchet/Http/OriginCheck.php",
    "chars": 1991,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\ConnectionInterface;\nuse Ratchet\\MessageComponentInterface;\nuse Psr\\Http\\Messa"
  },
  {
    "path": "src/Ratchet/Http/Router.php",
    "chars": 3152,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\ConnectionInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Symfony\\Compon"
  },
  {
    "path": "src/Ratchet/MessageComponentInterface.php",
    "chars": 111,
    "preview": "<?php\nnamespace Ratchet;\n\ninterface MessageComponentInterface extends ComponentInterface, MessageInterface {\n}\n"
  },
  {
    "path": "src/Ratchet/MessageInterface.php",
    "chars": 402,
    "preview": "<?php\nnamespace Ratchet;\n\ninterface MessageInterface {\n    /**\n     * Triggered when a client sends data through the soc"
  },
  {
    "path": "src/Ratchet/Server/EchoServer.php",
    "chars": 592,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\ConnectionInterface;\n\n/**\n * A simple"
  },
  {
    "path": "src/Ratchet/Server/FlashPolicy.php",
    "chars": 6288,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\ConnectionInterface;\n\n/**\n * An app t"
  },
  {
    "path": "src/Ratchet/Server/IoConnection.php",
    "chars": 716,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse Ratchet\\ConnectionInterface;\nuse React\\Socket\\ConnectionInterface as SocketConnectio"
  },
  {
    "path": "src/Ratchet/Server/IoServer.php",
    "chars": 5457,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse Ratchet\\MessageComponentInterface;\nuse React\\EventLoop\\Factory as LegacyLoopFactory;"
  },
  {
    "path": "src/Ratchet/Server/IpBlackList.php",
    "chars": 2762,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\ConnectionInterface;\n\nclass IpBlackLi"
  },
  {
    "path": "src/Ratchet/Session/Serialize/HandlerInterface.php",
    "chars": 261,
    "preview": "<?php\nnamespace Ratchet\\Session\\Serialize;\n\ninterface HandlerInterface {\n    /**\n     * @param array\n     * @return stri"
  },
  {
    "path": "src/Ratchet/Session/Serialize/PhpBinaryHandler.php",
    "chars": 1121,
    "preview": "<?php\nnamespace Ratchet\\Session\\Serialize;\n\nclass PhpBinaryHandler implements HandlerInterface {\n    /**\n     * {@inheri"
  },
  {
    "path": "src/Ratchet/Session/Serialize/PhpHandler.php",
    "chars": 1676,
    "preview": "<?php\nnamespace Ratchet\\Session\\Serialize;\n\nclass PhpHandler implements HandlerInterface {\n    /**\n     * Simply reverse"
  },
  {
    "path": "src/Ratchet/Session/SessionProvider.php",
    "chars": 8624,
    "preview": "<?php\nnamespace Ratchet\\Session;\nuse Ratchet\\ConnectionInterface;\nuse Ratchet\\Http\\HttpServerInterface;\nuse Psr\\Http\\Mes"
  },
  {
    "path": "src/Ratchet/Session/Storage/Proxy/VirtualProxy.php",
    "chars": 1844,
    "preview": "<?php\nnamespace Ratchet\\Session\\Storage\\Proxy;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\SessionHandler"
  },
  {
    "path": "src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony6.php",
    "chars": 1301,
    "preview": "<?php\nnamespace Ratchet\\Session\\Storage\\Proxy;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\SessionHandler"
  },
  {
    "path": "src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony7.php",
    "chars": 1337,
    "preview": "<?php\nnamespace Ratchet\\Session\\Storage\\Proxy;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\SessionHandler"
  },
  {
    "path": "src/Ratchet/Session/Storage/VirtualSessionStorage.php",
    "chars": 3779,
    "preview": "<?php\nnamespace Ratchet\\Session\\Storage;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage;\nuse "
  },
  {
    "path": "src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php",
    "chars": 3246,
    "preview": "<?php\nnamespace Ratchet\\Session\\Storage;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage;\nuse "
  },
  {
    "path": "src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony7.php",
    "chars": 3370,
    "preview": "<?php\nnamespace Ratchet\\Session\\Storage;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage;\nuse "
  },
  {
    "path": "src/Ratchet/Wamp/Exception.php",
    "chars": 70,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\n\nclass Exception extends \\Exception {\n}\n"
  },
  {
    "path": "src/Ratchet/Wamp/JsonException.php",
    "chars": 904,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\n\nclass JsonException extends Exception {\n    public function __construct() {\n        $code"
  },
  {
    "path": "src/Ratchet/Wamp/ServerProtocol.php",
    "chars": 4765,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\WebSocket\\WsServerInterface;\nuse Ratche"
  },
  {
    "path": "src/Ratchet/Wamp/Topic.php",
    "chars": 2436,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse Ratchet\\ConnectionInterface;\n\n/**\n * A topic/channel containing connections that have "
  },
  {
    "path": "src/Ratchet/Wamp/TopicManager.php",
    "chars": 3096,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse Ratchet\\ConnectionInterface;\nuse Ratchet\\WebSocket\\WsServerInterface;\n\nclass TopicMana"
  },
  {
    "path": "src/Ratchet/Wamp/WampConnection.php",
    "chars": 3504,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse Ratchet\\ConnectionInterface;\nuse Ratchet\\AbstractConnectionDecorator;\nuse Ratchet\\Wamp"
  },
  {
    "path": "src/Ratchet/Wamp/WampServer.php",
    "chars": 1858,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\WebSocket\\WsServerInterface;\nuse Ratche"
  },
  {
    "path": "src/Ratchet/Wamp/WampServerInterface.php",
    "chars": 1970,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse Ratchet\\ComponentInterface;\nuse Ratchet\\ConnectionInterface;\n\n/**\n * An extension of R"
  },
  {
    "path": "src/Ratchet/WebSocket/ConnContext.php",
    "chars": 430,
    "preview": "<?php\nnamespace Ratchet\\WebSocket;\nuse Ratchet\\RFC6455\\Messaging\\MessageBuffer;\n\nclass ConnContext {\n    /**\n     * @var"
  },
  {
    "path": "src/Ratchet/WebSocket/MessageCallableInterface.php",
    "chars": 237,
    "preview": "<?php\nnamespace Ratchet\\WebSocket;\nuse Ratchet\\ConnectionInterface;\nuse Ratchet\\RFC6455\\Messaging\\MessageInterface;\n\nint"
  },
  {
    "path": "src/Ratchet/WebSocket/MessageComponentInterface.php",
    "chars": 161,
    "preview": "<?php\nnamespace Ratchet\\WebSocket;\nuse Ratchet\\ComponentInterface;\n\ninterface MessageComponentInterface extends Componen"
  },
  {
    "path": "src/Ratchet/WebSocket/WsConnection.php",
    "chars": 1061,
    "preview": "<?php\nnamespace Ratchet\\WebSocket;\nuse Ratchet\\AbstractConnectionDecorator;\nuse Ratchet\\RFC6455\\Messaging\\DataInterface;"
  },
  {
    "path": "src/Ratchet/WebSocket/WsServer.php",
    "chars": 7935,
    "preview": "<?php\nnamespace Ratchet\\WebSocket;\nuse Ratchet\\ComponentInterface;\nuse Ratchet\\ConnectionInterface;\nuse Ratchet\\MessageC"
  },
  {
    "path": "src/Ratchet/WebSocket/WsServerInterface.php",
    "chars": 398,
    "preview": "<?php\nnamespace Ratchet\\WebSocket;\n\n/**\n * WebSocket Server Interface\n */\ninterface WsServerInterface {\n    /**\n     * I"
  },
  {
    "path": "tests/autobahn/bin/fuzzingserver.php",
    "chars": 1416,
    "preview": "<?php\nuse Ratchet\\ConnectionInterface;\n\n    require dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';\n\nclass "
  },
  {
    "path": "tests/autobahn/fuzzingclient-all.json",
    "chars": 565,
    "preview": "{\n    \"options\": {\"failByDrop\": false}\n  , \"outdir\": \"reports/ab\"\n\n  , \"servers\": [\n        {\"agent\": \"Ratchet/0.4 libev"
  },
  {
    "path": "tests/autobahn/fuzzingclient-profile.json",
    "chars": 326,
    "preview": "{\n    \"options\": {\"failByDrop\": false}\n  , \"outdir\": \"reports/profile\"\n\n  , \"servers\": [\n        {\"agent\": \"Ratchet\", \"u"
  },
  {
    "path": "tests/autobahn/fuzzingclient-quick.json",
    "chars": 253,
    "preview": "{\n    \"options\": {\"failByDrop\": false}\n  , \"outdir\": \"reports/rfc\"\n\n  , \"servers\": [\n       {\"agent\": \"Ratchet\", \"url\": "
  },
  {
    "path": "tests/bootstrap.php",
    "chars": 131,
    "preview": "<?php\n\n    $loader = require __DIR__ . '/../vendor/autoload.php';\n    $loader->addPsr4('Ratchet\\\\', __DIR__ . '/helpers/"
  },
  {
    "path": "tests/helpers/Ratchet/AbstractMessageComponentTestCase.php",
    "chars": 1845,
    "preview": "<?php\nnamespace Ratchet;\n\nuse PHPUnit\\Framework\\TestCase;\n\nabstract class AbstractMessageComponentTestCase extends TestC"
  },
  {
    "path": "tests/helpers/Ratchet/Mock/Connection.php",
    "chars": 428,
    "preview": "<?php\nnamespace Ratchet\\Mock;\nuse Ratchet\\ConnectionInterface;\n\n#[\\AllowDynamicProperties]\nclass Connection implements C"
  },
  {
    "path": "tests/helpers/Ratchet/Mock/ConnectionDecorator.php",
    "chars": 469,
    "preview": "<?php\nnamespace Ratchet\\Mock;\nuse Ratchet\\AbstractConnectionDecorator;\n\nclass ConnectionDecorator extends AbstractConnec"
  },
  {
    "path": "tests/helpers/Ratchet/Mock/WampComponent.php",
    "chars": 1298,
    "preview": "<?php\nnamespace Ratchet\\Mock;\nuse Ratchet\\Wamp\\WampServerInterface;\nuse Ratchet\\WebSocket\\WsServerInterface;\nuse Ratchet"
  },
  {
    "path": "tests/helpers/Ratchet/NullComponent.php",
    "chars": 966,
    "preview": "<?php\nnamespace Ratchet;\nuse Ratchet\\ConnectionInterface;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\WebSocket\\W"
  },
  {
    "path": "tests/helpers/Ratchet/Wamp/Stub/WsWampServerInterface.php",
    "chars": 198,
    "preview": "<?php\nnamespace Ratchet\\Wamp\\Stub;\nuse Ratchet\\WebSocket\\WsServerInterface;\nuse Ratchet\\Wamp\\WampServerInterface;\n\ninter"
  },
  {
    "path": "tests/helpers/Ratchet/WebSocket/Stub/WsMessageComponentInterface.php",
    "chars": 216,
    "preview": "<?php\nnamespace Ratchet\\WebSocket\\Stub;\nuse Ratchet\\MessageComponentInterface;\nuse Ratchet\\WebSocket\\WsServerInterface;\n"
  },
  {
    "path": "tests/unit/AbstractConnectionDecoratorTest.php",
    "chars": 4803,
    "preview": "<?php\nnamespace Ratchet;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Mock\\ConnectionDecorator;\n\n/**\n * @covers Ratchet\\A"
  },
  {
    "path": "tests/unit/AppTest.php",
    "chars": 1445,
    "preview": "<?php\nnamespace Ratchet;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\App;\nuse Ratchet\\Server\\IoServer;\n\nclass AppTest e"
  },
  {
    "path": "tests/unit/Http/HttpRequestParserTest.php",
    "chars": 2275,
    "preview": "<?php\nnamespace Ratchet\\Http;\n\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * @covers Ratchet\\Http\\HttpRequestParser\n */\nclass "
  },
  {
    "path": "tests/unit/Http/HttpServerTest.php",
    "chars": 2178,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\AbstractMessageComponentTestCase;\n\n/**\n * @covers Ratchet\\Http\\HttpServer\n */\n"
  },
  {
    "path": "tests/unit/Http/OriginCheckTest.php",
    "chars": 2116,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse Ratchet\\AbstractMessageComponentTestCase;\n\n/**\n * @covers Ratchet\\Http\\OriginCheck\n */"
  },
  {
    "path": "tests/unit/Http/RouterTest.php",
    "chars": 7957,
    "preview": "<?php\nnamespace Ratchet\\Http;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\WebSocket\\WsServerInterface;\nuse Symfony\\Compo"
  },
  {
    "path": "tests/unit/Server/EchoServerTest.php",
    "chars": 869,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Server\\EchoServer;\n\nclass EchoServerTest ext"
  },
  {
    "path": "tests/unit/Server/FlashPolicyComponentTest.php",
    "chars": 5543,
    "preview": "<?php\nnamespace Ratchet\\Application\\Server;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Server\\FlashPolicy;\n\n/**\n * @cov"
  },
  {
    "path": "tests/unit/Server/IoConnectionTest.php",
    "chars": 937,
    "preview": "<?php\nnamespace Ratchet\\Application\\Server;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Server\\IoConnection;\n\n/**\n * @co"
  },
  {
    "path": "tests/unit/Server/IoServerTest.php",
    "chars": 6267,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse PHPUnit\\Framework\\TestCase;\nuse React\\EventLoop\\StreamSelectLoop;\nuse React\\EventLoo"
  },
  {
    "path": "tests/unit/Server/IpBlackListComponentTest.php",
    "chars": 3596,
    "preview": "<?php\nnamespace Ratchet\\Server;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Server\\IpBlackList;\n\n/**\n * @covers Ratchet\\"
  },
  {
    "path": "tests/unit/Session/Serialize/PhpBinaryHandlerTest.php",
    "chars": 1069,
    "preview": "<?php\nnamespace Ratchet\\Session\\Serialize;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Session\\Serialize\\PhpBinaryHandle"
  },
  {
    "path": "tests/unit/Session/Serialize/PhpHandlerTest.php",
    "chars": 1224,
    "preview": "<?php\nnamespace Ratchet\\Session\\Serialize;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Session\\Serialize\\PhpHandler;\n\n/*"
  },
  {
    "path": "tests/unit/Session/SessionProviderTest.php",
    "chars": 5757,
    "preview": "<?php\nnamespace Ratchet\\Session;\nuse Ratchet\\AbstractMessageComponentTestCase;\nuse Symfony\\Component\\HttpFoundation\\Sess"
  },
  {
    "path": "tests/unit/Session/Storage/VirtualSessionStoragePDOTest.php",
    "chars": 1855,
    "preview": "<?php\nnamespace Ratchet\\Session\\Storage;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Session\\Serialize\\PhpHandler;\nuse S"
  },
  {
    "path": "tests/unit/Wamp/ServerProtocolTest.php",
    "chars": 9812,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse PHPUnit\\Framework\\TestCase;\nuse Ratchet\\Mock\\Connection;\nuse Ratchet\\Mock\\WampComponen"
  },
  {
    "path": "tests/unit/Wamp/TopicManagerTest.php",
    "chars": 7566,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\n\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * @covers Ratchet\\Wamp\\TopicManager\n */\nclass Topic"
  },
  {
    "path": "tests/unit/Wamp/TopicTest.php",
    "chars": 5628,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\n\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * @covers Ratchet\\Wamp\\Topic\n */\nclass TopicTest ex"
  },
  {
    "path": "tests/unit/Wamp/WampConnectionTest.php",
    "chars": 2387,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\n\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * @covers Ratchet\\Wamp\\WampConnection\n */\nclass Wam"
  },
  {
    "path": "tests/unit/Wamp/WampServerTest.php",
    "chars": 1736,
    "preview": "<?php\nnamespace Ratchet\\Wamp;\nuse Ratchet\\AbstractMessageComponentTestCase;\n\n/**\n * @covers Ratchet\\Wamp\\WampServer\n */\n"
  }
]

About this extraction

This page contains the full source code of the ratchetphp/Ratchet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 87 files (188.1 KB), approximately 50.0k tokens, and a symbol index with 479 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!