From 487a4fb3fce1e2ae566de044b9597fddb7f9a112 Mon Sep 17 00:00:00 2001 From: simon Date: Thu, 22 Oct 2020 15:00:48 +0200 Subject: [PATCH 1/2] Update to reactphp/http v1.0.0 --- README.md | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 43d8126..3556aa6 100644 --- a/README.md +++ b/README.md @@ -315,15 +315,37 @@ $connector->connect('tls://smtp.googlemail.com:465')->then(function (ConnectionI ### HTTP requests -HTTP operates on a higher layer than this low-level SSH proxy implementation. -If you want to issue HTTP requests, you can add a dependency for -[clue/reactphp-buzz](https://github.com/clue/reactphp-buzz). -It can interact with this library by issuing all -[HTTP requests through an SSH proxy server](https://github.com/clue/reactphp-buzz#ssh-proxy). -When using the `SshSocksConnector` (recommended), this works for both plain HTTP +This library also allows you to send +[HTTP requests through an SSH proxy server](https://github.com/reactphp/http#ssh-proxy). + +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\SshProxy\SshSocksConnector('me@localhost:22', $loop); + +$connector = new React\Socket\Connector($loop, array( + 'tcp' => $proxy, + 'dns' => false +)); + +$browser = new React\Http\Browser($loop, $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; +}); +``` + +We recommend using the `SshSocksConnector`, this works for both plain HTTP and TLS-encrypted HTTPS requests. When using the `SshProcessConnector`, this only works for plaintext HTTP requests. +See also [ReactPHP's HTTP client](https://github.com/reactphp/http#client-usage) +and any of the [examples](examples) for more details. + ### Database tunnel We should now have a basic understanding of how we can tunnel any TCP/IP-based From 8cda5d63a5c3311bf2561b81a200824f35a4967b Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 23 Oct 2020 11:53:34 +0200 Subject: [PATCH 2/2] Add improved HTTP examples --- composer.json | 1 + examples/01-https-request.php | 33 ++++++++++++++ examples/02-optional-proxy-https-request.php | 36 +++++++++++++++ ...ttp.php => 11-proxy-raw-http-protocol.php} | 18 ++++---- ...> 12-optional-proxy-raw-http-protocol.php} | 30 ++++++------- ...ps.php => 21-proxy-raw-https-protocol.php} | 18 ++++---- .../22-optional-proxy-raw-https-protocol.php | 44 +++++++++++++++++++ ...ssh-tunnel.php => 31-mysql-ssh-tunnel.php} | 14 +++--- 8 files changed, 149 insertions(+), 45 deletions(-) create mode 100644 examples/01-https-request.php create mode 100644 examples/02-optional-proxy-https-request.php rename examples/{01-proxy-http.php => 11-proxy-raw-http-protocol.php} (65%) rename examples/{02-optional-proxy-http.php => 12-optional-proxy-raw-http-protocol.php} (64%) rename examples/{11-proxy-https.php => 21-proxy-raw-https-protocol.php} (65%) create mode 100644 examples/22-optional-proxy-raw-https-protocol.php rename examples/{21-mysql-ssh-tunnel.php => 31-mysql-ssh-tunnel.php} (76%) diff --git a/composer.json b/composer.json index b5d7750..f02f35d 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "require-dev": { "clue/block-react": "^1.3", "phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.36", + "react/http": "^1.0", "react/mysql": "^0.5.3" } } diff --git a/examples/01-https-request.php b/examples/01-https-request.php new file mode 100644 index 0000000..9025d77 --- /dev/null +++ b/examples/01-https-request.php @@ -0,0 +1,33 @@ + $proxy, + 'timeout' => 3.0, + 'dns' => false +)); + +$browser = new React\Http\Browser($loop, $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; +}); + +$loop->run(); diff --git a/examples/02-optional-proxy-https-request.php b/examples/02-optional-proxy-https-request.php new file mode 100644 index 0000000..058fef9 --- /dev/null +++ b/examples/02-optional-proxy-https-request.php @@ -0,0 +1,36 @@ + $proxy, + 'timeout' => 3.0, + 'dns' => false + )); +} else { + $connector = new React\Socket\Connector($loop); +} + +$browser = new React\Http\Browser($loop, $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; +}); + +$loop->run(); diff --git a/examples/01-proxy-http.php b/examples/11-proxy-raw-http-protocol.php similarity index 65% rename from examples/01-proxy-http.php rename to examples/11-proxy-raw-http-protocol.php index 256e6ea..a4453bb 100644 --- a/examples/01-proxy-http.php +++ b/examples/11-proxy-raw-http-protocol.php @@ -7,14 +7,10 @@ // sure your login credentials are not stored in your bash history like this: // // $ export SSH_PROXY=user:secret@example.com -// $ php examples/01-proxy-http.php +// $ php examples/11-proxy-raw-http-protocol.php // // For illustration purposes only. If you want to send HTTP requests in a real -// world project, take a look at https://github.com/clue/reactphp-buzz#ssh-proxy - -use Clue\React\SshProxy\SshProcessConnector; -use React\Socket\Connector; -use React\Socket\ConnectionInterface; +// world project, take a look at example #01, example #02 and https://github.com/reactphp/http#client-usage. require __DIR__ . '/../vendor/autoload.php'; @@ -22,18 +18,20 @@ $loop = React\EventLoop\Factory::create(); -$proxy = new SshProcessConnector($url, $loop); -$connector = new Connector($loop, array( +$proxy = new Clue\React\SshProxy\SshProcessConnector($url, $loop); +$connector = new React\Socket\Connector($loop, array( 'tcp' => $proxy, 'timeout' => 3.0, 'dns' => false )); -$connector->connect('tcp://google.com:80')->then(function (ConnectionInterface $stream) { +$connector->connect('tcp://google.com:80')->then(function (React\Socket\ConnectionInterface $stream) { $stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n"); $stream->on('data', function ($chunk) { echo $chunk; }); -}, 'printf'); +}, function (Exception $e) { + echo 'Error: ' . $e->getMessage() . PHP_EOL; +}); $loop->run(); diff --git a/examples/02-optional-proxy-http.php b/examples/12-optional-proxy-raw-http-protocol.php similarity index 64% rename from examples/02-optional-proxy-http.php rename to examples/12-optional-proxy-raw-http-protocol.php index f66fa27..88cc597 100644 --- a/examples/02-optional-proxy-http.php +++ b/examples/12-optional-proxy-raw-http-protocol.php @@ -1,24 +1,20 @@ $proxy, 'timeout' => 3.0, 'dns' => false )); } else { - $connector = new Connector($loop); + $connector = new React\Socket\Connector($loop); } -$connector->connect('tcp://google.com:80')->then(function (ConnectionInterface $stream) { +$connector->connect('tcp://google.com:80')->then(function (React\Socket\ConnectionInterface $stream) { $stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n"); $stream->on('data', function ($chunk) { echo $chunk; }); -}, 'printf'); +}, function (Exception $e) { + echo 'Error: ' . $e->getMessage() . PHP_EOL; +}); $loop->run(); diff --git a/examples/11-proxy-https.php b/examples/21-proxy-raw-https-protocol.php similarity index 65% rename from examples/11-proxy-https.php rename to examples/21-proxy-raw-https-protocol.php index 25c3832..8ba790f 100644 --- a/examples/11-proxy-https.php +++ b/examples/21-proxy-raw-https-protocol.php @@ -7,14 +7,10 @@ // sure your login credentials are not stored in your bash history like this: // // $ export SSH_PROXY=user:secret@example.com -// $ php examples/11-proxy-https.php +// $ php examples/21-proxy-raw-https-protocol.php // // For illustration purposes only. If you want to send HTTP requests in a real -// world project, take a look at https://github.com/clue/reactphp-buzz#ssh-proxy - -use Clue\React\SshProxy\SshSocksConnector; -use React\Socket\Connector; -use React\Socket\ConnectionInterface; +// world project, take a look at example #01, example #02 and https://github.com/reactphp/http#client-usage. require __DIR__ . '/../vendor/autoload.php'; @@ -22,18 +18,20 @@ $loop = React\EventLoop\Factory::create(); -$proxy = new SshSocksConnector($url, $loop); -$connector = new Connector($loop, array( +$proxy = new Clue\React\SshProxy\SshSocksConnector($url, $loop); +$connector = new React\Socket\Connector($loop, array( 'tcp' => $proxy, 'timeout' => 3.0, 'dns' => false )); -$connector->connect('tls://google.com:443')->then(function (ConnectionInterface $stream) { +$connector->connect('tls://google.com:443')->then(function (React\Socket\ConnectionInterface $stream) { $stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n"); $stream->on('data', function ($chunk) { echo $chunk; }); -}, 'printf'); +}, function (Exception $e) { + echo 'Error: ' . $e->getMessage() . PHP_EOL; +}); $loop->run(); diff --git a/examples/22-optional-proxy-raw-https-protocol.php b/examples/22-optional-proxy-raw-https-protocol.php new file mode 100644 index 0000000..2b50263 --- /dev/null +++ b/examples/22-optional-proxy-raw-https-protocol.php @@ -0,0 +1,44 @@ + $proxy, + 'timeout' => 3.0, + 'dns' => false + )); +} else { + $connector = new React\Socket\Connector($loop); +} + +$connector->connect('tls://google.com:443')->then(function (React\Socket\ConnectionInterface $stream) { + $stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n"); + $stream->on('data', function ($chunk) { + echo $chunk; + }); +}, function (Exception $e) { + echo 'Error: ' . $e->getMessage() . PHP_EOL; +}); + +$loop->run(); diff --git a/examples/21-mysql-ssh-tunnel.php b/examples/31-mysql-ssh-tunnel.php similarity index 76% rename from examples/21-mysql-ssh-tunnel.php rename to examples/31-mysql-ssh-tunnel.php index 4007554..d5f9f8e 100644 --- a/examples/21-mysql-ssh-tunnel.php +++ b/examples/31-mysql-ssh-tunnel.php @@ -9,27 +9,23 @@ // history like this: // // $ export SSH_PROXY=user:secret@example.com -// $ export MYSQL_LOGIN=user:password@localhost -// $ php examples/21-mysql-ssh-tunnel.php +// $ export MYSQL_LOGIN=user:password@localhost +// $ php examples/31-mysql-ssh-tunnel.php // // See also https://github.com/friends-of-reactphp/mysql -use Clue\React\SshProxy\SshProcessConnector; -use React\MySQL\Factory; -use React\MySQL\QueryResult; - require __DIR__ . '/../vendor/autoload.php'; $loop = React\EventLoop\Factory::create(); $url = getenv('SSH_PROXY') !== false ? getenv('SSH_PROXY') : 'ssh://localhost:22'; -$proxy = new SshProcessConnector($url, $loop); +$proxy = new Clue\React\SshProxy\SshProcessConnector($url, $loop); $url = getenv('MYSQL_LOGIN') !== false ? getenv('MYSQL_LOGIN') : 'user:pass@localhost'; -$factory = new Factory($loop, $proxy); +$factory = new React\MySQL\Factory($loop, $proxy); $client = $factory->createLazyConnection($url); -$client->query('SELECT * FROM (SELECT "foo" UNION SELECT "bar") data')->then(function (QueryResult $query) { +$client->query('SELECT * FROM (SELECT "foo" UNION SELECT "bar") data')->then(function (React\MySQL\QueryResult $query) { var_dump($query->resultRows); }, 'printf'); $client->quit();