summaryrefslogtreecommitdiffstats
path: root/vendor/clue/http-proxy-react
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clue/http-proxy-react')
-rw-r--r--vendor/clue/http-proxy-react/CHANGELOG.md200
-rw-r--r--vendor/clue/http-proxy-react/LICENSE21
-rw-r--r--vendor/clue/http-proxy-react/README.md510
-rw-r--r--vendor/clue/http-proxy-react/composer.json31
-rw-r--r--vendor/clue/http-proxy-react/src/ProxyConnector.php278
5 files changed, 1040 insertions, 0 deletions
diff --git a/vendor/clue/http-proxy-react/CHANGELOG.md b/vendor/clue/http-proxy-react/CHANGELOG.md
new file mode 100644
index 0000000..19d534d
--- /dev/null
+++ b/vendor/clue/http-proxy-react/CHANGELOG.md
@@ -0,0 +1,200 @@
+# Changelog
+
+## 1.8.0 (2022-09-01)
+
+* Feature: Full support for PHP 8.1 and PHP 8.2.
+ (#47 and #48 by @SimonFrings)
+
+* Feature: Mark passwords and URIs as `#[\SensitiveParameter]` (PHP 8.2+).
+ (#49 by @SimonFrings)
+
+* Feature: Forward compatibility with upcoming Promise v3.
+ (#44 by @clue)
+
+* Fix: Fix invalid references in exception stack trace.
+ (#45 by @clue)
+
+* Improve test suite and fix legacy HHVM build.
+ (#46 by @SimonFrings)
+
+## 1.7.0 (2021-08-06)
+
+* Feature: Simplify usage by supporting new default loop and making `Connector` optional.
+ (#41 and #42 by @clue)
+
+ ```php
+ // old (still supported)
+ $proxy = new Clue\React\HttpProxy\ProxyConnector(
+ '127.0.0.1:8080',
+ new React\Socket\Connector($loop)
+ );
+
+ // new (using default loop)
+ $proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+ ```
+
+* Documentation improvements and updated examples.
+ (#39 and #43 by @clue and #40 by @PaulRotmann)
+
+* Improve test suite and use GitHub actions for continuous integration (CI).
+ (#38 by @SimonFrings)
+
+## 1.6.0 (2020-10-23)
+
+* Enhanced documentation for ReactPHP's new HTTP client.
+ (#35 and #37 by @SimonFrings)
+
+* Improve test suite, prepare PHP 8 support and support PHPUnit 9.3.
+ (#36 by @SimonFrings)
+
+## 1.5.0 (2020-06-19)
+
+* Feature / Fix: Support PHP 7.4 by skipping unneeded cleanup of exception trace args.
+ (#33 by @clue)
+
+* Clean up test suite and add `.gitattributes` to exclude dev files from exports.
+ Run tests on PHP 7.4, PHPUnit 9 and simplify test matrix.
+ Link to using SSH proxy (SSH tunnel) as an alternative.
+ (#27 by @clue and #31, #32 and #34 by @SimonFrings)
+
+## 1.4.0 (2018-10-30)
+
+* Feature: Improve error reporting for failed connection attempts and improve
+ cancellation forwarding during proxy connection setup.
+ (#23 and #26 by @clue)
+
+ All error messages now always contain a reference to the remote URI to give
+ more details which connection actually failed and the reason for this error.
+ Similarly, any underlying connection issues to the proxy server will now be
+ reported as part of the previous exception.
+
+ For most common use cases this means that simply reporting the `Exception`
+ message should give the most relevant details for any connection issues:
+
+ ```php
+ $promise = $proxy->connect('tcp://example.com:80');
+ $promise->then(function (ConnectionInterface $connection) {
+ // …
+ }, function (Exception $e) {
+ echo $e->getMessage();
+ });
+ ```
+
+* Feature: Add support for custom HTTP request headers.
+ (#25 by @valga and @clue)
+
+ ```php
+ // new: now supports custom HTTP request headers
+ $proxy = new ProxyConnector('127.0.0.1:8080', $connector, array(
+ 'Proxy-Authorization' => 'Bearer abc123',
+ 'User-Agent' => 'ReactPHP'
+ ));
+ ```
+
+* Fix: Fix connecting to IPv6 destination hosts.
+ (#22 by @clue)
+
+* Link to clue/reactphp-buzz for HTTP requests and update project homepage.
+ (#21 and #24 by @clue)
+
+## 1.3.0 (2018-02-13)
+
+* Feature: Support communication over Unix domain sockets (UDS)
+ (#20 by @clue)
+
+ ```php
+ // new: now supports communication over Unix domain sockets (UDS)
+ $proxy = new ProxyConnector('http+unix:///tmp/proxy.sock', $connector);
+ ```
+
+* Reduce memory consumption by avoiding circular reference from stream reader
+ (#18 by @valga)
+
+* Improve documentation
+ (#19 by @clue)
+
+## 1.2.0 (2017-08-30)
+
+* Feature: Use socket error codes for connection rejections
+ (#17 by @clue)
+
+ ```php
+ $promise = $proxy->connect('imap.example.com:143');
+ $promise->then(null, function (Exeption $e) {
+ if ($e->getCode() === SOCKET_EACCES) {
+ echo 'Failed to authenticate with proxy!';
+ }
+ throw $e;
+ });
+ ```
+
+* Improve test suite by locking Travis distro so new defaults will not break the build and
+ optionally exclude tests that rely on working internet connection
+ (#15 and #16 by @clue)
+
+## 1.1.0 (2017-06-11)
+
+* Feature: Support proxy authentication if proxy URL contains username/password
+ (#14 by @clue)
+
+ ```php
+ // new: username/password will now be passed to HTTP proxy server
+ $proxy = new ProxyConnector('user:pass@127.0.0.1:8080', $connector);
+ ```
+
+## 1.0.0 (2017-06-10)
+
+* First stable release, now following SemVer
+
+> Contains no other changes, so it's actually fully compatible with the v0.3.2 release.
+
+## 0.3.2 (2017-06-10)
+
+* Fix: Fix rejecting invalid URIs and unexpected URI schemes
+ (#13 by @clue)
+
+* Fix HHVM build for now again and ignore future HHVM build errors
+ (#12 by @clue)
+
+* Documentation for Connector concepts (TCP/TLS, timeouts, DNS resolution)
+ (#11 by @clue)
+
+## 0.3.1 (2017-05-10)
+
+* Feature: Forward compatibility with upcoming Socket v1.0 and v0.8
+ (#10 by @clue)
+
+## 0.3.0 (2017-04-10)
+
+* Feature / BC break: Replace deprecated SocketClient with new Socket component
+ (#9 by @clue)
+
+ This implies that the `ProxyConnector` from this package now implements the
+ `React\Socket\ConnectorInterface` instead of the legacy
+ `React\SocketClient\ConnectorInterface`.
+
+## 0.2.0 (2017-04-10)
+
+* Feature / BC break: Update SocketClient to v0.7 or v0.6 and
+ use `connect($uri)` instead of `create($host, $port)`
+ (#8 by @clue)
+
+ ```php
+ // old
+ $connector->create($host, $port)->then(function (Stream $conn) {
+ $conn->write("…");
+ });
+
+ // new
+ $connector->connect($uri)->then(function (ConnectionInterface $conn) {
+ $conn->write("…");
+ });
+ ```
+
+* Improve test suite by adding PHPUnit to require-dev
+ (#7 by @clue)
+
+
+## 0.1.0 (2016-11-01)
+
+* First tagged release
diff --git a/vendor/clue/http-proxy-react/LICENSE b/vendor/clue/http-proxy-react/LICENSE
new file mode 100644
index 0000000..7baae8e
--- /dev/null
+++ b/vendor/clue/http-proxy-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Christian Lück
+
+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.
diff --git a/vendor/clue/http-proxy-react/README.md b/vendor/clue/http-proxy-react/README.md
new file mode 100644
index 0000000..b5337c1
--- /dev/null
+++ b/vendor/clue/http-proxy-react/README.md
@@ -0,0 +1,510 @@
+# clue/reactphp-http-proxy
+
+[![CI status](https://github.com/clue/reactphp-http-proxy/actions/workflows/ci.yml/badge.svg)](https://github.com/clue/reactphp-http-proxy/actions)
+[![installs on Packagist](https://img.shields.io/packagist/dt/clue/http-proxy-react?color=blue&label=installs%20on%20Packagist)](https://packagist.org/packages/clue/http-proxy-react)
+
+Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP
+CONNECT proxy server, built on top of [ReactPHP](https://reactphp.org/).
+
+HTTP CONNECT proxy servers (also commonly known as "HTTPS proxy" or "SSL proxy")
+are commonly used to tunnel HTTPS traffic through an intermediary ("proxy"), to
+conceal the origin address (anonymity) or to circumvent address blocking
+(geoblocking). While many (public) HTTP CONNECT proxy servers often limit this
+to HTTPS port `443` only, this can technically be used to tunnel any
+TCP/IP-based protocol (HTTP, SMTP, IMAP etc.).
+This library provides a simple API to create these tunneled connections for you.
+Because it implements ReactPHP's standard
+[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface),
+it can simply be used in place of a normal connector.
+This makes it fairly simple to add HTTP CONNECT proxy support to pretty much any
+existing higher-level protocol implementation.
+
+* **Async execution of connections** -
+ Send any number of HTTP CONNECT requests in parallel and process their
+ responses as soon as results come in.
+ The Promise-based design provides a *sane* interface to working with out of
+ order responses and possible connection errors.
+* **Standard interfaces** -
+ Allows easy integration with existing higher-level components by implementing
+ ReactPHP's standard
+ [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface).
+* **Lightweight, SOLID design** -
+ Provides a thin abstraction that is [*just good enough*](https://en.wikipedia.org/wiki/Principle_of_good_enough)
+ and does not get in your way.
+ Builds on top of well-tested components and well-established concepts instead of reinventing the wheel.
+* **Good test coverage** -
+ Comes with an automated tests suite and is regularly tested against actual proxy servers in the wild.
+
+**Table of contents**
+
+* [Support us](#support-us)
+* [Quickstart example](#quickstart-example)
+* [Usage](#usage)
+ * [ProxyConnector](#proxyconnector)
+ * [Plain TCP connections](#plain-tcp-connections)
+ * [Secure TLS connections](#secure-tls-connections)
+ * [HTTP requests](#http-requests)
+ * [Connection timeout](#connection-timeout)
+ * [DNS resolution](#dns-resolution)
+ * [Authentication](#authentication)
+ * [Advanced HTTP headers](#advanced-http-headers)
+ * [Advanced secure proxy connections](#advanced-secure-proxy-connections)
+ * [Advanced Unix domain sockets](#advanced-unix-domain-sockets)
+* [Install](#install)
+* [Tests](#tests)
+* [License](#license)
+* [More](#more)
+
+## Support us
+
+We invest a lot of time developing, maintaining and updating our awesome
+open-source projects. You can help us sustain this high-quality of our work by
+[becoming a sponsor on GitHub](https://github.com/sponsors/clue). Sponsors get
+numerous benefits in return, see our [sponsoring page](https://github.com/sponsors/clue)
+for details.
+
+Let's take these projects to the next level together! 🚀
+
+## Quickstart example
+
+The following example code demonstrates how this library can be used to send a
+secure HTTPS request to google.com through a local HTTP proxy server:
+
+```php
+<?php
+
+require __DIR__ . '/vendor/autoload.php';
+
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+$connector = new React\Socket\Connector(array(
+ 'tcp' => $proxy,
+ 'dns' => false
+));
+
+$browser = new React\Http\Browser($connector);
+
+$browser->get('https://google.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
+ var_dump($response->getHeaders(), (string) $response->getBody());
+}, function (Exception $e) {
+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
+});
+```
+
+See also the [examples](examples).
+
+## Usage
+
+### ProxyConnector
+
+The `ProxyConnector` is responsible for creating plain TCP/IP connections to
+any destination by using an intermediary HTTP CONNECT proxy.
+
+```
+[you] -> [proxy] -> [destination]
+```
+
+Its constructor simply accepts an HTTP proxy URL with the proxy server address:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+```
+
+The proxy URL may or may not contain a scheme and port definition. The default
+port will be `80` for HTTP (or `443` for HTTPS), but many common HTTP proxy
+servers use custom ports (often the alternative HTTP port `8080`).
+
+If you need custom connector settings (DNS resolution, TLS parameters, timeouts,
+proxy servers etc.), you can explicitly pass a custom instance of the
+[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface):
+
+```php
+$connector = new React\Socket\Connector(array(
+ 'dns' => '127.0.0.1',
+ 'tcp' => array(
+ 'bindto' => '192.168.10.1:0'
+ ),
+ 'tls' => array(
+ 'verify_peer' => false,
+ 'verify_peer_name' => false
+ )
+));
+
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080', $connector);
+```
+
+This is the main class in this package.
+Because it implements ReactPHP's standard
+[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface),
+it can simply be used in place of a normal connector.
+Accordingly, it provides only a single public method, the
+[`connect()`](https://github.com/reactphp/socket#connect) method.
+The `connect(string $uri): PromiseInterface<ConnectionInterface, Exception>`
+method can be used to establish a streaming connection.
+It returns a [Promise](https://github.com/reactphp/promise) which either
+fulfills with a [ConnectionInterface](https://github.com/reactphp/socket#connectioninterface)
+on success or rejects with an `Exception` on error.
+
+This makes it fairly simple to add HTTP CONNECT proxy support to pretty much any
+higher-level component:
+
+```diff
+- $acme = new AcmeApi($connector);
++ $proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080', $connector);
++ $acme = new AcmeApi($proxy);
+```
+
+#### Plain TCP connections
+
+HTTP CONNECT proxies are most frequently used to issue HTTPS requests to your destination.
+However, this is actually performed on a higher protocol layer and this
+connector is actually inherently a general-purpose plain TCP/IP connector.
+As documented above, you can simply invoke its `connect()` method to establish
+a streaming plain TCP/IP connection and use any higher level protocol like so:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+$proxy->connect('tcp://smtp.googlemail.com:587')->then(function (React\Socket\ConnectionInterface $connection) {
+ $connection->write("EHLO local\r\n");
+ $connection->on('data', function ($chunk) use ($connection) {
+ echo $chunk;
+ });
+});
+```
+
+You can either use the `ProxyConnector` directly or you may want to wrap this connector
+in ReactPHP's [`Connector`](https://github.com/reactphp/socket#connector):
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+$connector = new React\Socket\Connector(array(
+ 'tcp' => $proxy,
+ 'dns' => false
+));
+
+$connector->connect('tcp://smtp.googlemail.com:587')->then(function (React\Socket\ConnectionInterface $connection) {
+ $connection->write("EHLO local\r\n");
+ $connection->on('data', function ($chunk) use ($connection) {
+ echo $chunk;
+ });
+});
+```
+
+Note that HTTP CONNECT proxies often restrict which ports one may connect to.
+Many (public) proxy servers do in fact limit this to HTTPS (443) only.
+
+#### Secure TLS connections
+
+This class can also be used if you want to establish a secure TLS connection
+(formerly known as SSL) between you and your destination, such as when using
+secure HTTPS to your destination site. You can simply wrap this connector in
+ReactPHP's [`Connector`](https://github.com/reactphp/socket#connector):
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+$connector = new React\Socket\Connector(array(
+ 'tcp' => $proxy,
+ 'dns' => false
+));
+
+$connector->connect('tls://smtp.googlemail.com:465')->then(function (React\Socket\ConnectionInterface $connection) {
+ $connection->write("EHLO local\r\n");
+ $connection->on('data', function ($chunk) use ($connection) {
+ echo $chunk;
+ });
+});
+```
+
+> Note how secure TLS connections are in fact entirely handled outside of
+ this HTTP CONNECT client implementation.
+
+#### HTTP requests
+
+This library also allows you to send HTTP requests through an HTTP CONNECT proxy server.
+
+In order to send HTTP requests, you first have to add a dependency for
+[ReactPHP's async HTTP client](https://github.com/reactphp/http#client-usage).
+This allows you to send both plain HTTP and TLS-encrypted HTTPS requests like this:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+$connector = new React\Socket\Connector(array(
+ 'tcp' => $proxy,
+ 'dns' => false
+));
+
+$browser = new React\Http\Browser($connector);
+
+$browser->get('https://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
+ var_dump($response->getHeaders(), (string) $response->getBody());
+}, function (Exception $e) {
+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
+});
+```
+
+See also [ReactPHP's HTTP client](https://github.com/reactphp/http#client-usage)
+and any of the [examples](examples) for more details.
+
+#### Connection timeout
+
+By default, the `ProxyConnector` does not implement any timeouts for establishing remote
+connections.
+Your underlying operating system may impose limits on pending and/or idle TCP/IP
+connections, anywhere in a range of a few minutes to several hours.
+
+Many use cases require more control over the timeout and likely values much
+smaller, usually in the range of a few seconds only.
+
+You can use ReactPHP's [`Connector`](https://github.com/reactphp/socket#connector)
+to decorate any given `ConnectorInterface` instance.
+It provides the same `connect()` method, but will automatically reject the
+underlying connection attempt if it takes too long:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+$connector = new React\Socket\Connector(array(
+ 'tcp' => $proxy,
+ 'dns' => false,
+ 'timeout' => 3.0
+));
+
+$connector->connect('tcp://google.com:80')->then(function ($connection) {
+ // connection succeeded within 3.0 seconds
+});
+```
+
+See also any of the [examples](examples).
+
+> Note how the connection timeout is in fact entirely handled outside of this
+ HTTP CONNECT client implementation.
+
+#### DNS resolution
+
+By default, the `ProxyConnector` does not perform any DNS resolution at all and simply
+forwards any hostname you're trying to connect to the remote proxy server.
+The remote proxy server is thus responsible for looking up any hostnames via DNS
+(this default mode is thus called *remote DNS resolution*).
+
+As an alternative, you can also send the destination IP to the remote proxy
+server.
+In this mode you either have to stick to using IPs only (which is ofen unfeasable)
+or perform any DNS lookups locally and only transmit the resolved destination IPs
+(this mode is thus called *local DNS resolution*).
+
+The default *remote DNS resolution* is useful if your local `ProxyConnector` either can
+not resolve target hostnames because it has no direct access to the internet or
+if it should not resolve target hostnames because its outgoing DNS traffic might
+be intercepted.
+
+As noted above, the `ProxyConnector` defaults to using remote DNS resolution.
+However, wrapping the `ProxyConnector` in ReactPHP's
+[`Connector`](https://github.com/reactphp/socket#connector) actually
+performs local DNS resolution unless explicitly defined otherwise.
+Given that remote DNS resolution is assumed to be the preferred mode, all
+other examples explicitly disable DNS resolution like this:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+$connector = new React\Socket\Connector(array(
+ 'tcp' => $proxy,
+ 'dns' => false
+));
+```
+
+If you want to explicitly use *local DNS resolution*, you can use the following code:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('127.0.0.1:8080');
+
+// set up Connector which uses Google's public DNS (8.8.8.8)
+$connector = new React\Socket\Connector(array(
+ 'tcp' => $proxy,
+ 'dns' => '8.8.8.8'
+));
+```
+
+> Note how local DNS resolution is in fact entirely handled outside of this
+ HTTP CONNECT client implementation.
+
+#### Authentication
+
+If your HTTP proxy server requires authentication, you may pass the username and
+password as part of the HTTP proxy URL like this:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('alice:password@127.0.0.1:8080');
+```
+
+Note that both the username and password must be percent-encoded if they contain
+special characters:
+
+```php
+$user = 'he:llo';
+$pass = 'p@ss';
+$url = rawurlencode($user) . ':' . rawurlencode($pass) . '@127.0.0.1:8080';
+
+$proxy = new Clue\React\HttpProxy\ProxyConnector($url);
+```
+
+> The authentication details will be used for basic authentication and will be
+ transferred in the `Proxy-Authorization` HTTP request header for each
+ connection attempt.
+ If the authentication details are missing or not accepted by the remote HTTP
+ proxy server, it is expected to reject each connection attempt with a
+ `407` (Proxy Authentication Required) response status code and an exception
+ error code of `SOCKET_EACCES` (13).
+
+#### Advanced HTTP headers
+
+The `ProxyConnector` constructor accepts an optional array of custom request
+headers to send in the `CONNECT` request. This can be useful if you're using a
+custom proxy setup or authentication scheme if the proxy server does not support
+basic [authentication](#authentication) as documented above. This is rarely used
+in practice, but may be useful for some more advanced use cases. In this case,
+you may simply pass an assoc array of additional request headers like this:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector(
+ '127.0.0.1:8080',
+ null,
+ array(
+ 'Proxy-Authorization' => 'Bearer abc123',
+ 'User-Agent' => 'ReactPHP'
+ )
+);
+```
+
+#### Advanced secure proxy connections
+
+Note that communication between the client and the proxy is usually via an
+unencrypted, plain TCP/IP HTTP connection. Note that this is the most common
+setup, because you can still establish a TLS connection between you and the
+destination host as above.
+
+If you want to connect to a (rather rare) HTTPS proxy, you may want use the
+`https://` scheme (HTTPS default port 443) to create a secure connection to the proxy:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('https://127.0.0.1:443');
+
+$proxy->connect('tcp://smtp.googlemail.com:587');
+```
+
+#### Advanced Unix domain sockets
+
+HTTP CONNECT proxy servers support forwarding TCP/IP based connections and
+higher level protocols.
+In some advanced cases, it may be useful to let your HTTP CONNECT proxy server
+listen on a Unix domain socket (UDS) path instead of a IP:port combination.
+For example, this allows you to rely on file system permissions instead of
+having to rely on explicit [authentication](#authentication).
+
+You can simply use the `http+unix://` URI scheme like this:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('http+unix:///tmp/proxy.sock');
+
+$proxy->connect('tcp://google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
+ // connected…
+});
+```
+
+Similarly, you can also combine this with [authentication](#authentication)
+like this:
+
+```php
+$proxy = new Clue\React\HttpProxy\ProxyConnector('http+unix://alice:password@/tmp/proxy.sock');
+```
+
+> Note that Unix domain sockets (UDS) are considered advanced usage and PHP only
+ has limited support for this.
+ In particular, enabling [secure TLS](#secure-tls-connections) may not be
+ supported.
+
+> Note that the HTTP CONNECT protocol does not support the notion of UDS paths.
+ The above works reasonably well because UDS is only used for the connection between
+ client and proxy server and the path will not actually passed over the protocol.
+ This implies that this does not support connecting to UDS destination paths.
+
+## Install
+
+The recommended way to install this library is [through Composer](https://getcomposer.org/).
+[New to Composer?](https://getcomposer.org/doc/00-intro.md)
+
+This project follows [SemVer](https://semver.org/).
+This will install the latest supported version:
+
+```bash
+composer require clue/http-proxy-react:^1.8
+```
+
+See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
+
+This project aims to run on any platform and thus does not require any PHP
+extensions and supports running on legacy PHP 5.3 through current PHP 8+ and
+HHVM.
+It's *highly recommended to use the latest supported PHP version* for this project.
+
+## Tests
+
+To run the test suite, you first need to clone this repo and then install all
+dependencies [through Composer](https://getcomposer.org/):
+
+```bash
+composer install
+```
+
+To run the test suite, go to the project root and run:
+
+```bash
+vendor/bin/phpunit
+```
+
+The test suite contains tests that rely on a working internet connection,
+alternatively you can also run it like this:
+
+```bash
+vendor/bin/phpunit --exclude-group internet
+```
+
+## License
+
+This project is released under the permissive [MIT license](LICENSE).
+
+> Did you know that I offer custom development services and issuing invoices for
+ sponsorships of releases and for contributions? Contact me (@clue) for details.
+
+## More
+
+* If you want to learn more about how the
+ [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface)
+ and its usual implementations look like, refer to the documentation of the underlying
+ [react/socket](https://github.com/reactphp/socket) component.
+* If you want to learn more about processing streams of data, refer to the
+ documentation of the underlying
+ [react/stream](https://github.com/reactphp/stream) component.
+* As an alternative to an HTTP CONNECT proxy, you may also want to look into
+ using a SOCKS (SOCKS4/SOCKS5) proxy instead.
+ You may want to use [clue/reactphp-socks](https://github.com/clue/reactphp-socks)
+ which also provides an implementation of the same
+ [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface)
+ so that supporting either proxy protocol should be fairly trivial.
+* As an alternative to an HTTP CONNECT proxy, you may also want to look into
+ using an SSH proxy (SSH tunnel) instead.
+ You may want to use [clue/reactphp-ssh-proxy](https://github.com/clue/reactphp-ssh-proxy)
+ which also provides an implementation of the same
+ [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface)
+ so that supporting either proxy protocol should be fairly trivial.
+* If you're dealing with public proxies, you'll likely have to work with mixed
+ quality and unreliable proxies. You may want to look into using
+ [clue/reactphp-connection-manager-extra](https://github.com/clue/reactphp-connection-manager-extra)
+ which allows retrying unreliable ones, implying connection timeouts,
+ concurrently working with multiple connectors and more.
+* If you're looking for an end-user HTTP CONNECT proxy server daemon, you may
+ want to use [LeProxy](https://leproxy.org/).
diff --git a/vendor/clue/http-proxy-react/composer.json b/vendor/clue/http-proxy-react/composer.json
new file mode 100644
index 0000000..4941b1a
--- /dev/null
+++ b/vendor/clue/http-proxy-react/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "clue/http-proxy-react",
+ "description": "Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP",
+ "keywords": ["HTTP", "CONNECT", "proxy", "ReactPHP", "async"],
+ "homepage": "https://github.com/clue/reactphp-http-proxy",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^3 || ^2.1 || ^1.2.1",
+ "react/socket": "^1.12",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "autoload": {
+ "psr-4": { "Clue\\React\\HttpProxy\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\HttpProxy\\": "tests/" }
+ }
+}
diff --git a/vendor/clue/http-proxy-react/src/ProxyConnector.php b/vendor/clue/http-proxy-react/src/ProxyConnector.php
new file mode 100644
index 0000000..165e8ba
--- /dev/null
+++ b/vendor/clue/http-proxy-react/src/ProxyConnector.php
@@ -0,0 +1,278 @@
+<?php
+
+namespace Clue\React\HttpProxy;
+
+use Exception;
+use InvalidArgumentException;
+use RuntimeException;
+use RingCentral\Psr7;
+use React\Promise;
+use React\Promise\Deferred;
+use React\Socket\ConnectionInterface;
+use React\Socket\Connector;
+use React\Socket\ConnectorInterface;
+use React\Socket\FixedUriConnector;
+use React\Socket\UnixConnector;
+
+/**
+ * A simple Connector that uses an HTTP CONNECT proxy to create plain TCP/IP connections to any destination
+ *
+ * [you] -> [proxy] -> [destination]
+ *
+ * This is most frequently used to issue HTTPS requests to your destination.
+ * However, this is actually performed on a higher protocol layer and this
+ * connector is actually inherently a general-purpose plain TCP/IP connector.
+ *
+ * Note that HTTP CONNECT proxies often restrict which ports one may connect to.
+ * Many (public) proxy servers do in fact limit this to HTTPS (443) only.
+ *
+ * If you want to establish a TLS connection (such as HTTPS) between you and
+ * your destination, you may want to wrap this connector in a SecureConnector
+ * instance.
+ *
+ * Note that communication between the client and the proxy is usually via an
+ * unencrypted, plain TCP/IP HTTP connection. Note that this is the most common
+ * setup, because you can still establish a TLS connection between you and the
+ * destination host as above.
+ *
+ * If you want to connect to a (rather rare) HTTPS proxy, you may want use its
+ * HTTPS port (443) and use a SecureConnector instance to create a secure
+ * connection to the proxy.
+ *
+ * @link https://tools.ietf.org/html/rfc7231#section-4.3.6
+ */
+class ProxyConnector implements ConnectorInterface
+{
+ private $connector;
+ private $proxyUri;
+ private $headers = '';
+
+ /**
+ * Instantiate a new ProxyConnector which uses the given $proxyUrl
+ *
+ * @param string $proxyUrl The proxy URL may or may not contain a scheme and
+ * port definition. The default port will be `80` for HTTP (or `443` for
+ * HTTPS), but many common HTTP proxy servers use custom ports.
+ * @param ?ConnectorInterface $connector (Optional) Connector to use.
+ * @param array $httpHeaders Custom HTTP headers to be sent to the proxy.
+ * @throws InvalidArgumentException if the proxy URL is invalid
+ */
+ public function __construct(
+ #[\SensitiveParameter]
+ $proxyUrl,
+ ConnectorInterface $connector = null,
+ array $httpHeaders = array()
+ ) {
+ // support `http+unix://` scheme for Unix domain socket (UDS) paths
+ if (preg_match('/^http\+unix:\/\/(.*?@)?(.+?)$/', $proxyUrl, $match)) {
+ // rewrite URI to parse authentication from dummy host
+ $proxyUrl = 'http://' . $match[1] . 'localhost';
+
+ // connector uses Unix transport scheme and explicit path given
+ $connector = new FixedUriConnector(
+ 'unix://' . $match[2],
+ $connector ?: new UnixConnector()
+ );
+ }
+
+ if (strpos($proxyUrl, '://') === false) {
+ $proxyUrl = 'http://' . $proxyUrl;
+ }
+
+ $parts = parse_url($proxyUrl);
+ if (!$parts || !isset($parts['scheme'], $parts['host']) || ($parts['scheme'] !== 'http' && $parts['scheme'] !== 'https')) {
+ throw new InvalidArgumentException('Invalid proxy URL "' . $proxyUrl . '"');
+ }
+
+ // apply default port and TCP/TLS transport for given scheme
+ if (!isset($parts['port'])) {
+ $parts['port'] = $parts['scheme'] === 'https' ? 443 : 80;
+ }
+ $parts['scheme'] = $parts['scheme'] === 'https' ? 'tls' : 'tcp';
+
+ $this->connector = $connector ?: new Connector();
+ $this->proxyUri = $parts['scheme'] . '://' . $parts['host'] . ':' . $parts['port'];
+
+ // prepare Proxy-Authorization header if URI contains username/password
+ if (isset($parts['user']) || isset($parts['pass'])) {
+ $this->headers = 'Proxy-Authorization: Basic ' . base64_encode(
+ rawurldecode($parts['user'] . ':' . (isset($parts['pass']) ? $parts['pass'] : ''))
+ ) . "\r\n";
+ }
+
+ // append any additional custom request headers
+ foreach ($httpHeaders as $name => $values) {
+ foreach ((array)$values as $value) {
+ $this->headers .= $name . ': ' . $value . "\r\n";
+ }
+ }
+ }
+
+ 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('Invalid target URI specified'));
+ }
+
+ $target = $parts['host'] . ':' . $parts['port'];
+
+ // construct URI to HTTP CONNECT proxy server to connect to
+ $proxyUri = $this->proxyUri;
+
+ // append path from URI if given
+ if (isset($parts['path'])) {
+ $proxyUri .= $parts['path'];
+ }
+
+ // parse query args
+ $args = array();
+ if (isset($parts['query'])) {
+ parse_str($parts['query'], $args);
+ }
+
+ // append hostname from URI to query string unless explicitly given
+ if (!isset($args['hostname'])) {
+ $args['hostname'] = trim($parts['host'], '[]');
+ }
+
+ // append query string
+ $proxyUri .= '?' . http_build_query($args, '', '&');
+
+ // append fragment from URI if given
+ if (isset($parts['fragment'])) {
+ $proxyUri .= '#' . $parts['fragment'];
+ }
+
+ $connecting = $this->connector->connect($proxyUri);
+
+ $deferred = new Deferred(function ($_, $reject) use ($connecting, $uri) {
+ $reject(new RuntimeException(
+ 'Connection to ' . $uri . ' cancelled while waiting for proxy (ECONNABORTED)',
+ defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
+ ));
+
+ // either close active connection or cancel pending connection attempt
+ $connecting->then(function (ConnectionInterface $stream) {
+ $stream->close();
+ });
+ $connecting->cancel();
+ });
+
+ $headers = $this->headers;
+ $connecting->then(function (ConnectionInterface $stream) use ($target, $headers, $deferred, $uri) {
+ // keep buffering data until headers are complete
+ $buffer = '';
+ $stream->on('data', $fn = function ($chunk) use (&$buffer, $deferred, $stream, &$fn, $uri) {
+ $buffer .= $chunk;
+
+ $pos = strpos($buffer, "\r\n\r\n");
+ if ($pos !== false) {
+ // end of headers received => stop buffering
+ $stream->removeListener('data', $fn);
+ $fn = null;
+
+ // try to parse headers as response message
+ try {
+ $response = Psr7\parse_response(substr($buffer, 0, $pos));
+ } catch (Exception $e) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy returned invalid response (EBADMSG)',
+ defined('SOCKET_EBADMSG') ? SOCKET_EBADMSG: 71,
+ $e
+ ));
+ $stream->close();
+ return;
+ }
+
+ if ($response->getStatusCode() === 407) {
+ // map status code 407 (Proxy Authentication Required) to EACCES
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy denied access with HTTP error code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (EACCES)',
+ defined('SOCKET_EACCES') ? SOCKET_EACCES : 13
+ ));
+ $stream->close();
+ return;
+ } elseif ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
+ // map non-2xx status code to ECONNREFUSED
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy refused connection with HTTP error code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
+ ));
+ $stream->close();
+ return;
+ }
+
+ // all okay, resolve with stream instance
+ $deferred->resolve($stream);
+
+ // emit remaining incoming as data event
+ $buffer = (string)substr($buffer, $pos + 4);
+ if ($buffer !== '') {
+ $stream->emit('data', array($buffer));
+ $buffer = '';
+ }
+ return;
+ }
+
+ // stop buffering when 8 KiB have been read
+ if (isset($buffer[8192])) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy response headers exceed maximum of 8 KiB (EMSGSIZE)',
+ defined('SOCKET_EMSGSIZE') ? SOCKET_EMSGSIZE : 90
+ ));
+ $stream->close();
+ }
+ });
+
+ $stream->on('error', function (Exception $e) use ($deferred, $uri) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy caused a stream error (EIO)',
+ defined('SOCKET_EIO') ? SOCKET_EIO : 5,
+ $e
+ ));
+ });
+
+ $stream->on('close', function () use ($deferred, $uri) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy was lost while waiting for response (ECONNRESET)',
+ defined('SOCKET_ECONNRESET') ? SOCKET_ECONNRESET : 104
+ ));
+ });
+
+ $stream->write("CONNECT " . $target . " HTTP/1.1\r\nHost: " . $target . "\r\n" . $headers . "\r\n");
+ }, function (Exception $e) use ($deferred, $uri) {
+ $deferred->reject($e = new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy failed (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111,
+ $e
+ ));
+
+ // avoid garbage references by replacing all closures in call stack.
+ // what a lovely piece of code!
+ $r = new \ReflectionProperty('Exception', 'trace');
+ $r->setAccessible(true);
+ $trace = $r->getValue($e);
+
+ // Exception trace arguments are not available on some PHP 7.4 installs
+ // @codeCoverageIgnoreStart
+ foreach ($trace as $ti => $one) {
+ if (isset($one['args'])) {
+ foreach ($one['args'] as $ai => $arg) {
+ if ($arg instanceof \Closure) {
+ $trace[$ti]['args'][$ai] = 'Object(' . get_class($arg) . ')';
+ }
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ $r->setValue($e, $trace);
+ });
+
+ return $deferred->promise();
+ }
+}