Skip to content

Commit 5b5e966

Browse files
committed
Merge branch 'darxriggs-parse-port-header'
Closes #6
2 parents a224a43 + dbb1f17 commit 5b5e966

File tree

4 files changed

+123
-65
lines changed

4 files changed

+123
-65
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
# Proxy Scheme and Host detection middleware
1+
# Proxy Scheme, Host and Port detection middleware
22

33
[![Build status][Master image]][Master]
44

5-
PSR-7 Middleware that determines the scheme and host from the 'X-Forwarded-Proto' and 'X-Forwarded-Host' headers and updates the Request's Uri object.
5+
PSR-7 Middleware that determines the scheme, host and port from the 'X-Forwarded-Proto', 'X-Forwarded-Host' and 'X-Forwarded-Port' headers and updates the Request's Uri object.
66

77
You can set a list of proxies that are trusted as the second constructor parameter. If this list is set, then the proxy headers will only be checked if the `REMOTE_ADDR` is in the trusted list.
88

99

10-
1110
## Installation
1211

1312
`composer require akrabat/rka-scheme-and-host-detection-middleware`
1413

14+
1515
## Usage
1616

1717
In Slim 3:
@@ -23,6 +23,7 @@ $app->add(new RKA\Middleware\SchemeAndHost($trustedProxies));
2323
$app->get('/', function ($request, $response, $args) {
2424
$scheme = $request->getUri()->getScheme();
2525
$host = $request->getUri()->getHost();
26+
$port = $request->getUri()->getPort();
2627

2728
return $response;
2829
});

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "akrabat/rka-scheme-and-host-detection-middleware",
3-
"description": "PSR-7 Middleware that determines the scheme and host from the 'X-Forwarded-Proto' and 'X-Forwarded-Host' headers and updates the Request's Uri object.",
3+
"description": "PSR-7 Middleware that determines the scheme, host and port from the 'X-Forwarded-Proto', 'X-Forwarded-Host' and 'X-Forwarded-Port' headers and updates the Request's Uri object.",
44
"keywords": [
55
"psr7", "middleware", "ip"
66
],

src/SchemeAndHost.php

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<?php
22
namespace RKA\Middleware;
33

4-
use Psr\Http\Message\ServerRequestInterface;
54
use Psr\Http\Message\ResponseInterface;
5+
use Psr\Http\Message\ServerRequestInterface;
6+
use Psr\Http\Message\UriInterface;
67

78
class SchemeAndHost
89
{
@@ -53,21 +54,62 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
5354
return $response = $next($request, $response);
5455
}
5556
}
56-
57+
5758
$uri = $request->getUri();
5859

59-
// scheme
60+
$uri = $this->processProtoHeader($request, $uri);
61+
$uri = $this->processPortHeader($request, $uri);
62+
$uri = $this->processHostHeader($request, $uri);
63+
64+
$request = $request->withUri($uri);
65+
66+
return $response = $next($request, $response);
67+
}
68+
69+
/**
70+
* Check that a given string is a valid IP address
71+
*
72+
* @param string $ip
73+
* @return boolean
74+
*/
75+
protected function isValidIpAddress($ip)
76+
{
77+
$flags = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
78+
if (filter_var($ip, FILTER_VALIDATE_IP, $flags) === false) {
79+
return false;
80+
}
81+
return true;
82+
}
83+
84+
protected function processProtoHeader(ServerRequestInterface $request, UriInterface $uri)
85+
{
6086
if ($request->hasHeader('X-Forwarded-Proto')) {
6187
$scheme = $request->getHeaderLine('X-Forwarded-Proto');
88+
6289
if (in_array($scheme, ['http', 'https'])) {
63-
$uri = $uri->withScheme($scheme);
90+
return $uri->withScheme($scheme);
91+
}
92+
}
93+
return $uri;
94+
}
95+
96+
protected function processPortHeader(ServerRequestInterface $request, UriInterface $uri)
97+
{
98+
if ($request->hasHeader('X-Forwarded-Port')) {
99+
$port = trim(current(explode(',', $request->getHeaderLine('X-Forwarded-Port'))));
100+
101+
if (preg_match('/^\d+\z/', $port)) {
102+
return $uri->withPort((int) $port);
64103
}
65104
}
105+
return $uri;
106+
}
66107

67-
// host (& maybe port too)
108+
protected function processHostHeader(ServerRequestInterface $request, UriInterface $uri)
109+
{
68110
if ($request->hasHeader('X-Forwarded-Host')) {
69111
$host = trim(current(explode(',', $request->getHeaderLine('X-Forwarded-Host'))));
70-
112+
71113
$port = null;
72114
if (preg_match('/^(\[[a-fA-F0-9:.]+\])(:\d+)?\z/', $host, $matches)) {
73115
$host = $matches[1];
@@ -86,46 +128,6 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
86128
$uri = $uri->withPort($port);
87129
}
88130
}
89-
90-
$request = $request->withUri($uri);
91-
92-
return $response = $next($request, $response);
93-
}
94-
95-
/**
96-
* Check that a given string is a valid IP address
97-
*
98-
* @param string $ip
99-
* @return boolean
100-
*/
101-
protected function isValidIpAddress($ip)
102-
{
103-
$flags = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
104-
if (filter_var($ip, FILTER_VALIDATE_IP, $flags) === false) {
105-
return false;
106-
}
107-
return true;
108-
}
109-
110-
/**
111-
* Getter for headers
112-
*
113-
* @return array
114-
*/
115-
public function getHeaders()
116-
{
117-
return $this->headers;
118-
}
119-
120-
/**
121-
* Setter for headers
122-
*
123-
* @param array $headers List of proxy headers to test against
124-
* @return self
125-
*/
126-
public function setHeaders(array $headers)
127-
{
128-
$this->headers = $headers;
129-
return $this;
131+
return $uri;
130132
}
131133
}

tests/SchemeAndHostTest.php

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,86 @@
22
namespace RKA\Middleware\Test;
33

44
use RKA\Middleware\SchemeAndHost;
5-
use Zend\Diactoros\ServerRequest;
65
use Zend\Diactoros\ServerRequestFactory;
7-
use Zend\Diactoros\Uri;
86
use Zend\Diactoros\Response;
9-
use Zend\Diactoros\Stream;
10-
use RuntimeException;
117

128
class SchemeAndHostTest extends \PHPUnit_Framework_TestCase
139
{
14-
public function testShemeAndHost()
10+
public function testSchemeAndHostAndPortWithPortInHostHeader()
11+
{
12+
$request = ServerRequestFactory::fromGlobals([
13+
'REMOTE_ADDR' => '192.168.0.1',
14+
'HTTP_HOST' => 'foo.com',
15+
'HTTP_X_FORWARDED_PROTO' => 'https',
16+
'HTTP_X_FORWARDED_HOST' => 'example.com:1234',
17+
]);
18+
19+
$response = new Response();
20+
21+
$middleware = new SchemeAndHost();
22+
$middleware($request, $response, function ($request, $response) use (&$scheme, &$host, &$port) {
23+
// simply store the values
24+
$scheme = $request->getUri()->getScheme();
25+
$host = $request->getUri()->getHost();
26+
$port = $request->getUri()->getPort();
27+
return $response;
28+
});
29+
30+
$this->assertSame('https', $scheme);
31+
$this->assertSame('example.com', $host);
32+
$this->assertSame(1234, $port);
33+
}
34+
35+
public function testSchemeAndHostAndPortWithPortInPortHeader()
1536
{
1637
$request = ServerRequestFactory::fromGlobals([
1738
'REMOTE_ADDR' => '192.168.0.1',
1839
'HTTP_HOST' => 'foo.com',
1940
'HTTP_X_FORWARDED_PROTO' => 'https',
2041
'HTTP_X_FORWARDED_HOST' => 'example.com',
42+
'HTTP_X_FORWARDED_PORT' => '1234',
43+
]);
44+
45+
$response = new Response();
46+
47+
$middleware = new SchemeAndHost();
48+
$middleware($request, $response, function ($request, $response) use (&$scheme, &$host, &$port) {
49+
// simply store the values
50+
$scheme = $request->getUri()->getScheme();
51+
$host = $request->getUri()->getHost();
52+
$port = $request->getUri()->getPort();
53+
return $response;
54+
});
55+
56+
$this->assertSame('https', $scheme);
57+
$this->assertSame('example.com', $host);
58+
$this->assertSame(1234, $port);
59+
}
60+
61+
public function testSchemeAndHostAndPortWithPortInHostAndPortHeader()
62+
{
63+
$request = ServerRequestFactory::fromGlobals([
64+
'REMOTE_ADDR' => '192.168.0.1',
65+
'HTTP_HOST' => 'foo.com',
66+
'HTTP_X_FORWARDED_PROTO' => 'https',
67+
'HTTP_X_FORWARDED_HOST' => 'example.com:1000',
68+
'HTTP_X_FORWARDED_PORT' => '2000',
2169
]);
2270

2371
$response = new Response();
2472

25-
$middleware = new SchemeAndHost([]);
26-
$response = $middleware($request, $response, function ($request, $response) use (&$scheme, &$host) {
27-
// simply store the scheme and host values
73+
$middleware = new SchemeAndHost();
74+
$middleware($request, $response, function ($request, $response) use (&$scheme, &$host, &$port) {
75+
// simply store the values
2876
$scheme = $request->getUri()->getScheme();
2977
$host = $request->getUri()->getHost();
78+
$port = $request->getUri()->getPort();
3079
return $response;
3180
});
3281

3382
$this->assertSame('https', $scheme);
3483
$this->assertSame('example.com', $host);
84+
$this->assertSame(1000, $port);
3585
}
3686

3787
public function testTrustedProxies()
@@ -40,41 +90,46 @@ public function testTrustedProxies()
4090
'REMOTE_ADDR' => '192.168.0.1',
4191
'HTTP_HOST' => 'foo.com',
4292
'HTTP_X_FORWARDED_PROTO' => 'https',
43-
'HTTP_X_FORWARDED_HOST' => 'example.com',
93+
'HTTP_X_FORWARDED_HOST' => 'example.com:1234',
4494
]);
4595

4696
$response = new Response();
4797

4898
$middleware = new SchemeAndHost(['192.168.0.1']);
49-
$response = $middleware($request, $response, function ($request, $response) use (&$scheme, &$host) {
50-
// simply store the scheme and host values
99+
$middleware($request, $response, function ($request, $response) use (&$scheme, &$host, &$port) {
100+
// simply store the values
51101
$scheme = $request->getUri()->getScheme();
52102
$host = $request->getUri()->getHost();
103+
$port = $request->getUri()->getPort();
53104
return $response;
54105
});
55106

56107
$this->assertSame('https', $scheme);
57108
$this->assertSame('example.com', $host);
109+
$this->assertSame(1234, $port);
58110
}
59111

60112
public function testNonTrustedProxies()
61113
{
62114
$request = ServerRequestFactory::fromGlobals([
63115
'REMOTE_ADDR' => '10.0.0.1',
64116
'HTTP_HOST' => 'foo.com',
65-
'HTTP_X_FORWARDED_HOST' => 'example.com',
117+
'HTTP_X_FORWARDED_HOST' => 'example.com:1234',
66118
]);
67119

68120
$response = new Response();
69121

70122
$middleware = new SchemeAndHost(['192.168.0.1']);
71-
$response = $middleware($request, $response, function ($request, $response) use (&$scheme, &$host) {
72-
// simply store the scheme and host values
123+
$middleware($request, $response, function ($request, $response) use (&$scheme, &$host, &$port) {
124+
// simply store the values
73125
$scheme = $request->getUri()->getScheme();
74126
$host = $request->getUri()->getHost();
127+
$port = $request->getUri()->getPort();
75128
return $response;
76129
});
77130

131+
$this->assertSame('http', $scheme);
78132
$this->assertSame('foo.com', $host);
133+
$this->assertSame(null, $port);
79134
}
80135
}

0 commit comments

Comments
 (0)