Skip to content

Commit a4bf529

Browse files
authored
Merge pull request #21 from SimonFrings/http
Update to reactphp/http v1.0.0 and add improved HTTP examples
2 parents 9ef7e53 + 8cda5d6 commit a4bf529

9 files changed

+177
-51
lines changed

README.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -315,15 +315,37 @@ $connector->connect('tls://smtp.googlemail.com:465')->then(function (ConnectionI
315315

316316
### HTTP requests
317317

318-
HTTP operates on a higher layer than this low-level SSH proxy implementation.
319-
If you want to issue HTTP requests, you can add a dependency for
320-
[clue/reactphp-buzz](https://github.com/clue/reactphp-buzz).
321-
It can interact with this library by issuing all
322-
[HTTP requests through an SSH proxy server](https://github.com/clue/reactphp-buzz#ssh-proxy).
323-
When using the `SshSocksConnector` (recommended), this works for both plain HTTP
318+
This library also allows you to send
319+
[HTTP requests through an SSH proxy server](https://github.com/reactphp/http#ssh-proxy).
320+
321+
In order to send HTTP requests, you first have to add a dependency for
322+
[ReactPHP's async HTTP client](https://github.com/reactphp/http#client-usage).
323+
This allows you to send both plain HTTP and TLS-encrypted HTTPS requests like this:
324+
325+
```php
326+
$proxy = new Clue\React\SshProxy\SshSocksConnector('me@localhost:22', $loop);
327+
328+
$connector = new React\Socket\Connector($loop, array(
329+
'tcp' => $proxy,
330+
'dns' => false
331+
));
332+
333+
$browser = new React\Http\Browser($loop, $connector);
334+
335+
$browser->get('https://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
336+
var_dump($response->getHeaders(), (string) $response->getBody());
337+
}, function (Exception $e) {
338+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
339+
});
340+
```
341+
342+
We recommend using the `SshSocksConnector`, this works for both plain HTTP
324343
and TLS-encrypted HTTPS requests. When using the `SshProcessConnector`, this only
325344
works for plaintext HTTP requests.
326345

346+
See also [ReactPHP's HTTP client](https://github.com/reactphp/http#client-usage)
347+
and any of the [examples](examples) for more details.
348+
327349
### Database tunnel
328350

329351
We should now have a basic understanding of how we can tunnel any TCP/IP-based

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"require-dev": {
3030
"clue/block-react": "^1.3",
3131
"phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.36",
32+
"react/http": "^1.0",
3233
"react/mysql": "^0.5.3"
3334
}
3435
}

examples/01-https-request.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
// A simple example which uses an HTTP client to requesthttps://example.com/ through an SSH proxy server.
4+
// The proxy can be given through the SSH_PROXY env and defaults to localhost otherwise.
5+
//
6+
// You can assign the SSH_PROXY environment and prefix this with a space to make
7+
// sure your login credentials are not stored in your bash history like this:
8+
//
9+
// $ export SSH_PROXY=user:secret@example.com
10+
// $ php examples/01-https-request.php
11+
12+
require __DIR__ . '/../vendor/autoload.php';
13+
14+
$url = getenv('SSH_PROXY') !== false ? getenv('SSH_PROXY') : 'ssh://localhost:22';
15+
16+
$loop = React\EventLoop\Factory::create();
17+
$proxy = new Clue\React\SshProxy\SshProcessConnector($url, $loop);
18+
19+
$connector = new React\Socket\Connector($loop, array(
20+
'tcp' => $proxy,
21+
'timeout' => 3.0,
22+
'dns' => false
23+
));
24+
25+
$browser = new React\Http\Browser($loop, $connector);
26+
27+
$browser->get('https://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
28+
var_dump($response->getHeaders(), (string) $response->getBody());
29+
}, function (Exception $e) {
30+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
31+
});
32+
33+
$loop->run();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
// A simple example which uses an HTTP client to request https://example.com/ (optional: Through an SSH proxy server.)
4+
//
5+
// The proxy can be given through the SSH_PROXY env or does not use a proxy otherwise.
6+
// You can assign the SSH_PROXY environment and prefix this with a space to make
7+
// sure your login credentials are not stored in your bash history like this:
8+
//
9+
// $ export SSH_PROXY=user:secret@example.com
10+
// $ php examples/02-optional-proxy-https-request.php
11+
12+
require __DIR__ . '/../vendor/autoload.php';
13+
14+
$loop = React\EventLoop\Factory::create();
15+
16+
// SSH_PROXY environment given? use this as the proxy URL
17+
if (getenv('SSH_PROXY') !== false) {
18+
$proxy = new Clue\React\SshProxy\SshProcessConnector(getenv('SSH_PROXY'), $loop);
19+
$connector = new React\Socket\Connector($loop, array(
20+
'tcp' => $proxy,
21+
'timeout' => 3.0,
22+
'dns' => false
23+
));
24+
} else {
25+
$connector = new React\Socket\Connector($loop);
26+
}
27+
28+
$browser = new React\Http\Browser($loop, $connector);
29+
30+
$browser->get('https://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
31+
var_dump($response->getHeaders(), (string) $response->getBody());
32+
}, function (Exception $e) {
33+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
34+
});
35+
36+
$loop->run();

examples/01-proxy-http.php renamed to examples/11-proxy-raw-http-protocol.php

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,31 @@
77
// sure your login credentials are not stored in your bash history like this:
88
//
99
// $ export SSH_PROXY=user:secret@example.com
10-
// $ php examples/01-proxy-http.php
10+
// $ php examples/11-proxy-raw-http-protocol.php
1111
//
1212
// For illustration purposes only. If you want to send HTTP requests in a real
13-
// world project, take a look at https://github.com/clue/reactphp-buzz#ssh-proxy
14-
15-
use Clue\React\SshProxy\SshProcessConnector;
16-
use React\Socket\Connector;
17-
use React\Socket\ConnectionInterface;
13+
// world project, take a look at example #01, example #02 and https://github.com/reactphp/http#client-usage.
1814

1915
require __DIR__ . '/../vendor/autoload.php';
2016

2117
$url = getenv('SSH_PROXY') !== false ? getenv('SSH_PROXY') : 'ssh://localhost:22';
2218

2319
$loop = React\EventLoop\Factory::create();
2420

25-
$proxy = new SshProcessConnector($url, $loop);
26-
$connector = new Connector($loop, array(
21+
$proxy = new Clue\React\SshProxy\SshProcessConnector($url, $loop);
22+
$connector = new React\Socket\Connector($loop, array(
2723
'tcp' => $proxy,
2824
'timeout' => 3.0,
2925
'dns' => false
3026
));
3127

32-
$connector->connect('tcp://google.com:80')->then(function (ConnectionInterface $stream) {
28+
$connector->connect('tcp://google.com:80')->then(function (React\Socket\ConnectionInterface $stream) {
3329
$stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
3430
$stream->on('data', function ($chunk) {
3531
echo $chunk;
3632
});
37-
}, 'printf');
33+
}, function (Exception $e) {
34+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
35+
});
3836

3937
$loop->run();
Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,44 @@
11
<?php
22

3-
// A simple example which requests http://google.com/ either directly or through
4-
// an SSH proxy server.
3+
// A simple example which requests http://google.com/ either directly or through an SSH proxy server.
54
// The proxy can be given through the SSH_PROXY env or does not use a proxy otherwise.
6-
// This example highlights how changing from direct connection to using a proxy
7-
// actually adds very little complexity and does not mess with your actual
8-
// network protocol otherwise.
95
//
106
// You can assign the SSH_PROXY environment and prefix this with a space to make
117
// sure your login credentials are not stored in your bash history like this:
128
//
139
// $ export SSH_PROXY=user:secret@example.com
14-
// $ php examples/02-optional-proxy-http.php
10+
// $ php examples/12-optional-proxy-raw-http-protocol.php
11+
//
12+
// This example highlights how changing from direct connection to using a proxy
13+
// actually adds very little complexity and does not mess with your actual
14+
// network protocol otherwise.
1515
//
1616
// For illustration purposes only. If you want to send HTTP requests in a real
17-
// world project, take a look at https://github.com/clue/reactphp-buzz#ssh-proxy
18-
19-
use Clue\React\SshProxy\SshProcessConnector;
20-
use React\Socket\Connector;
21-
use React\Socket\ConnectionInterface;
17+
// world project, take a look at example #01, example #02 and https://github.com/reactphp/http#client-usage.
2218

2319
require __DIR__ . '/../vendor/autoload.php';
2420

2521
$loop = React\EventLoop\Factory::create();
2622

2723
// SSH_PROXY environment given? use this as the proxy URL
2824
if (getenv('SSH_PROXY') !== false) {
29-
$proxy = new SshProcessConnector(getenv('SSH_PROXY'), $loop);
30-
$connector = new Connector($loop, array(
25+
$proxy = new Clue\React\SshProxy\SshProcessConnector(getenv('SSH_PROXY'), $loop);
26+
$connector = new React\Socket\Connector($loop, array(
3127
'tcp' => $proxy,
3228
'timeout' => 3.0,
3329
'dns' => false
3430
));
3531
} else {
36-
$connector = new Connector($loop);
32+
$connector = new React\Socket\Connector($loop);
3733
}
3834

39-
$connector->connect('tcp://google.com:80')->then(function (ConnectionInterface $stream) {
35+
$connector->connect('tcp://google.com:80')->then(function (React\Socket\ConnectionInterface $stream) {
4036
$stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
4137
$stream->on('data', function ($chunk) {
4238
echo $chunk;
4339
});
44-
}, 'printf');
40+
}, function (Exception $e) {
41+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
42+
});
4543

4644
$loop->run();

examples/11-proxy-https.php renamed to examples/21-proxy-raw-https-protocol.php

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,31 @@
77
// sure your login credentials are not stored in your bash history like this:
88
//
99
// $ export SSH_PROXY=user:secret@example.com
10-
// $ php examples/11-proxy-https.php
10+
// $ php examples/21-proxy-raw-https-protocol.php
1111
//
1212
// For illustration purposes only. If you want to send HTTP requests in a real
13-
// world project, take a look at https://github.com/clue/reactphp-buzz#ssh-proxy
14-
15-
use Clue\React\SshProxy\SshSocksConnector;
16-
use React\Socket\Connector;
17-
use React\Socket\ConnectionInterface;
13+
// world project, take a look at example #01, example #02 and https://github.com/reactphp/http#client-usage.
1814

1915
require __DIR__ . '/../vendor/autoload.php';
2016

2117
$url = getenv('SSH_PROXY') !== false ? getenv('SSH_PROXY') : 'ssh://localhost:22';
2218

2319
$loop = React\EventLoop\Factory::create();
2420

25-
$proxy = new SshSocksConnector($url, $loop);
26-
$connector = new Connector($loop, array(
21+
$proxy = new Clue\React\SshProxy\SshSocksConnector($url, $loop);
22+
$connector = new React\Socket\Connector($loop, array(
2723
'tcp' => $proxy,
2824
'timeout' => 3.0,
2925
'dns' => false
3026
));
3127

32-
$connector->connect('tls://google.com:443')->then(function (ConnectionInterface $stream) {
28+
$connector->connect('tls://google.com:443')->then(function (React\Socket\ConnectionInterface $stream) {
3329
$stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
3430
$stream->on('data', function ($chunk) {
3531
echo $chunk;
3632
});
37-
}, 'printf');
33+
}, function (Exception $e) {
34+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
35+
});
3836

3937
$loop->run();
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
// A simple example which requests https://google.com/ either directly or through an SSH proxy server.
4+
// The proxy can be given through the SSH_PROXY env or does not use a proxy otherwise.
5+
//
6+
// You can assign the SSH_PROXY environment and prefix this with a space to make
7+
// sure your login credentials are not stored in your bash history like this:
8+
//
9+
// $ export SSH_PROXY=user:secret@example.com
10+
// $ php examples/22-optional-proxy-raw-https-protocol.php
11+
//
12+
// This example highlights how changing from direct connection to using a proxy
13+
// actually adds very little complexity and does not mess with your actual
14+
// network protocol otherwise.
15+
//
16+
// For illustration purposes only. If you want to send HTTP requests in a real
17+
// world project, take a look at example #01, example #02 and https://github.com/reactphp/http#client-usage.
18+
19+
require __DIR__ . '/../vendor/autoload.php';
20+
21+
$loop = React\EventLoop\Factory::create();
22+
23+
// SSH_PROXY environment given? use this as the proxy URL
24+
if (getenv('SSH_PROXY') !== false) {
25+
$proxy = new Clue\React\SshProxy\SshProcessConnector(getenv('SSH_PROXY'), $loop);
26+
$connector = new React\Socket\Connector($loop, array(
27+
'tcp' => $proxy,
28+
'timeout' => 3.0,
29+
'dns' => false
30+
));
31+
} else {
32+
$connector = new React\Socket\Connector($loop);
33+
}
34+
35+
$connector->connect('tls://google.com:443')->then(function (React\Socket\ConnectionInterface $stream) {
36+
$stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
37+
$stream->on('data', function ($chunk) {
38+
echo $chunk;
39+
});
40+
}, function (Exception $e) {
41+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
42+
});
43+
44+
$loop->run();

examples/21-mysql-ssh-tunnel.php renamed to examples/31-mysql-ssh-tunnel.php

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,23 @@
99
// history like this:
1010
//
1111
// $ export SSH_PROXY=user:secret@example.com
12-
// $ export MYSQL_LOGIN=user:password@localhost
13-
// $ php examples/21-mysql-ssh-tunnel.php
12+
// $ export MYSQL_LOGIN=user:password@localhost
13+
// $ php examples/31-mysql-ssh-tunnel.php
1414
//
1515
// See also https://github.com/friends-of-reactphp/mysql
1616

17-
use Clue\React\SshProxy\SshProcessConnector;
18-
use React\MySQL\Factory;
19-
use React\MySQL\QueryResult;
20-
2117
require __DIR__ . '/../vendor/autoload.php';
2218

2319
$loop = React\EventLoop\Factory::create();
2420

2521
$url = getenv('SSH_PROXY') !== false ? getenv('SSH_PROXY') : 'ssh://localhost:22';
26-
$proxy = new SshProcessConnector($url, $loop);
22+
$proxy = new Clue\React\SshProxy\SshProcessConnector($url, $loop);
2723

2824
$url = getenv('MYSQL_LOGIN') !== false ? getenv('MYSQL_LOGIN') : 'user:pass@localhost';
29-
$factory = new Factory($loop, $proxy);
25+
$factory = new React\MySQL\Factory($loop, $proxy);
3026
$client = $factory->createLazyConnection($url);
3127

32-
$client->query('SELECT * FROM (SELECT "foo" UNION SELECT "bar") data')->then(function (QueryResult $query) {
28+
$client->query('SELECT * FROM (SELECT "foo" UNION SELECT "bar") data')->then(function (React\MySQL\QueryResult $query) {
3329
var_dump($query->resultRows);
3430
}, 'printf');
3531
$client->quit();

0 commit comments

Comments
 (0)