init
This commit is contained in:
2
vendor/react/socket/.gitignore
vendored
Executable file
2
vendor/react/socket/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
composer.lock
|
||||
vendor
|
||||
48
vendor/react/socket/.travis.yml
vendored
Executable file
48
vendor/react/socket/.travis.yml
vendored
Executable file
@@ -0,0 +1,48 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
# - 5.3 # requires old distro, see below
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
# - 7.0 # Mac OS X, ignore errors, see below
|
||||
- hhvm # ignore errors, see below
|
||||
|
||||
# lock distro so new future defaults will not break the build
|
||||
dist: trusty
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.3
|
||||
dist: precise
|
||||
- os: osx
|
||||
language: generic
|
||||
php: 7.0 # just to look right on travis
|
||||
env:
|
||||
- PACKAGE: php70
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
- os: osx
|
||||
|
||||
sudo: false
|
||||
|
||||
install:
|
||||
# OSX install inspired by https://github.com/kiler129/TravisCI-OSX-PHP
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
brew tap homebrew/homebrew-php
|
||||
echo "Installing PHP ..."
|
||||
brew install "${PACKAGE}"
|
||||
brew install "${PACKAGE}"-xdebug
|
||||
brew link "${PACKAGE}"
|
||||
echo "Installing composer ..."
|
||||
curl -s http://getcomposer.org/installer | php
|
||||
mv composer.phar /usr/local/bin/composer
|
||||
fi
|
||||
- composer install --no-interaction
|
||||
|
||||
script:
|
||||
- ./vendor/bin/phpunit --coverage-text
|
||||
465
vendor/react/socket/CHANGELOG.md
vendored
Executable file
465
vendor/react/socket/CHANGELOG.md
vendored
Executable file
@@ -0,0 +1,465 @@
|
||||
# Changelog
|
||||
|
||||
## 0.8.12 (2018-06-11)
|
||||
|
||||
* Feature: Improve memory consumption for failed and cancelled connection attempts.
|
||||
(#161 by @clue)
|
||||
|
||||
* Improve test suite to fix Travis config to test against legacy PHP 5.3 again.
|
||||
(#162 by @clue)
|
||||
|
||||
## 0.8.11 (2018-04-24)
|
||||
|
||||
* Feature: Improve memory consumption for cancelled connection attempts and
|
||||
simplify skipping DNS lookup when connecting to IP addresses.
|
||||
(#159 and #160 by @clue)
|
||||
|
||||
## 0.8.10 (2018-02-28)
|
||||
|
||||
* Feature: Update DNS dependency to support loading system default DNS
|
||||
nameserver config on all supported platforms
|
||||
(`/etc/resolv.conf` on Unix/Linux/Mac/Docker/WSL and WMIC on Windows)
|
||||
(#152 by @clue)
|
||||
|
||||
This means that connecting to hosts that are managed by a local DNS server,
|
||||
such as a corporate DNS server or when using Docker containers, will now
|
||||
work as expected across all platforms with no changes required:
|
||||
|
||||
```php
|
||||
$connector = new Connector($loop);
|
||||
$connector->connect('intranet.example:80')->then(function ($connection) {
|
||||
// …
|
||||
});
|
||||
```
|
||||
|
||||
## 0.8.9 (2018-01-18)
|
||||
|
||||
* Feature: Support explicitly choosing TLS version to negotiate with remote side
|
||||
by respecting `crypto_method` context parameter for all classes.
|
||||
(#149 by @clue)
|
||||
|
||||
By default, all connector and server classes support TLSv1.0+ and exclude
|
||||
support for legacy SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly
|
||||
choose the TLS version you want to negotiate with the remote side:
|
||||
|
||||
```php
|
||||
// new: now supports 'crypto_method` context parameter for all classes
|
||||
$connector = new Connector($loop, array(
|
||||
'tls' => array(
|
||||
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
|
||||
)
|
||||
));
|
||||
```
|
||||
|
||||
* Minor internal clean up to unify class imports
|
||||
(#148 by @clue)
|
||||
|
||||
## 0.8.8 (2018-01-06)
|
||||
|
||||
* Improve test suite by adding test group to skip integration tests relying on
|
||||
internet connection and fix minor documentation typo.
|
||||
(#146 by @clue and #145 by @cn007b)
|
||||
|
||||
## 0.8.7 (2017-12-24)
|
||||
|
||||
* Fix: Fix closing socket resource before removing from loop
|
||||
(#141 by @clue)
|
||||
|
||||
This fixes the root cause of an uncaught `Exception` that only manifested
|
||||
itself after the recent Stream v0.7.4 component update and only if you're
|
||||
using `ext-event` (`ExtEventLoop`).
|
||||
|
||||
* Improve test suite by testing against PHP 7.2
|
||||
(#140 by @carusogabriel)
|
||||
|
||||
## 0.8.6 (2017-11-18)
|
||||
|
||||
* Feature: Add Unix domain socket (UDS) support to `Server` with `unix://` URI scheme
|
||||
and add advanced `UnixServer` class.
|
||||
(#120 by @andig)
|
||||
|
||||
```php
|
||||
// new: Server now supports "unix://" scheme
|
||||
$server = new Server('unix:///tmp/server.sock', $loop);
|
||||
|
||||
// new: advanced usage
|
||||
$server = new UnixServer('/tmp/server.sock', $loop);
|
||||
```
|
||||
|
||||
* Restructure examples to ease getting started
|
||||
(#136 by @clue)
|
||||
|
||||
* Improve test suite by adding forward compatibility with PHPUnit 6 and
|
||||
ignore Mac OS X test failures for now until Travis tests work again
|
||||
(#133 by @gabriel-caruso and #134 by @clue)
|
||||
|
||||
## 0.8.5 (2017-10-23)
|
||||
|
||||
* Fix: Work around PHP bug with Unix domain socket (UDS) paths for Mac OS X
|
||||
(#123 by @andig)
|
||||
|
||||
* Fix: Fix `SecureServer` to return `null` URI if server socket is already closed
|
||||
(#129 by @clue)
|
||||
|
||||
* Improve test suite by adding forward compatibility with PHPUnit v5 and
|
||||
forward compatibility with upcoming EventLoop releases in tests and
|
||||
test Mac OS X on Travis
|
||||
(#122 by @andig and #125, #127 and #130 by @clue)
|
||||
|
||||
* Readme improvements
|
||||
(#118 by @jsor)
|
||||
|
||||
## 0.8.4 (2017-09-16)
|
||||
|
||||
* Feature: Add `FixedUriConnector` decorator to use fixed, preconfigured URI instead
|
||||
(#117 by @clue)
|
||||
|
||||
This can be useful for consumers that do not support certain URIs, such as
|
||||
when you want to explicitly connect to a Unix domain socket (UDS) path
|
||||
instead of connecting to a default address assumed by an higher-level API:
|
||||
|
||||
```php
|
||||
$connector = new FixedUriConnector(
|
||||
'unix:///var/run/docker.sock',
|
||||
new UnixConnector($loop)
|
||||
);
|
||||
|
||||
// destination will be ignored, actually connects to Unix domain socket
|
||||
$promise = $connector->connect('localhost:80');
|
||||
```
|
||||
|
||||
## 0.8.3 (2017-09-08)
|
||||
|
||||
* Feature: Reduce memory consumption for failed connections
|
||||
(#113 by @valga)
|
||||
|
||||
* Fix: Work around write chunk size for TLS streams for PHP < 7.1.14
|
||||
(#114 by @clue)
|
||||
|
||||
## 0.8.2 (2017-08-25)
|
||||
|
||||
* Feature: Update DNS dependency to support hosts file on all platforms
|
||||
(#112 by @clue)
|
||||
|
||||
This means that connecting to hosts such as `localhost` will now work as
|
||||
expected across all platforms with no changes required:
|
||||
|
||||
```php
|
||||
$connector = new Connector($loop);
|
||||
$connector->connect('localhost:8080')->then(function ($connection) {
|
||||
// …
|
||||
});
|
||||
```
|
||||
|
||||
## 0.8.1 (2017-08-15)
|
||||
|
||||
* Feature: Forward compatibility with upcoming EventLoop v1.0 and v0.5 and
|
||||
target evenement 3.0 a long side 2.0 and 1.0
|
||||
(#104 by @clue and #111 by @WyriHaximus)
|
||||
|
||||
* Improve test suite by locking Travis distro so new defaults will not break the build and
|
||||
fix HHVM build for now again and ignore future HHVM build errors
|
||||
(#109 and #110 by @clue)
|
||||
|
||||
* Minor documentation fixes
|
||||
(#103 by @christiaan and #108 by @hansott)
|
||||
|
||||
## 0.8.0 (2017-05-09)
|
||||
|
||||
* Feature: New `Server` class now acts as a facade for existing server classes
|
||||
and renamed old `Server` to `TcpServer` for advanced usage.
|
||||
(#96 and #97 by @clue)
|
||||
|
||||
The `Server` class is now the main class in this package that implements the
|
||||
`ServerInterface` and allows you to accept incoming streaming connections,
|
||||
such as plaintext TCP/IP or secure TLS connection streams.
|
||||
|
||||
> This is not a BC break and consumer code does not have to be updated.
|
||||
|
||||
* Feature / BC break: All addresses are now URIs that include the URI scheme
|
||||
(#98 by @clue)
|
||||
|
||||
```diff
|
||||
- $parts = parse_url('tcp://' . $conn->getRemoteAddress());
|
||||
+ $parts = parse_url($conn->getRemoteAddress());
|
||||
```
|
||||
|
||||
* Fix: Fix `unix://` addresses for Unix domain socket (UDS) paths
|
||||
(#100 by @clue)
|
||||
|
||||
* Feature: Forward compatibility with Stream v1.0 and v0.7
|
||||
(#99 by @clue)
|
||||
|
||||
## 0.7.2 (2017-04-24)
|
||||
|
||||
* Fix: Work around latest PHP 7.0.18 and 7.1.4 no longer accepting full URIs
|
||||
(#94 by @clue)
|
||||
|
||||
## 0.7.1 (2017-04-10)
|
||||
|
||||
* Fix: Ignore HHVM errors when closing connection that is already closing
|
||||
(#91 by @clue)
|
||||
|
||||
## 0.7.0 (2017-04-10)
|
||||
|
||||
* Feature: Merge SocketClient component into this component
|
||||
(#87 by @clue)
|
||||
|
||||
This means that this package now provides async, streaming plaintext TCP/IP
|
||||
and secure TLS socket server and client connections for ReactPHP.
|
||||
|
||||
```
|
||||
$connector = new React\Socket\Connector($loop);
|
||||
$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
|
||||
$connection->write('…');
|
||||
});
|
||||
```
|
||||
|
||||
Accordingly, the `ConnectionInterface` is now used to represent both incoming
|
||||
server side connections as well as outgoing client side connections.
|
||||
|
||||
If you've previously used the SocketClient component to establish outgoing
|
||||
client connections, upgrading should take no longer than a few minutes.
|
||||
All classes have been merged as-is from the latest `v0.7.0` release with no
|
||||
other changes, so you can simply update your code to use the updated namespace
|
||||
like this:
|
||||
|
||||
```php
|
||||
// old from SocketClient component and namespace
|
||||
$connector = new React\SocketClient\Connector($loop);
|
||||
$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
|
||||
$connection->write('…');
|
||||
});
|
||||
|
||||
// new
|
||||
$connector = new React\Socket\Connector($loop);
|
||||
$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
|
||||
$connection->write('…');
|
||||
});
|
||||
```
|
||||
|
||||
## 0.6.0 (2017-04-04)
|
||||
|
||||
* Feature: Add `LimitingServer` to limit and keep track of open connections
|
||||
(#86 by @clue)
|
||||
|
||||
```php
|
||||
$server = new Server(0, $loop);
|
||||
$server = new LimitingServer($server, 100);
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $connection) {
|
||||
$connection->write('hello there!' . PHP_EOL);
|
||||
…
|
||||
});
|
||||
```
|
||||
|
||||
* Feature / BC break: Add `pause()` and `resume()` methods to limit active
|
||||
connections
|
||||
(#84 by @clue)
|
||||
|
||||
```php
|
||||
$server = new Server(0, $loop);
|
||||
$server->pause();
|
||||
|
||||
$loop->addTimer(1.0, function() use ($server) {
|
||||
$server->resume();
|
||||
});
|
||||
```
|
||||
|
||||
## 0.5.1 (2017-03-09)
|
||||
|
||||
* Feature: Forward compatibility with Stream v0.5 and upcoming v0.6
|
||||
(#79 by @clue)
|
||||
|
||||
## 0.5.0 (2017-02-14)
|
||||
|
||||
* Feature / BC break: Replace `listen()` call with URIs passed to constructor
|
||||
and reject listening on hostnames with `InvalidArgumentException`
|
||||
and replace `ConnectionException` with `RuntimeException` for consistency
|
||||
(#61, #66 and #72 by @clue)
|
||||
|
||||
```php
|
||||
// old
|
||||
$server = new Server($loop);
|
||||
$server->listen(8080);
|
||||
|
||||
// new
|
||||
$server = new Server(8080, $loop);
|
||||
```
|
||||
|
||||
Similarly, you can now pass a full listening URI to the constructor to change
|
||||
the listening host:
|
||||
|
||||
```php
|
||||
// old
|
||||
$server = new Server($loop);
|
||||
$server->listen(8080, '127.0.0.1');
|
||||
|
||||
// new
|
||||
$server = new Server('127.0.0.1:8080', $loop);
|
||||
```
|
||||
|
||||
Trying to start listening on (DNS) host names will now throw an
|
||||
`InvalidArgumentException`, use IP addresses instead:
|
||||
|
||||
```php
|
||||
// old
|
||||
$server = new Server($loop);
|
||||
$server->listen(8080, 'localhost');
|
||||
|
||||
// new
|
||||
$server = new Server('127.0.0.1:8080', $loop);
|
||||
```
|
||||
|
||||
If trying to listen fails (such as if port is already in use or port below
|
||||
1024 may require root access etc.), it will now throw a `RuntimeException`,
|
||||
the `ConnectionException` class has been removed:
|
||||
|
||||
```php
|
||||
// old: throws React\Socket\ConnectionException
|
||||
$server = new Server($loop);
|
||||
$server->listen(80);
|
||||
|
||||
// new: throws RuntimeException
|
||||
$server = new Server(80, $loop);
|
||||
```
|
||||
|
||||
* Feature / BC break: Rename `shutdown()` to `close()` for consistency throughout React
|
||||
(#62 by @clue)
|
||||
|
||||
```php
|
||||
// old
|
||||
$server->shutdown();
|
||||
|
||||
// new
|
||||
$server->close();
|
||||
```
|
||||
|
||||
* Feature / BC break: Replace `getPort()` with `getAddress()`
|
||||
(#67 by @clue)
|
||||
|
||||
```php
|
||||
// old
|
||||
echo $server->getPort(); // 8080
|
||||
|
||||
// new
|
||||
echo $server->getAddress(); // 127.0.0.1:8080
|
||||
```
|
||||
|
||||
* Feature / BC break: `getRemoteAddress()` returns full address instead of only IP
|
||||
(#65 by @clue)
|
||||
|
||||
```php
|
||||
// old
|
||||
echo $connection->getRemoteAddress(); // 192.168.0.1
|
||||
|
||||
// new
|
||||
echo $connection->getRemoteAddress(); // 192.168.0.1:51743
|
||||
```
|
||||
|
||||
* Feature / BC break: Add `getLocalAddress()` method
|
||||
(#68 by @clue)
|
||||
|
||||
```php
|
||||
echo $connection->getLocalAddress(); // 127.0.0.1:8080
|
||||
```
|
||||
|
||||
* BC break: The `Server` and `SecureServer` class are now marked `final`
|
||||
and you can no longer `extend` them
|
||||
(which was never documented or recommended anyway).
|
||||
Public properties and event handlers are now internal only.
|
||||
Please use composition instead of extension.
|
||||
(#71, #70 and #69 by @clue)
|
||||
|
||||
## 0.4.6 (2017-01-26)
|
||||
|
||||
* Feature: Support socket context options passed to `Server`
|
||||
(#64 by @clue)
|
||||
|
||||
* Fix: Properly return `null` for unknown addresses
|
||||
(#63 by @clue)
|
||||
|
||||
* Improve documentation for `ServerInterface` and lock test suite requirements
|
||||
(#60 by @clue, #57 by @shaunbramley)
|
||||
|
||||
## 0.4.5 (2017-01-08)
|
||||
|
||||
* Feature: Add `SecureServer` for secure TLS connections
|
||||
(#55 by @clue)
|
||||
|
||||
* Add functional integration tests
|
||||
(#54 by @clue)
|
||||
|
||||
## 0.4.4 (2016-12-19)
|
||||
|
||||
* Feature / Fix: `ConnectionInterface` should extend `DuplexStreamInterface` + documentation
|
||||
(#50 by @clue)
|
||||
|
||||
* Feature / Fix: Improve test suite and switch to normal stream handler
|
||||
(#51 by @clue)
|
||||
|
||||
* Feature: Add examples
|
||||
(#49 by @clue)
|
||||
|
||||
## 0.4.3 (2016-03-01)
|
||||
|
||||
* Bug fix: Suppress errors on stream_socket_accept to prevent PHP from crashing
|
||||
* Support for PHP7 and HHVM
|
||||
* Support PHP 5.3 again
|
||||
|
||||
## 0.4.2 (2014-05-25)
|
||||
|
||||
* Verify stream is a valid resource in Connection
|
||||
|
||||
## 0.4.1 (2014-04-13)
|
||||
|
||||
* Bug fix: Check read buffer for data before shutdown signal and end emit (@ArtyDev)
|
||||
* Bug fix: v0.3.4 changes merged for v0.4.1
|
||||
|
||||
## 0.3.4 (2014-03-30)
|
||||
|
||||
* Bug fix: Reset socket to non-blocking after shutting down (PHP bug)
|
||||
|
||||
## 0.4.0 (2014-02-02)
|
||||
|
||||
* BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
|
||||
* BC break: Update to React/Promise 2.0
|
||||
* BC break: Update to Evenement 2.0
|
||||
* Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
|
||||
* Bump React dependencies to v0.4
|
||||
|
||||
## 0.3.3 (2013-07-08)
|
||||
|
||||
* Version bump
|
||||
|
||||
## 0.3.2 (2013-05-10)
|
||||
|
||||
* Version bump
|
||||
|
||||
## 0.3.1 (2013-04-21)
|
||||
|
||||
* Feature: Support binding to IPv6 addresses (@clue)
|
||||
|
||||
## 0.3.0 (2013-04-14)
|
||||
|
||||
* Bump React dependencies to v0.3
|
||||
|
||||
## 0.2.6 (2012-12-26)
|
||||
|
||||
* Version bump
|
||||
|
||||
## 0.2.3 (2012-11-14)
|
||||
|
||||
* Version bump
|
||||
|
||||
## 0.2.0 (2012-09-10)
|
||||
|
||||
* Bump React dependencies to v0.2
|
||||
|
||||
## 0.1.1 (2012-07-12)
|
||||
|
||||
* Version bump
|
||||
|
||||
## 0.1.0 (2012-07-11)
|
||||
|
||||
* First tagged release
|
||||
19
vendor/react/socket/LICENSE
vendored
Executable file
19
vendor/react/socket/LICENSE
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2012 Igor Wiedler, 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.
|
||||
1419
vendor/react/socket/README.md
vendored
Executable file
1419
vendor/react/socket/README.md
vendored
Executable file
File diff suppressed because it is too large
Load Diff
29
vendor/react/socket/composer.json
vendored
Executable file
29
vendor/react/socket/composer.json
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "react/socket",
|
||||
"description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
|
||||
"keywords": ["async", "socket", "stream", "connection", "ReactPHP"],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
|
||||
"react/dns": "^0.4.13",
|
||||
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
|
||||
"react/stream": "^1.0 || ^0.7.1",
|
||||
"react/promise": "^2.6.0 || ^1.2.1",
|
||||
"react/promise-timer": "^1.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"clue/block-react": "^1.2",
|
||||
"phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\Socket\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"React\\Tests\\Socket\\": "tests"
|
||||
}
|
||||
}
|
||||
}
|
||||
42
vendor/react/socket/examples/01-echo-server.php
vendored
Executable file
42
vendor/react/socket/examples/01-echo-server.php
vendored
Executable file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
// Just start this server and connect to it. Everything you send to it will be
|
||||
// sent back to you.
|
||||
//
|
||||
// $ php examples/01-echo-server.php 8000
|
||||
// $ telnet localhost 8000
|
||||
//
|
||||
// You can also run a secure TLS echo server like this:
|
||||
//
|
||||
// $ php examples/01-echo-server.php tls://127.0.0.1:8000 examples/localhost.pem
|
||||
// $ openssl s_client -connect localhost:8000
|
||||
//
|
||||
// You can also run a Unix domain socket (UDS) server like this:
|
||||
//
|
||||
// $ php examples/01-echo-server.php unix:///tmp/server.sock
|
||||
// $ nc -U /tmp/server.sock
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Server;
|
||||
use React\Socket\ConnectionInterface;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array(
|
||||
'tls' => array(
|
||||
'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem')
|
||||
)
|
||||
));
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $conn) {
|
||||
echo '[' . $conn->getRemoteAddress() . ' connected]' . PHP_EOL;
|
||||
$conn->pipe($conn);
|
||||
});
|
||||
|
||||
$server->on('error', 'printf');
|
||||
|
||||
echo 'Listening on ' . $server->getAddress() . PHP_EOL;
|
||||
|
||||
$loop->run();
|
||||
59
vendor/react/socket/examples/02-chat-server.php
vendored
Executable file
59
vendor/react/socket/examples/02-chat-server.php
vendored
Executable file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
// Just start this server and connect with any number of clients to it.
|
||||
// Everything a client sends will be broadcasted to all connected clients.
|
||||
//
|
||||
// $ php examples/02-chat-server.php 8000
|
||||
// $ telnet localhost 8000
|
||||
//
|
||||
// You can also run a secure TLS chat server like this:
|
||||
//
|
||||
// $ php examples/02-chat-server.php tls://127.0.0.1:8000 examples/localhost.pem
|
||||
// $ openssl s_client -connect localhost:8000
|
||||
//
|
||||
// You can also run a Unix domain socket (UDS) server like this:
|
||||
//
|
||||
// $ php examples/02-chat-server.php unix:///tmp/server.sock
|
||||
// $ nc -U /tmp/server.sock
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Server;
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Socket\LimitingServer;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array(
|
||||
'tls' => array(
|
||||
'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem')
|
||||
)
|
||||
));
|
||||
|
||||
$server = new LimitingServer($server, null);
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $client) use ($server) {
|
||||
// whenever a new message comes in
|
||||
$client->on('data', function ($data) use ($client, $server) {
|
||||
// remove any non-word characters (just for the demo)
|
||||
$data = trim(preg_replace('/[^\w\d \.\,\-\!\?]/u', '', $data));
|
||||
|
||||
// ignore empty messages
|
||||
if ($data === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// prefix with client IP and broadcast to all connected clients
|
||||
$data = trim(parse_url($client->getRemoteAddress(), PHP_URL_HOST), '[]') . ': ' . $data . PHP_EOL;
|
||||
foreach ($server->getConnections() as $connection) {
|
||||
$connection->write($data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$server->on('error', 'printf');
|
||||
|
||||
echo 'Listening on ' . $server->getAddress() . PHP_EOL;
|
||||
|
||||
$loop->run();
|
||||
57
vendor/react/socket/examples/03-http-server.php
vendored
Executable file
57
vendor/react/socket/examples/03-http-server.php
vendored
Executable file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
// Simple HTTP server example (for illustration purposes only).
|
||||
// This shows how a plaintext TCP/IP connection is accepted to then receive an
|
||||
// application level protocol message (HTTP request) and reply with an
|
||||
// application level protocol message (HTTP response) in return.
|
||||
//
|
||||
// This example exists for illustraion purposes only. It does not actually
|
||||
// parse incoming HTTP requests, so you can actually send *anything* and will
|
||||
// still respond with a valid HTTP response.
|
||||
// Real applications should use react/http instead!
|
||||
//
|
||||
// Just start this server and send a request to it:
|
||||
//
|
||||
// $ php examples/03-http-server.php 8000
|
||||
// $ curl -v http://localhost:8000/
|
||||
// $ ab -n1000 -c10 http://localhost:8000/
|
||||
// $ docker run -it --rm --net=host jordi/ab ab -n1000 -c10 http://localhost:8000/
|
||||
//
|
||||
// You can also run a secure HTTPS echo server like this:
|
||||
//
|
||||
// $ php examples/03-http-server.php tls://127.0.0.1:8000 examples/localhost.pem
|
||||
// $ curl -v --insecure https://localhost:8000/
|
||||
// $ ab -n1000 -c10 https://localhost:8000/
|
||||
// $ docker run -it --rm --net=host jordi/ab ab -n1000 -c10 https://localhost:8000/
|
||||
//
|
||||
// You can also run a Unix domain socket (UDS) server like this:
|
||||
//
|
||||
// $ php examples/03-http-server.php unix:///tmp/server.sock
|
||||
// $ nc -U /tmp/server.sock
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Server;
|
||||
use React\Socket\ConnectionInterface;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array(
|
||||
'tls' => array(
|
||||
'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem')
|
||||
)
|
||||
));
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $conn) {
|
||||
$conn->once('data', function () use ($conn) {
|
||||
$body = "<html><h1>Hello world!</h1></html>\r\n";
|
||||
$conn->end("HTTP/1.1 200 OK\r\nContent-Length: " . strlen($body) . "\r\nConnection: close\r\n\r\n" . $body);
|
||||
});
|
||||
});
|
||||
|
||||
$server->on('error', 'printf');
|
||||
|
||||
echo 'Listening on ' . strtr($server->getAddress(), array('tcp:' => 'http:', 'tls:' => 'https:')) . PHP_EOL;
|
||||
|
||||
$loop->run();
|
||||
36
vendor/react/socket/examples/11-http-client.php
vendored
Executable file
36
vendor/react/socket/examples/11-http-client.php
vendored
Executable file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
// Simple plaintext HTTP client example (for illustration purposes only).
|
||||
// This shows how a plaintext TCP/IP connection is established to then send an
|
||||
// application level protocol message (HTTP).
|
||||
// Real applications should use react/http-client instead!
|
||||
//
|
||||
// This simple example only accepts an optional host parameter to send the
|
||||
// request to. See also example #22 for proper URI parsing.
|
||||
//
|
||||
// $ php examples/11-http-client.php
|
||||
// $ php examples/11-http-client.php reactphp.org
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Connector;
|
||||
use React\Socket\ConnectionInterface;
|
||||
|
||||
$host = isset($argv[1]) ? $argv[1] : 'www.google.com';
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
$connector->connect($host. ':80')->then(function (ConnectionInterface $connection) use ($host) {
|
||||
$connection->on('data', function ($data) {
|
||||
echo $data;
|
||||
});
|
||||
$connection->on('close', function () {
|
||||
echo '[CLOSED]' . PHP_EOL;
|
||||
});
|
||||
|
||||
$connection->write("GET / HTTP/1.0\r\nHost: $host\r\n\r\n");
|
||||
}, 'printf');
|
||||
|
||||
$loop->run();
|
||||
36
vendor/react/socket/examples/12-https-client.php
vendored
Executable file
36
vendor/react/socket/examples/12-https-client.php
vendored
Executable file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
// Simple secure HTTPS client example (for illustration purposes only).
|
||||
// This shows how a secure TLS connection is established to then send an
|
||||
// application level protocol message (HTTP).
|
||||
// Real applications should use react/http-client instead
|
||||
//
|
||||
// This simple example only accepts an optional host parameter to send the
|
||||
// request to. See also example #22 for proper URI parsing.
|
||||
//
|
||||
// $ php examples/12-https-client.php
|
||||
// $ php examples/12-https-client.php reactphp.org
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Connector;
|
||||
use React\Socket\ConnectionInterface;
|
||||
|
||||
$host = isset($argv[1]) ? $argv[1] : 'www.google.com';
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
$connector->connect('tls://' . $host . ':443')->then(function (ConnectionInterface $connection) use ($host) {
|
||||
$connection->on('data', function ($data) {
|
||||
echo $data;
|
||||
});
|
||||
$connection->on('close', function () {
|
||||
echo '[CLOSED]' . PHP_EOL;
|
||||
});
|
||||
|
||||
$connection->write("GET / HTTP/1.0\r\nHost: $host\r\n\r\n");
|
||||
}, 'printf');
|
||||
|
||||
$loop->run();
|
||||
68
vendor/react/socket/examples/21-netcat-client.php
vendored
Executable file
68
vendor/react/socket/examples/21-netcat-client.php
vendored
Executable file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
// Simple plaintext TCP/IP and secure TLS client example that pipes console I/O.
|
||||
// This shows how a plaintext TCP/IP or secure TLS connection is established and
|
||||
// then everything you type on STDIN will be sent and everything the server
|
||||
// sends will be piped to your STDOUT.
|
||||
//
|
||||
// $ php examples/21-netcat-client.php www.google.com:80
|
||||
// $ php examples/21-netcat-client.php tls://www.google.com:443
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Connector;
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Stream\ReadableResourceStream;
|
||||
use React\Stream\WritableResourceStream;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
if (!defined('STDIN')) {
|
||||
echo 'STDIO streams require CLI SAPI' . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
fwrite(STDERR, 'Non-blocking console I/O not supported on Microsoft Windows' . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!isset($argv[1])) {
|
||||
fwrite(STDERR, 'Usage error: required argument <host:port>' . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
$stdin = new ReadableResourceStream(STDIN, $loop);
|
||||
$stdin->pause();
|
||||
$stdout = new WritableResourceStream(STDOUT, $loop);
|
||||
$stderr = new WritableResourceStream(STDERR, $loop);
|
||||
|
||||
$stderr->write('Connecting' . PHP_EOL);
|
||||
|
||||
$connector->connect($argv[1])->then(function (ConnectionInterface $connection) use ($stdin, $stdout, $stderr) {
|
||||
// pipe everything from STDIN into connection
|
||||
$stdin->resume();
|
||||
$stdin->pipe($connection);
|
||||
|
||||
// pipe everything from connection to STDOUT
|
||||
$connection->pipe($stdout);
|
||||
|
||||
// report errors to STDERR
|
||||
$connection->on('error', function ($error) use ($stderr) {
|
||||
$stderr->write('Stream ERROR: ' . $error . PHP_EOL);
|
||||
});
|
||||
|
||||
// report closing and stop reading from input
|
||||
$connection->on('close', function () use ($stderr, $stdin) {
|
||||
$stderr->write('[CLOSED]' . PHP_EOL);
|
||||
$stdin->close();
|
||||
});
|
||||
|
||||
$stderr->write('Connected' . PHP_EOL);
|
||||
}, function ($error) use ($stderr) {
|
||||
$stderr->write('Connection ERROR: ' . $error . PHP_EOL);
|
||||
});
|
||||
|
||||
$loop->run();
|
||||
60
vendor/react/socket/examples/22-http-client.php
vendored
Executable file
60
vendor/react/socket/examples/22-http-client.php
vendored
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
// Simple plaintext HTTP and secure HTTPS client example (for illustration purposes only).
|
||||
// This shows how an URI parameter can parsed to decide whether to establish
|
||||
// a plaintext TCP/IP or secure TLS connection and then send an
|
||||
// application level protocol message (HTTP).
|
||||
// Real applications should use react/http-client instead!
|
||||
//
|
||||
// Unlike examples #11 and #12, this example will actually take an optional URI
|
||||
// parameter and parse it to connect to the correct default port and use the
|
||||
// correct transport protocol.
|
||||
//
|
||||
// $ php examples/22-http-client.php
|
||||
// $ php examples/22-http-client.php https://reactphp.org/
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Socket\Connector;
|
||||
use React\Stream\WritableResourceStream;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$uri = isset($argv[1]) ? $argv[1] : 'www.google.com';
|
||||
|
||||
if (strpos($uri, '://') === false) {
|
||||
$uri = 'http://' . $uri;
|
||||
}
|
||||
$parts = parse_url($uri);
|
||||
|
||||
if (!$parts || !isset($parts['scheme'], $parts['host'])) {
|
||||
fwrite(STDERR, 'Usage error: required argument <host:port>' . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
if (!isset($parts['port'])) {
|
||||
$parts['port'] = $parts['scheme'] === 'https' ? 443 : 80;
|
||||
}
|
||||
|
||||
$host = $parts['host'];
|
||||
if (($parts['scheme'] === 'http' && $parts['port'] !== 80) || ($parts['scheme'] === 'https' && $parts['port'] !== 443)) {
|
||||
$host .= ':' . $parts['port'];
|
||||
}
|
||||
$target = ($parts['scheme'] === 'https' ? 'tls' : 'tcp') . '://' . $parts['host'] . ':' . $parts['port'];
|
||||
$resource = isset($parts['path']) ? $parts['path'] : '/';
|
||||
if (isset($parts['query'])) {
|
||||
$resource .= '?' . $parts['query'];
|
||||
}
|
||||
|
||||
$stdout = new WritableResourceStream(STDOUT, $loop);
|
||||
|
||||
$connector->connect($target)->then(function (ConnectionInterface $connection) use ($resource, $host, $stdout) {
|
||||
$connection->pipe($stdout);
|
||||
|
||||
$connection->write("GET $resource HTTP/1.0\r\nHost: $host\r\n\r\n");
|
||||
}, 'printf');
|
||||
|
||||
$loop->run();
|
||||
60
vendor/react/socket/examples/91-benchmark-server.php
vendored
Executable file
60
vendor/react/socket/examples/91-benchmark-server.php
vendored
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
// Just start the server and connect to it. It will count the number of bytes
|
||||
// sent for each connection and will print the average throughput once the
|
||||
// connection closes.
|
||||
//
|
||||
// $ php examples/91-benchmark-server.php 8000
|
||||
// $ telnet localhost 8000
|
||||
// $ echo hello world | nc -N localhost 8000
|
||||
// $ dd if=/dev/zero bs=1M count=1000 | nc -N localhost 8000
|
||||
//
|
||||
// You can also run a secure TLS benchmarking server like this:
|
||||
//
|
||||
// $ php examples/91-benchmark-server.php tls://127.0.0.1:8000 examples/localhost.pem
|
||||
// $ openssl s_client -connect localhost:8000
|
||||
// $ echo hello world | openssl s_client -connect localhost:8000
|
||||
// $ dd if=/dev/zero bs=1M count=1000 | openssl s_client -connect localhost:8000
|
||||
//
|
||||
// You can also run a Unix domain socket (UDS) server benchmark like this:
|
||||
//
|
||||
// $ php examples/91-benchmark-server.php unix:///tmp/server.sock
|
||||
// $ nc -N -U /tmp/server.sock
|
||||
// $ dd if=/dev/zero bs=1M count=1000 | nc -N -U /tmp/server.sock
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Server;
|
||||
use React\Socket\ConnectionInterface;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array(
|
||||
'tls' => array(
|
||||
'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem')
|
||||
)
|
||||
));
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $conn) use ($loop) {
|
||||
echo '[connected]' . PHP_EOL;
|
||||
|
||||
// count the number of bytes received from this connection
|
||||
$bytes = 0;
|
||||
$conn->on('data', function ($chunk) use (&$bytes) {
|
||||
$bytes += strlen($chunk);
|
||||
});
|
||||
|
||||
// report average throughput once client disconnects
|
||||
$t = microtime(true);
|
||||
$conn->on('close', function () use ($conn, $t, &$bytes) {
|
||||
$t = microtime(true) - $t;
|
||||
echo '[disconnected after receiving ' . $bytes . ' bytes in ' . round($t, 3) . 's => ' . round($bytes / $t / 1024 / 1024, 1) . ' MiB/s]' . PHP_EOL;
|
||||
});
|
||||
});
|
||||
|
||||
$server->on('error', 'printf');
|
||||
|
||||
echo 'Listening on ' . $server->getAddress() . PHP_EOL;
|
||||
|
||||
$loop->run();
|
||||
31
vendor/react/socket/examples/99-generate-self-signed.php
vendored
Executable file
31
vendor/react/socket/examples/99-generate-self-signed.php
vendored
Executable file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
// A very simple helper script used to generate self-signed certificates.
|
||||
// Accepts the CN and an optional passphrase to encrypt the private key.
|
||||
//
|
||||
// $ php 10-generate-self-signed.php localhost swordfish > secret.pem
|
||||
|
||||
// certificate details (Distinguished Name)
|
||||
// (OpenSSL applies defaults to missing fields)
|
||||
$dn = array(
|
||||
"commonName" => isset($argv[1]) ? $argv[1] : "localhost",
|
||||
// "countryName" => "AU",
|
||||
// "stateOrProvinceName" => "Some-State",
|
||||
// "localityName" => "London",
|
||||
// "organizationName" => "Internet Widgits Pty Ltd",
|
||||
// "organizationalUnitName" => "R&D",
|
||||
// "emailAddress" => "admin@example.com"
|
||||
);
|
||||
|
||||
// create certificate which is valid for ~10 years
|
||||
$privkey = openssl_pkey_new();
|
||||
$cert = openssl_csr_new($dn, $privkey);
|
||||
$cert = openssl_csr_sign($cert, null, $privkey, 3650);
|
||||
|
||||
// export public and (optionally encrypted) private key in PEM format
|
||||
openssl_x509_export($cert, $out);
|
||||
echo $out;
|
||||
|
||||
$passphrase = isset($argv[2]) ? $argv[2] : null;
|
||||
openssl_pkey_export($privkey, $out, $passphrase);
|
||||
echo $out;
|
||||
49
vendor/react/socket/examples/localhost.pem
vendored
Executable file
49
vendor/react/socket/examples/localhost.pem
vendored
Executable file
@@ -0,0 +1,49 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBZMRIwEAYDVQQDDAkxMjcu
|
||||
MC4wLjExCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK
|
||||
DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMwMTQ1OTA2WhcNMjYx
|
||||
MjI4MTQ1OTA2WjBZMRIwEAYDVQQDDAkxMjcuMC4wLjExCzAJBgNVBAYTAkFVMRMw
|
||||
EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0
|
||||
eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8SZWNS+Ktg0Py
|
||||
W8dx5uXZ+ZUawd3wnzLMHW7EhoUpIrIdp3kDU9NezF68dOhPMJY/Kh+6btRCxWXN
|
||||
2OVTqS5Xi826j3TSE07iF83JRLeveW0PcodjUBd+RzdwCWWo2pfMJz4v7x1wu1c9
|
||||
zNi6JxxpDAXTFSB4GiWsI4tFu2XmMRhfm6LRK4WPfsZIJKokdiG5fKSPDn7nrVj0
|
||||
UUXr2eBsEAzdwL14U9+mwbLdaAkz3qK3fqi8sEC09lEWm95gKMOhkQf5qvXODtT4
|
||||
wdVrrKDTyehLv0xaItnUDnXzrkMBU5QS9TQzzqSW6ZaBsSxtONEFUiXiN9dtyXsY
|
||||
YCUE54G/AgMBAAGjUDBOMB0GA1UdDgQWBBQ2GRz3QsQzdXaTMnPVCKfpigA10DAf
|
||||
BgNVHSMEGDAWgBQ2GRz3QsQzdXaTMnPVCKfpigA10DAMBgNVHRMEBTADAQH/MA0G
|
||||
CSqGSIb3DQEBBQUAA4IBAQA77iZ4KrpPY18Ezjt0mngYAuAxunKddXYdLZ2khywN
|
||||
0uI/VzYnkFVtrsC7y2jLHSxlmE2/viPPGZDUplENV2acN6JNW+tlt7/bsrQHDQw3
|
||||
7VCF27EWiDxHsaghhLkqC+kcop5YR5c0oDQTdEWEKSbow2zayUXDYbRRs76SClTe
|
||||
824Yul+Ts8Mka+AX2PXDg47iZ84fJRN/nKavcJUTJ2iS1uYw0GNnFMge/uwsfMR3
|
||||
V47qN0X5emky8fcq99FlMCbcy0gHAeSWAjClgr2dd2i0LDatUbj7YmdmFcskOgII
|
||||
IwGfvuWR2yPevYGAE0QgFeLHniN3RW8zmpnX/XtrJ4a7
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8SZWNS+Ktg0Py
|
||||
W8dx5uXZ+ZUawd3wnzLMHW7EhoUpIrIdp3kDU9NezF68dOhPMJY/Kh+6btRCxWXN
|
||||
2OVTqS5Xi826j3TSE07iF83JRLeveW0PcodjUBd+RzdwCWWo2pfMJz4v7x1wu1c9
|
||||
zNi6JxxpDAXTFSB4GiWsI4tFu2XmMRhfm6LRK4WPfsZIJKokdiG5fKSPDn7nrVj0
|
||||
UUXr2eBsEAzdwL14U9+mwbLdaAkz3qK3fqi8sEC09lEWm95gKMOhkQf5qvXODtT4
|
||||
wdVrrKDTyehLv0xaItnUDnXzrkMBU5QS9TQzzqSW6ZaBsSxtONEFUiXiN9dtyXsY
|
||||
YCUE54G/AgMBAAECggEBAKiO/3FE1CMddkCLZVtUp8ShqJgRokx9WI5ecwFApAkV
|
||||
ZHsjqDQQYRNmxhDUX/w0tOzLGyhde2xjJyZG29YviKsbHwu6zYwbeOzy/mkGOaK/
|
||||
g6DmmMmRs9Z6juifoQCu4GIFZ6il2adIL2vF7OeJh+eKudQj/7NFRSB7mXzNrQWK
|
||||
tZY3eux5zXWmio7pgZrx1HFZQiiL9NVLwT9J7oBnaoO3fREiu5J2xBpljG9Cr0j1
|
||||
LLiVLhukWJYRlHDtGt1CzI9w8iKo44PCRzpKyxpbsOrQxeSyEWUYQRv9VHA59LC7
|
||||
tVAJTbnTX1BNHkGZkOkoOpoZLwBaM2XbbDtcOGCAZMECgYEA+mTURFQ85/pxawvk
|
||||
9ndqZ+5He1u/bMLYIJDp0hdB/vgD+vw3gb2UyRwp0I6Wc6Si4FEEnbY7L0pzWsiR
|
||||
43CpLs+cyLfnD9NycuIasxs5fKb/1s1nGTkRAp7x9x/ZTtEf8v4YTmmMXFHzdo7V
|
||||
pv+czO89ppEDkxEtMf/b5SifhO8CgYEAwIDIUvXLduGhL+RPDwjc2SKdydXGV6om
|
||||
OEdt/V8oS801Z7k8l3gHXFm7zL/MpHmh9cag+F9dHK42kw2RSjDGsBlXXiAO1Z0I
|
||||
2A34OdPw/kow8fmIKWTMu3+28Kca+3RmUqeyaq0vazQ/bWMO9px+Ud3YfLo1Tn5I
|
||||
li0MecAx8DECgYEAvsLceKYYtL83c09fg2oc1ctSCCgw4WJcGAtvJ9DyRZacKbXH
|
||||
b/+H/+OF8879zmKqd+0hcCnqUzAMTCisBLPLIM+o6b45ufPkqKObpcJi/JWaKgLY
|
||||
vf2c+Psw6o4IF6T5Cz4MNIjzF06UBknxecYZpoPJ20F1kLCwVvxPgfl99l8CgYAb
|
||||
XfOcv67WTstgiJ+oroTfJamy+P5ClkDqvVTosW+EHz9ZaJ8xlXHOcj9do2LPey9I
|
||||
Rp250azmF+pQS5x9JKQKgv/FtN8HBVUtigbhCb14GUoODICMCfWFLmnumoMefnTR
|
||||
iV+3BLn6Dqp5vZxx+NuIffZ5/Or5JsDhALSGVomC8QKBgAi3Z/dNQrDHfkXMNn/L
|
||||
+EAoLuAbFgLs76r9VGgNaRQ/q5gex2bZEGoBj4Sxvs95NUIcfD9wKT7FF8HdxARv
|
||||
y3o6Bfc8Xp9So9SlFXrje+gkdEJ0rQR67d+XBuJZh86bXJHVrMwpoNL+ahLGdVSe
|
||||
81oh1uCH1YPLM29hPyaohxL8
|
||||
-----END PRIVATE KEY-----
|
||||
51
vendor/react/socket/examples/localhost_swordfish.pem
vendored
Executable file
51
vendor/react/socket/examples/localhost_swordfish.pem
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBZMRIwEAYDVQQDDAkxMjcu
|
||||
MC4wLjExCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK
|
||||
DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMwMTQxMDQzWhcNMjYx
|
||||
MjI4MTQxMDQzWjBZMRIwEAYDVQQDDAkxMjcuMC4wLjExCzAJBgNVBAYTAkFVMRMw
|
||||
EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0
|
||||
eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRXt83SrKIHr/i
|
||||
3lc8O8pz6NHE1DNHJa4xg2xalXWzCEV6m1qLd9VdaLT9cJD1afNmEMBgY6RblNL/
|
||||
paJWVoR9MOUeIoYl2PrhUCxsf7h6MRtezQQe3e+n+/0XunF0JUQIZuJqbxfRk5WT
|
||||
XmYnphqOZKEcistAYvFBjzl/D+Cl/nYsreADc+t9l5Vni89oTWEuqIrsM4WUZqqB
|
||||
VMAakd2nZJLWIrMxq9hbW1XNukOQfcmZVFTC6CUnLq8qzGbtfZYBuMBACnL1k/E/
|
||||
yPaAgR46l14VAcndDUJBtMeL2qYuNwvXQhg3KuBmpTUpH+yzxU+4T3lmv0xXmPqu
|
||||
ySH3xvW3AgMBAAGjUDBOMB0GA1UdDgQWBBRu68WTI4pVeTB7wuG9QGI3Ie441TAf
|
||||
BgNVHSMEGDAWgBRu68WTI4pVeTB7wuG9QGI3Ie441TAMBgNVHRMEBTADAQH/MA0G
|
||||
CSqGSIb3DQEBBQUAA4IBAQCc4pEjEHO47VRJkbHgC+c2gAVgxekkaA1czBA1uAvh
|
||||
ILRda0NLlvyftbjaG0zZp2ABUCfRfksl/Pf/PzWLUMEuH/9kEW2rgP43z6YgiL6k
|
||||
kBPlmAU607UjD726RPGkw8QPSXS/dWiNJ5CBpPWLpxC45pokqItYbY0ijQ5Piq09
|
||||
TchYlCX044oSRnPiP394PQ3HVdaGhJB2DnjDq3in5dVivFf8EdgzQSvp/wXy3WQs
|
||||
uFSVonSnrZGY/4AgT3psGaQ6fqKb4SBoqtf5bFQvp1XNNRkuEJnS/0dygEya0c+c
|
||||
aCe/1gXC2wDjx0/TekY5m1Nyw5SY6z7stOqL/ekwgejt
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIG7idPRLgiHkCAggA
|
||||
MBQGCCqGSIb3DQMHBAg+MLPdepHWSwSCBMgVW9LseCjfTAmF9U1qRnKsq3kIwEnW
|
||||
6aERBqs/mnmEhrXgZYgcvRRK7kD12TdHt/Nz46Ymu0h+Lrvuwtl1fHQUARTk/gFh
|
||||
onLhc9kjMUhLRIR007vJe3HvWOb/v+SBSDB38OpUxUwJmBVBuSaYLWVuPR6J5kUj
|
||||
xOgBS049lN3E9cfrHvb3bF/epIQrU0OgfyyxEvIi5n30y+tlRn3y68PY6Qd46t4Y
|
||||
UN5VZUwvJBgoRy9TGxSkiSRjhxC2PWpLYq/HMzDbcRcFF5dVAIioUd/VZ7fdgBfA
|
||||
uMW4SFfpFLDUX0aaYe+ZdA5tM0Bc0cOtG8Z0sc9JYDNNcvjmSiGCi646h8F0D3O6
|
||||
JKAQMMxQGWiyQeJ979LVjtq4lJESXA8VEKz9rV03y5xunmFCLy6dGt+6GJwXgabn
|
||||
OH7nvEv4GqAOqKc6E9je4JM+AF/oUazrfPse1KEEtsPKarazjCB/SKYtHyDJaavD
|
||||
GGjtiU9zWwGMOgIDyNmXe3ga7/TWoGOAg5YlTr6Hbq2Y/5ycgjAgPFjuXtvnoT0+
|
||||
mF5TnNfMAqTgQsE2gjhonK1pdlOen0lN5FtoUXp3CXU0dOq0J70GiX+1YA7VDn30
|
||||
n5WNAgfOXX3l3E95jGN370pHXyli5RUNW0NZVHV+22jlNWCVtQHUh+DVswQZg+i5
|
||||
+DqaIHz2jUetMo7gWtqGn/wwSopOs87VM1rcALhZL4EsJ+Zy81I/hA32RNnGbuol
|
||||
NAiZh+0KrtTcc/fPunpd8vRtOwGphM11dKucozUufuiPG2inR3aEqt5yNx54ec/f
|
||||
J6nryWRYiHEA/rCU9MSBM9cqKFtEmy9/8oxV41/SPxhXjHwDlABWTtFuJ3pf2sOF
|
||||
ILSYYFwB0ZGvdjE5yAJFBr9efno/L9fafmGk7a3vmVgK2AmUC9VNB5XHw1GjF8OP
|
||||
aQAXe4md9Bh0jk/D/iyp7e7IWNssul/7XejhabidWgFj6EXc9YxE59+FlhDqyMhn
|
||||
V6houc+QeUXuwsAKgRJJhJtpv/QSZ5BI3esxHHUt3ayGnvhFElpAc0t7C/EiXKIv
|
||||
DAFYP2jksBqijM8YtEgPWYzEP5buYxZnf/LK7FDocLsNcdF38UaKBbeF90e7bR8j
|
||||
SHspG9aJWICu8Yawnh8zuy/vQv+h9gWyGodd2p9lQzlbRXrutbwfmPf7xP6nzT9i
|
||||
9GcugJxTaZgkCfhhHxFk/nRHS2NAzagKVib1xkUlZJg2hX0fIFUdYteL1GGTvOx5
|
||||
m3mTOino4T19z9SEdZYb2OHYh29e/T74bJiLCYdXwevSYHxfZc8pYAf0jp4UnMT2
|
||||
f7B0ctX1iXuQ2uZVuxh+U1Mcu+v0gDla1jWh7AhcePSi4xBNUCak0kQip6r5e6Oi
|
||||
r4MIyMRk/Pc5pzEKo8G6nk26rNvX3aRvECoVfmK7IVdsqZ6IXlt9kOmWx3IeKzrO
|
||||
J5DxpzW+9oIRZJgPTkc4/XRb0tFmFQYTiChiQ1AJUEiCX0GpkFf7cq61aLGYtWyn
|
||||
vL2lmQhljzjrDo15hKErvk7eBZW7GW/6j/m/PfRdcBI4ceuP9zWQXnDOd9zmaE4b
|
||||
q3bJ+IbbyVZA2WwyzN7umCKWghsiPMAolxEnYM9JRf8BcqeqQiwVZlfO5KFuN6Ze
|
||||
le4=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
25
vendor/react/socket/phpunit.xml.dist
vendored
Executable file
25
vendor/react/socket/phpunit.xml.dist
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="React Test Suite">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./src/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
178
vendor/react/socket/src/Connection.php
vendored
Executable file
178
vendor/react/socket/src/Connection.php
vendored
Executable file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Stream\DuplexResourceStream;
|
||||
use React\Stream\Util;
|
||||
use React\Stream\WritableResourceStream;
|
||||
use React\Stream\WritableStreamInterface;
|
||||
|
||||
/**
|
||||
* The actual connection implementation for ConnectionInterface
|
||||
*
|
||||
* This class should only be used internally, see ConnectionInterface instead.
|
||||
*
|
||||
* @see ConnectionInterface
|
||||
* @internal
|
||||
*/
|
||||
class Connection extends EventEmitter implements ConnectionInterface
|
||||
{
|
||||
/**
|
||||
* Internal flag whether this is a Unix domain socket (UDS) connection
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public $unix = false;
|
||||
|
||||
/**
|
||||
* Internal flag whether encryption has been enabled on this connection
|
||||
*
|
||||
* Mostly used by internal StreamEncryption so that connection returns
|
||||
* `tls://` scheme for encrypted connections instead of `tcp://`.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public $encryptionEnabled = false;
|
||||
|
||||
/** @internal */
|
||||
public $stream;
|
||||
|
||||
private $input;
|
||||
|
||||
public function __construct($resource, LoopInterface $loop)
|
||||
{
|
||||
// PHP < 5.6.8 suffers from a buffer indicator bug on secure TLS connections
|
||||
// as a work-around we always read the complete buffer until its end.
|
||||
// The buffer size is limited due to TCP/IP buffers anyway, so this
|
||||
// should not affect usage otherwise.
|
||||
// See https://bugs.php.net/bug.php?id=65137
|
||||
// https://bugs.php.net/bug.php?id=41631
|
||||
// https://github.com/reactphp/socket-client/issues/24
|
||||
$clearCompleteBuffer = PHP_VERSION_ID < 50608;
|
||||
|
||||
// PHP < 7.1.4 (and PHP < 7.0.18) suffers from a bug when writing big
|
||||
// chunks of data over TLS streams at once.
|
||||
// We try to work around this by limiting the write chunk size to 8192
|
||||
// bytes for older PHP versions only.
|
||||
// This is only a work-around and has a noticable performance penalty on
|
||||
// affected versions. Please update your PHP version.
|
||||
// This applies to all streams because TLS may be enabled later on.
|
||||
// See https://github.com/reactphp/socket/issues/105
|
||||
$limitWriteChunks = (PHP_VERSION_ID < 70018 || (PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70104));
|
||||
|
||||
$this->input = new DuplexResourceStream(
|
||||
$resource,
|
||||
$loop,
|
||||
$clearCompleteBuffer ? -1 : null,
|
||||
new WritableResourceStream($resource, $loop, null, $limitWriteChunks ? 8192 : null)
|
||||
);
|
||||
|
||||
$this->stream = $resource;
|
||||
|
||||
Util::forwardEvents($this->input, $this, array('data', 'end', 'error', 'close', 'pipe', 'drain'));
|
||||
|
||||
$this->input->on('close', array($this, 'close'));
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return $this->input->isReadable();
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return $this->input->isWritable();
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
$this->input->pause();
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
$this->input->resume();
|
||||
}
|
||||
|
||||
public function pipe(WritableStreamInterface $dest, array $options = array())
|
||||
{
|
||||
return $this->input->pipe($dest, $options);
|
||||
}
|
||||
|
||||
public function write($data)
|
||||
{
|
||||
return $this->input->write($data);
|
||||
}
|
||||
|
||||
public function end($data = null)
|
||||
{
|
||||
$this->input->end($data);
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->input->close();
|
||||
$this->handleClose();
|
||||
$this->removeAllListeners();
|
||||
}
|
||||
|
||||
public function handleClose()
|
||||
{
|
||||
if (!is_resource($this->stream)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to cleanly shut down socket and ignore any errors in case other
|
||||
// side already closed. Shutting down may return to blocking mode on
|
||||
// some legacy versions, so reset to non-blocking just in case before
|
||||
// continuing to close the socket resource.
|
||||
// Underlying Stream implementation will take care of closing file
|
||||
// handle, so we otherwise keep this open here.
|
||||
@stream_socket_shutdown($this->stream, STREAM_SHUT_RDWR);
|
||||
stream_set_blocking($this->stream, false);
|
||||
}
|
||||
|
||||
public function getRemoteAddress()
|
||||
{
|
||||
return $this->parseAddress(@stream_socket_get_name($this->stream, true));
|
||||
}
|
||||
|
||||
public function getLocalAddress()
|
||||
{
|
||||
return $this->parseAddress(@stream_socket_get_name($this->stream, false));
|
||||
}
|
||||
|
||||
private function parseAddress($address)
|
||||
{
|
||||
if ($address === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->unix) {
|
||||
// remove trailing colon from address for HHVM < 3.19: https://3v4l.org/5C1lo
|
||||
// note that technically ":" is a valid address, so keep this in place otherwise
|
||||
if (substr($address, -1) === ':' && defined('HHVM_VERSION_ID') && HHVM_VERSION_ID < 31900) {
|
||||
$address = (string)substr($address, 0, -1);
|
||||
}
|
||||
|
||||
// work around unknown addresses should return null value: https://3v4l.org/5C1lo and https://bugs.php.net/bug.php?id=74556
|
||||
// PHP uses "\0" string and HHVM uses empty string (colon removed above)
|
||||
if ($address === '' || $address[0] === "\x00" ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 'unix://' . $address;
|
||||
}
|
||||
|
||||
// check if this is an IPv6 address which includes multiple colons but no square brackets
|
||||
$pos = strrpos($address, ':');
|
||||
if ($pos !== false && strpos($address, ':') < $pos && substr($address, 0, 1) !== '[') {
|
||||
$port = substr($address, $pos + 1);
|
||||
$address = '[' . substr($address, 0, $pos) . ']:' . $port;
|
||||
}
|
||||
|
||||
return ($this->encryptionEnabled ? 'tls' : 'tcp') . '://' . $address;
|
||||
}
|
||||
}
|
||||
119
vendor/react/socket/src/ConnectionInterface.php
vendored
Executable file
119
vendor/react/socket/src/ConnectionInterface.php
vendored
Executable file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\Stream\DuplexStreamInterface;
|
||||
|
||||
/**
|
||||
* Any incoming and outgoing connection is represented by this interface,
|
||||
* such as a normal TCP/IP connection.
|
||||
*
|
||||
* An incoming or outgoing connection is a duplex stream (both readable and
|
||||
* writable) that implements React's
|
||||
* [`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface).
|
||||
* It contains additional properties for the local and remote address (client IP)
|
||||
* where this connection has been established to/from.
|
||||
*
|
||||
* Most commonly, instances implementing this `ConnectionInterface` are emitted
|
||||
* by all classes implementing the [`ServerInterface`](#serverinterface) and
|
||||
* used by all classes implementing the [`ConnectorInterface`](#connectorinterface).
|
||||
*
|
||||
* Because the `ConnectionInterface` implements the underlying
|
||||
* [`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface)
|
||||
* you can use any of its events and methods as usual:
|
||||
*
|
||||
* ```php
|
||||
* $connection->on('data', function ($chunk) {
|
||||
* echo $chunk;
|
||||
* });
|
||||
*
|
||||
* $connection->on('end', function () {
|
||||
* echo 'ended';
|
||||
* });
|
||||
*
|
||||
* $connection->on('error', function (Exception $e) {
|
||||
* echo 'error: ' . $e->getMessage();
|
||||
* });
|
||||
*
|
||||
* $connection->on('close', function () {
|
||||
* echo 'closed';
|
||||
* });
|
||||
*
|
||||
* $connection->write($data);
|
||||
* $connection->end($data = null);
|
||||
* $connection->close();
|
||||
* // …
|
||||
* ```
|
||||
*
|
||||
* For more details, see the
|
||||
* [`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface).
|
||||
*
|
||||
* @see DuplexStreamInterface
|
||||
* @see ServerInterface
|
||||
* @see ConnectorInterface
|
||||
*/
|
||||
interface ConnectionInterface extends DuplexStreamInterface
|
||||
{
|
||||
/**
|
||||
* Returns the full remote address (URI) where this connection has been established with
|
||||
*
|
||||
* ```php
|
||||
* $address = $connection->getRemoteAddress();
|
||||
* echo 'Connection with ' . $address . PHP_EOL;
|
||||
* ```
|
||||
*
|
||||
* If the remote address can not be determined or is unknown at this time (such as
|
||||
* after the connection has been closed), it MAY return a `NULL` value instead.
|
||||
*
|
||||
* Otherwise, it will return the full address (URI) as a string value, such
|
||||
* as `tcp://127.0.0.1:8080`, `tcp://[::1]:80`, `tls://127.0.0.1:443`,
|
||||
* `unix://example.sock` or `unix:///path/to/example.sock`.
|
||||
* Note that individual URI components are application specific and depend
|
||||
* on the underlying transport protocol.
|
||||
*
|
||||
* If this is a TCP/IP based connection and you only want the remote IP, you may
|
||||
* use something like this:
|
||||
*
|
||||
* ```php
|
||||
* $address = $connection->getRemoteAddress();
|
||||
* $ip = trim(parse_url($address, PHP_URL_HOST), '[]');
|
||||
* echo 'Connection with ' . $ip . PHP_EOL;
|
||||
* ```
|
||||
*
|
||||
* @return ?string remote address (URI) or null if unknown
|
||||
*/
|
||||
public function getRemoteAddress();
|
||||
|
||||
/**
|
||||
* Returns the full local address (full URI with scheme, IP and port) where this connection has been established with
|
||||
*
|
||||
* ```php
|
||||
* $address = $connection->getLocalAddress();
|
||||
* echo 'Connection with ' . $address . PHP_EOL;
|
||||
* ```
|
||||
*
|
||||
* If the local address can not be determined or is unknown at this time (such as
|
||||
* after the connection has been closed), it MAY return a `NULL` value instead.
|
||||
*
|
||||
* Otherwise, it will return the full address (URI) as a string value, such
|
||||
* as `tcp://127.0.0.1:8080`, `tcp://[::1]:80`, `tls://127.0.0.1:443`,
|
||||
* `unix://example.sock` or `unix:///path/to/example.sock`.
|
||||
* Note that individual URI components are application specific and depend
|
||||
* on the underlying transport protocol.
|
||||
*
|
||||
* This method complements the [`getRemoteAddress()`](#getremoteaddress) method,
|
||||
* so they should not be confused.
|
||||
*
|
||||
* If your `TcpServer` instance is listening on multiple interfaces (e.g. using
|
||||
* the address `0.0.0.0`), you can use this method to find out which interface
|
||||
* actually accepted this connection (such as a public or local interface).
|
||||
*
|
||||
* If your system has multiple interfaces (e.g. a WAN and a LAN interface),
|
||||
* you can use this method to find out which interface was actually
|
||||
* used for this connection.
|
||||
*
|
||||
* @return ?string local address (URI) or null if unknown
|
||||
* @see self::getRemoteAddress()
|
||||
*/
|
||||
public function getLocalAddress();
|
||||
}
|
||||
136
vendor/react/socket/src/Connector.php
vendored
Executable file
136
vendor/react/socket/src/Connector.php
vendored
Executable file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\Dns\Config\Config;
|
||||
use React\Dns\Resolver\Factory;
|
||||
use React\Dns\Resolver\Resolver;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* The `Connector` class is the main class in this package that implements the
|
||||
* `ConnectorInterface` and allows you to create streaming connections.
|
||||
*
|
||||
* You can use this connector to create any kind of streaming connections, such
|
||||
* as plaintext TCP/IP, secure TLS or local Unix connection streams.
|
||||
*
|
||||
* Under the hood, the `Connector` is implemented as a *higher-level facade*
|
||||
* or the lower-level connectors implemented in this package. This means it
|
||||
* also shares all of their features and implementation details.
|
||||
* If you want to typehint in your higher-level protocol implementation, you SHOULD
|
||||
* use the generic [`ConnectorInterface`](#connectorinterface) instead.
|
||||
*
|
||||
* @see ConnectorInterface for the base interface
|
||||
*/
|
||||
final class Connector implements ConnectorInterface
|
||||
{
|
||||
private $connectors = array();
|
||||
|
||||
public function __construct(LoopInterface $loop, array $options = array())
|
||||
{
|
||||
// apply default options if not explicitly given
|
||||
$options += array(
|
||||
'tcp' => true,
|
||||
'tls' => true,
|
||||
'unix' => true,
|
||||
|
||||
'dns' => true,
|
||||
'timeout' => true,
|
||||
);
|
||||
|
||||
if ($options['timeout'] === true) {
|
||||
$options['timeout'] = (float)ini_get("default_socket_timeout");
|
||||
}
|
||||
|
||||
if ($options['tcp'] instanceof ConnectorInterface) {
|
||||
$tcp = $options['tcp'];
|
||||
} else {
|
||||
$tcp = new TcpConnector(
|
||||
$loop,
|
||||
is_array($options['tcp']) ? $options['tcp'] : array()
|
||||
);
|
||||
}
|
||||
|
||||
if ($options['dns'] !== false) {
|
||||
if ($options['dns'] instanceof Resolver) {
|
||||
$resolver = $options['dns'];
|
||||
} else {
|
||||
if ($options['dns'] !== true) {
|
||||
$server = $options['dns'];
|
||||
} else {
|
||||
// try to load nameservers from system config or default to Google's public DNS
|
||||
$config = Config::loadSystemConfigBlocking();
|
||||
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
|
||||
}
|
||||
|
||||
$factory = new Factory();
|
||||
$resolver = $factory->create(
|
||||
$server,
|
||||
$loop
|
||||
);
|
||||
}
|
||||
|
||||
$tcp = new DnsConnector($tcp, $resolver);
|
||||
}
|
||||
|
||||
if ($options['tcp'] !== false) {
|
||||
$options['tcp'] = $tcp;
|
||||
|
||||
if ($options['timeout'] !== false) {
|
||||
$options['tcp'] = new TimeoutConnector(
|
||||
$options['tcp'],
|
||||
$options['timeout'],
|
||||
$loop
|
||||
);
|
||||
}
|
||||
|
||||
$this->connectors['tcp'] = $options['tcp'];
|
||||
}
|
||||
|
||||
if ($options['tls'] !== false) {
|
||||
if (!$options['tls'] instanceof ConnectorInterface) {
|
||||
$options['tls'] = new SecureConnector(
|
||||
$tcp,
|
||||
$loop,
|
||||
is_array($options['tls']) ? $options['tls'] : array()
|
||||
);
|
||||
}
|
||||
|
||||
if ($options['timeout'] !== false) {
|
||||
$options['tls'] = new TimeoutConnector(
|
||||
$options['tls'],
|
||||
$options['timeout'],
|
||||
$loop
|
||||
);
|
||||
}
|
||||
|
||||
$this->connectors['tls'] = $options['tls'];
|
||||
}
|
||||
|
||||
if ($options['unix'] !== false) {
|
||||
if (!$options['unix'] instanceof ConnectorInterface) {
|
||||
$options['unix'] = new UnixConnector($loop);
|
||||
}
|
||||
$this->connectors['unix'] = $options['unix'];
|
||||
}
|
||||
}
|
||||
|
||||
public function connect($uri)
|
||||
{
|
||||
$scheme = 'tcp';
|
||||
if (strpos($uri, '://') !== false) {
|
||||
$scheme = (string)substr($uri, 0, strpos($uri, '://'));
|
||||
}
|
||||
|
||||
if (!isset($this->connectors[$scheme])) {
|
||||
return Promise\reject(new RuntimeException(
|
||||
'No connector available for URI scheme "' . $scheme . '"'
|
||||
));
|
||||
}
|
||||
|
||||
return $this->connectors[$scheme]->connect($uri);
|
||||
}
|
||||
}
|
||||
|
||||
58
vendor/react/socket/src/ConnectorInterface.php
vendored
Executable file
58
vendor/react/socket/src/ConnectorInterface.php
vendored
Executable file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
/**
|
||||
* The `ConnectorInterface` is responsible for providing an interface for
|
||||
* establishing streaming connections, such as a normal TCP/IP connection.
|
||||
*
|
||||
* This is the main interface defined in this package and it is used throughout
|
||||
* React's vast ecosystem.
|
||||
*
|
||||
* Most higher-level components (such as HTTP, database or other networking
|
||||
* service clients) accept an instance implementing this interface to create their
|
||||
* TCP/IP connection to the underlying networking service.
|
||||
* This is usually done via dependency injection, so it's fairly simple to actually
|
||||
* swap this implementation against any other implementation of this interface.
|
||||
*
|
||||
* The interface only offers a single `connect()` method.
|
||||
*
|
||||
* @see ConnectionInterface
|
||||
*/
|
||||
interface ConnectorInterface
|
||||
{
|
||||
/**
|
||||
* Creates a streaming connection to the given remote address
|
||||
*
|
||||
* If returns a Promise which either fulfills with a stream implementing
|
||||
* `ConnectionInterface` on success or rejects with an `Exception` if the
|
||||
* connection is not successful.
|
||||
*
|
||||
* ```php
|
||||
* $connector->connect('google.com:443')->then(
|
||||
* function (ConnectionInterface $connection) {
|
||||
* // connection successfully established
|
||||
* },
|
||||
* function (Exception $error) {
|
||||
* // failed to connect due to $error
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* The returned Promise MUST be implemented in such a way that it can be
|
||||
* cancelled when it is still pending. Cancelling a pending promise MUST
|
||||
* reject its value with an Exception. It SHOULD clean up any underlying
|
||||
* resources and references as applicable.
|
||||
*
|
||||
* ```php
|
||||
* $promise = $connector->connect($uri);
|
||||
*
|
||||
* $promise->cancel();
|
||||
* ```
|
||||
*
|
||||
* @param string $uri
|
||||
* @return \React\Promise\PromiseInterface resolves with a stream implementing ConnectionInterface on success or rejects with an Exception on error
|
||||
* @see ConnectionInterface
|
||||
*/
|
||||
public function connect($uri);
|
||||
}
|
||||
112
vendor/react/socket/src/DnsConnector.php
vendored
Executable file
112
vendor/react/socket/src/DnsConnector.php
vendored
Executable file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\Dns\Resolver\Resolver;
|
||||
use React\Promise;
|
||||
use React\Promise\CancellablePromiseInterface;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
final class DnsConnector implements ConnectorInterface
|
||||
{
|
||||
private $connector;
|
||||
private $resolver;
|
||||
|
||||
public function __construct(ConnectorInterface $connector, Resolver $resolver)
|
||||
{
|
||||
$this->connector = $connector;
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
public function connect($uri)
|
||||
{
|
||||
if (strpos($uri, '://') === false) {
|
||||
$parts = parse_url('tcp://' . $uri);
|
||||
unset($parts['scheme']);
|
||||
} else {
|
||||
$parts = parse_url($uri);
|
||||
}
|
||||
|
||||
if (!$parts || !isset($parts['host'])) {
|
||||
return Promise\reject(new InvalidArgumentException('Given URI "' . $uri . '" is invalid'));
|
||||
}
|
||||
|
||||
$host = trim($parts['host'], '[]');
|
||||
$connector = $this->connector;
|
||||
|
||||
// skip DNS lookup / URI manipulation if this URI already contains an IP
|
||||
if (false !== filter_var($host, FILTER_VALIDATE_IP)) {
|
||||
return $connector->connect($uri);
|
||||
}
|
||||
|
||||
return $this
|
||||
->resolveHostname($host)
|
||||
->then(function ($ip) use ($connector, $host, $parts) {
|
||||
$uri = '';
|
||||
|
||||
// prepend original scheme if known
|
||||
if (isset($parts['scheme'])) {
|
||||
$uri .= $parts['scheme'] . '://';
|
||||
}
|
||||
|
||||
if (strpos($ip, ':') !== false) {
|
||||
// enclose IPv6 addresses in square brackets before appending port
|
||||
$uri .= '[' . $ip . ']';
|
||||
} else {
|
||||
$uri .= $ip;
|
||||
}
|
||||
|
||||
// append original port if known
|
||||
if (isset($parts['port'])) {
|
||||
$uri .= ':' . $parts['port'];
|
||||
}
|
||||
|
||||
// append orignal path if known
|
||||
if (isset($parts['path'])) {
|
||||
$uri .= $parts['path'];
|
||||
}
|
||||
|
||||
// append original query if known
|
||||
if (isset($parts['query'])) {
|
||||
$uri .= '?' . $parts['query'];
|
||||
}
|
||||
|
||||
// append original hostname as query if resolved via DNS and if
|
||||
// destination URI does not contain "hostname" query param already
|
||||
$args = array();
|
||||
parse_str(isset($parts['query']) ? $parts['query'] : '', $args);
|
||||
if ($host !== $ip && !isset($args['hostname'])) {
|
||||
$uri .= (isset($parts['query']) ? '&' : '?') . 'hostname=' . rawurlencode($host);
|
||||
}
|
||||
|
||||
// append original fragment if known
|
||||
if (isset($parts['fragment'])) {
|
||||
$uri .= '#' . $parts['fragment'];
|
||||
}
|
||||
|
||||
return $connector->connect($uri);
|
||||
});
|
||||
}
|
||||
|
||||
private function resolveHostname($host)
|
||||
{
|
||||
$promise = $this->resolver->resolve($host);
|
||||
|
||||
return new Promise\Promise(
|
||||
function ($resolve, $reject) use ($promise) {
|
||||
// resolve/reject with result of DNS lookup
|
||||
$promise->then($resolve, $reject);
|
||||
},
|
||||
function ($_, $reject) use ($promise) {
|
||||
// cancellation should reject connection attempt
|
||||
$reject(new RuntimeException('Connection attempt cancelled during DNS lookup'));
|
||||
|
||||
// (try to) cancel pending DNS lookup
|
||||
if ($promise instanceof CancellablePromiseInterface) {
|
||||
$promise->cancel();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
41
vendor/react/socket/src/FixedUriConnector.php
vendored
Executable file
41
vendor/react/socket/src/FixedUriConnector.php
vendored
Executable file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
/**
|
||||
* Decorates an existing Connector to always use a fixed, preconfigured URI
|
||||
*
|
||||
* This can be useful for consumers that do not support certain URIs, such as
|
||||
* when you want to explicitly connect to a Unix domain socket (UDS) path
|
||||
* instead of connecting to a default address assumed by an higher-level API:
|
||||
*
|
||||
* ```php
|
||||
* $connector = new FixedUriConnector(
|
||||
* 'unix:///var/run/docker.sock',
|
||||
* new UnixConnector($loop)
|
||||
* );
|
||||
*
|
||||
* // destination will be ignored, actually connects to Unix domain socket
|
||||
* $promise = $connector->connect('localhost:80');
|
||||
* ```
|
||||
*/
|
||||
class FixedUriConnector implements ConnectorInterface
|
||||
{
|
||||
private $uri;
|
||||
private $connector;
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param ConnectorInterface $connector
|
||||
*/
|
||||
public function __construct($uri, ConnectorInterface $connector)
|
||||
{
|
||||
$this->uri = $uri;
|
||||
$this->connector = $connector;
|
||||
}
|
||||
|
||||
public function connect($_)
|
||||
{
|
||||
return $this->connector->connect($this->uri);
|
||||
}
|
||||
}
|
||||
203
vendor/react/socket/src/LimitingServer.php
vendored
Executable file
203
vendor/react/socket/src/LimitingServer.php
vendored
Executable file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use Exception;
|
||||
use OverflowException;
|
||||
|
||||
/**
|
||||
* The `LimitingServer` decorator wraps a given `ServerInterface` and is responsible
|
||||
* for limiting and keeping track of open connections to this server instance.
|
||||
*
|
||||
* Whenever the underlying server emits a `connection` event, it will check its
|
||||
* limits and then either
|
||||
* - keep track of this connection by adding it to the list of
|
||||
* open connections and then forward the `connection` event
|
||||
* - or reject (close) the connection when its limits are exceeded and will
|
||||
* forward an `error` event instead.
|
||||
*
|
||||
* Whenever a connection closes, it will remove this connection from the list of
|
||||
* open connections.
|
||||
*
|
||||
* ```php
|
||||
* $server = new LimitingServer($server, 100);
|
||||
* $server->on('connection', function (ConnectionInterface $connection) {
|
||||
* $connection->write('hello there!' . PHP_EOL);
|
||||
* …
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* See also the `ServerInterface` for more details.
|
||||
*
|
||||
* @see ServerInterface
|
||||
* @see ConnectionInterface
|
||||
*/
|
||||
class LimitingServer extends EventEmitter implements ServerInterface
|
||||
{
|
||||
private $connections = array();
|
||||
private $server;
|
||||
private $limit;
|
||||
|
||||
private $pauseOnLimit = false;
|
||||
private $autoPaused = false;
|
||||
private $manuPaused = false;
|
||||
|
||||
/**
|
||||
* Instantiates a new LimitingServer.
|
||||
*
|
||||
* You have to pass a maximum number of open connections to ensure
|
||||
* the server will automatically reject (close) connections once this limit
|
||||
* is exceeded. In this case, it will emit an `error` event to inform about
|
||||
* this and no `connection` event will be emitted.
|
||||
*
|
||||
* ```php
|
||||
* $server = new LimitingServer($server, 100);
|
||||
* $server->on('connection', function (ConnectionInterface $connection) {
|
||||
* $connection->write('hello there!' . PHP_EOL);
|
||||
* …
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* You MAY pass a `null` limit in order to put no limit on the number of
|
||||
* open connections and keep accepting new connection until you run out of
|
||||
* operating system resources (such as open file handles). This may be
|
||||
* useful if you do not want to take care of applying a limit but still want
|
||||
* to use the `getConnections()` method.
|
||||
*
|
||||
* You can optionally configure the server to pause accepting new
|
||||
* connections once the connection limit is reached. In this case, it will
|
||||
* pause the underlying server and no longer process any new connections at
|
||||
* all, thus also no longer closing any excessive connections.
|
||||
* The underlying operating system is responsible for keeping a backlog of
|
||||
* pending connections until its limit is reached, at which point it will
|
||||
* start rejecting further connections.
|
||||
* Once the server is below the connection limit, it will continue consuming
|
||||
* connections from the backlog and will process any outstanding data on
|
||||
* each connection.
|
||||
* This mode may be useful for some protocols that are designed to wait for
|
||||
* a response message (such as HTTP), but may be less useful for other
|
||||
* protocols that demand immediate responses (such as a "welcome" message in
|
||||
* an interactive chat).
|
||||
*
|
||||
* ```php
|
||||
* $server = new LimitingServer($server, 100, true);
|
||||
* $server->on('connection', function (ConnectionInterface $connection) {
|
||||
* $connection->write('hello there!' . PHP_EOL);
|
||||
* …
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param ServerInterface $server
|
||||
* @param int|null $connectionLimit
|
||||
* @param bool $pauseOnLimit
|
||||
*/
|
||||
public function __construct(ServerInterface $server, $connectionLimit, $pauseOnLimit = false)
|
||||
{
|
||||
$this->server = $server;
|
||||
$this->limit = $connectionLimit;
|
||||
if ($connectionLimit !== null) {
|
||||
$this->pauseOnLimit = $pauseOnLimit;
|
||||
}
|
||||
|
||||
$this->server->on('connection', array($this, 'handleConnection'));
|
||||
$this->server->on('error', array($this, 'handleError'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all currently active connections
|
||||
*
|
||||
* ```php
|
||||
* foreach ($server->getConnection() as $connection) {
|
||||
* $connection->write('Hi!');
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @return ConnectionInterface[]
|
||||
*/
|
||||
public function getConnections()
|
||||
{
|
||||
return $this->connections;
|
||||
}
|
||||
|
||||
public function getAddress()
|
||||
{
|
||||
return $this->server->getAddress();
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
if (!$this->manuPaused) {
|
||||
$this->manuPaused = true;
|
||||
|
||||
if (!$this->autoPaused) {
|
||||
$this->server->pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
if ($this->manuPaused) {
|
||||
$this->manuPaused = false;
|
||||
|
||||
if (!$this->autoPaused) {
|
||||
$this->server->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->server->close();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function handleConnection(ConnectionInterface $connection)
|
||||
{
|
||||
// close connection if limit exceeded
|
||||
if ($this->limit !== null && count($this->connections) >= $this->limit) {
|
||||
$this->handleError(new OverflowException('Connection closed because server reached connection limit'));
|
||||
$connection->close();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->connections[] = $connection;
|
||||
$that = $this;
|
||||
$connection->on('close', function () use ($that, $connection) {
|
||||
$that->handleDisconnection($connection);
|
||||
});
|
||||
|
||||
// pause accepting new connections if limit exceeded
|
||||
if ($this->pauseOnLimit && !$this->autoPaused && count($this->connections) >= $this->limit) {
|
||||
$this->autoPaused = true;
|
||||
|
||||
if (!$this->manuPaused) {
|
||||
$this->server->pause();
|
||||
}
|
||||
}
|
||||
|
||||
$this->emit('connection', array($connection));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function handleDisconnection(ConnectionInterface $connection)
|
||||
{
|
||||
unset($this->connections[array_search($connection, $this->connections)]);
|
||||
|
||||
// continue accepting new connection if below limit
|
||||
if ($this->autoPaused && count($this->connections) < $this->limit) {
|
||||
$this->autoPaused = false;
|
||||
|
||||
if (!$this->manuPaused) {
|
||||
$this->server->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function handleError(Exception $error)
|
||||
{
|
||||
$this->emit('error', array($error));
|
||||
}
|
||||
}
|
||||
64
vendor/react/socket/src/SecureConnector.php
vendored
Executable file
64
vendor/react/socket/src/SecureConnector.php
vendored
Executable file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise;
|
||||
use BadMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
final class SecureConnector implements ConnectorInterface
|
||||
{
|
||||
private $connector;
|
||||
private $streamEncryption;
|
||||
private $context;
|
||||
|
||||
public function __construct(ConnectorInterface $connector, LoopInterface $loop, array $context = array())
|
||||
{
|
||||
$this->connector = $connector;
|
||||
$this->streamEncryption = new StreamEncryption($loop, false);
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function connect($uri)
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
return Promise\reject(new BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)')); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
if (strpos($uri, '://') === false) {
|
||||
$uri = 'tls://' . $uri;
|
||||
}
|
||||
|
||||
$parts = parse_url($uri);
|
||||
if (!$parts || !isset($parts['scheme']) || $parts['scheme'] !== 'tls') {
|
||||
return Promise\reject(new InvalidArgumentException('Given URI "' . $uri . '" is invalid'));
|
||||
}
|
||||
|
||||
$uri = str_replace('tls://', '', $uri);
|
||||
$context = $this->context;
|
||||
|
||||
$encryption = $this->streamEncryption;
|
||||
return $this->connector->connect($uri)->then(function (ConnectionInterface $connection) use ($context, $encryption) {
|
||||
// (unencrypted) TCP/IP connection succeeded
|
||||
|
||||
if (!$connection instanceof Connection) {
|
||||
$connection->close();
|
||||
throw new UnexpectedValueException('Base connector does not use internal Connection class exposing stream resource');
|
||||
}
|
||||
|
||||
// set required SSL/TLS context options
|
||||
foreach ($context as $name => $value) {
|
||||
stream_context_set_option($connection->stream, 'ssl', $name, $value);
|
||||
}
|
||||
|
||||
// try to enable encryption
|
||||
return $encryption->enable($connection)->then(null, function ($error) use ($connection) {
|
||||
// establishing encryption failed => close invalid connection and return error
|
||||
$connection->close();
|
||||
throw $error;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
192
vendor/react/socket/src/SecureServer.php
vendored
Executable file
192
vendor/react/socket/src/SecureServer.php
vendored
Executable file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use BadMethodCallException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* The `SecureServer` class implements the `ServerInterface` and is responsible
|
||||
* for providing a secure TLS (formerly known as SSL) server.
|
||||
*
|
||||
* It does so by wrapping a `TcpServer` instance which waits for plaintext
|
||||
* TCP/IP connections and then performs a TLS handshake for each connection.
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer(8000, $loop);
|
||||
* $server = new SecureServer($server, $loop, array(
|
||||
* // tls context options here…
|
||||
* ));
|
||||
* ```
|
||||
*
|
||||
* Whenever a client completes the TLS handshake, it will emit a `connection` event
|
||||
* with a connection instance implementing [`ConnectionInterface`](#connectioninterface):
|
||||
*
|
||||
* ```php
|
||||
* $server->on('connection', function (ConnectionInterface $connection) {
|
||||
* echo 'Secure connection from' . $connection->getRemoteAddress() . PHP_EOL;
|
||||
*
|
||||
* $connection->write('hello there!' . PHP_EOL);
|
||||
* …
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Whenever a client fails to perform a successful TLS handshake, it will emit an
|
||||
* `error` event and then close the underlying TCP/IP connection:
|
||||
*
|
||||
* ```php
|
||||
* $server->on('error', function (Exception $e) {
|
||||
* echo 'Error' . $e->getMessage() . PHP_EOL;
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* See also the `ServerInterface` for more details.
|
||||
*
|
||||
* Note that the `SecureServer` class is a concrete implementation for TLS sockets.
|
||||
* If you want to typehint in your higher-level protocol implementation, you SHOULD
|
||||
* use the generic `ServerInterface` instead.
|
||||
*
|
||||
* @see ServerInterface
|
||||
* @see ConnectionInterface
|
||||
*/
|
||||
final class SecureServer extends EventEmitter implements ServerInterface
|
||||
{
|
||||
private $tcp;
|
||||
private $encryption;
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* Creates a secure TLS server and starts waiting for incoming connections
|
||||
*
|
||||
* It does so by wrapping a `TcpServer` instance which waits for plaintext
|
||||
* TCP/IP connections and then performs a TLS handshake for each connection.
|
||||
* It thus requires valid [TLS context options],
|
||||
* which in its most basic form may look something like this if you're using a
|
||||
* PEM encoded certificate file:
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer(8000, $loop);
|
||||
* $server = new SecureServer($server, $loop, array(
|
||||
* 'local_cert' => 'server.pem'
|
||||
* ));
|
||||
* ```
|
||||
*
|
||||
* Note that the certificate file will not be loaded on instantiation but when an
|
||||
* incoming connection initializes its TLS context.
|
||||
* This implies that any invalid certificate file paths or contents will only cause
|
||||
* an `error` event at a later time.
|
||||
*
|
||||
* If your private key is encrypted with a passphrase, you have to specify it
|
||||
* like this:
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer(8000, $loop);
|
||||
* $server = new SecureServer($server, $loop, array(
|
||||
* 'local_cert' => 'server.pem',
|
||||
* 'passphrase' => 'secret'
|
||||
* ));
|
||||
* ```
|
||||
*
|
||||
* Note that available [TLS context options],
|
||||
* their defaults and effects of changing these may vary depending on your system
|
||||
* and/or PHP version.
|
||||
* Passing unknown context options has no effect.
|
||||
*
|
||||
* Advanced usage: Despite allowing any `ServerInterface` as first parameter,
|
||||
* you SHOULD pass a `TcpServer` instance as first parameter, unless you
|
||||
* know what you're doing.
|
||||
* Internally, the `SecureServer` has to set the required TLS context options on
|
||||
* the underlying stream resources.
|
||||
* These resources are not exposed through any of the interfaces defined in this
|
||||
* package, but only through the internal `Connection` class.
|
||||
* The `TcpServer` class is guaranteed to emit connections that implement
|
||||
* the `ConnectionInterface` and uses the internal `Connection` class in order to
|
||||
* expose these underlying resources.
|
||||
* If you use a custom `ServerInterface` and its `connection` event does not
|
||||
* meet this requirement, the `SecureServer` will emit an `error` event and
|
||||
* then close the underlying connection.
|
||||
*
|
||||
* @param ServerInterface|TcpServer $tcp
|
||||
* @param LoopInterface $loop
|
||||
* @param array $context
|
||||
* @throws BadMethodCallException for legacy HHVM < 3.8 due to lack of support
|
||||
* @see TcpServer
|
||||
* @link http://php.net/manual/en/context.ssl.php for TLS context options
|
||||
*/
|
||||
public function __construct(ServerInterface $tcp, LoopInterface $loop, array $context)
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
throw new BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// default to empty passphrase to suppress blocking passphrase prompt
|
||||
$context += array(
|
||||
'passphrase' => ''
|
||||
);
|
||||
|
||||
$this->tcp = $tcp;
|
||||
$this->encryption = new StreamEncryption($loop);
|
||||
$this->context = $context;
|
||||
|
||||
$that = $this;
|
||||
$this->tcp->on('connection', function ($connection) use ($that) {
|
||||
$that->handleConnection($connection);
|
||||
});
|
||||
$this->tcp->on('error', function ($error) use ($that) {
|
||||
$that->emit('error', array($error));
|
||||
});
|
||||
}
|
||||
|
||||
public function getAddress()
|
||||
{
|
||||
$address = $this->tcp->getAddress();
|
||||
if ($address === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return str_replace('tcp://' , 'tls://', $address);
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
$this->tcp->pause();
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
$this->tcp->resume();
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
return $this->tcp->close();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function handleConnection(ConnectionInterface $connection)
|
||||
{
|
||||
if (!$connection instanceof Connection) {
|
||||
$this->emit('error', array(new UnexpectedValueException('Base server does not use internal Connection class exposing stream resource')));
|
||||
$connection->end();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->context as $name => $value) {
|
||||
stream_context_set_option($connection->stream, 'ssl', $name, $value);
|
||||
}
|
||||
|
||||
$that = $this;
|
||||
|
||||
$this->encryption->enable($connection)->then(
|
||||
function ($conn) use ($that) {
|
||||
$that->emit('connection', array($conn));
|
||||
},
|
||||
function ($error) use ($that, $connection) {
|
||||
$that->emit('error', array($error));
|
||||
$connection->end();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
73
vendor/react/socket/src/Server.php
vendored
Executable file
73
vendor/react/socket/src/Server.php
vendored
Executable file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use Exception;
|
||||
|
||||
final class Server extends EventEmitter implements ServerInterface
|
||||
{
|
||||
private $server;
|
||||
|
||||
public function __construct($uri, LoopInterface $loop, array $context = array())
|
||||
{
|
||||
// sanitize TCP context options if not properly wrapped
|
||||
if ($context && (!isset($context['tcp']) && !isset($context['tls']) && !isset($context['unix']))) {
|
||||
$context = array('tcp' => $context);
|
||||
}
|
||||
|
||||
// apply default options if not explicitly given
|
||||
$context += array(
|
||||
'tcp' => array(),
|
||||
'tls' => array(),
|
||||
'unix' => array()
|
||||
);
|
||||
|
||||
$scheme = 'tcp';
|
||||
$pos = strpos($uri, '://');
|
||||
if ($pos !== false) {
|
||||
$scheme = substr($uri, 0, $pos);
|
||||
}
|
||||
|
||||
if ($scheme === 'unix') {
|
||||
$server = new UnixServer($uri, $loop, $context['unix']);
|
||||
} else {
|
||||
$server = new TcpServer(str_replace('tls://', '', $uri), $loop, $context['tcp']);
|
||||
|
||||
if ($scheme === 'tls') {
|
||||
$server = new SecureServer($server, $loop, $context['tls']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->server = $server;
|
||||
|
||||
$that = $this;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use ($that) {
|
||||
$that->emit('connection', array($conn));
|
||||
});
|
||||
$server->on('error', function (Exception $error) use ($that) {
|
||||
$that->emit('error', array($error));
|
||||
});
|
||||
}
|
||||
|
||||
public function getAddress()
|
||||
{
|
||||
return $this->server->getAddress();
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
$this->server->pause();
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
$this->server->resume();
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->server->close();
|
||||
}
|
||||
}
|
||||
151
vendor/react/socket/src/ServerInterface.php
vendored
Executable file
151
vendor/react/socket/src/ServerInterface.php
vendored
Executable file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use Evenement\EventEmitterInterface;
|
||||
|
||||
/**
|
||||
* The `ServerInterface` is responsible for providing an interface for accepting
|
||||
* incoming streaming connections, such as a normal TCP/IP connection.
|
||||
*
|
||||
* Most higher-level components (such as a HTTP server) accept an instance
|
||||
* implementing this interface to accept incoming streaming connections.
|
||||
* This is usually done via dependency injection, so it's fairly simple to actually
|
||||
* swap this implementation against any other implementation of this interface.
|
||||
* This means that you SHOULD typehint against this interface instead of a concrete
|
||||
* implementation of this interface.
|
||||
*
|
||||
* Besides defining a few methods, this interface also implements the
|
||||
* `EventEmitterInterface` which allows you to react to certain events:
|
||||
*
|
||||
* connection event:
|
||||
* The `connection` event will be emitted whenever a new connection has been
|
||||
* established, i.e. a new client connects to this server socket:
|
||||
*
|
||||
* ```php
|
||||
* $server->on('connection', function (ConnectionInterface $connection) {
|
||||
* echo 'new connection' . PHP_EOL;
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* See also the `ConnectionInterface` for more details about handling the
|
||||
* incoming connection.
|
||||
*
|
||||
* error event:
|
||||
* The `error` event will be emitted whenever there's an error accepting a new
|
||||
* connection from a client.
|
||||
*
|
||||
* ```php
|
||||
* $server->on('error', function (Exception $e) {
|
||||
* echo 'error: ' . $e->getMessage() . PHP_EOL;
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Note that this is not a fatal error event, i.e. the server keeps listening for
|
||||
* new connections even after this event.
|
||||
*
|
||||
* @see ConnectionInterface
|
||||
*/
|
||||
interface ServerInterface extends EventEmitterInterface
|
||||
{
|
||||
/**
|
||||
* Returns the full address (URI) this server is currently listening on
|
||||
*
|
||||
* ```php
|
||||
* $address = $server->getAddress();
|
||||
* echo 'Server listening on ' . $address . PHP_EOL;
|
||||
* ```
|
||||
*
|
||||
* If the address can not be determined or is unknown at this time (such as
|
||||
* after the socket has been closed), it MAY return a `NULL` value instead.
|
||||
*
|
||||
* Otherwise, it will return the full address (URI) as a string value, such
|
||||
* as `tcp://127.0.0.1:8080`, `tcp://[::1]:80` or `tls://127.0.0.1:443`.
|
||||
* Note that individual URI components are application specific and depend
|
||||
* on the underlying transport protocol.
|
||||
*
|
||||
* If this is a TCP/IP based server and you only want the local port, you may
|
||||
* use something like this:
|
||||
*
|
||||
* ```php
|
||||
* $address = $server->getAddress();
|
||||
* $port = parse_url($address, PHP_URL_PORT);
|
||||
* echo 'Server listening on port ' . $port . PHP_EOL;
|
||||
* ```
|
||||
*
|
||||
* @return ?string the full listening address (URI) or NULL if it is unknown (not applicable to this server socket or already closed)
|
||||
*/
|
||||
public function getAddress();
|
||||
|
||||
/**
|
||||
* Pauses accepting new incoming connections.
|
||||
*
|
||||
* Removes the socket resource from the EventLoop and thus stop accepting
|
||||
* new connections. Note that the listening socket stays active and is not
|
||||
* closed.
|
||||
*
|
||||
* This means that new incoming connections will stay pending in the
|
||||
* operating system backlog until its configurable backlog is filled.
|
||||
* Once the backlog is filled, the operating system may reject further
|
||||
* incoming connections until the backlog is drained again by resuming
|
||||
* to accept new connections.
|
||||
*
|
||||
* Once the server is paused, no futher `connection` events SHOULD
|
||||
* be emitted.
|
||||
*
|
||||
* ```php
|
||||
* $server->pause();
|
||||
*
|
||||
* $server->on('connection', assertShouldNeverCalled());
|
||||
* ```
|
||||
*
|
||||
* This method is advisory-only, though generally not recommended, the
|
||||
* server MAY continue emitting `connection` events.
|
||||
*
|
||||
* Unless otherwise noted, a successfully opened server SHOULD NOT start
|
||||
* in paused state.
|
||||
*
|
||||
* You can continue processing events by calling `resume()` again.
|
||||
*
|
||||
* Note that both methods can be called any number of times, in particular
|
||||
* calling `pause()` more than once SHOULD NOT have any effect.
|
||||
* Similarly, calling this after `close()` is a NO-OP.
|
||||
*
|
||||
* @see self::resume()
|
||||
* @return void
|
||||
*/
|
||||
public function pause();
|
||||
|
||||
/**
|
||||
* Resumes accepting new incoming connections.
|
||||
*
|
||||
* Re-attach the socket resource to the EventLoop after a previous `pause()`.
|
||||
*
|
||||
* ```php
|
||||
* $server->pause();
|
||||
*
|
||||
* $loop->addTimer(1.0, function () use ($server) {
|
||||
* $server->resume();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Note that both methods can be called any number of times, in particular
|
||||
* calling `resume()` without a prior `pause()` SHOULD NOT have any effect.
|
||||
* Similarly, calling this after `close()` is a NO-OP.
|
||||
*
|
||||
* @see self::pause()
|
||||
* @return void
|
||||
*/
|
||||
public function resume();
|
||||
|
||||
/**
|
||||
* Shuts down this listening socket
|
||||
*
|
||||
* This will stop listening for new incoming connections on this socket.
|
||||
*
|
||||
* Calling this method more than once on the same instance is a NO-OP.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close();
|
||||
}
|
||||
146
vendor/react/socket/src/StreamEncryption.php
vendored
Executable file
146
vendor/react/socket/src/StreamEncryption.php
vendored
Executable file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise\Deferred;
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* This class is considered internal and its API should not be relied upon
|
||||
* outside of Socket.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class StreamEncryption
|
||||
{
|
||||
private $loop;
|
||||
private $method;
|
||||
private $server;
|
||||
|
||||
private $errstr;
|
||||
private $errno;
|
||||
|
||||
public function __construct(LoopInterface $loop, $server = true)
|
||||
{
|
||||
$this->loop = $loop;
|
||||
$this->server = $server;
|
||||
|
||||
// support TLSv1.0+ by default and exclude legacy SSLv2/SSLv3.
|
||||
// PHP 5.6+ supports bitmasks, legacy PHP only supports predefined
|
||||
// constants, so apply accordingly below.
|
||||
// Also, since PHP 5.6.7 up until before PHP 7.2.0 the main constant did
|
||||
// only support TLSv1.0, so we explicitly apply all versions.
|
||||
// @link http://php.net/manual/en/migration56.openssl.php#migration56.openssl.crypto-method
|
||||
// @link https://3v4l.org/plbFn
|
||||
if ($server) {
|
||||
$this->method = STREAM_CRYPTO_METHOD_TLS_SERVER;
|
||||
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_0_SERVER')) {
|
||||
$this->method |= STREAM_CRYPTO_METHOD_TLSv1_0_SERVER;
|
||||
}
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_1_SERVER')) {
|
||||
$this->method |= STREAM_CRYPTO_METHOD_TLSv1_1_SERVER;
|
||||
}
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_SERVER')) {
|
||||
$this->method |= STREAM_CRYPTO_METHOD_TLSv1_2_SERVER;
|
||||
}
|
||||
} else {
|
||||
$this->method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
||||
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT')) {
|
||||
$this->method |= STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT;
|
||||
}
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT')) {
|
||||
$this->method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
|
||||
}
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
|
||||
$this->method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function enable(Connection $stream)
|
||||
{
|
||||
return $this->toggle($stream, true);
|
||||
}
|
||||
|
||||
public function disable(Connection $stream)
|
||||
{
|
||||
return $this->toggle($stream, false);
|
||||
}
|
||||
|
||||
public function toggle(Connection $stream, $toggle)
|
||||
{
|
||||
// pause actual stream instance to continue operation on raw stream socket
|
||||
$stream->pause();
|
||||
|
||||
// TODO: add write() event to make sure we're not sending any excessive data
|
||||
|
||||
$deferred = new Deferred(function ($_, $reject) use ($toggle) {
|
||||
// cancelling this leaves this stream in an inconsistent state…
|
||||
$reject(new RuntimeException('Cancelled toggling encryption ' . $toggle ? 'on' : 'off'));
|
||||
});
|
||||
|
||||
// get actual stream socket from stream instance
|
||||
$socket = $stream->stream;
|
||||
|
||||
// get crypto method from context options or use global setting from constructor
|
||||
$method = $this->method;
|
||||
$context = stream_context_get_options($socket);
|
||||
if (isset($context['ssl']['crypto_method'])) {
|
||||
$method = $context['ssl']['crypto_method'];
|
||||
}
|
||||
|
||||
$that = $this;
|
||||
$toggleCrypto = function () use ($socket, $deferred, $toggle, $method, $that) {
|
||||
$that->toggleCrypto($socket, $deferred, $toggle, $method);
|
||||
};
|
||||
|
||||
$this->loop->addReadStream($socket, $toggleCrypto);
|
||||
|
||||
if (!$this->server) {
|
||||
$toggleCrypto();
|
||||
}
|
||||
|
||||
$loop = $this->loop;
|
||||
|
||||
return $deferred->promise()->then(function () use ($stream, $socket, $loop, $toggle) {
|
||||
$loop->removeReadStream($socket);
|
||||
|
||||
$stream->encryptionEnabled = $toggle;
|
||||
$stream->resume();
|
||||
|
||||
return $stream;
|
||||
}, function($error) use ($stream, $socket, $loop) {
|
||||
$loop->removeReadStream($socket);
|
||||
$stream->resume();
|
||||
throw $error;
|
||||
});
|
||||
}
|
||||
|
||||
public function toggleCrypto($socket, Deferred $deferred, $toggle, $method)
|
||||
{
|
||||
set_error_handler(array($this, 'handleError'));
|
||||
$result = stream_socket_enable_crypto($socket, $toggle, $method);
|
||||
restore_error_handler();
|
||||
|
||||
if (true === $result) {
|
||||
$deferred->resolve();
|
||||
} else if (false === $result) {
|
||||
$deferred->reject(new UnexpectedValueException(
|
||||
sprintf("Unable to complete SSL/TLS handshake: %s", $this->errstr),
|
||||
$this->errno
|
||||
));
|
||||
} else {
|
||||
// need more data, will retry
|
||||
}
|
||||
}
|
||||
|
||||
public function handleError($errno, $errstr)
|
||||
{
|
||||
$this->errstr = str_replace(array("\r", "\n"), ' ', $errstr);
|
||||
$this->errno = $errno;
|
||||
}
|
||||
}
|
||||
129
vendor/react/socket/src/TcpConnector.php
vendored
Executable file
129
vendor/react/socket/src/TcpConnector.php
vendored
Executable file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
final class TcpConnector implements ConnectorInterface
|
||||
{
|
||||
private $loop;
|
||||
private $context;
|
||||
|
||||
public function __construct(LoopInterface $loop, array $context = array())
|
||||
{
|
||||
$this->loop = $loop;
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function connect($uri)
|
||||
{
|
||||
if (strpos($uri, '://') === false) {
|
||||
$uri = 'tcp://' . $uri;
|
||||
}
|
||||
|
||||
$parts = parse_url($uri);
|
||||
if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
|
||||
return Promise\reject(new InvalidArgumentException('Given URI "' . $uri . '" is invalid'));
|
||||
}
|
||||
|
||||
$ip = trim($parts['host'], '[]');
|
||||
if (false === filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
return Promise\reject(new InvalidArgumentException('Given URI "' . $ip . '" does not contain a valid host IP'));
|
||||
}
|
||||
|
||||
// use context given in constructor
|
||||
$context = array(
|
||||
'socket' => $this->context
|
||||
);
|
||||
|
||||
// parse arguments from query component of URI
|
||||
$args = array();
|
||||
if (isset($parts['query'])) {
|
||||
parse_str($parts['query'], $args);
|
||||
}
|
||||
|
||||
// If an original hostname has been given, use this for TLS setup.
|
||||
// This can happen due to layers of nested connectors, such as a
|
||||
// DnsConnector reporting its original hostname.
|
||||
// These context options are here in case TLS is enabled later on this stream.
|
||||
// If TLS is not enabled later, this doesn't hurt either.
|
||||
if (isset($args['hostname'])) {
|
||||
$context['ssl'] = array(
|
||||
'SNI_enabled' => true,
|
||||
'peer_name' => $args['hostname']
|
||||
);
|
||||
|
||||
// Legacy PHP < 5.6 ignores peer_name and requires legacy context options instead.
|
||||
// The SNI_server_name context option has to be set here during construction,
|
||||
// as legacy PHP ignores any values set later.
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
$context['ssl'] += array(
|
||||
'SNI_server_name' => $args['hostname'],
|
||||
'CN_match' => $args['hostname']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// latest versions of PHP no longer accept any other URI components and
|
||||
// HHVM fails to parse URIs with a query but no path, so let's simplify our URI here
|
||||
$remote = 'tcp://' . $parts['host'] . ':' . $parts['port'];
|
||||
|
||||
$socket = @stream_socket_client(
|
||||
$remote,
|
||||
$errno,
|
||||
$errstr,
|
||||
0,
|
||||
STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT,
|
||||
stream_context_create($context)
|
||||
);
|
||||
|
||||
if (false === $socket) {
|
||||
return Promise\reject(new RuntimeException(
|
||||
sprintf("Connection to %s failed: %s", $uri, $errstr),
|
||||
$errno
|
||||
));
|
||||
}
|
||||
|
||||
stream_set_blocking($socket, 0);
|
||||
|
||||
// wait for connection
|
||||
|
||||
return $this->waitForStreamOnce($socket);
|
||||
}
|
||||
|
||||
private function waitForStreamOnce($stream)
|
||||
{
|
||||
$loop = $this->loop;
|
||||
|
||||
return new Promise\Promise(function ($resolve, $reject) use ($loop, $stream) {
|
||||
$loop->addWriteStream($stream, function ($stream) use ($loop, $resolve, $reject) {
|
||||
$loop->removeWriteStream($stream);
|
||||
|
||||
// The following hack looks like the only way to
|
||||
// detect connection refused errors with PHP's stream sockets.
|
||||
if (false === stream_socket_get_name($stream, true)) {
|
||||
fclose($stream);
|
||||
|
||||
$reject(new RuntimeException('Connection refused'));
|
||||
} else {
|
||||
$resolve(new Connection($stream, $loop));
|
||||
}
|
||||
});
|
||||
}, function () use ($loop, $stream) {
|
||||
$loop->removeWriteStream($stream);
|
||||
fclose($stream);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
// legacy PHP 5.3 sometimes requires a second close call (see tests)
|
||||
if (PHP_VERSION_ID < 50400 && is_resource($stream)) {
|
||||
fclose($stream);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
throw new RuntimeException('Cancelled while waiting for TCP/IP connection to be established');
|
||||
});
|
||||
}
|
||||
}
|
||||
236
vendor/react/socket/src/TcpServer.php
vendored
Executable file
236
vendor/react/socket/src/TcpServer.php
vendored
Executable file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* The `TcpServer` class implements the `ServerInterface` and
|
||||
* is responsible for accepting plaintext TCP/IP connections.
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer(8080, $loop);
|
||||
* ```
|
||||
*
|
||||
* Whenever a client connects, it will emit a `connection` event with a connection
|
||||
* instance implementing `ConnectionInterface`:
|
||||
*
|
||||
* ```php
|
||||
* $server->on('connection', function (ConnectionInterface $connection) {
|
||||
* echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL;
|
||||
* $connection->write('hello there!' . PHP_EOL);
|
||||
* …
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* See also the `ServerInterface` for more details.
|
||||
*
|
||||
* @see ServerInterface
|
||||
* @see ConnectionInterface
|
||||
*/
|
||||
final class TcpServer extends EventEmitter implements ServerInterface
|
||||
{
|
||||
private $master;
|
||||
private $loop;
|
||||
private $listening = false;
|
||||
|
||||
/**
|
||||
* Creates a plaintext TCP/IP socket server and starts listening on the given address
|
||||
*
|
||||
* This starts accepting new incoming connections on the given address.
|
||||
* See also the `connection event` documented in the `ServerInterface`
|
||||
* for more details.
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer(8080, $loop);
|
||||
* ```
|
||||
*
|
||||
* As above, the `$uri` parameter can consist of only a port, in which case the
|
||||
* server will default to listening on the localhost address `127.0.0.1`,
|
||||
* which means it will not be reachable from outside of this system.
|
||||
*
|
||||
* In order to use a random port assignment, you can use the port `0`:
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer(0, $loop);
|
||||
* $address = $server->getAddress();
|
||||
* ```
|
||||
*
|
||||
* In order to change the host the socket is listening on, you can provide an IP
|
||||
* address through the first parameter provided to the constructor, optionally
|
||||
* preceded by the `tcp://` scheme:
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer('192.168.0.1:8080', $loop);
|
||||
* ```
|
||||
*
|
||||
* If you want to listen on an IPv6 address, you MUST enclose the host in square
|
||||
* brackets:
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer('[::1]:8080', $loop);
|
||||
* ```
|
||||
*
|
||||
* If the given URI is invalid, does not contain a port, any other scheme or if it
|
||||
* contains a hostname, it will throw an `InvalidArgumentException`:
|
||||
*
|
||||
* ```php
|
||||
* // throws InvalidArgumentException due to missing port
|
||||
* $server = new TcpServer('127.0.0.1', $loop);
|
||||
* ```
|
||||
*
|
||||
* If the given URI appears to be valid, but listening on it fails (such as if port
|
||||
* is already in use or port below 1024 may require root access etc.), it will
|
||||
* throw a `RuntimeException`:
|
||||
*
|
||||
* ```php
|
||||
* $first = new TcpServer(8080, $loop);
|
||||
*
|
||||
* // throws RuntimeException because port is already in use
|
||||
* $second = new TcpServer(8080, $loop);
|
||||
* ```
|
||||
*
|
||||
* Note that these error conditions may vary depending on your system and/or
|
||||
* configuration.
|
||||
* See the exception message and code for more details about the actual error
|
||||
* condition.
|
||||
*
|
||||
* Optionally, you can specify [socket context options](http://php.net/manual/en/context.socket.php)
|
||||
* for the underlying stream socket resource like this:
|
||||
*
|
||||
* ```php
|
||||
* $server = new TcpServer('[::1]:8080', $loop, array(
|
||||
* 'backlog' => 200,
|
||||
* 'so_reuseport' => true,
|
||||
* 'ipv6_v6only' => true
|
||||
* ));
|
||||
* ```
|
||||
*
|
||||
* Note that available [socket context options](http://php.net/manual/en/context.socket.php),
|
||||
* their defaults and effects of changing these may vary depending on your system
|
||||
* and/or PHP version.
|
||||
* Passing unknown context options has no effect.
|
||||
*
|
||||
* @param string|int $uri
|
||||
* @param LoopInterface $loop
|
||||
* @param array $context
|
||||
* @throws InvalidArgumentException if the listening address is invalid
|
||||
* @throws RuntimeException if listening on this address fails (already in use etc.)
|
||||
*/
|
||||
public function __construct($uri, LoopInterface $loop, array $context = array())
|
||||
{
|
||||
$this->loop = $loop;
|
||||
|
||||
// a single port has been given => assume localhost
|
||||
if ((string)(int)$uri === (string)$uri) {
|
||||
$uri = '127.0.0.1:' . $uri;
|
||||
}
|
||||
|
||||
// assume default scheme if none has been given
|
||||
if (strpos($uri, '://') === false) {
|
||||
$uri = 'tcp://' . $uri;
|
||||
}
|
||||
|
||||
// parse_url() does not accept null ports (random port assignment) => manually remove
|
||||
if (substr($uri, -2) === ':0') {
|
||||
$parts = parse_url(substr($uri, 0, -2));
|
||||
if ($parts) {
|
||||
$parts['port'] = 0;
|
||||
}
|
||||
} else {
|
||||
$parts = parse_url($uri);
|
||||
}
|
||||
|
||||
// ensure URI contains TCP scheme, host and port
|
||||
if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
|
||||
throw new InvalidArgumentException('Invalid URI "' . $uri . '" given');
|
||||
}
|
||||
|
||||
if (false === filter_var(trim($parts['host'], '[]'), FILTER_VALIDATE_IP)) {
|
||||
throw new InvalidArgumentException('Given URI "' . $uri . '" does not contain a valid host IP');
|
||||
}
|
||||
|
||||
$this->master = @stream_socket_server(
|
||||
$uri,
|
||||
$errno,
|
||||
$errstr,
|
||||
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
|
||||
stream_context_create(array('socket' => $context))
|
||||
);
|
||||
if (false === $this->master) {
|
||||
throw new RuntimeException('Failed to listen on "' . $uri . '": ' . $errstr, $errno);
|
||||
}
|
||||
stream_set_blocking($this->master, 0);
|
||||
|
||||
$this->resume();
|
||||
}
|
||||
|
||||
public function getAddress()
|
||||
{
|
||||
if (!is_resource($this->master)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$address = stream_socket_get_name($this->master, false);
|
||||
|
||||
// check if this is an IPv6 address which includes multiple colons but no square brackets
|
||||
$pos = strrpos($address, ':');
|
||||
if ($pos !== false && strpos($address, ':') < $pos && substr($address, 0, 1) !== '[') {
|
||||
$port = substr($address, $pos + 1);
|
||||
$address = '[' . substr($address, 0, $pos) . ']:' . $port;
|
||||
}
|
||||
|
||||
return 'tcp://' . $address;
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
if (!$this->listening) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loop->removeReadStream($this->master);
|
||||
$this->listening = false;
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
if ($this->listening || !is_resource($this->master)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$that = $this;
|
||||
$this->loop->addReadStream($this->master, function ($master) use ($that) {
|
||||
$newSocket = @stream_socket_accept($master);
|
||||
if (false === $newSocket) {
|
||||
$that->emit('error', array(new RuntimeException('Error accepting new connection')));
|
||||
|
||||
return;
|
||||
}
|
||||
$that->handleConnection($newSocket);
|
||||
});
|
||||
$this->listening = true;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
if (!is_resource($this->master)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->pause();
|
||||
fclose($this->master);
|
||||
$this->removeAllListeners();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function handleConnection($socket)
|
||||
{
|
||||
$this->emit('connection', array(
|
||||
new Connection($socket, $this->loop)
|
||||
));
|
||||
}
|
||||
}
|
||||
25
vendor/react/socket/src/TimeoutConnector.php
vendored
Executable file
25
vendor/react/socket/src/TimeoutConnector.php
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise\Timer;
|
||||
|
||||
final class TimeoutConnector implements ConnectorInterface
|
||||
{
|
||||
private $connector;
|
||||
private $timeout;
|
||||
private $loop;
|
||||
|
||||
public function __construct(ConnectorInterface $connector, $timeout, LoopInterface $loop)
|
||||
{
|
||||
$this->connector = $connector;
|
||||
$this->timeout = $timeout;
|
||||
$this->loop = $loop;
|
||||
}
|
||||
|
||||
public function connect($uri)
|
||||
{
|
||||
return Timer\timeout($this->connector->connect($uri), $this->timeout, $this->loop);
|
||||
}
|
||||
}
|
||||
44
vendor/react/socket/src/UnixConnector.php
vendored
Executable file
44
vendor/react/socket/src/UnixConnector.php
vendored
Executable file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Unix domain socket connector
|
||||
*
|
||||
* Unix domain sockets use atomic operations, so we can as well emulate
|
||||
* async behavior.
|
||||
*/
|
||||
final class UnixConnector implements ConnectorInterface
|
||||
{
|
||||
private $loop;
|
||||
|
||||
public function __construct(LoopInterface $loop)
|
||||
{
|
||||
$this->loop = $loop;
|
||||
}
|
||||
|
||||
public function connect($path)
|
||||
{
|
||||
if (strpos($path, '://') === false) {
|
||||
$path = 'unix://' . $path;
|
||||
} elseif (substr($path, 0, 7) !== 'unix://') {
|
||||
return Promise\reject(new InvalidArgumentException('Given URI "' . $path . '" is invalid'));
|
||||
}
|
||||
|
||||
$resource = @stream_socket_client($path, $errno, $errstr, 1.0);
|
||||
|
||||
if (!$resource) {
|
||||
return Promise\reject(new RuntimeException('Unable to connect to unix domain socket "' . $path . '": ' . $errstr, $errno));
|
||||
}
|
||||
|
||||
$connection = new Connection($resource, $this->loop);
|
||||
$connection->unix = true;
|
||||
|
||||
return Promise\resolve($connection);
|
||||
}
|
||||
}
|
||||
130
vendor/react/socket/src/UnixServer.php
vendored
Executable file
130
vendor/react/socket/src/UnixServer.php
vendored
Executable file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace React\Socket;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* The `UnixServer` class implements the `ServerInterface` and
|
||||
* is responsible for accepting plaintext connections on unix domain sockets.
|
||||
*
|
||||
* ```php
|
||||
* $server = new UnixServer('unix:///tmp/app.sock', $loop);
|
||||
* ```
|
||||
*
|
||||
* See also the `ServerInterface` for more details.
|
||||
*
|
||||
* @see ServerInterface
|
||||
* @see ConnectionInterface
|
||||
*/
|
||||
final class UnixServer extends EventEmitter implements ServerInterface
|
||||
{
|
||||
private $master;
|
||||
private $loop;
|
||||
private $listening = false;
|
||||
|
||||
/**
|
||||
* Creates a plaintext socket server and starts listening on the given unix socket
|
||||
*
|
||||
* This starts accepting new incoming connections on the given address.
|
||||
* See also the `connection event` documented in the `ServerInterface`
|
||||
* for more details.
|
||||
*
|
||||
* ```php
|
||||
* $server = new UnixServer('unix:///tmp/app.sock', $loop);
|
||||
* ```
|
||||
*
|
||||
* @param string $path
|
||||
* @param LoopInterface $loop
|
||||
* @param array $context
|
||||
* @throws InvalidArgumentException if the listening address is invalid
|
||||
* @throws RuntimeException if listening on this address fails (already in use etc.)
|
||||
*/
|
||||
public function __construct($path, LoopInterface $loop, array $context = array())
|
||||
{
|
||||
$this->loop = $loop;
|
||||
|
||||
if (strpos($path, '://') === false) {
|
||||
$path = 'unix://' . $path;
|
||||
} elseif (substr($path, 0, 7) !== 'unix://') {
|
||||
throw new InvalidArgumentException('Given URI "' . $path . '" is invalid');
|
||||
}
|
||||
|
||||
$this->master = @stream_socket_server(
|
||||
$path,
|
||||
$errno,
|
||||
$errstr,
|
||||
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
|
||||
stream_context_create(array('socket' => $context))
|
||||
);
|
||||
if (false === $this->master) {
|
||||
throw new RuntimeException('Failed to listen on unix domain socket "' . $path . '": ' . $errstr, $errno);
|
||||
}
|
||||
stream_set_blocking($this->master, 0);
|
||||
|
||||
$this->resume();
|
||||
}
|
||||
|
||||
public function getAddress()
|
||||
{
|
||||
if (!is_resource($this->master)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 'unix://' . stream_socket_get_name($this->master, false);
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
if (!$this->listening) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loop->removeReadStream($this->master);
|
||||
$this->listening = false;
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
if ($this->listening || !is_resource($this->master)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$that = $this;
|
||||
$this->loop->addReadStream($this->master, function ($master) use ($that) {
|
||||
$newSocket = @stream_socket_accept($master);
|
||||
if (false === $newSocket) {
|
||||
$that->emit('error', array(new RuntimeException('Error accepting new connection')));
|
||||
|
||||
return;
|
||||
}
|
||||
$that->handleConnection($newSocket);
|
||||
});
|
||||
$this->listening = true;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
if (!is_resource($this->master)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->pause();
|
||||
fclose($this->master);
|
||||
$this->removeAllListeners();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function handleConnection($socket)
|
||||
{
|
||||
$connection = new Connection($socket, $this->loop);
|
||||
$connection->unix = true;
|
||||
|
||||
$this->emit('connection', array(
|
||||
$connection
|
||||
));
|
||||
}
|
||||
}
|
||||
47
vendor/react/socket/tests/ConnectionTest.php
vendored
Executable file
47
vendor/react/socket/tests/ConnectionTest.php
vendored
Executable file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\Connection;
|
||||
|
||||
class ConnectionTest extends TestCase
|
||||
{
|
||||
public function testCloseConnectionWillCloseSocketResource()
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('HHVM does not support socket operation on test memory stream');
|
||||
}
|
||||
|
||||
$resource = fopen('php://memory', 'r+');
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$connection = new Connection($resource, $loop);
|
||||
$connection->close();
|
||||
|
||||
$this->assertFalse(is_resource($resource));
|
||||
}
|
||||
|
||||
public function testCloseConnectionWillRemoveResourceFromLoopBeforeClosingResource()
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('HHVM does not support socket operation on test memory stream');
|
||||
}
|
||||
|
||||
$resource = fopen('php://memory', 'r+');
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addWriteStream')->with($resource);
|
||||
|
||||
$onRemove = null;
|
||||
$loop->expects($this->once())->method('removeWriteStream')->with($this->callback(function ($param) use (&$onRemove) {
|
||||
$onRemove = is_resource($param);
|
||||
return true;
|
||||
}));
|
||||
|
||||
$connection = new Connection($resource, $loop);
|
||||
$connection->write('test');
|
||||
$connection->close();
|
||||
|
||||
$this->assertTrue($onRemove);
|
||||
$this->assertFalse(is_resource($resource));
|
||||
}
|
||||
}
|
||||
128
vendor/react/socket/tests/ConnectorTest.php
vendored
Executable file
128
vendor/react/socket/tests/ConnectorTest.php
vendored
Executable file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\Connector;
|
||||
use React\Promise\Promise;
|
||||
|
||||
class ConnectorTest extends TestCase
|
||||
{
|
||||
public function testConnectorUsesTcpAsDefaultScheme()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$promise = new Promise(function () { });
|
||||
$tcp = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('connect')->with('127.0.0.1:80')->willReturn($promise);
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'tcp' => $tcp
|
||||
));
|
||||
|
||||
$connector->connect('127.0.0.1:80');
|
||||
}
|
||||
|
||||
public function testConnectorPassedThroughHostnameIfDnsIsDisabled()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$promise = new Promise(function () { });
|
||||
$tcp = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('connect')->with('tcp://google.com:80')->willReturn($promise);
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'tcp' => $tcp,
|
||||
'dns' => false
|
||||
));
|
||||
|
||||
$connector->connect('tcp://google.com:80');
|
||||
}
|
||||
|
||||
public function testConnectorWithUnknownSchemeAlwaysFails()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
$promise = $connector->connect('unknown://google.com:80');
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testConnectorWithDisabledTcpDefaultSchemeAlwaysFails()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$connector = new Connector($loop, array(
|
||||
'tcp' => false
|
||||
));
|
||||
|
||||
$promise = $connector->connect('google.com:80');
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testConnectorWithDisabledTcpSchemeAlwaysFails()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$connector = new Connector($loop, array(
|
||||
'tcp' => false
|
||||
));
|
||||
|
||||
$promise = $connector->connect('tcp://google.com:80');
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testConnectorWithDisabledTlsSchemeAlwaysFails()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$connector = new Connector($loop, array(
|
||||
'tls' => false
|
||||
));
|
||||
|
||||
$promise = $connector->connect('tls://google.com:443');
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testConnectorWithDisabledUnixSchemeAlwaysFails()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$connector = new Connector($loop, array(
|
||||
'unix' => false
|
||||
));
|
||||
|
||||
$promise = $connector->connect('unix://demo.sock');
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testConnectorUsesGivenResolverInstance()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$promise = new Promise(function () { });
|
||||
$resolver = $this->getMockBuilder('React\Dns\Resolver\Resolver')->disableOriginalConstructor()->getMock();
|
||||
$resolver->expects($this->once())->method('resolve')->with('google.com')->willReturn($promise);
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'dns' => $resolver
|
||||
));
|
||||
|
||||
$connector->connect('google.com:80');
|
||||
}
|
||||
|
||||
public function testConnectorUsesResolvedHostnameIfDnsIsUsed()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$promise = new Promise(function ($resolve) { $resolve('127.0.0.1'); });
|
||||
$resolver = $this->getMockBuilder('React\Dns\Resolver\Resolver')->disableOriginalConstructor()->getMock();
|
||||
$resolver->expects($this->once())->method('resolve')->with('google.com')->willReturn($promise);
|
||||
|
||||
$promise = new Promise(function () { });
|
||||
$tcp = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('connect')->with('tcp://127.0.0.1:80?hostname=google.com')->willReturn($promise);
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'tcp' => $tcp,
|
||||
'dns' => $resolver
|
||||
));
|
||||
|
||||
$connector->connect('tcp://google.com:80');
|
||||
}
|
||||
}
|
||||
111
vendor/react/socket/tests/DnsConnectorTest.php
vendored
Executable file
111
vendor/react/socket/tests/DnsConnectorTest.php
vendored
Executable file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\DnsConnector;
|
||||
use React\Promise;
|
||||
|
||||
class DnsConnectorTest extends TestCase
|
||||
{
|
||||
private $tcp;
|
||||
private $resolver;
|
||||
private $connector;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->tcp = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$this->resolver = $this->getMockBuilder('React\Dns\Resolver\Resolver')->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->connector = new DnsConnector($this->tcp, $this->resolver);
|
||||
}
|
||||
|
||||
public function testPassByResolverIfGivenIp()
|
||||
{
|
||||
$this->resolver->expects($this->never())->method('resolve');
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('127.0.0.1:80'))->will($this->returnValue(Promise\reject()));
|
||||
|
||||
$this->connector->connect('127.0.0.1:80');
|
||||
}
|
||||
|
||||
public function testPassThroughResolverIfGivenHost()
|
||||
{
|
||||
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=google.com'))->will($this->returnValue(Promise\reject()));
|
||||
|
||||
$this->connector->connect('google.com:80');
|
||||
}
|
||||
|
||||
public function testPassThroughResolverIfGivenHostWhichResolvesToIpv6()
|
||||
{
|
||||
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('::1')));
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('[::1]:80?hostname=google.com'))->will($this->returnValue(Promise\reject()));
|
||||
|
||||
$this->connector->connect('google.com:80');
|
||||
}
|
||||
|
||||
public function testPassByResolverIfGivenCompleteUri()
|
||||
{
|
||||
$this->resolver->expects($this->never())->method('resolve');
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://127.0.0.1:80/path?query#fragment'))->will($this->returnValue(Promise\reject()));
|
||||
|
||||
$this->connector->connect('scheme://127.0.0.1:80/path?query#fragment');
|
||||
}
|
||||
|
||||
public function testPassThroughResolverIfGivenCompleteUri()
|
||||
{
|
||||
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/path?query&hostname=google.com#fragment'))->will($this->returnValue(Promise\reject()));
|
||||
|
||||
$this->connector->connect('scheme://google.com:80/path?query#fragment');
|
||||
}
|
||||
|
||||
public function testPassThroughResolverIfGivenExplicitHost()
|
||||
{
|
||||
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/?hostname=google.de'))->will($this->returnValue(Promise\reject()));
|
||||
|
||||
$this->connector->connect('scheme://google.com:80/?hostname=google.de');
|
||||
}
|
||||
|
||||
public function testRejectsImmediatelyIfUriIsInvalid()
|
||||
{
|
||||
$this->resolver->expects($this->never())->method('resolve');
|
||||
$this->tcp->expects($this->never())->method('connect');
|
||||
|
||||
$promise = $this->connector->connect('////');
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testSkipConnectionIfDnsFails()
|
||||
{
|
||||
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.invalid'))->will($this->returnValue(Promise\reject()));
|
||||
$this->tcp->expects($this->never())->method('connect');
|
||||
|
||||
$this->connector->connect('example.invalid:80');
|
||||
}
|
||||
|
||||
public function testCancelDuringDnsCancelsDnsAndDoesNotStartTcpConnection()
|
||||
{
|
||||
$pending = new Promise\Promise(function () { }, $this->expectCallableOnce());
|
||||
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->will($this->returnValue($pending));
|
||||
$this->tcp->expects($this->never())->method('connect');
|
||||
|
||||
$promise = $this->connector->connect('example.com:80');
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testCancelDuringTcpConnectionCancelsTcpConnection()
|
||||
{
|
||||
$pending = new Promise\Promise(function () { }, function () { throw new \Exception(); });
|
||||
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->will($this->returnValue($pending));
|
||||
|
||||
$promise = $this->connector->connect('example.com:80');
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
}
|
||||
}
|
||||
19
vendor/react/socket/tests/FixedUriConnectorTest.php
vendored
Executable file
19
vendor/react/socket/tests/FixedUriConnectorTest.php
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\FixedUriConnector;
|
||||
use React\Tests\Socket\TestCase;
|
||||
|
||||
class FixedUriConnectorTest extends TestCase
|
||||
{
|
||||
public function testWillInvokeGivenConnector()
|
||||
{
|
||||
$base = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$base->expects($this->once())->method('connect')->with('test')->willReturn('ret');
|
||||
|
||||
$connector = new FixedUriConnector('test', $base);
|
||||
|
||||
$this->assertEquals('ret', $connector->connect('ignored'));
|
||||
}
|
||||
}
|
||||
32
vendor/react/socket/tests/FunctionalConnectorTest.php
vendored
Executable file
32
vendor/react/socket/tests/FunctionalConnectorTest.php
vendored
Executable file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use Clue\React\Block;
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Connector;
|
||||
use React\Socket\TcpServer;
|
||||
|
||||
class FunctionalConnectorTest extends TestCase
|
||||
{
|
||||
const TIMEOUT = 1.0;
|
||||
|
||||
/** @test */
|
||||
public function connectionToTcpServerShouldSucceedWithLocalhost()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(9998, $loop);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
$server->on('connection', array($server, 'close'));
|
||||
|
||||
$connector = new Connector($loop);
|
||||
|
||||
$connection = Block\await($connector->connect('localhost:9998'), $loop, self::TIMEOUT);
|
||||
|
||||
$this->assertInstanceOf('React\Socket\ConnectionInterface', $connection);
|
||||
|
||||
$connection->close();
|
||||
$server->close();
|
||||
}
|
||||
}
|
||||
438
vendor/react/socket/tests/FunctionalSecureServerTest.php
vendored
Executable file
438
vendor/react/socket/tests/FunctionalSecureServerTest.php
vendored
Executable file
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\SecureServer;
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Socket\TcpServer;
|
||||
use React\Socket\TcpConnector;
|
||||
use React\Socket\SecureConnector;
|
||||
use Clue\React\Block;
|
||||
|
||||
class FunctionalSecureServerTest extends TestCase
|
||||
{
|
||||
const TIMEOUT = 0.5;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
}
|
||||
|
||||
public function testEmitsConnectionForNewConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testWritesDataToConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $conn) {
|
||||
$conn->write('foo');
|
||||
});
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$local = Block\await($promise, $loop, self::TIMEOUT);
|
||||
/* @var $local ConnectionInterface */
|
||||
|
||||
$local->on('data', $this->expectCallableOnceWith('foo'));
|
||||
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
}
|
||||
|
||||
public function testWritesDataInMultipleChunksToConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $conn) {
|
||||
$conn->write(str_repeat('*', 400000));
|
||||
});
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$local = Block\await($promise, $loop, self::TIMEOUT);
|
||||
/* @var $local React\Stream\Stream */
|
||||
|
||||
$received = 0;
|
||||
$local->on('data', function ($chunk) use (&$received) {
|
||||
$received += strlen($chunk);
|
||||
});
|
||||
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
|
||||
$this->assertEquals(400000, $received);
|
||||
}
|
||||
|
||||
public function testWritesMoreDataInMultipleChunksToConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $conn) {
|
||||
$conn->write(str_repeat('*', 2000000));
|
||||
});
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$local = Block\await($promise, $loop, self::TIMEOUT);
|
||||
/* @var $local React\Stream\Stream */
|
||||
|
||||
$received = 0;
|
||||
$local->on('data', function ($chunk) use (&$received) {
|
||||
$received += strlen($chunk);
|
||||
});
|
||||
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
|
||||
$this->assertEquals(2000000, $received);
|
||||
}
|
||||
|
||||
public function testEmitsDataFromConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$once = $this->expectCallableOnceWith('foo');
|
||||
$server->on('connection', function (ConnectionInterface $conn) use ($once) {
|
||||
$conn->on('data', $once);
|
||||
});
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$local = Block\await($promise, $loop, self::TIMEOUT);
|
||||
/* @var $local React\Stream\Stream */
|
||||
|
||||
$local->write("foo");
|
||||
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsDataInMultipleChunksFromConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$received = 0;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$received) {
|
||||
$conn->on('data', function ($chunk) use (&$received) {
|
||||
$received += strlen($chunk);
|
||||
});
|
||||
});
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$local = Block\await($promise, $loop, self::TIMEOUT);
|
||||
/* @var $local React\Stream\Stream */
|
||||
|
||||
$local->write(str_repeat('*', 400000));
|
||||
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
|
||||
$this->assertEquals(400000, $received);
|
||||
}
|
||||
|
||||
public function testPipesDataBackInMultipleChunksFromConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$received) {
|
||||
$conn->pipe($conn);
|
||||
});
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$local = Block\await($promise, $loop, self::TIMEOUT);
|
||||
/* @var $local React\Stream\Stream */
|
||||
|
||||
$received = 0;
|
||||
$local->on('data', function ($chunk) use (&$received) {
|
||||
$received += strlen($chunk);
|
||||
});
|
||||
|
||||
$local->write(str_repeat('*', 400000));
|
||||
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
|
||||
$this->assertEquals(400000, $received);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 5.6
|
||||
*/
|
||||
public function testEmitsConnectionForNewTlsv11Connection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem',
|
||||
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_SERVER
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false,
|
||||
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 5.6
|
||||
*/
|
||||
public function testEmitsErrorForClientWithTlsVersionMismatch()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem',
|
||||
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_SERVER|STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false,
|
||||
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$this->setExpectedException('RuntimeException', 'handshake');
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionForNewConnectionWithEncryptedCertificate()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost_swordfish.pem',
|
||||
'passphrase' => 'swordfish'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testEmitsErrorForServerWithInvalidCertificate()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => 'invalid.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$this->setExpectedException('RuntimeException', 'handshake');
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testEmitsErrorForServerWithEncryptedCertificateMissingPassphrase()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost_swordfish.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$this->setExpectedException('RuntimeException', 'handshake');
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testEmitsErrorForServerWithEncryptedCertificateWithInvalidPassphrase()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost_swordfish.pem',
|
||||
'passphrase' => 'nope'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$this->setExpectedException('RuntimeException', 'handshake');
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testEmitsErrorForConnectionWithPeerVerification()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => true
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsErrorIfConnectionIsCancelled()
|
||||
{
|
||||
if (PHP_OS !== 'Linux') {
|
||||
$this->markTestSkipped('Linux only (OS is ' . PHP_OS . ')');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
|
||||
'verify_peer' => false
|
||||
));
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsNothingIfConnectionIsIdle()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableNever());
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect(str_replace('tls://', '', $server->getAddress()));
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsErrorIfConnectionIsNotSecureHandshake()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new SecureServer($server, $loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect(str_replace('tls://', '', $server->getAddress()));
|
||||
|
||||
$promise->then(function (ConnectionInterface $stream) {
|
||||
$stream->write("GET / HTTP/1.0\r\n\r\n");
|
||||
});
|
||||
|
||||
Block\sleep(self::TIMEOUT, $loop);
|
||||
}
|
||||
}
|
||||
324
vendor/react/socket/tests/FunctionalTcpServerTest.php
vendored
Executable file
324
vendor/react/socket/tests/FunctionalTcpServerTest.php
vendored
Executable file
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\TcpServer;
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Socket\TcpConnector;
|
||||
use Clue\React\Block;
|
||||
|
||||
class FunctionalTcpServerTest extends TestCase
|
||||
{
|
||||
public function testEmitsConnectionForNewConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsNoConnectionForNewConnectionWhenPaused()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$server->pause();
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionForNewConnectionWhenResumedAfterPause()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
$server->pause();
|
||||
$server->resume();
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithRemoteIp()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$peer = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$peer) {
|
||||
$peer = $conn->getRemoteAddress();
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertContains('127.0.0.1:', $peer);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithLocalIp()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$local = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$local) {
|
||||
$local = $conn->getLocalAddress();
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertContains('127.0.0.1:', $local);
|
||||
$this->assertEquals($server->getAddress(), $local);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithLocalIpDespiteListeningOnAll()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer('0.0.0.0:0', $loop);
|
||||
$local = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$local) {
|
||||
$local = $conn->getLocalAddress();
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertContains('127.0.0.1:', $local);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithRemoteIpAfterConnectionIsClosedByPeer()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$peer = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$peer) {
|
||||
$conn->on('close', function () use ($conn, &$peer) {
|
||||
$peer = $conn->getRemoteAddress();
|
||||
});
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$client = Block\await($promise, $loop, 0.1);
|
||||
$client->end();
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertContains('127.0.0.1:', $peer);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithRemoteNullAddressAfterConnectionIsClosedLocally()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$peer = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$peer) {
|
||||
$conn->close();
|
||||
$peer = $conn->getRemoteAddress();
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertNull($peer);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionEvenIfConnectionIsCancelled()
|
||||
{
|
||||
if (PHP_OS !== 'Linux') {
|
||||
$this->markTestSkipped('Linux only (OS is ' . PHP_OS . ')');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionForNewIpv6Connection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
try {
|
||||
$server = new TcpServer('[::1]:0', $loop);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->markTestSkipped('Unable to start IPv6 server socket (not available on your platform?)');
|
||||
}
|
||||
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithRemoteIpv6()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
try {
|
||||
$server = new TcpServer('[::1]:0', $loop);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->markTestSkipped('Unable to start IPv6 server socket (not available on your platform?)');
|
||||
}
|
||||
|
||||
$peer = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$peer) {
|
||||
$peer = $conn->getRemoteAddress();
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertContains('[::1]:', $peer);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithLocalIpv6()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
try {
|
||||
$server = new TcpServer('[::1]:0', $loop);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->markTestSkipped('Unable to start IPv6 server socket (not available on your platform?)');
|
||||
}
|
||||
|
||||
$local = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$local) {
|
||||
$local = $conn->getLocalAddress();
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertContains('[::1]:', $local);
|
||||
$this->assertEquals($server->getAddress(), $local);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithInheritedContextOptions()
|
||||
{
|
||||
if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.13', '<')) {
|
||||
// https://3v4l.org/hB4Tc
|
||||
$this->markTestSkipped('Not supported on legacy HHVM < 3.13');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop, array(
|
||||
'backlog' => 4
|
||||
));
|
||||
|
||||
$all = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$all) {
|
||||
$all = stream_context_get_options($conn->stream);
|
||||
});
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertEquals(array('socket' => array('backlog' => 4)), $all);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testFailsToListenOnInvalidUri()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
new TcpServer('///', $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testFailsToListenOnUriWithoutPort()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
new TcpServer('127.0.0.1', $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testFailsToListenOnUriWithWrongScheme()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
new TcpServer('udp://127.0.0.1:0', $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testFailsToListenOnUriWIthHostname()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
new TcpServer('localhost:8080', $loop);
|
||||
}
|
||||
}
|
||||
328
vendor/react/socket/tests/IntegrationTest.php
vendored
Executable file
328
vendor/react/socket/tests/IntegrationTest.php
vendored
Executable file
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use Clue\React\Block;
|
||||
use React\Dns\Resolver\Factory as ResolverFactory;
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Connector;
|
||||
use React\Socket\DnsConnector;
|
||||
use React\Socket\SecureConnector;
|
||||
use React\Socket\TcpConnector;
|
||||
|
||||
/** @group internet */
|
||||
class IntegrationTest extends TestCase
|
||||
{
|
||||
const TIMEOUT = 5.0;
|
||||
|
||||
/** @test */
|
||||
public function gettingStuffFromGoogleShouldWork()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
$conn = Block\await($connector->connect('google.com:80'), $loop);
|
||||
|
||||
$this->assertContains(':80', $conn->getRemoteAddress());
|
||||
$this->assertNotEquals('google.com:80', $conn->getRemoteAddress());
|
||||
|
||||
$conn->write("GET / HTTP/1.0\r\n\r\n");
|
||||
|
||||
$response = $this->buffer($conn, $loop, self::TIMEOUT);
|
||||
|
||||
$this->assertRegExp('#^HTTP/1\.0#', $response);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function gettingEncryptedStuffFromGoogleShouldWork()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$secureConnector = new Connector($loop);
|
||||
|
||||
$conn = Block\await($secureConnector->connect('tls://google.com:443'), $loop);
|
||||
|
||||
$conn->write("GET / HTTP/1.0\r\n\r\n");
|
||||
|
||||
$response = $this->buffer($conn, $loop, self::TIMEOUT);
|
||||
|
||||
$this->assertRegExp('#^HTTP/1\.0#', $response);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function gettingEncryptedStuffFromGoogleShouldWorkIfHostIsResolvedFirst()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$factory = new ResolverFactory();
|
||||
$dns = $factory->create('8.8.8.8', $loop);
|
||||
|
||||
$connector = new DnsConnector(
|
||||
new SecureConnector(
|
||||
new TcpConnector($loop),
|
||||
$loop
|
||||
),
|
||||
$dns
|
||||
);
|
||||
|
||||
$conn = Block\await($connector->connect('google.com:443'), $loop);
|
||||
|
||||
$conn->write("GET / HTTP/1.0\r\n\r\n");
|
||||
|
||||
$response = $this->buffer($conn, $loop, self::TIMEOUT);
|
||||
|
||||
$this->assertRegExp('#^HTTP/1\.0#', $response);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function gettingPlaintextStuffFromEncryptedGoogleShouldNotWork()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
$conn = Block\await($connector->connect('google.com:443'), $loop);
|
||||
|
||||
$this->assertContains(':443', $conn->getRemoteAddress());
|
||||
$this->assertNotEquals('google.com:443', $conn->getRemoteAddress());
|
||||
|
||||
$conn->write("GET / HTTP/1.0\r\n\r\n");
|
||||
|
||||
$response = $this->buffer($conn, $loop, self::TIMEOUT);
|
||||
|
||||
$this->assertNotRegExp('#^HTTP/1\.0#', $response);
|
||||
}
|
||||
|
||||
public function testConnectingFailsIfDnsUsesInvalidResolver()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$factory = new ResolverFactory();
|
||||
$dns = $factory->create('demo.invalid', $loop);
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'dns' => $dns
|
||||
));
|
||||
|
||||
$this->setExpectedException('RuntimeException');
|
||||
Block\await($connector->connect('google.com:80'), $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testCancellingPendingConnectionWithoutTimeoutShouldNotCreateAnyGarbageReferences()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop, array('timeout' => false));
|
||||
|
||||
gc_collect_cycles();
|
||||
$promise = $connector->connect('8.8.8.8:80');
|
||||
$promise->cancel();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testCancellingPendingConnectionShouldNotCreateAnyGarbageReferences()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop);
|
||||
|
||||
gc_collect_cycles();
|
||||
$promise = $connector->connect('8.8.8.8:80');
|
||||
$promise->cancel();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testWaitingForRejectedConnectionShouldNotCreateAnyGarbageReferences()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop, array('timeout' => false));
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$wait = true;
|
||||
$promise = $connector->connect('127.0.0.1:1')->then(
|
||||
null,
|
||||
function ($e) use (&$wait) {
|
||||
$wait = false;
|
||||
throw $e;
|
||||
}
|
||||
);
|
||||
|
||||
// run loop for short period to ensure we detect connection refused error
|
||||
Block\sleep(0.01, $loop);
|
||||
if ($wait) {
|
||||
Block\sleep(0.2, $loop);
|
||||
if ($wait) {
|
||||
$this->fail('Connection attempt did not fail');
|
||||
}
|
||||
}
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7
|
||||
*/
|
||||
public function testWaitingForConnectionTimeoutShouldNotCreateAnyGarbageReferences()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop, array('timeout' => 0.001));
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$wait = true;
|
||||
$promise = $connector->connect('google.com:80')->then(
|
||||
null,
|
||||
function ($e) use (&$wait) {
|
||||
$wait = false;
|
||||
throw $e;
|
||||
}
|
||||
);
|
||||
|
||||
// run loop for short period to ensure we detect connection timeout error
|
||||
Block\sleep(0.01, $loop);
|
||||
if ($wait) {
|
||||
Block\sleep(0.2, $loop);
|
||||
if ($wait) {
|
||||
$this->fail('Connection attempt did not fail');
|
||||
}
|
||||
}
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testWaitingForInvalidDnsConnectionShouldNotCreateAnyGarbageReferences()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop, array('timeout' => false));
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$wait = true;
|
||||
$promise = $connector->connect('example.invalid:80')->then(
|
||||
null,
|
||||
function ($e) use (&$wait) {
|
||||
$wait = false;
|
||||
throw $e;
|
||||
}
|
||||
);
|
||||
|
||||
// run loop for short period to ensure we detect DNS error
|
||||
Block\sleep(0.01, $loop);
|
||||
if ($wait) {
|
||||
Block\sleep(0.2, $loop);
|
||||
if ($wait) {
|
||||
$this->fail('Connection attempt did not fail');
|
||||
}
|
||||
}
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testWaitingForSuccessfullyClosedConnectionShouldNotCreateAnyGarbageReferences()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
$connector = new Connector($loop, array('timeout' => false));
|
||||
|
||||
gc_collect_cycles();
|
||||
$promise = $connector->connect('google.com:80')->then(
|
||||
function ($conn) {
|
||||
$conn->close();
|
||||
}
|
||||
);
|
||||
Block\await($promise, $loop, self::TIMEOUT);
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testConnectingFailsIfTimeoutIsTooSmall()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'timeout' => 0.001
|
||||
));
|
||||
|
||||
$this->setExpectedException('RuntimeException');
|
||||
Block\await($connector->connect('google.com:80'), $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testSelfSignedRejectsIfVerificationIsEnabled()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'tls' => array(
|
||||
'verify_peer' => true
|
||||
)
|
||||
));
|
||||
|
||||
$this->setExpectedException('RuntimeException');
|
||||
Block\await($connector->connect('tls://self-signed.badssl.com:443'), $loop, self::TIMEOUT);
|
||||
}
|
||||
|
||||
public function testSelfSignedResolvesIfVerificationIsDisabled()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$connector = new Connector($loop, array(
|
||||
'tls' => array(
|
||||
'verify_peer' => false
|
||||
)
|
||||
));
|
||||
|
||||
$conn = Block\await($connector->connect('tls://self-signed.badssl.com:443'), $loop, self::TIMEOUT);
|
||||
$conn->close();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
}
|
||||
195
vendor/react/socket/tests/LimitingServerTest.php
vendored
Executable file
195
vendor/react/socket/tests/LimitingServerTest.php
vendored
Executable file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\LimitingServer;
|
||||
use React\Socket\TcpServer;
|
||||
use React\EventLoop\Factory;
|
||||
use Clue\React\Block;
|
||||
|
||||
class LimitingServerTest extends TestCase
|
||||
{
|
||||
public function testGetAddressWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('getAddress')->willReturn('127.0.0.1:1234');
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
|
||||
$this->assertEquals('127.0.0.1:1234', $server->getAddress());
|
||||
}
|
||||
|
||||
public function testPauseWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('pause');
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
|
||||
$server->pause();
|
||||
}
|
||||
|
||||
public function testPauseTwiceWillBePassedThroughToTcpServerOnce()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('pause');
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
|
||||
$server->pause();
|
||||
$server->pause();
|
||||
}
|
||||
|
||||
public function testResumeWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('resume');
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
|
||||
$server->pause();
|
||||
$server->resume();
|
||||
}
|
||||
|
||||
public function testResumeTwiceWillBePassedThroughToTcpServerOnce()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('resume');
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
|
||||
$server->pause();
|
||||
$server->resume();
|
||||
$server->resume();
|
||||
}
|
||||
|
||||
public function testCloseWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('close');
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
|
||||
$server->close();
|
||||
}
|
||||
|
||||
public function testSocketErrorWillBeForwarded()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$tcp = new TcpServer(0, $loop);
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$tcp->emit('error', array(new \RuntimeException('test')));
|
||||
}
|
||||
|
||||
public function testSocketConnectionWillBeForwarded()
|
||||
{
|
||||
$connection = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$tcp = new TcpServer(0, $loop);
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
$server->on('connection', $this->expectCallableOnceWith($connection));
|
||||
$server->on('error', $this->expectCallableNever());
|
||||
|
||||
$tcp->emit('connection', array($connection));
|
||||
|
||||
$this->assertEquals(array($connection), $server->getConnections());
|
||||
}
|
||||
|
||||
public function testSocketConnectionWillBeClosedOnceLimitIsReached()
|
||||
{
|
||||
$first = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
|
||||
$first->expects($this->never())->method('close');
|
||||
$second = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
|
||||
$second->expects($this->once())->method('close');
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$tcp = new TcpServer(0, $loop);
|
||||
|
||||
$server = new LimitingServer($tcp, 1);
|
||||
$server->on('connection', $this->expectCallableOnceWith($first));
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$tcp->emit('connection', array($first));
|
||||
$tcp->emit('connection', array($second));
|
||||
}
|
||||
|
||||
public function testPausingServerWillBePausedOnceLimitIsReached()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addReadStream');
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$tcp = new TcpServer(0, $loop);
|
||||
|
||||
$connection = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
|
||||
|
||||
$server = new LimitingServer($tcp, 1, true);
|
||||
|
||||
$tcp->emit('connection', array($connection));
|
||||
}
|
||||
|
||||
public function testSocketDisconnectionWillRemoveFromList()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$tcp = new TcpServer(0, $loop);
|
||||
|
||||
$socket = stream_socket_client($tcp->getAddress());
|
||||
fclose($socket);
|
||||
|
||||
$server = new LimitingServer($tcp, 100);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
$server->on('error', $this->expectCallableNever());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertEquals(array(), $server->getConnections());
|
||||
}
|
||||
|
||||
public function testPausingServerWillEmitOnlyOneButAcceptTwoConnectionsDueToOperatingSystem()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new LimitingServer($server, 1, true);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
$server->on('error', $this->expectCallableNever());
|
||||
|
||||
$first = stream_socket_client($server->getAddress());
|
||||
$second = stream_socket_client($server->getAddress());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
fclose($first);
|
||||
fclose($second);
|
||||
}
|
||||
|
||||
public function testPausingServerWillEmitTwoConnectionsFromBacklog()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$twice = $this->createCallableMock();
|
||||
$twice->expects($this->exactly(2))->method('__invoke');
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server = new LimitingServer($server, 1, true);
|
||||
$server->on('connection', $twice);
|
||||
$server->on('error', $this->expectCallableNever());
|
||||
|
||||
$first = stream_socket_client($server->getAddress());
|
||||
fclose($first);
|
||||
$second = stream_socket_client($server->getAddress());
|
||||
fclose($second);
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
}
|
||||
74
vendor/react/socket/tests/SecureConnectorTest.php
vendored
Executable file
74
vendor/react/socket/tests/SecureConnectorTest.php
vendored
Executable file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Promise;
|
||||
use React\Socket\SecureConnector;
|
||||
|
||||
class SecureConnectorTest extends TestCase
|
||||
{
|
||||
private $loop;
|
||||
private $tcp;
|
||||
private $connector;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$this->loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$this->tcp = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$this->connector = new SecureConnector($this->tcp, $this->loop);
|
||||
}
|
||||
|
||||
public function testConnectionWillWaitForTcpConnection()
|
||||
{
|
||||
$pending = new Promise\Promise(function () { });
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('example.com:80'))->will($this->returnValue($pending));
|
||||
|
||||
$promise = $this->connector->connect('example.com:80');
|
||||
|
||||
$this->assertInstanceOf('React\Promise\PromiseInterface', $promise);
|
||||
}
|
||||
|
||||
public function testConnectionWithCompleteUriWillBePassedThroughExpectForScheme()
|
||||
{
|
||||
$pending = new Promise\Promise(function () { });
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('example.com:80/path?query#fragment'))->will($this->returnValue($pending));
|
||||
|
||||
$this->connector->connect('tls://example.com:80/path?query#fragment');
|
||||
}
|
||||
|
||||
public function testConnectionToInvalidSchemeWillReject()
|
||||
{
|
||||
$this->tcp->expects($this->never())->method('connect');
|
||||
|
||||
$promise = $this->connector->connect('tcp://example.com:80');
|
||||
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testCancelDuringTcpConnectionCancelsTcpConnection()
|
||||
{
|
||||
$pending = new Promise\Promise(function () { }, function () { throw new \Exception(); });
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('example.com:80'))->will($this->returnValue($pending));
|
||||
|
||||
$promise = $this->connector->connect('example.com:80');
|
||||
$promise->cancel();
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testConnectionWillBeClosedAndRejectedIfConnectioIsNoStream()
|
||||
{
|
||||
$connection = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
|
||||
$connection->expects($this->once())->method('close');
|
||||
|
||||
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('example.com:80'))->willReturn(Promise\resolve($connection));
|
||||
|
||||
$promise = $this->connector->connect('example.com:80');
|
||||
|
||||
$promise->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
}
|
||||
}
|
||||
204
vendor/react/socket/tests/SecureIntegrationTest.php
vendored
Executable file
204
vendor/react/socket/tests/SecureIntegrationTest.php
vendored
Executable file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\EventLoop\Factory as LoopFactory;
|
||||
use React\Socket\TcpServer;
|
||||
use React\Socket\SecureServer;
|
||||
use React\Socket\TcpConnector;
|
||||
use React\Socket\SecureConnector;
|
||||
use Clue\React\Block;
|
||||
use React\Promise\Promise;
|
||||
use Evenement\EventEmitterInterface;
|
||||
use React\Promise\Deferred;
|
||||
use React\Socket\ConnectionInterface;
|
||||
|
||||
class SecureIntegrationTest extends TestCase
|
||||
{
|
||||
const TIMEOUT = 0.5;
|
||||
|
||||
private $loop;
|
||||
private $server;
|
||||
private $connector;
|
||||
private $address;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$this->loop = LoopFactory::create();
|
||||
$this->server = new TcpServer(0, $this->loop);
|
||||
$this->server = new SecureServer($this->server, $this->loop, array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
));
|
||||
$this->address = $this->server->getAddress();
|
||||
$this->connector = new SecureConnector(new TcpConnector($this->loop), $this->loop, array('verify_peer' => false));
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
if ($this->server !== null) {
|
||||
$this->server->close();
|
||||
$this->server = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function testConnectToServer()
|
||||
{
|
||||
$client = Block\await($this->connector->connect($this->address), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
$client->close();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
|
||||
public function testConnectToServerEmitsConnection()
|
||||
{
|
||||
$promiseServer = $this->createPromiseForEvent($this->server, 'connection', $this->expectCallableOnce());
|
||||
|
||||
$promiseClient = $this->connector->connect($this->address);
|
||||
|
||||
list($_, $client) = Block\awaitAll(array($promiseServer, $promiseClient), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
$client->close();
|
||||
}
|
||||
|
||||
public function testSendSmallDataToServerReceivesOneChunk()
|
||||
{
|
||||
// server expects one connection which emits one data event
|
||||
$received = new Deferred();
|
||||
$this->server->on('connection', function (ConnectionInterface $peer) use ($received) {
|
||||
$peer->on('data', function ($chunk) use ($received) {
|
||||
$received->resolve($chunk);
|
||||
});
|
||||
});
|
||||
|
||||
$client = Block\await($this->connector->connect($this->address), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
$client->write('hello');
|
||||
|
||||
// await server to report one "data" event
|
||||
$data = Block\await($received->promise(), $this->loop, self::TIMEOUT);
|
||||
|
||||
$client->close();
|
||||
|
||||
$this->assertEquals('hello', $data);
|
||||
}
|
||||
|
||||
public function testSendDataWithEndToServerReceivesAllData()
|
||||
{
|
||||
$disconnected = new Deferred();
|
||||
$this->server->on('connection', function (ConnectionInterface $peer) use ($disconnected) {
|
||||
$received = '';
|
||||
$peer->on('data', function ($chunk) use (&$received) {
|
||||
$received .= $chunk;
|
||||
});
|
||||
$peer->on('close', function () use (&$received, $disconnected) {
|
||||
$disconnected->resolve($received);
|
||||
});
|
||||
});
|
||||
|
||||
$client = Block\await($this->connector->connect($this->address), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
$data = str_repeat('a', 200000);
|
||||
$client->end($data);
|
||||
|
||||
// await server to report connection "close" event
|
||||
$received = Block\await($disconnected->promise(), $this->loop, self::TIMEOUT);
|
||||
|
||||
$this->assertEquals($data, $received);
|
||||
}
|
||||
|
||||
public function testSendDataWithoutEndingToServerReceivesAllData()
|
||||
{
|
||||
$received = '';
|
||||
$this->server->on('connection', function (ConnectionInterface $peer) use (&$received) {
|
||||
$peer->on('data', function ($chunk) use (&$received) {
|
||||
$received .= $chunk;
|
||||
});
|
||||
});
|
||||
|
||||
$client = Block\await($this->connector->connect($this->address), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
$data = str_repeat('d', 200000);
|
||||
$client->write($data);
|
||||
|
||||
// buffer incoming data for 0.1s (should be plenty of time)
|
||||
Block\sleep(0.1, $this->loop);
|
||||
|
||||
$client->close();
|
||||
|
||||
$this->assertEquals($data, $received);
|
||||
}
|
||||
|
||||
public function testConnectToServerWhichSendsSmallDataReceivesOneChunk()
|
||||
{
|
||||
$this->server->on('connection', function (ConnectionInterface $peer) {
|
||||
$peer->write('hello');
|
||||
});
|
||||
|
||||
$client = Block\await($this->connector->connect($this->address), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
// await client to report one "data" event
|
||||
$receive = $this->createPromiseForEvent($client, 'data', $this->expectCallableOnceWith('hello'));
|
||||
Block\await($receive, $this->loop, self::TIMEOUT);
|
||||
|
||||
$client->close();
|
||||
}
|
||||
|
||||
public function testConnectToServerWhichSendsDataWithEndReceivesAllData()
|
||||
{
|
||||
$data = str_repeat('b', 100000);
|
||||
$this->server->on('connection', function (ConnectionInterface $peer) use ($data) {
|
||||
$peer->end($data);
|
||||
});
|
||||
|
||||
$client = Block\await($this->connector->connect($this->address), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
// await data from client until it closes
|
||||
$received = $this->buffer($client, $this->loop, self::TIMEOUT);
|
||||
|
||||
$this->assertEquals($data, $received);
|
||||
}
|
||||
|
||||
public function testConnectToServerWhichSendsDataWithoutEndingReceivesAllData()
|
||||
{
|
||||
$data = str_repeat('c', 100000);
|
||||
$this->server->on('connection', function (ConnectionInterface $peer) use ($data) {
|
||||
$peer->write($data);
|
||||
});
|
||||
|
||||
$client = Block\await($this->connector->connect($this->address), $this->loop, self::TIMEOUT);
|
||||
/* @var $client ConnectionInterface */
|
||||
|
||||
// buffer incoming data for 0.1s (should be plenty of time)
|
||||
$received = '';
|
||||
$client->on('data', function ($chunk) use (&$received) {
|
||||
$received .= $chunk;
|
||||
});
|
||||
Block\sleep(0.1, $this->loop);
|
||||
|
||||
$client->close();
|
||||
|
||||
$this->assertEquals($data, $received);
|
||||
}
|
||||
|
||||
private function createPromiseForEvent(EventEmitterInterface $emitter, $event, $fn)
|
||||
{
|
||||
return new Promise(function ($resolve) use ($emitter, $event, $fn) {
|
||||
$emitter->on($event, function () use ($resolve, $fn) {
|
||||
$resolve(call_user_func_array($fn, func_get_args()));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
105
vendor/react/socket/tests/SecureServerTest.php
vendored
Executable file
105
vendor/react/socket/tests/SecureServerTest.php
vendored
Executable file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\SecureServer;
|
||||
use React\Socket\TcpServer;
|
||||
|
||||
class SecureServerTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetAddressWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('getAddress')->willReturn('tcp://127.0.0.1:1234');
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$server = new SecureServer($tcp, $loop, array());
|
||||
|
||||
$this->assertEquals('tls://127.0.0.1:1234', $server->getAddress());
|
||||
}
|
||||
|
||||
public function testGetAddressWillReturnNullIfTcpServerReturnsNull()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('getAddress')->willReturn(null);
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$server = new SecureServer($tcp, $loop, array());
|
||||
|
||||
$this->assertNull($server->getAddress());
|
||||
}
|
||||
|
||||
public function testPauseWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('pause');
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$server = new SecureServer($tcp, $loop, array());
|
||||
|
||||
$server->pause();
|
||||
}
|
||||
|
||||
public function testResumeWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('resume');
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$server = new SecureServer($tcp, $loop, array());
|
||||
|
||||
$server->resume();
|
||||
}
|
||||
|
||||
public function testCloseWillBePassedThroughToTcpServer()
|
||||
{
|
||||
$tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock();
|
||||
$tcp->expects($this->once())->method('close');
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$server = new SecureServer($tcp, $loop, array());
|
||||
|
||||
$server->close();
|
||||
}
|
||||
|
||||
public function testConnectionWillBeEndedWithErrorIfItIsNotAStream()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$tcp = new TcpServer(0, $loop);
|
||||
|
||||
$connection = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
|
||||
$connection->expects($this->once())->method('end');
|
||||
|
||||
$server = new SecureServer($tcp, $loop, array());
|
||||
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$tcp->emit('connection', array($connection));
|
||||
}
|
||||
|
||||
public function testSocketErrorWillBeForwarded()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$tcp = new TcpServer(0, $loop);
|
||||
|
||||
$server = new SecureServer($tcp, $loop, array());
|
||||
|
||||
$server->on('error', $this->expectCallableOnce());
|
||||
|
||||
$tcp->emit('error', array(new \RuntimeException('test')));
|
||||
}
|
||||
}
|
||||
173
vendor/react/socket/tests/ServerTest.php
vendored
Executable file
173
vendor/react/socket/tests/ServerTest.php
vendored
Executable file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\Server;
|
||||
use React\Socket\TcpConnector;
|
||||
use React\Socket\UnixConnector;
|
||||
use Clue\React\Block;
|
||||
use React\Socket\ConnectionInterface;
|
||||
|
||||
class ServerTest extends TestCase
|
||||
{
|
||||
const TIMEOUT = 0.1;
|
||||
|
||||
public function testCreateServerWithZeroPortAssignsRandomPort()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(0, $loop);
|
||||
$this->assertNotEquals(0, $server->getAddress());
|
||||
$server->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsForInvalidUri()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$server = new Server('invalid URI', $loop);
|
||||
}
|
||||
|
||||
public function testConstructorCreatesExpectedTcpServer()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(0, $loop);
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$connector->connect($server->getAddress())
|
||||
->then($this->expectCallableOnce(), $this->expectCallableNever());
|
||||
|
||||
$connection = Block\await($connector->connect($server->getAddress()), $loop, self::TIMEOUT);
|
||||
|
||||
$connection->close();
|
||||
$server->close();
|
||||
}
|
||||
|
||||
public function testConstructorCreatesExpectedUnixServer()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server($this->getRandomSocketUri(), $loop);
|
||||
|
||||
$connector = new UnixConnector($loop);
|
||||
$connector->connect($server->getAddress())
|
||||
->then($this->expectCallableOnce(), $this->expectCallableNever());
|
||||
|
||||
$connection = Block\await($connector->connect($server->getAddress()), $loop, self::TIMEOUT);
|
||||
|
||||
$connection->close();
|
||||
$server->close();
|
||||
}
|
||||
|
||||
public function testEmitsConnectionForNewConnection()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(0, $loop);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$client = stream_socket_client($server->getAddress());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testDoesNotEmitConnectionForNewConnectionToPausedServer()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(0, $loop);
|
||||
$server->pause();
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
|
||||
$client = stream_socket_client($server->getAddress());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testDoesEmitConnectionForNewConnectionToResumedServer()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(0, $loop);
|
||||
$server->pause();
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$client = stream_socket_client($server->getAddress());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$server->resume();
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
public function testDoesNotAllowConnectionToClosedServer()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(0, $loop);
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
$address = $server->getAddress();
|
||||
$server->close();
|
||||
|
||||
$client = @stream_socket_client($address);
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertFalse($client);
|
||||
}
|
||||
|
||||
public function testEmitsConnectionWithInheritedContextOptions()
|
||||
{
|
||||
if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.13', '<')) {
|
||||
// https://3v4l.org/hB4Tc
|
||||
$this->markTestSkipped('Not supported on legacy HHVM < 3.13');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server(0, $loop, array(
|
||||
'backlog' => 4
|
||||
));
|
||||
|
||||
$all = null;
|
||||
$server->on('connection', function (ConnectionInterface $conn) use (&$all) {
|
||||
$all = stream_context_get_options($conn->stream);
|
||||
});
|
||||
|
||||
$client = stream_socket_client($server->getAddress());
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
|
||||
$this->assertEquals(array('socket' => array('backlog' => 4)), $all);
|
||||
}
|
||||
|
||||
public function testDoesNotEmitSecureConnectionForNewPlainConnection()
|
||||
{
|
||||
if (!function_exists('stream_socket_enable_crypto')) {
|
||||
$this->markTestSkipped('Not supported on your platform (outdated HHVM?)');
|
||||
}
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new Server('tls://127.0.0.1:0', $loop, array(
|
||||
'tls' => array(
|
||||
'local_cert' => __DIR__ . '/../examples/localhost.pem'
|
||||
)
|
||||
));
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
|
||||
$client = stream_socket_client(str_replace('tls://', '', $server->getAddress()));
|
||||
|
||||
Block\sleep(0.1, $loop);
|
||||
}
|
||||
|
||||
private function getRandomSocketUri()
|
||||
{
|
||||
return "unix://" . sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(rand(), true) . '.sock';
|
||||
}
|
||||
}
|
||||
10
vendor/react/socket/tests/Stub/CallableStub.php
vendored
Executable file
10
vendor/react/socket/tests/Stub/CallableStub.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket\Stub;
|
||||
|
||||
class CallableStub
|
||||
{
|
||||
public function __invoke()
|
||||
{
|
||||
}
|
||||
}
|
||||
63
vendor/react/socket/tests/Stub/ConnectionStub.php
vendored
Executable file
63
vendor/react/socket/tests/Stub/ConnectionStub.php
vendored
Executable file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket\Stub;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Stream\WritableStreamInterface;
|
||||
use React\Stream\Util;
|
||||
|
||||
class ConnectionStub extends EventEmitter implements ConnectionInterface
|
||||
{
|
||||
private $data = '';
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
}
|
||||
|
||||
public function pipe(WritableStreamInterface $dest, array $options = array())
|
||||
{
|
||||
Util::pipe($this, $dest, $options);
|
||||
|
||||
return $dest;
|
||||
}
|
||||
|
||||
public function write($data)
|
||||
{
|
||||
$this->data .= $data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function end($data = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getRemoteAddress()
|
||||
{
|
||||
return '127.0.0.1';
|
||||
}
|
||||
}
|
||||
18
vendor/react/socket/tests/Stub/ServerStub.php
vendored
Executable file
18
vendor/react/socket/tests/Stub/ServerStub.php
vendored
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket\Stub;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\Socket\ServerInterface;
|
||||
|
||||
class ServerStub extends EventEmitter implements ServerInterface
|
||||
{
|
||||
public function getAddress()
|
||||
{
|
||||
return '127.0.0.1:80';
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
}
|
||||
}
|
||||
260
vendor/react/socket/tests/TcpConnectorTest.php
vendored
Executable file
260
vendor/react/socket/tests/TcpConnectorTest.php
vendored
Executable file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use Clue\React\Block;
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Socket\TcpConnector;
|
||||
use React\Socket\TcpServer;
|
||||
|
||||
class TcpConnectorTest extends TestCase
|
||||
{
|
||||
const TIMEOUT = 0.1;
|
||||
|
||||
/** @test */
|
||||
public function connectionToEmptyPortShouldFail()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$connector->connect('127.0.0.1:9999')
|
||||
->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToTcpServerShouldAddResourceToLoop()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
|
||||
$valid = false;
|
||||
$loop->expects($this->once())->method('addWriteStream')->with($this->callback(function ($arg) use (&$valid) {
|
||||
$valid = is_resource($arg);
|
||||
return true;
|
||||
}));
|
||||
$connector->connect($server->getAddress());
|
||||
|
||||
$this->assertTrue($valid);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToTcpServerShouldSucceed()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(9999, $loop);
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
$server->on('connection', array($server, 'close'));
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$connection = Block\await($connector->connect('127.0.0.1:9999'), $loop, self::TIMEOUT);
|
||||
|
||||
$this->assertInstanceOf('React\Socket\ConnectionInterface', $connection);
|
||||
|
||||
$connection->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToTcpServerShouldSucceedWithRemoteAdressSameAsTarget()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(9999, $loop);
|
||||
$server->on('connection', array($server, 'close'));
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$connection = Block\await($connector->connect('127.0.0.1:9999'), $loop, self::TIMEOUT);
|
||||
/* @var $connection ConnectionInterface */
|
||||
|
||||
$this->assertEquals('tcp://127.0.0.1:9999', $connection->getRemoteAddress());
|
||||
|
||||
$connection->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToTcpServerShouldSucceedWithLocalAdressOnLocalhost()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(9999, $loop);
|
||||
$server->on('connection', array($server, 'close'));
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$connection = Block\await($connector->connect('127.0.0.1:9999'), $loop, self::TIMEOUT);
|
||||
/* @var $connection ConnectionInterface */
|
||||
|
||||
$this->assertContains('tcp://127.0.0.1:', $connection->getLocalAddress());
|
||||
$this->assertNotEquals('tcp://127.0.0.1:9999', $connection->getLocalAddress());
|
||||
|
||||
$connection->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToTcpServerShouldSucceedWithNullAddressesAfterConnectionClosed()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$server = new TcpServer(9999, $loop);
|
||||
$server->on('connection', array($server, 'close'));
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$connection = Block\await($connector->connect('127.0.0.1:9999'), $loop, self::TIMEOUT);
|
||||
/* @var $connection ConnectionInterface */
|
||||
|
||||
$connection->close();
|
||||
|
||||
$this->assertNull($connection->getRemoteAddress());
|
||||
$this->assertNull($connection->getLocalAddress());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToTcpServerWillCloseWhenOtherSideCloses()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
// immediately close connection and server once connection is in
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->on('connection', function (ConnectionInterface $conn) use ($server) {
|
||||
$conn->close();
|
||||
$server->close();
|
||||
});
|
||||
|
||||
$once = $this->expectCallableOnce();
|
||||
$connector = new TcpConnector($loop);
|
||||
$connector->connect($server->getAddress())->then(function (ConnectionInterface $conn) use ($once) {
|
||||
$conn->write('hello');
|
||||
$conn->on('close', $once);
|
||||
});
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToEmptyIp6PortShouldFail()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$connector
|
||||
->connect('[::1]:9999')
|
||||
->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToIp6TcpServerShouldSucceed()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
|
||||
try {
|
||||
$server = new TcpServer('[::1]:9999', $loop);
|
||||
} catch (\Exception $e) {
|
||||
$this->markTestSkipped('Unable to start IPv6 server socket (IPv6 not supported on this system?)');
|
||||
}
|
||||
|
||||
$server->on('connection', $this->expectCallableOnce());
|
||||
$server->on('connection', array($server, 'close'));
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$connection = Block\await($connector->connect('[::1]:9999'), $loop, self::TIMEOUT);
|
||||
/* @var $connection ConnectionInterface */
|
||||
|
||||
$this->assertEquals('tcp://[::1]:9999', $connection->getRemoteAddress());
|
||||
|
||||
$this->assertContains('tcp://[::1]:', $connection->getLocalAddress());
|
||||
$this->assertNotEquals('tcp://[::1]:9999', $connection->getLocalAddress());
|
||||
|
||||
$connection->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToHostnameShouldFailImmediately()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$connector->connect('www.google.com:80')->then(
|
||||
$this->expectCallableNever(),
|
||||
$this->expectCallableOnce()
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToInvalidPortShouldFailImmediately()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$connector->connect('255.255.255.255:12345678')->then(
|
||||
$this->expectCallableNever(),
|
||||
$this->expectCallableOnce()
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function connectionToInvalidSchemeShouldFailImmediately()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$connector = new TcpConnector($loop);
|
||||
$connector->connect('tls://google.com:443')->then(
|
||||
$this->expectCallableNever(),
|
||||
$this->expectCallableOnce()
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function cancellingConnectionShouldRemoveResourceFromLoopAndCloseResource()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->on('connection', $this->expectCallableNever());
|
||||
|
||||
$loop->expects($this->once())->method('addWriteStream');
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
|
||||
$resource = null;
|
||||
$valid = false;
|
||||
$loop->expects($this->once())->method('removeWriteStream')->with($this->callback(function ($arg) use (&$resource, &$valid) {
|
||||
$resource = $arg;
|
||||
$valid = is_resource($arg);
|
||||
return true;
|
||||
}));
|
||||
$promise->cancel();
|
||||
|
||||
// ensure that this was a valid resource during the removeWriteStream() call
|
||||
$this->assertTrue($valid);
|
||||
|
||||
// ensure that this resource should now be closed after the cancel() call
|
||||
$this->assertInternalType('resource', $resource);
|
||||
$this->assertFalse(is_resource($resource));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function cancellingConnectionShouldRejectPromise()
|
||||
{
|
||||
$loop = Factory::create();
|
||||
$connector = new TcpConnector($loop);
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
|
||||
$promise = $connector->connect($server->getAddress());
|
||||
$promise->cancel();
|
||||
|
||||
$this->setExpectedException('RuntimeException', 'Cancelled');
|
||||
Block\await($promise, $loop);
|
||||
}
|
||||
}
|
||||
285
vendor/react/socket/tests/TcpServerTest.php
vendored
Executable file
285
vendor/react/socket/tests/TcpServerTest.php
vendored
Executable file
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use Clue\React\Block;
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\TcpServer;
|
||||
use React\Stream\DuplexResourceStream;
|
||||
|
||||
class TcpServerTest extends TestCase
|
||||
{
|
||||
private $loop;
|
||||
private $server;
|
||||
private $port;
|
||||
|
||||
private function createLoop()
|
||||
{
|
||||
return Factory::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\TcpServer::__construct
|
||||
* @covers React\Socket\TcpServer::getAddress
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
$this->loop = $this->createLoop();
|
||||
$this->server = new TcpServer(0, $this->loop);
|
||||
|
||||
$this->port = parse_url($this->server->getAddress(), PHP_URL_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\TcpServer::handleConnection
|
||||
*/
|
||||
public function testConnection()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
|
||||
$this->server->on('connection', $this->expectCallableOnce());
|
||||
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\TcpServer::handleConnection
|
||||
*/
|
||||
public function testConnectionWithManyClients()
|
||||
{
|
||||
$client1 = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
$client2 = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
$client3 = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
|
||||
$this->server->on('connection', $this->expectCallableExactly(3));
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testDataEventWillNotBeEmittedWhenClientSendsNoData()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
|
||||
$mock = $this->expectCallableNever();
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('data', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testDataWillBeEmittedWithDataClientSends()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
|
||||
fwrite($client, "foo\n");
|
||||
|
||||
$mock = $this->expectCallableOnceWith("foo\n");
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('data', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testDataWillBeEmittedEvenWhenClientShutsDownAfterSending()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:' . $this->port);
|
||||
fwrite($client, "foo\n");
|
||||
stream_socket_shutdown($client, STREAM_SHUT_WR);
|
||||
|
||||
$mock = $this->expectCallableOnceWith("foo\n");
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('data', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testLoopWillEndWhenServerIsClosed()
|
||||
{
|
||||
// explicitly unset server because we already call close()
|
||||
$this->server->close();
|
||||
$this->server = null;
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
|
||||
public function testCloseTwiceIsNoOp()
|
||||
{
|
||||
$this->server->close();
|
||||
$this->server->close();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
|
||||
public function testGetAddressAfterCloseReturnsNull()
|
||||
{
|
||||
$this->server->close();
|
||||
$this->assertNull($this->server->getAddress());
|
||||
}
|
||||
|
||||
public function testLoopWillEndWhenServerIsClosedAfterSingleConnection()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:' . $this->port);
|
||||
|
||||
// explicitly unset server because we only accept a single connection
|
||||
// and then already call close()
|
||||
$server = $this->server;
|
||||
$this->server = null;
|
||||
|
||||
$server->on('connection', function ($conn) use ($server) {
|
||||
$conn->close();
|
||||
$server->close();
|
||||
});
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
|
||||
public function testDataWillBeEmittedInMultipleChunksWhenClientSendsExcessiveAmounts()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:' . $this->port);
|
||||
$stream = new DuplexResourceStream($client, $this->loop);
|
||||
|
||||
$bytes = 1024 * 1024;
|
||||
$stream->end(str_repeat('*', $bytes));
|
||||
|
||||
$mock = $this->expectCallableOnce();
|
||||
|
||||
// explicitly unset server because we only accept a single connection
|
||||
// and then already call close()
|
||||
$server = $this->server;
|
||||
$this->server = null;
|
||||
|
||||
$received = 0;
|
||||
$server->on('connection', function ($conn) use ($mock, &$received, $server) {
|
||||
// count number of bytes received
|
||||
$conn->on('data', function ($data) use (&$received) {
|
||||
$received += strlen($data);
|
||||
});
|
||||
|
||||
$conn->on('end', $mock);
|
||||
|
||||
// do not await any further connections in order to let the loop terminate
|
||||
$server->close();
|
||||
});
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
$this->assertEquals($bytes, $received);
|
||||
}
|
||||
|
||||
public function testConnectionDoesNotEndWhenClientDoesNotClose()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
|
||||
$mock = $this->expectCallableNever();
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('end', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\Connection::end
|
||||
*/
|
||||
public function testConnectionDoesEndWhenClientCloses()
|
||||
{
|
||||
$client = stream_socket_client('tcp://localhost:'.$this->port);
|
||||
|
||||
fclose($client);
|
||||
|
||||
$mock = $this->expectCallableOnce();
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('end', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testCtorAddsResourceToLoop()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addReadStream');
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
}
|
||||
|
||||
public function testResumeWithoutPauseIsNoOp()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addReadStream');
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->resume();
|
||||
}
|
||||
|
||||
public function testPauseRemovesResourceFromLoop()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->pause();
|
||||
}
|
||||
|
||||
public function testPauseAfterPauseIsNoOp()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->pause();
|
||||
$server->pause();
|
||||
}
|
||||
|
||||
public function testCloseRemovesResourceFromLoop()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$server = new TcpServer(0, $loop);
|
||||
$server->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
public function testListenOnBusyPortThrows()
|
||||
{
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
$this->markTestSkipped('Windows supports listening on same port multiple times');
|
||||
}
|
||||
|
||||
$another = new TcpServer($this->port, $this->loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\TcpServer::close
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
if ($this->server) {
|
||||
$this->server->close();
|
||||
}
|
||||
}
|
||||
|
||||
private function tick()
|
||||
{
|
||||
Block\sleep(0, $this->loop);
|
||||
}
|
||||
}
|
||||
101
vendor/react/socket/tests/TestCase.php
vendored
Executable file
101
vendor/react/socket/tests/TestCase.php
vendored
Executable file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Stream\ReadableStreamInterface;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use Clue\React\Block;
|
||||
use React\Promise\Promise;
|
||||
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||
|
||||
class TestCase extends BaseTestCase
|
||||
{
|
||||
protected function expectCallableExactly($amount)
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
$mock
|
||||
->expects($this->exactly($amount))
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function expectCallableOnce()
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
$mock
|
||||
->expects($this->once())
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function expectCallableOnceWith($value)
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
$mock
|
||||
->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($value);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function expectCallableNever()
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
$mock
|
||||
->expects($this->never())
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function createCallableMock()
|
||||
{
|
||||
return $this->getMockBuilder('React\Tests\Socket\Stub\CallableStub')->getMock();
|
||||
}
|
||||
|
||||
protected function buffer(ReadableStreamInterface $stream, LoopInterface $loop, $timeout)
|
||||
{
|
||||
if (!$stream->isReadable()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Block\await(new Promise(
|
||||
function ($resolve, $reject) use ($stream) {
|
||||
$buffer = '';
|
||||
$stream->on('data', function ($chunk) use (&$buffer) {
|
||||
$buffer .= $chunk;
|
||||
});
|
||||
|
||||
$stream->on('error', $reject);
|
||||
|
||||
$stream->on('close', function () use (&$buffer, $resolve) {
|
||||
$resolve($buffer);
|
||||
});
|
||||
},
|
||||
function () use ($stream) {
|
||||
$stream->close();
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
), $loop, $timeout);
|
||||
}
|
||||
|
||||
public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null)
|
||||
{
|
||||
if (method_exists($this, 'expectException')) {
|
||||
// PHPUnit 5+
|
||||
$this->expectException($exception);
|
||||
if ($exceptionMessage !== '') {
|
||||
$this->expectExceptionMessage($exceptionMessage);
|
||||
}
|
||||
if ($exceptionCode !== null) {
|
||||
$this->expectExceptionCode($exceptionCode);
|
||||
}
|
||||
} else {
|
||||
// legacy PHPUnit 4
|
||||
parent::setExpectedException($exception, $exceptionMessage, $exceptionCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
103
vendor/react/socket/tests/TimeoutConnectorTest.php
vendored
Executable file
103
vendor/react/socket/tests/TimeoutConnectorTest.php
vendored
Executable file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\TimeoutConnector;
|
||||
use React\Promise;
|
||||
use React\EventLoop\Factory;
|
||||
|
||||
class TimeoutConnectorTest extends TestCase
|
||||
{
|
||||
public function testRejectsOnTimeout()
|
||||
{
|
||||
$promise = new Promise\Promise(function () { });
|
||||
|
||||
$connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$connector->expects($this->once())->method('connect')->with('google.com:80')->will($this->returnValue($promise));
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$timeout = new TimeoutConnector($connector, 0.01, $loop);
|
||||
|
||||
$timeout->connect('google.com:80')->then(
|
||||
$this->expectCallableNever(),
|
||||
$this->expectCallableOnce()
|
||||
);
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
public function testRejectsWhenConnectorRejects()
|
||||
{
|
||||
$promise = Promise\reject(new \RuntimeException());
|
||||
|
||||
$connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$connector->expects($this->once())->method('connect')->with('google.com:80')->will($this->returnValue($promise));
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$timeout = new TimeoutConnector($connector, 5.0, $loop);
|
||||
|
||||
$timeout->connect('google.com:80')->then(
|
||||
$this->expectCallableNever(),
|
||||
$this->expectCallableOnce()
|
||||
);
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
public function testResolvesWhenConnectorResolves()
|
||||
{
|
||||
$promise = Promise\resolve();
|
||||
|
||||
$connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$connector->expects($this->once())->method('connect')->with('google.com:80')->will($this->returnValue($promise));
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$timeout = new TimeoutConnector($connector, 5.0, $loop);
|
||||
|
||||
$timeout->connect('google.com:80')->then(
|
||||
$this->expectCallableOnce(),
|
||||
$this->expectCallableNever()
|
||||
);
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
public function testRejectsAndCancelsPendingPromiseOnTimeout()
|
||||
{
|
||||
$promise = new Promise\Promise(function () { }, $this->expectCallableOnce());
|
||||
|
||||
$connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$connector->expects($this->once())->method('connect')->with('google.com:80')->will($this->returnValue($promise));
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$timeout = new TimeoutConnector($connector, 0.01, $loop);
|
||||
|
||||
$timeout->connect('google.com:80')->then(
|
||||
$this->expectCallableNever(),
|
||||
$this->expectCallableOnce()
|
||||
);
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
public function testCancelsPendingPromiseOnCancel()
|
||||
{
|
||||
$promise = new Promise\Promise(function () { }, function () { throw new \Exception(); });
|
||||
|
||||
$connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||
$connector->expects($this->once())->method('connect')->with('google.com:80')->will($this->returnValue($promise));
|
||||
|
||||
$loop = Factory::create();
|
||||
|
||||
$timeout = new TimeoutConnector($connector, 0.01, $loop);
|
||||
|
||||
$out = $timeout->connect('google.com:80');
|
||||
$out->cancel();
|
||||
|
||||
$out->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
}
|
||||
}
|
||||
64
vendor/react/socket/tests/UnixConnectorTest.php
vendored
Executable file
64
vendor/react/socket/tests/UnixConnectorTest.php
vendored
Executable file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use React\Socket\ConnectionInterface;
|
||||
use React\Socket\UnixConnector;
|
||||
|
||||
class UnixConnectorTest extends TestCase
|
||||
{
|
||||
private $loop;
|
||||
private $connector;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$this->connector = new UnixConnector($this->loop);
|
||||
}
|
||||
|
||||
public function testInvalid()
|
||||
{
|
||||
$promise = $this->connector->connect('google.com:80');
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testInvalidScheme()
|
||||
{
|
||||
$promise = $this->connector->connect('tcp://google.com:80');
|
||||
$promise->then(null, $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
public function testValid()
|
||||
{
|
||||
// random unix domain socket path
|
||||
$path = sys_get_temp_dir() . '/test' . uniqid() . '.sock';
|
||||
|
||||
// temporarily create unix domain socket server to connect to
|
||||
$server = stream_socket_server('unix://' . $path, $errno, $errstr);
|
||||
|
||||
// skip test if we can not create a test server (Windows etc.)
|
||||
if (!$server) {
|
||||
$this->markTestSkipped('Unable to create socket "' . $path . '": ' . $errstr . '(' . $errno .')');
|
||||
return;
|
||||
}
|
||||
|
||||
// tests succeeds if we get notified of successful connection
|
||||
$promise = $this->connector->connect($path);
|
||||
$promise->then($this->expectCallableOnce());
|
||||
|
||||
// remember remote and local address of this connection and close again
|
||||
$remote = $local = false;
|
||||
$promise->then(function(ConnectionInterface $conn) use (&$remote, &$local) {
|
||||
$remote = $conn->getRemoteAddress();
|
||||
$local = $conn->getLocalAddress();
|
||||
$conn->close();
|
||||
});
|
||||
|
||||
// clean up server
|
||||
fclose($server);
|
||||
unlink($path);
|
||||
|
||||
$this->assertNull($local);
|
||||
$this->assertEquals('unix://' . $path, $remote);
|
||||
}
|
||||
}
|
||||
283
vendor/react/socket/tests/UnixServerTest.php
vendored
Executable file
283
vendor/react/socket/tests/UnixServerTest.php
vendored
Executable file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Socket;
|
||||
|
||||
use Clue\React\Block;
|
||||
use React\EventLoop\Factory;
|
||||
use React\Socket\UnixServer;
|
||||
use React\Stream\DuplexResourceStream;
|
||||
|
||||
class UnixServerTest extends TestCase
|
||||
{
|
||||
private $loop;
|
||||
private $server;
|
||||
private $uds;
|
||||
|
||||
/**
|
||||
* @covers React\Socket\UnixServer::__construct
|
||||
* @covers React\Socket\UnixServer::getAddress
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
$this->loop = Factory::create();
|
||||
$this->uds = $this->getRandomSocketUri();
|
||||
$this->server = new UnixServer($this->uds, $this->loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\UnixServer::handleConnection
|
||||
*/
|
||||
public function testConnection()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
|
||||
$this->server->on('connection', $this->expectCallableOnce());
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\UnixServer::handleConnection
|
||||
*/
|
||||
public function testConnectionWithManyClients()
|
||||
{
|
||||
$client1 = stream_socket_client($this->uds);
|
||||
$client2 = stream_socket_client($this->uds);
|
||||
$client3 = stream_socket_client($this->uds);
|
||||
|
||||
$this->server->on('connection', $this->expectCallableExactly(3));
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testDataEventWillNotBeEmittedWhenClientSendsNoData()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
|
||||
$mock = $this->expectCallableNever();
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('data', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testDataWillBeEmittedWithDataClientSends()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
|
||||
fwrite($client, "foo\n");
|
||||
|
||||
$mock = $this->expectCallableOnceWith("foo\n");
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('data', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testDataWillBeEmittedEvenWhenClientShutsDownAfterSending()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
fwrite($client, "foo\n");
|
||||
stream_socket_shutdown($client, STREAM_SHUT_WR);
|
||||
|
||||
$mock = $this->expectCallableOnceWith("foo\n");
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('data', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testLoopWillEndWhenServerIsClosed()
|
||||
{
|
||||
// explicitly unset server because we already call close()
|
||||
$this->server->close();
|
||||
$this->server = null;
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
|
||||
public function testCloseTwiceIsNoOp()
|
||||
{
|
||||
$this->server->close();
|
||||
$this->server->close();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
|
||||
public function testGetAddressAfterCloseReturnsNull()
|
||||
{
|
||||
$this->server->close();
|
||||
$this->assertNull($this->server->getAddress());
|
||||
}
|
||||
|
||||
public function testLoopWillEndWhenServerIsClosedAfterSingleConnection()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
|
||||
// explicitly unset server because we only accept a single connection
|
||||
// and then already call close()
|
||||
$server = $this->server;
|
||||
$this->server = null;
|
||||
|
||||
$server->on('connection', function ($conn) use ($server) {
|
||||
$conn->close();
|
||||
$server->close();
|
||||
});
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
// if we reach this, then everything is good
|
||||
$this->assertNull(null);
|
||||
}
|
||||
|
||||
public function testDataWillBeEmittedInMultipleChunksWhenClientSendsExcessiveAmounts()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
$stream = new DuplexResourceStream($client, $this->loop);
|
||||
|
||||
$bytes = 1024 * 1024;
|
||||
$stream->end(str_repeat('*', $bytes));
|
||||
|
||||
$mock = $this->expectCallableOnce();
|
||||
|
||||
// explicitly unset server because we only accept a single connection
|
||||
// and then already call close()
|
||||
$server = $this->server;
|
||||
$this->server = null;
|
||||
|
||||
$received = 0;
|
||||
$server->on('connection', function ($conn) use ($mock, &$received, $server) {
|
||||
// count number of bytes received
|
||||
$conn->on('data', function ($data) use (&$received) {
|
||||
$received += strlen($data);
|
||||
});
|
||||
|
||||
$conn->on('end', $mock);
|
||||
|
||||
// do not await any further connections in order to let the loop terminate
|
||||
$server->close();
|
||||
});
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
$this->assertEquals($bytes, $received);
|
||||
}
|
||||
|
||||
public function testConnectionDoesNotEndWhenClientDoesNotClose()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
|
||||
$mock = $this->expectCallableNever();
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('end', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\Connection::end
|
||||
*/
|
||||
public function testConnectionDoesEndWhenClientCloses()
|
||||
{
|
||||
$client = stream_socket_client($this->uds);
|
||||
|
||||
fclose($client);
|
||||
|
||||
$mock = $this->expectCallableOnce();
|
||||
|
||||
$this->server->on('connection', function ($conn) use ($mock) {
|
||||
$conn->on('end', $mock);
|
||||
});
|
||||
$this->tick();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
public function testCtorAddsResourceToLoop()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addReadStream');
|
||||
|
||||
$server = new UnixServer($this->getRandomSocketUri(), $loop);
|
||||
}
|
||||
|
||||
public function testResumeWithoutPauseIsNoOp()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addReadStream');
|
||||
|
||||
$server = new UnixServer($this->getRandomSocketUri(), $loop);
|
||||
$server->resume();
|
||||
}
|
||||
|
||||
public function testPauseRemovesResourceFromLoop()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$server = new UnixServer($this->getRandomSocketUri(), $loop);
|
||||
$server->pause();
|
||||
}
|
||||
|
||||
public function testPauseAfterPauseIsNoOp()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$server = new UnixServer($this->getRandomSocketUri(), $loop);
|
||||
$server->pause();
|
||||
$server->pause();
|
||||
}
|
||||
|
||||
public function testCloseRemovesResourceFromLoop()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('removeReadStream');
|
||||
|
||||
$server = new UnixServer($this->getRandomSocketUri(), $loop);
|
||||
$server->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
public function testListenOnBusyPortThrows()
|
||||
{
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
$this->markTestSkipped('Windows supports listening on same port multiple times');
|
||||
}
|
||||
|
||||
$another = new UnixServer($this->uds, $this->loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Socket\UnixServer::close
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
if ($this->server) {
|
||||
$this->server->close();
|
||||
}
|
||||
}
|
||||
|
||||
private function getRandomSocketUri()
|
||||
{
|
||||
return "unix://" . sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(rand(), true) . '.sock';
|
||||
}
|
||||
|
||||
private function tick()
|
||||
{
|
||||
Block\sleep(0, $this->loop);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user