8000 Documentation for custom HTTP headers and simplify logic · SimonFrings/reactphp-http-proxy@031d626 · GitHub
[go: up one dir, main page]

Skip to content

Commit 031d626

Browse files
committed
Documentation for custom HTTP headers and simplify logic
1 parent 8dc21a3 commit 031d626

File tree

4 files changed

+55
-22
lines changed

4 files changed

+55
-22
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ existing higher-level protocol implementation.
4343
* [Connection timeout](#connection-timeout)
4444
* [DNS resolution](#dns-resolution)
4545
* [Authentication](#authentication)
46+
* [Advanced HTTP headers](#advanced-http-headers)
4647
* [Advanced secure proxy connections](#advanced-secure-proxy-connections)
4748
* [Advanced Unix domain sockets](#advanced-unix-domain-sockets)
4849
* [Install](#install)
@@ -307,6 +308,22 @@ $proxy = new ProxyConnector(
307308
`407` (Proxy Authentication Required) response status code and an exception
308309
error code of `SOCKET_EACCES` (13).
309310

311+
#### Advanced HTTP headers
312+
313+
The `ProxyConnector` constructor accepts an optional array of custom request
314+
headers to send in the `CONNECT` request. This can be useful if you're using a
315+
custom proxy setup or authentication scheme if the proxy server does not support
316+
basic [authentication](#authentication) as documented above. This is rarely used
317+
in practice, but may be useful for some more advanced use cases. In this case,
318+
you may simply pass an assoc array of additional request headers like this:
319+
320+
```php
321+
$proxy = new ProxyConnector('127.0.0.1:8080', $connector, array(
322+
'Proxy-Authentication' => 'Bearer abc123',
323+
'User-Agent' => 'ReactPHP'
324+
));
325+
```
326+
310327
#### Advanced secure proxy connections
311328

312329
Note that communication between the client and the proxy is usually via an

examples/03-custom-proxy-headers.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
// A simple example which requests https://google.com/ through an HTTP CONNECT proxy.
44
// The proxy can be given as first argument and defaults to localhost:8080 otherwise.
5+
//
6+
// For illustration purposes only. If you want to send HTTP requests in a real
7+
// world project, take a look at https://github.com/clue/reactphp-buzz#http-proxy
58

69
use Clue\React\HttpProxy\ProxyConnector;
710
use React\Socket\Connector;
811
use React\Socket\ConnectionInterface;
9-
use RingCentral\Psr7;
1012

1113
require __DIR__ . '/../vendor/autoload.php';
1214

src/ProxyConnector.php

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ class ProxyConnector implements ConnectorInterface
4343
{
4444
private $connector;
4545
private $proxyUri;
46-
private $proxyAuth = '';
47-
/** @var array */
48-
private $proxyHeaders;
46+
private $headers = '';
4947

5048
/**
5149
* Instantiate a new ProxyConnector which uses the given $proxyUrl
@@ -93,12 +91,17 @@ public function __construct($proxyUrl, ConnectorInterface $connector, array $htt
9391

9492
// prepare Proxy-Authorization header if URI contains username/password
9593
if (isset($parts['user']) || isset($parts['pass'])) {
96-
$this->proxyAuth = 'Basic ' . base64_encode(
94+
$this->headers = 'Proxy-Authorization: Basic ' . base64_encode(
9795
rawurldecode($parts['user'] . ':' . (isset($parts['pass']) ? $parts['pass'] : ''))
98-
);
96+
) . "\r\n";
9997
}
10098

101-
$this->proxyHeaders = $httpHeaders;
99+
// append any additional custom request headers
100+
foreach ($httpHeaders as $name => $values) {
101+
foreach ((array)$values as $value) {
102+
$this->headers .= $name . ': ' . $value . "\r\n";
103+
}
104+
}
102105
}
103106

104107
public function connect($uri)
@@ -156,9 +159,8 @@ public function connect($uri)
156159
$connecting->cancel();
157160
});
158161

159-
$auth = $this->proxyAuth;
160-
$headers = $this->proxyHeaders;
161-
$connecting->then(function (ConnectionInterface $stream) use ($target, $auth, $headers, $deferred) {
162+
$headers = $this->headers;
163+
$connecting->then(function (ConnectionInterface $stream) use ($target, $headers, $deferred) {
162164
// keep buffering data until headers are complete
163165
$buffer = '';
164166
$stream->on('data', $fn = function ($chunk) use (&$buffer, $deferred, $stream, &$fn) {
@@ -218,13 +220,7 @@ public function connect($uri)
218220
$deferred->reject(new RuntimeException('Connection to proxy lost while waiting for response (ECONNRESET)', defined('SOCKET_ECONNRESET') ? SOCKET_ECONNRESET : 104));
219221
});
220222

221-
$headers['Host'] = $target;
222-
if ($auth !== '') {
223-
$headers['Proxy-Authorization'] = $auth;
224-
}
225-
$request = new Psr7\Request('CONNECT', $target, $headers);
226-
$request = $request->withRequestTarget($target);
227-
$stream->write(Psr7\str($request));
223+
$stream->write("CONNECT " . $target . " HTTP/1.1\r\nHost: " . $target . "\r\n" . $headers . "\r\n");
228224
}, function (Exception $e) use ($deferred) {
229225
$deferred->reject($e = new RuntimeException(
230226
'Unable to connect to proxy (ECONNREFUSED)',

tests/ProxyConnectorTest.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,28 +218,46 @@ public function testWillProxyAuthorizationHeaderIfUnixProxyUriContainsAuthentica
218218
public function testWillSendCustomHttpHeadersToProxy()
219219
{
220220
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
221-
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nX-Custom-Header: X-Custom-Value\r\nHost: google.com:80\r\n\r\n");
221+
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\nX-Custom-Header: X-Custom-Value\r\n\r\n");
222222

223223
$promise = \React\Promise\resolve($stream);
224224
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
225225

226226
$proxy = new ProxyConnector('proxy.example.com', $this->connector, array(
227-
'X-Custom-Header' => 'X-Custom-Value',
227+
'X-Custom-Header' => 'X-Custom-Value'
228228
));
229229

230230
$proxy->connect('google.com:80');
231231
}
232232

233-
public function testWillOverrideProxyAuthorizationHeaderWithCredentialsFromUri()
233+
public function testWillSendMultipleCustomCookieHeadersToProxy()
234234
{
235235
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
236-
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nProxy-Authorization: Basic dXNlcjpwYXNz\r\nHost: google.com:80\r\n\r\n");
236+
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\nCookie: id=123\r\nCookie: year=2018\r\n\r\n");
237+
238+
$promise = \React\Promise\resolve($stream);
239+
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
240+
241+
$proxy = new ProxyConnector('proxy.example.com', $this->connector, array(
242+
'Cookie' => array(
243+
'id=123',
244+
'year=2018'
245+
)
246+
));
247+
248+
$proxy->connect('google.com:80');
249+
}
250+
251+
public function testWillAppendCustomProxyAuthorizationHeaderWithCredentialsFromUri()
252+
{
253+
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
254+
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\nProxy-Authorization: Basic dXNlcjpwYXNz\r\nProxy-Authorization: foobar\r\n\r\n");
237255

238256
$promise = \React\Promise\resolve($stream);
239257
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
240258

241259
$proxy = new ProxyConnector('user:pass@proxy.example.com', $this->connector, array(
242-
'Proxy-Authorization' => 'foobar',
260+
'Proxy-Authorization' => 'foobar'
243261
));
244262

245263
$proxy->connect('google.com:80');

0 commit comments

Comments
 (0)
0